Files
rose-ash/sx/sx/handlers/htmx-api.sx
giles 4f02f82f4e HS parser: fix number+comparison keyword collision, eval-hs uses hs-compile
Parser: skip unit suffix when next ident is a comparison keyword
(starts, ends, contains, matches, is, does, in, precedes, follows).
Fixes "123 starts with '12'" returning "123starts" instead of true.

eval-hs: use hs-compile directly instead of hs-to-sx-from-source with
"return " prefix, which was causing the parser to consume the comparison
as a string suffix.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 11:29:01 +00:00

139 lines
4.2 KiB
Plaintext

;; htmx demo API handlers — return HTML fragments for hx-* demos
;; Click to load
(defhandler
ex-click
:path "/sx/(applications.(htmx.(api.click)))"
:method :get
:returns "element"
(&key)
(div
(~tw :tokens "space-y-2")
(p (~tw :tokens "text-stone-800 font-medium") "Content loaded!")
(p
(~tw :tokens "text-stone-500 text-sm")
"Fetched from the server via hx-get")))
;; Active search
(defhandler
ex-search
:path "/sx/(applications.(htmx.(api.search)))"
:method :get
:returns "element"
(&key q)
(let
((query (or q "")))
(let
((items (list {:desc "GET request" :name "hx-get"} {:desc "POST request" :name "hx-post"} {:desc "Swap strategy" :name "hx-swap"} {:desc "Target element" :name "hx-target"} {:desc "Event trigger" :name "hx-trigger"} {:desc "Confirm dialog" :name "hx-confirm"} {:desc "Progressive enhancement" :name "hx-boost"} {:desc "CSS selector filter" :name "hx-select"})))
(let
((filtered (if (= query "") (list) (filter (fn (item) (contains? (downcase (get item :name)) (downcase query))) items))))
(if
(empty? filtered)
(p
(~tw :tokens "text-gray-400 italic py-2")
(str "No results for \"" query "\""))
(ul
(~tw :tokens "divide-y divide-gray-100")
(map
(fn
(item)
(li
(~tw :tokens "py-2 px-1")
(span
(~tw :tokens "font-medium text-gray-800")
(get item :name))
(span
(~tw :tokens "text-sm text-gray-500 ml-2")
(get item :desc))))
filtered)))))))
;; Tabs
(defhandler
ex-tab
:path "/sx/(applications.(htmx.(api.tab)))"
:method :get
:returns "element"
(&key tab)
(let
((tab (or tab "overview")))
(cond
(= tab "overview")
(div
(~tw :tokens "p-4 space-y-2")
(h3 (~tw :tokens "font-semibold text-stone-800") "Overview")
(p
(~tw :tokens "text-stone-600 text-sm")
"htmx gives you access to AJAX, CSS Transitions, WebSockets and Server Sent Events directly in HTML, using attributes."))
(= tab "features")
(div
(~tw :tokens "p-4 space-y-2")
(h3 (~tw :tokens "font-semibold text-stone-800") "Features")
(ul
(~tw
:tokens "list-disc list-inside text-sm text-stone-600 space-y-1")
(li "Any element, any event")
(li "Multiple swap strategies")
(li "CSS transition support")
(li "Out-of-band swaps")))
(= tab "code")
(div
(~tw :tokens "p-4")
(pre
(~tw :tokens "text-sm bg-stone-100 rounded p-3")
(code "(button :hx-get \"/api\" :hx-target \"#out\"\n \"Load\")")))
true
(div (~tw :tokens "p-4 text-stone-400") "Unknown tab"))))
;; Delete item — returns empty fragment to remove the element
(defhandler
ex-delete
:path "/sx/(applications.(htmx.(api.delete)))"
:method :delete
:csrf false
:returns "element"
(&key)
(<>))
;; Form submission
(defhandler
ex-form
:path "/sx/(applications.(htmx.(api.form)))"
:method :post
:csrf false
:returns "element"
(&key name email)
(div
(~tw :tokens "p-4 bg-green-50 border border-green-200 rounded-lg")
(p
(~tw :tokens "text-green-800 font-medium")
(str "Hello, " (or name "stranger") "!"))
(p
(~tw :tokens "text-sm text-green-600 mt-1")
(str "Email: " (or email "not provided")))))
;; Slow endpoint for indicator demo
(defhandler
ex-slow
:path "/sx/(applications.(htmx.(api.slow)))"
:method :get
:returns "element"
(&key)
(div
(~tw :tokens "p-4 bg-amber-50 border border-amber-200 rounded-lg")
(p (~tw :tokens "text-amber-800 font-medium") "Slow response received")
(p
(~tw :tokens "text-sm text-amber-600 mt-1")
"This response was delayed")))
;; Append item (beforeend swap demo)
(defhandler
ex-append
:path "/sx/(applications.(htmx.(api.append)))"
:method :post
:csrf false
:returns "element"
(&key)
(div
(~tw :tokens "p-2 border-b border-gray-100 text-sm text-stone-700")
"New item appended"))