host: blog pages as SX trees + render-page (no embedded HTML)
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 18s

The handler runs the dynamic logic in the full evaluator and builds a static SX
element tree via quasiquote; render-page (5.1) renders it. No aser pipeline
needed for server-rendered pages. host/blog--page is now an (html (head..)(body..))
tree; home builds the posts <ul> via map+quasiquote; the post body is rendered
per-block then injected with (raw! ...); /new is an SX form tree. Only the
doctype prefix remains as a string (render-to-html doesn't emit it). 181/181.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-19 20:56:05 +00:00
parent 962cb1b43e
commit c16924a991

View File

@@ -84,57 +84,80 @@
(join "" (map host/blog--render-node (rest tree))))
(else (host/blog--render-node tree))))
(str "<p>(empty post)</p>")))))
;; ── page shell ──────────────────────────────────────────────────────
;; A page is an SX element tree, rendered via render-page (5.1). The handler
;; builds the tree (running any dynamic logic in the full evaluator, e.g. a posts
;; loop) and render-page renders the static result — no embedded HTML strings,
;; only the doctype prefix render-to-html doesn't emit. `body` is an SX node.
(define host/blog--page
(fn (title body)
(str "<!doctype html><meta charset=\"utf-8\"><title>" title "</title>" body)))
(str "<!doctype html>"
(render-page
(quasiquote
(html
(head (meta :charset "utf-8") (title (unquote title)))
(body (unquote body))))))))
;; ── read handlers ───────────────────────────────────────────────────
;; Post body is rendered per-block (a guarded HTML string) then injected raw.
(define host/blog-post
(fn (req)
(let ((slug (dream-param req "slug")))
(let ((r (host/blog-get slug)))
(if r
(dream-html
(host/blog--page (get r :title) (host/blog-render r)))
(host/blog--page (get r :title)
(quasiquote (article (raw! (unquote (host/blog-render r)))))))
(dream-html-status 404
(host/blog--page "Not found"
(str "<h1>404</h1><p>No published post: " slug "</p>"))))))))
(quasiquote
(div (h1 "404")
(p (unquote (str "No published post: " slug))))))))))))
(define host/blog--li
(fn (acc p)
(str acc "<li><a href=\"/" (get p :slug) "/\">" (get p :title) "</a></li>")))
(define host/blog-home
(fn (req)
(let ((posts (host/blog-list)))
(dream-html
(host/blog--page "Blog"
(str "<h1>Posts</h1>"
(if (> (len posts) 0)
(str "<ul>" (reduce host/blog--li "" posts) "</ul>")
"<p>No posts yet.</p>")
"<p><a href=\"/new\">+ New post</a></p>"))))))
(let ((items
(map
(fn (p)
(quasiquote
(li (a :href (unquote (str "/" (get p :slug) "/"))
(unquote (get p :title))))))
posts)))
(let ((listing (if (> (len posts) 0)
(list (quote ul) items)
(quote (p "No posts yet.")))))
(dream-html
(host/blog--page "Blog"
(quasiquote
(div (h1 "Posts")
(unquote listing)
(p (a :href "/new" "+ New post")))))))))))
(define host/blog-index (fn (req) (host/ok (host/blog-list))))
;; ── create page (GET /new) — clean minimal form ────────────────────
;; A plain create form: title + sx_content (SX element markup) + status. No
;; legacy JS editor, no external assets, no shims. The rich WYSIWYG is a future
;; native SX-island editor served via the Phase-5.2 SSR pipeline (render-page
;; alone can't render dynamic-logic component bodies — proven). Posts to /new.
;; ── create page (GET /new) — clean minimal form as an SX tree ───────
;; No legacy JS editor, no external assets, no shims. The rich WYSIWYG is a
;; future native SX-island editor (Phase 5.2+). Posts to /new.
(define host/blog-new-form
(fn (req)
(dream-html
(host/blog--page "New post"
(str
"<h1>New post</h1>"
"<form method=\"post\" action=\"/new\">"
"<p><input name=\"title\" placeholder=\"Title\" style=\"font-size:1.4em;width:100%\"></p>"
"<p><textarea name=\"sx_content\" rows=\"12\" style=\"width:100%;font-family:monospace\" "
"placeholder=\"(p &quot;Your post as SX markup&quot;)\"></textarea></p>"
"<p><select name=\"status\"><option value=\"draft\">Draft</option>"
"<option value=\"published\">Published</option></select> "
"<button type=\"submit\">Publish</button></p>"
"</form><p><a href=\"/\">&larr; all posts</a></p>")))))
(quasiquote
(div
(h1 "New post")
(form :method "post" :action "/new"
(p (input :name "title" :placeholder "Title"
:style "font-size:1.4em;width:100%"))
(p (textarea :name "sx_content" :rows "12"
:style "width:100%;font-family:monospace"
:placeholder "(p \"Your post as SX markup\")"))
(p (select :name "status"
(option :value "draft" "Draft")
(option :value "published" "Published"))
" "
(button :type "submit" "Publish")))
(p (a :href "/" "all posts"))))))))
;; ── write handlers ──────────────────────────────────────────────────
;; POST /new — form-urlencoded ingest (the editor's submit shape: title,