diff --git a/src/components/nostr/kinds/ScrollRenderer.tsx b/src/components/nostr/kinds/ScrollRenderer.tsx
index ac2bb7f..0db3034 100644
--- a/src/components/nostr/kinds/ScrollRenderer.tsx
+++ b/src/components/nostr/kinds/ScrollRenderer.tsx
@@ -148,7 +148,11 @@ export function ScrollDetailRenderer({ event }: { event: NostrEvent }) {
)}
-
+
);
}
diff --git a/src/components/scroll/ScrollExecutor.tsx b/src/components/scroll/ScrollExecutor.tsx
index 6c39a12..d35b46d 100644
--- a/src/components/scroll/ScrollExecutor.tsx
+++ b/src/components/scroll/ScrollExecutor.tsx
@@ -21,9 +21,48 @@ interface ScrollExecutorProps {
params: ScrollParam[];
/** Base64-encoded WASM binary */
wasmBase64: string;
+ /** Event ID used as localStorage key for persisting settings */
+ eventId?: string;
}
-export function ScrollExecutor({ params, wasmBase64 }: ScrollExecutorProps) {
+const SCROLL_STORAGE_PREFIX = "scroll_settings_";
+
+function loadScrollSettings(eventId: string): {
+ paramValues?: Record;
+ endianness?: "LE" | "BE";
+ presenceBytes?: boolean;
+} {
+ try {
+ const stored = localStorage.getItem(SCROLL_STORAGE_PREFIX + eventId);
+ return stored ? JSON.parse(stored) : {};
+ } catch {
+ return {};
+ }
+}
+
+function saveScrollSettings(
+ eventId: string,
+ settings: {
+ paramValues: Record;
+ endianness: "LE" | "BE";
+ presenceBytes: boolean;
+ },
+) {
+ try {
+ localStorage.setItem(
+ SCROLL_STORAGE_PREFIX + eventId,
+ JSON.stringify(settings),
+ );
+ } catch {
+ // localStorage full or unavailable — silently ignore
+ }
+}
+
+export function ScrollExecutor({
+ params,
+ wasmBase64,
+ eventId,
+}: ScrollExecutorProps) {
const { pubkey } = useAccount();
const { relays: relayStates } = useRelayState();
@@ -31,17 +70,28 @@ export function ScrollExecutor({ params, wasmBase64 }: ScrollExecutorProps) {
.filter(([, state]) => state.connectionState === "connected")
.map(([url]) => url);
- // Pre-fill "me" params with logged-in pubkey
+ // Load persisted settings
+ const stored = eventId ? loadScrollSettings(eventId) : {};
+
+ // Pre-fill "me" params with logged-in pubkey, then overlay persisted values
const defaultValues: Record = {};
for (const p of params) {
if (p.name === "me" && p.type === "public_key" && pubkey) {
defaultValues[p.name] = pubkey;
}
}
+ // Filter stored values to only include current params (remove stale keys)
+ const validParamNames = new Set(params.map((p) => p.name));
+ const filteredStored = Object.fromEntries(
+ Object.entries(stored.paramValues || {}).filter(([k]) =>
+ validParamNames.has(k),
+ ),
+ );
+ const initialValues = { ...defaultValues, ...filteredStored };
const [runtimeState, setRuntimeState] = useState("idle");
const [paramValues, setParamValues] =
- useState>(defaultValues);
+ useState>(initialValues);
const [displayedEventsMap, setDisplayedEventsMap] = useState<
Map
>(new Map());
@@ -50,10 +100,15 @@ export function ScrollExecutor({ params, wasmBase64 }: ScrollExecutorProps) {
const [activeSubs, setActiveSubs] = useState([]);
const [eventCount, setEventCount] = useState(0);
const controllerRef = useRef(null);
+ const isInitialMount = useRef(true);
// Encoding options
- const [endianness, setEndianness] = useState<"LE" | "BE">("BE");
- const [presenceBytes, setPresenceBytes] = useState(false);
+ const [endianness, setEndianness] = useState<"LE" | "BE">(
+ stored.endianness || "BE",
+ );
+ const [presenceBytes, setPresenceBytes] = useState(
+ stored.presenceBytes ?? false,
+ );
const isActive = runtimeState === "loading" || runtimeState === "running";
@@ -70,6 +125,16 @@ export function ScrollExecutor({ params, wasmBase64 }: ScrollExecutorProps) {
(p) => p.required && !paramValues[p.name]?.trim(),
);
+ // Persist settings to localStorage when they change (skip initial mount)
+ useEffect(() => {
+ if (!eventId) return;
+ if (isInitialMount.current) {
+ isInitialMount.current = false;
+ return;
+ }
+ saveScrollSettings(eventId, { paramValues, endianness, presenceBytes });
+ }, [eventId, paramValues, endianness, presenceBytes]);
+
useEffect(() => {
return () => {
controllerRef.current?.stop();