Merge worktree-typed into macros: defcomp type annotations

This commit is contained in:
2026-03-11 21:02:12 +00:00
parent 477ce766ff
commit 95ffc0ecb7
6 changed files with 98 additions and 45 deletions

View File

@@ -2,7 +2,9 @@
(defcomp ~sx-home-content ()
(div :id "main-content" :class "max-w-3xl mx-auto px-4 py-6"
(~doc-code :code (highlight (component-source "~sx-header") "lisp"))))
(~doc-code :code (highlight (component-source "~sx-header") "lisp"))
(~doc-code :code (highlight (component-source "~video-player") "lisp"))
(~doc-code :code (highlight (component-source "~video-embed") "lisp"))))
(defcomp ~docs-introduction-content ()
(~doc-page :title "Introduction"

View File

@@ -45,8 +45,8 @@
(reset! shade (+ 400 (* (mod (* (deref idx) 137) 5) 50)))))
;; Only fetch video if none loaded (marsh: reactive + conditional hypermedia)
(let ((embed (dom-query-by-id "video-embed")))
(when (not (dom-first-child embed))
(dom-dispatch (get e "currentTarget") "fetch-video" (dict)))))
(when (not (dom-get-prop embed "firstChild"))
(dom-dispatch (dom-get-prop e "currentTarget") "fetch-video" {}))))
:sx-get "/api/random-video"
:sx-target "#video-embed"
:sx-swap "innerHTML"
@@ -66,9 +66,8 @@
;; navigations. Content swapped in via sx-get from the reactive word click.
;; Empty initially (zero height). Iframe provides height when loaded.
(defisland ~video-player ()
(div :style "display:flex;justify-content:center;"
(div :id "video-embed"
:style "position:relative;width:66%;max-width:20rem;")))
(div :id "video-embed"
:style "position:relative;width:20rem;max-width:66vw;"))
;; @css grid grid-cols-3
@@ -151,7 +150,8 @@
;; Video island — preserved across navigation morphs (like ~sx-header).
;; Outside logo-opacity so it doesn't fade.
;; Marsh demo: reactive click triggers hypermedia fetch, result lands here.
(~video-player)
;; Island renders as inline <span>; force it to block so margin:auto centers.
(div :style "display:flex;justify-content:center;" (~video-player))
;; Sibling arrows for EVERY level in the trail
;; Trail row i is level (i+2) of depth — opacity = (i+2)/depth
;; Last row (leaf) gets is-leaf for larger current page title

View File

@@ -1,18 +1,34 @@
;; SX docs — home page components
;; YouTube embed — rendered client-side from video ID returned by /api/random-video.
;; Marsh demo: the server picks the video (hypermedia), the island triggers the fetch (reactive).
;; YouTube video embed — rendered client-side from video ID returned by /api/random-video.
;; Marsh demo: server picks video (hypermedia), island controls playback (reactive).
;; Play/pause uses YouTube postMessage API via dom-call-method — no iframe reload.
(defcomp ~video-embed (&key video-id)
(<>
(button
:sx-get "/api/clear-video" :sx-target "#video-embed"
:sx-swap "innerHTML"
:style "position:absolute;top:-0.5rem;right:-0.5rem;width:1.25rem;height:1.25rem;border-radius:50%;border:none;background:rgba(0,0,0,0.5);color:white;font-size:0.75rem;line-height:1;cursor:pointer;display:flex;align-items:center;justify-content:center;z-index:10;"
"x")
(iframe :src (str "https://www.youtube.com/embed/" video-id "?autoplay=1&mute=1")
:allow "accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
:allowfullscreen "true"
:style "width:100%;aspect-ratio:16/9;border-radius:0.5rem;border:none;")))
(let ((playing (signal true)))
(<>
;; Close button — clears via hypermedia
(button
:sx-get "/api/clear-video" :sx-target "#video-embed"
:sx-swap "innerHTML"
:style "position:absolute;top:-0.5rem;right:-0.5rem;width:1.25rem;height:1.25rem;border-radius:50%;border:none;background:rgba(0,0,0,0.5);color:white;font-size:0.75rem;line-height:1;cursor:pointer;display:flex;align-items:center;justify-content:center;z-index:10;"
"x")
;; Play/pause button — reactive signal toggles YouTube via postMessage
(button
:on-click (fn (e)
(let ((iframe (dom-query "#video-iframe"))
(win (dom-get-prop iframe "contentWindow"))
(cmd (if (deref playing) "pauseVideo" "playVideo")))
(dom-call-method win "postMessage"
(str "{\"event\":\"command\",\"func\":\"" cmd "\",\"args\":[]}")
"https://www.youtube.com")
(reset! playing (not (deref playing)))))
:style "position:absolute;top:1rem;right:-0.5rem;width:1.25rem;height:1.25rem;border-radius:50%;border:none;background:rgba(0,0,0,0.5);color:white;font-size:0.75rem;line-height:1;cursor:pointer;display:flex;align-items:center;justify-content:center;z-index:10;"
(if (deref playing) "||" ">"))
;; Iframe — stays in DOM, playback controlled via postMessage
(iframe :id "video-iframe"
:src (str "https://www.youtube.com/embed/" video-id "?autoplay=1&enablejsapi=1&controls=0&modestbranding=1&rel=0")
:allow "accelerometer; autoplay; encrypted-media"
:style "width:100%;aspect-ratio:16/9;border-radius:0.5rem;border:none;pointer-events:none;"))))
(defcomp ~sx-hero (&key &rest children)
(div :class "max-w-4xl mx-auto px-6 py-16 text-center"