;; Cart overview components (defcomp ~overview/badge (&key (icon :as string) (text :as string)) (span :class "inline-flex items-center gap-1 px-2 py-0.5 rounded-full bg-stone-100" (i :class icon :aria-hidden "true") text)) (defcomp ~overview/badges-wrap (&key badges) (div :class "mt-1 flex flex-wrap gap-2 text-xs text-stone-600" badges)) (defcomp ~overview/group-card-img (&key (src :as string) (alt :as string)) (img :src src :alt alt :class "h-16 w-16 rounded-xl object-cover border border-stone-200 flex-shrink-0")) (defcomp ~overview/mp-subtitle (&key (title :as string)) (p :class "text-xs text-stone-500 truncate" title)) (defcomp ~overview/group-card (&key (href :as string) img (display-title :as string) subtitle badges (total :as string)) (a :href href :class "block rounded-2xl border border-stone-200 bg-white shadow-sm hover:shadow-md hover:border-stone-300 transition p-4 sm:p-5" (div :class "flex items-start gap-4" img (div :class "flex-1 min-w-0" (h3 :class "text-base sm:text-lg font-semibold text-stone-900 truncate" display-title) subtitle badges) (div :class "text-right flex-shrink-0" (div :class "text-lg font-bold text-stone-900" total) (div :class "mt-1 text-xs text-emerald-700 font-medium" "View cart \u2192"))))) (defcomp ~overview/orphan-card (&key badges (total :as string)) (div :class "rounded-2xl border border-dashed border-amber-300 bg-amber-50/60 p-4 sm:p-5" (div :class "flex items-start gap-4" (div :class "h-16 w-16 rounded-xl bg-amber-100 flex items-center justify-center flex-shrink-0" (i :class "fa fa-shopping-cart text-amber-500 text-xl" :aria-hidden "true")) (div :class "flex-1 min-w-0" (h3 :class "text-base sm:text-lg font-semibold text-stone-900" "Other items") badges) (div :class "text-right flex-shrink-0" (div :class "text-lg font-bold text-stone-900" total))))) (defcomp ~overview/panel (&key cards) (div :class "max-w-full px-3 py-3 space-y-3" (div :class "space-y-4" cards))) (defcomp ~overview/empty () (div :class "max-w-full px-3 py-3 space-y-3" (div :class "rounded-2xl border border-dashed border-stone-300 bg-white/80 p-6 sm:p-8 text-center" (~shared:misc/empty-state :icon "fa fa-shopping-cart" :message "Your cart is empty" :cls "text-center")))) ;; Assembled page group card — replaces Python _page_group_card_sx (defcomp ~overview/page-group-card-from-data (&key (grp :as dict) (cart-url-base :as string)) (let* ((post (get grp "post")) (product-count (or (get grp "product_count") 0)) (calendar-count (or (get grp "calendar_count") 0)) (ticket-count (or (get grp "ticket_count") 0)) (total (or (get grp "total") 0)) (market-place (get grp "market_place")) (badges (<> (when (> product-count 0) (~overview/badge :icon "fa fa-box-open" :text (str product-count " item" (pluralize product-count)))) (when (> calendar-count 0) (~overview/badge :icon "fa fa-calendar" :text (str calendar-count " booking" (pluralize calendar-count)))) (when (> ticket-count 0) (~overview/badge :icon "fa fa-ticket" :text (str ticket-count " ticket" (pluralize ticket-count))))))) (if post (let* ((slug (or (get post "slug") "")) (title (or (get post "title") "")) (feature-image (get post "feature_image")) (mp-name (if market-place (or (get market-place "name") "") "")) (display-title (if (!= mp-name "") mp-name title))) (~overview/group-card :href (str cart-url-base "/" slug "/") :img (if feature-image (~overview/group-card-img :src feature-image :alt title) (~shared:misc/img-or-placeholder :src nil :size-cls "h-16 w-16 rounded-xl" :placeholder-icon "fa fa-store text-xl")) :display-title display-title :subtitle (when (!= mp-name "") (~overview/mp-subtitle :title title)) :badges (~overview/badges-wrap :badges badges) :total (str "\u00a3" (format-decimal total 2)))) (~overview/orphan-card :badges (~overview/badges-wrap :badges badges) :total (str "\u00a3" (format-decimal total 2)))))) ;; Assembled cart overview content — replaces Python _overview_main_panel_sx (defcomp ~overview/content (&key (page-groups :as list) (cart-url-base :as string)) (if (empty? page-groups) (~overview/empty) (~overview/panel :cards (map (lambda (grp) (~overview/page-group-card-from-data :grp grp :cart-url-base cart-url-base)) page-groups))))