Merge branch 'worktree-sx-layout-conversion' into macros

# Conflicts:
#	blog/sxc/pages/layouts.py
#	cart/sxc/pages/layouts.py
#	events/sxc/pages/helpers.py
#	events/sxc/pages/layouts.py
#	market/sxc/pages/layouts.py
#	sx/sxc/pages/layouts.py
This commit is contained in:
2026-03-04 22:25:52 +00:00
18 changed files with 1289 additions and 1180 deletions

View File

@@ -228,6 +228,11 @@ def create_app() -> "Quart":
("market", "container-nav", nav_params),
], required=False)
ctx["container_nav"] = events_nav + market_nav
# Populate g._defpage_ctx for layout IO primitives
if not hasattr(g, '_defpage_ctx'):
g._defpage_ctx = {}
g._defpage_ctx.setdefault("post", post_data.get("post"))
g._defpage_ctx.setdefault("container_nav", ctx["container_nav"])
return ctx
# --- oEmbed endpoint ---

View File

@@ -1,42 +1,105 @@
;; Market layout defcomps — root header via ~root-header-auto,
;; market-specific headers passed as &key params.
;; Market layout defcomps — fully self-contained via IO primitives.
;; Registered via register_sx_layout in layouts.py.
;; --- Browse layout: root + post header + market header ---
;; ---------------------------------------------------------------------------
;; Auto-fetching market header macro
;; ---------------------------------------------------------------------------
(defcomp ~market-browse-layout-full (&key post-header market-header)
(defmacro ~market-header-auto (oob)
"Market header row using (market-header-ctx)."
(quasiquote
(let ((__mctx (market-header-ctx)))
(~menu-row-sx :id "market-row" :level 2
:link-href (get __mctx "link-href")
:link-label-content (~market-shop-label
:title (get __mctx "market-title")
:top-slug (get __mctx "top-slug")
:sub-div (get __mctx "sub-slug"))
:nav (get __mctx "desktop-nav")
:child-id "market-header-child"
:oob (unquote oob)))))
;; ---------------------------------------------------------------------------
;; OOB clear helpers
;; ---------------------------------------------------------------------------
(defcomp ~market-clear-oob ()
"Clear OOB divs for browse level."
(<>
(~clear-oob-div :id "product-admin-row")
(~clear-oob-div :id "product-admin-header-child")
(~clear-oob-div :id "product-row")
(~clear-oob-div :id "product-header-child")
(~clear-oob-div :id "market-admin-row")
(~clear-oob-div :id "market-admin-header-child")
(~clear-oob-div :id "post-admin-row")
(~clear-oob-div :id "post-admin-header-child")))
(defcomp ~market-clear-oob-admin ()
"Clear OOB divs for admin level."
(<>
(~clear-oob-div :id "product-admin-row")
(~clear-oob-div :id "product-admin-header-child")
(~clear-oob-div :id "product-row")
(~clear-oob-div :id "product-header-child")))
;; ---------------------------------------------------------------------------
;; Browse layout: root + post + market (self-contained)
;; ---------------------------------------------------------------------------
(defcomp ~market-browse-layout-full ()
(<> (~root-header-auto)
(~header-child-sx :inner (<> post-header market-header))))
(~header-child-sx
:inner (<> (~post-header-auto nil)
(~market-header-auto nil)))))
(defcomp ~market-browse-layout-oob (&key oob-header post-header-oob clear-oob)
(<> oob-header post-header-oob clear-oob))
(defcomp ~market-browse-layout-oob ()
(<> (~post-header-auto true)
(~oob-header-sx :parent-id "post-header-child"
:row (~market-header-auto nil))
(~market-clear-oob)
(~root-header-auto true)))
;; --- Product layout: root + post + market + product ---
(defcomp ~market-browse-layout-mobile ()
(let ((__mctx (market-header-ctx)))
(get __mctx "mobile-nav")))
;; ---------------------------------------------------------------------------
;; Market admin layout: root + post + market + post-admin (self-contained)
;; ---------------------------------------------------------------------------
(defcomp ~market-admin-layout-full (&key selected)
(<> (~root-header-auto)
(~header-child-sx
:inner (<> (~post-header-auto nil)
(~market-header-auto nil)
(~post-admin-header-auto nil selected)))))
(defcomp ~market-admin-layout-oob (&key selected)
(<> (~market-header-auto true)
(~oob-header-sx :parent-id "market-header-child"
:row (~post-admin-header-auto nil selected))
(~market-clear-oob-admin)
(~root-header-auto true)))
;; ---------------------------------------------------------------------------
;; Parameterized defcomps — used by renders.py (non-defpage routes)
;; ---------------------------------------------------------------------------
;; Product layout: root + post + market + product
(defcomp ~market-product-layout-full (&key post-header market-header product-header)
(<> (~root-header-auto)
(~header-child-sx :inner (<> post-header market-header product-header))))
;; --- Product admin layout: root + post + market + product + admin ---
;; Product admin layout: root + post + market + product + admin
(defcomp ~market-product-admin-layout-full (&key post-header market-header product-header admin-header)
(<> (~root-header-auto)
(~header-child-sx :inner (<> post-header market-header product-header admin-header))))
;; --- Market admin layout: root + post + market + market-admin ---
(defcomp ~market-admin-layout-full (&key post-header market-header admin-header)
(<> (~root-header-auto)
(~header-child-sx :inner (<> post-header market-header admin-header))))
(defcomp ~market-admin-layout-oob (&key market-header-oob admin-oob-header clear-oob)
(<> market-header-oob admin-oob-header clear-oob))
;; --- OOB wrappers ---
;; OOB wrappers
(defcomp ~market-oob-wrap (&key parts)
(<> parts))
;; --- Content wrappers ---
;; Content wrappers
(defcomp ~market-content-padded (&key content)
(<> content (div :class "pb-8")))

