Send all responses as sexp wire format with client-side rendering
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 5m35s
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 5m35s
- 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:
@@ -24,38 +24,38 @@
|
||||
(span :class "inline-block px-2 py-0.5 rounded-full text-xs font-medium bg-sky-100 text-sky-700" name))
|
||||
|
||||
(defcomp ~events-entry-time-linked (&key href date-str)
|
||||
(<> (a :href href :class "hover:text-stone-700" date-str) (raw! " · ")))
|
||||
(<> (a :href href :class "hover:text-stone-700" date-str) " · "))
|
||||
|
||||
(defcomp ~events-entry-time-plain (&key date-str)
|
||||
(<> (span date-str) (raw! " · ")))
|
||||
(<> (span date-str) " · "))
|
||||
|
||||
(defcomp ~events-entry-cost (&key cost-html)
|
||||
(div :class "mt-1 text-sm font-medium text-green-600" (raw! cost-html)))
|
||||
(defcomp ~events-entry-cost (&key cost)
|
||||
(div :class "mt-1 text-sm font-medium text-green-600" cost))
|
||||
|
||||
(defcomp ~events-entry-card (&key title-html badges-html time-parts cost-html widget-html)
|
||||
(defcomp ~events-entry-card (&key title badges time-parts cost widget)
|
||||
(article :class "rounded-xl bg-white shadow-sm border border-stone-200 p-4"
|
||||
(div :class "flex flex-col sm:flex-row sm:items-start justify-between gap-3"
|
||||
(div :class "flex-1 min-w-0"
|
||||
(raw! title-html)
|
||||
(div :class "flex flex-wrap items-center gap-1.5 mt-1" (raw! badges-html))
|
||||
(div :class "mt-1 text-sm text-stone-500" (raw! time-parts))
|
||||
(raw! cost-html))
|
||||
(raw! widget-html))))
|
||||
title
|
||||
(div :class "flex flex-wrap items-center gap-1.5 mt-1" badges)
|
||||
(div :class "mt-1 text-sm text-stone-500" time-parts)
|
||||
cost)
|
||||
widget)))
|
||||
|
||||
(defcomp ~events-entry-card-tile (&key title-html badges-html time-html cost-html widget-html)
|
||||
(defcomp ~events-entry-card-tile (&key title badges time cost widget)
|
||||
(article :class "rounded-xl bg-white shadow-sm border border-stone-200 overflow-hidden"
|
||||
(div :class "p-3"
|
||||
(raw! title-html)
|
||||
(div :class "flex flex-wrap items-center gap-1 mt-1" (raw! badges-html))
|
||||
(div :class "mt-1 text-xs text-stone-500" (raw! time-html))
|
||||
(raw! cost-html))
|
||||
(raw! widget-html)))
|
||||
title
|
||||
(div :class "flex flex-wrap items-center gap-1 mt-1" badges)
|
||||
(div :class "mt-1 text-xs text-stone-500" time)
|
||||
cost)
|
||||
widget))
|
||||
|
||||
(defcomp ~events-entry-tile-widget-wrapper (&key widget-html)
|
||||
(div :class "border-t border-stone-100 px-3 py-2" (raw! widget-html)))
|
||||
(defcomp ~events-entry-tile-widget-wrapper (&key widget)
|
||||
(div :class "border-t border-stone-100 px-3 py-2" widget))
|
||||
|
||||
(defcomp ~events-entry-widget-wrapper (&key widget-html)
|
||||
(div :class "shrink-0" (raw! widget-html)))
|
||||
(defcomp ~events-entry-widget-wrapper (&key widget)
|
||||
(div :class "shrink-0" widget))
|
||||
|
||||
(defcomp ~events-date-separator (&key date-str)
|
||||
(div :class "pt-2 pb-1"
|
||||
@@ -63,7 +63,7 @@
|
||||
|
||||
(defcomp ~events-sentinel (&key page next-url)
|
||||
(div :id (str "sentinel-" page) :class "h-4 opacity-0 pointer-events-none"
|
||||
:hx-get next-url :hx-trigger "intersect once delay:250ms" :hx-swap "outerHTML"
|
||||
:sx-get next-url :sx-trigger "intersect once delay:250ms" :sx-swap "outerHTML"
|
||||
:role "status" :aria-hidden "true"
|
||||
(div :class "text-center text-xs text-stone-400" "loading...")))
|
||||
|
||||
@@ -80,24 +80,24 @@
|
||||
|
||||
(defcomp ~events-view-toggle (&key list-href tile-href hx-select list-active tile-active list-svg tile-svg)
|
||||
(div :class "hidden md:flex justify-end px-3 pt-3 gap-1"
|
||||
(a :href list-href :hx-get list-href :hx-target "#main-panel" :hx-select hx-select
|
||||
:hx-swap "outerHTML" :hx-push-url "true"
|
||||
(a :href list-href :sx-get list-href :sx-target "#main-panel" :sx-select hx-select
|
||||
:sx-swap "outerHTML" :sx-push-url "true"
|
||||
:class (str "p-1.5 rounded " list-active) :title "List view"
|
||||
:_ "on click js localStorage.removeItem('events_view') end"
|
||||
(raw! list-svg))
|
||||
(a :href tile-href :hx-get tile-href :hx-target "#main-panel" :hx-select hx-select
|
||||
:hx-swap "outerHTML" :hx-push-url "true"
|
||||
list-svg)
|
||||
(a :href tile-href :sx-get tile-href :sx-target "#main-panel" :sx-select hx-select
|
||||
:sx-swap "outerHTML" :sx-push-url "true"
|
||||
:class (str "p-1.5 rounded " tile-active) :title "Tile view"
|
||||
:_ "on click js localStorage.setItem('events_view','tile') end"
|
||||
(raw! tile-svg))))
|
||||
tile-svg)))
|
||||
|
||||
(defcomp ~events-grid (&key grid-cls cards-html)
|
||||
(div :class grid-cls (raw! cards-html)))
|
||||
(defcomp ~events-grid (&key grid-cls cards)
|
||||
(div :class grid-cls cards))
|
||||
|
||||
(defcomp ~events-empty ()
|
||||
(div :class "px-3 py-12 text-center text-stone-400"
|
||||
(i :class "fa fa-calendar-xmark text-4xl mb-3" :aria-hidden "true")
|
||||
(p :class "text-lg" "No upcoming events")))
|
||||
|
||||
(defcomp ~events-main-panel-body (&key toggle-html body-html)
|
||||
(<> (raw! toggle-html) (raw! body-html) (div :class "pb-8")))
|
||||
(defcomp ~events-main-panel-body (&key toggle body)
|
||||
(<> toggle body (div :class "pb-8")))
|
||||
|
||||
Reference in New Issue
Block a user