""" Shared helper functions for s-expression page rendering. These are used by per-service sexp_components.py files to build common page elements (headers, search, etc.) from template context. """ from __future__ import annotations from typing import Any from .jinja_bridge import render from .page import SEARCH_HEADERS_MOBILE, SEARCH_HEADERS_DESKTOP def call_url(ctx: dict, key: str, path: str = "/") -> str: """Call a URL helper from context (e.g., blog_url, account_url).""" fn = ctx.get(key) if callable(fn): return fn(path) return str(fn or "") + path def get_asset_url(ctx: dict) -> str: """Extract the asset URL base from context.""" au = ctx.get("asset_url") if callable(au): result = au("") return result.rsplit("/", 1)[0] if "/" in result else result return au or "" def root_header_html(ctx: dict, *, oob: bool = False) -> str: """Build the root header row HTML.""" return render( "header-row", cart_mini_html=ctx.get("cart_mini_html", ""), blog_url=call_url(ctx, "blog_url", ""), site_title=ctx.get("base_title", ""), nav_tree_html=ctx.get("nav_tree_html", ""), auth_menu_html=ctx.get("auth_menu_html", ""), nav_panel_html=ctx.get("nav_panel_html", ""), oob=oob, ) def search_mobile_html(ctx: dict) -> str: """Build mobile search input HTML.""" return render( "search-mobile", current_local_href=ctx.get("current_local_href", "/"), search=ctx.get("search", ""), search_count=ctx.get("search_count", ""), hx_select=ctx.get("hx_select", "#main-panel"), search_headers_mobile=SEARCH_HEADERS_MOBILE, ) def search_desktop_html(ctx: dict) -> str: """Build desktop search input HTML.""" return render( "search-desktop", current_local_href=ctx.get("current_local_href", "/"), search=ctx.get("search", ""), search_count=ctx.get("search_count", ""), hx_select=ctx.get("hx_select", "#main-panel"), search_headers_desktop=SEARCH_HEADERS_DESKTOP, ) def full_page(ctx: dict, *, header_rows_html: str, filter_html: str = "", aside_html: str = "", content_html: str = "", menu_html: str = "", body_end_html: str = "", meta_html: str = "") -> str: """Render a full app page with the standard layout.""" return render( "app-layout", title=ctx.get("base_title", "Rose Ash"), asset_url=get_asset_url(ctx), meta_html=meta_html, header_rows_html=header_rows_html, menu_html=menu_html, filter_html=filter_html, aside_html=aside_html, content_html=content_html, body_end_html=body_end_html, ) def oob_page(ctx: dict, *, oobs_html: str = "", filter_html: str = "", aside_html: str = "", content_html: str = "", menu_html: str = "") -> str: """Render an OOB response with standard swap targets.""" return render( "oob-response", oobs_html=oobs_html, filter_html=filter_html, aside_html=aside_html, menu_html=menu_html, content_html=content_html, )