Add Specs section, Reflexive Web essay, fix highlight and dev caching

- Fix highlight() returning SxExpr so syntax-highlighted code renders
  as DOM elements instead of leaking SX source text into the page
- Add Specs section that reads and displays canonical SX spec files
  from shared/sx/ref/ with syntax highlighting
- Add "The Reflexive Web" essay on SX becoming a complete LISP with
  AI as native participant
- Change logo from (<x>) to (<sx>) everywhere
- Unify all backgrounds to bg-stone-100, center code blocks
- Skip component/style cookie cache in dev mode so .sx edits are
  visible immediately on refresh without clearing localStorage

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-05 11:49:05 +00:00
parent 6fa843016b
commit 7ecbf19c11
14 changed files with 319 additions and 73 deletions

View File

@@ -2,24 +2,24 @@
(defcomp ~example-card (&key title description &rest children)
(div :class "border border-stone-200 rounded-lg overflow-hidden"
(div :class "bg-stone-50 px-4 py-3 border-b border-stone-200"
(div :class "bg-stone-100 px-4 py-3 border-b border-stone-200"
(h3 :class "font-semibold text-stone-800" title)
(when description
(p :class "text-sm text-stone-500 mt-1" description)))
(div :class "p-4" children)))
(defcomp ~example-demo (&key &rest children)
(div :class "border border-dashed border-stone-300 rounded p-4 bg-white" children))
(div :class "border border-dashed border-stone-300 rounded p-4 bg-stone-100" children))
(defcomp ~example-source (&key code)
(div :class "bg-stone-50 border border-stone-200 rounded p-4 mt-3 overflow-x-auto"
(pre :class "text-sm" (code code))))
(div :class "bg-stone-100 rounded p-5 mt-3 mx-auto max-w-3xl"
(pre :class "text-sm leading-relaxed whitespace-pre-wrap break-words" (code code))))
;; --- Click to load demo ---
(defcomp ~click-to-load-demo ()
(div :class "space-y-4"
(div :id "click-result" :class "p-4 rounded bg-stone-50 text-stone-500 text-center"
(div :id "click-result" :class "p-4 rounded bg-stone-100 text-stone-500 text-center"
"Click the button to load content.")
(button
:sx-get "/examples/api/click"
@@ -50,7 +50,7 @@
(button :type "submit"
:class "px-4 py-2 bg-violet-600 text-white rounded hover:bg-violet-700 transition-colors text-sm"
"Submit"))
(div :id "form-result" :class "p-3 rounded bg-stone-50 text-stone-500 text-sm text-center"
(div :id "form-result" :class "p-3 rounded bg-stone-100 text-stone-500 text-sm text-center"
"Submit the form to see the result.")))
(defcomp ~form-result (&key name)
@@ -66,7 +66,7 @@
:sx-get "/examples/api/poll"
:sx-trigger "load, every 2s"
:sx-swap "innerHTML"
:class "p-4 rounded border border-stone-200 bg-white text-center font-mono"
:class "p-4 rounded border border-stone-200 bg-stone-100 text-center font-mono"
"Loading...")))
(defcomp ~poll-result (&key time count)
@@ -145,10 +145,10 @@
(defcomp ~oob-demo ()
(div :class "space-y-4"
(div :class "grid grid-cols-2 gap-4"
(div :id "oob-box-a" :class "p-4 rounded border border-stone-200 bg-white text-center"
(div :id "oob-box-a" :class "p-4 rounded border border-stone-200 bg-stone-100 text-center"
(p :class "text-stone-500" "Box A")
(p :class "text-sm text-stone-400" "Waiting..."))
(div :id "oob-box-b" :class "p-4 rounded border border-stone-200 bg-white text-center"
(div :id "oob-box-b" :class "p-4 rounded border border-stone-200 bg-stone-100 text-center"
(p :class "text-stone-500" "Box B")
(p :class "text-sm text-stone-400" "Waiting...")))
(button
@@ -167,7 +167,7 @@
:sx-get "/examples/api/lazy"
:sx-trigger "load"
:sx-swap "innerHTML"
:class "p-6 rounded border border-stone-200 bg-stone-50 text-center"
:class "p-6 rounded border border-stone-200 bg-stone-100 text-center"
(div :class "animate-pulse space-y-2"
(div :class "h-4 bg-stone-200 rounded w-3/4 mx-auto")
(div :class "h-4 bg-stone-200 rounded w-1/2 mx-auto")))))
@@ -328,7 +328,7 @@
(p :class "text-sm text-stone-400" "Messages will appear here."))))
(defcomp ~reset-message (&key message time)
(div :class "px-3 py-2 bg-stone-50 rounded text-sm text-stone-700"
(div :class "px-3 py-2 bg-stone-100 rounded text-sm text-stone-700"
(str "[" time "] " message)))
;; --- Edit row demo ---
@@ -488,7 +488,7 @@
:sx-swap "innerHTML"
:class "px-3 py-1.5 bg-stone-600 text-white rounded text-sm hover:bg-stone-700"
"Full Dashboard"))
(div :id "filter-target" :class "border border-stone-200 rounded p-4 bg-white"
(div :id "filter-target" :class "border border-stone-200 rounded p-4 bg-stone-100"
(p :class "text-sm text-stone-400" "Click a button to load content."))))
;; --- Tabs demo ---
@@ -525,7 +525,7 @@
:sx-swap "innerHTML"
:class "px-4 py-2 bg-violet-600 text-white rounded hover:bg-violet-700 transition-colors text-sm"
"Load with animation")
(div :id "anim-target" :class "p-4 rounded border border-stone-200 bg-white text-center"
(div :id "anim-target" :class "p-4 rounded border border-stone-200 bg-stone-100 text-center"
(p :class "text-stone-400" "Content will fade in here."))))
(defcomp ~anim-result (&key color time)
@@ -552,7 +552,7 @@
:sx-get "/examples/api/dialog/close"
:sx-target "#dialog-container"
:sx-swap "innerHTML")
(div :class "relative bg-white rounded-lg shadow-xl p-6 max-w-md w-full mx-4 space-y-4"
(div :class "relative bg-stone-100 rounded-lg shadow-xl p-6 max-w-md w-full mx-4 space-y-4"
(h3 :class "text-lg font-semibold text-stone-800" title)
(p :class "text-stone-600" message)
(div :class "flex justify-end gap-2"
@@ -573,23 +573,23 @@
(defcomp ~keyboard-shortcuts-demo ()
(div :class "space-y-4"
(div :class "p-4 rounded border border-stone-200 bg-stone-50"
(div :class "p-4 rounded border border-stone-200 bg-stone-100"
(p :class "text-sm text-stone-600 font-medium mb-2" "Keyboard shortcuts:")
(div :class "flex gap-4"
(div :class "flex items-center gap-1"
(kbd :class "px-2 py-0.5 bg-white border border-stone-300 rounded text-xs font-mono" "s")
(kbd :class "px-2 py-0.5 bg-stone-100 border border-stone-300 rounded text-xs font-mono" "s")
(span :class "text-sm text-stone-500" "Search"))
(div :class "flex items-center gap-1"
(kbd :class "px-2 py-0.5 bg-white border border-stone-300 rounded text-xs font-mono" "n")
(kbd :class "px-2 py-0.5 bg-stone-100 border border-stone-300 rounded text-xs font-mono" "n")
(span :class "text-sm text-stone-500" "New item"))
(div :class "flex items-center gap-1"
(kbd :class "px-2 py-0.5 bg-white border border-stone-300 rounded text-xs font-mono" "h")
(kbd :class "px-2 py-0.5 bg-stone-100 border border-stone-300 rounded text-xs font-mono" "h")
(span :class "text-sm text-stone-500" "Help"))))
(div :id "kbd-target"
:sx-get "/examples/api/keyboard?key=s"
:sx-trigger "keyup[key=='s'&&!event.target.matches('input,textarea')] from:body"
:sx-swap "innerHTML"
:class "p-4 rounded border border-stone-200 bg-white text-center"
:class "p-4 rounded border border-stone-200 bg-stone-100 text-center"
(p :class "text-stone-400 text-sm" "Press a shortcut key..."))
(div :sx-get "/examples/api/keyboard?key=n"
:sx-trigger "keyup[key=='n'&&!event.target.matches('input,textarea')] from:body"
@@ -675,7 +675,7 @@
(button :type "submit"
:class "px-4 py-2 bg-violet-600 text-white rounded hover:bg-violet-700 transition-colors text-sm"
"Submit as JSON"))
(div :id "json-result" :class "p-3 rounded bg-stone-50 text-stone-500 text-sm"
(div :id "json-result" :class "p-3 rounded bg-stone-100 text-stone-500 text-sm"
"Submit the form to see the server echo the parsed JSON.")))
(defcomp ~json-result (&key body content-type)
@@ -697,7 +697,7 @@
:sx-vals "{\"source\": \"button\", \"version\": \"2.0\"}"
:class "px-4 py-2 bg-violet-600 text-white rounded hover:bg-violet-700 transition-colors text-sm"
"Send with vals")
(div :id "vals-result" :class "p-3 rounded bg-stone-50 text-sm text-stone-400"
(div :id "vals-result" :class "p-3 rounded bg-stone-100 text-sm text-stone-400"
"Click to see server-received values."))
(div :class "space-y-2"
(h4 :class "text-sm font-semibold text-stone-700" "sx-headers — send custom headers")
@@ -708,7 +708,7 @@
:sx-headers {:X-Custom-Token "abc123" :X-Request-Source "demo"}
:class "px-4 py-2 bg-violet-600 text-white rounded hover:bg-violet-700 transition-colors text-sm"
"Send with headers")
(div :id "headers-result" :class "p-3 rounded bg-stone-50 text-sm text-stone-400"
(div :id "headers-result" :class "p-3 rounded bg-stone-100 text-sm text-stone-400"
"Click to see server-received headers."))))
(defcomp ~echo-result (&key label items)
@@ -729,7 +729,7 @@
:class "sx-loading-btn px-4 py-2 bg-violet-600 text-white rounded hover:bg-violet-700 transition-colors text-sm flex items-center gap-2"
(span :class "sx-spinner w-4 h-4 border-2 border-white/30 border-t-white rounded-full animate-spin")
(span "Load slow endpoint"))
(div :id "loading-result" :class "p-4 rounded border border-stone-200 bg-white text-center"
(div :id "loading-result" :class "p-4 rounded border border-stone-200 bg-stone-100 text-center"
(p :class "text-stone-400 text-sm" "Click the button — it takes 2 seconds."))))
(defcomp ~loading-result (&key time)
@@ -749,7 +749,7 @@
:sx-sync "replace"
:placeholder "Type to search (random delay 0.5-2s)..."
:class "w-full px-3 py-2 border border-stone-300 rounded text-sm focus:outline-none focus:ring-2 focus:ring-violet-500")
(div :id "sync-result" :class "p-4 rounded border border-stone-200 bg-white"
(div :id "sync-result" :class "p-4 rounded border border-stone-200 bg-stone-100"
(p :class "text-sm text-stone-400" "Type to trigger requests — stale ones get aborted."))))
(defcomp ~sync-result (&key query delay)
@@ -768,7 +768,7 @@
:sx-retry "exponential:1000:8000"
:class "px-4 py-2 bg-violet-600 text-white rounded hover:bg-violet-700 transition-colors text-sm"
"Call flaky endpoint")
(div :id "retry-result" :class "p-4 rounded border border-stone-200 bg-white text-center"
(div :id "retry-result" :class "p-4 rounded border border-stone-200 bg-stone-100 text-center"
(p :class "text-stone-400 text-sm" "Endpoint fails twice, succeeds on 3rd attempt."))))
(defcomp ~retry-result (&key attempt message)