Replace env free-variable threading with IO-primitive auto-fetch macros
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 1m38s

Layout components now self-resolve context (cart-mini, auth-menu, nav-tree,
rights, URLs) via new IO primitives (root-header-ctx, select-colours,
account-nav-ctx, app-rights) and defmacro wrappers (~root-header-auto,
~auth-header-row-auto, ~root-mobile-auto). This eliminates _ctx_to_env(),
HELPER_CSS_CLASSES, and verbose :key threading across all 10 services.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-04 18:20:57 +00:00
parent 8be00df6d9
commit 7fda7a8027
41 changed files with 551 additions and 523 deletions

View File

@@ -24,3 +24,10 @@
(div :id (str "entry-title-" entry-id) :class "flex gap-1 items-center"
title times))
(defcomp ~events-slot-label (&key name description)
(div :class "flex flex-col md:flex-row md:gap-2 items-center"
(div :class "flex flex-row items-center gap-2"
(i :class "fa fa-clock")
(div :class "shrink-0" name))
(p :class "text-stone-500 whitespace-pre-line break-all w-full" description)))

View File

@@ -1,13 +1,11 @@
;; Events layout defcomps — root header from env free variables,
;; Events layout defcomps — root header via ~root-header-auto,
;; events-specific headers passed as &key params.
;; --- Calendar admin layout: root + post + child(admin + cal + cal-admin) ---
(defcomp ~events-cal-admin-layout-full (&key post-header admin-header
calendar-header calendar-admin-header)
(<> (~root-header :cart-mini cart-mini :blog-url blog-url :site-title site-title
:app-label app-label :nav-tree nav-tree :auth-menu auth-menu
:nav-panel nav-panel :settings-url settings-url :is-admin is-admin)
(<> (~root-header-auto)
post-header
(~header-child-sx :inner (<> admin-header calendar-header calendar-admin-header))))
@@ -23,9 +21,7 @@
(defcomp ~events-slot-layout-full (&key post-header admin-header
calendar-header calendar-admin-header slot-header)
(<> (~root-header :cart-mini cart-mini :blog-url blog-url :site-title site-title
:app-label app-label :nav-tree nav-tree :auth-menu auth-menu
:nav-panel nav-panel :settings-url settings-url :is-admin is-admin)
(<> (~root-header-auto)
post-header
(~header-child-sx :inner (<> admin-header calendar-header calendar-admin-header slot-header))))
@@ -36,9 +32,7 @@
(defcomp ~events-day-admin-layout-full (&key post-header admin-header
calendar-header day-header day-admin-header)
(<> (~root-header :cart-mini cart-mini :blog-url blog-url :site-title site-title
:app-label app-label :nav-tree nav-tree :auth-menu auth-menu
:nav-panel nav-panel :settings-url settings-url :is-admin is-admin)
(<> (~root-header-auto)
post-header
(~header-child-sx :inner (<> admin-header calendar-header day-header day-admin-header))))
@@ -48,9 +42,7 @@
;; --- Entry layout: root + child(post + cal + day + entry) ---
(defcomp ~events-entry-layout-full (&key post-header calendar-header day-header entry-header)
(<> (~root-header :cart-mini cart-mini :blog-url blog-url :site-title site-title
:app-label app-label :nav-tree nav-tree :auth-menu auth-menu
:nav-panel nav-panel :settings-url settings-url :is-admin is-admin)
(<> (~root-header-auto)
(~header-child-sx :inner (<> post-header calendar-header day-header entry-header))))
(defcomp ~events-entry-layout-oob (&key day-oob entry-oob-wrap clear-oob)
@@ -61,9 +53,7 @@
(defcomp ~events-entry-admin-layout-full (&key post-header admin-header
calendar-header day-header
entry-header entry-admin-header)
(<> (~root-header :cart-mini cart-mini :blog-url blog-url :site-title site-title
:app-label app-label :nav-tree nav-tree :auth-menu auth-menu
:nav-panel nav-panel :settings-url settings-url :is-admin is-admin)
(<> (~root-header-auto)
post-header
(~header-child-sx :inner (<> admin-header calendar-header day-header
entry-header entry-admin-header))))
@@ -76,9 +66,7 @@
(defcomp ~events-ticket-types-layout-full (&key post-header calendar-header day-header
entry-header entry-admin-header
ticket-types-header)
(<> (~root-header :cart-mini cart-mini :blog-url blog-url :site-title site-title
:app-label app-label :nav-tree nav-tree :auth-menu auth-menu
:nav-panel nav-panel :settings-url settings-url :is-admin is-admin)
(<> (~root-header-auto)
(~header-child-sx :inner (<> post-header calendar-header day-header
entry-header entry-admin-header ticket-types-header))))
@@ -90,9 +78,7 @@
(defcomp ~events-ticket-type-layout-full (&key post-header calendar-header day-header
entry-header entry-admin-header
ticket-types-header ticket-type-header)
(<> (~root-header :cart-mini cart-mini :blog-url blog-url :site-title site-title
:app-label app-label :nav-tree nav-tree :auth-menu auth-menu
:nav-panel nav-panel :settings-url settings-url :is-admin is-admin)
(<> (~root-header-auto)
(~header-child-sx :inner (<> post-header calendar-header day-header
entry-header entry-admin-header
ticket-types-header ticket-type-header))))
@@ -103,9 +89,7 @@
;; --- Markets layout: root + child(post + markets) ---
(defcomp ~events-markets-layout-full (&key post-header markets-header)
(<> (~root-header :cart-mini cart-mini :blog-url blog-url :site-title site-title
:app-label app-label :nav-tree nav-tree :auth-menu auth-menu
:nav-panel nav-panel :settings-url settings-url :is-admin is-admin)
(<> (~root-header-auto)
(~header-child-sx :inner (<> post-header markets-header))))
(defcomp ~events-markets-layout-oob (&key post-oob markets-oob-wrap)

View File

@@ -2,7 +2,7 @@
from __future__ import annotations
from shared.sx.helpers import (
call_url, render_to_sx, render_to_sx_with_env, _ctx_to_env,
call_url, render_to_sx, render_to_sx_with_env,
post_admin_header_sx,
)
from shared.sx.parser import SxExpr

View File

@@ -3,7 +3,7 @@ from __future__ import annotations
from markupsafe import escape
from shared.sx.helpers import render_to_sx, render_to_sx_with_env, _ctx_to_env
from shared.sx.helpers import render_to_sx, render_to_sx_with_env
from shared.sx.parser import SxExpr
from .utils import (

View File

@@ -228,11 +228,11 @@ def _register_events_layouts() -> None:
# --- Calendar admin layout (root + post + child(post-admin + calendar + cal-admin)) ---
async def _cal_admin_full(ctx: dict, **kw: Any) -> str:
from shared.sx.helpers import render_to_sx_with_env, _ctx_to_env, post_admin_header_sx
from shared.sx.helpers import render_to_sx_with_env, post_admin_header_sx
from shared.sx.parser import SxExpr
ctx = await _ensure_container_nav(ctx)
slug = (ctx.get("post") or {}).get("slug", "")
return await render_to_sx_with_env("events-cal-admin-layout-full", _ctx_to_env(ctx),
return await render_to_sx_with_env("events-cal-admin-layout-full", {},
post_header=SxExpr(await _post_header_sx(ctx)),
admin_header=SxExpr(await post_admin_header_sx(ctx, slug, selected="calendars")),
calendar_header=SxExpr(await _calendar_header_sx(ctx)),
@@ -241,11 +241,11 @@ async def _cal_admin_full(ctx: dict, **kw: Any) -> str:
async def _cal_admin_oob(ctx: dict, **kw: Any) -> str:
from shared.sx.helpers import render_to_sx_with_env, _ctx_to_env, post_admin_header_sx, oob_header_sx
from shared.sx.helpers import render_to_sx_with_env, post_admin_header_sx, oob_header_sx
from shared.sx.parser import SxExpr
ctx = await _ensure_container_nav(ctx)
slug = (ctx.get("post") or {}).get("slug", "")
return await render_to_sx_with_env("events-cal-admin-layout-oob", _ctx_to_env(ctx, oob=True),
return await render_to_sx_with_env("events-cal-admin-layout-oob", {},
admin_oob=SxExpr(await post_admin_header_sx(ctx, slug, oob=True, selected="calendars")),
cal_oob=SxExpr(await _calendar_header_sx(ctx, oob=True)),
cal_admin_oob_wrap=SxExpr(await oob_header_sx("calendar-header-child",
@@ -264,11 +264,11 @@ async def _slots_full(ctx: dict, **kw: Any) -> str:
async def _slots_oob(ctx: dict, **kw: Any) -> str:
from shared.sx.helpers import render_to_sx_with_env, _ctx_to_env, post_admin_header_sx
from shared.sx.helpers import render_to_sx_with_env, post_admin_header_sx
from shared.sx.parser import SxExpr
ctx = await _ensure_container_nav({**ctx, "is_admin_section": True})
slug = (ctx.get("post") or {}).get("slug", "")
return await render_to_sx_with_env("events-slots-layout-oob", _ctx_to_env(ctx, oob=True),
return await render_to_sx_with_env("events-slots-layout-oob", {},
admin_oob=SxExpr(await post_admin_header_sx(ctx, slug, oob=True, selected="calendars")),
cal_admin_oob=SxExpr(await _calendar_admin_header_sx(ctx, oob=True)),
clear_oob=SxExpr(_clear_deeper_oob("post-row", "post-header-child",
@@ -281,11 +281,11 @@ async def _slots_oob(ctx: dict, **kw: Any) -> str:
# --- Slot detail layout (extends cal-admin with slot header) ---
async def _slot_full(ctx: dict, **kw: Any) -> str:
from shared.sx.helpers import render_to_sx_with_env, _ctx_to_env, post_admin_header_sx
from shared.sx.helpers import render_to_sx_with_env, post_admin_header_sx
from shared.sx.parser import SxExpr
ctx = await _ensure_container_nav({**ctx, "is_admin_section": True})
slug = (ctx.get("post") or {}).get("slug", "")
return await render_to_sx_with_env("events-slot-layout-full", _ctx_to_env(ctx),
return await render_to_sx_with_env("events-slot-layout-full", {},
post_header=SxExpr(await _post_header_sx(ctx)),
admin_header=SxExpr(await post_admin_header_sx(ctx, slug, selected="calendars")),
calendar_header=SxExpr(await _calendar_header_sx(ctx)),
@@ -295,11 +295,11 @@ async def _slot_full(ctx: dict, **kw: Any) -> str:
async def _slot_oob(ctx: dict, **kw: Any) -> str:
from shared.sx.helpers import render_to_sx_with_env, _ctx_to_env, post_admin_header_sx, oob_header_sx
from shared.sx.helpers import render_to_sx_with_env, post_admin_header_sx, oob_header_sx
from shared.sx.parser import SxExpr
ctx = await _ensure_container_nav({**ctx, "is_admin_section": True})
slug = (ctx.get("post") or {}).get("slug", "")
return await render_to_sx_with_env("events-slot-layout-oob", _ctx_to_env(ctx, oob=True),
return await render_to_sx_with_env("events-slot-layout-oob", {},
admin_oob=SxExpr(await post_admin_header_sx(ctx, slug, oob=True, selected="calendars")),
cal_admin_oob=SxExpr(await _calendar_admin_header_sx(ctx, oob=True)),
slot_oob_wrap=SxExpr(await oob_header_sx("calendar-admin-header-child",
@@ -315,11 +315,11 @@ async def _slot_oob(ctx: dict, **kw: Any) -> str:
# --- Day admin layout (root + post + post-admin + child(cal + day + day-admin)) ---
async def _day_admin_full(ctx: dict, **kw: Any) -> str:
from shared.sx.helpers import render_to_sx_with_env, _ctx_to_env, post_admin_header_sx
from shared.sx.helpers import render_to_sx_with_env, post_admin_header_sx
from shared.sx.parser import SxExpr
ctx = await _ensure_container_nav(ctx)
slug = (ctx.get("post") or {}).get("slug", "")
return await render_to_sx_with_env("events-day-admin-layout-full", _ctx_to_env(ctx),
return await render_to_sx_with_env("events-day-admin-layout-full", {},
post_header=SxExpr(await _post_header_sx(ctx)),
admin_header=SxExpr(await post_admin_header_sx(ctx, slug, selected="calendars")),
calendar_header=SxExpr(await _calendar_header_sx(ctx)),
@@ -329,11 +329,11 @@ async def _day_admin_full(ctx: dict, **kw: Any) -> str:
async def _day_admin_oob(ctx: dict, **kw: Any) -> str:
from shared.sx.helpers import render_to_sx_with_env, _ctx_to_env, post_admin_header_sx, oob_header_sx
from shared.sx.helpers import render_to_sx_with_env, post_admin_header_sx, oob_header_sx
from shared.sx.parser import SxExpr
ctx = await _ensure_container_nav(ctx)
slug = (ctx.get("post") or {}).get("slug", "")
return await render_to_sx_with_env("events-day-admin-layout-oob", _ctx_to_env(ctx, oob=True),
return await render_to_sx_with_env("events-day-admin-layout-oob", {},
admin_oob=SxExpr(await post_admin_header_sx(ctx, slug, oob=True, selected="calendars")),
cal_oob=SxExpr(await _calendar_header_sx(ctx, oob=True)),
day_admin_oob_wrap=SxExpr(await oob_header_sx("day-header-child",
@@ -349,9 +349,9 @@ async def _day_admin_oob(ctx: dict, **kw: Any) -> str:
# --- Entry layout (root + child(post + cal + day + entry), + menu) ---
async def _entry_full(ctx: dict, **kw: Any) -> str:
from shared.sx.helpers import render_to_sx_with_env, _ctx_to_env
from shared.sx.helpers import render_to_sx_with_env
from shared.sx.parser import SxExpr
return await render_to_sx_with_env("events-entry-layout-full", _ctx_to_env(ctx),
return await render_to_sx_with_env("events-entry-layout-full", {},
post_header=SxExpr(await _post_header_sx(ctx)),
calendar_header=SxExpr(await _calendar_header_sx(ctx)),
day_header=SxExpr(await _day_header_sx(ctx)),
@@ -360,9 +360,9 @@ async def _entry_full(ctx: dict, **kw: Any) -> str:
async def _entry_oob(ctx: dict, **kw: Any) -> str:
from shared.sx.helpers import render_to_sx_with_env, _ctx_to_env, oob_header_sx
from shared.sx.helpers import render_to_sx_with_env, oob_header_sx
from shared.sx.parser import SxExpr
return await render_to_sx_with_env("events-entry-layout-oob", _ctx_to_env(ctx, oob=True),
return await render_to_sx_with_env("events-entry-layout-oob", {},
day_oob=SxExpr(await _day_header_sx(ctx, oob=True)),
entry_oob_wrap=SxExpr(await oob_header_sx("day-header-child",
"entry-header-child", await _entry_header_html(ctx))),
@@ -376,11 +376,11 @@ async def _entry_oob(ctx: dict, **kw: Any) -> str:
# --- Entry admin layout (root + post + child(post-admin + cal + day + entry + entry-admin), + menu) ---
async def _entry_admin_full(ctx: dict, **kw: Any) -> str:
from shared.sx.helpers import render_to_sx_with_env, _ctx_to_env, post_admin_header_sx
from shared.sx.helpers import render_to_sx_with_env, post_admin_header_sx
from shared.sx.parser import SxExpr
ctx = await _ensure_container_nav(ctx)
slug = (ctx.get("post") or {}).get("slug", "")
return await render_to_sx_with_env("events-entry-admin-layout-full", _ctx_to_env(ctx),
return await render_to_sx_with_env("events-entry-admin-layout-full", {},
post_header=SxExpr(await _post_header_sx(ctx)),
admin_header=SxExpr(await post_admin_header_sx(ctx, slug, selected="calendars")),
calendar_header=SxExpr(await _calendar_header_sx(ctx)),
@@ -391,11 +391,11 @@ async def _entry_admin_full(ctx: dict, **kw: Any) -> str:
async def _entry_admin_oob(ctx: dict, **kw: Any) -> str:
from shared.sx.helpers import render_to_sx_with_env, _ctx_to_env, post_admin_header_sx, oob_header_sx
from shared.sx.helpers import render_to_sx_with_env, post_admin_header_sx, oob_header_sx
from shared.sx.parser import SxExpr
ctx = await _ensure_container_nav(ctx)
slug = (ctx.get("post") or {}).get("slug", "")
return await render_to_sx_with_env("events-entry-admin-layout-oob", _ctx_to_env(ctx, oob=True),
return await render_to_sx_with_env("events-entry-admin-layout-oob", {},
admin_oob=SxExpr(await post_admin_header_sx(ctx, slug, oob=True, selected="calendars")),
entry_oob=SxExpr(await _entry_header_html(ctx, oob=True)),
entry_admin_oob_wrap=SxExpr(await oob_header_sx("entry-header-child",
@@ -412,9 +412,9 @@ async def _entry_admin_oob(ctx: dict, **kw: Any) -> str:
# --- Ticket types layout (extends entry admin with ticket-types header, + menu) ---
async def _ticket_types_full(ctx: dict, **kw: Any) -> str:
from shared.sx.helpers import render_to_sx_with_env, _ctx_to_env
from shared.sx.helpers import render_to_sx_with_env
from shared.sx.parser import SxExpr
return await render_to_sx_with_env("events-ticket-types-layout-full", _ctx_to_env(ctx),
return await render_to_sx_with_env("events-ticket-types-layout-full", {},
post_header=SxExpr(await _post_header_sx(ctx)),
calendar_header=SxExpr(await _calendar_header_sx(ctx)),
day_header=SxExpr(await _day_header_sx(ctx)),
@@ -425,9 +425,9 @@ async def _ticket_types_full(ctx: dict, **kw: Any) -> str:
async def _ticket_types_oob(ctx: dict, **kw: Any) -> str:
from shared.sx.helpers import render_to_sx_with_env, _ctx_to_env, oob_header_sx
from shared.sx.helpers import render_to_sx_with_env, oob_header_sx
from shared.sx.parser import SxExpr
return await render_to_sx_with_env("events-ticket-types-layout-oob", _ctx_to_env(ctx, oob=True),
return await render_to_sx_with_env("events-ticket-types-layout-oob", {},
entry_admin_oob=SxExpr(await _entry_admin_header_html(ctx, oob=True)),
ticket_types_oob_wrap=SxExpr(await oob_header_sx("entry-admin-header-child",
"ticket_types-header-child", await _ticket_types_header_html(ctx))),
@@ -437,9 +437,9 @@ async def _ticket_types_oob(ctx: dict, **kw: Any) -> str:
# --- Ticket type detail layout (extends ticket types with ticket-type header, + menu) ---
async def _ticket_type_full(ctx: dict, **kw: Any) -> str:
from shared.sx.helpers import render_to_sx_with_env, _ctx_to_env
from shared.sx.helpers import render_to_sx_with_env
from shared.sx.parser import SxExpr
return await render_to_sx_with_env("events-ticket-type-layout-full", _ctx_to_env(ctx),
return await render_to_sx_with_env("events-ticket-type-layout-full", {},
post_header=SxExpr(await _post_header_sx(ctx)),
calendar_header=SxExpr(await _calendar_header_sx(ctx)),
day_header=SxExpr(await _day_header_sx(ctx)),
@@ -451,9 +451,9 @@ async def _ticket_type_full(ctx: dict, **kw: Any) -> str:
async def _ticket_type_oob(ctx: dict, **kw: Any) -> str:
from shared.sx.helpers import render_to_sx_with_env, _ctx_to_env, oob_header_sx
from shared.sx.helpers import render_to_sx_with_env, oob_header_sx
from shared.sx.parser import SxExpr
return await render_to_sx_with_env("events-ticket-type-layout-oob", _ctx_to_env(ctx, oob=True),
return await render_to_sx_with_env("events-ticket-type-layout-oob", {},
ticket_types_oob=SxExpr(await _ticket_types_header_html(ctx, oob=True)),
ticket_type_oob_wrap=SxExpr(await oob_header_sx("ticket_types-header-child",
"ticket_type-header-child", await _ticket_type_header_html(ctx))),
@@ -463,18 +463,18 @@ async def _ticket_type_oob(ctx: dict, **kw: Any) -> str:
# --- Markets layout (root + child(post + markets)) ---
async def _markets_full(ctx: dict, **kw: Any) -> str:
from shared.sx.helpers import render_to_sx_with_env, _ctx_to_env
from shared.sx.helpers import render_to_sx_with_env
from shared.sx.parser import SxExpr
return await render_to_sx_with_env("events-markets-layout-full", _ctx_to_env(ctx),
return await render_to_sx_with_env("events-markets-layout-full", {},
post_header=SxExpr(await _post_header_sx(ctx)),
markets_header=SxExpr(await _markets_header_sx(ctx)),
)
async def _markets_oob(ctx: dict, **kw: Any) -> str:
from shared.sx.helpers import render_to_sx_with_env, _ctx_to_env, oob_header_sx
from shared.sx.helpers import render_to_sx_with_env, oob_header_sx
from shared.sx.parser import SxExpr
return await render_to_sx_with_env("events-markets-layout-oob", _ctx_to_env(ctx, oob=True),
return await render_to_sx_with_env("events-markets-layout-oob", {},
post_oob=SxExpr(await _post_header_sx(ctx, oob=True)),
markets_oob_wrap=SxExpr(await oob_header_sx("post-header-child",
"markets-header-child", await _markets_header_sx(ctx))),

View File

@@ -35,11 +35,11 @@ def _register_events_layouts() -> None:
# --- Calendar admin layout (root + post + child(post-admin + calendar + cal-admin)) ---
async def _cal_admin_full(ctx: dict, **kw: Any) -> str:
from shared.sx.helpers import render_to_sx_with_env, _ctx_to_env, post_admin_header_sx
from shared.sx.helpers import render_to_sx_with_env, post_admin_header_sx
from shared.sx.parser import SxExpr
ctx = await _ensure_container_nav(ctx)
slug = (ctx.get("post") or {}).get("slug", "")
return await render_to_sx_with_env("events-cal-admin-layout-full", _ctx_to_env(ctx),
return await render_to_sx_with_env("events-cal-admin-layout-full", {},
post_header=SxExpr(await _post_header_sx(ctx)),
admin_header=SxExpr(await post_admin_header_sx(ctx, slug, selected="calendars")),
calendar_header=SxExpr(await _calendar_header_sx(ctx)),
@@ -48,11 +48,11 @@ async def _cal_admin_full(ctx: dict, **kw: Any) -> str:
async def _cal_admin_oob(ctx: dict, **kw: Any) -> str:
from shared.sx.helpers import render_to_sx_with_env, _ctx_to_env, post_admin_header_sx, oob_header_sx
from shared.sx.helpers import render_to_sx_with_env, post_admin_header_sx, oob_header_sx
from shared.sx.parser import SxExpr
ctx = await _ensure_container_nav(ctx)
slug = (ctx.get("post") or {}).get("slug", "")
return await render_to_sx_with_env("events-cal-admin-layout-oob", _ctx_to_env(ctx, oob=True),
return await render_to_sx_with_env("events-cal-admin-layout-oob", {},
admin_oob=SxExpr(await post_admin_header_sx(ctx, slug, oob=True, selected="calendars")),
cal_oob=SxExpr(await _calendar_header_sx(ctx, oob=True)),
cal_admin_oob_wrap=SxExpr(await oob_header_sx("calendar-header-child",
@@ -71,11 +71,11 @@ async def _slots_full(ctx: dict, **kw: Any) -> str:
async def _slots_oob(ctx: dict, **kw: Any) -> str:
from shared.sx.helpers import render_to_sx_with_env, _ctx_to_env, post_admin_header_sx
from shared.sx.helpers import render_to_sx_with_env, post_admin_header_sx
from shared.sx.parser import SxExpr
ctx = await _ensure_container_nav({**ctx, "is_admin_section": True})
slug = (ctx.get("post") or {}).get("slug", "")
return await render_to_sx_with_env("events-slots-layout-oob", _ctx_to_env(ctx, oob=True),
return await render_to_sx_with_env("events-slots-layout-oob", {},
admin_oob=SxExpr(await post_admin_header_sx(ctx, slug, oob=True, selected="calendars")),
cal_admin_oob=SxExpr(await _calendar_admin_header_sx(ctx, oob=True)),
clear_oob=SxExpr(_clear_deeper_oob("post-row", "post-header-child",
@@ -88,11 +88,11 @@ async def _slots_oob(ctx: dict, **kw: Any) -> str:
# --- Slot detail layout (extends cal-admin with slot header) ---
async def _slot_full(ctx: dict, **kw: Any) -> str:
from shared.sx.helpers import render_to_sx_with_env, _ctx_to_env, post_admin_header_sx
from shared.sx.helpers import render_to_sx_with_env, post_admin_header_sx
from shared.sx.parser import SxExpr
ctx = await _ensure_container_nav({**ctx, "is_admin_section": True})
slug = (ctx.get("post") or {}).get("slug", "")
return await render_to_sx_with_env("events-slot-layout-full", _ctx_to_env(ctx),
return await render_to_sx_with_env("events-slot-layout-full", {},
post_header=SxExpr(await _post_header_sx(ctx)),
admin_header=SxExpr(await post_admin_header_sx(ctx, slug, selected="calendars")),
calendar_header=SxExpr(await _calendar_header_sx(ctx)),
@@ -102,11 +102,11 @@ async def _slot_full(ctx: dict, **kw: Any) -> str:
async def _slot_oob(ctx: dict, **kw: Any) -> str:
from shared.sx.helpers import render_to_sx_with_env, _ctx_to_env, post_admin_header_sx, oob_header_sx
from shared.sx.helpers import render_to_sx_with_env, post_admin_header_sx, oob_header_sx
from shared.sx.parser import SxExpr
ctx = await _ensure_container_nav({**ctx, "is_admin_section": True})
slug = (ctx.get("post") or {}).get("slug", "")
return await render_to_sx_with_env("events-slot-layout-oob", _ctx_to_env(ctx, oob=True),
return await render_to_sx_with_env("events-slot-layout-oob", {},
admin_oob=SxExpr(await post_admin_header_sx(ctx, slug, oob=True, selected="calendars")),
cal_admin_oob=SxExpr(await _calendar_admin_header_sx(ctx, oob=True)),
slot_oob_wrap=SxExpr(await oob_header_sx("calendar-admin-header-child",
@@ -122,11 +122,11 @@ async def _slot_oob(ctx: dict, **kw: Any) -> str:
# --- Day admin layout (root + post + post-admin + child(cal + day + day-admin)) ---
async def _day_admin_full(ctx: dict, **kw: Any) -> str:
from shared.sx.helpers import render_to_sx_with_env, _ctx_to_env, post_admin_header_sx
from shared.sx.helpers import render_to_sx_with_env, post_admin_header_sx
from shared.sx.parser import SxExpr
ctx = await _ensure_container_nav(ctx)
slug = (ctx.get("post") or {}).get("slug", "")
return await render_to_sx_with_env("events-day-admin-layout-full", _ctx_to_env(ctx),
return await render_to_sx_with_env("events-day-admin-layout-full", {},
post_header=SxExpr(await _post_header_sx(ctx)),
admin_header=SxExpr(await post_admin_header_sx(ctx, slug, selected="calendars")),
calendar_header=SxExpr(await _calendar_header_sx(ctx)),
@@ -136,11 +136,11 @@ async def _day_admin_full(ctx: dict, **kw: Any) -> str:
async def _day_admin_oob(ctx: dict, **kw: Any) -> str:
from shared.sx.helpers import render_to_sx_with_env, _ctx_to_env, post_admin_header_sx, oob_header_sx
from shared.sx.helpers import render_to_sx_with_env, post_admin_header_sx, oob_header_sx
from shared.sx.parser import SxExpr
ctx = await _ensure_container_nav(ctx)
slug = (ctx.get("post") or {}).get("slug", "")
return await render_to_sx_with_env("events-day-admin-layout-oob", _ctx_to_env(ctx, oob=True),
return await render_to_sx_with_env("events-day-admin-layout-oob", {},
admin_oob=SxExpr(await post_admin_header_sx(ctx, slug, oob=True, selected="calendars")),
cal_oob=SxExpr(await _calendar_header_sx(ctx, oob=True)),
day_admin_oob_wrap=SxExpr(await oob_header_sx("day-header-child",
@@ -156,9 +156,9 @@ async def _day_admin_oob(ctx: dict, **kw: Any) -> str:
# --- Entry layout (root + child(post + cal + day + entry), + menu) ---
async def _entry_full(ctx: dict, **kw: Any) -> str:
from shared.sx.helpers import render_to_sx_with_env, _ctx_to_env
from shared.sx.helpers import render_to_sx_with_env
from shared.sx.parser import SxExpr
return await render_to_sx_with_env("events-entry-layout-full", _ctx_to_env(ctx),
return await render_to_sx_with_env("events-entry-layout-full", {},
post_header=SxExpr(await _post_header_sx(ctx)),
calendar_header=SxExpr(await _calendar_header_sx(ctx)),
day_header=SxExpr(await _day_header_sx(ctx)),
@@ -167,9 +167,9 @@ async def _entry_full(ctx: dict, **kw: Any) -> str:
async def _entry_oob(ctx: dict, **kw: Any) -> str:
from shared.sx.helpers import render_to_sx_with_env, _ctx_to_env, oob_header_sx
from shared.sx.helpers import render_to_sx_with_env, oob_header_sx
from shared.sx.parser import SxExpr
return await render_to_sx_with_env("events-entry-layout-oob", _ctx_to_env(ctx, oob=True),
return await render_to_sx_with_env("events-entry-layout-oob", {},
day_oob=SxExpr(await _day_header_sx(ctx, oob=True)),
entry_oob_wrap=SxExpr(await oob_header_sx("day-header-child",
"entry-header-child", await _entry_header_html(ctx))),
@@ -183,11 +183,11 @@ async def _entry_oob(ctx: dict, **kw: Any) -> str:
# --- Entry admin layout (root + post + child(post-admin + cal + day + entry + entry-admin), + menu) ---
async def _entry_admin_full(ctx: dict, **kw: Any) -> str:
from shared.sx.helpers import render_to_sx_with_env, _ctx_to_env, post_admin_header_sx
from shared.sx.helpers import render_to_sx_with_env, post_admin_header_sx
from shared.sx.parser import SxExpr
ctx = await _ensure_container_nav(ctx)
slug = (ctx.get("post") or {}).get("slug", "")
return await render_to_sx_with_env("events-entry-admin-layout-full", _ctx_to_env(ctx),
return await render_to_sx_with_env("events-entry-admin-layout-full", {},
post_header=SxExpr(await _post_header_sx(ctx)),
admin_header=SxExpr(await post_admin_header_sx(ctx, slug, selected="calendars")),
calendar_header=SxExpr(await _calendar_header_sx(ctx)),
@@ -198,11 +198,11 @@ async def _entry_admin_full(ctx: dict, **kw: Any) -> str:
async def _entry_admin_oob(ctx: dict, **kw: Any) -> str:
from shared.sx.helpers import render_to_sx_with_env, _ctx_to_env, post_admin_header_sx, oob_header_sx
from shared.sx.helpers import render_to_sx_with_env, post_admin_header_sx, oob_header_sx
from shared.sx.parser import SxExpr
ctx = await _ensure_container_nav(ctx)
slug = (ctx.get("post") or {}).get("slug", "")
return await render_to_sx_with_env("events-entry-admin-layout-oob", _ctx_to_env(ctx, oob=True),
return await render_to_sx_with_env("events-entry-admin-layout-oob", {},
admin_oob=SxExpr(await post_admin_header_sx(ctx, slug, oob=True, selected="calendars")),
entry_oob=SxExpr(await _entry_header_html(ctx, oob=True)),
entry_admin_oob_wrap=SxExpr(await oob_header_sx("entry-header-child",
@@ -219,9 +219,9 @@ async def _entry_admin_oob(ctx: dict, **kw: Any) -> str:
# --- Ticket types layout (extends entry admin with ticket-types header, + menu) ---
async def _ticket_types_full(ctx: dict, **kw: Any) -> str:
from shared.sx.helpers import render_to_sx_with_env, _ctx_to_env
from shared.sx.helpers import render_to_sx_with_env
from shared.sx.parser import SxExpr
return await render_to_sx_with_env("events-ticket-types-layout-full", _ctx_to_env(ctx),
return await render_to_sx_with_env("events-ticket-types-layout-full", {},
post_header=SxExpr(await _post_header_sx(ctx)),
calendar_header=SxExpr(await _calendar_header_sx(ctx)),
day_header=SxExpr(await _day_header_sx(ctx)),
@@ -232,9 +232,9 @@ async def _ticket_types_full(ctx: dict, **kw: Any) -> str:
async def _ticket_types_oob(ctx: dict, **kw: Any) -> str:
from shared.sx.helpers import render_to_sx_with_env, _ctx_to_env, oob_header_sx
from shared.sx.helpers import render_to_sx_with_env, oob_header_sx
from shared.sx.parser import SxExpr
return await render_to_sx_with_env("events-ticket-types-layout-oob", _ctx_to_env(ctx, oob=True),
return await render_to_sx_with_env("events-ticket-types-layout-oob", {},
entry_admin_oob=SxExpr(await _entry_admin_header_html(ctx, oob=True)),
ticket_types_oob_wrap=SxExpr(await oob_header_sx("entry-admin-header-child",
"ticket_types-header-child", await _ticket_types_header_html(ctx))),
@@ -244,9 +244,9 @@ async def _ticket_types_oob(ctx: dict, **kw: Any) -> str:
# --- Ticket type detail layout (extends ticket types with ticket-type header, + menu) ---
async def _ticket_type_full(ctx: dict, **kw: Any) -> str:
from shared.sx.helpers import render_to_sx_with_env, _ctx_to_env
from shared.sx.helpers import render_to_sx_with_env
from shared.sx.parser import SxExpr
return await render_to_sx_with_env("events-ticket-type-layout-full", _ctx_to_env(ctx),
return await render_to_sx_with_env("events-ticket-type-layout-full", {},
post_header=SxExpr(await _post_header_sx(ctx)),
calendar_header=SxExpr(await _calendar_header_sx(ctx)),
day_header=SxExpr(await _day_header_sx(ctx)),
@@ -258,9 +258,9 @@ async def _ticket_type_full(ctx: dict, **kw: Any) -> str:
async def _ticket_type_oob(ctx: dict, **kw: Any) -> str:
from shared.sx.helpers import render_to_sx_with_env, _ctx_to_env, oob_header_sx
from shared.sx.helpers import render_to_sx_with_env, oob_header_sx
from shared.sx.parser import SxExpr
return await render_to_sx_with_env("events-ticket-type-layout-oob", _ctx_to_env(ctx, oob=True),
return await render_to_sx_with_env("events-ticket-type-layout-oob", {},
ticket_types_oob=SxExpr(await _ticket_types_header_html(ctx, oob=True)),
ticket_type_oob_wrap=SxExpr(await oob_header_sx("ticket_types-header-child",
"ticket_type-header-child", await _ticket_type_header_html(ctx))),
@@ -270,18 +270,18 @@ async def _ticket_type_oob(ctx: dict, **kw: Any) -> str:
# --- Markets layout (root + child(post + markets)) ---
async def _markets_full(ctx: dict, **kw: Any) -> str:
from shared.sx.helpers import render_to_sx_with_env, _ctx_to_env
from shared.sx.helpers import render_to_sx_with_env
from shared.sx.parser import SxExpr
return await render_to_sx_with_env("events-markets-layout-full", _ctx_to_env(ctx),
return await render_to_sx_with_env("events-markets-layout-full", {},
post_header=SxExpr(await _post_header_sx(ctx)),
markets_header=SxExpr(await _markets_header_sx(ctx)),
)
async def _markets_oob(ctx: dict, **kw: Any) -> str:
from shared.sx.helpers import render_to_sx_with_env, _ctx_to_env, oob_header_sx
from shared.sx.helpers import render_to_sx_with_env, oob_header_sx
from shared.sx.parser import SxExpr
return await render_to_sx_with_env("events-markets-layout-oob", _ctx_to_env(ctx, oob=True),
return await render_to_sx_with_env("events-markets-layout-oob", {},
post_oob=SxExpr(await _post_header_sx(ctx, oob=True)),
markets_oob_wrap=SxExpr(await oob_header_sx("post-header-child",
"markets-header-child", await _markets_header_sx(ctx))),

View File

@@ -2,7 +2,7 @@
from __future__ import annotations
from shared.sx.helpers import (
render_to_sx_with_env, _ctx_to_env,
render_to_sx_with_env,
post_admin_header_sx, oob_header_sx,
header_child_sx, full_page_sx, oob_page_sx,
)
@@ -44,7 +44,7 @@ async def render_all_events_page(ctx: dict, entries, has_more, pending_tickets,
ctx, entries, has_more, pending_tickets, page_info,
page, view, ticket_url, next_url, events_url,
)
hdr = await render_to_sx_with_env("layout-root-full", _ctx_to_env(ctx))
hdr = await render_to_sx_with_env("layout-root-full", {})
return await full_page_sx(ctx, header_rows=hdr, content=content)
@@ -105,7 +105,7 @@ async def render_page_summary_page(ctx: dict, entries, has_more, pending_tickets
is_page_scoped=True, post=post,
)
hdr = await render_to_sx_with_env("layout-root-full", _ctx_to_env(ctx))
hdr = await render_to_sx_with_env("layout-root-full", {})
hdr += await header_child_sx(await _post_header_sx(ctx))
return await full_page_sx(ctx, header_rows=hdr, content=content)
@@ -160,7 +160,7 @@ async def render_calendars_page(ctx: dict) -> str:
content = await _calendars_main_panel_sx(ctx)
ctx = await _ensure_container_nav(ctx)
slug = (ctx.get("post") or {}).get("slug", "")
root_hdr = await render_to_sx_with_env("layout-root-full", _ctx_to_env(ctx))
root_hdr = await render_to_sx_with_env("layout-root-full", {})
post_hdr = await _post_header_sx(ctx)
admin_hdr = await post_admin_header_sx(ctx, slug, selected="calendars")
return await full_page_sx(ctx, header_rows=root_hdr + post_hdr + admin_hdr, content=content)
@@ -184,7 +184,7 @@ async def render_calendars_oob(ctx: dict) -> str:
async def render_calendar_page(ctx: dict) -> str:
"""Full page: calendar month view."""
content = await _calendar_main_panel_html(ctx)
hdr = await render_to_sx_with_env("layout-root-full", _ctx_to_env(ctx))
hdr = await render_to_sx_with_env("layout-root-full", {})
child = await _post_header_sx(ctx) + await _calendar_header_sx(ctx)
hdr += await header_child_sx(child)
return await full_page_sx(ctx, header_rows=hdr, content=content)
@@ -208,7 +208,7 @@ async def render_calendar_oob(ctx: dict) -> str:
async def render_day_page(ctx: dict) -> str:
"""Full page: day detail."""
content = await _day_main_panel_html(ctx)
hdr = await render_to_sx_with_env("layout-root-full", _ctx_to_env(ctx))
hdr = await render_to_sx_with_env("layout-root-full", {})
child = (await _post_header_sx(ctx)
+ await _calendar_header_sx(ctx) + await _day_header_sx(ctx))
hdr += await header_child_sx(child)

View File

@@ -1,7 +1,6 @@
"""Slot panels, forms, edit/add, slot picker JS."""
from __future__ import annotations
from markupsafe import escape
from shared.sx.helpers import render_to_sx
from shared.sx.parser import SxExpr
@@ -156,20 +155,12 @@ async def _slot_header_html(ctx: dict, *, oob: bool = False) -> str:
if not slot:
return ""
# Label: icon + name + description
desc = getattr(slot, "description", "") or ""
label_inner = (
f'<div class="flex flex-col md:flex-row md:gap-2 items-center">'
f'<div class="flex flex-row items-center gap-2">'
f'<i class="fa fa-clock"></i>'
f'<div class="shrink-0">{escape(slot.name)}</div>'
f'</div>'
f'<p class="text-stone-500 whitespace-pre-line break-all w-full">{escape(desc)}</p>'
f'</div>'
)
label_sx = await render_to_sx("events-slot-label",
name=slot.name, description=desc)
return await render_to_sx("menu-row-sx", id="slot-row", level=5,
link_label_content=SxExpr(label_inner),
link_label_content=SxExpr(label_sx),
child_id="slot-header-child", oob=oob)

View File

@@ -17,7 +17,8 @@ from shared.sx.parser import SxExpr
def _clear_oob(*ids: str) -> str:
"""Generate OOB swaps to remove orphaned header rows/children."""
return "".join(f'(div :id "{i}" :hx-swap-oob "outerHTML")' for i in ids)
from shared.sx.helpers import sx_call
return "".join(sx_call("clear-oob-div", id=i) for i in ids)
# All possible header row/child IDs at each depth (deepest first)