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:
@@ -6,13 +6,13 @@
|
||||
(div :class "font-medium truncate" name)
|
||||
(div :class "text-xs text-stone-600 truncate" time-str))))
|
||||
|
||||
(defcomp ~events-day-entries-nav (&key inner-html)
|
||||
(defcomp ~events-day-entries-nav (&key inner)
|
||||
(div :class "flex flex-col sm:flex-row sm:items-center gap-2 border-r border-stone-200 mr-2 sm:max-w-2xl"
|
||||
:id "day-entries-nav-wrapper"
|
||||
(div :class "flex overflow-x-auto gap-1 scrollbar-thin"
|
||||
(raw! inner-html))))
|
||||
inner)))
|
||||
|
||||
(defcomp ~events-day-table (&key list-container rows-html pre-action add-url)
|
||||
(defcomp ~events-day-table (&key list-container rows pre-action add-url)
|
||||
(section :id "day-entries" :class list-container
|
||||
(table :class "w-full text-sm border table-fixed"
|
||||
(thead :class "bg-stone-100"
|
||||
@@ -23,10 +23,10 @@
|
||||
(th :class "text-left p-2 w-1/6" "Cost")
|
||||
(th :class "text-left p-2 w-1/6" "Tickets")
|
||||
(th :class "text-left p-2 w-1/6" "Actions")))
|
||||
(tbody (raw! rows-html)))
|
||||
(tbody rows))
|
||||
(div :id "entry-add-container" :class "mt-4"
|
||||
(button :type "button" :class pre-action
|
||||
:hx-get add-url :hx-target "#entry-add-container" :hx-swap "innerHTML"
|
||||
:sx-get add-url :sx-target "#entry-add-container" :sx-swap "innerHTML"
|
||||
"+ Add entry"))))
|
||||
|
||||
(defcomp ~events-day-empty-row ()
|
||||
@@ -34,20 +34,20 @@
|
||||
|
||||
(defcomp ~events-day-row-name (&key href pill-cls name)
|
||||
(td :class "p-2 align-top w-2/6" (div :class "font-medium"
|
||||
(a :href href :class pill-cls :hx-get href :hx-target "#main-panel" :hx-select "#main-panel"
|
||||
:hx-swap "outerHTML" :hx-push-url "true" name))))
|
||||
(a :href href :class pill-cls :sx-get href :sx-target "#main-panel" :sx-select "#main-panel"
|
||||
:sx-swap "outerHTML" :sx-push-url "true" name))))
|
||||
|
||||
(defcomp ~events-day-row-slot (&key href pill-cls slot-name time-str)
|
||||
(td :class "p-2 align-top w-1/6" (div :class "text-xs font-medium"
|
||||
(a :href href :class pill-cls :hx-get href :hx-target "#main-panel" :hx-select "#main-panel"
|
||||
:hx-swap "outerHTML" :hx-push-url "true" slot-name)
|
||||
(span :class "text-stone-600 font-normal" (raw! time-str)))))
|
||||
(a :href href :class pill-cls :sx-get href :sx-target "#main-panel" :sx-select "#main-panel"
|
||||
:sx-swap "outerHTML" :sx-push-url "true" slot-name)
|
||||
(span :class "text-stone-600 font-normal" time-str))))
|
||||
|
||||
(defcomp ~events-day-row-time (&key start end)
|
||||
(td :class "p-2 align-top w-1/6" (div :class "text-xs text-stone-600" (str start end))))
|
||||
|
||||
(defcomp ~events-day-row-state (&key state-id badge-html)
|
||||
(td :class "p-2 align-top w-1/6" (div :id state-id (raw! badge-html))))
|
||||
(defcomp ~events-day-row-state (&key state-id badge)
|
||||
(td :class "p-2 align-top w-1/6" (div :id state-id badge)))
|
||||
|
||||
(defcomp ~events-day-row-cost (&key cost-str)
|
||||
(td :class "p-2 align-top w-1/6" (span :class "font-medium text-green-600" cost-str)))
|
||||
@@ -63,19 +63,19 @@
|
||||
(defcomp ~events-day-row-actions ()
|
||||
(td :class "p-2 align-top w-1/6"))
|
||||
|
||||
(defcomp ~events-day-row (&key tr-cls name-html slot-html state-html cost-html tickets-html actions-html)
|
||||
(tr :class tr-cls (raw! name-html) (raw! slot-html) (raw! state-html) (raw! cost-html) (raw! tickets-html) (raw! actions-html)))
|
||||
(defcomp ~events-day-row (&key tr-cls name slot state cost tickets actions)
|
||||
(tr :class tr-cls name slot state cost tickets actions))
|
||||
|
||||
(defcomp ~events-day-admin-panel ()
|
||||
(div :class "p-4 text-sm text-stone-500" "Admin options"))
|
||||
|
||||
(defcomp ~events-day-entries-nav-oob-empty ()
|
||||
(div :id "day-entries-nav-wrapper" :hx-swap-oob "true"))
|
||||
(div :id "day-entries-nav-wrapper" :sx-swap-oob "true"))
|
||||
|
||||
(defcomp ~events-day-entries-nav-oob (&key items-html)
|
||||
(defcomp ~events-day-entries-nav-oob (&key items)
|
||||
(div :class "flex flex-col sm:flex-row sm:items-center gap-2 border-r border-stone-200 mr-2 sm:max-w-2xl"
|
||||
:id "day-entries-nav-wrapper" :hx-swap-oob "true"
|
||||
(div :class "flex overflow-x-auto gap-1 scrollbar-thin" (raw! items-html))))
|
||||
:id "day-entries-nav-wrapper" :sx-swap-oob "true"
|
||||
(div :class "flex overflow-x-auto gap-1 scrollbar-thin" items)))
|
||||
|
||||
(defcomp ~events-day-nav-entry (&key href nav-btn name time-str)
|
||||
(a :href href :class nav-btn
|
||||
|
||||
Reference in New Issue
Block a user