Files
mono/blog/sx/menu_items.sx
giles c1ad6fd8d4 Replace Python sx_call loops with data-driven SX defcomps using map
Move rendering logic from Python for-loops building sx_call strings into
SX defcomp components that use map/lambda over data dicts. Python now
serializes display data into plain dicts and passes them via a single
sx_call; the SX layer handles iteration and conditional rendering.

Covers orders (rows, items, calendar, tickets), federation (timeline,
search, actors, profile activities), and blog (cards, pages, filters,
snippets, menu items, tag groups, page search, nav OOB).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 16:03:29 +00:00

61 lines
3.1 KiB
Plaintext

;; Menu item form and page search components
(defcomp ~page-search-item (&key id title slug feature-image)
(div :class "flex items-center gap-3 p-3 hover:bg-stone-50 cursor-pointer border-b last:border-b-0"
:data-page-id id :data-page-title title :data-page-slug slug
:data-page-image (or feature-image "")
(if feature-image
(img :src feature-image :alt title :class "w-10 h-10 rounded-full object-cover flex-shrink-0")
(div :class "w-10 h-10 rounded-full bg-stone-200 flex-shrink-0"))
(div :class "flex-1 min-w-0"
(div :class "font-medium truncate" title)
(div :class "text-xs text-stone-500 truncate" slug))))
(defcomp ~page-search-results (&key items sentinel)
(div :class "border border-stone-200 rounded-md max-h-64 overflow-y-auto"
items sentinel))
(defcomp ~page-search-sentinel (&key url query next-page)
(div :sx-get url :sx-trigger "intersect once" :sx-swap "outerHTML"
:sx-vals (str "{\"q\": \"" query "\", \"page\": " next-page "}")
:class "p-3 text-center text-sm text-stone-400"
(i :class "fa fa-spinner fa-spin") " Loading more..."))
(defcomp ~page-search-empty (&key query)
(div :class "p-3 text-center text-stone-400 border border-stone-200 rounded-md"
(str "No pages found matching \"" query "\"")))
;; Data-driven page search results (replaces Python render_page_search_results loop)
(defcomp ~page-search-results-from-data (&key pages query has-more search-url next-page)
(if (and (not pages) query)
(~page-search-empty :query query)
(when pages
(~page-search-results
:items (<> (map (lambda (p)
(~page-search-item
:id (get p "id") :title (get p "title")
:slug (get p "slug") :feature-image (get p "feature_image")))
pages))
:sentinel (when has-more
(~page-search-sentinel :url search-url :query query :next-page next-page))))))
;; Data-driven menu nav items (replaces Python render_menu_items_nav_oob loop)
(defcomp ~blog-menu-nav-from-data (&key items nav-cls container-id arrow-cls scroll-hs)
(if (not items)
(~blog-nav-empty :wrapper-id "menu-items-nav-wrapper")
(~scroll-nav-wrapper :wrapper-id "menu-items-nav-wrapper" :container-id container-id
:arrow-cls arrow-cls
:left-hs (str "on click set #" container-id ".scrollLeft to #" container-id ".scrollLeft - 200")
:scroll-hs scroll-hs
:right-hs (str "on click set #" container-id ".scrollLeft to #" container-id ".scrollLeft + 200")
:items (<> (map (lambda (item)
(let* ((img (~img-or-placeholder :src (get item "feature_image") :alt (get item "label")
:size-cls "w-8 h-8 rounded-full object-cover flex-shrink-0")))
(if (= (get item "slug") "cart")
(~blog-nav-item-plain :href (get item "href") :selected (get item "selected")
:nav-cls nav-cls :img img :label (get item "label"))
(~blog-nav-item-link :href (get item "href") :hx-get (get item "hx_get")
:selected (get item "selected") :nav-cls nav-cls :img img :label (get item "label")))))
items))
:oob true)))