URL restructure, 404 page, trailing slash normalization, layout fixes

- Rename /reactive-islands/ → /reactive/, /reference/ → /hypermedia/reference/,
  /examples/ → /hypermedia/examples/ across all .sx and .py files
- Add 404 error page (not-found.sx) working on both server refresh and
  client-side SX navigation via orchestration.sx error response handling
- Add trailing slash redirect (GET only, excludes /api/, /static/, /internal/)
- Remove blue sky-500 header bar from SX docs layout (conditional on header-rows)
- Fix 405 on API endpoints from trailing slash redirect hitting POST/PUT/DELETE
- Fix client-side 404: orchestration.sx now swaps error response content
  instead of silently dropping it
- Add new plan files and home page component

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-10 21:30:18 +00:00
parent e149dfe968
commit 1341c144da
35 changed files with 2305 additions and 438 deletions

View File

@@ -306,7 +306,47 @@
;; ==========================================================================
;; 12. Named stores — page-level signal containers (L3)
;; 12. Marsh scopes — child scopes within islands
;; ==========================================================================
;;
;; Marshes are zones inside islands where server content is re-evaluated
;; in the island's reactive context. When a marsh is re-morphed with new
;; content, its old effects and computeds must be disposed WITHOUT disturbing
;; the island's own reactive graph.
;;
;; Scope hierarchy: island → marsh → effects/computeds
;; Disposing a marsh disposes its subscope. Disposing an island disposes
;; all its marshes. The signal graph is a tree, not a flat list.
;;
;; Platform interface required:
;; (dom-set-data el key val) → void — store JS value on element
;; (dom-get-data el key) → any — retrieve stored value
(define with-marsh-scope
(fn (marsh-el body-fn)
;; Execute body-fn collecting all disposables into a marsh-local list.
;; Nested under the current island scope — if the island is disposed,
;; the marsh is disposed too (because island scope collected the marsh's
;; own dispose function).
(let ((disposers (list)))
(with-island-scope
(fn (d) (append! disposers d))
body-fn)
;; Store disposers on the marsh element for later cleanup
(dom-set-data marsh-el "sx-marsh-disposers" disposers))))
(define dispose-marsh-scope
(fn (marsh-el)
;; Dispose all effects/computeds registered in this marsh's scope.
;; Parent island scope and sibling marshes are unaffected.
(let ((disposers (dom-get-data marsh-el "sx-marsh-disposers")))
(when disposers
(for-each (fn (d) (invoke d)) disposers)
(dom-set-data marsh-el "sx-marsh-disposers" nil)))))
;; ==========================================================================
;; 13. Named stores — page-level signal containers (L3)
;; ==========================================================================
;;
;; Stores persist across island creation/destruction. They live at page