diff --git a/shared/sx/helpers.py b/shared/sx/helpers.py index d42b77c..825fa6e 100644 --- a/shared/sx/helpers.py +++ b/shared/sx/helpers.py @@ -463,11 +463,12 @@ def components_for_request(source: str = "", Reads the ``SX-Components`` header (comma-separated component names like ``~card,~nav-item``) and returns only the definitions the client is missing. If *source* is provided, only sends components needed - for that source (plus transitive deps). + for that source (plus transitive deps). If the header is absent, + returns all needed defs. - *extra_names* — additional component names to include beyond what - *source* references. Used by defpage to send components the page's - content expression needs for client-side routing. + *extra_names* — additional component names (``~foo``) to include + beyond what *source* references. Used by ``execute_page`` to send + components the page's content expression needs for client-side routing. """ from quart import request from .jinja_bridge import _COMPONENT_ENV diff --git a/shared/sx/pages.py b/shared/sx/pages.py index a3ba7e7..8796988 100644 --- a/shared/sx/pages.py +++ b/shared/sx/pages.py @@ -282,7 +282,7 @@ async def execute_page( # Compute content expression deps so the server sends component # definitions the client needs for future client-side routing extra_deps: set[str] | None = None - if page_def.content_expr is not None: + if page_def.content_expr is not None and page_def.data_expr is None: from .deps import components_needed from .parser import serialize try: diff --git a/sx/content/highlight.py b/sx/content/highlight.py index 40e0615..1515eb5 100644 --- a/sx/content/highlight.py +++ b/sx/content/highlight.py @@ -8,12 +8,22 @@ from __future__ import annotations import re +def _escape(text: str) -> str: + """Escape a token for embedding in an SX string literal.""" + return (text + .replace("\\", "\\\\") + .replace('"', '\\"') + .replace("\n", "\\n") + .replace("\t", "\\t") + .replace("\r", "\\r")) + + def highlight_sx(code: str) -> str: """Highlight s-expression source code as sx with Tailwind spans.""" tokens = _tokenize_sx(code) parts = [] for kind, text in tokens: - escaped = text.replace("\\", "\\\\").replace('"', '\\"') + escaped = _escape(text) if kind == "comment": parts.append(f'(span :class "text-stone-400 italic" "{escaped}")') elif kind == "string": @@ -94,7 +104,7 @@ def highlight_python(code: str) -> str: tokens = _tokenize_python(code) parts = [] for kind, text in tokens: - escaped = text.replace("\\", "\\\\").replace('"', '\\"') + escaped = _escape(text) if kind == "comment": parts.append(f'(span :class "text-stone-400 italic" "{escaped}")') elif kind == "string": @@ -176,7 +186,7 @@ def highlight_bash(code: str) -> str: tokens = _tokenize_bash(code) parts = [] for kind, text in tokens: - escaped = text.replace("\\", "\\\\").replace('"', '\\"') + escaped = _escape(text) if kind == "comment": parts.append(f'(span :class "text-stone-400 italic" "{escaped}")') elif kind == "string": diff --git a/sx/sx/nav-data.sx b/sx/sx/nav-data.sx index d16901b..096a065 100644 --- a/sx/sx/nav-data.sx +++ b/sx/sx/nav-data.sx @@ -111,6 +111,8 @@ (dict :label "Async IO" :href "/isomorphism/async-io"))) (define plans-nav-items (list + (dict :label "Status" :href "/plans/status" + :summary "Audit of all plans — what's done, what's in progress, and what remains.") (dict :label "Reader Macros" :href "/plans/reader-macros" :summary "Extensible parse-time transformations via # dispatch — datum comments, raw strings, and quote shorthand.") (dict :label "SX-Activity" :href "/plans/sx-activity" @@ -118,7 +120,13 @@ (dict :label "Predictive Prefetching" :href "/plans/predictive-prefetch" :summary "Prefetch missing component definitions before the user clicks — hover a link, fetch its deps, navigate client-side.") (dict :label "Content-Addressed Components" :href "/plans/content-addressed-components" - :summary "Components identified by CID, stored on IPFS, fetched from anywhere. Canonical serialization, content verification, federated sharing."))) + :summary "Components identified by CID, stored on IPFS, fetched from anywhere. Canonical serialization, content verification, federated sharing.") + (dict :label "Fragment Protocol" :href "/plans/fragment-protocol" + :summary "Structured sexp request/response for cross-service component transfer.") + (dict :label "Glue Decoupling" :href "/plans/glue-decoupling" + :summary "Eliminate all cross-app model imports via glue service layer.") + (dict :label "Social Sharing" :href "/plans/social-sharing" + :summary "OAuth-based sharing to Facebook, Instagram, Threads, Twitter/X, LinkedIn, and Mastodon."))) (define bootstrappers-nav-items (list (dict :label "Overview" :href "/bootstrappers/") diff --git a/sx/sx/plans.sx b/sx/sx/plans.sx index 2840c7b..347ac89 100644 --- a/sx/sx/plans.sx +++ b/sx/sx/plans.sx @@ -1264,6 +1264,282 @@ ". It extends Phase 3 by making more navigations go client-side without needing any IO bridge — purely by ensuring component definitions are available before they're needed.") (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 3 (client-side routing with deps checking). No dependency on Phase 4."))))) +;; --------------------------------------------------------------------------- +;; Plan Status Overview +;; --------------------------------------------------------------------------- + +(defcomp ~plan-status-content () + (~doc-page :title "Plan Status" + + (p :class "text-lg text-stone-600 mb-6" + "Audit of all plans across the SX language and Rose Ash platform. Last updated March 2026.") + + ;; ----------------------------------------------------------------------- + ;; Completed + ;; ----------------------------------------------------------------------- + + (~doc-section :title "Completed" :id "completed" + + (div :class "space-y-4" + + (div :class "rounded border border-green-200 bg-green-50 p-4" + (div :class "flex items-center gap-2 mb-1" + (span :class "inline-block px-2 py-0.5 rounded text-xs font-bold bg-green-600 text-white uppercase" "Complete") + (span :class "font-semibold text-stone-800" "Split Cart into Microservices")) + (p :class "text-sm text-stone-600" "Cart decomposed into 4 services: relations (internal, owns ContainerRelation), likes (internal, unified generic likes), orders (public, owns Order/OrderItem + SumUp checkout), and cart (thin CartItem CRUD). All three new services deployed with dedicated databases.")) + + (div :class "rounded border border-green-200 bg-green-50 p-4" + (div :class "flex items-center gap-2 mb-1" + (span :class "inline-block px-2 py-0.5 rounded text-xs font-bold bg-green-600 text-white uppercase" "Complete") + (span :class "font-semibold text-stone-800" "Ticket Purchase Through Cart")) + (p :class "text-sm text-stone-600" "Tickets flow through the cart like products: state=pending in cart, reserved at checkout, confirmed on payment. TicketDTO, CartSummaryDTO with ticket_count/ticket_total, CalendarService protocol methods all implemented.")) + + (div :class "rounded border border-green-200 bg-green-50 p-4" + (div :class "flex items-center gap-2 mb-1" + (span :class "inline-block px-2 py-0.5 rounded text-xs font-bold bg-green-600 text-white uppercase" "Complete") + (span :class "font-semibold text-stone-800" "Ticket UX Improvements")) + (p :class "text-sm text-stone-600" "+/- quantity buttons on entry pages and cart. Tickets grouped by event in cart display. Adjust quantity route, sold/basket counts, matching product card UX pattern.")) + + (div :class "rounded border border-green-200 bg-green-50 p-4" + (div :class "flex items-center gap-2 mb-1" + (span :class "inline-block px-2 py-0.5 rounded text-xs font-bold bg-green-600 text-white uppercase" "Complete") + (a :href "/isomorphism/" :class "font-semibold text-green-800 underline" "Isomorphic Phase 1: Dependency Analysis")) + (p :class "text-sm text-stone-600" "Per-page component bundles via deps.sx. Transitive closure, scan-refs, components-needed, page-css-classes. 15 tests, bootstrapped to both hosts.")) + + (div :class "rounded border border-green-200 bg-green-50 p-4" + (div :class "flex items-center gap-2 mb-1" + (span :class "inline-block px-2 py-0.5 rounded text-xs font-bold bg-green-600 text-white uppercase" "Complete") + (a :href "/isomorphism/" :class "font-semibold text-green-800 underline" "Isomorphic Phase 2: IO Detection")) + (p :class "text-sm text-stone-600" "Automatic IO classification. scan-io-refs, transitive-io-refs, compute-all-io-refs. Server expands IO components, serializes pure ones for client.")) + + (div :class "rounded border border-green-200 bg-green-50 p-4" + (div :class "flex items-center gap-2 mb-1" + (span :class "inline-block px-2 py-0.5 rounded text-xs font-bold bg-green-600 text-white uppercase" "Complete") + (a :href "/isomorphism/" :class "font-semibold text-green-800 underline" "Isomorphic Phase 3: Client-Side Routing")) + (p :class "text-sm text-stone-600" "router.sx spec, page registry via