All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 1m13s
Move 24 defcomp definitions from Python string constants in components.py to 7 grouped .sexp files under shared/sexp/templates/. Add load_sexp_dir() to jinja_bridge.py for file-based loading. Migrate events and market link-card fragment handlers from render_template to sexp. Delete 9 superseded Jinja HTML fragment templates. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
165 lines
8.7 KiB
Common Lisp
165 lines
8.7 KiB
Common Lisp
(defcomp ~app-shell (&key title asset-url meta-html body-html body-end-html)
|
|
(<>
|
|
(raw! "<!doctype html>")
|
|
(html :lang "en"
|
|
(head
|
|
(meta :charset "utf-8")
|
|
(meta :name "viewport" :content "width=device-width, initial-scale=1")
|
|
(meta :name "robots" :content "index,follow")
|
|
(meta :name "theme-color" :content "#ffffff")
|
|
(title title)
|
|
(when meta-html (raw! meta-html))
|
|
(style "@media (min-width: 768px) { .js-mobile-sentinel { display:none !important; } }")
|
|
(link :rel "stylesheet" :type "text/css" :href (str asset-url "/styles/basics.css"))
|
|
(link :rel "stylesheet" :type "text/css" :href (str asset-url "/styles/cards.css"))
|
|
(link :rel "stylesheet" :type "text/css" :href (str asset-url "/styles/blog-content.css"))
|
|
(script :src "https://unpkg.com/htmx.org@2.0.8")
|
|
(script :src "https://unpkg.com/hyperscript.org@0.9.12")
|
|
(script :src "https://cdn.tailwindcss.com")
|
|
(link :rel "stylesheet" :href (str asset-url "/fontawesome/css/all.min.css"))
|
|
(link :rel "stylesheet" :href (str asset-url "/fontawesome/css/v4-shims.min.css"))
|
|
(link :href "https://unpkg.com/prismjs/themes/prism.css" :rel "stylesheet")
|
|
(script :src "https://unpkg.com/prismjs/prism.js")
|
|
(script :src "https://unpkg.com/prismjs/components/prism-javascript.min.js")
|
|
(script :src "https://unpkg.com/prismjs/components/prism-python.min.js")
|
|
(script :src "https://unpkg.com/prismjs/components/prism-bash.min.js")
|
|
(script :src "https://cdn.jsdelivr.net/npm/sweetalert2@11")
|
|
(script "if(matchMedia('(hover:hover) and (pointer:fine)').matches){document.documentElement.classList.add('hover-capable')}")
|
|
(script "document.addEventListener('click',function(e){var t=e.target.closest('[data-close-details]');if(!t)return;var d=t.closest('details');if(d)d.removeAttribute('open')})")
|
|
(style
|
|
"details[data-toggle-group=\"mobile-panels\"]>summary{list-style:none}"
|
|
"details[data-toggle-group=\"mobile-panels\"]>summary::-webkit-details-marker{display:none}"
|
|
"@media(min-width:768px){.nav-group:focus-within .submenu,.nav-group:hover .submenu{display:block}}"
|
|
"img{max-width:100%;height:auto}"
|
|
".clamp-2{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}"
|
|
".clamp-3{display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden}"
|
|
".no-scrollbar::-webkit-scrollbar{display:none}.no-scrollbar{-ms-overflow-style:none;scrollbar-width:none}"
|
|
"details.group{overflow:hidden}details.group>summary{list-style:none}details.group>summary::-webkit-details-marker{display:none}"
|
|
".htmx-indicator{display:none}.htmx-request .htmx-indicator{display:inline-flex}"
|
|
".js-wrap.open .js-pop{display:block}.js-wrap.open .js-backdrop{display:block}"))
|
|
(body :class "bg-stone-50 text-stone-900"
|
|
(raw! body-html)
|
|
(when body-end-html (raw! body-end-html))
|
|
(script :src (str asset-url "/scripts/body.js"))))))
|
|
|
|
(defcomp ~app-layout (&key title asset-url meta-html menu-colour
|
|
header-rows-html menu-html
|
|
filter-html aside-html content-html
|
|
body-end-html)
|
|
(let* ((colour (or menu-colour "sky")))
|
|
(~app-shell :title (or title "Rose Ash") :asset-url asset-url
|
|
:meta-html meta-html :body-end-html body-end-html
|
|
:body-html (str
|
|
"<div class=\"max-w-screen-2xl mx-auto py-1 px-1\">"
|
|
"<div class=\"w-full\">"
|
|
"<details class=\"group/root p-2\" data-toggle-group=\"mobile-panels\">"
|
|
"<summary>"
|
|
"<header class=\"z-50\">"
|
|
"<div id=\"root-header-summary\" class=\"flex items-start gap-2 p-1 bg-" colour "-500\">"
|
|
"<div class=\"flex flex-col w-full items-center\">"
|
|
header-rows-html
|
|
"</div>"
|
|
"</div>"
|
|
"</header>"
|
|
"</summary>"
|
|
"<div id=\"root-menu\" hx-swap-oob=\"outerHTML\" class=\"md:hidden\">"
|
|
(or menu-html "")
|
|
"</div>"
|
|
"</details>"
|
|
"</div>"
|
|
"<div id=\"filter\">"
|
|
(or filter-html "")
|
|
"</div>"
|
|
"<main id=\"root-panel\" class=\"max-w-full\">"
|
|
"<div class=\"md:min-h-0\">"
|
|
"<div class=\"flex flex-row md:h-full md:min-h-0\">"
|
|
"<aside id=\"aside\" class=\"hidden md:flex md:flex-col max-w-xs md:h-full md:min-h-0 mr-3\">"
|
|
(or aside-html "")
|
|
"</aside>"
|
|
"<section id=\"main-panel\" class=\"flex-1 md:h-full md:min-h-0 overflow-y-auto overscroll-contain js-grid-viewport\">"
|
|
(or content-html "")
|
|
"<div class=\"pb-8\"></div>"
|
|
"</section>"
|
|
"</div>"
|
|
"</div>"
|
|
"</main>"
|
|
"</div>"))))
|
|
|
|
(defcomp ~oob-response (&key oobs-html filter-html aside-html menu-html content-html)
|
|
(<>
|
|
(when oobs-html (raw! oobs-html))
|
|
(div :id "filter" :hx-swap-oob "outerHTML"
|
|
(when filter-html (raw! filter-html)))
|
|
(aside :id "aside" :hx-swap-oob "outerHTML"
|
|
:class "hidden md:flex md:flex-col max-w-xs md:h-full md:min-h-0 mr-3"
|
|
(when aside-html (raw! aside-html)))
|
|
(div :id "root-menu" :hx-swap-oob "outerHTML" :class "md:hidden"
|
|
(when menu-html (raw! menu-html)))
|
|
(section :id "main-panel"
|
|
:class "flex-1 md:h-full md:min-h-0 overflow-y-auto overscroll-contain js-grid-viewport"
|
|
(when content-html (raw! content-html)))))
|
|
|
|
(defcomp ~header-row (&key cart-mini-html blog-url site-title
|
|
nav-tree-html auth-menu-html nav-panel-html
|
|
settings-url is-admin oob hamburger-html)
|
|
(<>
|
|
(div :id "root-row"
|
|
:hx-swap-oob (if oob "outerHTML" nil)
|
|
:class "flex flex-col items-center md:flex-row justify-center md:justify-between w-full p-1 bg-sky-500"
|
|
(div :class "w-full flex flex-row items-top"
|
|
(when cart-mini-html (raw! cart-mini-html))
|
|
(div :class "font-bold text-5xl flex-1"
|
|
(a :href (or blog-url "/") :class "flex justify-center md:justify-start"
|
|
(h1 (or site-title ""))))
|
|
(nav :class "hidden md:flex gap-4 text-sm ml-2 justify-end items-center flex-0"
|
|
(when nav-tree-html (raw! nav-tree-html))
|
|
(when auth-menu-html (raw! auth-menu-html))
|
|
(when nav-panel-html (raw! nav-panel-html))
|
|
(when (and is-admin settings-url)
|
|
(a :href settings-url :class "justify-center cursor-pointer flex flex-row items-center gap-2 rounded bg-stone-200 text-black p-3"
|
|
(i :class "fa fa-cog" :aria-hidden "true"))))
|
|
(when hamburger-html (raw! hamburger-html))))
|
|
(div :class "block md:hidden text-md font-bold"
|
|
(when auth-menu-html (raw! auth-menu-html)))))
|
|
|
|
(defcomp ~menu-row (&key id level colour link-href link-label link-label-html icon
|
|
hx-select nav-html child-id child-html oob)
|
|
(let* ((c (or colour "sky"))
|
|
(lv (or level 1))
|
|
(shade (str (- 500 (* lv 100)))))
|
|
(<>
|
|
(div :id id
|
|
:hx-swap-oob (if oob "outerHTML" nil)
|
|
:class (str "flex flex-col items-center md:flex-row justify-center md:justify-between w-full p-1 bg-" c "-" shade)
|
|
(div :class "relative nav-group"
|
|
(a :href link-href
|
|
:hx-get link-href
|
|
:hx-target "#main-panel"
|
|
:hx-select (or hx-select "#main-panel")
|
|
:hx-swap "outerHTML"
|
|
:hx-push-url "true"
|
|
:class "w-full whitespace-normal flex items-center gap-2 font-bold text-2xl px-3 py-2"
|
|
(when icon (i :class icon :aria-hidden "true"))
|
|
(if link-label-html (raw! link-label-html)
|
|
(when link-label (div link-label)))))
|
|
(when nav-html
|
|
(nav :class "hidden md:flex gap-4 text-sm ml-2 justify-end items-center flex-0"
|
|
(raw! nav-html))))
|
|
(when child-id
|
|
(div :id child-id :class "flex flex-col w-full items-center"
|
|
(when child-html (raw! child-html)))))))
|
|
|
|
(defcomp ~nav-link (&key href hx-select label icon aclass select-colours)
|
|
(div :class "relative nav-group"
|
|
(a :href href
|
|
:hx-get href
|
|
:hx-target "#main-panel"
|
|
:hx-select (or hx-select "#main-panel")
|
|
:hx-swap "outerHTML"
|
|
:hx-push-url "true"
|
|
:class (or aclass
|
|
(str "justify-center cursor-pointer flex flex-row items-center gap-2 rounded bg-stone-200 text-black p-3 "
|
|
(or select-colours "")))
|
|
(when icon (i :class icon :aria-hidden "true"))
|
|
(when label (span label)))))
|