Python sxc/pages/ functions no longer build nested sx_call chains or reference leaf component names. Instead they extract data (URLs, prices, CSRF, cart state) and call a single top-level composition defcomp with pure data values. The .sx defcomps handle all component-to-component wiring, iteration (map), and conditional rendering. New .sx composition defcomps: - headers.sx: ~market-header-from-data, ~market-desktop-nav-from-data, ~market-product-header-from-data, ~market-product-admin-header-from-data - prices.sx: ~market-prices-header-from-data, ~market-card-price-from-data - navigation.sx: ~market-mobile-nav-from-data - cards.sx: ~market-product-cards-content, ~market-card-from-data, ~market-cards-content, ~market-landing-from-data - detail.sx: ~market-product-detail-from-data, ~market-detail-gallery-from-data, ~market-detail-info-from-data - meta.sx: ~market-product-meta-from-data - filters.sx: ~market-desktop-filter-from-data, ~market-mobile-chips-from-data, ~market-mobile-filter-content-from-data, plus 6 sub-composition defcomps Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
203 lines
7.2 KiB
Python
203 lines
7.2 KiB
Python
"""Layout registration + header data builders."""
|
|
from __future__ import annotations
|
|
|
|
from shared.sx.helpers import sx_call
|
|
|
|
from .utils import _set_prices, _price_str
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Header data extraction — pure data, no component references
|
|
# ---------------------------------------------------------------------------
|
|
|
|
def _market_header_data(ctx: dict) -> dict:
|
|
"""Extract market header data for .sx composition."""
|
|
from quart import url_for
|
|
from shared.utils import route_prefix
|
|
|
|
prefix = route_prefix()
|
|
hx_select = ctx.get("hx_select_search", "#main-panel")
|
|
select_colours = ctx.get("select_colours", "")
|
|
rights = ctx.get("rights", {})
|
|
qs = ctx.get("qs", "")
|
|
categories = ctx.get("categories", {})
|
|
|
|
all_href = prefix + url_for("market.browse.browse_all") + qs
|
|
|
|
cat_data = []
|
|
for cat, data in categories.items():
|
|
cat_href = prefix + url_for("market.browse.browse_top", top_slug=data["slug"]) + qs
|
|
cat_data.append({
|
|
"href": cat_href,
|
|
"active": cat == ctx.get("category_label", ""),
|
|
"label": cat,
|
|
})
|
|
|
|
admin_href = ""
|
|
if rights and rights.get("admin"):
|
|
admin_href = prefix + url_for("defpage_market_admin")
|
|
|
|
return {
|
|
"market-title": ctx.get("market_title", ""),
|
|
"top-slug": ctx.get("top_slug", ""),
|
|
"sub-slug": ctx.get("sub_slug", ""),
|
|
"link-href": url_for("defpage_market_home"),
|
|
"categories": cat_data,
|
|
"hx-select": hx_select,
|
|
"select-colours": select_colours,
|
|
"all-href": all_href,
|
|
"all-active": ctx.get("category_label", "") == "All Products",
|
|
"admin-href": admin_href,
|
|
}
|
|
|
|
|
|
def _market_header_sx(ctx: dict, *, oob: bool = False) -> str:
|
|
"""Build market header as sx — delegates to .sx defcomp."""
|
|
data = _market_header_data(ctx)
|
|
return sx_call("market-header-from-data", oob=oob, **data)
|
|
|
|
|
|
def _product_header_data(ctx: dict, d: dict) -> dict:
|
|
"""Extract product header data for .sx composition."""
|
|
from quart import url_for
|
|
from shared.browser.app.csrf import generate_csrf_token
|
|
|
|
slug = d.get("slug", "")
|
|
hx_select = ctx.get("hx_select_search", "#main-panel")
|
|
cart = ctx.get("cart", [])
|
|
rights = ctx.get("rights", {})
|
|
|
|
# Price data
|
|
pr = _set_prices(d)
|
|
sp_str = _price_str(pr["sp_val"], pr["sp_raw"], pr["sp_cur"]) if pr["sp_val"] else ""
|
|
rp_str = _price_str(pr["rp_val"], pr["rp_raw"], pr["rp_cur"]) if pr["rp_val"] else ""
|
|
|
|
# RRP
|
|
rrp_str = ""
|
|
rrp_raw = d.get("rrp_raw")
|
|
rrp_val = d.get("rrp")
|
|
case_size = d.get("case_size_count") or 1
|
|
if rrp_raw and rrp_val:
|
|
rrp_str = f"{rrp_raw[0]}{rrp_val * case_size:.2f}"
|
|
|
|
# Cart state
|
|
csrf = generate_csrf_token()
|
|
cart_action = url_for("market.browse.product.cart", product_slug=slug)
|
|
quantity = sum(ci.quantity for ci in cart if ci.product.slug == slug) if cart else 0
|
|
cart_url_fn = ctx.get("cart_url")
|
|
cart_href = cart_url_fn("/") if callable(cart_url_fn) else "/"
|
|
|
|
admin_href = ""
|
|
if rights and rights.get("admin"):
|
|
admin_href = url_for("market.browse.product.admin", product_slug=slug)
|
|
|
|
return {
|
|
"title": d.get("title", ""),
|
|
"link-href": url_for("market.browse.product.product_detail", product_slug=slug),
|
|
"hx-select": hx_select,
|
|
"price-data": {
|
|
"cart-id": f"cart-{slug}",
|
|
"cart-action": cart_action,
|
|
"csrf": csrf,
|
|
"quantity": quantity,
|
|
"cart-href": cart_href,
|
|
"sp-val": pr["sp_val"] or "",
|
|
"sp-str": sp_str,
|
|
"rp-val": pr["rp_val"] or "",
|
|
"rp-str": rp_str,
|
|
"rrp-str": rrp_str,
|
|
},
|
|
"admin-href": admin_href,
|
|
}
|
|
|
|
|
|
def _product_header_sx(ctx: dict, d: dict, *, oob: bool = False) -> str:
|
|
"""Build product header as sx — delegates to .sx defcomp."""
|
|
data = _product_header_data(ctx, d)
|
|
return sx_call("market-product-header-from-data", oob=oob, **data)
|
|
|
|
|
|
def _product_admin_header_sx(ctx: dict, d: dict, *, oob: bool = False) -> str:
|
|
"""Build product admin header as sx — delegates to .sx defcomp."""
|
|
from quart import url_for
|
|
slug = d.get("slug", "")
|
|
link_href = url_for("market.browse.product.admin", product_slug=slug)
|
|
return sx_call("market-product-admin-header-from-data",
|
|
link_href=link_href, oob=oob)
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Mobile nav panel data extraction
|
|
# ---------------------------------------------------------------------------
|
|
|
|
def _mobile_nav_data(ctx: dict) -> dict:
|
|
"""Extract mobile nav panel data for .sx composition."""
|
|
from quart import url_for
|
|
from shared.utils import route_prefix
|
|
|
|
prefix = route_prefix()
|
|
categories = ctx.get("categories", {})
|
|
qs = ctx.get("qs", "")
|
|
top_slug = ctx.get("top_slug", "")
|
|
sub_slug = ctx.get("sub_slug", "")
|
|
hx_select = ctx.get("hx_select_search", "#main-panel")
|
|
select_colours = ctx.get("select_colours", "")
|
|
|
|
all_href = prefix + url_for("market.browse.browse_all") + qs
|
|
|
|
cat_data = []
|
|
for cat, data in categories.items():
|
|
cat_slug = data.get("slug", "")
|
|
cat_active = top_slug == cat_slug.lower() if top_slug else False
|
|
cat_href = prefix + url_for("market.browse.browse_top", top_slug=cat_slug) + qs
|
|
|
|
subs = data.get("subs", [])
|
|
sub_data = []
|
|
if subs:
|
|
for sub in subs:
|
|
sub_href = prefix + url_for("market.browse.browse_sub",
|
|
top_slug=cat_slug, sub_slug=sub["slug"]) + qs
|
|
sub_active = cat_active and sub_slug == sub.get("slug")
|
|
sub_label = sub.get("html_label") or sub.get("name", "")
|
|
sub_data.append({
|
|
"href": sub_href,
|
|
"active": sub_active,
|
|
"label": sub_label,
|
|
"count": sub.get("count", 0),
|
|
})
|
|
|
|
cat_data.append({
|
|
"name": cat,
|
|
"href": cat_href,
|
|
"active": cat_active,
|
|
"count": data.get("count", 0),
|
|
"subs": sub_data if sub_data else None,
|
|
})
|
|
|
|
return {
|
|
"categories": cat_data,
|
|
"all-href": all_href,
|
|
"all-active": ctx.get("category_label", "") == "All Products",
|
|
"hx-select": hx_select,
|
|
"select-colours": select_colours,
|
|
}
|
|
|
|
|
|
def _mobile_nav_panel_sx(ctx: dict) -> str:
|
|
"""Build mobile nav panel as sx — delegates to .sx defcomp."""
|
|
data = _mobile_nav_data(ctx)
|
|
return sx_call("market-mobile-nav-from-data", **data)
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Layout registration — all layouts delegate to .sx defcomps
|
|
# ---------------------------------------------------------------------------
|
|
|
|
def _register_market_layouts() -> None:
|
|
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")
|