Add Plans section to SX docs with isomorphic architecture roadmap
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 2m38s
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 2m38s
New top-level nav section at /plans/ with the 6-phase isomorphic architecture plan: component distribution, smart boundary, SPA routing, client IO bridge, streaming suspense, and full isomorphism. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -13,7 +13,8 @@
|
||||
(dict :label "Examples" :href "/examples/click-to-load")
|
||||
(dict :label "Essays" :href "/essays/")
|
||||
(dict :label "Specs" :href "/specs/")
|
||||
(dict :label "Bootstrappers" :href "/bootstrappers/"))))
|
||||
(dict :label "Bootstrappers" :href "/bootstrappers/")
|
||||
(dict :label "Plans" :href "/plans/"))))
|
||||
(<> (map (lambda (item)
|
||||
(~nav-link
|
||||
:href (get item "href")
|
||||
|
||||
@@ -101,6 +101,10 @@
|
||||
(dict :label "Continuations" :href "/specs/continuations")
|
||||
(dict :label "call/cc" :href "/specs/callcc")))
|
||||
|
||||
(define plans-nav-items (list
|
||||
(dict :label "Isomorphic Architecture" :href "/plans/isomorphic-architecture"
|
||||
:summary "Making the server/client boundary a sliding window — per-page bundles, smart expansion, SPA routing, client IO, streaming suspense.")))
|
||||
|
||||
(define bootstrappers-nav-items (list
|
||||
(dict :label "Overview" :href "/bootstrappers/")
|
||||
(dict :label "JavaScript" :href "/bootstrappers/javascript")
|
||||
|
||||
388
sx/sx/plans.sx
Normal file
388
sx/sx/plans.sx
Normal file
@@ -0,0 +1,388 @@
|
||||
;; Plans section — architecture roadmaps and implementation plans
|
||||
|
||||
;; ---------------------------------------------------------------------------
|
||||
;; Plans index page
|
||||
;; ---------------------------------------------------------------------------
|
||||
|
||||
(defcomp ~plans-index-content ()
|
||||
(~doc-page :title "Plans"
|
||||
(div :class "space-y-4"
|
||||
(p :class "text-lg text-stone-600 mb-4"
|
||||
"Architecture roadmaps and implementation plans for SX.")
|
||||
(div :class "space-y-3"
|
||||
(map (fn (item)
|
||||
(a :href (get item "href")
|
||||
:sx-get (get item "href") :sx-target "#main-panel" :sx-select "#main-panel"
|
||||
:sx-swap "outerHTML" :sx-push-url "true"
|
||||
:class "block rounded border border-stone-200 p-4 hover:border-violet-300 hover:bg-violet-50 transition-colors"
|
||||
(div :class "font-semibold text-stone-800" (get item "label"))
|
||||
(when (get item "summary")
|
||||
(p :class "text-sm text-stone-500 mt-1" (get item "summary")))))
|
||||
plans-nav-items)))))
|
||||
|
||||
;; ---------------------------------------------------------------------------
|
||||
;; Isomorphic Architecture Roadmap
|
||||
;; ---------------------------------------------------------------------------
|
||||
|
||||
(defcomp ~plan-isomorphic-content ()
|
||||
(~doc-page :title "Isomorphic Architecture Roadmap"
|
||||
|
||||
(~doc-section :title "Context" :id "context"
|
||||
(p "SX has a working server-client pipeline: server evaluates pages with IO (DB, fragments), serializes as SX wire format, client parses and renders to DOM. The language and primitives are already isomorphic " (em "— same spec, same semantics, both sides.") " What's missing is the " (strong "plumbing") " that makes the boundary between server and client a sliding window rather than a fixed wall.")
|
||||
(p "The key insight: " (strong "s-expressions can partially unfold on the server after IO, then finish unfolding on the client.") " The system should be clever enough to know which downstream components have data fetches, resolve those server-side, and send the rest as pure SX for client rendering. Eventually, the client can also do IO (mapping server DB queries to REST calls), handle routing (SPA), and even work offline with cached data."))
|
||||
|
||||
(~doc-section :title "Current State" :id "current-state"
|
||||
(ul :class "space-y-2 text-stone-700 list-disc pl-5"
|
||||
(li (strong "Primitive parity: ") "100%. ~80 pure primitives, same names/semantics, JS and Python.")
|
||||
(li (strong "eval/parse/render: ") "Complete both sides. sx-ref.js has eval, parse, render-to-html, render-to-dom, aser.")
|
||||
(li (strong "Engine: ") "engine.sx (morph, swaps, triggers, history), orchestration.sx (fetch, events), boot.sx (hydration) — all transpiled.")
|
||||
(li (strong "Wire format: ") "Server _aser → SX source → client parses → renders to DOM. Boundary is clean.")
|
||||
(li (strong "Component caching: ") "Hash-based localStorage for component definitions and style dictionaries.")
|
||||
(li (strong "CSS on-demand: ") "CSSX resolves keywords to CSS rules, injects only used rules.")
|
||||
(li (strong "Boundary enforcement: ") "boundary.sx + SX_BOUNDARY_STRICT=1 validates all primitives/IO/helpers at registration.")))
|
||||
|
||||
;; -----------------------------------------------------------------------
|
||||
;; Phase 1
|
||||
;; -----------------------------------------------------------------------
|
||||
|
||||
(~doc-section :title "Phase 1: Component Distribution & Dependency Analysis" :id "phase-1"
|
||||
|
||||
(div :class "rounded border border-violet-200 bg-violet-50 p-4 mb-4"
|
||||
(p :class "text-violet-900 font-medium" "What it enables")
|
||||
(p :class "text-violet-800" "Per-page component bundles instead of sending every definition to every page. Smaller payloads, faster boot, better cache hit rates."))
|
||||
|
||||
(~doc-subsection :title "The Problem"
|
||||
(p "client_components_tag() in jinja_bridge.py serializes ALL entries in _COMPONENT_ENV. The sx_page() template sends everything or nothing based on a single global hash. No mechanism determines which components a page actually needs."))
|
||||
|
||||
(~doc-subsection :title "Approach"
|
||||
|
||||
(div :class "space-y-4"
|
||||
(div
|
||||
(h4 :class "font-semibold text-stone-700" "1. Transitive closure analyzer")
|
||||
(p "New module shared/sx/deps.py:")
|
||||
(ul :class "list-disc pl-5 text-stone-700 space-y-1"
|
||||
(li "Walk Component.body AST, collect all Symbol refs starting with ~")
|
||||
(li "Recursively follow into their bodies")
|
||||
(li "Handle control forms (if/when/cond/case) — include ALL branches")
|
||||
(li "Handle macros — expand during walk using limited eval"))
|
||||
(~doc-code :code (highlight "def transitive_deps(name: str, env: dict) -> set[str]:\n \"\"\"Compute transitive component dependencies.\"\"\"\n seen = set()\n def walk(n):\n if n in seen: return\n seen.add(n)\n comp = env.get(n)\n if comp:\n for dep in _scan_ast(comp.body):\n walk(dep)\n walk(name)\n return seen - {name}" "python")))
|
||||
|
||||
(div
|
||||
(h4 :class "font-semibold text-stone-700" "2. Runtime component scanning")
|
||||
(p "After _aser serializes page content, scan the SX string for (~name patterns (parallel to existing scan_classes_from_sx for CSS). Then compute transitive closure to get sub-components."))
|
||||
|
||||
(div
|
||||
(h4 :class "font-semibold text-stone-700" "3. Per-page component block")
|
||||
(p "In sx_page() — replace all-or-nothing with page-specific bundle. Hash changes per page, localStorage cache keyed by route pattern."))
|
||||
|
||||
(div
|
||||
(h4 :class "font-semibold text-stone-700" "4. SX partial responses")
|
||||
(p "components_for_request() already diffs against SX-Components header. Enhance with transitive closure so only truly needed missing components are sent."))))
|
||||
|
||||
(~doc-subsection :title "Files"
|
||||
(ul :class "list-disc pl-5 text-stone-700 space-y-1 font-mono text-sm"
|
||||
(li "New: shared/sx/deps.py — dependency analysis")
|
||||
(li "shared/sx/jinja_bridge.py — per-page bundle generation")
|
||||
(li "shared/sx/helpers.py — modify sx_page() and sx_response()")
|
||||
(li "shared/sx/types.py — add deps: set[str] to Component")
|
||||
(li "shared/sx/ref/boot.sx — per-page component caching")))
|
||||
|
||||
(~doc-subsection :title "Verification"
|
||||
(ul :class "list-disc pl-5 text-stone-700 space-y-1"
|
||||
(li "Page using 5/50 components → data-components block contains only those 5 + transitive deps")
|
||||
(li "No \"Unknown component\" errors after bundle reduction")
|
||||
(li "Payload size reduction measurable"))))
|
||||
|
||||
;; -----------------------------------------------------------------------
|
||||
;; Phase 2
|
||||
;; -----------------------------------------------------------------------
|
||||
|
||||
(~doc-section :title "Phase 2: Smart Server/Client Boundary" :id "phase-2"
|
||||
|
||||
(div :class "rounded border border-violet-200 bg-violet-50 p-4 mb-4"
|
||||
(p :class "text-violet-900 font-medium" "What it enables")
|
||||
(p :class "text-violet-800" "Formalized partial evaluation model. Server evaluates IO, serializes pure subtrees. The system automatically knows \"this component needs server data\" vs \"this component is pure and can render anywhere.\""))
|
||||
|
||||
(~doc-subsection :title "Current Mechanism"
|
||||
(p "_aser in async_eval.py already does partial evaluation — IO primitives are awaited and substituted, HTML tags and component calls serialize as SX. The _expand_components context var controls expansion. But this is a global toggle, not per-component."))
|
||||
|
||||
(~doc-subsection :title "Approach"
|
||||
|
||||
(div :class "space-y-4"
|
||||
(div
|
||||
(h4 :class "font-semibold text-stone-700" "1. Automatic IO detection")
|
||||
(p "Extend Phase 1 AST walker to check for references to IO_PRIMITIVES names (frag, query, service, current-user, etc.).")
|
||||
(~doc-code :code (highlight "def has_io_deps(name: str, env: dict) -> bool:\n \"\"\"True if component transitively references any IO primitive.\"\"\"\n ..." "python")))
|
||||
|
||||
(div
|
||||
(h4 :class "font-semibold text-stone-700" "2. Component metadata")
|
||||
(~doc-code :code (highlight "ComponentMeta:\n deps: set[str] # transitive component deps (Phase 1)\n io_refs: set[str] # IO primitive names referenced\n is_pure: bool # True if io_refs empty (transitively)" "python")))
|
||||
|
||||
(div
|
||||
(h4 :class "font-semibold text-stone-700" "3. Selective expansion")
|
||||
(p "Refine _aser: instead of checking a global _expand_components flag, check the component's is_pure metadata:")
|
||||
(ul :class "list-disc pl-5 text-stone-700 space-y-1"
|
||||
(li "IO-dependent → expand server-side (IO must resolve)")
|
||||
(li "Pure → serialize for client (let client render)")
|
||||
(li "Explicit override: :server true on defcomp forces server expansion")))
|
||||
|
||||
(div
|
||||
(h4 :class "font-semibold text-stone-700" "4. Data manifest for pages")
|
||||
(p "PageDef produces a declaration of what IO the page needs, enabling Phase 3 (client can prefetch data) and Phase 5 (streaming)."))))
|
||||
|
||||
(~doc-subsection :title "Verification"
|
||||
(ul :class "list-disc pl-5 text-stone-700 space-y-1"
|
||||
(li "Components calling (query ...) classified IO-dependent; pure components classified pure")
|
||||
(li "Existing pages produce identical output (regression)"))))
|
||||
|
||||
;; -----------------------------------------------------------------------
|
||||
;; Phase 3
|
||||
;; -----------------------------------------------------------------------
|
||||
|
||||
(~doc-section :title "Phase 3: Client-Side Routing (SPA Mode)" :id "phase-3"
|
||||
|
||||
(div :class "rounded border border-violet-200 bg-violet-50 p-4 mb-4"
|
||||
(p :class "text-violet-900 font-medium" "What it enables")
|
||||
(p :class "text-violet-800" "After initial page load, client resolves routes locally using cached components + data. Only hits server for fresh data or unknown routes. Like Next.js client-side navigation."))
|
||||
|
||||
(~doc-subsection :title "Current Mechanism"
|
||||
(p "All routing is server-side via defpage → Quart routes. Client navigates via sx-boost links doing sx-get + morphing. Every navigation = server roundtrip."))
|
||||
|
||||
(~doc-subsection :title "Approach"
|
||||
|
||||
(div :class "space-y-4"
|
||||
(div
|
||||
(h4 :class "font-semibold text-stone-700" "1. Client-side page registry")
|
||||
(p "Serialize defpage routing info to client:")
|
||||
(~doc-code :code (highlight "(script :type \"text/sx-pages\")\n;; {\"docs-page\": {\"path\": \"/docs/:slug\", \"auth\": \"public\",\n;; \"content\": \"(case slug ...)\", \"data\": null}}" "lisp")))
|
||||
|
||||
(div
|
||||
(h4 :class "font-semibold text-stone-700" "2. Client route matcher")
|
||||
(p "New spec file shared/sx/ref/router.sx — convert /docs/<slug> patterns to matchers. On boost-link click: match URL → if found and pure, evaluate locally. If IO needed: fetch data from server, evaluate content locally. No match: fall through to standard fetch."))
|
||||
|
||||
(div
|
||||
(h4 :class "font-semibold text-stone-700" "3. Data endpoint")
|
||||
(~doc-code :code (highlight "GET /internal/page-data/<page-name>?<params>\n# Returns JSON with evaluated :data expression\n# Reuses execute_page() logic, stops after :data step" "python")))
|
||||
|
||||
(div
|
||||
(h4 :class "font-semibold text-stone-700" "4. Layout caching")
|
||||
(p "Layouts depend on auth/fragments, so cache current layout and reuse across navigations. SX-Layout-Hash header tracks staleness."))
|
||||
|
||||
(div
|
||||
(h4 :class "font-semibold text-stone-700" "5. Integration with orchestration.sx")
|
||||
(p "Intercept bind-boost-link to try client-side resolution first."))))
|
||||
|
||||
(div :class "rounded border border-amber-200 bg-amber-50 p-3 mt-2"
|
||||
(p :class "text-amber-800 text-sm" (strong "Depends on: ") "Phase 1 (client knows which components each page needs), Phase 2 (which pages are pure vs IO)."))
|
||||
|
||||
(~doc-subsection :title "Verification"
|
||||
(ul :class "list-disc pl-5 text-stone-700 space-y-1"
|
||||
(li "Pure page navigation: zero server requests")
|
||||
(li "IO page navigation: exactly one data request (not full page fetch)")
|
||||
(li "Browser back/forward works with client-resolved routes")
|
||||
(li "Disabling client registry → identical behavior to current"))))
|
||||
|
||||
;; -----------------------------------------------------------------------
|
||||
;; Phase 4
|
||||
;; -----------------------------------------------------------------------
|
||||
|
||||
(~doc-section :title "Phase 4: Client Async & IO Bridge" :id "phase-4"
|
||||
|
||||
(div :class "rounded border border-violet-200 bg-violet-50 p-4 mb-4"
|
||||
(p :class "text-violet-900 font-medium" "What it enables")
|
||||
(p :class "text-violet-800" "Client evaluates IO primitives by mapping them to server REST calls. Same SX code, different transport. (query \"market\" \"products\" :ids \"1,2,3\") on server → DB; on client → fetch(\"/internal/data/products?ids=1,2,3\")."))
|
||||
|
||||
(~doc-subsection :title "Approach"
|
||||
|
||||
(div :class "space-y-4"
|
||||
(div
|
||||
(h4 :class "font-semibold text-stone-700" "1. Async client evaluator")
|
||||
(p "Two possible mechanisms:")
|
||||
(ul :class "list-disc pl-5 text-stone-700 space-y-1"
|
||||
(li (strong "Promise-based: ") "evalExpr returns value or Promise; rendering awaits")
|
||||
(li (strong "Continuation-based: ") "use existing shift/reset to suspend on IO, resume when data arrives (architecturally cleaner, leverages existing spec)")))
|
||||
|
||||
(div
|
||||
(h4 :class "font-semibold text-stone-700" "2. IO primitive bridge")
|
||||
(p "Register async IO primitives in client PRIMITIVES:")
|
||||
(ul :class "list-disc pl-5 text-stone-700 space-y-1 font-mono text-sm"
|
||||
(li "query → fetch to /internal/data/")
|
||||
(li "service → fetch to target service internal endpoint")
|
||||
(li "frag → fetch fragment HTML")
|
||||
(li "current-user → cached from initial page load")))
|
||||
|
||||
(div
|
||||
(h4 :class "font-semibold text-stone-700" "3. Client data cache")
|
||||
(p "Keyed by (service, query, params-hash), configurable TTL, server can invalidate via SX-Invalidate header."))
|
||||
|
||||
(div
|
||||
(h4 :class "font-semibold text-stone-700" "4. Optimistic updates")
|
||||
(p "Extend existing apply-optimistic/revert-optimistic in engine.sx from DOM-level to data-level."))))
|
||||
|
||||
(div :class "rounded border border-amber-200 bg-amber-50 p-3 mt-2"
|
||||
(p :class "text-amber-800 text-sm" (strong "Depends on: ") "Phase 2 (IO affinity), Phase 3 (routing for when to trigger IO)."))
|
||||
|
||||
(~doc-subsection :title "Verification"
|
||||
(ul :class "list-disc pl-5 text-stone-700 space-y-1"
|
||||
(li "Client (query ...) returns identical data to server-side")
|
||||
(li "Data cache prevents redundant fetches")
|
||||
(li "Same component source → identical output on either side"))))
|
||||
|
||||
;; -----------------------------------------------------------------------
|
||||
;; Phase 5
|
||||
;; -----------------------------------------------------------------------
|
||||
|
||||
(~doc-section :title "Phase 5: Streaming & Suspense" :id "phase-5"
|
||||
|
||||
(div :class "rounded border border-violet-200 bg-violet-50 p-4 mb-4"
|
||||
(p :class "text-violet-900 font-medium" "What it enables")
|
||||
(p :class "text-violet-800" "Server streams partially-evaluated SX as IO resolves. Client renders available subtrees immediately, fills in suspended parts. Like React Suspense but built on delimited continuations."))
|
||||
|
||||
(~doc-subsection :title "Approach"
|
||||
|
||||
(div :class "space-y-4"
|
||||
(div
|
||||
(h4 :class "font-semibold text-stone-700" "1. Continuation-based suspension")
|
||||
(p "When _aser encounters IO during slot evaluation, emit a placeholder with a suspension ID, schedule async resolution:")
|
||||
(~doc-code :code (highlight "(~suspense :id \"placeholder-123\"\n :fallback (div \"Loading...\"))" "lisp")))
|
||||
|
||||
(div
|
||||
(h4 :class "font-semibold text-stone-700" "2. Chunked transfer")
|
||||
(p "Quart async generator responses:")
|
||||
(ul :class "list-disc pl-5 text-stone-700 space-y-1"
|
||||
(li "First chunk: HTML shell + synchronous content + placeholders")
|
||||
(li "Subsequent chunks: <script> tags replacing placeholders with resolved content")))
|
||||
|
||||
(div
|
||||
(h4 :class "font-semibold text-stone-700" "3. Client suspension rendering")
|
||||
(p "~suspense component renders fallback, listens for resolution via inline script or SSE (existing SSE infrastructure in orchestration.sx)."))
|
||||
|
||||
(div
|
||||
(h4 :class "font-semibold text-stone-700" "4. Priority-based IO")
|
||||
(p "Above-fold content resolves first. All IO starts concurrently (asyncio.create_task), results flushed in priority order."))))
|
||||
|
||||
(div :class "rounded border border-amber-200 bg-amber-50 p-3 mt-2"
|
||||
(p :class "text-amber-800 text-sm" (strong "Depends on: ") "Phase 4 (client async for filling suspended subtrees), Phase 2 (IO analysis for priority).")))
|
||||
|
||||
;; -----------------------------------------------------------------------
|
||||
;; Phase 6
|
||||
;; -----------------------------------------------------------------------
|
||||
|
||||
(~doc-section :title "Phase 6: Full Isomorphism" :id "phase-6"
|
||||
|
||||
(div :class "rounded border border-violet-200 bg-violet-50 p-4 mb-4"
|
||||
(p :class "text-violet-900 font-medium" "What it enables")
|
||||
(p :class "text-violet-800" "Same SX code runs on either side. Runtime chooses optimal split. Offline-first with cached data + client eval."))
|
||||
|
||||
(~doc-subsection :title "Approach"
|
||||
|
||||
(div :class "space-y-4"
|
||||
(div
|
||||
(h4 :class "font-semibold text-stone-700" "1. Runtime boundary optimizer")
|
||||
(p "Given component tree + IO dependency graph, decide per-component: server-expand, client-render, or stream. Planning step cached at registration, recomputed on component change."))
|
||||
|
||||
(div
|
||||
(h4 :class "font-semibold text-stone-700" "2. Affinity annotations")
|
||||
(~doc-code :code (highlight "(defcomp ~product-grid (&key products)\n :affinity :client ;; interactive, prefer client\n ...)\n\n(defcomp ~auth-menu (&key user)\n :affinity :server ;; auth-sensitive, always server\n ...)" "lisp"))
|
||||
(p "Default: auto (runtime decides from IO analysis)."))
|
||||
|
||||
(div
|
||||
(h4 :class "font-semibold text-stone-700" "3. Offline data layer")
|
||||
(p "Service Worker intercepts /internal/data/ requests, serves from IndexedDB when offline, syncs when back online."))
|
||||
|
||||
(div
|
||||
(h4 :class "font-semibold text-stone-700" "4. Isomorphic testing")
|
||||
(p "Evaluate same component on Python and JS, compare output. Extends existing test_sx_ref.py cross-evaluator comparison."))
|
||||
|
||||
(div
|
||||
(h4 :class "font-semibold text-stone-700" "5. Universal page descriptor")
|
||||
(p "defpage is portable: server executes via execute_page(), client executes via route match → fetch data → eval content → render DOM. Same descriptor, different execution environment."))))
|
||||
|
||||
(div :class "rounded border border-amber-200 bg-amber-50 p-3 mt-2"
|
||||
(p :class "text-amber-800 text-sm" (strong "Depends on: ") "All previous phases.")))
|
||||
|
||||
;; -----------------------------------------------------------------------
|
||||
;; Cross-Cutting Concerns
|
||||
;; -----------------------------------------------------------------------
|
||||
|
||||
(~doc-section :title "Cross-Cutting Concerns" :id "cross-cutting"
|
||||
|
||||
(~doc-subsection :title "Error Reporting"
|
||||
(ul :class "list-disc pl-5 text-stone-700 space-y-1"
|
||||
(li "Phase 1: \"Unknown component\" includes which page expected it and what bundle was sent")
|
||||
(li "Phase 2: Server logs which components expanded server-side vs sent to client")
|
||||
(li "Phase 3: Client route failures include unmatched path and available routes")
|
||||
(li "Phase 4: Client IO errors include query name, params, server response")
|
||||
(li "Source location tracking in parser → propagate through eval → include in error messages")))
|
||||
|
||||
(~doc-subsection :title "Backward Compatibility"
|
||||
(ul :class "list-disc pl-5 text-stone-700 space-y-1"
|
||||
(li "Pages without annotations behave as today")
|
||||
(li "SX-Request / SX-Components / SX-Css header protocol continues")
|
||||
(li "Existing .sx files require no changes")
|
||||
(li "_expand_components continues as override")
|
||||
(li "Each phase is opt-in: disable → identical to previous behavior")))
|
||||
|
||||
(~doc-subsection :title "Spec Integrity"
|
||||
(p "All new behavior specified in .sx files under shared/sx/ref/ before implementation. Bootstrappers transpile from spec. This ensures JS and Python stay in sync.")))
|
||||
|
||||
;; -----------------------------------------------------------------------
|
||||
;; Critical Files
|
||||
;; -----------------------------------------------------------------------
|
||||
|
||||
(~doc-section :title "Critical Files" :id "critical-files"
|
||||
(div :class "overflow-x-auto rounded border border-stone-200"
|
||||
(table :class "w-full text-left text-sm"
|
||||
(thead (tr :class "border-b border-stone-200 bg-stone-100"
|
||||
(th :class "px-3 py-2 font-medium text-stone-600" "File")
|
||||
(th :class "px-3 py-2 font-medium text-stone-600" "Role")
|
||||
(th :class "px-3 py-2 font-medium text-stone-600" "Phases")))
|
||||
(tbody
|
||||
(tr :class "border-b border-stone-100"
|
||||
(td :class "px-3 py-2 font-mono text-sm text-violet-700" "shared/sx/async_eval.py")
|
||||
(td :class "px-3 py-2 text-stone-700" "Core evaluator, _aser, server/client boundary")
|
||||
(td :class "px-3 py-2 text-stone-600" "2, 5"))
|
||||
(tr :class "border-b border-stone-100"
|
||||
(td :class "px-3 py-2 font-mono text-sm text-violet-700" "shared/sx/helpers.py")
|
||||
(td :class "px-3 py-2 text-stone-700" "sx_page(), sx_response(), output pipeline")
|
||||
(td :class "px-3 py-2 text-stone-600" "1, 3"))
|
||||
(tr :class "border-b border-stone-100"
|
||||
(td :class "px-3 py-2 font-mono text-sm text-violet-700" "shared/sx/jinja_bridge.py")
|
||||
(td :class "px-3 py-2 text-stone-700" "_COMPONENT_ENV, component registry")
|
||||
(td :class "px-3 py-2 text-stone-600" "1, 2"))
|
||||
(tr :class "border-b border-stone-100"
|
||||
(td :class "px-3 py-2 font-mono text-sm text-violet-700" "shared/sx/pages.py")
|
||||
(td :class "px-3 py-2 text-stone-700" "defpage, execute_page(), page lifecycle")
|
||||
(td :class "px-3 py-2 text-stone-600" "2, 3"))
|
||||
(tr :class "border-b border-stone-100"
|
||||
(td :class "px-3 py-2 font-mono text-sm text-violet-700" "shared/sx/ref/boot.sx")
|
||||
(td :class "px-3 py-2 text-stone-700" "Client boot, component caching")
|
||||
(td :class "px-3 py-2 text-stone-600" "1, 3, 4"))
|
||||
(tr :class "border-b border-stone-100"
|
||||
(td :class "px-3 py-2 font-mono text-sm text-violet-700" "shared/sx/ref/orchestration.sx")
|
||||
(td :class "px-3 py-2 text-stone-700" "Client fetch/swap/morph")
|
||||
(td :class "px-3 py-2 text-stone-600" "3, 4"))
|
||||
(tr :class "border-b border-stone-100"
|
||||
(td :class "px-3 py-2 font-mono text-sm text-violet-700" "shared/sx/ref/eval.sx")
|
||||
(td :class "px-3 py-2 text-stone-700" "Evaluator spec")
|
||||
(td :class "px-3 py-2 text-stone-600" "4"))
|
||||
(tr :class "border-b border-stone-100"
|
||||
(td :class "px-3 py-2 font-mono text-sm text-violet-700" "shared/sx/ref/engine.sx")
|
||||
(td :class "px-3 py-2 text-stone-700" "Morph, swaps, triggers")
|
||||
(td :class "px-3 py-2 text-stone-600" "3"))
|
||||
(tr :class "border-b border-stone-100"
|
||||
(td :class "px-3 py-2 font-mono text-sm text-violet-700" "shared/sx/deps.py")
|
||||
(td :class "px-3 py-2 text-stone-700" "Dependency analysis (new)")
|
||||
(td :class "px-3 py-2 text-stone-600" "1, 2"))
|
||||
(tr :class "border-b border-stone-100"
|
||||
(td :class "px-3 py-2 font-mono text-sm text-violet-700" "shared/sx/ref/router.sx")
|
||||
(td :class "px-3 py-2 text-stone-700" "Client-side routing (new)")
|
||||
(td :class "px-3 py-2 text-stone-600" "3"))
|
||||
(tr :class "border-b border-stone-100"
|
||||
(td :class "px-3 py-2 font-mono text-sm text-violet-700" "shared/sx/ref/io-bridge.sx")
|
||||
(td :class "px-3 py-2 text-stone-700" "Client IO primitives (new)")
|
||||
(td :class "px-3 py-2 text-stone-600" "4"))
|
||||
(tr :class "border-b border-stone-100"
|
||||
(td :class "px-3 py-2 font-mono text-sm text-violet-700" "shared/sx/ref/suspense.sx")
|
||||
(td :class "px-3 py-2 text-stone-700" "Streaming/suspension (new)")
|
||||
(td :class "px-3 py-2 text-stone-600" "5"))))))))
|
||||
@@ -386,3 +386,32 @@
|
||||
(~bootstrapper-js-content
|
||||
:bootstrapper-source bootstrapper-source
|
||||
:bootstrapped-output bootstrapped-output))))
|
||||
|
||||
;; ---------------------------------------------------------------------------
|
||||
;; Plans section
|
||||
;; ---------------------------------------------------------------------------
|
||||
|
||||
(defpage plans-index
|
||||
:path "/plans/"
|
||||
:auth :public
|
||||
:layout (:sx-section
|
||||
:section "Plans"
|
||||
:sub-label "Plans"
|
||||
:sub-href "/plans/"
|
||||
:sub-nav (~section-nav :items plans-nav-items :current "")
|
||||
:selected "")
|
||||
:content (~plans-index-content))
|
||||
|
||||
(defpage plan-page
|
||||
:path "/plans/<slug>"
|
||||
:auth :public
|
||||
:layout (:sx-section
|
||||
:section "Plans"
|
||||
:sub-label "Plans"
|
||||
:sub-href "/plans/"
|
||||
:sub-nav (~section-nav :items plans-nav-items
|
||||
:current (find-current plans-nav-items slug))
|
||||
:selected (or (find-current plans-nav-items slug) ""))
|
||||
:content (case slug
|
||||
"isomorphic-architecture" (~plan-isomorphic-content)
|
||||
:else (~plans-index-content)))
|
||||
|
||||
Reference in New Issue
Block a user