Add attribute detail pages with live demos for SX reference
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:
@@ -709,4 +709,177 @@ def register(url_prefix: str = "/") -> Blueprint:
|
||||
oob_comp = _oob_code("retry-comp", comp_text)
|
||||
return sx_response(f'(<> {sx_src} {oob_wire} {oob_comp})')
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Reference attribute detail API endpoints (for live demos)
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
def _ref_wire(wire_id: str, sx_src: str) -> str:
|
||||
"""Build OOB swap showing the wire response text."""
|
||||
from sxc.sx_components import _oob_code
|
||||
return _oob_code(f"ref-wire-{wire_id}", sx_src)
|
||||
|
||||
@bp.get("/reference/api/time")
|
||||
async def ref_time():
|
||||
from shared.sx.helpers import sx_response
|
||||
now = datetime.now().strftime("%H:%M:%S")
|
||||
sx_src = f'(span :class "text-stone-800 text-sm" "Server time: " (strong "{now}"))'
|
||||
oob = _ref_wire("sx-get", sx_src)
|
||||
return sx_response(f'(<> {sx_src} {oob})')
|
||||
|
||||
@csrf_exempt
|
||||
@bp.post("/reference/api/greet")
|
||||
async def ref_greet():
|
||||
from shared.sx.helpers import sx_response
|
||||
form = await request.form
|
||||
name = form.get("name") or "stranger"
|
||||
sx_src = f'(span :class "text-stone-800 text-sm" "Hello, " (strong "{name}") "!")'
|
||||
oob = _ref_wire("sx-post", sx_src)
|
||||
return sx_response(f'(<> {sx_src} {oob})')
|
||||
|
||||
@csrf_exempt
|
||||
@bp.put("/reference/api/status")
|
||||
async def ref_status():
|
||||
from shared.sx.helpers import sx_response
|
||||
form = await request.form
|
||||
status = form.get("status", "unknown")
|
||||
sx_src = f'(span :class "text-stone-700 text-sm" "Status: " (strong "{status}") " — updated via PUT")'
|
||||
oob = _ref_wire("sx-put", sx_src)
|
||||
return sx_response(f'(<> {sx_src} {oob})')
|
||||
|
||||
@csrf_exempt
|
||||
@bp.patch("/reference/api/theme")
|
||||
async def ref_theme():
|
||||
from shared.sx.helpers import sx_response
|
||||
form = await request.form
|
||||
theme = form.get("theme", "unknown")
|
||||
sx_src = f'"{theme}"'
|
||||
oob = _ref_wire("sx-patch", sx_src)
|
||||
return sx_response(f'(<> {sx_src} {oob})')
|
||||
|
||||
@csrf_exempt
|
||||
@bp.delete("/reference/api/item/<item_id>")
|
||||
async def ref_delete(item_id: str):
|
||||
from shared.sx.helpers import sx_response
|
||||
oob = _ref_wire("sx-delete", '""')
|
||||
return sx_response(f'(<> {oob})')
|
||||
|
||||
@bp.get("/reference/api/trigger-search")
|
||||
async def ref_trigger_search():
|
||||
from shared.sx.helpers import sx_response
|
||||
q = request.args.get("q", "")
|
||||
if not q:
|
||||
sx_src = '(span :class "text-stone-400 text-sm" "Start typing to trigger a search.")'
|
||||
else:
|
||||
sx_src = f'(span :class "text-stone-800 text-sm" "Results for: " (strong "{q}"))'
|
||||
oob = _ref_wire("sx-trigger", sx_src)
|
||||
return sx_response(f'(<> {sx_src} {oob})')
|
||||
|
||||
@bp.get("/reference/api/swap-item")
|
||||
async def ref_swap_item():
|
||||
from shared.sx.helpers import sx_response
|
||||
now = datetime.now().strftime("%H:%M:%S")
|
||||
sx_src = f'(div :class "text-sm text-violet-700" "New item (" "{now}" ")")'
|
||||
oob = _ref_wire("sx-swap", sx_src)
|
||||
return sx_response(f'(<> {sx_src} {oob})')
|
||||
|
||||
@bp.get("/reference/api/oob")
|
||||
async def ref_oob():
|
||||
from shared.sx.helpers import sx_response
|
||||
now = datetime.now().strftime("%H:%M:%S")
|
||||
sx_src = (
|
||||
f'(<>'
|
||||
f' (span :class "text-emerald-700 text-sm" "Main updated at " "{now}")'
|
||||
f' (div :id "ref-oob-side" :sx-swap-oob "innerHTML"'
|
||||
f' (span :class "text-violet-700 text-sm" "OOB updated at " "{now}")))')
|
||||
oob = _ref_wire("sx-swap-oob", sx_src)
|
||||
return sx_response(f'(<> {sx_src} {oob})')
|
||||
|
||||
@bp.get("/reference/api/select-page")
|
||||
async def ref_select_page():
|
||||
from shared.sx.helpers import sx_response
|
||||
now = datetime.now().strftime("%H:%M:%S")
|
||||
sx_src = (
|
||||
f'(<>'
|
||||
f' (div :id "the-header" (h3 "Page header — not selected"))'
|
||||
f' (div :id "the-content"'
|
||||
f' (span :class "text-emerald-700 text-sm"'
|
||||
f' "This fragment was selected from a larger response. Time: " "{now}"))'
|
||||
f' (div :id "the-footer" (p "Page footer — not selected")))')
|
||||
oob = _ref_wire("sx-select", sx_src)
|
||||
return sx_response(f'(<> {sx_src} {oob})')
|
||||
|
||||
@bp.get("/reference/api/slow-echo")
|
||||
async def ref_slow_echo():
|
||||
from shared.sx.helpers import sx_response
|
||||
await asyncio.sleep(0.8)
|
||||
q = request.args.get("q", "")
|
||||
sx_src = f'(span :class "text-stone-800 text-sm" "Echo: " (strong "{q}"))'
|
||||
oob = _ref_wire("sx-sync", sx_src)
|
||||
return sx_response(f'(<> {sx_src} {oob})')
|
||||
|
||||
@csrf_exempt
|
||||
@bp.post("/reference/api/upload-name")
|
||||
async def ref_upload_name():
|
||||
from shared.sx.helpers import sx_response
|
||||
files = await request.files
|
||||
f = files.get("file")
|
||||
name = f.filename if f else "(no file)"
|
||||
sx_src = f'(span :class "text-stone-800 text-sm" "Received: " (strong "{name}"))'
|
||||
oob = _ref_wire("sx-encoding", sx_src)
|
||||
return sx_response(f'(<> {sx_src} {oob})')
|
||||
|
||||
@bp.get("/reference/api/echo-headers")
|
||||
async def ref_echo_headers():
|
||||
from shared.sx.helpers import sx_response
|
||||
custom = [(k, v) for k, v in request.headers if k.lower().startswith("x-")]
|
||||
if not custom:
|
||||
sx_src = '(span :class "text-stone-400 text-sm" "No custom headers received.")'
|
||||
else:
|
||||
items = " ".join(
|
||||
f'(li (strong "{k}") ": " "{v}")' for k, v in custom)
|
||||
sx_src = f'(ul :class "text-sm text-stone-700 space-y-1" {items})'
|
||||
oob = _ref_wire("sx-headers", sx_src)
|
||||
return sx_response(f'(<> {sx_src} {oob})')
|
||||
|
||||
@bp.get("/reference/api/echo-vals")
|
||||
async def ref_echo_vals_get():
|
||||
from shared.sx.helpers import sx_response
|
||||
vals = list(request.args.items())
|
||||
if not vals:
|
||||
sx_src = '(span :class "text-stone-400 text-sm" "No values received.")'
|
||||
else:
|
||||
items = " ".join(
|
||||
f'(li (strong "{k}") ": " "{v}")' for k, v in vals)
|
||||
sx_src = f'(ul :class "text-sm text-stone-700 space-y-1" {items})'
|
||||
oob_include = _ref_wire("sx-include", sx_src)
|
||||
return sx_response(f'(<> {sx_src} {oob_include})')
|
||||
|
||||
@csrf_exempt
|
||||
@bp.post("/reference/api/echo-vals")
|
||||
async def ref_echo_vals_post():
|
||||
from shared.sx.helpers import sx_response
|
||||
form = await request.form
|
||||
vals = list(form.items())
|
||||
if not vals:
|
||||
sx_src = '(span :class "text-stone-400 text-sm" "No values received.")'
|
||||
else:
|
||||
items = " ".join(
|
||||
f'(li (strong "{k}") ": " "{v}")' for k, v in vals)
|
||||
sx_src = f'(ul :class "text-sm text-stone-700 space-y-1" {items})'
|
||||
oob = _ref_wire("sx-vals", sx_src)
|
||||
return sx_response(f'(<> {sx_src} {oob})')
|
||||
|
||||
_ref_flaky = {"n": 0}
|
||||
|
||||
@bp.get("/reference/api/flaky")
|
||||
async def ref_flaky():
|
||||
from shared.sx.helpers import sx_response
|
||||
_ref_flaky["n"] += 1
|
||||
n = _ref_flaky["n"]
|
||||
if n % 3 != 0:
|
||||
return Response("", status=503, content_type="text/plain")
|
||||
sx_src = f'(span :class "text-emerald-700 text-sm" "Success on attempt " "{n}" "!")'
|
||||
oob = _ref_wire("sx-retry", sx_src)
|
||||
return sx_response(f'(<> {sx_src} {oob})')
|
||||
|
||||
return bp
|
||||
|
||||
Reference in New Issue
Block a user