diff --git a/shared/static/scripts/sx-browser.js b/shared/static/scripts/sx-browser.js index 20883b4..c043acc 100644 --- a/shared/static/scripts/sx-browser.js +++ b/shared/static/scripts/sx-browser.js @@ -14,7 +14,7 @@ // ========================================================================= var NIL = Object.freeze({ _nil: true, toString: function() { return "nil"; } }); - var SX_VERSION = "2026-03-11T17:12:38Z"; + var SX_VERSION = "2026-03-11T17:38:00Z"; function isNil(x) { return x === NIL || x === null || x === undefined; } function isSxTruthy(x) { return x !== false && !isNil(x); } @@ -275,6 +275,7 @@ function error(msg) { throw new Error(msg); } function inspect(x) { return JSON.stringify(x); } + function debugLog() { console.error.apply(console, ["[sx-debug]"].concat(Array.prototype.slice.call(arguments))); } @@ -355,7 +356,7 @@ PRIMITIVES["index-of"] = function(s, needle, from) { return String(s).indexOf(needle, from || 0); }; PRIMITIVES["starts-with?"] = function(s, p) { return String(s).indexOf(p) === 0; }; PRIMITIVES["ends-with?"] = function(s, p) { var str = String(s); return str.indexOf(p, str.length - p.length) !== -1; }; - PRIMITIVES["slice"] = function(c, a, b) { return b !== undefined ? c.slice(a, b) : c.slice(a); }; + PRIMITIVES["slice"] = function(c, a, b) { if (!c || typeof c.slice !== "function") { console.error("[sx-debug] slice called on non-sliceable:", typeof c, c, "a=", a, "b=", b, new Error().stack); return []; } return b !== undefined ? c.slice(a, b) : c.slice(a); }; PRIMITIVES["substring"] = function(s, a, b) { return String(s).substring(a, b); }; PRIMITIVES["string-length"] = function(s) { return String(s).length; }; PRIMITIVES["string-contains?"] = function(s, sub) { return String(s).indexOf(String(sub)) !== -1; }; @@ -382,7 +383,7 @@ PRIMITIVES["len"] = function(c) { return Array.isArray(c) ? c.length : typeof c === "string" ? c.length : Object.keys(c).length; }; PRIMITIVES["first"] = function(c) { return c && c.length > 0 ? c[0] : NIL; }; PRIMITIVES["last"] = function(c) { return c && c.length > 0 ? c[c.length - 1] : NIL; }; - PRIMITIVES["rest"] = function(c) { return c ? c.slice(1) : []; }; + PRIMITIVES["rest"] = function(c) { if (c && typeof c.slice !== "function") { console.error("[sx-debug] rest called on non-sliceable:", typeof c, c, new Error().stack); return []; } return c ? c.slice(1) : []; }; PRIMITIVES["nth"] = function(c, n) { return c && n >= 0 && n < c.length ? c[n] : NIL; }; PRIMITIVES["cons"] = function(x, c) { return [x].concat(c || []); }; PRIMITIVES["append"] = function(c, x) { return (c || []).concat([x]); }; @@ -719,7 +720,7 @@ // eval-expr var evalExpr = function(expr, env) { return (function() { var _m = typeOf(expr); if (_m == "number") return expr; if (_m == "string") return expr; if (_m == "boolean") return expr; if (_m == "nil") return NIL; if (_m == "symbol") return (function() { var name = symbolName(expr); - return (isSxTruthy(envHas(env, name)) ? envGet(env, name) : (isSxTruthy(isPrimitive(name)) ? getPrimitive(name) : (isSxTruthy((name == "true")) ? true : (isSxTruthy((name == "false")) ? false : (isSxTruthy((name == "nil")) ? NIL : error((String("Undefined symbol: ") + String(name)))))))); + return (isSxTruthy(envHas(env, name)) ? envGet(env, name) : (isSxTruthy(isPrimitive(name)) ? getPrimitive(name) : (isSxTruthy((name == "true")) ? true : (isSxTruthy((name == "false")) ? false : (isSxTruthy((name == "nil")) ? NIL : (debugLog("Undefined symbol:", name, "primitive?:", isPrimitive(name)), error((String("Undefined symbol: ") + String(name))))))))); })(); if (_m == "keyword") return keywordName(expr); if (_m == "dict") return mapDict(function(k, v) { return trampoline(evalExpr(v, env)); }, expr); if (_m == "list") return (isSxTruthy(isEmpty(expr)) ? [] : evalList(expr, env)); return expr; })(); }; // eval-list @@ -5226,6 +5227,7 @@ return (isSxTruthy((_batchDepth == 0)) ? (function() { if (typeof jsonParse === "function") PRIMITIVES["json-parse"] = jsonParse; if (typeof nowMs === "function") PRIMITIVES["now-ms"] = nowMs; PRIMITIVES["sx-parse"] = sxParse; + PRIMITIVES["console-log"] = function() { console.log.apply(console, ["[sx]"].concat(Array.prototype.slice.call(arguments))); return arguments.length > 0 ? arguments[0] : NIL; }; // Expose deps module functions as primitives so runtime-evaluated SX code // (e.g. test-deps.sx in browser) can call them diff --git a/shared/sx/pages.py b/shared/sx/pages.py index 2050a5b..6165dc0 100644 --- a/shared/sx/pages.py +++ b/shared/sx/pages.py @@ -76,7 +76,7 @@ def register_page_helpers(service: str, helpers: dict[str, Any]) -> None: Then in .sx:: (defpage docs-page - :path "/docs/" + :path "/language/docs/" :auth :public :content (docs-content slug)) """ diff --git a/shared/sx/ref/eval.sx b/shared/sx/ref/eval.sx index 5d44a33..4945887 100644 --- a/shared/sx/ref/eval.sx +++ b/shared/sx/ref/eval.sx @@ -91,7 +91,8 @@ (= name "true") true (= name "false") false (= name "nil") nil - :else (error (str "Undefined symbol: " name)))) + :else (do (debug-log "Undefined symbol:" name "primitive?:" (primitive? name)) + (error (str "Undefined symbol: " name))))) ;; --- keyword → its string name --- "keyword" (keyword-name expr) diff --git a/shared/sx/ref/page-helpers.sx b/shared/sx/ref/page-helpers.sx index 69e2ba1..c173390 100644 --- a/shared/sx/ref/page-helpers.sx +++ b/shared/sx/ref/page-helpers.sx @@ -92,7 +92,7 @@ (define build-ref-items-with-href (fn (items base-path detail-keys n-fields) ;; items: list of lists (tuples), each with n-fields elements - ;; base-path: e.g. "/hypermedia/reference/attributes/" + ;; base-path: e.g. "/geography/hypermedia/reference/attributes/" ;; detail-keys: list of strings (keys that have detail pages) ;; n-fields: 2 or 3 (number of fields per tuple) (map @@ -128,26 +128,26 @@ "attributes" {"req-attrs" (build-ref-items-with-href (get raw-data "req-attrs") - "/hypermedia/reference/attributes/" detail-keys 3) + "/geography/hypermedia/reference/attributes/" detail-keys 3) "beh-attrs" (build-ref-items-with-href (get raw-data "beh-attrs") - "/hypermedia/reference/attributes/" detail-keys 3) + "/geography/hypermedia/reference/attributes/" detail-keys 3) "uniq-attrs" (build-ref-items-with-href (get raw-data "uniq-attrs") - "/hypermedia/reference/attributes/" detail-keys 3)} + "/geography/hypermedia/reference/attributes/" detail-keys 3)} "headers" {"req-headers" (build-ref-items-with-href (get raw-data "req-headers") - "/hypermedia/reference/headers/" detail-keys 3) + "/geography/hypermedia/reference/headers/" detail-keys 3) "resp-headers" (build-ref-items-with-href (get raw-data "resp-headers") - "/hypermedia/reference/headers/" detail-keys 3)} + "/geography/hypermedia/reference/headers/" detail-keys 3)} "events" {"events-list" (build-ref-items-with-href (get raw-data "events-list") - "/hypermedia/reference/events/" detail-keys 2)} + "/geography/hypermedia/reference/events/" detail-keys 2)} "js-api" {"js-api-list" (map (fn (item) {"name" (nth item 0) "desc" (nth item 1)}) @@ -157,13 +157,13 @@ :else {"req-attrs" (build-ref-items-with-href (get raw-data "req-attrs") - "/hypermedia/reference/attributes/" detail-keys 3) + "/geography/hypermedia/reference/attributes/" detail-keys 3) "beh-attrs" (build-ref-items-with-href (get raw-data "beh-attrs") - "/hypermedia/reference/attributes/" detail-keys 3) + "/geography/hypermedia/reference/attributes/" detail-keys 3) "uniq-attrs" (build-ref-items-with-href (get raw-data "uniq-attrs") - "/hypermedia/reference/attributes/" detail-keys 3)}))) + "/geography/hypermedia/reference/attributes/" detail-keys 3)}))) ;; -------------------------------------------------------------------------- diff --git a/shared/sx/ref/platform_js.py b/shared/sx/ref/platform_js.py index ad5e759..3086710 100644 --- a/shared/sx/ref/platform_js.py +++ b/shared/sx/ref/platform_js.py @@ -959,7 +959,7 @@ PRIMITIVES_JS_MODULES: dict[str, str] = { PRIMITIVES["index-of"] = function(s, needle, from) { return String(s).indexOf(needle, from || 0); }; PRIMITIVES["starts-with?"] = function(s, p) { return String(s).indexOf(p) === 0; }; PRIMITIVES["ends-with?"] = function(s, p) { var str = String(s); return str.indexOf(p, str.length - p.length) !== -1; }; - PRIMITIVES["slice"] = function(c, a, b) { return b !== undefined ? c.slice(a, b) : c.slice(a); }; + PRIMITIVES["slice"] = function(c, a, b) { if (!c || typeof c.slice !== "function") { console.error("[sx-debug] slice called on non-sliceable:", typeof c, c, "a=", a, "b=", b, new Error().stack); return []; } return b !== undefined ? c.slice(a, b) : c.slice(a); }; PRIMITIVES["substring"] = function(s, a, b) { return String(s).substring(a, b); }; PRIMITIVES["string-length"] = function(s) { return String(s).length; }; PRIMITIVES["string-contains?"] = function(s, sub) { return String(s).indexOf(String(sub)) !== -1; }; @@ -987,7 +987,7 @@ PRIMITIVES_JS_MODULES: dict[str, str] = { PRIMITIVES["len"] = function(c) { return Array.isArray(c) ? c.length : typeof c === "string" ? c.length : Object.keys(c).length; }; PRIMITIVES["first"] = function(c) { return c && c.length > 0 ? c[0] : NIL; }; PRIMITIVES["last"] = function(c) { return c && c.length > 0 ? c[c.length - 1] : NIL; }; - PRIMITIVES["rest"] = function(c) { return c ? c.slice(1) : []; }; + PRIMITIVES["rest"] = function(c) { if (c && typeof c.slice !== "function") { console.error("[sx-debug] rest called on non-sliceable:", typeof c, c, new Error().stack); return []; } return c ? c.slice(1) : []; }; PRIMITIVES["nth"] = function(c, n) { return c && n >= 0 && n < c.length ? c[n] : NIL; }; PRIMITIVES["cons"] = function(x, c) { return [x].concat(c || []); }; PRIMITIVES["append"] = function(c, x) { return (c || []).concat([x]); }; @@ -1265,6 +1265,7 @@ PLATFORM_JS_PRE = ''' function error(msg) { throw new Error(msg); } function inspect(x) { return JSON.stringify(x); } + function debugLog() { console.error.apply(console, ["[sx-debug]"].concat(Array.prototype.slice.call(arguments))); } ''' @@ -2898,7 +2899,8 @@ def fixups_js(has_html, has_sx, has_dom, has_signals=False, has_deps=False, has_ if (typeof domTextContent === "function") PRIMITIVES["dom-text-content"] = domTextContent; if (typeof jsonParse === "function") PRIMITIVES["json-parse"] = jsonParse; if (typeof nowMs === "function") PRIMITIVES["now-ms"] = nowMs; - PRIMITIVES["sx-parse"] = sxParse;''') + PRIMITIVES["sx-parse"] = sxParse; + PRIMITIVES["console-log"] = function() { console.log.apply(console, ["[sx]"].concat(Array.prototype.slice.call(arguments))); return arguments.length > 0 ? arguments[0] : NIL; };''') if has_deps: lines.append(''' // Expose deps module functions as primitives so runtime-evaluated SX code diff --git a/shared/sx/ref/sx_ref.py b/shared/sx/ref/sx_ref.py index 8cbff3b..87243af 100644 --- a/shared/sx/ref/sx_ref.py +++ b/shared/sx/ref/sx_ref.py @@ -1192,6 +1192,7 @@ def eval_expr(expr, env): elif sx_truthy((name == 'nil')): return NIL else: + debug_log('Undefined symbol:', name, 'primitive?:', is_primitive(name)) return error(sx_str('Undefined symbol: ', name)) elif _match == 'keyword': return keyword_name(expr) diff --git a/sx/bp/pages/routes.py b/sx/bp/pages/routes.py index cc0b2f9..e295d96 100644 --- a/sx/bp/pages/routes.py +++ b/sx/bp/pages/routes.py @@ -22,7 +22,7 @@ def register(url_prefix: str = "/") -> Blueprint: # Example API endpoints (for live demos) # ------------------------------------------------------------------ - @bp.get("/hypermedia/examples/api/click") + @bp.get("/geography/hypermedia/examples/api/click") async def api_click(): from shared.sx.helpers import sx_response from sxc.pages.renders import _oob_code, _component_source_text, _full_wire_text @@ -35,7 +35,7 @@ def register(url_prefix: str = "/") -> Blueprint: return sx_response(f'(<> {sx_src} {oob_wire} {oob_comp})') @csrf_exempt - @bp.post("/hypermedia/examples/api/form") + @bp.post("/geography/hypermedia/examples/api/form") async def api_form(): from shared.sx.helpers import sx_response from sxc.pages.renders import _oob_code, _component_source_text, _full_wire_text @@ -51,7 +51,7 @@ def register(url_prefix: str = "/") -> Blueprint: _poll_count = {"n": 0} - @bp.get("/hypermedia/examples/api/poll") + @bp.get("/geography/hypermedia/examples/api/poll") async def api_poll(): from shared.sx.helpers import sx_response from sxc.pages.renders import _oob_code, _component_source_text, _full_wire_text @@ -66,7 +66,7 @@ def register(url_prefix: str = "/") -> Blueprint: return sx_response(f'(<> {sx_src} {oob_wire} {oob_comp})') @csrf_exempt - @bp.delete("/hypermedia/examples/api/delete/") + @bp.delete("/geography/hypermedia/examples/api/delete/") async def api_delete(item_id: str): from shared.sx.helpers import sx_response from sxc.pages.renders import _oob_code, _component_source_text, _full_wire_text @@ -78,7 +78,7 @@ def register(url_prefix: str = "/") -> Blueprint: oob_comp = _oob_code("delete-comp", comp_text) return sx_response(f'(<> {oob_wire} {oob_comp})') - @bp.get("/hypermedia/examples/api/edit") + @bp.get("/geography/hypermedia/examples/api/edit") async def api_edit_form(): from shared.sx.helpers import sx_response from sxc.pages.renders import _oob_code, _component_source_text, _full_wire_text @@ -92,7 +92,7 @@ def register(url_prefix: str = "/") -> Blueprint: return sx_response(f'(<> {sx_src} {oob_wire} {oob_comp})') @csrf_exempt - @bp.post("/hypermedia/examples/api/edit") + @bp.post("/geography/hypermedia/examples/api/edit") async def api_edit_save(): from shared.sx.helpers import sx_response from sxc.pages.renders import _oob_code, _component_source_text, _full_wire_text @@ -106,7 +106,7 @@ def register(url_prefix: str = "/") -> Blueprint: oob_comp = _oob_code("edit-comp", comp_text) return sx_response(f'(<> {sx_src} {oob_wire} {oob_comp})') - @bp.get("/hypermedia/examples/api/edit/cancel") + @bp.get("/geography/hypermedia/examples/api/edit/cancel") async def api_edit_cancel(): from shared.sx.helpers import sx_response from sxc.pages.renders import _oob_code, _component_source_text, _full_wire_text @@ -119,7 +119,7 @@ def register(url_prefix: str = "/") -> Blueprint: oob_comp = _oob_code("edit-comp", comp_text) return sx_response(f'(<> {sx_src} {oob_wire} {oob_comp})') - @bp.get("/hypermedia/examples/api/oob") + @bp.get("/geography/hypermedia/examples/api/oob") async def api_oob(): from shared.sx.helpers import sx_response from sxc.pages.renders import _oob_code, _full_wire_text @@ -138,7 +138,7 @@ def register(url_prefix: str = "/") -> Blueprint: # --- Lazy Loading --- - @bp.get("/hypermedia/examples/api/lazy") + @bp.get("/geography/hypermedia/examples/api/lazy") async def api_lazy(): from shared.sx.helpers import sx_response from sxc.pages.renders import _oob_code, _component_source_text, _full_wire_text @@ -152,7 +152,7 @@ def register(url_prefix: str = "/") -> Blueprint: # --- Infinite Scroll --- - @bp.get("/hypermedia/examples/api/scroll") + @bp.get("/geography/hypermedia/examples/api/scroll") async def api_scroll(): from shared.sx.helpers import sx_response from sxc.pages.renders import _oob_code, _full_wire_text @@ -166,7 +166,7 @@ def register(url_prefix: str = "/") -> Blueprint: if next_page <= 6: sentinel = ( f'(div :id "scroll-sentinel"' - f' :sx-get "/hypermedia/examples/api/scroll?page={next_page}"' + f' :sx-get "/geography/hypermedia/examples/api/scroll?page={next_page}"' f' :sx-trigger "intersect once"' f' :sx-target "#scroll-items"' f' :sx-swap "beforeend"' @@ -188,7 +188,7 @@ def register(url_prefix: str = "/") -> Blueprint: _jobs: dict[str, int] = {} @csrf_exempt - @bp.post("/hypermedia/examples/api/progress/start") + @bp.post("/geography/hypermedia/examples/api/progress/start") async def api_progress_start(): from shared.sx.helpers import sx_response from sxc.pages.renders import _oob_code, _component_source_text, _full_wire_text @@ -201,7 +201,7 @@ def register(url_prefix: str = "/") -> Blueprint: oob_comp = _oob_code("progress-comp", comp_text) return sx_response(f'(<> {sx_src} {oob_wire} {oob_comp})') - @bp.get("/hypermedia/examples/api/progress/status") + @bp.get("/geography/hypermedia/examples/api/progress/status") async def api_progress_status(): from shared.sx.helpers import sx_response from sxc.pages.renders import _oob_code, _component_source_text, _full_wire_text @@ -218,7 +218,7 @@ def register(url_prefix: str = "/") -> Blueprint: # --- Active Search --- - @bp.get("/hypermedia/examples/api/search") + @bp.get("/geography/hypermedia/examples/api/search") async def api_search(): from shared.sx.helpers import sx_response from sxc.pages.renders import _oob_code, _component_source_text, _full_wire_text @@ -241,7 +241,7 @@ def register(url_prefix: str = "/") -> Blueprint: _TAKEN_EMAILS = {"admin@example.com", "test@example.com", "user@example.com"} - @bp.get("/hypermedia/examples/api/validate") + @bp.get("/geography/hypermedia/examples/api/validate") async def api_validate(): from shared.sx.helpers import sx_response from sxc.pages.renders import _oob_code, _component_source_text, _full_wire_text @@ -267,7 +267,7 @@ def register(url_prefix: str = "/") -> Blueprint: return sx_response(f'(<> {sx_src} {oob_wire} {oob_comp})') @csrf_exempt - @bp.post("/hypermedia/examples/api/validate/submit") + @bp.post("/geography/hypermedia/examples/api/validate/submit") async def api_validate_submit(): from shared.sx.helpers import sx_response form = await request.form @@ -279,7 +279,7 @@ def register(url_prefix: str = "/") -> Blueprint: # --- Value Select --- - @bp.get("/hypermedia/examples/api/values") + @bp.get("/geography/hypermedia/examples/api/values") async def api_values(): from shared.sx.helpers import sx_response from sxc.pages.renders import _oob_code, _full_wire_text @@ -297,7 +297,7 @@ def register(url_prefix: str = "/") -> Blueprint: # --- Reset on Submit --- @csrf_exempt - @bp.post("/hypermedia/examples/api/reset-submit") + @bp.post("/geography/hypermedia/examples/api/reset-submit") async def api_reset_submit(): from shared.sx.helpers import sx_response from sxc.pages.renders import _oob_code, _component_source_text, _full_wire_text @@ -323,7 +323,7 @@ def register(url_prefix: str = "/") -> Blueprint: _edit_rows[r["id"]] = dict(r) return _edit_rows - @bp.get("/hypermedia/examples/api/editrow/") + @bp.get("/geography/hypermedia/examples/api/editrow/") async def api_editrow_form(row_id: str): from shared.sx.helpers import sx_response from sxc.pages.renders import _oob_code, _component_source_text, _full_wire_text @@ -338,7 +338,7 @@ def register(url_prefix: str = "/") -> Blueprint: return sx_response(f'(<> {sx_src} {oob_wire} {oob_comp})') @csrf_exempt - @bp.post("/hypermedia/examples/api/editrow/") + @bp.post("/geography/hypermedia/examples/api/editrow/") async def api_editrow_save(row_id: str): from shared.sx.helpers import sx_response from sxc.pages.renders import _oob_code, _component_source_text, _full_wire_text @@ -359,7 +359,7 @@ def register(url_prefix: str = "/") -> Blueprint: oob_comp = _oob_code("editrow-comp", comp_text) return sx_response(f'(<> {sx_src} {oob_wire} {oob_comp})') - @bp.get("/hypermedia/examples/api/editrow//cancel") + @bp.get("/geography/hypermedia/examples/api/editrow//cancel") async def api_editrow_cancel(row_id: str): from shared.sx.helpers import sx_response from sxc.pages.renders import _oob_code, _component_source_text, _full_wire_text @@ -385,7 +385,7 @@ def register(url_prefix: str = "/") -> Blueprint: return _bulk_users @csrf_exempt - @bp.post("/hypermedia/examples/api/bulk") + @bp.post("/geography/hypermedia/examples/api/bulk") async def api_bulk(): from shared.sx.helpers import sx_response from sxc.pages.renders import _oob_code, _component_source_text, _full_wire_text @@ -415,7 +415,7 @@ def register(url_prefix: str = "/") -> Blueprint: _swap_count = {"n": 0} @csrf_exempt - @bp.post("/hypermedia/examples/api/swap-log") + @bp.post("/geography/hypermedia/examples/api/swap-log") async def api_swap_log(): from shared.sx.helpers import sx_response from sxc.pages.renders import _oob_code, _full_wire_text @@ -435,7 +435,7 @@ def register(url_prefix: str = "/") -> Blueprint: # --- Select Filter (dashboard) --- - @bp.get("/hypermedia/examples/api/dashboard") + @bp.get("/geography/hypermedia/examples/api/dashboard") async def api_dashboard(): from shared.sx.helpers import sx_response from sxc.pages.renders import _oob_code, _full_wire_text @@ -480,7 +480,7 @@ def register(url_prefix: str = "/") -> Blueprint: ' (li "Wire format v2")))'), } - @bp.get("/hypermedia/examples/api/tabs/") + @bp.get("/geography/hypermedia/examples/api/tabs/") async def api_tabs(tab: str): from shared.sx.helpers import sx_response from sxc.pages.renders import _oob_code, _full_wire_text @@ -500,7 +500,7 @@ def register(url_prefix: str = "/") -> Blueprint: # --- Animations --- - @bp.get("/hypermedia/examples/api/animate") + @bp.get("/geography/hypermedia/examples/api/animate") async def api_animate(): from shared.sx.helpers import sx_response from sxc.pages.renders import _oob_code, _component_source_text, _full_wire_text @@ -516,7 +516,7 @@ def register(url_prefix: str = "/") -> Blueprint: # --- Dialogs --- - @bp.get("/hypermedia/examples/api/dialog") + @bp.get("/geography/hypermedia/examples/api/dialog") async def api_dialog(): from shared.sx.helpers import sx_response from sxc.pages.renders import _oob_code, _component_source_text, _full_wire_text @@ -527,7 +527,7 @@ def register(url_prefix: str = "/") -> Blueprint: oob_comp = _oob_code("dialog-comp", comp_text) return sx_response(f'(<> {sx_src} {oob_wire} {oob_comp})') - @bp.get("/hypermedia/examples/api/dialog/close") + @bp.get("/geography/hypermedia/examples/api/dialog/close") async def api_dialog_close(): from shared.sx.helpers import sx_response from sxc.pages.renders import _oob_code, _full_wire_text @@ -543,7 +543,7 @@ def register(url_prefix: str = "/") -> Blueprint: "h": "Help panel opened", } - @bp.get("/hypermedia/examples/api/keyboard") + @bp.get("/geography/hypermedia/examples/api/keyboard") async def api_keyboard(): from shared.sx.helpers import sx_response from sxc.pages.renders import _oob_code, _component_source_text, _full_wire_text @@ -568,7 +568,7 @@ def register(url_prefix: str = "/") -> Blueprint: _profile.update(PROFILE_DEFAULT) return _profile - @bp.get("/hypermedia/examples/api/putpatch/edit-all") + @bp.get("/geography/hypermedia/examples/api/putpatch/edit-all") async def api_pp_edit_all(): from shared.sx.helpers import sx_response from sxc.pages.renders import _oob_code, _component_source_text, _full_wire_text @@ -581,7 +581,7 @@ def register(url_prefix: str = "/") -> Blueprint: return sx_response(f'(<> {sx_src} {oob_wire} {oob_comp})') @csrf_exempt - @bp.put("/hypermedia/examples/api/putpatch") + @bp.put("/geography/hypermedia/examples/api/putpatch") async def api_pp_put(): from shared.sx.helpers import sx_response from sxc.pages.renders import _oob_code, _component_source_text, _full_wire_text @@ -597,7 +597,7 @@ def register(url_prefix: str = "/") -> Blueprint: oob_comp = _oob_code("pp-comp", comp_text) return sx_response(f'(<> {sx_src} {oob_wire} {oob_comp})') - @bp.get("/hypermedia/examples/api/putpatch/cancel") + @bp.get("/geography/hypermedia/examples/api/putpatch/cancel") async def api_pp_cancel(): from shared.sx.helpers import sx_response from sxc.pages.renders import _oob_code, _component_source_text, _full_wire_text @@ -612,7 +612,7 @@ def register(url_prefix: str = "/") -> Blueprint: # --- JSON Encoding --- @csrf_exempt - @bp.post("/hypermedia/examples/api/json-echo") + @bp.post("/geography/hypermedia/examples/api/json-echo") async def api_json_echo(): from shared.sx.helpers import sx_response from sxc.pages.renders import _oob_code, _component_source_text, _full_wire_text @@ -630,7 +630,7 @@ def register(url_prefix: str = "/") -> Blueprint: # --- Vals & Headers --- - @bp.get("/hypermedia/examples/api/echo-vals") + @bp.get("/geography/hypermedia/examples/api/echo-vals") async def api_echo_vals(): from shared.sx.helpers import sx_response from sxc.pages.renders import _oob_code, _component_source_text, _full_wire_text @@ -644,7 +644,7 @@ def register(url_prefix: str = "/") -> Blueprint: oob_comp = _oob_code("vals-comp", comp_text) return sx_response(f'(<> {sx_src} {oob_wire} {oob_comp})') - @bp.get("/hypermedia/examples/api/echo-headers") + @bp.get("/geography/hypermedia/examples/api/echo-headers") async def api_echo_headers(): from shared.sx.helpers import sx_response from sxc.pages.renders import _oob_code, _component_source_text, _full_wire_text @@ -659,7 +659,7 @@ def register(url_prefix: str = "/") -> Blueprint: # --- Loading States --- - @bp.get("/hypermedia/examples/api/slow") + @bp.get("/geography/hypermedia/examples/api/slow") async def api_slow(): from shared.sx.helpers import sx_response from sxc.pages.renders import _oob_code, _component_source_text, _full_wire_text @@ -674,7 +674,7 @@ def register(url_prefix: str = "/") -> Blueprint: # --- Request Abort (sync replace) --- - @bp.get("/hypermedia/examples/api/slow-search") + @bp.get("/geography/hypermedia/examples/api/slow-search") async def api_slow_search(): from shared.sx.helpers import sx_response from sxc.pages.renders import _oob_code, _component_source_text, _full_wire_text @@ -694,7 +694,7 @@ def register(url_prefix: str = "/") -> Blueprint: _flaky = {"n": 0} - @bp.get("/hypermedia/examples/api/flaky") + @bp.get("/geography/hypermedia/examples/api/flaky") async def api_flaky(): from shared.sx.helpers import sx_response from sxc.pages.renders import _oob_code, _component_source_text, _full_wire_text @@ -718,7 +718,7 @@ def register(url_prefix: str = "/") -> Blueprint: from sxc.pages.renders import _oob_code return _oob_code(f"ref-wire-{wire_id}", sx_src) - @bp.get("/hypermedia/reference/api/time") + @bp.get("/geography/hypermedia/reference/api/time") async def ref_time(): from shared.sx.helpers import sx_response now = datetime.now().strftime("%H:%M:%S") @@ -727,7 +727,7 @@ def register(url_prefix: str = "/") -> Blueprint: return sx_response(f'(<> {sx_src} {oob})') @csrf_exempt - @bp.post("/hypermedia/reference/api/greet") + @bp.post("/geography/hypermedia/reference/api/greet") async def ref_greet(): from shared.sx.helpers import sx_response form = await request.form @@ -737,7 +737,7 @@ def register(url_prefix: str = "/") -> Blueprint: return sx_response(f'(<> {sx_src} {oob})') @csrf_exempt - @bp.put("/hypermedia/reference/api/status") + @bp.put("/geography/hypermedia/reference/api/status") async def ref_status(): from shared.sx.helpers import sx_response form = await request.form @@ -747,7 +747,7 @@ def register(url_prefix: str = "/") -> Blueprint: return sx_response(f'(<> {sx_src} {oob})') @csrf_exempt - @bp.patch("/hypermedia/reference/api/theme") + @bp.patch("/geography/hypermedia/reference/api/theme") async def ref_theme(): from shared.sx.helpers import sx_response form = await request.form @@ -757,13 +757,13 @@ def register(url_prefix: str = "/") -> Blueprint: return sx_response(f'(<> {sx_src} {oob})') @csrf_exempt - @bp.delete("/hypermedia/reference/api/item/") + @bp.delete("/geography/hypermedia/reference/api/item/") 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("/hypermedia/reference/api/trigger-search") + @bp.get("/geography/hypermedia/reference/api/trigger-search") async def ref_trigger_search(): from shared.sx.helpers import sx_response q = request.args.get("q", "") @@ -774,7 +774,7 @@ def register(url_prefix: str = "/") -> Blueprint: oob = _ref_wire("sx-trigger", sx_src) return sx_response(f'(<> {sx_src} {oob})') - @bp.get("/hypermedia/reference/api/swap-item") + @bp.get("/geography/hypermedia/reference/api/swap-item") async def ref_swap_item(): from shared.sx.helpers import sx_response now = datetime.now().strftime("%H:%M:%S") @@ -782,7 +782,7 @@ def register(url_prefix: str = "/") -> Blueprint: oob = _ref_wire("sx-swap", sx_src) return sx_response(f'(<> {sx_src} {oob})') - @bp.get("/hypermedia/reference/api/oob") + @bp.get("/geography/hypermedia/reference/api/oob") async def ref_oob(): from shared.sx.helpers import sx_response now = datetime.now().strftime("%H:%M:%S") @@ -794,7 +794,7 @@ def register(url_prefix: str = "/") -> Blueprint: oob = _ref_wire("sx-swap-oob", sx_src) return sx_response(f'(<> {sx_src} {oob})') - @bp.get("/hypermedia/reference/api/select-page") + @bp.get("/geography/hypermedia/reference/api/select-page") async def ref_select_page(): from shared.sx.helpers import sx_response now = datetime.now().strftime("%H:%M:%S") @@ -808,7 +808,7 @@ def register(url_prefix: str = "/") -> Blueprint: oob = _ref_wire("sx-select", sx_src) return sx_response(f'(<> {sx_src} {oob})') - @bp.get("/hypermedia/reference/api/slow-echo") + @bp.get("/geography/hypermedia/reference/api/slow-echo") async def ref_slow_echo(): from shared.sx.helpers import sx_response await asyncio.sleep(0.8) @@ -818,7 +818,7 @@ def register(url_prefix: str = "/") -> Blueprint: return sx_response(f'(<> {sx_src} {oob})') @csrf_exempt - @bp.post("/hypermedia/reference/api/upload-name") + @bp.post("/geography/hypermedia/reference/api/upload-name") async def ref_upload_name(): from shared.sx.helpers import sx_response files = await request.files @@ -828,7 +828,7 @@ def register(url_prefix: str = "/") -> Blueprint: oob = _ref_wire("sx-encoding", sx_src) return sx_response(f'(<> {sx_src} {oob})') - @bp.get("/hypermedia/reference/api/echo-headers") + @bp.get("/geography/hypermedia/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-")] @@ -841,7 +841,7 @@ def register(url_prefix: str = "/") -> Blueprint: oob = _ref_wire("sx-headers", sx_src) return sx_response(f'(<> {sx_src} {oob})') - @bp.get("/hypermedia/reference/api/echo-vals") + @bp.get("/geography/hypermedia/reference/api/echo-vals") async def ref_echo_vals_get(): from shared.sx.helpers import sx_response vals = list(request.args.items()) @@ -855,7 +855,7 @@ def register(url_prefix: str = "/") -> Blueprint: return sx_response(f'(<> {sx_src} {oob_include})') @csrf_exempt - @bp.post("/hypermedia/reference/api/echo-vals") + @bp.post("/geography/hypermedia/reference/api/echo-vals") async def ref_echo_vals_post(): from shared.sx.helpers import sx_response form = await request.form @@ -871,7 +871,7 @@ def register(url_prefix: str = "/") -> Blueprint: _ref_flaky = {"n": 0} - @bp.get("/hypermedia/reference/api/flaky") + @bp.get("/geography/hypermedia/reference/api/flaky") async def ref_flaky(): from shared.sx.helpers import sx_response _ref_flaky["n"] += 1 @@ -882,7 +882,7 @@ def register(url_prefix: str = "/") -> Blueprint: oob = _ref_wire("sx-retry", sx_src) return sx_response(f'(<> {sx_src} {oob})') - @bp.get("/hypermedia/reference/api/prompt-echo") + @bp.get("/geography/hypermedia/reference/api/prompt-echo") async def ref_prompt_echo(): from shared.sx.helpers import sx_response name = request.headers.get("SX-Prompt", "anonymous") @@ -890,7 +890,7 @@ def register(url_prefix: str = "/") -> Blueprint: oob = _ref_wire("sx-prompt", sx_src) return sx_response(f'(<> {sx_src} {oob})') - @bp.get("/hypermedia/reference/api/sse-time") + @bp.get("/geography/hypermedia/reference/api/sse-time") async def ref_sse_time(): async def generate(): for _ in range(30): # stream for 60 seconds max @@ -905,7 +905,7 @@ def register(url_prefix: str = "/") -> Blueprint: _marsh_sale_idx = {"n": 0} - @bp.get("/reactive/api/flash-sale") + @bp.get("/geography/reactive/api/flash-sale") async def api_marsh_flash_sale(): from shared.sx.helpers import sx_response prices = [14.99, 9.99, 24.99, 12.49, 7.99, 29.99, 4.99, 16.50] @@ -927,7 +927,7 @@ def register(url_prefix: str = "/") -> Blueprint: _settle_counter = {"n": 0} - @bp.get("/reactive/api/settle-data") + @bp.get("/geography/reactive/api/settle-data") async def api_settle_data(): from shared.sx.helpers import sx_response _settle_counter["n"] += 1 @@ -943,7 +943,7 @@ def register(url_prefix: str = "/") -> Blueprint: # --- Demo 4: signal-bound URL endpoints --- - @bp.get("/reactive/api/search/products") + @bp.get("/geography/reactive/api/search/products") async def api_search_products(): from shared.sx.helpers import sx_response q = request.args.get("q", "") @@ -962,7 +962,7 @@ def register(url_prefix: str = "/") -> Blueprint: ) return sx_response(sx_src) - @bp.get("/reactive/api/search/events") + @bp.get("/geography/reactive/api/search/events") async def api_search_events(): from shared.sx.helpers import sx_response q = request.args.get("q", "") @@ -981,7 +981,7 @@ def register(url_prefix: str = "/") -> Blueprint: ) return sx_response(sx_src) - @bp.get("/reactive/api/search/posts") + @bp.get("/geography/reactive/api/search/posts") async def api_search_posts(): from shared.sx.helpers import sx_response q = request.args.get("q", "") @@ -1002,7 +1002,7 @@ def register(url_prefix: str = "/") -> Blueprint: # --- Demo 5: marsh transform endpoint --- - @bp.get("/reactive/api/catalog") + @bp.get("/geography/reactive/api/catalog") async def api_catalog(): from shared.sx.helpers import sx_response items = [ @@ -1031,7 +1031,7 @@ def register(url_prefix: str = "/") -> Blueprint: # --- Header demos --- - @bp.get("/hypermedia/reference/api/trigger-event") + @bp.get("/geography/hypermedia/reference/api/trigger-event") async def ref_trigger_event(): from shared.sx.helpers import sx_response now = datetime.now().strftime("%H:%M:%S") @@ -1040,7 +1040,7 @@ def register(url_prefix: str = "/") -> Blueprint: resp.headers["SX-Trigger"] = "showNotice" return resp - @bp.get("/hypermedia/reference/api/retarget") + @bp.get("/geography/hypermedia/reference/api/retarget") async def ref_retarget(): from shared.sx.helpers import sx_response now = datetime.now().strftime("%H:%M:%S") @@ -1051,7 +1051,7 @@ def register(url_prefix: str = "/") -> Blueprint: # --- Event demos --- - @bp.get("/hypermedia/reference/api/error-500") + @bp.get("/geography/hypermedia/reference/api/error-500") async def ref_error_500(): return Response("Server error", status=500, content_type="text/plain") diff --git a/sx/content/pages.py b/sx/content/pages.py index 0230b5a..ac86218 100644 --- a/sx/content/pages.py +++ b/sx/content/pages.py @@ -10,79 +10,79 @@ from __future__ import annotations # --------------------------------------------------------------------------- DOCS_NAV = [ - ("Introduction", "/docs/introduction"), - ("Getting Started", "/docs/getting-started"), - ("Components", "/docs/components"), - ("Evaluator", "/docs/evaluator"), - ("Primitives", "/docs/primitives"), - ("CSS", "/docs/css"), - ("Server Rendering", "/docs/server-rendering"), + ("Introduction", "/language/docs/introduction"), + ("Getting Started", "/language/docs/getting-started"), + ("Components", "/language/docs/components"), + ("Evaluator", "/language/docs/evaluator"), + ("Primitives", "/language/docs/primitives"), + ("CSS", "/language/docs/css"), + ("Server Rendering", "/language/docs/server-rendering"), ] REFERENCE_NAV = [ - ("Attributes", "/hypermedia/reference/attributes"), - ("Headers", "/hypermedia/reference/headers"), - ("Events", "/hypermedia/reference/events"), - ("JS API", "/hypermedia/reference/js-api"), + ("Attributes", "/geography/hypermedia/reference/attributes"), + ("Headers", "/geography/hypermedia/reference/headers"), + ("Events", "/geography/hypermedia/reference/events"), + ("JS API", "/geography/hypermedia/reference/js-api"), ] PROTOCOLS_NAV = [ - ("Wire Format", "/protocols/wire-format"), - ("Fragments", "/protocols/fragments"), - ("Resolver I/O", "/protocols/resolver-io"), - ("Internal Services", "/protocols/internal-services"), - ("ActivityPub", "/protocols/activitypub"), - ("Future", "/protocols/future"), + ("Wire Format", "/applications/protocols/wire-format"), + ("Fragments", "/applications/protocols/fragments"), + ("Resolver I/O", "/applications/protocols/resolver-io"), + ("Internal Services", "/applications/protocols/internal-services"), + ("ActivityPub", "/applications/protocols/activitypub"), + ("Future", "/applications/protocols/future"), ] EXAMPLES_NAV = [ - ("Click to Load", "/hypermedia/examples/click-to-load"), - ("Form Submission", "/hypermedia/examples/form-submission"), - ("Polling", "/hypermedia/examples/polling"), - ("Delete Row", "/hypermedia/examples/delete-row"), - ("Inline Edit", "/hypermedia/examples/inline-edit"), - ("OOB Swaps", "/hypermedia/examples/oob-swaps"), - ("Lazy Loading", "/hypermedia/examples/lazy-loading"), - ("Infinite Scroll", "/hypermedia/examples/infinite-scroll"), - ("Progress Bar", "/hypermedia/examples/progress-bar"), - ("Active Search", "/hypermedia/examples/active-search"), - ("Inline Validation", "/hypermedia/examples/inline-validation"), - ("Value Select", "/hypermedia/examples/value-select"), - ("Reset on Submit", "/hypermedia/examples/reset-on-submit"), - ("Edit Row", "/hypermedia/examples/edit-row"), - ("Bulk Update", "/hypermedia/examples/bulk-update"), - ("Swap Positions", "/hypermedia/examples/swap-positions"), - ("Select Filter", "/hypermedia/examples/select-filter"), - ("Tabs", "/hypermedia/examples/tabs"), - ("Animations", "/hypermedia/examples/animations"), - ("Dialogs", "/hypermedia/examples/dialogs"), - ("Keyboard Shortcuts", "/hypermedia/examples/keyboard-shortcuts"), - ("PUT / PATCH", "/hypermedia/examples/put-patch"), - ("JSON Encoding", "/hypermedia/examples/json-encoding"), - ("Vals & Headers", "/hypermedia/examples/vals-and-headers"), - ("Loading States", "/hypermedia/examples/loading-states"), - ("Request Abort", "/hypermedia/examples/sync-replace"), - ("Retry", "/hypermedia/examples/retry"), + ("Click to Load", "/geography/hypermedia/examples/click-to-load"), + ("Form Submission", "/geography/hypermedia/examples/form-submission"), + ("Polling", "/geography/hypermedia/examples/polling"), + ("Delete Row", "/geography/hypermedia/examples/delete-row"), + ("Inline Edit", "/geography/hypermedia/examples/inline-edit"), + ("OOB Swaps", "/geography/hypermedia/examples/oob-swaps"), + ("Lazy Loading", "/geography/hypermedia/examples/lazy-loading"), + ("Infinite Scroll", "/geography/hypermedia/examples/infinite-scroll"), + ("Progress Bar", "/geography/hypermedia/examples/progress-bar"), + ("Active Search", "/geography/hypermedia/examples/active-search"), + ("Inline Validation", "/geography/hypermedia/examples/inline-validation"), + ("Value Select", "/geography/hypermedia/examples/value-select"), + ("Reset on Submit", "/geography/hypermedia/examples/reset-on-submit"), + ("Edit Row", "/geography/hypermedia/examples/edit-row"), + ("Bulk Update", "/geography/hypermedia/examples/bulk-update"), + ("Swap Positions", "/geography/hypermedia/examples/swap-positions"), + ("Select Filter", "/geography/hypermedia/examples/select-filter"), + ("Tabs", "/geography/hypermedia/examples/tabs"), + ("Animations", "/geography/hypermedia/examples/animations"), + ("Dialogs", "/geography/hypermedia/examples/dialogs"), + ("Keyboard Shortcuts", "/geography/hypermedia/examples/keyboard-shortcuts"), + ("PUT / PATCH", "/geography/hypermedia/examples/put-patch"), + ("JSON Encoding", "/geography/hypermedia/examples/json-encoding"), + ("Vals & Headers", "/geography/hypermedia/examples/vals-and-headers"), + ("Loading States", "/geography/hypermedia/examples/loading-states"), + ("Request Abort", "/geography/hypermedia/examples/sync-replace"), + ("Retry", "/geography/hypermedia/examples/retry"), ] ESSAYS_NAV = [ - ("sx sucks", "/essays/sx-sucks"), - ("Why S-Expressions", "/essays/why-sexps"), - ("The htmx/React Hybrid", "/essays/htmx-react-hybrid"), - ("On-Demand CSS", "/essays/on-demand-css"), - ("Client Reactivity", "/essays/client-reactivity"), - ("SX Native", "/essays/sx-native"), - ("The SX Manifesto", "/philosophy/sx-manifesto"), - ("Tail-Call Optimization", "/essays/tail-call-optimization"), - ("Continuations", "/essays/continuations"), + ("sx sucks", "/etc/essays/sx-sucks"), + ("Why S-Expressions", "/etc/essays/why-sexps"), + ("The htmx/React Hybrid", "/etc/essays/htmx-react-hybrid"), + ("On-Demand CSS", "/etc/essays/on-demand-css"), + ("Client Reactivity", "/etc/essays/client-reactivity"), + ("SX Native", "/etc/essays/sx-native"), + ("The SX Manifesto", "/etc/philosophy/sx-manifesto"), + ("Tail-Call Optimization", "/etc/essays/tail-call-optimization"), + ("Continuations", "/etc/essays/continuations"), ] MAIN_NAV = [ - ("Docs", "/docs/introduction"), - ("Reference", "/hypermedia/reference/"), - ("Protocols", "/protocols/wire-format"), - ("Examples", "/hypermedia/examples/click-to-load"), - ("Essays", "/essays/sx-sucks"), + ("Docs", "/language/docs/introduction"), + ("Reference", "/geography/hypermedia/reference/"), + ("Protocols", "/applications/protocols/wire-format"), + ("Examples", "/geography/hypermedia/examples/click-to-load"), + ("Essays", "/etc/essays/sx-sucks"), ] # --------------------------------------------------------------------------- @@ -539,7 +539,7 @@ HEADER_DETAILS: dict[str, dict] = { ';; SX-Location: /docs/introduction\n' ';;\n' ';; With options:\n' - ';; SX-Location: {"path": "/docs/intro", "target": "#sidebar", "swap": "innerHTML"}' + ';; SX-Location: {"path": "/language/docs/intro", "target": "#sidebar", "swap": "innerHTML"}' ), }, "SX-Replace-Url": { @@ -676,8 +676,8 @@ EVENT_DETAILS: dict[str, dict] = { ';; sx-boost containers try client routing first.\n' ';; On success, sx:clientRoute fires on the swap target.\n' '(nav :sx-boost "#main-panel"\n' - ' (a :href "/essays/" "Essays")\n' - ' (a :href "/plans/" "Plans"))\n' + ' (a :href "/etc/essays/" "Essays")\n' + ' (a :href "/etc/plans/" "Plans"))\n' '\n' ';; Listen in body.js:\n' ';; document.body.addEventListener("sx:clientRoute",\n' @@ -744,7 +744,7 @@ ATTR_DETAILS: dict[str, dict] = { ), "demo": "ref-get-demo", "example": ( - '(button :sx-get "/hypermedia/reference/api/time"\n' + '(button :sx-get "/geography/hypermedia/reference/api/time"\n' ' :sx-target "#ref-get-result"\n' ' :sx-swap "innerHTML"\n' ' "Load server time")' @@ -764,7 +764,7 @@ ATTR_DETAILS: dict[str, dict] = { ), "demo": "ref-post-demo", "example": ( - '(form :sx-post "/hypermedia/reference/api/greet"\n' + '(form :sx-post "/geography/hypermedia/reference/api/greet"\n' ' :sx-target "#ref-post-result"\n' ' :sx-swap "innerHTML"\n' ' (input :type "text" :name "name"\n' @@ -786,7 +786,7 @@ ATTR_DETAILS: dict[str, dict] = { ), "demo": "ref-put-demo", "example": ( - '(button :sx-put "/hypermedia/reference/api/status"\n' + '(button :sx-put "/geography/hypermedia/reference/api/status"\n' ' :sx-target "#ref-put-view"\n' ' :sx-swap "innerHTML"\n' ' :sx-vals "{\\"status\\": \\"published\\"}"\n' @@ -807,7 +807,7 @@ ATTR_DETAILS: dict[str, dict] = { ), "demo": "ref-delete-demo", "example": ( - '(button :sx-delete "/hypermedia/reference/api/item/1"\n' + '(button :sx-delete "/geography/hypermedia/reference/api/item/1"\n' ' :sx-target "#ref-del-1"\n' ' :sx-swap "delete"\n' ' "Remove")' @@ -826,7 +826,7 @@ ATTR_DETAILS: dict[str, dict] = { ), "demo": "ref-patch-demo", "example": ( - '(button :sx-patch "/hypermedia/reference/api/theme"\n' + '(button :sx-patch "/geography/hypermedia/reference/api/theme"\n' ' :sx-vals "{\\"theme\\": \\"dark\\"}"\n' ' :sx-target "#ref-patch-val"\n' ' :sx-swap "innerHTML"\n' @@ -852,7 +852,7 @@ ATTR_DETAILS: dict[str, dict] = { "example": ( '(input :type "text" :name "q"\n' ' :placeholder "Type to search..."\n' - ' :sx-get "/hypermedia/reference/api/trigger-search"\n' + ' :sx-get "/geography/hypermedia/reference/api/trigger-search"\n' ' :sx-trigger "input changed delay:300ms"\n' ' :sx-target "#ref-trigger-result"\n' ' :sx-swap "innerHTML")' @@ -874,12 +874,12 @@ ATTR_DETAILS: dict[str, dict] = { "demo": "ref-target-demo", "example": ( ';; Two buttons targeting different elements\n' - '(button :sx-get "/hypermedia/reference/api/time"\n' + '(button :sx-get "/geography/hypermedia/reference/api/time"\n' ' :sx-target "#ref-target-a"\n' ' :sx-swap "innerHTML"\n' ' "Update Box A")\n' '\n' - '(button :sx-get "/hypermedia/reference/api/time"\n' + '(button :sx-get "/geography/hypermedia/reference/api/time"\n' ' :sx-target "#ref-target-b"\n' ' :sx-swap "innerHTML"\n' ' "Update Box B")' @@ -894,13 +894,13 @@ ATTR_DETAILS: dict[str, dict] = { "demo": "ref-swap-demo", "example": ( ';; Append to the end of a list\n' - '(button :sx-get "/hypermedia/reference/api/swap-item"\n' + '(button :sx-get "/geography/hypermedia/reference/api/swap-item"\n' ' :sx-target "#ref-swap-list"\n' ' :sx-swap "beforeend"\n' ' "beforeend")\n' '\n' ';; Prepend to the start\n' - '(button :sx-get "/hypermedia/reference/api/swap-item"\n' + '(button :sx-get "/geography/hypermedia/reference/api/swap-item"\n' ' :sx-target "#ref-swap-list"\n' ' :sx-swap "afterbegin"\n' ' "afterbegin")' @@ -921,7 +921,7 @@ ATTR_DETAILS: dict[str, dict] = { ), "demo": "ref-oob-demo", "example": ( - '(button :sx-get "/hypermedia/reference/api/oob"\n' + '(button :sx-get "/geography/hypermedia/reference/api/oob"\n' ' :sx-target "#ref-oob-main"\n' ' :sx-swap "innerHTML"\n' ' "Update both boxes")' @@ -944,7 +944,7 @@ ATTR_DETAILS: dict[str, dict] = { ), "demo": "ref-select-demo", "example": ( - '(button :sx-get "/hypermedia/reference/api/select-page"\n' + '(button :sx-get "/geography/hypermedia/reference/api/select-page"\n' ' :sx-target "#ref-select-result"\n' ' :sx-select "#the-content"\n' ' :sx-swap "innerHTML"\n' @@ -968,7 +968,7 @@ ATTR_DETAILS: dict[str, dict] = { ), "demo": "ref-confirm-demo", "example": ( - '(button :sx-delete "/hypermedia/reference/api/item/confirm"\n' + '(button :sx-delete "/geography/hypermedia/reference/api/item/confirm"\n' ' :sx-target "#ref-confirm-item"\n' ' :sx-swap "delete"\n' ' :sx-confirm "Are you sure you want to delete this file?"\n' @@ -983,8 +983,8 @@ ATTR_DETAILS: dict[str, dict] = { ), "demo": "ref-pushurl-demo", "example": ( - '(a :href "/hypermedia/reference/attributes/sx-get"\n' - ' :sx-get "/hypermedia/reference/attributes/sx-get"\n' + '(a :href "/geography/hypermedia/reference/attributes/sx-get"\n' + ' :sx-get "/geography/hypermedia/reference/attributes/sx-get"\n' ' :sx-target "#main-panel"\n' ' :sx-select "#main-panel"\n' ' :sx-swap "outerHTML"\n' @@ -1003,7 +1003,7 @@ ATTR_DETAILS: dict[str, dict] = { "example": ( '(input :type "text" :name "q"\n' ' :placeholder "Type quickly..."\n' - ' :sx-get "/hypermedia/reference/api/slow-echo"\n' + ' :sx-get "/geography/hypermedia/reference/api/slow-echo"\n' ' :sx-trigger "input changed delay:100ms"\n' ' :sx-sync "replace"\n' ' :sx-target "#ref-sync-result"\n' @@ -1024,7 +1024,7 @@ ATTR_DETAILS: dict[str, dict] = { ), "demo": "ref-encoding-demo", "example": ( - '(form :sx-post "/hypermedia/reference/api/upload-name"\n' + '(form :sx-post "/geography/hypermedia/reference/api/upload-name"\n' ' :sx-encoding "multipart/form-data"\n' ' :sx-target "#ref-encoding-result"\n' ' :sx-swap "innerHTML"\n' @@ -1044,7 +1044,7 @@ ATTR_DETAILS: dict[str, dict] = { ), "demo": "ref-headers-demo", "example": ( - '(button :sx-get "/hypermedia/reference/api/echo-headers"\n' + '(button :sx-get "/geography/hypermedia/reference/api/echo-headers"\n' ' :sx-headers \'{"X-Custom-Token": "abc123", "X-Request-Source": "demo"}\'\n' ' :sx-target "#ref-headers-result"\n' ' :sx-swap "innerHTML"\n' @@ -1073,7 +1073,7 @@ ATTR_DETAILS: dict[str, dict] = { ' (option :value "books" "Books")\n' ' (option :value "tools" "Tools"))\n' '\n' - '(button :sx-get "/hypermedia/reference/api/echo-vals"\n' + '(button :sx-get "/geography/hypermedia/reference/api/echo-vals"\n' ' :sx-include "#ref-inc-cat"\n' ' :sx-target "#ref-include-result"\n' ' :sx-swap "innerHTML"\n' @@ -1097,7 +1097,7 @@ ATTR_DETAILS: dict[str, dict] = { ), "demo": "ref-vals-demo", "example": ( - '(button :sx-post "/hypermedia/reference/api/echo-vals"\n' + '(button :sx-post "/geography/hypermedia/reference/api/echo-vals"\n' ' :sx-vals \'{"source": "demo", "page": "3"}\'\n' ' :sx-target "#ref-vals-result"\n' ' :sx-swap "innerHTML"\n' @@ -1112,8 +1112,8 @@ ATTR_DETAILS: dict[str, dict] = { ), "demo": "ref-media-demo", "example": ( - '(a :href "/hypermedia/reference/attributes/sx-get"\n' - ' :sx-get "/hypermedia/reference/attributes/sx-get"\n' + '(a :href "/geography/hypermedia/reference/attributes/sx-get"\n' + ' :sx-get "/geography/hypermedia/reference/attributes/sx-get"\n' ' :sx-target "#main-panel"\n' ' :sx-select "#main-panel"\n' ' :sx-swap "outerHTML"\n' @@ -1133,7 +1133,7 @@ ATTR_DETAILS: dict[str, dict] = { ';; Left box: sx works normally\n' ';; Right box: sx-disable prevents any sx behavior\n' '(div :sx-disable "true"\n' - ' (button :sx-get "/hypermedia/reference/api/time"\n' + ' (button :sx-get "/geography/hypermedia/reference/api/time"\n' ' :sx-target "#ref-dis-b"\n' ' :sx-swap "innerHTML"\n' ' "Load")\n' @@ -1166,7 +1166,7 @@ ATTR_DETAILS: dict[str, dict] = { ), "demo": "ref-retry-demo", "example": ( - '(button :sx-get "/hypermedia/reference/api/flaky"\n' + '(button :sx-get "/geography/hypermedia/reference/api/flaky"\n' ' :sx-target "#ref-retry-result"\n' ' :sx-swap "innerHTML"\n' ' :sx-retry "true"\n' @@ -1221,9 +1221,9 @@ ATTR_DETAILS: dict[str, dict] = { "example": ( ';; Boost with configurable target\n' '(nav :sx-boost "#main-panel"\n' - ' (a :href "/docs/introduction" "Introduction")\n' - ' (a :href "/docs/components" "Components")\n' - ' (a :href "/docs/evaluator" "Evaluator"))\n' + ' (a :href "/language/docs/introduction" "Introduction")\n' + ' (a :href "/language/docs/components" "Components")\n' + ' (a :href "/language/docs/evaluator" "Evaluator"))\n' '\n' ';; All links swap into #main-panel automatically.\n' ';; Pure pages render client-side (no server request).' @@ -1239,7 +1239,7 @@ ATTR_DETAILS: dict[str, dict] = { ), "demo": "ref-preload-demo", "example": ( - '(button :sx-get "/hypermedia/reference/api/time"\n' + '(button :sx-get "/geography/hypermedia/reference/api/time"\n' ' :sx-target "#ref-preload-result"\n' ' :sx-swap "innerHTML"\n' ' :sx-preload "mouseover"\n' @@ -1275,7 +1275,7 @@ ATTR_DETAILS: dict[str, dict] = { ), "demo": "ref-indicator-demo", "example": ( - '(button :sx-get "/hypermedia/reference/api/slow-echo"\n' + '(button :sx-get "/geography/hypermedia/reference/api/slow-echo"\n' ' :sx-target "#ref-indicator-result"\n' ' :sx-swap "innerHTML"\n' ' :sx-indicator "#ref-spinner"\n' @@ -1302,7 +1302,7 @@ ATTR_DETAILS: dict[str, dict] = { ), "demo": "ref-validate-demo", "example": ( - '(form :sx-post "/hypermedia/reference/api/greet"\n' + '(form :sx-post "/geography/hypermedia/reference/api/greet"\n' ' :sx-target "#ref-validate-result"\n' ' :sx-swap "innerHTML"\n' ' :sx-validate "true"\n' @@ -1340,7 +1340,7 @@ ATTR_DETAILS: dict[str, dict] = { ), "demo": "ref-optimistic-demo", "example": ( - '(button :sx-delete "/hypermedia/reference/api/item/opt1"\n' + '(button :sx-delete "/geography/hypermedia/reference/api/item/opt1"\n' ' :sx-target "#ref-opt-item"\n' ' :sx-swap "delete"\n' ' :sx-optimistic "remove"\n' @@ -1362,7 +1362,7 @@ ATTR_DETAILS: dict[str, dict] = { ), "demo": "ref-replace-url-demo", "example": ( - '(button :sx-get "/hypermedia/reference/api/time"\n' + '(button :sx-get "/geography/hypermedia/reference/api/time"\n' ' :sx-target "#ref-replurl-result"\n' ' :sx-swap "innerHTML"\n' ' :sx-replace-url "true"\n' @@ -1378,7 +1378,7 @@ ATTR_DETAILS: dict[str, dict] = { ), "demo": "ref-disabled-elt-demo", "example": ( - '(button :sx-get "/hypermedia/reference/api/slow-echo"\n' + '(button :sx-get "/geography/hypermedia/reference/api/slow-echo"\n' ' :sx-target "#ref-diselt-result"\n' ' :sx-swap "innerHTML"\n' ' :sx-disabled-elt "this"\n' @@ -1394,7 +1394,7 @@ ATTR_DETAILS: dict[str, dict] = { ), "demo": "ref-prompt-demo", "example": ( - '(button :sx-get "/hypermedia/reference/api/prompt-echo"\n' + '(button :sx-get "/geography/hypermedia/reference/api/prompt-echo"\n' ' :sx-target "#ref-prompt-result"\n' ' :sx-swap "innerHTML"\n' ' :sx-prompt "Enter your name:"\n' @@ -1414,7 +1414,7 @@ ATTR_DETAILS: dict[str, dict] = { ), "demo": "ref-params-demo", "example": ( - '(form :sx-post "/hypermedia/reference/api/echo-vals"\n' + '(form :sx-post "/geography/hypermedia/reference/api/echo-vals"\n' ' :sx-target "#ref-params-result"\n' ' :sx-swap "innerHTML"\n' ' :sx-params "name"\n' @@ -1433,7 +1433,7 @@ ATTR_DETAILS: dict[str, dict] = { ), "demo": "ref-sse-demo", "example": ( - '(div :sx-sse "/hypermedia/reference/api/sse-time"\n' + '(div :sx-sse "/geography/hypermedia/reference/api/sse-time"\n' ' :sx-sse-swap "time"\n' ' :sx-target "#ref-sse-result"\n' ' :sx-swap "innerHTML"\n' diff --git a/sx/sx/analyzer.sx b/sx/sx/analyzer.sx index 70c9f59..6adb301 100644 --- a/sx/sx/analyzer.sx +++ b/sx/sx/analyzer.sx @@ -12,7 +12,7 @@ "Each bar shows how many of the " (strong (str total-components)) " total components a page actually needs, computed by the " - (a :href "/specs/deps" :class "text-violet-700 underline" "deps.sx") + (a :href "/language/specs/deps" :class "text-violet-700 underline" "deps.sx") " transitive closure algorithm. " "Click a page to see its component tree; expand a component to see its SX source.") diff --git a/sx/sx/cssx.sx b/sx/sx/cssx.sx index 19d2b0a..e2e6277 100644 --- a/sx/sx/cssx.sx +++ b/sx/sx/cssx.sx @@ -373,7 +373,7 @@ "directly. They arrive as part of the rendered HTML — keyframes, custom properties, " "scoped rules, anything.") (li (strong "External stylesheets: ") "Components can reference pre-loaded CSS files " - "or lazy-load them via " (code "~suspense") " (see " (a :href "/cssx/async" "Async CSS") ").") + "or lazy-load them via " (code "~suspense") " (see " (a :href "/applications/cssx/async" "Async CSS") ").") (li (strong "Custom properties: ") "A " (code "~theme") " component sets " (code "--color-primary") " etc. via a " (code "