17 Commits

Author SHA1 Message Date
60ed828e0e Merge branch 'macros'
Some checks failed
Build and Deploy / build-and-deploy (push) Has been cancelled
# Conflicts:
#	blog/bp/post/admin/routes.py
#	events/sxc/pages/calendar.py
#	events/sxc/pages/entries.py
#	events/sxc/pages/slots.py
#	events/sxc/pages/tickets.py
2026-03-05 16:40:06 +00:00
2a04aaad5e Fix market header ImportError and sx docs menu bar 3 OOB insertion
- market/sx/layouts.sx: Update ~market-header-auto macro to build nav
  from data fields via ~market-desktop-nav-from-data instead of
  expecting pre-built "desktop-nav" SxExpr (removed in Phase 9)
- shared/sx/primitives_io.py: Import _market_header_data instead of
  deleted _desktop_category_nav_sx, return individual data fields
- sx/sx/layouts.sx: Fix ~sx-section-layout-oob to use ~oob-header-sx
  for inserting sub-row into always-existing container div

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 08:50:48 +00:00
51ebf347ba Move events/market/blog composition from Python to .sx defcomps (Phase 9)
Some checks failed
Build and Deploy / build-and-deploy (push) Failing after 2m33s
Continues the pattern of eliminating Python sx_call tree-building in favour
of data-driven .sx defcomps. POST/PUT/DELETE routes now pass plain data
(dicts, lists, scalars) and let .sx handle iteration, conditionals, and
layout via map/let/when/if. Single response components wrap OOB swaps.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 08:17:09 +00:00
e81d77437e Move market composition from Python to .sx defcomps (Phase 3)
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>
2026-03-05 01:11:57 +00:00
1077fae815 Merge branch 'worktree-sx-layout-conversion' into macros
# Conflicts:
#	blog/sxc/pages/layouts.py
#	cart/sxc/pages/layouts.py
#	events/sxc/pages/helpers.py
#	events/sxc/pages/layouts.py
#	market/sxc/pages/layouts.py
#	sx/sxc/pages/layouts.py
2026-03-04 22:25:52 +00:00
57a31a3b83 Convert all 23 register_custom_layout calls to register_sx_layout across 6 services
Layout defcomps are now fully self-contained via IO-primitive auto-fetch
macros, eliminating Python layout functions that manually threaded context
values through SxExpr wrappers.

Services converted:
- Federation (1 layout): social
- Blog (7 layouts): blog, blog-settings, blog-cache, blog-snippets,
  blog-menu-items, blog-tag-groups, blog-tag-group-edit
- SX docs (2 layouts): sx, sx-section
- Cart (2 layouts): cart-page, cart-admin + orders/order-detail
- Events (9 layouts): calendar-admin, slots, slot, day-admin, entry,
  entry-admin, ticket-types, ticket-type, markets
- Market (2 layouts): market, market-admin

New IO primitives added to shared/sx/primitives_io.py:
- federation-actor-ctx, cart-page-ctx, request-view-args
- events-calendar-ctx, events-day-ctx, events-entry-ctx,
  events-slot-ctx, events-ticket-type-ctx
- market-header-ctx (pre-builds desktop/mobile nav as SxExpr)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 22:21:44 +00:00
278ae3e8f6 Make SxExpr a str subclass, sx_call/render functions return SxExpr
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>
2026-03-04 21:47:00 +00:00
7fda7a8027 Replace env free-variable threading with IO-primitive auto-fetch macros
Layout components now self-resolve context (cart-mini, auth-menu, nav-tree,
rights, URLs) via new IO primitives (root-header-ctx, select-colours,
account-nav-ctx, app-rights) and defmacro wrappers (~root-header-auto,
~auth-header-row-auto, ~root-mobile-auto). This eliminates _ctx_to_env(),
HELPER_CSS_CLASSES, and verbose :key threading across all 10 services.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 18:20:57 +00:00
1dbf600af2 Convert test/cart/blog/market layouts to use _ctx_to_env + render_to_sx_with_env
Phase 4 (Test): Update ~test-layout-full and ~test-detail-layout-full defcomps
to use ~root-header with env free variables. Switch render functions to
render_to_sx_with_env.

Phase 5 (Cart): Convert cart-page, cart-admin, and order render functions.
Update cart .sx layout defcomps to use ~root-header from free variables.

Phase 6 (Blog): Convert all 7 blog layouts (blog, settings, sub-settings x5).
Remove all root_header_sx calls from blog.

