Stepper cookie persistence: SSR + client-side save/restore
- Parse Cookie header in OCaml HTTP server for get-cookie primitive - Stepper saves step-idx to cookie via host-set! FFI on click - Stepper restores from cookie: get-cookie on server, host-get FFI on client - Cache key includes stepper cookie value to avoid stale SSR - registerNative: also update Sx_primitives table for CALL_PRIM dispatch Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -2,9 +2,10 @@
|
||||
~home/stepper
|
||||
()
|
||||
(let
|
||||
((source "(div (~cssx/tw :tokens \"text-center\")\n (h1 (~cssx/tw :tokens \"text-3xl font-bold mb-2\")\n (span (~cssx/tw :tokens \"text-rose-500\") \"the \")\n (span (~cssx/tw :tokens \"text-amber-500\") \"joy \")\n (span (~cssx/tw :tokens \"text-emerald-500\") \"of \")\n (span (~cssx/tw :tokens \"text-violet-600 text-4xl\") \"sx\")))")
|
||||
((source "(div (~tw :tokens \"text-center\")\n (h1 (~tw :tokens \"text-3xl font-bold mb-2\")\n (span (~tw :tokens \"text-rose-500\") \"the \")\n (span (~tw :tokens \"text-amber-500\") \"joy \")\n (span (~tw :tokens \"text-emerald-500\") \"of \")\n (span (~tw :tokens \"text-violet-600 text-4xl\") \"sx\")))")
|
||||
(steps (signal (list)))
|
||||
(store (if (client?) (def-store "home-stepper" (fn () {:step-idx (signal 9)})) nil))
|
||||
(store
|
||||
(if (client?) (def-store "home-stepper" (fn () {:step-idx (signal 9)})) nil))
|
||||
(step-idx (if store (get store "step-idx") (signal 9)))
|
||||
(dom-stack-sig (signal (list)))
|
||||
(code-tokens (signal (list))))
|
||||
@@ -204,7 +205,7 @@
|
||||
(= (keyword-name (nth sp 1)) "tokens")
|
||||
(string? (nth sp 2)))
|
||||
(let
|
||||
((result (trampoline (~cssx/tw :tokens (nth sp 2)))))
|
||||
((result (trampoline (~tw :tokens (nth sp 2)))))
|
||||
(when
|
||||
(spread? result)
|
||||
(let
|
||||
@@ -239,7 +240,14 @@
|
||||
(= step-type "expr")
|
||||
nil))
|
||||
(swap! step-idx inc)
|
||||
(update-code-highlight))))
|
||||
(update-code-highlight)
|
||||
(host-set!
|
||||
(dom-document)
|
||||
"cookie"
|
||||
(str
|
||||
"sx-home-stepper="
|
||||
(deref step-idx)
|
||||
";path=/;max-age=31536000;SameSite=Lax")))))
|
||||
(rebuild-preview
|
||||
(fn
|
||||
(target)
|
||||
@@ -266,16 +274,22 @@
|
||||
(rebuild-preview target)
|
||||
(reset! step-idx target)
|
||||
(update-code-highlight)
|
||||
)))))
|
||||
|
||||
(host-set!
|
||||
(dom-document)
|
||||
"cookie"
|
||||
(str
|
||||
"sx-home-stepper="
|
||||
target
|
||||
";path=/;max-age=31536000;SameSite=Lax")))))))
|
||||
(let
|
||||
((saved (get-cookie "sx-home-stepper")))
|
||||
((saved (if (client?) (let ((raw (host-get (dom-document) "cookie")) (prefix "sx-home-stepper=")) (when (and (string? raw) (contains? raw prefix)) (let ((start (+ (index-of raw prefix) (len prefix)))) (let ((rest (slice raw start)) (end-pos (index-of rest ";"))) (if (> end-pos -1) (slice rest 0 end-pos) rest))))) (get-cookie "sx-home-stepper"))))
|
||||
(when
|
||||
saved
|
||||
(thaw-from-sx saved)
|
||||
(when
|
||||
(or (< (deref step-idx) 0) (> (deref step-idx) 16))
|
||||
(reset! step-idx 9))))
|
||||
(string? saved)
|
||||
(let
|
||||
((n (parse-number saved)))
|
||||
(when
|
||||
(and (number? n) (>= n 0) (<= n 16))
|
||||
(reset! step-idx n)))))
|
||||
(let
|
||||
((parsed (sx-parse source)))
|
||||
(when
|
||||
@@ -292,10 +306,10 @@
|
||||
(let
|
||||
((_eff (effect (fn () (schedule-idle (fn () (build-code-dom) (rebuild-preview (deref step-idx)) (update-code-highlight) (run-post-render-hooks)))))))
|
||||
(div
|
||||
:class "space-y-4"
|
||||
(~tw :tokens "space-y-4 text-center")
|
||||
(div
|
||||
:data-code-view true
|
||||
(~cssx/tw
|
||||
(~tw
|
||||
:tokens "font-mono bg-stone-50 rounded p-2 overflow-x-auto leading-relaxed whitespace-pre-wrap")
|
||||
:style "font-size:0.5rem"
|
||||
(map
|
||||
@@ -319,12 +333,9 @@
|
||||
(span :class cls (get tok "text"))))
|
||||
(deref code-tokens)))
|
||||
(div
|
||||
:class "flex items-center justify-center gap-2 md:gap-3"
|
||||
(~tw :tokens "flex items-center justify-center gap-2 md:gap-3")
|
||||
(button
|
||||
:on-click (fn
|
||||
(e)
|
||||
(do-back)
|
||||
)
|
||||
:on-click (fn (e) (do-back))
|
||||
:class (str
|
||||
"px-2 py-1 rounded text-3xl "
|
||||
(if
|
||||
@@ -333,15 +344,12 @@
|
||||
"text-stone-300 cursor-not-allowed"))
|
||||
"◀")
|
||||
(span
|
||||
:class "text-sm text-stone-500 font-mono tabular-nums"
|
||||
(~tw :tokens "text-sm text-stone-500 font-mono tabular-nums")
|
||||
(deref step-idx)
|
||||
" / "
|
||||
(len (deref steps)))
|
||||
(button
|
||||
:on-click (fn
|
||||
(e)
|
||||
(do-step)
|
||||
)
|
||||
:on-click (fn (e) (do-step))
|
||||
:class (str
|
||||
"px-2 py-1 rounded text-3xl "
|
||||
(if
|
||||
|
||||
Reference in New Issue
Block a user