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:
@@ -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.")
|
||||
|
||||
@@ -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)))
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user