;; Menu item form and page search components (defcomp ~menu_items/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 ~menu_items/page-search-results (&key items sentinel) (div :class "border border-stone-200 rounded-md max-h-64 overflow-y-auto" items sentinel)) (defcomp ~menu_items/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 ~menu_items/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 ~menu_items/page-search-results-from-data (&key pages query has-more search-url next-page) (if (and (not pages) query) (~menu_items/page-search-empty :query query) (when pages (~menu_items/page-search-results :items (<> (map (lambda (p) (~menu_items/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 (~menu_items/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 ~menu_items/menu-nav-from-data (&key items nav-cls container-id arrow-cls scroll-hs) (if (not items) (~shared:nav/blog-nav-empty :wrapper-id "menu-items-nav-wrapper") (~shared:misc/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 (~shared:misc/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") (~shared:nav/blog-nav-item-plain :href (get item "href") :selected (get item "selected") :nav-cls nav-cls :img img :label (get item "label")) (~shared:nav/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)))