Replace all 676 inline sexp() string calls across 7 services with render(component_name, **kwargs) calls backed by 46 external .sexpr component definition files (587 defcomps total). - Add render() function to shared/sexp/jinja_bridge.py - Add load_service_components() helper and update load_sexp_dir() for *.sexpr - Update parser keyword regex to support HTMX hx-on::event syntax - Convert remaining inline HTML in route files to render() calls - Add shared/sexp/templates/misc.sexp for cross-service utility components Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
97 lines
4.9 KiB
Plaintext
97 lines
4.9 KiB
Plaintext
;; Events admin components
|
|
|
|
(defcomp ~events-calendar-admin-panel (&key description-html csrf description)
|
|
(section :class "max-w-3xl mx-auto p-4 space-y-10"
|
|
(div
|
|
(h2 :class "text-xl font-semibold" "Calendar configuration")
|
|
(div :id "cal-put-errors" :class "mt-2 text-sm text-red-600")
|
|
(div (label :class "block text-sm font-medium text-stone-700" "Description")
|
|
(raw! description-html))
|
|
(form :id "calendar-form" :method "post" :hx-target "#main-panel" :hx-select "#main-panel"
|
|
:hx-on::before-request "document.querySelector('#cal-put-errors').textContent='';"
|
|
:hx-on::response-error "document.querySelector('#cal-put-errors').innerHTML = event.detail.xhr.responseText;"
|
|
:hx-on::after-request "if (event.detail.successful) this.reset()"
|
|
:class "hidden space-y-4 mt-4" :autocomplete "off"
|
|
(input :type "hidden" :name "csrf_token" :value csrf)
|
|
(div (label :class "block text-sm font-medium text-stone-700" "Description")
|
|
(div description)
|
|
(textarea :name "description" :autocomplete "off" :rows "4" :class "w-full p-2 border rounded" description))
|
|
(div (button :class "px-3 py-2 rounded bg-stone-800 text-white" "Save"))))
|
|
(hr :class "border-stone-200")))
|
|
|
|
(defcomp ~events-entry-admin-link (&key href)
|
|
(a :href href :class "inline-flex items-center gap-1 px-2 py-1 text-xs text-stone-500 hover:text-stone-700 hover:bg-stone-100 rounded"
|
|
(i :class "fa fa-cog" :aria-hidden "true") " Admin"))
|
|
|
|
(defcomp ~events-entry-field (&key label content-html)
|
|
(div :class "flex flex-col mb-4"
|
|
(div :class "text-xs font-semibold uppercase tracking-wide text-stone-500" label)
|
|
(raw! content-html)))
|
|
|
|
(defcomp ~events-entry-name-field (&key name)
|
|
(div :class "mt-1 text-lg font-medium" name))
|
|
|
|
(defcomp ~events-entry-slot-assigned (&key slot-name flex-label)
|
|
(div :class "mt-1"
|
|
(span :class "px-2 py-1 rounded text-sm bg-blue-100 text-blue-700" slot-name)
|
|
(span :class "ml-2 text-xs text-stone-500" flex-label)))
|
|
|
|
(defcomp ~events-entry-slot-none ()
|
|
(div :class "mt-1" (span :class "text-sm text-stone-400" "No slot assigned")))
|
|
|
|
(defcomp ~events-entry-time-field (&key time-str)
|
|
(div :class "mt-1" time-str))
|
|
|
|
(defcomp ~events-entry-state-field (&key entry-id badge-html)
|
|
(div :class "mt-1" (div :id (str "entry-state-" entry-id) (raw! badge-html))))
|
|
|
|
(defcomp ~events-entry-cost-field (&key cost-html)
|
|
(div :class "mt-1" (span :class "font-medium text-green-600" (raw! cost-html))))
|
|
|
|
(defcomp ~events-entry-tickets-field (&key entry-id tickets-config-html)
|
|
(div :class "mt-1" :id (str "entry-tickets-" entry-id) (raw! tickets-config-html)))
|
|
|
|
(defcomp ~events-entry-date-field (&key date-str)
|
|
(div :class "mt-1" date-str))
|
|
|
|
(defcomp ~events-entry-posts-field (&key entry-id posts-panel-html)
|
|
(div :class "mt-1" :id (str "entry-posts-" entry-id) (raw! posts-panel-html)))
|
|
|
|
(defcomp ~events-entry-panel (&key entry-id list-container name-html slot-html time-html state-html cost-html
|
|
tickets-html buy-html date-html posts-html options-html pre-action edit-url)
|
|
(section :id (str "entry-" entry-id) :class list-container
|
|
(raw! name-html) (raw! slot-html) (raw! time-html) (raw! state-html) (raw! cost-html)
|
|
(raw! tickets-html) (raw! buy-html) (raw! date-html) (raw! posts-html)
|
|
(div :class "flex gap-2 mt-6"
|
|
(raw! options-html)
|
|
(button :type "button" :class pre-action
|
|
:hx-get edit-url :hx-target (str "#entry-" entry-id) :hx-swap "outerHTML"
|
|
"Edit"))))
|
|
|
|
(defcomp ~events-entry-title (&key name badge-html)
|
|
(<> (i :class "fa fa-clock") " " name " " (raw! badge-html)))
|
|
|
|
(defcomp ~events-entry-times (&key time-str)
|
|
(div :class "text-sm text-gray-600" time-str))
|
|
|
|
(defcomp ~events-entry-optioned-oob (&key entry-id title-html state-html)
|
|
(<> (div :id (str "entry-title-" entry-id) :hx-swap-oob "innerHTML" (raw! title-html))
|
|
(div :id (str "entry-state-" entry-id) :hx-swap-oob "innerHTML" (raw! state-html))))
|
|
|
|
(defcomp ~events-entry-options (&key entry-id buttons-html)
|
|
(div :id (str "calendar_entry_options_" entry-id) :class "flex flex-col md:flex-row gap-1"
|
|
(raw! buttons-html)))
|
|
|
|
(defcomp ~events-entry-option-button (&key url target csrf btn-type action-btn confirm-title confirm-text
|
|
label is-btn)
|
|
(form :hx-post url :hx-select target :hx-target target :hx-swap "outerHTML"
|
|
:hx-trigger (if is-btn "confirmed" nil)
|
|
(input :type "hidden" :name "csrf_token" :value csrf)
|
|
(button :type btn-type :class action-btn
|
|
:data-confirm "true" :data-confirm-title confirm-title
|
|
:data-confirm-text confirm-text :data-confirm-icon "question"
|
|
:data-confirm-confirm-text (str "Yes, " label " it")
|
|
:data-confirm-cancel-text "Cancel"
|
|
:data-confirm-event (if is-btn "confirmed" nil)
|
|
(i :class "fa-solid fa-rotate mr-2" :aria-hidden "true") label)))
|