Add Bootstrappers section, essays index, specs prose, layout fixes

- New Bootstrappers top-level section with overview index and JS bootstrapper
  page that runs bootstrap_js.py and displays both source and generated output
  with live script injection (full page load, not SX navigation)
- Essays section: index page with linked cards and summaries, sx-sucks moved
  to end of nav, removed "grand tradition" line
- Specs: English prose descriptions alongside all canonical .sx specs, added
  Boot/CSSX/Browser spec files to architecture page
- Layout: menu bar nav items wrap instead of overflow, baseline alignment
  between label and nav options
- Homepage: added copyright line

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-05 16:12:38 +00:00
parent 436848060d
commit 1797bd4b16
8 changed files with 315 additions and 38 deletions

View File

@@ -4,8 +4,10 @@
(div :class "max-w-4xl mx-auto px-6 py-16 text-center"
(h1 :class "text-5xl font-bold text-stone-900 mb-4"
(span :class "text-violet-600 font-mono" "(<sx>)"))
(p :class "text-2xl text-stone-600 mb-8"
(p :class "text-2xl text-stone-600 mb-4"
"s-expressions for the web")
(p :class "text-sm text-stone-400"
"\u00a9 Giles Bradshaw 2026")
(p :class "text-lg text-stone-500 max-w-2xl mx-auto mb-12"
"A hypermedia-driven UI engine that combines htmx's server-first philosophy "
"with React's component model. S-expressions over the wire — no HTML, no JavaScript frameworks.")

View File

@@ -214,10 +214,10 @@
:layout (:sx-section
:section "Essays"
:sub-label "Essays"
:sub-href "/essays/sx-sucks"
:sub-nav (~section-nav :items essays-nav-items :current "sx sucks")
:selected "sx sucks")
:content (~essay-sx-sucks))
:sub-href "/essays/"
:sub-nav (~section-nav :items essays-nav-items :current "")
:selected "")
:content (~essays-index-content))
(defpage essay-page
:path "/essays/<slug>"
@@ -225,7 +225,7 @@
:layout (:sx-section
:section "Essays"
:sub-label "Essays"
:sub-href "/essays/sx-sucks"
:sub-href "/essays/"
:sub-nav (~section-nav :items essays-nav-items
:current (find-current essays-nav-items slug))
:selected (or (find-current essays-nav-items slug) ""))
@@ -241,7 +241,7 @@
"continuations" (~essay-continuations)
"godel-escher-bach" (~essay-godel-escher-bach)
"reflexive-web" (~essay-reflexive-web)
:else (~essay-sx-sucks)))
:else (~essays-index-content)))
;; ---------------------------------------------------------------------------
;; Specs section
@@ -273,6 +273,7 @@
:spec-title "Core Language"
:spec-files (map (fn (item)
(dict :title (get item "title") :desc (get item "desc")
:prose (get item "prose")
:filename (get item "filename") :href (str "/specs/" (get item "slug"))
:source (read-spec-file (get item "filename"))))
core-spec-items))
@@ -280,14 +281,56 @@
:spec-title "Adapters & Engine"
:spec-files (map (fn (item)
(dict :title (get item "title") :desc (get item "desc")
:prose (get item "prose")
:filename (get item "filename") :href (str "/specs/" (get item "slug"))
:source (read-spec-file (get item "filename"))))
adapter-spec-items))
"browser" (~spec-overview-content
:spec-title "Browser"
:spec-files (map (fn (item)
(dict :title (get item "title") :desc (get item "desc")
:prose (get item "prose")
:filename (get item "filename") :href (str "/specs/" (get item "slug"))
:source (read-spec-file (get item "filename"))))
browser-spec-items))
:else (let ((spec (find-spec slug)))
(if spec
(~spec-detail-content
:spec-title (get spec "title")
:spec-desc (get spec "desc")
:spec-filename (get spec "filename")
:spec-source (read-spec-file (get spec "filename")))
:spec-source (read-spec-file (get spec "filename"))
:spec-prose (get spec "prose"))
(~spec-not-found :slug slug)))))
;; ---------------------------------------------------------------------------
;; Bootstrappers section
;; ---------------------------------------------------------------------------
(defpage bootstrappers-index
:path "/bootstrappers/"
:auth :public
:layout (:sx-section
:section "Bootstrappers"
:sub-label "Bootstrappers"
:sub-href "/bootstrappers/"
:sub-nav (~section-nav :items bootstrappers-nav-items :current "Overview")
:selected "Overview")
:content (~bootstrappers-index-content))
(defpage bootstrapper-page
:path "/bootstrappers/<slug>"
:auth :public
:layout (:sx-section
:section "Bootstrappers"
:sub-label "Bootstrappers"
:sub-href "/bootstrappers/"
:sub-nav (~section-nav :items bootstrappers-nav-items
:current (find-current bootstrappers-nav-items slug))
:selected (or (find-current bootstrappers-nav-items slug) ""))
:data (bootstrapper-data slug)
:content (if bootstrapper-not-found
(~spec-not-found :slug slug)
(~bootstrapper-js-content
:bootstrapper-source bootstrapper-source
:bootstrapped-output bootstrapped-output)))

View File

@@ -17,6 +17,7 @@ def _register_sx_helpers() -> None:
"reference-data": _reference_data,
"attr-detail-data": _attr_detail_data,
"read-spec-file": _read_spec_file,
"bootstrapper-data": _bootstrapper_data,
})
@@ -118,6 +119,47 @@ def _read_spec_file(filename: str) -> str:
return ";; spec file not found"
def _bootstrapper_data(target: str) -> dict:
"""Return bootstrapper source and generated output for a target.
Returns a dict whose keys become SX env bindings:
- bootstrapper-source: the Python bootstrapper source code
- bootstrapped-output: the generated JavaScript
- bootstrapper-not-found: truthy if target unknown
"""
import os
if target != "javascript":
return {"bootstrapper-not-found": True}
ref_dir = os.path.join(os.path.dirname(__file__), "..", "..", "shared", "sx", "ref")
if not os.path.isdir(ref_dir):
ref_dir = "/app/shared/sx/ref"
# Read bootstrapper source
bs_path = os.path.join(ref_dir, "bootstrap_js.py")
try:
with open(bs_path, encoding="utf-8") as f:
bootstrapper_source = f.read()
except FileNotFoundError:
bootstrapper_source = "# bootstrapper source not found"
# Run the bootstrap to generate JS
from shared.sx.ref.bootstrap_js import compile_ref_to_js
try:
bootstrapped_output = compile_ref_to_js(
adapters=["dom", "engine", "orchestration", "boot", "cssx"]
)
except Exception as e:
bootstrapped_output = f"// bootstrap error: {e}"
return {
"bootstrapper-not-found": None,
"bootstrapper-source": bootstrapper_source,
"bootstrapped-output": bootstrapped_output,
}
def _attr_detail_data(slug: str) -> dict:
"""Return attribute detail data for a specific attribute slug.