Reactive code view stepper for home page
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 25s
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 25s
- Imperative code view with syntax colouring matching highlight.py - Token step indices aligned with split-tag (16 steps) - Component spreads (~cssx/tw) dimmed, not highlighted - Evaluated tokens bold+larger, current amber bg+largest, future faint - Lakes for DOM preview and code view (survive reactive re-renders) - dom-stack as signal (persists across re-renders) - schedule-idle for initial code DOM build + step replay - post-render hooks flush CSSX after each event handler - Self-registering spec defines (js-emit-define emits PRIMITIVES[]) - Generic render hooks replace flush-cssx-to-dom in spec - Fix nil→NIL in platform JS, fix append semantics Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
(defisland ~home/stepper ()
|
||||
(let ((source "(div (~cssx/tw :tokens \"p-6 rounded-lg border border-stone-200 bg-white 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\")))")
|
||||
(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\")))")
|
||||
(steps (signal (list)))
|
||||
(step-idx (signal 0))
|
||||
(step-idx (signal 9))
|
||||
(dom-stack-sig (signal (list)))
|
||||
(code-tokens (signal (list)))
|
||||
(code-spans (list)))
|
||||
@@ -60,19 +60,35 @@
|
||||
(is-comp (and (= (type-of head) "symbol") (starts-with? (symbol-name head) "~")))
|
||||
(open-step (get step-ref "v")))
|
||||
(append! tokens {"text" "(" "cls" "text-stone-400" "step" open-step})
|
||||
(when (or is-tag is-comp)
|
||||
(dict-set! step-ref "v" (+ (get step-ref "v") 1)))
|
||||
(build-code-tokens head tokens step-ref indent)
|
||||
(when is-tag
|
||||
(dict-set! step-ref "v" (+ (get step-ref "v") 1)))
|
||||
(for-each (fn (a)
|
||||
(let ((is-child (and (list? a) (not (empty? a))
|
||||
(= (type-of (first a)) "symbol")
|
||||
(or (is-html-tag? (symbol-name (first a)))
|
||||
(starts-with? (symbol-name (first a)) "~")))))
|
||||
(if (and is-tag is-child)
|
||||
(do (append! tokens {"text" (str "\n" (join "" (map (fn (_) " ") (range 0 (+ indent 1))))) "cls" "" "step" -1})
|
||||
(build-code-tokens a tokens step-ref (+ indent 1)))
|
||||
(do (append! tokens {"text" " " "cls" "" "step" -1})
|
||||
(build-code-tokens a tokens step-ref indent)))))
|
||||
(starts-with? (symbol-name (first a)) "~"))))
|
||||
(is-spread (and (list? a) (not (empty? a))
|
||||
(= (type-of (first a)) "symbol")
|
||||
(starts-with? (symbol-name (first a)) "~"))))
|
||||
(if is-spread
|
||||
;; Component spread: save counter, process, restore
|
||||
;; All tokens inside share parent open-step
|
||||
(let ((saved (get step-ref "v"))
|
||||
(saved-tokens-len (len tokens)))
|
||||
(append! tokens {"text" " " "cls" "" "step" -1})
|
||||
(build-code-tokens a tokens step-ref indent)
|
||||
;; Mark all tokens added during spread as spread tokens
|
||||
(let mark-loop ((j saved-tokens-len))
|
||||
(when (< j (len tokens))
|
||||
(dict-set! (nth tokens j) "spread" true)
|
||||
(mark-loop (+ j 1))))
|
||||
(dict-set! step-ref "v" saved))
|
||||
(if (and is-tag is-child)
|
||||
(do (append! tokens {"text" (str "\n" (join "" (map (fn (_) " ") (range 0 (+ indent 1))))) "cls" "" "step" -1})
|
||||
(build-code-tokens a tokens step-ref (+ indent 1)))
|
||||
(do (append! tokens {"text" " " "cls" "" "step" -1})
|
||||
(build-code-tokens a tokens step-ref indent))))))
|
||||
(rest expr))
|
||||
(append! tokens {"text" ")" "cls" "text-stone-400" "step" (if is-tag (get step-ref "v") open-step)})
|
||||
(when is-tag
|
||||
@@ -97,7 +113,7 @@
|
||||
(dom-set-attr sp "class" (get tok "cls"))
|
||||
(dom-set-prop sp "textContent" (get tok "text"))
|
||||
(dom-append code-el sp)
|
||||
(append! code-spans (dict "el" sp "step" (get tok "step") "cls" (get tok "cls")))))
|
||||
(append! code-spans (dict "el" sp "step" (get tok "step") "cls" (get tok "cls") "spread" (get tok "spread")))))
|
||||
(deref code-tokens)))))))
|
||||
(update-code-highlight (fn ()
|
||||
(let ((cur (deref step-idx)))
|
||||
@@ -108,10 +124,13 @@
|
||||
(when (not (= step-num -1))
|
||||
(dom-set-attr el "class"
|
||||
(str base
|
||||
(let ((is-spread (get s "spread")))
|
||||
(cond
|
||||
(= step-num cur) " bg-violet-100 rounded px-0.5 font-bold"
|
||||
(< step-num cur) " font-bold text-lg"
|
||||
:else " opacity-40"))))))
|
||||
(and (= step-num cur) is-spread) " opacity-60"
|
||||
(= step-num cur) " bg-amber-100 rounded px-0.5 font-bold text-sm"
|
||||
(and (< step-num cur) is-spread) " opacity-60"
|
||||
(< step-num cur) " font-bold text-xs"
|
||||
:else " opacity-40")))))))
|
||||
code-spans))))
|
||||
(do-step (fn ()
|
||||
(build-code-dom)
|
||||
@@ -179,13 +198,20 @@
|
||||
;; Defer code DOM build until lake exists
|
||||
(schedule-idle (fn ()
|
||||
(build-code-dom)
|
||||
(update-code-highlight))))))))
|
||||
;; Replay to initial step-idx
|
||||
(let ((target (deref step-idx)))
|
||||
(reset! step-idx 0)
|
||||
(set-stack (list (get-preview)))
|
||||
(for-each (fn (_) (do-step)) (slice (deref steps) 0 target)))
|
||||
(update-code-highlight)
|
||||
(run-post-render-hooks))))))))
|
||||
(div :class "space-y-4"
|
||||
;; Code view lake — spans built imperatively, classes updated on step
|
||||
(lake :id "code-view" :tag "pre"
|
||||
:class "text-sm font-mono bg-stone-50 rounded p-4 overflow-x-auto leading-relaxed")
|
||||
(div (~cssx/tw :tokens "font-mono bg-stone-50 rounded p-2 overflow-x-auto leading-relaxed whitespace-pre-wrap")
|
||||
:style "font-size:0.5rem"
|
||||
(lake :id "code-view"))
|
||||
;; Controls
|
||||
(div :class "flex items-center justify-center gap-3"
|
||||
(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 "
|
||||
(if (> (deref step-idx) 0)
|
||||
|
||||
Reference in New Issue
Block a user