refactor(dev): dogfood framework CSS in theme adapter panel

Replace all inline styles in theme-adapter.js with framework classes.
The panel now uses its own tokens (var(--bg-1), var(--fg-0), etc.) so
it visually adapts when you change theme colors — true dogfooding.

New framework components added to fill gaps:
- popover.css — fixed-position floating panel (.popover, .popover-br)
- chip.css + chip.cljc — selectable preset buttons (.chip, .chip-active)
- swatch.css — color preview strips (.swatch-row, .swatch)
- button.css — icon-only buttons (.btn-icon, .btn-icon-round)
- card.css — sectioned card variant (.card-flush, .card-section)
- utilities.css — text/flex helpers (.text-xs, .font-semibold, .flex-1, etc.)

Theme adapter JS shrunk from 340 to 250 lines by removing the 60-line
inline style object and applyStyle() helper.
This commit is contained in:
Florian Schroedl
2026-03-11 16:53:08 +01:00
parent 59d46700bc
commit 9f3ebe453f
10 changed files with 300 additions and 186 deletions

View File

@@ -78,6 +78,24 @@ a.btn-link {
line-height: var(--size-6);
}
.btn-icon {
padding: var(--size-2);
line-height: 1;
aspect-ratio: 1;
}
.btn-icon.btn-sm {
padding: var(--size-1);
}
.btn-icon.btn-lg {
padding: var(--size-3);
}
.btn-icon-round {
border-radius: 9999px;
}
.btn:disabled {
opacity: 0.5;
cursor: not-allowed;

View File

@@ -11,6 +11,19 @@
padding: var(--size-6);
}
.card-flush {
padding: 0;
gap: 0;
}
.card-section {
padding: var(--size-3) var(--size-4);
}
.card-section + .card-section {
border-top: var(--border-0);
}
.card-header {
display: flex;
flex-direction: column;

54
src/ui/chip.cljc Normal file
View File

@@ -0,0 +1,54 @@
(ns ui.chip
(:require [clojure.string :as str]))
#?(:squint (defn- kw-name [s] s)
:cljs (defn- kw-name [s] (name s))
:clj (defn- kw-name [s] (name s)))
(defn chip-class-list
"Returns a vector of CSS class strings for a chip."
[{:keys [active]}]
(cond-> ["chip"]
active (conj "chip-active")))
(defn chip-classes
"Returns a space-joined class string."
[opts]
(str/join " " (chip-class-list opts)))
(defn chip
"A small selectable button for tags, filters, presets.
Props: :active, :dot-color, :on-click, :class, :attrs"
[{:keys [active dot-color on-click class attrs] :as _props} & children]
#?(:squint
(let [classes (cond-> (chip-classes {:active active})
class (str " " class))
base-attrs (cond-> (merge {:class classes} attrs)
on-click (assoc :on-click on-click))
dot (when dot-color
[:span {:class "chip-dot" :style {"background" dot-color}}])]
(cond-> [:button base-attrs]
dot (conj dot)
true (into children)))
:cljs
(let [cls (chip-class-list {:active active})
classes (cond-> cls class (conj class))
base-attrs (cond-> (merge {:class classes} attrs)
on-click (assoc :on {:click on-click}))
dot (when dot-color
[:span {:class ["chip-dot"] :style {:background dot-color}}])]
(cond-> [:button base-attrs]
dot (conj dot)
true (into children)))
:clj
(let [classes (cond-> (chip-classes {:active active})
class (str " " class))
base-attrs (merge {:class classes} attrs)
dot (when dot-color
[:span {:class "chip-dot"
:style (str "background:" dot-color)}])]
(cond-> [:button base-attrs]
dot (conj dot)
true (into children)))))

37
src/ui/chip.css Normal file
View File

@@ -0,0 +1,37 @@
/* ── Chip ───────────────────────────────────────────────────────── */
/* Small selectable buttons for tags, filters, presets. */
.chip {
display: inline-flex;
align-items: center;
gap: var(--size-1);
padding: var(--size-1) var(--size-2);
font-size: var(--font-xs);
font-weight: 500;
line-height: var(--size-4);
border: var(--border-0);
border-radius: var(--radius-sm);
background: transparent;
color: var(--fg-1);
cursor: pointer;
font-family: inherit;
transition: background 150ms ease, border-color 150ms ease, color 150ms ease;
}
.chip:hover:not(.chip-active) {
background: var(--bg-2);
}
.chip-active {
background: var(--accent);
border-color: var(--accent);
color: var(--fg-on-accent);
}
.chip-dot {
display: inline-block;
width: 6px;
height: 6px;
border-radius: 9999px;
flex-shrink: 0;
}

12
src/ui/popover.css Normal file
View File

@@ -0,0 +1,12 @@
/* ── Popover ────────────────────────────────────────────────────── */
/* Fixed-position floating panel. Combine with a corner class. */
.popover {
position: fixed;
z-index: 9999;
}
.popover-br { bottom: var(--size-4); right: var(--size-4); }
.popover-bl { bottom: var(--size-4); left: var(--size-4); }
.popover-tr { top: var(--size-4); right: var(--size-4); }
.popover-tl { top: var(--size-4); left: var(--size-4); }

13
src/ui/swatch.css Normal file
View File

@@ -0,0 +1,13 @@
/* ── Swatch ─────────────────────────────────────────────────────── */
/* Color preview strip — a row of small colored boxes. */
.swatch-row {
display: flex;
gap: 2px;
}
.swatch {
flex: 1;
height: var(--size-4);
border-radius: var(--radius-sm);
}

View File

@@ -37,6 +37,19 @@
.mb-6 { margin-bottom: var(--size-6); }
.p-4 { padding: var(--size-4); }
.flex-1 { flex: 1; min-width: 0; }
.shrink-0 { flex-shrink: 0; }
.flex-row { flex-direction: row; }
.flex-wrap { flex-wrap: wrap; }
.text-xs { font-size: var(--font-xs); }
.text-sm { font-size: var(--font-sm); }
.text-right { text-align: right; }
.font-semibold { font-weight: 600; }
.font-mono { font-family: ui-monospace, 'JetBrains Mono', monospace; }
.uppercase { text-transform: uppercase; }
.tracking-wide { letter-spacing: 0.05em; }
.w-full { width: 100%; }
.sr-only {
position: absolute;