(defcomp ~examples/card (&key title description &rest children) (div (~tw :tokens "border border-stone-200 rounded-lg overflow-hidden") (div (~tw :tokens "bg-stone-100 px-4 py-3 border-b border-stone-200") (h3 (~tw :tokens "font-semibold text-stone-800") title) (when description (p (~tw :tokens "text-sm text-stone-500 mt-1") description))) (div (~tw :tokens "p-4") children))) (defcomp ~examples/demo (&key &rest children) (div (~tw :tokens "border border-dashed border-stone-300 rounded p-4 bg-stone-100") children)) (defcomp ~examples/source (&key src-code) (div (~tw :tokens "not-prose bg-stone-100 rounded p-5 mt-3 mx-auto max-w-3xl") (pre (~tw :tokens "text-sm leading-relaxed whitespace-pre-wrap break-words") (code src-code)))) (defcomp ~examples/click-to-load-demo () (div (~tw :tokens "space-y-4") (div :id "click-result" (~tw :tokens "p-4 rounded bg-stone-100 text-stone-500 text-center") "Click the button to load content.") (button :sx-get "/sx/(geography.(hypermedia.(example.(api.click))))" :sx-target "#click-result" :sx-swap "innerHTML" (~tw :tokens "px-4 py-2 bg-violet-600 text-white rounded hover:bg-violet-700 transition-colors") "Load content"))) (defcomp ~examples/click-result (&key time) (div (~tw :tokens "space-y-2") (p (~tw :tokens "text-stone-800 font-medium") "Content loaded!") (p (~tw :tokens "text-stone-500 text-sm") (str "Fetched from the server via sx-get at " time)))) (defcomp ~examples/form-demo () (div (~tw :tokens "space-y-4") (form :sx-post "/sx/(geography.(hypermedia.(example.(api.form))))" :sx-target "#form-result" :sx-swap "innerHTML" (~tw :tokens "space-y-3") (div (label (~tw :tokens "block text-sm font-medium text-stone-700 mb-1") "Name") (input :type "text" :name "name" :placeholder "Enter a name" (~tw :tokens "w-full px-3 py-2 border border-stone-300 rounded text-sm focus:outline-none focus:ring-2 focus:ring-violet-500"))) (button :type "submit" (~tw :tokens "px-4 py-2 bg-violet-600 text-white rounded hover:bg-violet-700 transition-colors text-sm") "Submit")) (div :id "form-result" (~tw :tokens "p-3 rounded bg-stone-100 text-stone-500 text-sm text-center") "Submit the form to see the result."))) (defcomp ~examples/form-result (&key name) (div (~tw :tokens "text-stone-800") (p (str "Hello, " (if (empty? name) "stranger" name) "!")) (p (~tw :tokens "text-sm text-stone-500 mt-1") "Submitted via sx-post. The form data was sent as a POST request."))) (defcomp ~examples/polling-demo () (div (~tw :tokens "space-y-4") (div :id "poll-target" :sx-get "/sx/(geography.(hypermedia.(example.(api.poll))))" :sx-trigger "load, every 2s" :sx-swap "innerHTML" (~tw :tokens "p-4 rounded border border-stone-200 bg-stone-100 text-center font-mono") "Loading..."))) (defcomp ~examples/poll-result (&key time count) (div (p (~tw :tokens "text-stone-800 font-medium") (str "Server time: " time)) (p (~tw :tokens "text-stone-500 text-sm mt-1") (str "Poll count: " count)) (div (~tw :tokens "mt-2 flex justify-center") (div (~tw :tokens "flex gap-1") (map (fn (i) (div :class (str "w-2 h-2 rounded-full " (if (<= i count) "bg-violet-500" "bg-stone-200")))) (list 1 2 3 4 5 6 7 8 9 10)))))) (defcomp ~examples/delete-demo (&key items) (div (table (~tw :tokens "w-full text-left text-sm") (thead (tr (~tw :tokens "border-b border-stone-200") (th (~tw :tokens "px-3 py-2 font-medium text-stone-600") "Item") (th (~tw :tokens "px-3 py-2 font-medium text-stone-600 w-20") ""))) (tbody :id "delete-rows" (map (fn (item) (~examples/delete-row :id (nth item 0) :name (nth item 1))) items))))) (defcomp ~examples/delete-row (&key id name) (tr :id (str "row-" id) (~tw :tokens "border-b border-stone-100 transition-all") (td (~tw :tokens "px-3 py-2 text-stone-700") name) (td (~tw :tokens "px-3 py-2") (button :sx-delete (str "/sx/(geography.(hypermedia.(example.(api.(delete." id ")))))") :sx-target (str "#row-" id) :sx-swap "outerHTML" :sx-confirm "Delete this item?" (~tw :tokens "text-rose-500 hover:text-rose-700 text-sm") "delete")))) (defcomp ~examples/inline-edit-demo () (div :id "edit-target" (~tw :tokens "space-y-3") (~examples/inline-view :value "Click edit to change this text"))) (defcomp ~examples/inline-view (&key value) (div (~tw :tokens "flex items-center justify-between p-3 rounded border border-stone-200") (span (~tw :tokens "text-stone-800") value) (button :sx-get (str "/sx/(geography.(hypermedia.(example.(api.edit))))?value=" value) :sx-target "#edit-target" :sx-swap "innerHTML" (~tw :tokens "text-sm text-violet-600 hover:text-violet-800") "edit"))) (defcomp ~examples/inline-edit-form (&key value) (form :sx-post "/sx/(geography.(hypermedia.(example.(api.edit))))" :sx-target "#edit-target" :sx-swap "innerHTML" (~tw :tokens "flex items-center gap-2 p-3 rounded border border-violet-300 bg-violet-50") (input :type "text" :name "value" :value value (~tw :tokens "flex-1 px-3 py-1.5 border border-stone-300 rounded text-sm focus:outline-none focus:ring-2 focus:ring-violet-500")) (button :type "submit" (~tw :tokens "px-3 py-1.5 bg-violet-600 text-white rounded text-sm hover:bg-violet-700") "save") (button :type "button" :sx-get (str "/sx/(geography.(hypermedia.(example.(api.edit-cancel))))?value=" value) :sx-target "#edit-target" :sx-swap "innerHTML" (~tw :tokens "px-3 py-1.5 bg-stone-200 text-stone-700 rounded text-sm hover:bg-stone-300") "cancel"))) (defcomp ~examples/oob-demo () (div (~tw :tokens "space-y-4") (div (~tw :tokens "grid grid-cols-2 gap-4") (div :id "oob-box-a" (~tw :tokens "p-4 rounded border border-stone-200 bg-stone-100 text-center") (p (~tw :tokens "text-stone-500") "Box A") (p (~tw :tokens "text-sm text-stone-400") "Waiting...")) (div :id "oob-box-b" (~tw :tokens "p-4 rounded border border-stone-200 bg-stone-100 text-center") (p (~tw :tokens "text-stone-500") "Box B") (p (~tw :tokens "text-sm text-stone-400") "Waiting..."))) (button :sx-get "/sx/(geography.(hypermedia.(example.(api.oob))))" :sx-target "#oob-box-a" :sx-swap "innerHTML" (~tw :tokens "px-4 py-2 bg-violet-600 text-white rounded hover:bg-violet-700 transition-colors text-sm") "Update both boxes"))) (defcomp ~examples/lazy-loading-demo () (div (~tw :tokens "space-y-4") (p (~tw :tokens "text-sm text-stone-500") "The content below loads automatically when the page renders.") (div :id "lazy-target" :sx-get "/sx/(geography.(hypermedia.(example.(api.lazy))))" :sx-trigger "load" :sx-swap "innerHTML" (~tw :tokens "p-6 rounded border border-stone-200 bg-stone-100 text-center") (div (~tw :tokens "animate-pulse space-y-2") (div (~tw :tokens "h-4 bg-stone-200 rounded w-3/4 mx-auto")) (div (~tw :tokens "h-4 bg-stone-200 rounded w-1/2 mx-auto")))))) (defcomp ~examples/lazy-result (&key time) (div (~tw :tokens "space-y-2") (p (~tw :tokens "text-stone-800 font-medium") "Content loaded on page render!") (p (~tw :tokens "text-stone-500 text-sm") (str "Loaded via sx-trigger=\"load\" at " time)))) (defcomp ~examples/infinite-scroll-demo () (div (~tw :tokens "h-64 overflow-y-auto border border-stone-200 rounded") :id "scroll-container" (div :id "scroll-items" (map-indexed (fn (i item) (div (~tw :tokens "px-4 py-3 border-b border-stone-100 text-sm text-stone-700") (str "Item " (+ i 1) " — loaded with the page"))) (list 1 2 3 4 5)) (div :id "scroll-sentinel" :sx-get "/sx/(geography.(hypermedia.(example.(api.scroll))))?page=2" :sx-trigger "intersect once" :sx-target "#scroll-items" :sx-swap "beforeend" (~tw :tokens "p-3 text-center text-stone-400 text-sm") "Loading more...")))) (defcomp ~examples/scroll-items (&key items page) (<> (map (fn (item) (div (~tw :tokens "px-4 py-3 border-b border-stone-100 text-sm text-stone-700") item)) items) (when (<= page 5) (div :id "scroll-sentinel" :sx-get (str "/sx/(geography.(hypermedia.(example.(api.scroll))))?page=" page) :sx-trigger "intersect once" :sx-target "#scroll-items" :sx-swap "beforeend" (~tw :tokens "p-3 text-center text-stone-400 text-sm") "Loading more...")))) (defcomp ~examples/progress-bar-demo () (div (~tw :tokens "space-y-4") (div :id "progress-target" (~tw :tokens "space-y-3") (div (~tw :tokens "w-full bg-stone-200 rounded-full h-4") (div (~tw :tokens "bg-violet-600 h-4 rounded-full transition-all") :style "width: 0%")) (p (~tw :tokens "text-sm text-stone-500 text-center") "Click start to begin.")) (button :sx-post "/sx/(geography.(hypermedia.(example.(api.progress-start))))" :sx-target "#progress-target" :sx-swap "innerHTML" (~tw :tokens "px-4 py-2 bg-violet-600 text-white rounded hover:bg-violet-700 transition-colors text-sm") "Start job"))) (defcomp ~examples/progress-status (&key percent job-id) (div (~tw :tokens "space-y-3") (div (~tw :tokens "w-full bg-stone-200 rounded-full h-4") (div (~tw :tokens "bg-violet-600 h-4 rounded-full transition-all") :style (str "width: " percent "%"))) (p (~tw :tokens "text-sm text-stone-500 text-center") (str percent "% complete")) (when (< percent 100) (div :sx-get (str "/sx/(geography.(hypermedia.(example.(api.progress-status))))?job=" job-id) :sx-trigger "load delay:500ms" :sx-target "#progress-target" :sx-swap "innerHTML")) (when (= percent 100) (p (~tw :tokens "text-sm text-emerald-600 font-medium text-center") "Job complete!")))) (defcomp ~examples/active-search-demo () (div (~tw :tokens "space-y-3") (input :type "text" :name "q" :sx-get "/sx/(geography.(hypermedia.(example.(api.search))))" :sx-trigger "keyup delay:300ms changed" :sx-target "#search-results" :sx-swap "innerHTML" :placeholder "Search programming languages..." (~tw :tokens "w-full px-3 py-2 border border-stone-300 rounded text-sm focus:outline-none focus:ring-2 focus:ring-violet-500")) (div :id "search-results" (~tw :tokens "border border-stone-200 rounded divide-y divide-stone-100") (p (~tw :tokens "p-3 text-sm text-stone-400") "Type to search...")))) (defcomp ~examples/search-results (&key items query) (<> (if (empty? items) (p (~tw :tokens "p-3 text-sm text-stone-400") (str "No results for \"" query "\"")) (map (fn (item) (div (~tw :tokens "px-3 py-2 text-sm text-stone-700") item)) items)))) (defcomp ~examples/inline-validation-demo () (form (~tw :tokens "space-y-4") :sx-post "/sx/(geography.(hypermedia.(example.(api.validate-submit))))" :sx-target "#validation-result" :sx-swap "innerHTML" (div (label (~tw :tokens "block text-sm font-medium text-stone-700 mb-1") "Email") (input :type "text" :name "email" :placeholder "user@example.com" :sx-get "/sx/(geography.(hypermedia.(example.(api.validate))))" :sx-trigger "blur" :sx-target "#email-feedback" :sx-swap "innerHTML" (~tw :tokens "w-full px-3 py-2 border border-stone-300 rounded text-sm focus:outline-none focus:ring-2 focus:ring-violet-500")) (div :id "email-feedback" (~tw :tokens "mt-1"))) (button :type "submit" (~tw :tokens "px-4 py-2 bg-violet-600 text-white rounded hover:bg-violet-700 transition-colors text-sm") "Submit") (div :id "validation-result"))) (defcomp ~examples/validation-ok (&key email) (p (~tw :tokens "text-sm text-emerald-600") (str email " is available"))) (defcomp ~examples/validation-error (&key message) (p (~tw :tokens "text-sm text-rose-600") message)) (defcomp ~examples/value-select-demo () (div (~tw :tokens "space-y-3") (div (label (~tw :tokens "block text-sm font-medium text-stone-700 mb-1") "Category") (select :name "category" :sx-get "/sx/(geography.(hypermedia.(example.(api.values))))" :sx-trigger "change" :sx-target "#value-items" :sx-swap "innerHTML" (~tw :tokens "w-full px-3 py-2 border border-stone-300 rounded text-sm focus:outline-none focus:ring-2 focus:ring-violet-500") (option :value "" "Pick a category...") (option :value "Languages" "Languages") (option :value "Frameworks" "Frameworks") (option :value "Databases" "Databases"))) (div (label (~tw :tokens "block text-sm font-medium text-stone-700 mb-1") "Item") (select :id "value-items" (~tw :tokens "w-full px-3 py-2 border border-stone-300 rounded text-sm focus:outline-none focus:ring-2 focus:ring-violet-500") (option :value "" "Select a category first..."))))) (defcomp ~examples/value-options (&key items) (<> (map (fn (item) (option :value item item)) items))) (defcomp ~examples/reset-on-submit-demo () (div (~tw :tokens "space-y-3") (form :id "reset-form" :sx-post "/sx/(geography.(hypermedia.(example.(api.reset-submit))))" :sx-target "#reset-result" :sx-swap "innerHTML" :sx-on:afterSwap "this.reset()" (~tw :tokens "flex gap-2") (input :type "text" :name "message" :placeholder "Type a message..." (~tw :tokens "flex-1 px-3 py-2 border border-stone-300 rounded text-sm focus:outline-none focus:ring-2 focus:ring-violet-500")) (button :type "submit" (~tw :tokens "px-4 py-2 bg-violet-600 text-white rounded hover:bg-violet-700 transition-colors text-sm") "Send")) (div :id "reset-result" (~tw :tokens "space-y-2") (p (~tw :tokens "text-sm text-stone-400") "Messages will appear here.")))) (defcomp ~examples/reset-message (&key message time) (div (~tw :tokens "px-3 py-2 bg-stone-100 rounded text-sm text-stone-700") (str "[" time "] " message))) (defcomp ~examples/edit-row-demo (&key rows) (div (table (~tw :tokens "w-full text-left text-sm") (thead (tr (~tw :tokens "border-b border-stone-200") (th (~tw :tokens "px-3 py-2 font-medium text-stone-600") "Name") (th (~tw :tokens "px-3 py-2 font-medium text-stone-600") "Price") (th (~tw :tokens "px-3 py-2 font-medium text-stone-600") "Stock") (th (~tw :tokens "px-3 py-2 font-medium text-stone-600 w-24") ""))) (tbody :id "edit-rows" (map (fn (row) (~examples/edit-row-view :id (nth row 0) :name (nth row 1) :price (nth row 2) :stock (nth row 3))) rows))))) (defcomp ~examples/edit-row-view (&key id name price stock) (tr :id (str "erow-" id) (~tw :tokens "border-b border-stone-100") (td (~tw :tokens "px-3 py-2 text-stone-700") name) (td (~tw :tokens "px-3 py-2 text-stone-700") (str "$" price)) (td (~tw :tokens "px-3 py-2 text-stone-700") stock) (td (~tw :tokens "px-3 py-2") (button :sx-get (str "/sx/(geography.(hypermedia.(example.(api.(editrow." id ")))))") :sx-target (str "#erow-" id) :sx-swap "outerHTML" (~tw :tokens "text-sm text-violet-600 hover:text-violet-800") "edit")))) (defcomp ~examples/edit-row-form (&key id name price stock) (tr :id (str "erow-" id) (~tw :tokens "border-b border-stone-100 bg-violet-50") (td (~tw :tokens "px-3 py-2") (input :type "text" :name "name" :value name (~tw :tokens "w-full px-2 py-1 border border-stone-300 rounded text-sm"))) (td (~tw :tokens "px-3 py-2") (input :type "text" :name "price" :value price (~tw :tokens "w-20 px-2 py-1 border border-stone-300 rounded text-sm"))) (td (~tw :tokens "px-3 py-2") (input :type "text" :name "stock" :value stock (~tw :tokens "w-20 px-2 py-1 border border-stone-300 rounded text-sm"))) (td (~tw :tokens "px-3 py-2 space-x-1") (button :sx-post (str "/sx/(geography.(hypermedia.(example.(api.(editrow." id ")))))") :sx-target (str "#erow-" id) :sx-swap "outerHTML" :sx-include (str "#erow-" id) (~tw :tokens "text-sm text-emerald-600 hover:text-emerald-800") "save") (button :sx-get (str "/sx/(geography.(hypermedia.(example.(api.(editrow-cancel." id ")))))") :sx-target (str "#erow-" id) :sx-swap "outerHTML" (~tw :tokens "text-sm text-stone-500 hover:text-stone-700") "cancel")))) (defcomp ~examples/bulk-update-demo (&key users) (div (~tw :tokens "space-y-3") (form :id "bulk-form" (div (~tw :tokens "flex gap-2 mb-3") (button :type "button" :sx-post "/sx/(geography.(hypermedia.(example.(api.bulk))))?action=activate" :sx-target "#bulk-table" :sx-swap "innerHTML" :sx-include "#bulk-form" (~tw :tokens "px-3 py-1.5 bg-emerald-600 text-white rounded text-sm hover:bg-emerald-700") "Activate") (button :type "button" :sx-post "/sx/(geography.(hypermedia.(example.(api.bulk))))?action=deactivate" :sx-target "#bulk-table" :sx-swap "innerHTML" :sx-include "#bulk-form" (~tw :tokens "px-3 py-1.5 bg-stone-600 text-white rounded text-sm hover:bg-stone-700") "Deactivate")) (table (~tw :tokens "w-full text-left text-sm") (thead (tr (~tw :tokens "border-b border-stone-200") (th (~tw :tokens "px-3 py-2 w-8") "") (th (~tw :tokens "px-3 py-2 font-medium text-stone-600") "Name") (th (~tw :tokens "px-3 py-2 font-medium text-stone-600") "Email") (th (~tw :tokens "px-3 py-2 font-medium text-stone-600") "Status"))) (tbody :id "bulk-table" (map (fn (u) (~examples/bulk-row :id (nth u 0) :name (nth u 1) :email (nth u 2) :status (nth u 3))) users)))))) (defcomp ~examples/bulk-row (&key id name email status) (tr (~tw :tokens "border-b border-stone-100") (td (~tw :tokens "px-3 py-2") (input :type "checkbox" :name "ids" :value id)) (td (~tw :tokens "px-3 py-2 text-stone-700") name) (td (~tw :tokens "px-3 py-2 text-stone-700") email) (td (~tw :tokens "px-3 py-2") (span :class (str "px-2 py-0.5 rounded text-xs font-medium " (if (= status "active") "bg-emerald-100 text-emerald-700" "bg-stone-100 text-stone-500")) status)))) (defcomp ~examples/swap-positions-demo () (div (~tw :tokens "space-y-3") (div (~tw :tokens "flex gap-2") (button :sx-post "/sx/(geography.(hypermedia.(example.(api.swap-log))))?mode=beforeend" :sx-target "#swap-log" :sx-swap "beforeend" (~tw :tokens "px-3 py-1.5 bg-violet-600 text-white rounded text-sm hover:bg-violet-700") "Add to End") (button :sx-post "/sx/(geography.(hypermedia.(example.(api.swap-log))))?mode=afterbegin" :sx-target "#swap-log" :sx-swap "afterbegin" (~tw :tokens "px-3 py-1.5 bg-violet-600 text-white rounded text-sm hover:bg-violet-700") "Add to Start") (button :sx-post "/sx/(geography.(hypermedia.(example.(api.swap-log))))?mode=none" :sx-target "#swap-log" :sx-swap "none" (~tw :tokens "px-3 py-1.5 bg-stone-600 text-white rounded text-sm hover:bg-stone-700") "Silent Ping") (span :id "swap-counter" (~tw :tokens "self-center text-sm text-stone-500") "Count: 0")) (div :id "swap-log" (~tw :tokens "border border-stone-200 rounded h-48 overflow-y-auto divide-y divide-stone-100") (p (~tw :tokens "p-3 text-sm text-stone-400") "Log entries will appear here.")))) (defcomp ~examples/swap-entry (&key time mode) (div (~tw :tokens "px-3 py-2 text-sm text-stone-700") (str "[" time "] " mode))) (defcomp ~examples/select-filter-demo () (div (~tw :tokens "space-y-3") (div (~tw :tokens "flex gap-2") (button :sx-get "/sx/(geography.(hypermedia.(example.(api.dashboard))))" :sx-target "#filter-target" :sx-swap "innerHTML" :sx-select "#dash-stats" (~tw :tokens "px-3 py-1.5 bg-violet-600 text-white rounded text-sm hover:bg-violet-700") "Stats Only") (button :sx-get "/sx/(geography.(hypermedia.(example.(api.dashboard))))" :sx-target "#filter-target" :sx-swap "innerHTML" :sx-select "#dash-header" (~tw :tokens "px-3 py-1.5 bg-violet-600 text-white rounded text-sm hover:bg-violet-700") "Header Only") (button :sx-get "/sx/(geography.(hypermedia.(example.(api.dashboard))))" :sx-target "#filter-target" :sx-swap "innerHTML" (~tw :tokens "px-3 py-1.5 bg-stone-600 text-white rounded text-sm hover:bg-stone-700") "Full Dashboard")) (div :id "filter-target" (~tw :tokens "border border-stone-200 rounded p-4 bg-stone-100") (p (~tw :tokens "text-sm text-stone-400") "Click a button to load content.")))) (defcomp ~examples/tabs-demo () (div (~tw :tokens "space-y-0") (div (~tw :tokens "flex border-b border-stone-200") :id "tab-buttons" (~examples/tab-btn :tab "tab1" :label "Overview" :active "true") (~examples/tab-btn :tab "tab2" :label "Details" :active "false") (~examples/tab-btn :tab "tab3" :label "History" :active "false")) (div :id "tab-content" (~tw :tokens "p-4 border border-t-0 border-stone-200 rounded-b") (p (~tw :tokens "text-stone-700") "Welcome to the Overview tab. This content is loaded by default.") (p (~tw :tokens "text-stone-500 text-sm mt-2") "Click the tabs above to navigate. Watch the browser URL update.")))) (defcomp ~examples/tab-btn (&key tab label active) (button :sx-get (str "/sx/(geography.(hypermedia.(example.(api.(tabs." tab ")))))") :sx-target "#tab-content" :sx-swap "innerHTML" :sx-push-url (str "/sx/(geography.(hypermedia.(example.tabs)))?tab=" tab) :class (str "px-4 py-2 text-sm font-medium border-b-2 -mb-px transition-colors " (if (= active "true") "border-violet-600 text-violet-600" "border-transparent text-stone-500 hover:text-stone-700")) label)) (defcomp ~examples/animations-demo () (div (~tw :tokens "space-y-4") (button :sx-get "/sx/(geography.(hypermedia.(example.(api.animate))))" :sx-target "#anim-target" :sx-swap "innerHTML" (~tw :tokens "px-4 py-2 bg-violet-600 text-white rounded hover:bg-violet-700 transition-colors text-sm") "Load with animation") (div :id "anim-target" (~tw :tokens "p-4 rounded border border-stone-200 bg-stone-100 text-center") (p (~tw :tokens "text-stone-400") "Content will fade in here.")))) (defcomp ~examples/anim-result (&key color time) (div (~tw :tokens "sx-fade-in space-y-2") (div :class (str "p-4 rounded transition-colors duration-700 " color) (p (~tw :tokens "font-medium") "Faded in!") (p (~tw :tokens "text-sm mt-1") (str "Loaded at " time))))) (defcomp ~examples/dialogs-demo () (div (button :sx-get "/sx/(geography.(hypermedia.(example.(api.dialog))))" :sx-target "#dialog-container" :sx-swap "innerHTML" (~tw :tokens "px-4 py-2 bg-violet-600 text-white rounded hover:bg-violet-700 transition-colors text-sm") "Open Dialog") (div :id "dialog-container"))) (defcomp ~examples/dialog-modal (&key title message) (div (~tw :tokens "fixed inset-0 z-50 flex items-center justify-center") (div (~tw :tokens "absolute inset-0 bg-black/50") :sx-get "/sx/(geography.(hypermedia.(example.(api.dialog-close))))" :sx-target "#dialog-container" :sx-swap "innerHTML") (div (~tw :tokens "relative bg-stone-100 rounded-lg shadow-xl p-6 max-w-md w-full mx-4 space-y-4") (h3 (~tw :tokens "text-lg font-semibold text-stone-800") title) (p (~tw :tokens "text-stone-600") message) (div (~tw :tokens "flex justify-end gap-2") (button :sx-get "/sx/(geography.(hypermedia.(example.(api.dialog-close))))" :sx-target "#dialog-container" :sx-swap "innerHTML" (~tw :tokens "px-4 py-2 bg-stone-200 text-stone-700 rounded text-sm hover:bg-stone-300") "Cancel") (button :sx-get "/sx/(geography.(hypermedia.(example.(api.dialog-close))))" :sx-target "#dialog-container" :sx-swap "innerHTML" (~tw :tokens "px-4 py-2 bg-violet-600 text-white rounded text-sm hover:bg-violet-700") "Confirm"))))) (defcomp ~examples/keyboard-shortcuts-demo () (div (~tw :tokens "space-y-4") (div (~tw :tokens "p-4 rounded border border-stone-200 bg-stone-100") (p (~tw :tokens "text-sm text-stone-600 font-medium mb-2") "Keyboard shortcuts:") (div (~tw :tokens "flex gap-4") (div (~tw :tokens "flex items-center gap-1") (kbd (~tw :tokens "px-2 py-0.5 bg-stone-100 border border-stone-300 rounded text-xs font-mono") "s") (span (~tw :tokens "text-sm text-stone-500") "Search")) (div (~tw :tokens "flex items-center gap-1") (kbd (~tw :tokens "px-2 py-0.5 bg-stone-100 border border-stone-300 rounded text-xs font-mono") "n") (span (~tw :tokens "text-sm text-stone-500") "New item")) (div (~tw :tokens "flex items-center gap-1") (kbd (~tw :tokens "px-2 py-0.5 bg-stone-100 border border-stone-300 rounded text-xs font-mono") "h") (span (~tw :tokens "text-sm text-stone-500") "Help")))) (div :id "kbd-target" :sx-get "/sx/(geography.(hypermedia.(example.(api.keyboard))))?key=s" :sx-trigger "keyup[key=='s'&&!event.target.matches('input,textarea')] from:body" :sx-swap "innerHTML" (~tw :tokens "p-4 rounded border border-stone-200 bg-stone-100 text-center") (p (~tw :tokens "text-stone-400 text-sm") "Press a shortcut key...")) (div :sx-get "/sx/(geography.(hypermedia.(example.(api.keyboard))))?key=n" :sx-trigger "keyup[key=='n'&&!event.target.matches('input,textarea')] from:body" :sx-target "#kbd-target" :sx-swap "innerHTML") (div :sx-get "/sx/(geography.(hypermedia.(example.(api.keyboard))))?key=h" :sx-trigger "keyup[key=='h'&&!event.target.matches('input,textarea')] from:body" :sx-target "#kbd-target" :sx-swap "innerHTML"))) (defcomp ~examples/kbd-result (&key key action) (div (~tw :tokens "space-y-1") (p (~tw :tokens "text-stone-800 font-medium") action) (p (~tw :tokens "text-sm text-stone-500") (str "Triggered by pressing '" key "'")))) (defcomp ~examples/put-patch-demo (&key name email role) (div :id "pp-target" (~tw :tokens "space-y-4") (~examples/pp-view :name name :email email :role role))) (defcomp ~examples/pp-view (&key name email role) (div (~tw :tokens "space-y-3") (div (~tw :tokens "flex justify-between items-start") (div (p (~tw :tokens "text-stone-800 font-medium") name) (p (~tw :tokens "text-sm text-stone-500") email) (p (~tw :tokens "text-sm text-stone-500") role)) (button :sx-get "/sx/(geography.(hypermedia.(example.(api.putpatch-edit-all))))" :sx-target "#pp-target" :sx-swap "innerHTML" (~tw :tokens "text-sm text-violet-600 hover:text-violet-800") "Edit All (PUT)")))) (defcomp ~examples/pp-form-full (&key name email role) (form :sx-put "/sx/(geography.(hypermedia.(example.(api.putpatch))))" :sx-target "#pp-target" :sx-swap "innerHTML" (~tw :tokens "space-y-3") (div (label (~tw :tokens "block text-sm font-medium text-stone-700 mb-1") "Name") (input :type "text" :name "name" :value name (~tw :tokens "w-full px-3 py-2 border border-stone-300 rounded text-sm"))) (div (label (~tw :tokens "block text-sm font-medium text-stone-700 mb-1") "Email") (input :type "text" :name "email" :value email (~tw :tokens "w-full px-3 py-2 border border-stone-300 rounded text-sm"))) (div (label (~tw :tokens "block text-sm font-medium text-stone-700 mb-1") "Role") (input :type "text" :name "role" :value role (~tw :tokens "w-full px-3 py-2 border border-stone-300 rounded text-sm"))) (div (~tw :tokens "flex gap-2") (button :type "submit" (~tw :tokens "px-4 py-2 bg-violet-600 text-white rounded text-sm hover:bg-violet-700") "Save All (PUT)") (button :type "button" :sx-get "/sx/(geography.(hypermedia.(example.(api.putpatch-cancel))))" :sx-target "#pp-target" :sx-swap "innerHTML" (~tw :tokens "px-4 py-2 bg-stone-200 text-stone-700 rounded text-sm hover:bg-stone-300") "Cancel")))) (defcomp ~examples/json-encoding-demo () (div (~tw :tokens "space-y-4") (form :sx-post "/sx/(geography.(hypermedia.(example.(api.json-echo))))" :sx-target "#json-result" :sx-swap "innerHTML" :sx-encoding "json" (~tw :tokens "space-y-3") (div (label (~tw :tokens "block text-sm font-medium text-stone-700 mb-1") "Name") (input :type "text" :name "name" :value "Ada Lovelace" (~tw :tokens "w-full px-3 py-2 border border-stone-300 rounded text-sm"))) (div (label (~tw :tokens "block text-sm font-medium text-stone-700 mb-1") "Age") (input :type "number" :name "age" :value "36" (~tw :tokens "w-full px-3 py-2 border border-stone-300 rounded text-sm"))) (button :type "submit" (~tw :tokens "px-4 py-2 bg-violet-600 text-white rounded hover:bg-violet-700 transition-colors text-sm") "Submit as JSON")) (div :id "json-result" (~tw :tokens "p-3 rounded bg-stone-100 text-stone-500 text-sm") "Submit the form to see the server echo the parsed JSON."))) (defcomp ~examples/json-result (&key body content-type) (div (~tw :tokens "space-y-2") (p (~tw :tokens "text-stone-800 font-medium") "Server received:") (pre (~tw :tokens "text-sm bg-stone-100 p-3 rounded overflow-x-auto") (code body)) (p (~tw :tokens "text-sm text-stone-500") (str "Content-Type: " content-type)))) (defcomp ~examples/vals-headers-demo () (div (~tw :tokens "space-y-6") (div (~tw :tokens "space-y-2") (h4 (~tw :tokens "text-sm font-semibold text-stone-700") "sx-vals — send extra values") (button :sx-get "/sx/(geography.(hypermedia.(example.(api.echo-vals))))" :sx-target "#vals-result" :sx-swap "innerHTML" :sx-vals "{\"source\": \"button\", \"version\": \"2.0\"}" (~tw :tokens "px-4 py-2 bg-violet-600 text-white rounded hover:bg-violet-700 transition-colors text-sm") "Send with vals") (div :id "vals-result" (~tw :tokens "p-3 rounded bg-stone-100 text-sm text-stone-400") "Click to see server-received values.")) (div (~tw :tokens "space-y-2") (h4 (~tw :tokens "text-sm font-semibold text-stone-700") "sx-headers — send custom headers") (button :sx-get "/sx/(geography.(hypermedia.(example.(api.echo-headers))))" :sx-target "#headers-result" :sx-swap "innerHTML" :sx-headers {:X-Request-Source "demo" :X-Custom-Token "abc123"} (~tw :tokens "px-4 py-2 bg-violet-600 text-white rounded hover:bg-violet-700 transition-colors text-sm") "Send with headers") (div :id "headers-result" (~tw :tokens "p-3 rounded bg-stone-100 text-sm text-stone-400") "Click to see server-received headers.")))) (defcomp ~examples/echo-result (&key label items) (div (~tw :tokens "space-y-1") (p (~tw :tokens "text-stone-800 font-medium") (str "Server received " label ":")) (map (fn (item) (div (~tw :tokens "text-sm text-stone-600 font-mono") item)) items))) (defcomp ~examples/loading-states-demo () (div (~tw :tokens "space-y-4") (button :sx-get "/sx/(geography.(hypermedia.(example.(api.slow))))" :sx-target "#loading-result" :sx-swap "innerHTML" (~tw :tokens "sx-loading-btn px-4 py-2 bg-violet-600 text-white rounded hover:bg-violet-700 transition-colors text-sm flex items-center gap-2") (span (~tw :tokens "sx-spinner w-4 h-4 border-2 border-white/30 border-t-white rounded-full animate-spin")) (span "Load slow endpoint")) (div :id "loading-result" (~tw :tokens "p-4 rounded border border-stone-200 bg-stone-100 text-center") (p (~tw :tokens "text-stone-400 text-sm") "Click the button — it takes 2 seconds.")))) (defcomp ~examples/loading-result (&key time) (div (p (~tw :tokens "text-stone-800 font-medium") "Loaded!") (p (~tw :tokens "text-sm text-stone-500") (str "Response arrived at " time)))) (defcomp ~examples/sync-replace-demo () (div (~tw :tokens "space-y-3") (input :type "text" :name "q" :sx-get "/sx/(geography.(hypermedia.(example.(api.slow-search))))" :sx-trigger "keyup delay:200ms changed" :sx-target "#sync-result" :sx-swap "innerHTML" :sx-sync "replace" :placeholder "Type to search (random delay 0.5-2s)..." (~tw :tokens "w-full px-3 py-2 border border-stone-300 rounded text-sm focus:outline-none focus:ring-2 focus:ring-violet-500")) (div :id "sync-result" (~tw :tokens "p-4 rounded border border-stone-200 bg-stone-100") (p (~tw :tokens "text-sm text-stone-400") "Type to trigger requests — stale ones get aborted.")))) (defcomp ~examples/sync-result (&key query delay) (div (p (~tw :tokens "text-stone-800 font-medium") (str "Result for: \"" query "\"")) (p (~tw :tokens "text-sm text-stone-500") (str "Server took " delay "ms to respond")))) (defcomp ~examples/retry-demo () (div (~tw :tokens "space-y-4") (button :sx-get "/sx/(geography.(hypermedia.(example.(api.flaky))))" :sx-target "#retry-result" :sx-swap "innerHTML" :sx-retry "exponential:1000:8000" (~tw :tokens "px-4 py-2 bg-violet-600 text-white rounded hover:bg-violet-700 transition-colors text-sm") "Call flaky endpoint") (div :id "retry-result" (~tw :tokens "p-4 rounded border border-stone-200 bg-stone-100 text-center") (p (~tw :tokens "text-stone-400 text-sm") "Endpoint fails twice, succeeds on 3rd attempt.")))) (defcomp ~examples/retry-result (&key attempt message) (div (~tw :tokens "space-y-1") (p (~tw :tokens "text-stone-800 font-medium") message) (p (~tw :tokens "text-sm text-stone-500") (str "Succeeded on attempt #" attempt))))