All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 1m20s
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>
106 lines
5.1 KiB
Plaintext
106 lines
5.1 KiB
Plaintext
;; Market card components
|
|
|
|
(defcomp ~market-label-overlay (&key src)
|
|
(img :src src :alt ""
|
|
:class "pointer-events-none absolute inset-0 w-full h-full object-contain object-top"))
|
|
|
|
(defcomp ~market-card-image (&key image labels-html brand-highlight brand)
|
|
(div :class "w-full aspect-square bg-stone-100 relative"
|
|
(figure :class "inline-block w-full h-full"
|
|
(div :class "relative w-full h-full"
|
|
(img :src image :alt "no image" :class "absolute inset-0 w-full h-full object-contain object-top" :loading "lazy" :decoding "async" :fetchpriority "low")
|
|
(raw! labels-html))
|
|
(figcaption :class (str "mt-2 text-sm text-center" brand-highlight " text-stone-600") brand))))
|
|
|
|
(defcomp ~market-card-no-image (&key labels-html brand)
|
|
(div :class "w-full aspect-square bg-stone-100 relative"
|
|
(div :class "p-2 flex flex-col items-center justify-center gap-2 text-red-500 h-full relative"
|
|
(div :class "text-stone-400 text-xs" "No image")
|
|
(ul :class "flex flex-row gap-1" (raw! labels-html))
|
|
(div :class "text-stone-900 text-center line-clamp-3 break-words [overflow-wrap:anywhere]" brand))))
|
|
|
|
(defcomp ~market-card-label-item (&key label)
|
|
(li label))
|
|
|
|
(defcomp ~market-card-sticker (&key src name ring-cls)
|
|
(img :src src :alt name :class (str "w-6 h-6" ring-cls)))
|
|
|
|
(defcomp ~market-card-stickers (&key items-html)
|
|
(div :class "flex flex-row justify-center gap-2 p-2" (raw! items-html)))
|
|
|
|
(defcomp ~market-card-highlight (&key pre mid post)
|
|
(<> pre (mark mid) post))
|
|
|
|
(defcomp ~market-card-text (&key text)
|
|
(<> text))
|
|
|
|
(defcomp ~market-product-card (&key like-html href hx-select image-html price-html add-html stickers-html title-html)
|
|
(div :class "flex flex-col rounded-xl bg-white shadow hover:shadow-md transition overflow-hidden relative"
|
|
(raw! like-html)
|
|
(a :href href :hx-get href :hx-target "#main-panel"
|
|
:hx-select hx-select :hx-swap "outerHTML" :hx-push-url "true"
|
|
(raw! image-html) (raw! price-html))
|
|
(div :class "flex justify-center" (raw! add-html))
|
|
(a :href href :hx-get href :hx-target "#main-panel"
|
|
:hx-select hx-select :hx-swap "outerHTML" :hx-push-url "true"
|
|
(raw! stickers-html)
|
|
(div :class "text-sm font-medium text-stone-800 text-center line-clamp-3 break-words [overflow-wrap:anywhere]"
|
|
(raw! title-html)))))
|
|
|
|
(defcomp ~market-like-button (&key form-id action slug csrf icon-cls)
|
|
(div :class "absolute top-2 right-2 z-10 text-6xl md:text-xl"
|
|
(form :id form-id :action action :method "post"
|
|
:hx-post action :hx-target (str "#like-" slug) :hx-swap "outerHTML"
|
|
(input :type "hidden" :name "csrf_token" :value csrf)
|
|
(button :type "submit" :class "cursor-pointer"
|
|
(i :class icon-cls :aria-hidden "true")))))
|
|
|
|
(defcomp ~market-market-card-title-link (&key href name)
|
|
(a :href href :class "hover:text-emerald-700"
|
|
(h2 :class "text-lg font-semibold text-stone-900" name)))
|
|
|
|
(defcomp ~market-market-card-title (&key name)
|
|
(h2 :class "text-lg font-semibold text-stone-900" name))
|
|
|
|
(defcomp ~market-market-card-desc (&key description)
|
|
(p :class "text-sm text-stone-600 mt-1 line-clamp-2" description))
|
|
|
|
(defcomp ~market-market-card-badge (&key href title)
|
|
(div :class "flex flex-wrap items-center gap-1.5 mt-3"
|
|
(a :href href :class "inline-block px-2 py-0.5 rounded-full text-xs font-medium bg-amber-100 text-amber-800 hover:bg-amber-200"
|
|
title)))
|
|
|
|
(defcomp ~market-market-card (&key title-html desc-html badge-html)
|
|
(article :class "rounded-xl bg-white shadow-sm border border-stone-200 p-5 flex flex-col justify-between hover:border-stone-400 transition-colors"
|
|
(div (raw! title-html) (raw! desc-html))
|
|
(raw! badge-html)))
|
|
|
|
(defcomp ~market-sentinel-mobile (&key id next-url hyperscript)
|
|
(div :id id
|
|
:class "block md:hidden h-[60vh] opacity-0 pointer-events-none js-mobile-sentinel"
|
|
:hx-get next-url :hx-trigger "intersect once delay:250ms, sentinelmobile:retry"
|
|
:hx-swap "outerHTML"
|
|
:_ hyperscript
|
|
:role "status" :aria-live "polite" :aria-hidden "true"
|
|
(div :class "js-loading text-center text-xs text-stone-400" "loading...")
|
|
(div :class "js-neterr hidden text-center text-xs text-stone-400" "Retrying...")))
|
|
|
|
(defcomp ~market-sentinel-desktop (&key id next-url hyperscript)
|
|
(div :id id
|
|
:class "hidden md:block h-4 opacity-0 pointer-events-none"
|
|
:hx-get next-url :hx-trigger "intersect once delay:250ms, sentinel:retry"
|
|
:hx-swap "outerHTML"
|
|
:_ hyperscript
|
|
:role "status" :aria-live "polite" :aria-hidden "true"
|
|
(div :class "js-loading text-center text-xs text-stone-400" "loading...")
|
|
(div :class "js-neterr hidden text-center text-xs text-stone-400" "Retrying...")))
|
|
|
|
(defcomp ~market-sentinel-end ()
|
|
(div :class "col-span-full mt-4 text-center text-xs text-stone-400" "End of results"))
|
|
|
|
(defcomp ~market-market-sentinel (&key id next-url)
|
|
(div :id id :class "h-4 opacity-0 pointer-events-none"
|
|
:hx-get next-url :hx-trigger "intersect once delay:250ms"
|
|
:hx-swap "outerHTML" :role "status" :aria-hidden "true"
|
|
(div :class "text-center text-xs text-stone-400" "loading...")))
|