"""Singleton widget registry for cross-domain UI composition. Usage:: from shared.services.widget_registry import widgets # Register at app startup (after domain services) widgets.add_container_nav(NavWidget(...)) # Query in templates / context processors for w in widgets.container_nav: ctx = await w.context_fn(session, container_type="page", ...) """ from __future__ import annotations from shared.contracts.widgets import ( NavWidget, CardWidget, AccountPageWidget, AccountNavLink, ) class _WidgetRegistry: """Central registry holding all widget descriptors. Widgets are added at startup and read at request time. Properties return sorted-by-order copies. """ def __init__(self) -> None: self._container_nav: list[NavWidget] = [] self._container_card: list[CardWidget] = [] self._account_pages: list[AccountPageWidget] = [] self._account_nav: list[AccountNavLink] = [] # -- registration --------------------------------------------------------- def add_container_nav(self, w: NavWidget) -> None: self._container_nav.append(w) def add_container_card(self, w: CardWidget) -> None: self._container_card.append(w) def add_account_page(self, w: AccountPageWidget) -> None: self._account_pages.append(w) # Auto-create a matching internal nav link slug = w.slug def _href(s=slug): from shared.infrastructure.urls import blog_url return blog_url(f"/auth/{s}/") self._account_nav.append(AccountNavLink( label=w.label, order=w.order, href_fn=_href, external=False, )) def add_account_link(self, link: AccountNavLink) -> None: self._account_nav.append(link) # -- read access (sorted copies) ------------------------------------------ @property def container_nav(self) -> list[NavWidget]: return sorted(self._container_nav, key=lambda w: w.order) @property def container_cards(self) -> list[CardWidget]: return sorted(self._container_card, key=lambda w: w.order) @property def account_pages(self) -> list[AccountPageWidget]: return sorted(self._account_pages, key=lambda w: w.order) @property def account_nav(self) -> list[AccountNavLink]: return sorted(self._account_nav, key=lambda w: w.order) def account_page_by_slug(self, slug: str) -> AccountPageWidget | None: for w in self._account_pages: if w.slug == slug: return w return None # Module-level singleton — import this everywhere. widgets = _WidgetRegistry()