Add admin preview views + fix markdown converter
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 5m31s
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 5m31s
- Fix _markdown() in lexical_to_sx.py: render markdown to HTML with mistune.html() before storing in ~kg-html - Add shared/sx/prettify.py: sx_to_pretty_sx and json_to_pretty_sx produce sx AST for syntax-highlighted DOM (uses canonical serialize()) - Add preview tab to admin header nav - Add GET /preview/ route with 4 views: prettified sx, prettified lexical JSON, sx rendered HTML, lexical rendered HTML - Add ~blog-preview-panel and ~blog-preview-section components - Add syntax highlight CSS for sx/JSON tokens Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -142,3 +142,30 @@
|
||||
(defcomp ~blog-tag-group-edit-main (&key edit-form delete-form)
|
||||
(div :class "max-w-2xl mx-auto px-4 py-6 space-y-6"
|
||||
edit-form delete-form))
|
||||
|
||||
;; Preview panel components
|
||||
|
||||
(defcomp ~blog-preview-panel (&key sections)
|
||||
(div :class "max-w-4xl mx-auto px-4 py-6 space-y-4"
|
||||
(style "
|
||||
.sx-pretty, .json-pretty { font-family: monospace; font-size: 12px; line-height: 1.6; white-space: pre-wrap; }
|
||||
.sx-list, .json-obj, .json-arr { display: block; }
|
||||
.sx-paren { color: #64748b; }
|
||||
.sx-sym { color: #0369a1; }
|
||||
.sx-kw { color: #7c3aed; }
|
||||
.sx-str { color: #15803d; }
|
||||
.sx-num { color: #c2410c; }
|
||||
.sx-bool { color: #b91c1c; font-weight: 600; }
|
||||
.json-brace, .json-bracket { color: #64748b; }
|
||||
.json-key { color: #7c3aed; }
|
||||
.json-str { color: #15803d; }
|
||||
.json-num { color: #c2410c; }
|
||||
.json-lit { color: #b91c1c; font-weight: 600; }
|
||||
.json-field { display: block; }
|
||||
")
|
||||
sections))
|
||||
|
||||
(defcomp ~blog-preview-section (&key title content)
|
||||
(details :class "border rounded bg-white"
|
||||
(summary :class "cursor-pointer px-4 py-3 font-medium text-sm bg-stone-100 hover:bg-stone-200 select-none" title)
|
||||
(div :class "p-4 overflow-x-auto text-xs" content)))
|
||||
|
||||
@@ -1377,6 +1377,68 @@ async def render_post_data_oob(ctx: dict) -> str:
|
||||
return oob_page_sx(oobs=admin_hdr_oob, content=content)
|
||||
|
||||
|
||||
# ---- Post preview ----
|
||||
|
||||
def _preview_main_panel_sx(ctx: dict) -> str:
|
||||
"""Build the preview panel with 4 expandable sections."""
|
||||
sections: list[str] = []
|
||||
|
||||
# 1. Prettified SX source
|
||||
sx_pretty = ctx.get("sx_pretty", "")
|
||||
if sx_pretty:
|
||||
sections.append(sx_call("blog-preview-section",
|
||||
title="S-Expression Source",
|
||||
content=SxExpr(sx_pretty),
|
||||
))
|
||||
|
||||
# 2. Prettified Lexical JSON
|
||||
json_pretty = ctx.get("json_pretty", "")
|
||||
if json_pretty:
|
||||
sections.append(sx_call("blog-preview-section",
|
||||
title="Lexical JSON",
|
||||
content=SxExpr(json_pretty),
|
||||
))
|
||||
|
||||
# 3. SX rendered preview
|
||||
sx_rendered = ctx.get("sx_rendered", "")
|
||||
if sx_rendered:
|
||||
rendered_sx = f'(div :class "blog-content prose max-w-none" (raw! {sx_serialize(sx_rendered)}))'
|
||||
sections.append(sx_call("blog-preview-section",
|
||||
title="SX Rendered",
|
||||
content=SxExpr(rendered_sx),
|
||||
))
|
||||
|
||||
# 4. Lexical rendered preview
|
||||
lex_rendered = ctx.get("lex_rendered", "")
|
||||
if lex_rendered:
|
||||
rendered_sx = f'(div :class "blog-content prose max-w-none" (raw! {sx_serialize(lex_rendered)}))'
|
||||
sections.append(sx_call("blog-preview-section",
|
||||
title="Lexical Rendered",
|
||||
content=SxExpr(rendered_sx),
|
||||
))
|
||||
|
||||
if not sections:
|
||||
return '(div :class "p-8 text-stone-500" "No content to preview.")'
|
||||
|
||||
inner = " ".join(sections)
|
||||
return sx_call("blog-preview-panel", sections=SxExpr(f"(<> {inner})"))
|
||||
|
||||
|
||||
async def render_post_preview_page(ctx: dict) -> str:
|
||||
root_hdr = root_header_sx(ctx)
|
||||
post_hdr = _post_header_sx(ctx)
|
||||
admin_hdr = _post_admin_header_sx(ctx, selected="preview")
|
||||
header_rows = "(<> " + root_hdr + " " + post_hdr + " " + admin_hdr + ")"
|
||||
content = _preview_main_panel_sx(ctx)
|
||||
return full_page_sx(ctx, header_rows=header_rows, content=content)
|
||||
|
||||
|
||||
async def render_post_preview_oob(ctx: dict) -> str:
|
||||
admin_hdr_oob = _post_admin_header_sx(ctx, oob=True, selected="preview")
|
||||
content = _preview_main_panel_sx(ctx)
|
||||
return oob_page_sx(oobs=admin_hdr_oob, content=content)
|
||||
|
||||
|
||||
# ---- Post entries ----
|
||||
|
||||
async def render_post_entries_page(ctx: dict) -> str:
|
||||
|
||||
Reference in New Issue
Block a user