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:
@@ -52,8 +52,13 @@
|
||||
(create-fragment)
|
||||
(render-dom-list expr env ns))
|
||||
|
||||
;; Fallback
|
||||
:else (create-text-node (str expr)))))
|
||||
;; Signal → reactive text in island scope, deref outside
|
||||
:else
|
||||
(if (signal? expr)
|
||||
(if *island-scope*
|
||||
(reactive-text expr)
|
||||
(create-text-node (str (deref expr))))
|
||||
(create-text-node (str expr))))))
|
||||
|
||||
|
||||
;; --------------------------------------------------------------------------
|
||||
@@ -81,6 +86,10 @@
|
||||
(= name "lake")
|
||||
(render-dom-lake args env ns)
|
||||
|
||||
;; marsh — reactive server-morphable slot within an island
|
||||
(= name "marsh")
|
||||
(render-dom-marsh args env ns)
|
||||
|
||||
;; html: prefix → force element rendering
|
||||
(starts-with? name "html:")
|
||||
(render-dom-element (slice name 5) args env ns)
|
||||
@@ -490,7 +499,8 @@
|
||||
(if (and *island-scope*
|
||||
(= (type-of coll-expr) "list")
|
||||
(> (len coll-expr) 1)
|
||||
(= (first coll-expr) "deref"))
|
||||
(= (type-of (first coll-expr)) "symbol")
|
||||
(= (symbol-name (first coll-expr)) "deref"))
|
||||
;; Reactive path: pass signal to reactive-list
|
||||
(let ((f (trampoline (eval-expr (nth expr 1) env)))
|
||||
(sig (trampoline (eval-expr (nth coll-expr 1) env))))
|
||||
@@ -698,6 +708,56 @@
|
||||
el))))
|
||||
|
||||
|
||||
;; --------------------------------------------------------------------------
|
||||
;; render-dom-marsh — reactive server-morphable slot within an island
|
||||
;; --------------------------------------------------------------------------
|
||||
;;
|
||||
;; (marsh :id "name" :tag "div" :transform fn children...)
|
||||
;;
|
||||
;; Like a lake but reactive: during morph, new content is parsed as SX and
|
||||
;; re-evaluated in the island's signal scope. The :transform function (if
|
||||
;; present) reshapes server content before evaluation.
|
||||
;;
|
||||
;; Renders as <div data-sx-marsh="name">children</div>.
|
||||
;; Stores the island env and transform on the element for morph retrieval.
|
||||
|
||||
(define render-dom-marsh
|
||||
(fn (args env ns)
|
||||
(let ((marsh-id nil)
|
||||
(marsh-tag "div")
|
||||
(marsh-transform nil)
|
||||
(children (list)))
|
||||
(reduce
|
||||
(fn (state arg)
|
||||
(let ((skip (get state "skip")))
|
||||
(if skip
|
||||
(assoc state "skip" false "i" (inc (get state "i")))
|
||||
(if (and (= (type-of arg) "keyword")
|
||||
(< (inc (get state "i")) (len args)))
|
||||
(let ((kname (keyword-name arg))
|
||||
(kval (trampoline (eval-expr (nth args (inc (get state "i"))) env))))
|
||||
(cond
|
||||
(= kname "id") (set! marsh-id kval)
|
||||
(= kname "tag") (set! marsh-tag kval)
|
||||
(= kname "transform") (set! marsh-transform kval))
|
||||
(assoc state "skip" true "i" (inc (get state "i"))))
|
||||
(do
|
||||
(append! children arg)
|
||||
(assoc state "i" (inc (get state "i"))))))))
|
||||
(dict "i" 0 "skip" false)
|
||||
args)
|
||||
(let ((el (dom-create-element marsh-tag nil)))
|
||||
(dom-set-attr el "data-sx-marsh" (or marsh-id ""))
|
||||
;; Store transform function and island env for morph retrieval
|
||||
(when marsh-transform
|
||||
(dom-set-data el "sx-marsh-transform" marsh-transform))
|
||||
(dom-set-data el "sx-marsh-env" env)
|
||||
(for-each
|
||||
(fn (c) (dom-append el (render-to-dom c env ns)))
|
||||
children)
|
||||
el))))
|
||||
|
||||
|
||||
;; --------------------------------------------------------------------------
|
||||
;; Reactive DOM rendering helpers
|
||||
;; --------------------------------------------------------------------------
|
||||
@@ -726,14 +786,17 @@
|
||||
(updated (if (empty? existing) attr-name (str existing "," attr-name))))
|
||||
(dom-set-attr el "data-sx-reactive-attrs" updated))
|
||||
(effect (fn ()
|
||||
(let ((val (compute-fn)))
|
||||
(cond
|
||||
(or (nil? val) (= val false))
|
||||
(dom-remove-attr el attr-name)
|
||||
(= val true)
|
||||
(dom-set-attr el attr-name "")
|
||||
:else
|
||||
(dom-set-attr el attr-name (str val))))))))
|
||||
(let ((raw (compute-fn)))
|
||||
;; If compute-fn returned a signal (e.g. from computed), deref it
|
||||
;; to get the actual value and track the dependency
|
||||
(let ((val (if (signal? raw) (deref raw) raw)))
|
||||
(cond
|
||||
(or (nil? val) (= val false))
|
||||
(dom-remove-attr el attr-name)
|
||||
(= val true)
|
||||
(dom-set-attr el attr-name "")
|
||||
:else
|
||||
(dom-set-attr el attr-name (str val)))))))))
|
||||
|
||||
;; reactive-fragment — conditionally render a fragment based on a signal
|
||||
;; Used for (when (deref sig) ...) or (if (deref sig) ...) inside an island.
|
||||
|
||||
Reference in New Issue
Block a user