Phase 5 cleanup: remove legacy HTML components, fix nav-tree fragment
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 1m43s
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 1m43s
- Remove old raw! layout components (~app-head, ~app-layout, ~oob-response, ~header-row, ~menu-row, ~oob-header, ~header-child) from layout.sexp - Convert nav-tree fragment from Jinja HTML to sexp source, fixing the "Unexpected character: ." parse error caused by HTML leaking into sexp - Add _as_sexp() helper to safely coerce HTML fragments to ~rich-text - Fix federation/sexp/search.sexpr extra closing paren - Remove dead _html() wrappers from blog and account sexp_components - Remove stale render import from cart sexp_components - Add dev_watcher.py to auto-reload on .sexp/.sexpr/.js/.css changes - Add test_parse_all.py to parse-check all 59 sexpr/sexp files - Fix test assertions for sx- attribute prefix (was hx-) - Add sexp.js version logging for cache debugging Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -36,19 +36,36 @@ def get_asset_url(ctx: dict) -> str:
|
||||
# Sexp-native helper functions — return sexp source (not HTML)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def _as_sexp(val: Any) -> SexpExpr | None:
|
||||
"""Coerce a fragment value to SexpExpr.
|
||||
|
||||
If *val* is already a ``SexpExpr`` (from a ``text/sexp`` fragment),
|
||||
return it as-is. If it's a non-empty string (HTML from a
|
||||
``text/html`` fragment), wrap it in ``~rich-text``. Otherwise
|
||||
return ``None``.
|
||||
"""
|
||||
if not val:
|
||||
return None
|
||||
if isinstance(val, SexpExpr):
|
||||
return val
|
||||
html = str(val)
|
||||
escaped = html.replace("\\", "\\\\").replace('"', '\\"')
|
||||
return SexpExpr(f'(~rich-text :html "{escaped}")')
|
||||
|
||||
|
||||
def root_header_sexp(ctx: dict, *, oob: bool = False) -> str:
|
||||
"""Build the root header row as a sexp call string."""
|
||||
rights = ctx.get("rights") or {}
|
||||
is_admin = rights.get("admin") if isinstance(rights, dict) else getattr(rights, "admin", False)
|
||||
settings_url = call_url(ctx, "blog_url", "/settings/") if is_admin else ""
|
||||
return sexp_call("header-row-sx",
|
||||
cart_mini=ctx.get("cart_mini") and SexpExpr(str(ctx.get("cart_mini"))),
|
||||
cart_mini=_as_sexp(ctx.get("cart_mini")),
|
||||
blog_url=call_url(ctx, "blog_url", ""),
|
||||
site_title=ctx.get("base_title", ""),
|
||||
app_label=ctx.get("app_label", ""),
|
||||
nav_tree=ctx.get("nav_tree") and SexpExpr(str(ctx.get("nav_tree"))),
|
||||
auth_menu=ctx.get("auth_menu") and SexpExpr(str(ctx.get("auth_menu"))),
|
||||
nav_panel=ctx.get("nav_panel") and SexpExpr(str(ctx.get("nav_panel"))),
|
||||
nav_tree=_as_sexp(ctx.get("nav_tree")),
|
||||
auth_menu=_as_sexp(ctx.get("auth_menu")),
|
||||
nav_panel=_as_sexp(ctx.get("nav_panel")),
|
||||
settings_url=settings_url,
|
||||
is_admin=is_admin,
|
||||
oob=oob,
|
||||
@@ -285,19 +302,6 @@ def sexp_response(source_or_component: str, status: int = 200,
|
||||
return resp
|
||||
|
||||
|
||||
def oob_page(ctx: dict, *, oobs_html: str = "",
|
||||
filter_html: str = "", aside_html: str = "",
|
||||
content_html: str = "", menu_html: str = "") -> str:
|
||||
"""Render an OOB response with standard swap targets."""
|
||||
return render(
|
||||
"oob-response",
|
||||
oobs_html=oobs_html,
|
||||
filter_html=filter_html,
|
||||
aside_html=aside_html,
|
||||
menu_html=menu_html,
|
||||
content_html=content_html,
|
||||
)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Sexp wire-format full page shell
|
||||
|
||||
Reference in New Issue
Block a user