Persist home stepper state to localStorage via freeze scope
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 11m28s
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:
@@ -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 ---
|
||||
|
||||
|
||||
@@ -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 ---
|
||||
|
||||
|
||||
@@ -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"))
|
||||
|
||||
Reference in New Issue
Block a user