host: /new mounts the real WYSIWYG editor (sx-editor.js), 181/181
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 24s

Replace the plain textarea at GET /new with the real Ghost/Koenig-style block
editor (shared/static/scripts/sx-editor.js): a #sx-editor mount point + hidden
sx_content field + title + status; on submit getSx() fills sx_content and POSTs
to /new (the proven ingest). Assets (sx-browser.js, sx-editor.js, editor.css)
referenced from the docs static host (sx.rose-ash.com/static/scripts) — STOPGAP
hardcoded URLs pending an asset-manifest (Phase 5.2) and a native SX-island
editor. SxEditor.mount({}) is safe (all opts guarded); getSx() needs no SX
runtime. Wiring + assets + mount-safety validated; browser mount needs visual
check (no Playwright in this worktree).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-19 20:19:12 +00:00
parent 70759d6ab1
commit 11bb8c058c

View File

@@ -98,21 +98,40 @@
(define host/blog-index (fn (req) (host/ok (host/blog-list))))
;; ── create form (GET /new) — minimal chrome; the SX editor posts here too ──
;; ── create page (GET /new) — the real WYSIWYG block editor ──────────
;; Mounts the self-contained sx-editor.js (Ghost/Koenig-style block editor) that
;; serializes the visual edit to `sx_content`. Assets (sx-browser.js for Sx.parse,
;; sx-editor.js, editor.css) are referenced from the docs static host
;; (sx.rose-ash.com/static/scripts) — no host static-serving needed. On submit the
;; handle's getSx() fills the hidden sx_content field, then it POSTs to /new.
;; (This reuses the legacy JS editor; a native SX-island editor is the future.)
(define host/blog--asset "https://sx.rose-ash.com/static/scripts")
(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%\" "
"placeholder=\"(article (h1 &quot;Title&quot;) (p &quot;Body&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>")))))
(str
"<!doctype html><html><head><meta charset=\"utf-8\"><title>New post</title>"
"<link rel=\"stylesheet\" href=\"" host/blog--asset "/editor.css\">"
"<style>body{max-width:768px;margin:2rem auto;padding:0 1rem;font-family:system-ui}"
"#title-input{width:100%;font-size:1.9em;font-weight:700;border:none;outline:none;margin:.5rem 0}"
".bar{display:flex;gap:1rem;align-items:center;margin-top:1.5rem;border-top:1px solid #eee;padding-top:1rem}</style>"
"</head><body>"
"<form id=\"post-new-form\" method=\"post\" action=\"/new\">"
"<input id=\"title-input\" name=\"title\" placeholder=\"Post title\" autocomplete=\"off\">"
"<input type=\"hidden\" id=\"sx-content-input\" name=\"sx_content\" value=\"\">"
"<div id=\"sx-editor\"></div>"
"<div class=\"bar\">"
"<select name=\"status\"><option value=\"draft\">Draft</option>"
"<option value=\"published\" selected>Published</option></select>"
"<button type=\"submit\">Publish</button>"
"<a href=\"/\">all posts</a></div>"
"</form>"
"<script src=\"" host/blog--asset "/sx-browser.js\"></script>"
"<script src=\"" host/blog--asset "/sx-editor.js\"></script>"
"<script>(function(){var h=SxEditor.mount('sx-editor',{});"
"document.getElementById('post-new-form').addEventListener('submit',function(){"
"document.getElementById('sx-content-input').value=h.getSx();});})();</script>"
"</body></html>"))))
;; ── write handlers ──────────────────────────────────────────────────
;; POST /new — form-urlencoded ingest (the editor's submit shape: title,