;; Market product detail components (defcomp ~market-detail-gallery-inner (&key like image alt labels brand) (<> like (figure :class "inline-block" (div :class "relative w-full aspect-square" (img :data-main-img "" :src image :alt alt :class "w-full h-full object-contain object-top" :loading "eager" :decoding "async") labels) (figcaption :class "mt-2 text-sm text-stone-600 text-center" brand)))) (defcomp ~market-detail-nav-buttons () (<> (button :type "button" :data-prev "" :class "absolute left-2 top-1/2 -translate-y-1/2 z-10 grid place-items-center w-12 h-12 md:w-14 md:h-14 rounded-full bg-white/90 hover:bg-white shadow-lg text-3xl md:text-4xl" :title "Previous" "\u2039") (button :type "button" :data-next "" :class "absolute right-2 top-1/2 -translate-y-1/2 z-10 grid place-items-center w-12 h-12 md:w-14 md:h-14 rounded-full bg-white/90 hover:bg-white shadow-lg text-3xl md:text-4xl" :title "Next" "\u203a"))) (defcomp ~market-detail-gallery (&key inner nav) (div :class "relative rounded-xl overflow-hidden bg-stone-100" inner nav)) (defcomp ~market-detail-thumb (&key title src alt) (<> (button :type "button" :data-thumb "" :class "shrink-0 rounded-lg overflow-hidden bg-stone-100 hover:opacity-90 ring-offset-2" :title title (img :src src :class "h-16 w-16 object-contain" :alt alt :loading "lazy" :decoding "async")) (span :data-image-src src :class "hidden"))) (defcomp ~market-detail-thumbs (&key thumbs) (div :class "flex flex-row justify-center" (div :class "mt-3 flex gap-2 overflow-x-auto no-scrollbar" thumbs))) (defcomp ~market-detail-no-image (&key like) (div :class "relative aspect-square bg-stone-100 rounded-xl flex items-center justify-center text-stone-400" like "No image")) (defcomp ~market-detail-sticker (&key src name) (img :src src :alt name :class "w-10 h-10")) (defcomp ~market-detail-stickers (&key items) (div :class "p-2 flex flex-row justify-center gap-2" items)) (defcomp ~market-detail-unit-price (&key price) (div (str "Unit price: " price))) (defcomp ~market-detail-case-size (&key size) (div (str "Case size: " size))) (defcomp ~market-detail-extras (&key inner) (div :class "mt-2 space-y-1 text-sm text-stone-600" inner)) (defcomp ~market-detail-desc-short (&key text) (p :class "leading-relaxed text-lg" text)) (defcomp ~market-detail-desc-html (&key html) (div :class "max-w-none text-sm leading-relaxed" (~rich-text :html html))) (defcomp ~market-detail-desc-wrapper (&key inner) (div :class "mt-4 text-stone-800 space-y-3" inner)) (defcomp ~market-detail-section (&key title html) (details :class "group rounded-xl border bg-white shadow-sm open:shadow p-0" (summary :class "cursor-pointer select-none px-4 py-3 flex items-center justify-between" (span :class "font-medium" title) (span :class "ml-2 text-xl transition-transform group-open:rotate-180" "\u2304")) (div :class "px-4 pb-4 max-w-none text-sm leading-relaxed" (~rich-text :html html)))) (defcomp ~market-detail-sections (&key items) (div :class "mt-8 space-y-3" items)) (defcomp ~market-detail-right-col (&key inner) (div :class "md:col-span-3" inner)) (defcomp ~market-detail-layout (&key gallery stickers details) (<> (div :class "mt-3 grid grid-cols-1 md:grid-cols-5 gap-6" :data-gallery-root "" (div :class "md:col-span-2" gallery stickers) details) (div :class "pb-8"))) (defcomp ~market-landing-excerpt (&key text) (div :class "w-full text-center italic text-3xl p-2" text)) (defcomp ~market-landing-image (&key src) (div :class "mb-3 flex justify-center" (img :src src :alt "" :class "rounded-lg w-full md:w-3/4 object-cover"))) (defcomp ~market-landing-html (&key html) (div :class "blog-content p-2" (~rich-text :html html))) (defcomp ~market-landing-content (&key inner) (<> (article :class "relative w-full" inner) (div :class "pb-8"))) ;; --------------------------------------------------------------------------- ;; Composition: product detail page from data ;; --------------------------------------------------------------------------- ;; Gallery section from pre-computed data (defcomp ~market-detail-gallery-from-data (&key images labels brand like-data has-nav-buttons thumbs) (let ((like-sx (when like-data (~market-like-button :form-id (get like-data "form-id") :action (get like-data "action") :slug (get like-data "slug") :csrf (get like-data "csrf") :icon-cls (get like-data "icon-cls"))))) (if images (<> (~market-detail-gallery :inner (~market-detail-gallery-inner :like like-sx :image (get (first images) "src") :alt (get (first images) "alt") :labels (when labels (<> (map (lambda (src) (~market-label-overlay :src src)) labels))) :brand brand) :nav (when has-nav-buttons (~market-detail-nav-buttons))) (when thumbs (~market-detail-thumbs :thumbs (<> (map (lambda (t) (~market-detail-thumb :title (get t "title") :src (get t "src") :alt (get t "alt"))) thumbs))))) (~market-detail-no-image :like like-sx)))) ;; Right column details from data (defcomp ~market-detail-info-from-data (&key extras desc-short desc-html sections) (~market-detail-right-col :inner (<> (when extras (~market-detail-extras :inner (<> (map (lambda (e) (if (= (get e "type") "unit-price") (~market-detail-unit-price :price (get e "value")) (~market-detail-case-size :size (get e "value")))) extras)))) (when (or desc-short desc-html) (~market-detail-desc-wrapper :inner (<> (when desc-short (~market-detail-desc-short :text desc-short)) (when desc-html (~market-detail-desc-html :html desc-html))))) (when sections (~market-detail-sections :items (<> (map (lambda (s) (~market-detail-section :title (get s "title") :html (get s "html"))) sections))))))) ;; Full product detail layout from data (defcomp ~market-product-detail-from-data (&key images labels brand like-data has-nav-buttons thumbs sticker-items extras desc-short desc-html sections) (~market-detail-layout :gallery (~market-detail-gallery-from-data :images images :labels labels :brand brand :like-data like-data :has-nav-buttons has-nav-buttons :thumbs thumbs) :stickers (when sticker-items (~market-detail-stickers :items (<> (map (lambda (s) (~market-detail-sticker :src (get s "src") :name (get s "name"))) sticker-items)))) :details (~market-detail-info-from-data :extras extras :desc-short desc-short :desc-html desc-html :sections sections)))