Add attribute detail pages with live demos for SX reference
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 4m45s
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 4m45s
Per-attribute documentation pages at /reference/attributes/<slug> with: - Live interactive demos (demo components in reference.sx) - S-expression source code display - Server handler code shown as s-expressions (defhandlers in handlers/reference.sx) - Wire response display via OOB swaps on demo interaction - Linked attribute names in the reference table Covers all 20 implemented attributes (sx-get/post/put/delete/patch, sx-trigger/target/swap/swap-oob/select/confirm/push-url/sync/encoding/ headers/include/vals/media/disable/on:*, sx-retry, data-sx, data-sx-env). Also adds sx-on:* to BEHAVIOR_ATTRS, updates REFERENCE_NAV to link /reference/attributes, and makes /reference/ an index page. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -189,10 +189,13 @@ def _doc_nav_sx(items: list[tuple[str, str]], current: str) -> str:
|
||||
|
||||
def _attr_table_sx(title: str, attrs: list[tuple[str, str, bool]]) -> str:
|
||||
"""Build an attribute reference table."""
|
||||
from content.pages import ATTR_DETAILS
|
||||
rows = []
|
||||
for attr, desc, exists in attrs:
|
||||
href = f"/reference/attributes/{attr}" if exists and attr in ATTR_DETAILS else None
|
||||
rows.append(sx_call("doc-attr-row", attr=attr, description=desc,
|
||||
exists="true" if exists else None))
|
||||
exists="true" if exists else None,
|
||||
href=href))
|
||||
return (
|
||||
f'(div :class "space-y-3"'
|
||||
f' (h3 :class "text-xl font-semibold text-stone-700" "{title}")'
|
||||
@@ -470,7 +473,6 @@ def _docs_server_rendering_sx() -> str:
|
||||
|
||||
def _reference_content_sx(slug: str) -> str:
|
||||
builders = {
|
||||
"": _reference_attrs_sx,
|
||||
"attributes": _reference_attrs_sx,
|
||||
"headers": _reference_headers_sx,
|
||||
"events": _reference_events_sx,
|
||||
@@ -479,6 +481,98 @@ def _reference_content_sx(slug: str) -> str:
|
||||
return builders.get(slug or "", _reference_attrs_sx)()
|
||||
|
||||
|
||||
def _reference_index_sx() -> str:
|
||||
"""Build the reference index page with links to sub-sections."""
|
||||
sections = [
|
||||
("Attributes", "/reference/attributes",
|
||||
"All sx attributes — request verbs, behavior modifiers, and sx-unique features."),
|
||||
("Headers", "/reference/headers",
|
||||
"Custom HTTP headers used to coordinate between the sx client and server."),
|
||||
("Events", "/reference/events",
|
||||
"DOM events fired during the sx request lifecycle."),
|
||||
("JS API", "/reference/js-api",
|
||||
"JavaScript functions for parsing, evaluating, and rendering s-expressions."),
|
||||
]
|
||||
cards = []
|
||||
for label, href, desc in sections:
|
||||
cards.append(
|
||||
f'(a :href "{href}"'
|
||||
f' :sx-get "{href}" :sx-target "#main-panel" :sx-select "#main-panel"'
|
||||
f' :sx-swap "outerHTML" :sx-push-url "true"'
|
||||
f' :class "block p-5 rounded-lg border border-stone-200 hover:border-violet-300'
|
||||
f' hover:shadow-sm transition-all no-underline"'
|
||||
f' (h3 :class "text-lg font-semibold text-violet-700 mb-1" "{label}")'
|
||||
f' (p :class "text-stone-600 text-sm" "{desc}"))'
|
||||
)
|
||||
return (
|
||||
f'(~doc-page :title "Reference"'
|
||||
f' (p :class "text-stone-600 mb-6"'
|
||||
f' "Complete reference for the sx client library.")'
|
||||
f' (div :class "grid gap-4 sm:grid-cols-2"'
|
||||
f' {" ".join(cards)}))'
|
||||
)
|
||||
|
||||
|
||||
def _reference_attr_detail_sx(slug: str) -> str:
|
||||
"""Build a detail page for a single sx attribute."""
|
||||
from content.pages import ATTR_DETAILS
|
||||
detail = ATTR_DETAILS.get(slug)
|
||||
if not detail:
|
||||
return (
|
||||
f'(~doc-page :title "Not Found"'
|
||||
f' (p :class "text-stone-600"'
|
||||
f' "No documentation found for \\"{slug}\\"."))'
|
||||
)
|
||||
|
||||
title = slug
|
||||
desc = detail["description"]
|
||||
escaped_desc = desc.replace('\\', '\\\\').replace('"', '\\"')
|
||||
|
||||
# Live demo
|
||||
demo_name = detail.get("demo")
|
||||
demo_sx = ""
|
||||
if demo_name:
|
||||
demo_sx = (
|
||||
f' (~example-card :title "Demo"'
|
||||
f' (~example-demo (~{demo_name})))'
|
||||
)
|
||||
|
||||
# S-expression source
|
||||
example_sx = _example_code(detail["example"], "lisp")
|
||||
|
||||
# Server handler (s-expression)
|
||||
handler_sx = ""
|
||||
if "handler" in detail:
|
||||
handler_sx = (
|
||||
f' (h3 :class "text-lg font-semibold text-stone-700 mt-6"'
|
||||
f' "Server handler")'
|
||||
f' {_example_code(detail["handler"], "lisp")}'
|
||||
)
|
||||
|
||||
# Wire response placeholder (only for attrs with server interaction)
|
||||
wire_sx = ""
|
||||
if "handler" in detail:
|
||||
wire_id = slug.replace(":", "-").replace("*", "star")
|
||||
wire_sx = (
|
||||
f' (h3 :class "text-lg font-semibold text-stone-700 mt-6"'
|
||||
f' "Wire response")'
|
||||
f' (p :class "text-stone-500 text-sm mb-2"'
|
||||
f' "Trigger the demo to see the raw response the server sends.")'
|
||||
f' {_placeholder("ref-wire-" + wire_id)}'
|
||||
)
|
||||
|
||||
return (
|
||||
f'(~doc-page :title "{title}"'
|
||||
f' (p :class "text-stone-600 mb-6" "{escaped_desc}")'
|
||||
f' {demo_sx}'
|
||||
f' (h3 :class "text-lg font-semibold text-stone-700 mt-6"'
|
||||
f' "S-expression")'
|
||||
f' {example_sx}'
|
||||
f' {handler_sx}'
|
||||
f' {wire_sx})'
|
||||
)
|
||||
|
||||
|
||||
def _reference_attrs_sx() -> str:
|
||||
from content.pages import REQUEST_ATTRS, BEHAVIOR_ATTRS, SX_UNIQUE_ATTRS, HTMX_MISSING_ATTRS
|
||||
return (
|
||||
|
||||
Reference in New Issue
Block a user