Files
rose-ash/sx/sxc/pages/__init__.py
giles a8c0741f54
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 4m5s
Add SX editor to post edit page, prevent sx_content clearing on save
- Add sx_content to _post_to_edit_dict so edit page receives existing content
- Add SX/Koenig editor tabs, sx-editor mount point, and SxEditor.mount init
- Only pass sx_content to writer_update when form field is present (prevents
  accidental clearing when editing via Koenig-only path)
- Add csrf_exempt to example API POST/DELETE/PUT demo endpoints
- Add defpage infrastructure (pages.py, layouts.py) and sx docs page definitions
- Add defhandler definitions for example API handlers (examples.sx)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 10:23:33 +00:00

170 lines
5.9 KiB
Python

"""SX docs defpage setup — registers layouts and page helpers."""
from __future__ import annotations
from typing import Any
def setup_sx_pages() -> None:
"""Register sx-specific layouts, page helpers, and load page definitions.
Called during app startup before mount_pages().
"""
_register_sx_layouts()
_register_sx_helpers()
_load_sx_page_files()
def _load_sx_page_files() -> None:
"""Load defpage definitions from sx/sxc/pages/*.sx."""
import os
from shared.sx.pages import load_page_dir
pages_dir = os.path.dirname(__file__)
load_page_dir(pages_dir, "sx")
# ---------------------------------------------------------------------------
# Layouts
# ---------------------------------------------------------------------------
def _register_sx_layouts() -> None:
"""Register the sx docs layout presets."""
from shared.sx.layouts import register_custom_layout
register_custom_layout("sx", _sx_full_headers, _sx_oob_headers)
register_custom_layout("sx-section", _sx_section_full_headers, _sx_section_oob_headers)
def _sx_full_headers(ctx: dict, **kw: Any) -> str:
"""Full headers for sx home page: root + sx menu row."""
from shared.sx.helpers import root_header_sx
from sxc.sx_components import _sx_header_sx, _main_nav_sx
main_nav = _main_nav_sx(kw.get("section"))
root_hdr = root_header_sx(ctx)
sx_row = _sx_header_sx(main_nav)
return "(<> " + root_hdr + " " + sx_row + ")"
def _sx_oob_headers(ctx: dict, **kw: Any) -> str:
"""OOB headers for sx home page."""
from shared.sx.helpers import root_header_sx, oob_header_sx
from sxc.sx_components import _sx_header_sx, _main_nav_sx
root_hdr = root_header_sx(ctx)
main_nav = _main_nav_sx(kw.get("section"))
sx_row = _sx_header_sx(main_nav)
rows = "(<> " + root_hdr + " " + sx_row + ")"
return oob_header_sx("root-header-child", "sx-header-child", rows)
def _sx_section_full_headers(ctx: dict, **kw: Any) -> str:
"""Full headers for sx section pages: root + sx row + sub row."""
from shared.sx.helpers import root_header_sx
from sxc.sx_components import (
_sx_header_sx, _main_nav_sx, _sub_row_sx,
)
section = kw.get("section", "")
sub_label = kw.get("sub_label", section)
sub_href = kw.get("sub_href", "/")
sub_nav = kw.get("sub_nav", "")
selected = kw.get("selected", "")
root_hdr = root_header_sx(ctx)
main_nav = _main_nav_sx(section)
sub_row = _sub_row_sx(sub_label, sub_href, sub_nav, selected)
sx_row = _sx_header_sx(main_nav, child=sub_row)
return "(<> " + root_hdr + " " + sx_row + ")"
def _sx_section_oob_headers(ctx: dict, **kw: Any) -> str:
"""OOB headers for sx section pages."""
from shared.sx.helpers import root_header_sx, oob_header_sx
from sxc.sx_components import (
_sx_header_sx, _main_nav_sx, _sub_row_sx,
)
section = kw.get("section", "")
sub_label = kw.get("sub_label", section)
sub_href = kw.get("sub_href", "/")
sub_nav = kw.get("sub_nav", "")
selected = kw.get("selected", "")
root_hdr = root_header_sx(ctx)
main_nav = _main_nav_sx(section)
sub_row = _sub_row_sx(sub_label, sub_href, sub_nav, selected)
sx_row = _sx_header_sx(main_nav, child=sub_row)
rows = "(<> " + root_hdr + " " + sx_row + ")"
return oob_header_sx("root-header-child", "sx-header-child", rows)
# ---------------------------------------------------------------------------
# Page helpers — Python functions callable from defpage content expressions
# ---------------------------------------------------------------------------
def _register_sx_helpers() -> None:
"""Register Python content builder functions as page helpers."""
from shared.sx.pages import register_page_helpers
from sxc.sx_components import (
_docs_content_sx, _reference_content_sx,
_protocol_content_sx, _examples_content_sx,
_essay_content_sx,
_docs_nav_sx, _reference_nav_sx,
_protocols_nav_sx, _examples_nav_sx, _essays_nav_sx,
)
from content.highlight import highlight as _highlight
from content.pages import (
DOCS_NAV, REFERENCE_NAV, PROTOCOLS_NAV,
EXAMPLES_NAV, ESSAYS_NAV,
)
def _find_current(nav_list, slug, match_fn=None):
"""Find the current nav label for a slug."""
if match_fn:
return match_fn(nav_list, slug)
for label, href in nav_list:
if href.endswith(slug):
return label
return None
def _home_content():
"""Build home page content (uses highlight for hero code block)."""
hero_code = _highlight(
'(div :class "p-4 bg-white rounded shadow"\n'
' (h1 :class "text-2xl font-bold" "Hello")\n'
' (button :sx-get "/api/data"\n'
' :sx-target "#result"\n'
' "Load data"))', "lisp")
return (
f'(div :id "main-content"'
f' (~sx-hero {hero_code})'
f' (~sx-philosophy)'
f' (~sx-how-it-works)'
f' (~sx-credits))'
)
register_page_helpers("sx", {
# Content builders
"home-content": _home_content,
"docs-content": _docs_content_sx,
"reference-content": _reference_content_sx,
"protocol-content": _protocol_content_sx,
"examples-content": _examples_content_sx,
"essay-content": _essay_content_sx,
"highlight": _highlight,
# Nav builders
"docs-nav": _docs_nav_sx,
"reference-nav": _reference_nav_sx,
"protocols-nav": _protocols_nav_sx,
"examples-nav": _examples_nav_sx,
"essays-nav": _essays_nav_sx,
# Nav data (for current label lookup)
"DOCS_NAV": DOCS_NAV,
"REFERENCE_NAV": REFERENCE_NAV,
"PROTOCOLS_NAV": PROTOCOLS_NAV,
"EXAMPLES_NAV": EXAMPLES_NAV,
"ESSAYS_NAV": ESSAYS_NAV,
# Utility
"find-current": _find_current,
})