Add syntax highlighting to spreads page code blocks

Use (highlight "..." "lisp") page helper instead of raw strings
for ~docs/code :code values.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-13 10:44:09 +00:00
parent 9d0bd3b0e7
commit 98036b2292

View File

@@ -22,12 +22,9 @@
(p "A spread is a value type. " (code "make-spread") " creates one from a dict of "
"attributes. When the renderer encounters a spread as a child of an element, "
"it merges the attrs onto the parent element instead of appending a DOM node.")
(~docs/code :code "(defcomp ~highlight (&key colour)
(make-spread {\"class\" (str \"highlight-\" colour)
\"data-highlight\" colour}))")
(~docs/code :code (highlight "(defcomp ~highlight (&key colour)\n (make-spread {\"class\" (str \"highlight-\" colour)\n \"data-highlight\" colour}))" "lisp"))
(p "Use it as a child of any element:")
(~docs/code :code "(div (~highlight :colour \"yellow\")
\"This div gets class=highlight-yellow\")")
(~docs/code :code (highlight "(div (~highlight :colour \"yellow\")\n \"This div gets class=highlight-yellow\")" "lisp"))
(p (code "class") " values are appended (space-joined). "
(code "style") " values are appended (semicolon-joined). "
"All other attributes overwrite."))
@@ -35,13 +32,7 @@
(~docs/subsection :title "2. collect! / collected / clear-collected!"
(p "Render-time accumulators. Values are collected into named buckets "
"during rendering and retrieved at flush points. Deduplication is automatic.")
(~docs/code :code ";; Deep inside a component tree:
(collect! \"cssx\" \".sx-bg-red-500{background-color:hsl(0,72%,53%)}\")
;; At the flush point (once, in the layout):
(let ((rules (collected \"cssx\")))
(clear-collected! \"cssx\")
(raw! (str \"<style>\" (join \"\" rules) \"</style>\")))")
(~docs/code :code (highlight ";; Deep inside a component tree:\n(collect! \"cssx\" \".sx-bg-red-500{background-color:hsl(0,72%,53%)}\")\n\n;; At the flush point (once, in the layout):\n(let ((rules (collected \"cssx\")))\n (clear-collected! \"cssx\")\n (raw! (str \"<style>\" (join \"\" rules) \"</style>\")))" "lisp"))
(p "This is upward communication through the render tree: "
"a deeply nested component contributes a CSS rule, and the layout "
"emits all accumulated rules as a single " (code "<style>") " tag. "
@@ -51,11 +42,7 @@
(p "Inside an island, when a spread's value depends on signals, "
(code "reactive-spread") " tracks signal dependencies and surgically "
"updates the parent element's attributes when signals change.")
(~docs/code :code "(defisland ~themed-card ()
(let ((theme (signal \"violet\")))
(div (~cssx/tw :tokens (str \"bg-\" (deref theme) \"-500 p-4\"))
(button :on-click (fn (e) (reset! theme \"rose\"))
\"change theme\"))))")
(~docs/code :code (highlight "(defisland ~themed-card ()\n (let ((theme (signal \"violet\")))\n (div (~cssx/tw :tokens (str \"bg-\" (deref theme) \"-500 p-4\"))\n (button :on-click (fn (e) (reset! theme \"rose\"))\n \"change theme\"))))" "lisp"))
(p "When " (code "theme") " changes from " (code "\"violet\"") " to "
(code "\"rose\"") ":")
(ul :class "list-disc pl-5 space-y-1 text-stone-600"
@@ -111,18 +98,7 @@
(~docs/section :title "CSSX: the first application" :id "cssx"
(p (code "~cssx/tw") " is a component that uses all three primitives:")
(~docs/code :code "(defcomp ~cssx/tw (tokens)
(let ((token-list (filter (fn (t) (not (= t \"\")))
(split (or tokens \"\") \" \")))
(results (map cssx-process-token token-list))
(valid (filter (fn (r) (not (nil? r))) results))
(classes (map (fn (r) (get r \"cls\")) valid))
(rules (map (fn (r) (get r \"rule\")) valid))
(_ (for-each (fn (rule) (collect! \"cssx\" rule)) rules)))
(if (empty? classes)
nil
(make-spread {\"class\" (join \" \" classes)
\"data-tw\" (or tokens \"\")}))))")
(~docs/code :code (highlight "(defcomp ~cssx/tw (tokens)\n (let ((token-list (filter (fn (t) (not (= t \"\")))\n (split (or tokens \"\") \" \")))\n (results (map cssx-process-token token-list))\n (valid (filter (fn (r) (not (nil? r))) results))\n (classes (map (fn (r) (get r \"cls\")) valid))\n (rules (map (fn (r) (get r \"rule\")) valid))\n (_ (for-each (fn (rule) (collect! \"cssx\" rule)) rules)))\n (if (empty? classes)\n nil\n (make-spread {\"class\" (join \" \" classes)\n \"data-tw\" (or tokens \"\")}))))" "lisp"))
(p "It's a regular " (code "defcomp") ". It uses " (code "make-spread") " to "
"inject classes onto its parent, " (code "collect!") " to accumulate CSS rules "
"for batch flushing, and when called inside an island with signal-dependent "
@@ -141,15 +117,7 @@
(~docs/section :title "Semantic style variables" :id "variables"
(p "Because " (code "~cssx/tw") " returns a spread, and spreads are values, "
"you can bind them to names:")
(~docs/code :code ";; Define once
(define heading-style (~cssx/tw :tokens \"text-violet-700 text-2xl font-bold\"))
(define nav-link (~cssx/tw :tokens \"text-stone-500 text-sm\"))
(define card-base (~cssx/tw :tokens \"bg-stone-50 rounded-lg p-4\"))
;; Use everywhere
(div card-base
(h1 heading-style \"Title\")
(a nav-link :href \"/\" \"Home\"))")
(~docs/code :code (highlight ";; Define once\n(define heading-style (~cssx/tw :tokens \"text-violet-700 text-2xl font-bold\"))\n(define nav-link (~cssx/tw :tokens \"text-stone-500 text-sm\"))\n(define card-base (~cssx/tw :tokens \"bg-stone-50 rounded-lg p-4\"))\n\n;; Use everywhere\n(div card-base\n (h1 heading-style \"Title\")\n (a nav-link :href \"/\" \"Home\"))" "lisp"))
(p "These are semantic names wrapping utility tokens. Change the definition, "
"every use updates. No build step, no CSS-in-JS runtime. Just " (code "define") ".")
(p "Namespacing prevents clashes \u2014 " (code "~app/heading") " vs "
@@ -194,24 +162,7 @@
(p (code "provide") " creates a named scope with a value (downward) and an accumulator (upward). "
(code "context") " reads the value. " (code "emit!") " appends to the accumulator. "
(code "emitted") " retrieves accumulated values.")
(~docs/code :code ";; Downward: theme context
(provide \"theme\" {:primary \"violet\" :font \"serif\"}
(h1 :style (str \"color:\" (get (context \"theme\") :primary))
\"Themed heading\"))
;; Upward: script accumulation (like collect!)
(provide \"scripts\" nil
(div
(emit! \"scripts\" \"analytics.js\")
(div (emit! \"scripts\" \"charts.js\") \"chart\"))
(for-each (fn (s) (script :src s)) (emitted \"scripts\")))
;; Both at once
(provide \"page\" {:title \"Home\"}
(h1 (context \"page\" :title))
(emit! \"page\" {:meta \"og:title\" :content \"Home\"})
(for-each (fn (m) (meta :name (get m :meta) :content (get m :content)))
(emitted \"page\")))"))
(~docs/code :code (highlight ";; Downward: theme context\n(provide \"theme\" {:primary \"violet\" :font \"serif\"}\n (h1 :style (str \"color:\" (get (context \"theme\") :primary))\n \"Themed heading\"))\n\n;; Upward: script accumulation (like collect!)\n(provide \"scripts\" nil\n (div\n (emit! \"scripts\" \"analytics.js\")\n (div (emit! \"scripts\" \"charts.js\") \"chart\"))\n (for-each (fn (s) (script :src s)) (emitted \"scripts\")))\n\n;; Both at once\n(provide \"page\" {:title \"Home\"}\n (h1 (context \"page\" :title))\n (emit! \"page\" {:meta \"og:title\" :content \"Home\"})\n (for-each (fn (m) (meta :name (get m :meta) :content (get m :content)))\n (emitted \"page\")))" "lisp")))
(~docs/subsection :title "What this means"
(p "Three mechanisms collapse into one:")