Python no longer generates s-expression strings. All SX rendering now goes through render_to_sx() which builds AST from native Python values and evaluates via async_eval_to_sx() — no SX string literals in Python. - Add render_to_sx()/render_to_html() infrastructure in shared/sx/helpers.py - Add (abort status msg) IO primitive in shared/sx/primitives_io.py - Convert all 9 services: ~650 sx_call() invocations replaced - Convert shared helpers (root_header_sx, full_page_sx, etc.) to async - Fix likes service import bug (likes.models → models) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
181 lines
6.9 KiB
Python
181 lines
6.9 KiB
Python
"""Market defpage setup — registers layouts, page helpers, and loads .sx pages."""
|
|
from __future__ import annotations
|
|
|
|
from typing import Any
|
|
|
|
|
|
def setup_market_pages() -> None:
|
|
"""Register market-specific layouts, page helpers, and load page definitions."""
|
|
_register_market_layouts()
|
|
_register_market_helpers()
|
|
_load_market_page_files()
|
|
|
|
|
|
def _load_market_page_files() -> None:
|
|
import os
|
|
from shared.sx.pages import load_page_dir
|
|
load_page_dir(os.path.dirname(__file__), "market")
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Layouts
|
|
# ---------------------------------------------------------------------------
|
|
|
|
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 root_header_sx, header_child_sx
|
|
from sx.sx_components import _post_header_sx, _market_header_sx
|
|
|
|
root_hdr = await root_header_sx(ctx)
|
|
child = "(<> " + await _post_header_sx(ctx) + " " + await _market_header_sx(ctx) + ")"
|
|
return "(<> " + root_hdr + " " + await header_child_sx(child) + ")"
|
|
|
|
|
|
async def _market_oob(ctx: dict, **kw: Any) -> str:
|
|
from shared.sx.helpers import oob_header_sx
|
|
from sx.sx_components import _post_header_sx, _market_header_sx, _clear_deeper_oob
|
|
|
|
oobs = await oob_header_sx("post-header-child", "market-header-child",
|
|
await _market_header_sx(ctx))
|
|
oobs = "(<> " + oobs + " " + await _post_header_sx(ctx, oob=True) + " "
|
|
oobs += _clear_deeper_oob("post-row", "post-header-child",
|
|
"market-row", "market-header-child") + ")"
|
|
return oobs
|
|
|
|
|
|
async def _market_mobile(ctx: dict, **kw: Any) -> str:
|
|
from sx.sx_components import _mobile_nav_panel_sx
|
|
return await _mobile_nav_panel_sx(ctx)
|
|
|
|
|
|
async def _market_admin_full(ctx: dict, **kw: Any) -> str:
|
|
from shared.sx.helpers import root_header_sx, header_child_sx
|
|
from sx.sx_components import (
|
|
_post_header_sx, _market_header_sx, _market_admin_header_sx,
|
|
)
|
|
|
|
selected = kw.get("selected", "")
|
|
root_hdr = await root_header_sx(ctx)
|
|
child = "(<> " + await _post_header_sx(ctx) + " " + await _market_header_sx(ctx) + " "
|
|
child += await _market_admin_header_sx(ctx, selected=selected) + ")"
|
|
return "(<> " + root_hdr + " " + await header_child_sx(child) + ")"
|
|
|
|
|
|
async def _market_admin_oob(ctx: dict, **kw: Any) -> str:
|
|
from shared.sx.helpers import oob_header_sx
|
|
from sx.sx_components import (
|
|
_market_header_sx, _market_admin_header_sx, _clear_deeper_oob,
|
|
)
|
|
|
|
selected = kw.get("selected", "")
|
|
oobs = "(<> " + await _market_header_sx(ctx, oob=True) + " "
|
|
oobs += await oob_header_sx("market-header-child", "market-admin-header-child",
|
|
await _market_admin_header_sx(ctx, selected=selected)) + " "
|
|
oobs += _clear_deeper_oob("post-row", "post-header-child",
|
|
"market-row", "market-header-child",
|
|
"market-admin-row", "market-admin-header-child") + ")"
|
|
return oobs
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Page helpers
|
|
# ---------------------------------------------------------------------------
|
|
|
|
def _register_market_helpers() -> None:
|
|
from shared.sx.pages import register_page_helpers
|
|
|
|
register_page_helpers("market", {
|
|
"all-markets-content": _h_all_markets_content,
|
|
"page-markets-content": _h_page_markets_content,
|
|
"page-admin-content": _h_page_admin_content,
|
|
"market-home-content": _h_market_home_content,
|
|
"market-admin-content": _h_market_admin_content,
|
|
})
|
|
|
|
|
|
async def _h_all_markets_content(**kw):
|
|
from quart import g, url_for, request
|
|
from shared.utils import route_prefix
|
|
from shared.services.registry import services
|
|
from shared.infrastructure.data_client import fetch_data
|
|
from shared.contracts.dtos import PostDTO, dto_from_dict
|
|
|
|
page = int(request.args.get("page", 1))
|
|
markets, has_more = await services.market.list_marketplaces(
|
|
g.s, page=page, per_page=20,
|
|
)
|
|
|
|
page_info = {}
|
|
if markets:
|
|
post_ids = list({m.container_id for m in markets if m.container_type == "page"})
|
|
if post_ids:
|
|
raw_posts = await fetch_data("blog", "posts-by-ids",
|
|
params={"ids": ",".join(str(i) for i in post_ids)},
|
|
required=False) or []
|
|
for raw_p in raw_posts:
|
|
p = dto_from_dict(PostDTO, raw_p)
|
|
page_info[p.id] = {"title": p.title, "slug": p.slug}
|
|
|
|
if not markets:
|
|
from sx.sx_components import _no_markets_sx
|
|
return await _no_markets_sx()
|
|
|
|
prefix = route_prefix()
|
|
next_url = prefix + url_for("all_markets.markets_fragment", page=page + 1)
|
|
|
|
from sx.sx_components import _market_cards_sx, _markets_grid
|
|
cards = await _market_cards_sx(markets, page_info, page, has_more, next_url)
|
|
content = await _markets_grid(cards)
|
|
return "(<> " + content + " " + '(div :class "pb-8")' + ")"
|
|
|
|
|
|
async def _h_page_markets_content(slug=None, **kw):
|
|
from quart import g, url_for, request
|
|
from shared.utils import route_prefix
|
|
from shared.services.registry import services
|
|
|
|
post = g.post_data["post"]
|
|
page = int(request.args.get("page", 1))
|
|
markets, has_more = await services.market.list_marketplaces(
|
|
g.s, "page", post["id"], page=page, per_page=20,
|
|
)
|
|
post_slug = post.get("slug", "")
|
|
|
|
if not markets:
|
|
from sx.sx_components import _no_markets_sx
|
|
return await _no_markets_sx("No markets for this page")
|
|
|
|
prefix = route_prefix()
|
|
next_url = prefix + url_for("page_markets.markets_fragment", page=page + 1)
|
|
|
|
from sx.sx_components import _market_cards_sx, _markets_grid
|
|
cards = await _market_cards_sx(markets, {}, page, has_more, next_url,
|
|
show_page_badge=False, post_slug=post_slug)
|
|
content = await _markets_grid(cards)
|
|
return "(<> " + content + " " + '(div :class "pb-8")' + ")"
|
|
|
|
|
|
async def _h_page_admin_content(slug=None, **kw):
|
|
from shared.sx.page import get_template_context
|
|
from sx.sx_components import _markets_admin_panel_sx
|
|
ctx = await get_template_context()
|
|
content = await _markets_admin_panel_sx(ctx)
|
|
return '(div :id "main-panel" ' + content + ')'
|
|
|
|
|
|
async def _h_market_home_content(page_slug=None, market_slug=None, **kw):
|
|
from quart import g
|
|
post_data = getattr(g, "post_data", {})
|
|
post = post_data.get("post", {})
|
|
from sx.sx_components import _market_landing_content_sx
|
|
return await _market_landing_content_sx(post)
|
|
|
|
|
|
def _h_market_admin_content(page_slug=None, market_slug=None, **kw):
|
|
return '"market admin"'
|