Decision Records
ADR-0008: Design tokens and Lucide iconography for the pickers
Architecture Decision Record
- Status: accepted
- Date: 2026-07-09
- Deciders: project owner
Context
Both pickers shipped functional but undesigned. The Avalonia picker was stock Fluent โ system brushes, the OS accent, emoji as icons (๐ ๐ ๐), opacity-based hierarchy โ and the webui was default-Tailwind zinc with a solid violet-fill selection that crushed contrast. Nothing tied the two front-ends together visually, and nothing signaled which filter was active.
Decision
- One shared palette for both pickers: the Tailwind zinc neutral ramp plus a
single violet accent (
#7c3aedlight /#a78bfadark), matching the product gradient in the catalog manifest. No org-brand adoption (the Aylith copper system stays on aylith.com surfaces). - Selection is an accent-tinted surface (~10โ15% alpha) with a small accent edge โ never a solid accent fill with inverted text.
- Avalonia gets a token layer, not a retemplate.
Styles/Tokens.axamldefinesClip*brushes in Light/Dark theme dictionaries and overrides theSystemAccentColorfamily so stock Fluent controls (focus, carets, ComboBox highlights) recolor for free;Styles/Controls.axamladds class-based styles (pill,accent,groupHeader,meta,lucide). Retemplating Fluent controls was rejected: it costs perf and breaks across Avalonia upgrades. - Icons are Lucide 1.23.0 in both pickers. The webui deep-imports
lucide-solid/icons/*(only used icons bundle); the Avalonia picker carries the same geometry converted toStreamGeometrypath data inui/Icons.cs(one shared frozen instance per icon, zero per-row allocation). Lucide is stroke-based, so Avalonia renders icons as strokedPath(classlucide, 1.75 thickness, round caps) โ a filledPathIconrenders them wrong.webui/src/lib/icons.tsandui/Icons.csare the paired parity surfaces. - Search matches highlight in amber (the old WPF app's convention), via a
custom
HighlightedTextBlockin Avalonia (empty-query fast path assigns plainText, keeping the warm-show path allocation-free) and an indexOf-split<Highlighted>component in Solid.
Consequences
- The pickers read as one product: same accent, same icons, same row anatomy (kind icon ยท preview ยท meta line ยท pin), same highlight color.
- Kind icons re-map in exactly two files; the icon set is pinned to lucide 1.23.0 in both, so a future icon refresh is a deliberate, versioned change.
- The warm show-cycle is untouched: tokens are resolved brushes, icon geometry
is static, and the highlight control's reset path allocates nothing
(verified against
bench/baseline.jsonafter the restyle). - Trade-off: the Avalonia icon set is transcribed (generated from the lucide SVGs by script), so adding an icon there is a small manual step rather than an import.