chore: add bb check-dev script for pre-commit server verification

Babashka script that checks all ui-dev tmux panes for compile errors,
verifies hiccup serves content, ensures squint .mjs files aren't
truncated, and confirms replicant JS is compiled. Replaces the manual
tmux capture-pane + curl checks documented in AGENTS.md.
This commit is contained in:
Florian Schroedl
2026-03-05 19:20:27 +01:00
parent 4f42dce649
commit 828d467226
6 changed files with 253 additions and 45 deletions

View File

@@ -72,9 +72,10 @@
;; ── Helpers ─────────────────────────────────────────────────────────
(defn section [title & children]
[:section {:style "margin-bottom: 2.5rem;"}
[:h3 {:style "color: var(--fg-1); margin-bottom: 1rem; border-bottom: var(--border-0); padding-bottom: 0.5rem;"} title]
(into [:div {:style "display: flex; flex-direction: column; gap: 1rem;"}] children)])
(let [id (str/lower-case title)]
[:section {:id id :style "margin-bottom: 2.5rem;"}
[:h3 {:style "color: var(--fg-1); margin-bottom: 1rem; border-bottom: var(--border-0); padding-bottom: 0.5rem;"} title]
(into [:div {:style "display: flex; flex-direction: column; gap: 1rem;"}] children)]))
;; ── Component Demos ─────────────────────────────────────────────────
@@ -370,6 +371,28 @@
;; ── Navigation Data ─────────────────────────────────────────────────
(def component-nav
[{:title "General"
:items [{:label "Button" :anchor "button"}
{:label "Badge" :anchor "badge"}
{:label "Card" :anchor "card"}]}
{:title "Forms"
:items [{:label "Form" :anchor "form"}
{:label "Switch" :anchor "switch"}]}
{:title "Data Display"
:items [{:label "Table" :anchor "table"}
{:label "Accordion" :anchor "accordion"}
{:label "Progress" :anchor "progress"}]}
{:title "Feedback"
:items [{:label "Alert" :anchor "alert"}
{:label "Dialog" :anchor "dialog"}
{:label "Spinner" :anchor "spinner"}
{:label "Skeleton" :anchor "skeleton"}
{:label "Tooltip" :anchor "tooltip"}]}
{:title "Navigation"
:items [{:label "Breadcrumb" :anchor "breadcrumb"}
{:label "Pagination" :anchor "pagination"}]}])
(def nav-items
[{:id :components :label "Components" :icon-name :package :href "/"}
{:id :icons :label "Icons" :icon-name :image :href "/icons"}
@@ -402,6 +425,13 @@
{:href href :icon-name icon-name :active (= id active-page)}
label))))
(sidebar/sidebar-separator)
(sidebar/sidebar-group {:label "Components"}
(for [{:keys [title items]} component-nav]
(sidebar/sidebar-collapsible {:title title :open true}
(apply sidebar/sidebar-menu {}
(for [{:keys [label anchor]} items]
(sidebar/sidebar-menu-item {:href (str "/#" anchor)} label))))))
(sidebar/sidebar-separator)
(sidebar/sidebar-group {:label "Targets"}
(apply sidebar/sidebar-menu {}
(for [{:keys [label port active]} (make-targets own-port)]

View File

@@ -1,5 +1,6 @@
(ns dev.replicant
(:require [replicant.dom :as d]
(:require [clojure.string :as str]
[replicant.dom :as d]
[ui.button :as button]
[ui.alert :as alert]
[ui.badge :as badge]
@@ -25,10 +26,11 @@
;; ── Helpers ─────────────────────────────────────────────────────────
(defn section [title & children]
[:section {:style {:margin-bottom "2.5rem"}}
[:h3 {:style {:color "var(--fg-1)" :margin-bottom "1rem"
:border-bottom "var(--border-0)" :padding-bottom "0.5rem"}} title]
(into [:div {:style {:display "flex" :flex-direction "column" :gap "1rem"}}] children)])
(let [id (str/lower-case title)]
[:section {:id id :style {:margin-bottom "2.5rem"}}
[:h3 {:style {:color "var(--fg-1)" :margin-bottom "1rem"
:border-bottom "var(--border-0)" :padding-bottom "0.5rem"}} title]
(into [:div {:style {:display "flex" :flex-direction "column" :gap "1rem"}}] children)]))
(defn page-header [title subtitle]
[:div {:style {:margin-bottom "2rem"}}
@@ -326,6 +328,28 @@
;; ── Navigation ──────────────────────────────────────────────────────
(def component-nav
[{:title "General"
:items [{:label "Button" :anchor "button"}
{:label "Badge" :anchor "badge"}
{:label "Card" :anchor "card"}]}
{:title "Forms"
:items [{:label "Form" :anchor "form"}
{:label "Switch" :anchor "switch"}]}
{:title "Data Display"
:items [{:label "Table" :anchor "table"}
{:label "Accordion" :anchor "accordion"}
{:label "Progress" :anchor "progress"}]}
{:title "Feedback"
:items [{:label "Alert" :anchor "alert"}
{:label "Dialog" :anchor "dialog"}
{:label "Spinner" :anchor "spinner"}
{:label "Skeleton" :anchor "skeleton"}
{:label "Tooltip" :anchor "tooltip"}]}
{:title "Navigation"
:items [{:label "Breadcrumb" :anchor "breadcrumb"}
{:label "Pagination" :anchor "pagination"}]}])
(def nav-items
[{:id :components :label "Components" :icon-name :package}
{:id :icons :label "Icons" :icon-name :image}
@@ -335,6 +359,16 @@
(fn [_e]
(reset! !page page-id)))
(defn navigate-to-section! [anchor]
(fn [_e]
(when (not= @!page :components)
(reset! !page :components))
(js/setTimeout
(fn []
(when-let [el (.getElementById js/document anchor)]
(.scrollIntoView el #js {:behavior "smooth" :block "start"})))
50)))
(defn toggle-theme! [_e]
(let [el (.-documentElement js/document)
current (.. el -dataset -theme)]
@@ -378,6 +412,13 @@
:on-click (navigate! id)}
label))))
(sidebar/sidebar-separator)
(sidebar/sidebar-group {:label "Components"}
(for [{:keys [title items]} component-nav]
(sidebar/sidebar-collapsible {:title title :open true}
(apply sidebar/sidebar-menu {}
(for [{:keys [label anchor]} items]
(sidebar/sidebar-menu-item {:on-click (navigate-to-section! anchor)} label))))))
(sidebar/sidebar-separator)
(sidebar/sidebar-group {:label "Targets"}
(apply sidebar/sidebar-menu {}
(for [{:keys [label port active]} (make-targets)]

View File

@@ -42,10 +42,11 @@
(.removeAttribute layout "data-sidebar-open")))
(defn section [title & children]
[:section {:style {"margin-bottom" "2.5rem"}}
[:h3 {:style {"color" "var(--fg-1)" "margin-bottom" "1rem"
"border-bottom" "var(--border-0)" "padding-bottom" "0.5rem"}} title]
(into [:div {:style {"display" "flex" "flex-direction" "column" "gap" "1rem"}}] children)])
(let [id (.toLowerCase title)]
[:section {:id id :style {"margin-bottom" "2.5rem"}}
[:h3 {:style {"color" "var(--fg-1)" "margin-bottom" "1rem"
"border-bottom" "var(--border-0)" "padding-bottom" "0.5rem"}} title]
(into [:div {:style {"display" "flex" "flex-direction" "column" "gap" "1rem"}}] children)]))
(defn page-header [title subtitle]
[:div {:style {"margin-bottom" "2rem"}}
@@ -353,6 +354,28 @@
;; ── Navigation ──────────────────────────────────────────────────────
(def component-nav
[{:title "General"
:items [{:label "Button" :anchor "button"}
{:label "Badge" :anchor "badge"}
{:label "Card" :anchor "card"}]}
{:title "Forms"
:items [{:label "Form" :anchor "form"}
{:label "Switch" :anchor "switch"}]}
{:title "Data Display"
:items [{:label "Table" :anchor "table"}
{:label "Accordion" :anchor "accordion"}
{:label "Progress" :anchor "progress"}]}
{:title "Feedback"
:items [{:label "Alert" :anchor "alert"}
{:label "Dialog" :anchor "dialog"}
{:label "Spinner" :anchor "spinner"}
{:label "Skeleton" :anchor "skeleton"}
{:label "Tooltip" :anchor "tooltip"}]}
{:title "Navigation"
:items [{:label "Breadcrumb" :anchor "breadcrumb"}
{:label "Pagination" :anchor "pagination"}]}])
(def nav-items
[{:id "components" :label "Components" :icon-name "package"}
{:id "icons" :label "Icons" :icon-name "image"}
@@ -363,6 +386,17 @@
(reset! !page page-id)
(render!)))
(defn navigate-to-section! [anchor]
(fn [_e]
(when (not= @!page "components")
(reset! !page "components")
(render!))
(js/setTimeout
(fn []
(when-let [el (js/document.getElementById anchor)]
(.scrollIntoView el {"behavior" "smooth" "block" "start"})))
50)))
;; ── App Shell ───────────────────────────────────────────────────────
(defn own-port []
@@ -390,6 +424,15 @@
label))
nav-items)))
(sidebar/sidebar-separator)
(into (sidebar/sidebar-group {:label "Components"})
(map (fn [{:keys [title items]}]
(sidebar/sidebar-collapsible {:title title :open true}
(into (sidebar/sidebar-menu {})
(map (fn [{:keys [label anchor]}]
(sidebar/sidebar-menu-item {:on-click (navigate-to-section! anchor)} label))
items))))
component-nav))
(sidebar/sidebar-separator)
(sidebar/sidebar-group {:label "Targets"}
(into (sidebar/sidebar-menu {})
(map (fn [{:keys [label port active]}]