Send all responses as sexp wire format with client-side rendering
- Server sends sexp source text, client (sexp.js) renders everything - SexpExpr marker class for nested sexp composition in serialize() - sexp_page() HTML shell with data-mount="body" for full page loads - sexp_response() returns text/sexp for OOB/partial responses - ~app-body layout component replaces ~app-layout (no raw!) - ~rich-text is the only component using raw! (for CMS HTML content) - Fragment endpoints return text/sexp, auto-wrapped in SexpExpr - All _*_html() helpers converted to _*_sexp() returning sexp source - Head auto-hoist: sexp.js moves meta/title/link/script[ld+json] from rendered body to document.head automatically - Unknown components render warning box instead of crashing page - Component kwargs preserve AST for lazy rendering (fixes <> in kwargs) - Fix unterminated paren in events/sexp/tickets.sexpr Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -19,11 +19,11 @@
|
||||
|
||||
(defcomp ~test-filter-card (&key href label count colour-border colour-bg colour-text active)
|
||||
(a :href href
|
||||
:hx-get href
|
||||
:hx-target "#main-panel"
|
||||
:hx-select "#main-panel"
|
||||
:hx-swap "outerHTML"
|
||||
:hx-push-url "true"
|
||||
:sx-get href
|
||||
:sx-target "#main-panel"
|
||||
:sx-select "#main-panel"
|
||||
:sx-swap "outerHTML"
|
||||
:sx-push-url "true"
|
||||
:class (str "block rounded border p-3 text-center transition-colors no-underline hover:opacity-80 "
|
||||
colour-border " " colour-bg " "
|
||||
(if active "ring-2 ring-offset-1 ring-stone-500 " ""))
|
||||
@@ -79,11 +79,11 @@
|
||||
"bg-orange-50"))))
|
||||
(td :class "px-3 py-2 text-sm font-mono text-stone-700 max-w-0 truncate" :title nodeid
|
||||
(a :href (str "/test/" nodeid)
|
||||
:hx-get (str "/test/" nodeid)
|
||||
:hx-target "#main-panel"
|
||||
:hx-select "#main-panel"
|
||||
:hx-swap "outerHTML"
|
||||
:hx-push-url "true"
|
||||
:sx-get (str "/test/" nodeid)
|
||||
:sx-target "#main-panel"
|
||||
:sx-select "#main-panel"
|
||||
:sx-swap "outerHTML"
|
||||
:sx-push-url "true"
|
||||
:class "hover:underline hover:text-sky-600"
|
||||
nodeid))
|
||||
(td :class "px-3 py-2 text-center"
|
||||
@@ -97,7 +97,7 @@
|
||||
(td :class "px-3 py-2 text-sm text-rose-600 font-mono max-w-xs truncate" :title longrepr
|
||||
(when longrepr longrepr))))
|
||||
|
||||
(defcomp ~test-results-table (&key rows-html has-failures)
|
||||
(defcomp ~test-results-table (&key rows has-failures)
|
||||
(div :class "overflow-x-auto rounded border border-stone-200 bg-white"
|
||||
(table :class "w-full text-left"
|
||||
(thead
|
||||
@@ -106,7 +106,7 @@
|
||||
(th :class "px-3 py-2 text-xs font-medium text-stone-600 text-center w-24" "Status")
|
||||
(th :class "px-3 py-2 text-xs font-medium text-stone-600 text-right w-20" "Time")
|
||||
(th :class "px-3 py-2 text-xs font-medium text-stone-600 w-48" "Error")))
|
||||
(tbody (raw! rows-html)))))
|
||||
(tbody (when rows rows)))))
|
||||
|
||||
(defcomp ~test-running-indicator ()
|
||||
(div :class "flex items-center justify-center py-12 text-stone-500"
|
||||
@@ -124,11 +124,11 @@
|
||||
(div :class "space-y-6 p-4"
|
||||
(div :class "flex items-center gap-3"
|
||||
(a :href "/"
|
||||
:hx-get "/"
|
||||
:hx-target "#main-panel"
|
||||
:hx-select "#main-panel"
|
||||
:hx-swap "outerHTML"
|
||||
:hx-push-url "true"
|
||||
:sx-get "/"
|
||||
:sx-target "#main-panel"
|
||||
:sx-select "#main-panel"
|
||||
:sx-swap "outerHTML"
|
||||
:sx-push-url "true"
|
||||
:class "text-sky-600 hover:text-sky-800 text-sm"
|
||||
"← Back to results")
|
||||
(span :class (str "inline-flex items-center rounded-full border px-2 py-0.5 text-xs font-medium "
|
||||
|
||||
Reference in New Issue
Block a user