View File

@@ -4,15 +4,9 @@ from __future__ import annotations
from typing import Any
from shared.sx.parser import SxExpr
from shared.sx.helpers import (
sx_call,
post_header_sx as _post_header_sx,
post_admin_header_sx,
oob_header_sx as _oob_header_sx,
header_child_sx,
)
from shared.sx.helpers import sx_call
from .utils import _set_prices, _price_str, _clear_deeper_oob
from .utils import _set_prices, _price_str
# ---------------------------------------------------------------------------
@@ -272,62 +266,14 @@ def _product_admin_header_sx(ctx: dict, d: dict, *, oob: bool = False) -> str:
)
# ---------------------------------------------------------------------------
# Market admin header
# ---------------------------------------------------------------------------
async def _market_admin_header_sx(ctx: dict, *, oob: bool = False, selected: str = "") -> str:
"""Build market admin header row -- delegates to shared helper."""
slug = (ctx.get("post") or {}).get("slug", "")
return await post_admin_header_sx(ctx, slug, oob=oob, selected=selected)
# ===========================================================================
# Layout registration
# Layout registration — all layouts delegate to .sx defcomps
# ===========================================================================
def _register_market_layouts() -> None:
from shared.sx.layouts import register_custom_layout
register_custom_layout("market", _market_full, _market_oob, _market_mobile)
register_custom_layout("market-admin", _market_admin_full, _market_admin_oob)
async def _market_full(ctx: dict, **kw: Any) -> str:
from shared.sx.helpers import render_to_sx_with_env
return await render_to_sx_with_env("market-browse-layout-full", {},
post_header=await _post_header_sx(ctx),
market_header=_market_header_sx(ctx))
async def _market_oob(ctx: dict, **kw: Any) -> str:
oob_hdr = await _oob_header_sx("post-header-child", "market-header-child",
_market_header_sx(ctx))
return sx_call("market-browse-layout-oob",
oob_header=oob_hdr,
post_header_oob=await _post_header_sx(ctx, oob=True),
clear_oob=SxExpr(_clear_deeper_oob("post-row", "post-header-child",
"market-row", "market-header-child")))
def _market_mobile(ctx: dict, **kw: Any) -> str:
return _mobile_nav_panel_sx(ctx)
async def _market_admin_full(ctx: dict, **kw: Any) -> str:
from shared.sx.helpers import render_to_sx_with_env
selected = kw.get("selected", "")
return await render_to_sx_with_env("market-admin-layout-full", {},
post_header=await _post_header_sx(ctx),
market_header=_market_header_sx(ctx),
admin_header=await _market_admin_header_sx(ctx, selected=selected))
async def _market_admin_oob(ctx: dict, **kw: Any) -> str:
selected = kw.get("selected", "")
return sx_call("market-admin-layout-oob",
market_header_oob=_market_header_sx(ctx, oob=True),
admin_oob_header=await _oob_header_sx("market-header-child", "market-admin-header-child",
await _market_admin_header_sx(ctx, selected=selected)),
clear_oob=SxExpr(_clear_deeper_oob("post-row", "post-header-child",
"market-row", "market-header-child",
"market-admin-row", "market-admin-header-child")))
from shared.sx.layouts import register_sx_layout
register_sx_layout("market",
"market-browse-layout-full", "market-browse-layout-oob",
"market-browse-layout-mobile")
register_sx_layout("market-admin",
"market-admin-layout-full", "market-admin-layout-oob")