;; Events fragment components — served as HTML fragments for other apps. ;; container-cards entries, account page tickets, account page bookings. ;; --------------------------------------------------------------------------- ;; Container cards entries (fragments/container_cards_entries.html) ;; --------------------------------------------------------------------------- (defcomp ~fragments/frag-entry-card (&key href name date-str time-str) (a :href href :class "flex flex-col gap-1 px-3 py-2 bg-stone-50 hover:bg-stone-100 rounded border border-stone-200 transition text-sm whitespace-nowrap flex-shrink-0 min-w-[180px]" (div :class "font-medium text-stone-900 truncate" name) (div :class "text-xs text-stone-600" date-str) (div :class "text-xs text-stone-500" time-str))) (defcomp ~fragments/frag-entries-widget (&key cards) (div :class "mt-4 mb-2" (h3 :class "text-sm font-semibold text-stone-700 mb-2 px-2" "Events:") (div :class "overflow-x-auto scrollbar-hide" :style "scroll-behavior: smooth;" (div :class "flex gap-2 px-2" cards)))) ;; --------------------------------------------------------------------------- ;; Account page tickets (fragments/account_page_tickets.html) ;; --------------------------------------------------------------------------- (defcomp ~fragments/frag-ticket-item (&key href entry-name date-str calendar-name type-name badge) (div :class "py-4 first:pt-0 last:pb-0" (div :class "flex items-start justify-between gap-4" (div :class "min-w-0 flex-1" (a :href href :class "text-sm font-medium text-stone-800 hover:text-emerald-700 transition" entry-name) (div :class "mt-1 flex flex-wrap items-center gap-x-3 gap-y-1 text-xs text-stone-500" (span date-str) calendar-name type-name)) (div :class "flex-shrink-0" badge)))) (defcomp ~fragments/frag-tickets-panel (&key items) (div :class "w-full max-w-3xl mx-auto px-4 py-6" (div :class "bg-white/70 backdrop-blur rounded-2xl shadow border border-stone-200 p-6 sm:p-8 space-y-6" (h1 :class "text-xl font-semibold tracking-tight" "Tickets") items))) (defcomp ~fragments/frag-tickets-list (&key items) (div :class "divide-y divide-stone-100" items)) ;; --------------------------------------------------------------------------- ;; Account page bookings (fragments/account_page_bookings.html) ;; --------------------------------------------------------------------------- (defcomp ~fragments/frag-booking-item (&key name date-str calendar-name cost-str badge) (div :class "py-4 first:pt-0 last:pb-0" (div :class "flex items-start justify-between gap-4" (div :class "min-w-0 flex-1" (p :class "text-sm font-medium text-stone-800" name) (div :class "mt-1 flex flex-wrap items-center gap-x-3 gap-y-1 text-xs text-stone-500" (span date-str) calendar-name cost-str)) (div :class "flex-shrink-0" badge)))) (defcomp ~fragments/frag-bookings-panel (&key items) (div :class "w-full max-w-3xl mx-auto px-4 py-6" (div :class "bg-white/70 backdrop-blur rounded-2xl shadow border border-stone-200 p-6 sm:p-8 space-y-6" (h1 :class "text-xl font-semibold tracking-tight" "Bookings") items))) (defcomp ~fragments/frag-bookings-list (&key items) (div :class "divide-y divide-stone-100" items)) ;; --------------------------------------------------------------------------- ;; From-data defcomps — iteration in sx ;; --------------------------------------------------------------------------- ;; Container cards: list of widgets, each with entries (defcomp ~fragments/frag-container-cards-from-data (&key widgets) (<> (map (lambda (w) (if (get w "entries") (~fragments/frag-entries-widget :cards (<> (map (lambda (e) (~fragments/frag-entry-card :href (get e "href") :name (get e "name") :date-str (get e "date-str") :time-str (get e "time-str"))) (get w "entries")))) "")) (or widgets (list))))) ;; Ticket item from data — composes badge + optional spans (defcomp ~fragments/frag-ticket-item-from-data (&key href entry-name date-str calendar-name type-name state) (~fragments/frag-ticket-item :href href :entry-name entry-name :date-str date-str :calendar-name (when calendar-name (span "\u00b7 " calendar-name)) :type-name (when type-name (span "\u00b7 " type-name)) :badge (~shared:controls/status-pill :status state))) ;; Tickets panel from data — full panel with list iteration (defcomp ~fragments/frag-tickets-panel-from-data (&key tickets) (~fragments/frag-tickets-panel :items (if (empty? (or tickets (list))) (~shared:misc/empty-state :message "No tickets yet." :cls "text-sm text-stone-500") (~fragments/frag-tickets-list :items (<> (map (lambda (t) (~fragments/frag-ticket-item-from-data :href (get t "href") :entry-name (get t "entry-name") :date-str (get t "date-str") :calendar-name (get t "calendar-name") :type-name (get t "type-name") :state (get t "state"))) tickets)))))) ;; Booking item from data — composes badge + optional spans (defcomp ~fragments/frag-booking-item-from-data (&key name date-str end-time calendar-name cost-str state) (~fragments/frag-booking-item :name name :date-str (<> date-str (when end-time (span "\u2013 " end-time))) :calendar-name (when calendar-name (span "\u00b7 " calendar-name)) :cost-str (when cost-str (span "\u00b7 \u00a3" cost-str)) :badge (~shared:controls/status-pill :status state))) ;; Bookings panel from data — full panel with list iteration (defcomp ~fragments/frag-bookings-panel-from-data (&key bookings) (~fragments/frag-bookings-panel :items (if (empty? (or bookings (list))) (~shared:misc/empty-state :message "No bookings yet." :cls "text-sm text-stone-500") (~fragments/frag-bookings-list :items (<> (map (lambda (b) (~fragments/frag-booking-item-from-data :href (get b "href") :name (get b "name") :date-str (get b "date-str") :end-time (get b "end-time") :calendar-name (get b "calendar-name") :cost-str (get b "cost-str") :state (get b "state"))) bookings))))))