Move SX construction from Python to .sx defcomps (phases 0-4)
Eliminate Python s-expression string building across account, orders, federation, and cart services. Visual rendering logic now lives entirely in .sx defcomp components; Python files contain only data serialization, header/layout wiring, and thin wrappers that call defcomps. Phase 0: Shared DRY extraction — auth/orders header defcomps, format-decimal/ pluralize/escape/route-prefix primitives. Phase 1: Account — dashboard, newsletters, login/device/check-email content. Phase 2: Orders — order list, detail, filter, checkout return assembled defcomps. Phase 3: Federation — social nav, post cards, timeline, search, actors, notifications, compose, profile assembled defcomps. Phase 4: Cart — overview, page cart items/calendar/tickets/summary, admin, payments assembled defcomps; orders rendering reuses Phase 2 shared defcomps. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -27,28 +27,41 @@ def _register_account_layouts() -> None:
|
||||
|
||||
|
||||
def _account_full(ctx: dict, **kw: Any) -> str:
|
||||
from shared.sx.helpers import root_header_sx, header_child_sx
|
||||
from sx.sx_components import _auth_header_sx
|
||||
from shared.sx.helpers import root_header_sx, header_child_sx, call_url, sx_call, SxExpr
|
||||
|
||||
root_hdr = root_header_sx(ctx)
|
||||
hdr_child = header_child_sx(_auth_header_sx(ctx))
|
||||
auth_hdr = sx_call("auth-header-row",
|
||||
account_url=call_url(ctx, "account_url", ""),
|
||||
select_colours=ctx.get("select_colours", ""),
|
||||
account_nav=_as_sx_nav(ctx),
|
||||
)
|
||||
hdr_child = header_child_sx(auth_hdr)
|
||||
return "(<> " + root_hdr + " " + hdr_child + ")"
|
||||
|
||||
|
||||
def _account_oob(ctx: dict, **kw: Any) -> str:
|
||||
from shared.sx.helpers import root_header_sx
|
||||
from sx.sx_components import _auth_header_sx
|
||||
from shared.sx.helpers import root_header_sx, call_url, sx_call
|
||||
|
||||
return "(<> " + _auth_header_sx(ctx, oob=True) + " " + root_header_sx(ctx, oob=True) + ")"
|
||||
auth_hdr = sx_call("auth-header-row",
|
||||
account_url=call_url(ctx, "account_url", ""),
|
||||
select_colours=ctx.get("select_colours", ""),
|
||||
account_nav=_as_sx_nav(ctx),
|
||||
oob=True,
|
||||
)
|
||||
return "(<> " + auth_hdr + " " + root_header_sx(ctx, oob=True) + ")"
|
||||
|
||||
|
||||
def _account_mobile(ctx: dict, **kw: Any) -> str:
|
||||
from shared.sx.helpers import mobile_menu_sx, mobile_root_nav_sx, sx_call, SxExpr
|
||||
from sx.sx_components import _auth_nav_mobile_sx
|
||||
from shared.sx.helpers import mobile_menu_sx, mobile_root_nav_sx, sx_call, SxExpr, call_url
|
||||
ctx = _inject_account_nav(ctx)
|
||||
nav_items = sx_call("auth-nav-items",
|
||||
account_url=call_url(ctx, "account_url", ""),
|
||||
select_colours=ctx.get("select_colours", ""),
|
||||
account_nav=_as_sx_nav(ctx),
|
||||
)
|
||||
auth_section = sx_call("mobile-menu-section",
|
||||
label="account", href="/", level=1, colour="sky",
|
||||
items=SxExpr(_auth_nav_mobile_sx(ctx)))
|
||||
items=SxExpr(nav_items))
|
||||
return mobile_menu_sx(auth_section, mobile_root_nav_sx(ctx))
|
||||
|
||||
|
||||
@@ -61,6 +74,13 @@ def _inject_account_nav(ctx: dict) -> dict:
|
||||
return ctx
|
||||
|
||||
|
||||
def _as_sx_nav(ctx: dict) -> Any:
|
||||
"""Convert account_nav fragment to SxExpr for use in sx_call."""
|
||||
from shared.sx.helpers import _as_sx
|
||||
ctx = _inject_account_nav(ctx)
|
||||
return _as_sx(ctx.get("account_nav"))
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Page helpers
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -69,22 +89,19 @@ def _register_account_helpers() -> None:
|
||||
from shared.sx.pages import register_page_helpers
|
||||
|
||||
register_page_helpers("account", {
|
||||
"account-content": _h_account_content,
|
||||
"newsletters-content": _h_newsletters_content,
|
||||
"fragment-content": _h_fragment_content,
|
||||
})
|
||||
|
||||
|
||||
def _h_account_content(**kw):
|
||||
from sx.sx_components import _account_main_panel_sx
|
||||
return _account_main_panel_sx({})
|
||||
|
||||
|
||||
async def _h_newsletters_content(**kw):
|
||||
"""Fetch newsletter data, return assembled defcomp call."""
|
||||
from quart import g
|
||||
from sqlalchemy import select
|
||||
from shared.models import UserNewsletter
|
||||
from shared.models.ghost_membership_entities import GhostNewsletter
|
||||
from shared.sx.helpers import sx_call, SxExpr
|
||||
from shared.sx.parser import serialize
|
||||
|
||||
result = await g.s.execute(
|
||||
select(GhostNewsletter).order_by(GhostNewsletter.name)
|
||||
@@ -102,20 +119,21 @@ async def _h_newsletters_content(**kw):
|
||||
for nl in all_newsletters:
|
||||
un = user_subs.get(nl.id)
|
||||
newsletter_list.append({
|
||||
"newsletter": nl,
|
||||
"un": un,
|
||||
"newsletter": {"id": nl.id, "name": nl.name, "description": nl.description},
|
||||
"un": {"newsletter_id": un.newsletter_id, "subscribed": un.subscribed} if un else None,
|
||||
"subscribed": un.subscribed if un else False,
|
||||
})
|
||||
|
||||
if not newsletter_list:
|
||||
from shared.sx.helpers import sx_call
|
||||
return sx_call("account-newsletter-empty")
|
||||
from sx.sx_components import _newsletters_panel_sx
|
||||
ctx = {"account_url": getattr(g, "_account_url", None)}
|
||||
if ctx["account_url"] is None:
|
||||
from shared.infrastructure.urls import account_url
|
||||
ctx["account_url"] = account_url
|
||||
return _newsletters_panel_sx(ctx, newsletter_list)
|
||||
account_url = getattr(g, "_account_url", None)
|
||||
if account_url is None:
|
||||
from shared.infrastructure.urls import account_url as _account_url
|
||||
account_url = _account_url
|
||||
# Call account_url to get the base URL string
|
||||
account_url_str = account_url("") if callable(account_url) else str(account_url or "")
|
||||
|
||||
return sx_call("account-newsletters-content",
|
||||
newsletter_list=SxExpr(serialize(newsletter_list)),
|
||||
account_url=account_url_str)
|
||||
|
||||
|
||||
async def _h_fragment_content(slug=None, **kw):
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
:path "/"
|
||||
:auth :login
|
||||
:layout :account
|
||||
:content (account-content))
|
||||
:content (~account-dashboard-content))
|
||||
|
||||
;; ---------------------------------------------------------------------------
|
||||
;; Newsletters
|
||||
|
||||
Reference in New Issue
Block a user