Component names now reflect filesystem location using / as path separator
and : as namespace separator for shared components:
~sx-header → ~layouts/header
~layout-app-body → ~shared:layout/app-body
~blog-admin-dashboard → ~admin/dashboard
209 files, 4,941 replacements across all services.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
SxExpr is now a str subclass so it works everywhere a plain string
does (join, isinstance, f-strings) while serialize() still emits it
unquoted. sx_call() and all internal render functions (_render_to_sx,
async_eval_to_sx, etc.) return SxExpr, eliminating the "forgot to
wrap" bug class that caused the sx_content leak and list serialization
bugs.
- Phase 0: SxExpr(str) with .source property, __add__/__radd__
- Phase 1: sx_call returns SxExpr (drop-in, all 200+ sites unchanged)
- Phase 2: async_eval_to_sx, async_eval_slot_to_sx, _render_to_sx,
mobile_menu_sx return SxExpr; remove isinstance(str) workaround
- Phase 3: Remove ~150 redundant SxExpr() wrappings across 45 files
- Phase 4: serialize() docstring, handler return docs, ;; returns: sx
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add dict recursion to _convert_result for service methods returning dict[K, list[DTO]]
- New container-cards.sx: parses post_ids/slugs, calls confirmed-entries-for-posts, emits card-widget markers
- New account-page.sx: dispatches on slug for tickets/bookings panels with status pills and empty states
- Fix blog _parse_card_fragments to handle SxExpr via str() cast
- Remove events Python fragment handlers and simplify app.py to plain auto_mount
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>