Persist home stepper state to localStorage via freeze scope
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 11m28s

- freeze-scope "home-stepper" captures step-idx signal
- Each step/back saves to localStorage via freeze-to-sx
- On mount, restores from localStorage via thaw-from-sx
- Invalid state resets to default (step 9)
- Clear preview lake before replay to prevent duplicates
- Register local-storage-get/set/remove as primitives
- Arrows 3x bigger

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-14 23:27:46 +00:00
parent cb4f4b85e5
commit f9bdd65583
3 changed files with 32 additions and 6 deletions

View File

@@ -14,7 +14,7 @@
// =========================================================================
var NIL = Object.freeze({ _nil: true, toString: function() { return "nil"; } });
var SX_VERSION = "2026-03-14T22:48:39Z";
var SX_VERSION = "2026-03-14T23:31:43Z";
function isNil(x) { return x === NIL || x === null || x === undefined; }
function isSxTruthy(x) { return x !== false && !isNil(x); }
@@ -5757,6 +5757,11 @@ PRIMITIVES["resource"] = resource;
PRIMITIVES["is-html-tag?"] = function(n) { return HTML_TAGS.indexOf(n) >= 0; };
PRIMITIVES["make-env"] = function() { return merge(componentEnv, PRIMITIVES); };
// localStorage — registered here (before boot) so islands can use at hydration
if (typeof localStorageGet === "function") PRIMITIVES["local-storage-get"] = localStorageGet;
if (typeof localStorageSet === "function") PRIMITIVES["local-storage-set"] = localStorageSet;
if (typeof localStorageRemove === "function") PRIMITIVES["local-storage-remove"] = localStorageRemove;
// =========================================================================
// Platform interface — DOM adapter (browser-only)
@@ -7019,6 +7024,7 @@ PRIMITIVES["resource"] = resource;
function localStorageRemove(key) {
try { localStorage.removeItem(key); } catch (e) {}
}
// localStorage primitives registered in CEK_FIXUPS_JS for ordering
// --- Cookies ---

View File

@@ -1531,6 +1531,11 @@ CEK_FIXUPS_JS = '''
PRIMITIVES["make-symbol"] = function(n) { return new Symbol(n); };
PRIMITIVES["is-html-tag?"] = function(n) { return HTML_TAGS.indexOf(n) >= 0; };
PRIMITIVES["make-env"] = function() { return merge(componentEnv, PRIMITIVES); };
// localStorage — registered here (before boot) so islands can use at hydration
if (typeof localStorageGet === "function") PRIMITIVES["local-storage-get"] = localStorageGet;
if (typeof localStorageSet === "function") PRIMITIVES["local-storage-set"] = localStorageSet;
if (typeof localStorageRemove === "function") PRIMITIVES["local-storage-remove"] = localStorageRemove;
'''
@@ -2912,6 +2917,7 @@ PLATFORM_BOOT_JS = """
function localStorageRemove(key) {
try { localStorage.removeItem(key); } catch (e) {}
}
// localStorage primitives registered in CEK_FIXUPS_JS for ordering
// --- Cookies ---

View File

@@ -174,7 +174,8 @@
(when (and parent rendered)
(dom-append parent rendered)))))
(swap! step-idx inc)
(update-code-highlight))))
(update-code-highlight)
(local-storage-set "sx-home-stepper" (freeze-to-sx "home-stepper")))))
(do-back (fn ()
(when (> (deref step-idx) 0)
(let ((target (- (deref step-idx) 1))
@@ -182,7 +183,18 @@
(when container (dom-set-prop container "innerHTML" ""))
(set-stack (list (get-preview)))
(reset! step-idx 0)
(for-each (fn (_) (do-step)) (slice (deref steps) 0 target)))))))
(for-each (fn (_) (do-step)) (slice (deref steps) 0 target))
(local-storage-set "sx-home-stepper" (freeze-to-sx "home-stepper")))))))
;; Freeze scope for persistence
(freeze-scope "home-stepper" (fn ()
(freeze-signal "step" step-idx)))
;; Restore from localStorage on mount
(let ((saved (local-storage-get "sx-home-stepper")))
(when saved
(thaw-from-sx saved)
;; Validate — reset to default if out of range
(when (or (< (deref step-idx) 0) (> (deref step-idx) 16))
(reset! step-idx 9))))
;; Auto-parse via effect
(effect (fn ()
(let ((parsed (sx-parse source)))
@@ -198,7 +210,9 @@
;; Defer code DOM build until lake exists
(schedule-idle (fn ()
(build-code-dom)
;; Replay to initial step-idx
;; Clear preview and replay to initial step-idx
(let ((preview (get-preview)))
(when preview (dom-set-prop preview "innerHTML" "")))
(let ((target (deref step-idx)))
(reset! step-idx 0)
(set-stack (list (get-preview)))
@@ -213,7 +227,7 @@
;; Controls
(div :class "flex items-center justify-center gap-2 md:gap-3"
(button :on-click (fn (e) (do-back))
:class (str "px-2 py-1 rounded text-lg "
:class (str "px-2 py-1 rounded text-3xl "
(if (> (deref step-idx) 0)
"text-stone-600 hover:text-stone-800 hover:bg-stone-100"
"text-stone-300 cursor-not-allowed"))
@@ -221,7 +235,7 @@
(span :class "text-sm text-stone-500 font-mono tabular-nums"
(deref step-idx) " / " (len (deref steps)))
(button :on-click (fn (e) (do-step))
:class (str "px-2 py-1 rounded text-lg "
:class (str "px-2 py-1 rounded text-3xl "
(if (< (deref step-idx) (len (deref steps)))
"text-violet-600 hover:text-violet-800 hover:bg-violet-50"
"text-violet-300 cursor-not-allowed"))