OCaml evaluator for page dispatch + handler aser, 83/83 Playwright tests
Major architectural change: page function dispatch and handler execution
now go through the OCaml kernel instead of the Python bootstrapped evaluator.
OCaml integration:
- Page dispatch: bridge.eval() evaluates SX URL expressions (geography, marshes, etc.)
- Handler aser: bridge.aser() serializes handler responses as SX wire format
- _ensure_components loads all .sx files into OCaml kernel (spec, web adapter, handlers)
- defhandler/defpage registered as no-op special forms so handler files load
- helper IO primitive dispatches to Python page helpers + IO handlers
- ok-raw response format for SX wire format (no double-escaping)
- Natural list serialization in eval (no (list ...) wrapper)
- Clean pipe: _read_until_ok always sends io-response on error
SX adapter (aser):
- scope-emit!/scope-peek aliases to avoid CEK special form conflict
- aser-fragment/aser-call: strings starting with "(" pass through unserialized
- Registered cond-scheme?, is-else-clause?, primitive?, get-primitive in kernel
- random-int, parse-int as kernel primitives; json-encode, into via IO bridge
Handler migration:
- All IO calls converted to (helper "name" args...) pattern
- request-arg, request-form, state-get, state-set!, now, component-source etc.
- Fixed bare (effect ...) in island bodies leaking disposer functions as text
- Fixed lower-case → lower, ~search-results → ~examples/search-results
Reactive islands:
- sx-hydrate-islands called after client-side navigation swap
- force-dispose-islands-in for outerHTML swaps (clears hydration markers)
- clear-processed! platform primitive for re-hydration
Content restructuring:
- Design, event bridge, named stores, phase 2 consolidated into reactive overview
- Marshes split into overview + 5 example sub-pages
- Nav links use sx-get/sx-target for client-side navigation
Playwright test suite (sx/tests/test_demos.py):
- 83 tests covering hypermedia demos, reactive islands, marshes, spec explorer
- Server-side rendering, handler interactions, island hydration, navigation
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -59,11 +59,11 @@
|
||||
:method :get
|
||||
:returns "element"
|
||||
(&key)
|
||||
(let ((now (now "%Y-%m-%d %H:%M:%S")))
|
||||
(let ((now (helper "now" "%Y-%m-%d %H:%M:%S")))
|
||||
(<>
|
||||
(~examples/click-result :time now)
|
||||
(~docs/oob-code :target-id "click-comp"
|
||||
:text (component-source "~examples/click-result"))
|
||||
:text (helper "component-source" "~examples/click-result"))
|
||||
(~docs/oob-code :target-id "click-wire"
|
||||
:text (str "(~examples/click-result :time \"" now "\")")))))
|
||||
|
||||
@@ -78,11 +78,11 @@
|
||||
:csrf false
|
||||
:returns "element"
|
||||
(&key)
|
||||
(let ((name (request-form "name" "")))
|
||||
(let ((name (helper "request-form" "name" "")))
|
||||
(<>
|
||||
(~examples/form-result :name name)
|
||||
(~docs/oob-code :target-id "form-comp"
|
||||
:text (component-source "~examples/form-result"))
|
||||
:text (helper "component-source" "~examples/form-result"))
|
||||
(~docs/oob-code :target-id "form-wire"
|
||||
:text (str "(~examples/form-result :name \"" name "\")")))))
|
||||
|
||||
@@ -96,16 +96,17 @@
|
||||
:method :get
|
||||
:returns "element"
|
||||
(&key)
|
||||
(let ((n (+ (state-get "ex-poll-n" 0) 1)))
|
||||
(state-set! "ex-poll-n" n)
|
||||
(let ((now (now "%H:%M:%S"))
|
||||
(let ((prev (helper "state-get" "ex-poll-n" 0)))
|
||||
(let ((n (+ prev 1)))
|
||||
(helper "state-set!" "ex-poll-n" n)
|
||||
(let ((now (helper "now" "%H:%M:%S"))
|
||||
(count (if (< n 10) n 10)))
|
||||
(<>
|
||||
(~examples/poll-result :time now :count count)
|
||||
(~docs/oob-code :target-id "poll-comp"
|
||||
:text (component-source "~examples/poll-result"))
|
||||
:text (helper "component-source" "~examples/poll-result"))
|
||||
(~docs/oob-code :target-id "poll-wire"
|
||||
:text (str "(~examples/poll-result :time \"" now "\" :count " count ")"))))))
|
||||
:text (str "(~examples/poll-result :time \"" now "\" :count " count ")")))))))
|
||||
|
||||
|
||||
;; --------------------------------------------------------------------------
|
||||
@@ -120,7 +121,7 @@
|
||||
(&key item-id)
|
||||
(<>
|
||||
(~docs/oob-code :target-id "delete-comp"
|
||||
:text (component-source "~examples/delete-row"))
|
||||
:text (helper "component-source" "~examples/delete-row"))
|
||||
(~docs/oob-code :target-id "delete-wire"
|
||||
:text "(empty — row removed by outerHTML swap)")))
|
||||
|
||||
@@ -134,11 +135,11 @@
|
||||
:method :get
|
||||
:returns "element"
|
||||
(&key)
|
||||
(let ((value (request-arg "value" "")))
|
||||
(let ((value (helper "request-arg" "value" "")))
|
||||
(<>
|
||||
(~examples/inline-edit-form :value value)
|
||||
(~docs/oob-code :target-id "edit-comp"
|
||||
:text (component-source "~examples/inline-edit-form"))
|
||||
:text (helper "component-source" "~examples/inline-edit-form"))
|
||||
(~docs/oob-code :target-id "edit-wire"
|
||||
:text (str "(~examples/inline-edit-form :value \"" value "\")")))))
|
||||
|
||||
@@ -148,11 +149,11 @@
|
||||
:csrf false
|
||||
:returns "element"
|
||||
(&key)
|
||||
(let ((value (request-form "value" "")))
|
||||
(let ((value (helper "request-form" "value" "")))
|
||||
(<>
|
||||
(~examples/inline-view :value value)
|
||||
(~docs/oob-code :target-id "edit-comp"
|
||||
:text (component-source "~examples/inline-view"))
|
||||
:text (helper "component-source" "~examples/inline-view"))
|
||||
(~docs/oob-code :target-id "edit-wire"
|
||||
:text (str "(~examples/inline-view :value \"" value "\")")))))
|
||||
|
||||
@@ -161,11 +162,11 @@
|
||||
:method :get
|
||||
:returns "element"
|
||||
(&key)
|
||||
(let ((value (request-arg "value" "")))
|
||||
(let ((value (helper "request-arg" "value" "")))
|
||||
(<>
|
||||
(~examples/inline-view :value value)
|
||||
(~docs/oob-code :target-id "edit-comp"
|
||||
:text (component-source "~examples/inline-view"))
|
||||
:text (helper "component-source" "~examples/inline-view"))
|
||||
(~docs/oob-code :target-id "edit-wire"
|
||||
:text (str "(~examples/inline-view :value \"" value "\")")))))
|
||||
|
||||
@@ -179,7 +180,7 @@
|
||||
:method :get
|
||||
:returns "element"
|
||||
(&key)
|
||||
(let ((now (now "%H:%M:%S")))
|
||||
(let ((now (helper "now" "%H:%M:%S")))
|
||||
(<>
|
||||
(p :class "text-emerald-600 font-medium" "Box A updated!")
|
||||
(p :class "text-sm text-stone-500" (str "at " now))
|
||||
@@ -199,11 +200,11 @@
|
||||
:method :get
|
||||
:returns "element"
|
||||
(&key)
|
||||
(let ((now (now "%H:%M:%S")))
|
||||
(let ((now (helper "now" "%H:%M:%S")))
|
||||
(<>
|
||||
(~examples/lazy-result :time now)
|
||||
(~docs/oob-code :target-id "lazy-comp"
|
||||
:text (component-source "~examples/lazy-result"))
|
||||
:text (helper "component-source" "~examples/lazy-result"))
|
||||
(~docs/oob-code :target-id "lazy-wire"
|
||||
:text (str "(~examples/lazy-result :time \"" now "\")")))))
|
||||
|
||||
@@ -217,7 +218,7 @@
|
||||
:method :get
|
||||
:returns "element"
|
||||
(&key)
|
||||
(let ((page (request-arg "page" "2")))
|
||||
(let ((page (helper "request-arg" "page" "2")))
|
||||
(let ((pg (parse-int page))
|
||||
(start (+ (* (- (parse-int page) 1) 5) 1)))
|
||||
(<>
|
||||
@@ -249,30 +250,31 @@
|
||||
:csrf false
|
||||
:returns "element"
|
||||
(&key)
|
||||
(let ((n (+ (state-get "ex-job-counter" 0) 1)))
|
||||
(state-set! "ex-job-counter" n)
|
||||
(let ((prev-job (helper "state-get" "ex-job-counter" 0)))
|
||||
(let ((n (+ prev-job 1)))
|
||||
(helper "state-set!" "ex-job-counter" n)
|
||||
(let ((job-id (str "job-" n)))
|
||||
(state-set! (str "ex-job-" job-id) 0)
|
||||
(helper "state-set!" (str "ex-job-" job-id) 0)
|
||||
(<>
|
||||
(~examples/progress-status :percent 0 :job-id job-id)
|
||||
(~docs/oob-code :target-id "progress-comp"
|
||||
:text (component-source "~examples/progress-status"))
|
||||
:text (helper "component-source" "~examples/progress-status"))
|
||||
(~docs/oob-code :target-id "progress-wire"
|
||||
:text (str "(~examples/progress-status :percent 0 :job-id \"" job-id "\")"))))))
|
||||
:text (str "(~examples/progress-status :percent 0 :job-id \"" job-id "\")")))))))
|
||||
|
||||
(defhandler ex-progress-status
|
||||
:path "/sx/(geography.(hypermedia.(example.(api.progress-status))))"
|
||||
:method :get
|
||||
:returns "element"
|
||||
(&key)
|
||||
(let ((job-id (request-arg "job" "")))
|
||||
(let ((current (state-get (str "ex-job-" job-id) 0)))
|
||||
(let ((job-id (helper "request-arg" "job" "")))
|
||||
(let ((current (helper "state-get" (str "ex-job-" job-id) 0)))
|
||||
(let ((next (if (>= (+ current (random-int 15 30)) 100) 100 (+ current (random-int 15 30)))))
|
||||
(state-set! (str "ex-job-" job-id) next)
|
||||
(helper "state-set!" (str "ex-job-" job-id) next)
|
||||
(<>
|
||||
(~examples/progress-status :percent next :job-id job-id)
|
||||
(~docs/oob-code :target-id "progress-comp"
|
||||
:text (component-source "~examples/progress-status"))
|
||||
:text (helper "component-source" "~examples/progress-status"))
|
||||
(~docs/oob-code :target-id "progress-wire"
|
||||
:text (str "(~examples/progress-status :percent " next " :job-id \"" job-id "\")")))))))
|
||||
|
||||
@@ -286,17 +288,17 @@
|
||||
:method :get
|
||||
:returns "element"
|
||||
(&key)
|
||||
(let ((q (request-arg "q" "")))
|
||||
(let ((q (helper "request-arg" "q" "")))
|
||||
(let ((results (if (= q "")
|
||||
search-languages
|
||||
(filter (fn (lang) (contains? (lower-case lang) (lower-case q)))
|
||||
(filter (fn (lang) (contains? (lower lang) (lower q)))
|
||||
search-languages))))
|
||||
(<>
|
||||
(~search-results :items results :query q)
|
||||
(~examples/search-results :items results :query q)
|
||||
(~docs/oob-code :target-id "search-comp"
|
||||
:text (component-source "~search-results"))
|
||||
:text (helper "component-source" "~examples/search-results"))
|
||||
(~docs/oob-code :target-id "search-wire"
|
||||
:text (str "(~search-results :items (list ...) :query \"" q "\")"))))))
|
||||
:text (str "(~examples/search-results :items (list ...) :query \"" q "\")"))))))
|
||||
|
||||
|
||||
;; --------------------------------------------------------------------------
|
||||
@@ -308,27 +310,37 @@
|
||||
:method :get
|
||||
:returns "element"
|
||||
(&key)
|
||||
(let ((email (request-arg "email" "")))
|
||||
(let ((result
|
||||
(cond
|
||||
(= email "")
|
||||
(list "validation-error" "(~examples/validation-error :message \"Email is required\")"
|
||||
(~examples/validation-error :message "Email is required"))
|
||||
(not (contains? email "@"))
|
||||
(list "validation-error" "(~examples/validation-error :message \"Invalid email format\")"
|
||||
(~examples/validation-error :message "Invalid email format"))
|
||||
(some (fn (e) (= (lower-case e) (lower-case email))) taken-emails)
|
||||
(list "validation-error" (str "(~examples/validation-error :message \"" email " is already taken\")")
|
||||
(~examples/validation-error :message (str email " is already taken")))
|
||||
:else
|
||||
(list "validation-ok" (str "(~examples/validation-ok :email \"" email "\")")
|
||||
(~examples/validation-ok :email email)))))
|
||||
(<>
|
||||
(nth result 2)
|
||||
(~docs/oob-code :target-id "validate-comp"
|
||||
:text (component-source (first result)))
|
||||
(~docs/oob-code :target-id "validate-wire"
|
||||
:text (nth result 1))))))
|
||||
(let ((email (helper "request-arg" "email" "")))
|
||||
(cond
|
||||
(= email "")
|
||||
(<>
|
||||
(~examples/validation-error :message "Email is required")
|
||||
(~docs/oob-code :target-id "validate-comp"
|
||||
:text (helper "component-source" "~examples/validation-error"))
|
||||
(~docs/oob-code :target-id "validate-wire"
|
||||
:text "(~examples/validation-error :message \"Email is required\")"))
|
||||
(not (contains? email "@"))
|
||||
(<>
|
||||
(~examples/validation-error :message "Invalid email format")
|
||||
(~docs/oob-code :target-id "validate-comp"
|
||||
:text (helper "component-source" "~examples/validation-error"))
|
||||
(~docs/oob-code :target-id "validate-wire"
|
||||
:text "(~examples/validation-error :message \"Invalid email format\")"))
|
||||
(some (fn (e) (= (lower e) (lower email))) taken-emails)
|
||||
(<>
|
||||
(~examples/validation-error :message (str email " is already taken"))
|
||||
(~docs/oob-code :target-id "validate-comp"
|
||||
:text (helper "component-source" "~examples/validation-error"))
|
||||
(~docs/oob-code :target-id "validate-wire"
|
||||
:text (str "(~examples/validation-error :message \"" email " is already taken\")")))
|
||||
:else
|
||||
(<>
|
||||
(~examples/validation-ok :email email)
|
||||
(~docs/oob-code :target-id "validate-comp"
|
||||
:text (helper "component-source" "~examples/validation-ok"))
|
||||
(~docs/oob-code :target-id "validate-wire"
|
||||
:text (str "(~examples/validation-ok :email \"" email "\")"))))))
|
||||
|
||||
|
||||
(defhandler ex-validate-submit
|
||||
:path "/sx/(geography.(hypermedia.(example.(api.validate-submit))))"
|
||||
@@ -336,7 +348,7 @@
|
||||
:csrf false
|
||||
:returns "element"
|
||||
(&key)
|
||||
(let ((email (request-form "email" "")))
|
||||
(let ((email (helper "request-form" "email" "")))
|
||||
(if (or (= email "") (not (contains? email "@")))
|
||||
(p :class "text-sm text-rose-600 mt-2" "Please enter a valid email.")
|
||||
(p :class "text-sm text-emerald-600 mt-2" (str "Form submitted with: " email)))))
|
||||
@@ -351,15 +363,14 @@
|
||||
:method :get
|
||||
:returns "element"
|
||||
(&key)
|
||||
(let ((cat (request-arg "category" "")))
|
||||
(let ((cat (helper "request-arg" "category" "")))
|
||||
(let ((items (get value-select-data cat (list))))
|
||||
(let ((options (if (empty? items)
|
||||
(list (option :value "" "No items"))
|
||||
(map (fn (i) (option :value i i)) items))))
|
||||
(<>
|
||||
options
|
||||
(~docs/oob-code :target-id "values-wire"
|
||||
:text (str "(options for \"" cat "\")")))))))
|
||||
(<>
|
||||
(if (empty? items)
|
||||
(option :value "" "No items")
|
||||
(map (fn (i) (option :value i i)) items))
|
||||
(~docs/oob-code :target-id "values-wire"
|
||||
:text (str "(options for \"" cat "\")"))))))
|
||||
|
||||
|
||||
;; --------------------------------------------------------------------------
|
||||
@@ -372,12 +383,12 @@
|
||||
:csrf false
|
||||
:returns "element"
|
||||
(&key)
|
||||
(let ((msg (request-form "message" "(empty)"))
|
||||
(now (now "%H:%M:%S")))
|
||||
(let ((msg (helper "request-form" "message" "(empty)"))
|
||||
(now (helper "now" "%H:%M:%S")))
|
||||
(<>
|
||||
(~examples/reset-message :message msg :time now)
|
||||
(~docs/oob-code :target-id "reset-comp"
|
||||
:text (component-source "~examples/reset-message"))
|
||||
:text (helper "component-source" "~examples/reset-message"))
|
||||
(~docs/oob-code :target-id "reset-wire"
|
||||
:text (str "(~examples/reset-message :message \"" msg "\" :time \"" now "\")")))))
|
||||
|
||||
@@ -392,12 +403,12 @@
|
||||
:returns "element"
|
||||
(&key row-id)
|
||||
(let ((default (get edit-row-defaults row-id {"id" row-id "name" "" "price" "0" "stock" "0"})))
|
||||
(let ((row (state-get (str "ex-row-" row-id) default)))
|
||||
(let ((row (helper "state-get" (str "ex-row-" row-id) default)))
|
||||
(<>
|
||||
(~examples/edit-row-form :id (get row "id") :name (get row "name")
|
||||
:price (get row "price") :stock (get row "stock"))
|
||||
(~docs/oob-code :target-id "editrow-comp"
|
||||
:text (component-source "~examples/edit-row-form"))
|
||||
:text (helper "component-source" "~examples/edit-row-form"))
|
||||
(~docs/oob-code :target-id "editrow-wire"
|
||||
:text (str "(~examples/edit-row-form :id \"" (get row "id") "\" ...)"))))))
|
||||
|
||||
@@ -407,15 +418,15 @@
|
||||
:csrf false
|
||||
:returns "element"
|
||||
(&key row-id)
|
||||
(let ((name (request-form "name" ""))
|
||||
(price (request-form "price" "0"))
|
||||
(stock (request-form "stock" "0")))
|
||||
(state-set! (str "ex-row-" row-id)
|
||||
(let ((name (helper "request-form" "name" ""))
|
||||
(price (helper "request-form" "price" "0"))
|
||||
(stock (helper "request-form" "stock" "0")))
|
||||
(helper "state-set!" (str "ex-row-" row-id)
|
||||
{"id" row-id "name" name "price" price "stock" stock})
|
||||
(<>
|
||||
(~examples/edit-row-view :id row-id :name name :price price :stock stock)
|
||||
(~docs/oob-code :target-id "editrow-comp"
|
||||
:text (component-source "~examples/edit-row-view"))
|
||||
:text (helper "component-source" "~examples/edit-row-view"))
|
||||
(~docs/oob-code :target-id "editrow-wire"
|
||||
:text (str "(~examples/edit-row-view :id \"" row-id "\" ...)")))))
|
||||
|
||||
@@ -425,12 +436,12 @@
|
||||
:returns "element"
|
||||
(&key row-id)
|
||||
(let ((default (get edit-row-defaults row-id {"id" row-id "name" "" "price" "0" "stock" "0"})))
|
||||
(let ((row (state-get (str "ex-row-" row-id) default)))
|
||||
(let ((row (helper "state-get" (str "ex-row-" row-id) default)))
|
||||
(<>
|
||||
(~examples/edit-row-view :id (get row "id") :name (get row "name")
|
||||
:price (get row "price") :stock (get row "stock"))
|
||||
(~docs/oob-code :target-id "editrow-comp"
|
||||
:text (component-source "~examples/edit-row-view"))
|
||||
:text (helper "component-source" "~examples/edit-row-view"))
|
||||
(~docs/oob-code :target-id "editrow-wire"
|
||||
:text (str "(~examples/edit-row-view :id \"" (get row "id") "\" ...)"))))))
|
||||
|
||||
@@ -444,29 +455,29 @@
|
||||
:csrf false
|
||||
:returns "element"
|
||||
(&key)
|
||||
(let ((action (request-arg "action" "activate"))
|
||||
(ids (request-form-list "ids")))
|
||||
(let ((action (helper "request-arg" "action" "activate"))
|
||||
(ids (helper "request-form-list" "ids")))
|
||||
(let ((new-status (if (= action "activate") "active" "inactive")))
|
||||
;; Update matching users in state
|
||||
(for-each (fn (uid)
|
||||
(let ((default (get bulk-user-defaults uid nil)))
|
||||
(let ((user (state-get (str "ex-bulk-" uid) default)))
|
||||
(let ((user (helper "state-get" (str "ex-bulk-" uid) default)))
|
||||
(when user
|
||||
(state-set! (str "ex-bulk-" uid)
|
||||
(helper "state-set!" (str "ex-bulk-" uid)
|
||||
(assoc user "status" new-status))))))
|
||||
ids)
|
||||
;; Return all rows
|
||||
(let ((rows (map (fn (uid)
|
||||
(let ((default (get bulk-user-defaults uid
|
||||
{"id" uid "name" "" "email" "" "status" "active"})))
|
||||
(let ((u (state-get (str "ex-bulk-" uid) default)))
|
||||
(let ((u (helper "state-get" (str "ex-bulk-" uid) default)))
|
||||
(~examples/bulk-row :id (get u "id") :name (get u "name")
|
||||
:email (get u "email") :status (get u "status")))))
|
||||
(list "1" "2" "3" "4" "5"))))
|
||||
(<>
|
||||
rows
|
||||
(~docs/oob-code :target-id "bulk-comp"
|
||||
:text (component-source "~examples/bulk-row"))
|
||||
:text (helper "component-source" "~examples/bulk-row"))
|
||||
(~docs/oob-code :target-id "bulk-wire"
|
||||
:text (str "(updated " (len ids) " users to " new-status ")")))))))
|
||||
|
||||
@@ -481,10 +492,11 @@
|
||||
:csrf false
|
||||
:returns "element"
|
||||
(&key)
|
||||
(let ((mode (request-arg "mode" "beforeend"))
|
||||
(n (+ (state-get "ex-swap-n" 0) 1))
|
||||
(now (now "%H:%M:%S")))
|
||||
(state-set! "ex-swap-n" n)
|
||||
(let ((mode (helper "request-arg" "mode" "beforeend"))
|
||||
(prev-swap (helper "state-get" "ex-swap-n" 0))
|
||||
(now (helper "now" "%H:%M:%S")))
|
||||
(let ((n (+ prev-swap 1)))
|
||||
(helper "state-set!" "ex-swap-n" n)
|
||||
(<>
|
||||
(div :class "px-3 py-2 text-sm text-stone-700"
|
||||
(str "[" now "] " mode " (#" n ")"))
|
||||
@@ -492,7 +504,7 @@
|
||||
:class "self-center text-sm text-stone-500"
|
||||
(str "Count: " n))
|
||||
(~docs/oob-code :target-id "swap-wire"
|
||||
:text (str "(entry + oob counter: " n ")")))))
|
||||
:text (str "(entry + oob counter: " n ")"))))))
|
||||
|
||||
|
||||
;; --------------------------------------------------------------------------
|
||||
@@ -504,7 +516,7 @@
|
||||
:method :get
|
||||
:returns "element"
|
||||
(&key)
|
||||
(let ((now (now "%H:%M:%S")))
|
||||
(let ((now (helper "now" "%H:%M:%S")))
|
||||
(<>
|
||||
(div :id "dash-header" :class "p-3 bg-violet-50 rounded mb-3"
|
||||
(h4 :class "font-semibold text-violet-800" "Dashboard Header")
|
||||
@@ -556,12 +568,12 @@
|
||||
:returns "element"
|
||||
(&key)
|
||||
(let ((idx (random-int 0 4))
|
||||
(now (now "%H:%M:%S")))
|
||||
(now (helper "now" "%H:%M:%S")))
|
||||
(let ((color (nth anim-colors idx)))
|
||||
(<>
|
||||
(~anim-result :color color :time now)
|
||||
(~docs/oob-code :target-id "anim-comp"
|
||||
:text (component-source "~anim-result"))
|
||||
:text (helper "component-source" "~anim-result"))
|
||||
(~docs/oob-code :target-id "anim-wire"
|
||||
:text (str "(~anim-result :color \"" color "\" :time \"" now "\")"))))))
|
||||
|
||||
@@ -579,7 +591,7 @@
|
||||
(~examples/dialog-modal :title "Confirm Action"
|
||||
:message "Are you sure you want to proceed? This is a demo dialog rendered entirely with sx components.")
|
||||
(~docs/oob-code :target-id "dialog-comp"
|
||||
:text (component-source "~examples/dialog-modal"))
|
||||
:text (helper "component-source" "~examples/dialog-modal"))
|
||||
(~docs/oob-code :target-id "dialog-wire"
|
||||
:text "(~examples/dialog-modal :title \"Confirm Action\" :message \"...\")")))
|
||||
|
||||
@@ -602,12 +614,12 @@
|
||||
:method :get
|
||||
:returns "element"
|
||||
(&key)
|
||||
(let ((key (request-arg "key" "")))
|
||||
(let ((key (helper "request-arg" "key" "")))
|
||||
(let ((action (get kbd-actions key (str "Unknown key: " key))))
|
||||
(<>
|
||||
(~examples/kbd-result :key key :action action)
|
||||
(~docs/oob-code :target-id "kbd-comp"
|
||||
:text (component-source "~examples/kbd-result"))
|
||||
:text (helper "component-source" "~examples/kbd-result"))
|
||||
(~docs/oob-code :target-id "kbd-wire"
|
||||
:text (str "(~examples/kbd-result :key \"" key "\" :action \"" action "\")"))))))
|
||||
|
||||
@@ -621,12 +633,12 @@
|
||||
:method :get
|
||||
:returns "element"
|
||||
(&key)
|
||||
(let ((p (state-get "ex-profile"
|
||||
(let ((p (helper "state-get" "ex-profile"
|
||||
{"name" "Ada Lovelace" "email" "ada@example.com" "role" "Engineer"})))
|
||||
(<>
|
||||
(~examples/pp-form-full :name (get p "name") :email (get p "email") :role (get p "role"))
|
||||
(~docs/oob-code :target-id "pp-comp"
|
||||
:text (component-source "~examples/pp-form-full"))
|
||||
:text (helper "component-source" "~examples/pp-form-full"))
|
||||
(~docs/oob-code :target-id "pp-wire"
|
||||
:text (str "(~examples/pp-form-full :name \"" (get p "name") "\" ...)")))))
|
||||
|
||||
@@ -636,14 +648,14 @@
|
||||
:csrf false
|
||||
:returns "element"
|
||||
(&key)
|
||||
(let ((name (request-form "name" ""))
|
||||
(email (request-form "email" ""))
|
||||
(role (request-form "role" "")))
|
||||
(state-set! "ex-profile" {"name" name "email" email "role" role})
|
||||
(let ((name (helper "request-form" "name" ""))
|
||||
(email (helper "request-form" "email" ""))
|
||||
(role (helper "request-form" "role" "")))
|
||||
(helper "state-set!" "ex-profile" {"name" name "email" email "role" role})
|
||||
(<>
|
||||
(~examples/pp-view :name name :email email :role role)
|
||||
(~docs/oob-code :target-id "pp-comp"
|
||||
:text (component-source "~examples/pp-view"))
|
||||
:text (helper "component-source" "~examples/pp-view"))
|
||||
(~docs/oob-code :target-id "pp-wire"
|
||||
:text (str "(~examples/pp-view :name \"" name "\" ...)")))))
|
||||
|
||||
@@ -652,12 +664,12 @@
|
||||
:method :get
|
||||
:returns "element"
|
||||
(&key)
|
||||
(let ((p (state-get "ex-profile"
|
||||
(let ((p (helper "state-get" "ex-profile"
|
||||
{"name" "Ada Lovelace" "email" "ada@example.com" "role" "Engineer"})))
|
||||
(<>
|
||||
(~examples/pp-view :name (get p "name") :email (get p "email") :role (get p "role"))
|
||||
(~docs/oob-code :target-id "pp-comp"
|
||||
:text (component-source "~examples/pp-view"))
|
||||
:text (helper "component-source" "~examples/pp-view"))
|
||||
(~docs/oob-code :target-id "pp-wire"
|
||||
:text (str "(~examples/pp-view :name \"" (get p "name") "\" ...)")))))
|
||||
|
||||
@@ -672,13 +684,13 @@
|
||||
:csrf false
|
||||
:returns "element"
|
||||
(&key)
|
||||
(let ((data (request-json))
|
||||
(ct (request-content-type)))
|
||||
(let ((data (helper "request-json"))
|
||||
(ct (helper "request-content-type")))
|
||||
(let ((body (json-encode data)))
|
||||
(<>
|
||||
(~examples/json-result :body body :content-type ct)
|
||||
(~docs/oob-code :target-id "json-comp"
|
||||
:text (component-source "~examples/json-result"))
|
||||
:text (helper "component-source" "~examples/json-result"))
|
||||
(~docs/oob-code :target-id "json-wire"
|
||||
:text (str "(~examples/json-result :body \"" body "\" :content-type \"" ct "\")"))))))
|
||||
|
||||
@@ -692,7 +704,7 @@
|
||||
:method :get
|
||||
:returns "element"
|
||||
(&key)
|
||||
(let ((vals (into (list) (request-args-all))))
|
||||
(let ((vals (helper "into" (list) (helper "request-args-all"))))
|
||||
(let ((filtered (filter (fn (pair) (and (not (= (first pair) "_"))
|
||||
(not (= (first pair) "sx-request"))))
|
||||
vals)))
|
||||
@@ -700,7 +712,7 @@
|
||||
(<>
|
||||
(~examples/echo-result :label "values" :items items)
|
||||
(~docs/oob-code :target-id "vals-comp"
|
||||
:text (component-source "~examples/echo-result"))
|
||||
:text (helper "component-source" "~examples/echo-result"))
|
||||
(~docs/oob-code :target-id "vals-wire"
|
||||
:text (str "(~examples/echo-result :label \"values\" :items (list ...))")))))))
|
||||
|
||||
@@ -709,13 +721,13 @@
|
||||
:method :get
|
||||
:returns "element"
|
||||
(&key)
|
||||
(let ((all-headers (into (list) (request-headers-all))))
|
||||
(let ((all-headers (helper "into" (list) (helper "request-headers-all"))))
|
||||
(let ((custom (filter (fn (pair) (starts-with? (first pair) "x-")) all-headers)))
|
||||
(let ((items (map (fn (pair) (str (first pair) ": " (nth pair 1))) custom)))
|
||||
(<>
|
||||
(~examples/echo-result :label "headers" :items items)
|
||||
(~docs/oob-code :target-id "vals-comp"
|
||||
:text (component-source "~examples/echo-result"))
|
||||
:text (helper "component-source" "~examples/echo-result"))
|
||||
(~docs/oob-code :target-id "vals-wire"
|
||||
:text (str "(~examples/echo-result :label \"headers\" :items (list ...))")))))))
|
||||
|
||||
@@ -730,11 +742,11 @@
|
||||
:returns "element"
|
||||
(&key)
|
||||
(sleep 2000)
|
||||
(let ((now (now "%H:%M:%S")))
|
||||
(let ((now (helper "now" "%H:%M:%S")))
|
||||
(<>
|
||||
(~examples/loading-result :time now)
|
||||
(~docs/oob-code :target-id "loading-comp"
|
||||
:text (component-source "~examples/loading-result"))
|
||||
:text (helper "component-source" "~examples/loading-result"))
|
||||
(~docs/oob-code :target-id "loading-wire"
|
||||
:text (str "(~examples/loading-result :time \"" now "\")")))))
|
||||
|
||||
@@ -750,11 +762,11 @@
|
||||
(&key)
|
||||
(let ((delay-ms (random-int 500 2000)))
|
||||
(sleep delay-ms)
|
||||
(let ((q (request-arg "q" "")))
|
||||
(let ((q (helper "request-arg" "q" "")))
|
||||
(<>
|
||||
(~examples/sync-result :query q :delay (str delay-ms))
|
||||
(~docs/oob-code :target-id "sync-comp"
|
||||
:text (component-source "~examples/sync-result"))
|
||||
:text (helper "component-source" "~examples/sync-result"))
|
||||
(~docs/oob-code :target-id "sync-wire"
|
||||
:text (str "(~examples/sync-result :query \"" q "\" :delay \"" delay-ms "\")"))))))
|
||||
|
||||
@@ -768,8 +780,9 @@
|
||||
:method :get
|
||||
:returns "element"
|
||||
(&key)
|
||||
(let ((n (+ (state-get "ex-flaky-n" 0) 1)))
|
||||
(state-set! "ex-flaky-n" n)
|
||||
(let ((prev-flaky (helper "state-get" "ex-flaky-n" 0)))
|
||||
(let ((n (+ prev-flaky 1)))
|
||||
(helper "state-set!" "ex-flaky-n" n)
|
||||
(if (not (= (mod n 3) 0))
|
||||
(do
|
||||
(set-response-status 503)
|
||||
@@ -777,6 +790,6 @@
|
||||
(<>
|
||||
(~examples/retry-result :attempt (str n) :message "Success! The endpoint finally responded.")
|
||||
(~docs/oob-code :target-id "retry-comp"
|
||||
:text (component-source "~examples/retry-result"))
|
||||
:text (helper "component-source" "~examples/retry-result"))
|
||||
(~docs/oob-code :target-id "retry-wire"
|
||||
:text (str "(~examples/retry-result :attempt \"" n "\" ...)"))))))
|
||||
:text (str "(~examples/retry-result :attempt \"" n "\" ...)")))))))
|
||||
Reference in New Issue
Block a user