Phase 7 (Market): Convert market and market-admin layouts plus browse/product
render functions. Remove root_header_sx import.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 15:02:59 +00:00
049796c391 Delete market sx_components.py — move all rendering to sxc/pages
Phase 6 of the zero-Python-rendering plan. All 46 rendering functions
move from market/sx/sx_components.py into market/sxc/pages/__init__.py.
Route handlers import from sxc.pages instead. load_service_components
call moves into _load_market_page_files.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 11:08:44 +00:00
400667b15a Delete account/sx/sx_components.py — all rendering now in .sx
Phase 1 of zero-Python rendering: account service.

- Auth pages (login, device, check-email) use _render_auth_page() helper
  calling render_to_sx() + full_page_sx() directly in routes
- Newsletter toggle POST renders inline via render_to_sx()
- Newsletter page helper returns data dict; defpage :data slot fetches,
  :content slot renders via ~account-newsletters-content defcomp
- Fragment page uses (frag ...) IO primitive directly in .sx
- Defpage _eval_slot now uses async_eval_slot_to_sx which expands
  component bodies server-side (executing IO) but serializes tags as SX
- Fix pre-existing OOB ParseError: _eval_slot was producing HTML instead
  of s-expressions for component content slots
- Fix market url_for endpoint: defpage_market_home (app-level, not blueprint)
- Fix events calendar nav: wrap multiple SX parts in fragment

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 01:16:01 +00:00
e085fe43b4 Replace sx_call() with render_to_sx() across all services
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>
2026-03-04 00:08:33 +00:00
c243d17eeb Migrate all apps to defpage declarative page routes
Replace Python GET page handlers with declarative defpage definitions in .sx
files across all 8 apps (sx docs, orders, account, market, cart, federation,
events, blog). Each app now has sxc/pages/ with setup functions, layout
registrations, page helpers, and .sx defpage declarations.

Core infrastructure: add g I/O primitive, PageDef support for auth/layout/
data/content/filter/aside/menu slots, post_author auth level, and custom
layout registration. Remove ~1400 lines of render_*_page/render_*_oob
boilerplate. Update all endpoint references in routes, sx_components, and
templates to defpage_* naming.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 14:52:34 +00:00
ab75e505a8 Add macros, declarative handlers (defhandler), and convert all fragment routes to sx
Phase 1 — Macros: defmacro + quasiquote syntax (`, ,, ,@) in parser,
evaluator, HTML renderer, and JS mirror. Macro type, expansion, and
round-trip serialization.

Phase 2 — Expanded primitives: app-url, url-for, asset-url, config,
format-date, parse-int (pure); service, request-arg, request-path,
nav-tree, get-children (I/O); jinja-global, relations-from (pure).
Updated _io_service to accept (service "registry-name" "method" :kwargs)
with auto kebab→snake conversion. DTO-to-dict now expands datetime fields
into year/month/day convenience keys. Tuple returns converted to lists.

Phase 3 — Declarative handlers: HandlerDef type, defhandler special form,
handler registry (service → name → HandlerDef), async evaluator+renderer
(async_eval.py) that awaits I/O primitives inline within control flow.
Handler loading from .sx files, execute_handler, blueprint factory.

Phase 4 — Convert all fragment routes: 13 Python fragment handlers across
8 services replaced with declarative .sx handler files. All routes.py
simplified to uniform sx dispatch pattern. Two Jinja HTML handlers
(events/container-cards, events/account-page) kept as Python.

New files: shared/sx/async_eval.py, shared/sx/handlers.py,
shared/sx/tests/test_handlers.py, plus 13 handler .sx files under
{service}/sx/handlers/. MarketService.product_by_slug() added.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 00:22:18 +00:00
c0d369eb8e Refactor SX templates: shared components, Python migration, cleanup
- Extract shared components (empty-state, delete-btn, sentinel, crud-*,
  view-toggle, img-or-placeholder, avatar, sumup-settings-form, auth
  forms, order tables/detail/checkout)
- Migrate all Python sx_call() callers to use shared components directly
- Remove 55+ thin wrapper defcomps from domain .sx files
- Remove trivial passthrough wrappers (blog-header-label, market-card-text, etc)
- Unify duplicate auth flows (account + federation) into shared/sx/templates/auth.sx
- Unify duplicate order views (cart + orders) into shared/sx/templates/orders.sx
- Disable static file caching in dev (SEND_FILE_MAX_AGE_DEFAULT=0)
- Add SX response validation and debug headers

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 20:34:34 +00:00
755313bd29 Add market admin CRUD: list, create, and delete marketplaces
Replaces placeholder "Market admin" text with a functional admin panel
that lists marketplaces for a page and supports create/delete via sx,
mirroring the events calendar admin pattern.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 19:16:39 +00:00
e8bc228c7f Rebrand sexp → sx across web platform (173 files)
Rename all sexp directories, files, identifiers, and references to sx.
artdag/ excluded (separate media processing DSL).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 11:06:57 +00:00