Delete account/sx/sx_components.py — all rendering now in .sx
Phase 1 of zero-Python rendering: account service. - Auth pages (login, device, check-email) use _render_auth_page() helper calling render_to_sx() + full_page_sx() directly in routes - Newsletter toggle POST renders inline via render_to_sx() - Newsletter page helper returns data dict; defpage :data slot fetches, :content slot renders via ~account-newsletters-content defcomp - Fragment page uses (frag ...) IO primitive directly in .sx - Defpage _eval_slot now uses async_eval_slot_to_sx which expands component bodies server-side (executing IO) but serializes tags as SX - Fix pre-existing OOB ParseError: _eval_slot was producing HTML instead of s-expressions for component content slots - Fix market url_for endpoint: defpage_market_home (app-level, not blueprint) - Fix events calendar nav: wrap multiple SX parts in fragment Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,107 +0,0 @@
|
||||
"""
|
||||
Account service s-expression page components.
|
||||
|
||||
Renders login, device auth, and check-email pages. Dashboard and newsletters
|
||||
are now fully handled by .sx defcomps called from defpage expressions.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
from typing import Any
|
||||
|
||||
from shared.sx.jinja_bridge import load_service_components
|
||||
from shared.sx.helpers import (
|
||||
render_to_sx,
|
||||
root_header_sx, full_page_sx,
|
||||
)
|
||||
|
||||
# Load account-specific .sx components + handlers at import time
|
||||
load_service_components(os.path.dirname(os.path.dirname(__file__)),
|
||||
service_name="account")
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Public API: Auth pages (login, device, check_email)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
async def render_login_page(ctx: dict) -> str:
|
||||
"""Full page: login form."""
|
||||
error = ctx.get("error", "")
|
||||
email = ctx.get("email", "")
|
||||
hdr = await root_header_sx(ctx)
|
||||
content = await render_to_sx("account-login-content",
|
||||
error=error or None, email=email)
|
||||
return await full_page_sx(ctx, header_rows=hdr,
|
||||
content=content,
|
||||
meta_html='<title>Login \u2014 Rose Ash</title>')
|
||||
|
||||
|
||||
async def render_device_page(ctx: dict) -> str:
|
||||
"""Full page: device authorization form."""
|
||||
error = ctx.get("error", "")
|
||||
code = ctx.get("code", "")
|
||||
hdr = await root_header_sx(ctx)
|
||||
content = await render_to_sx("account-device-content",
|
||||
error=error or None, code=code)
|
||||
return await full_page_sx(ctx, header_rows=hdr,
|
||||
content=content,
|
||||
meta_html='<title>Authorize Device \u2014 Rose Ash</title>')
|
||||
|
||||
|
||||
async def render_device_approved_page(ctx: dict) -> str:
|
||||
"""Full page: device approved."""
|
||||
hdr = await root_header_sx(ctx)
|
||||
content = await render_to_sx("account-device-approved")
|
||||
return await full_page_sx(ctx, header_rows=hdr,
|
||||
content=content,
|
||||
meta_html='<title>Device Authorized \u2014 Rose Ash</title>')
|
||||
|
||||
|
||||
async def render_check_email_page(ctx: dict) -> str:
|
||||
"""Full page: check email after magic link sent."""
|
||||
email = ctx.get("email", "")
|
||||
email_error = ctx.get("email_error")
|
||||
hdr = await root_header_sx(ctx)
|
||||
content = await render_to_sx("account-check-email-content",
|
||||
email=email, email_error=email_error)
|
||||
return await full_page_sx(ctx, header_rows=hdr,
|
||||
content=content,
|
||||
meta_html='<title>Check your email \u2014 Rose Ash</title>')
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Public API: Fragment renderers for POST handlers
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
async def render_newsletter_toggle(un) -> str:
|
||||
"""Render a newsletter toggle switch for POST response."""
|
||||
from shared.browser.app.csrf import generate_csrf_token
|
||||
|
||||
nid = un.newsletter_id
|
||||
from quart import g
|
||||
account_url_fn = getattr(g, "_account_url", None)
|
||||
if account_url_fn is None:
|
||||
from shared.infrastructure.urls import account_url
|
||||
account_url_fn = account_url
|
||||
|
||||
toggle_url = account_url_fn(f"/newsletter/{nid}/toggle/")
|
||||
csrf = generate_csrf_token()
|
||||
|
||||
if un.subscribed:
|
||||
bg = "bg-emerald-500"
|
||||
translate = "translate-x-6"
|
||||
checked = "true"
|
||||
else:
|
||||
bg = "bg-stone-300"
|
||||
translate = "translate-x-1"
|
||||
checked = "false"
|
||||
|
||||
return await render_to_sx(
|
||||
"account-newsletter-toggle",
|
||||
id=f"nl-{nid}", url=toggle_url,
|
||||
hdrs=f'{{"X-CSRFToken": "{csrf}"}}',
|
||||
target=f"#nl-{nid}",
|
||||
cls=f"relative inline-flex h-6 w-11 items-center rounded-full transition-colors focus:outline-none focus:ring-2 focus:ring-emerald-500 focus:ring-offset-2 {bg}",
|
||||
checked=checked,
|
||||
knob_cls=f"inline-block h-4 w-4 rounded-full bg-white shadow transform transition-transform {translate}",
|
||||
)
|
||||
Reference in New Issue
Block a user