migrate accent colours from HSL to oklch, inject theme into admin

Phase 1: Replace hex_to_hsl with hex_to_oklch in CSSGenerator, output
--t-accent-l/c/h instead of --t-accent-h/s/l. All 46 HSL accent
references across theme-semantic.css, theme-layer2-attributes.css, and
shop/components.css replaced with oklch/color-mix equivalents. Dead
style*= attribute selectors for button variants replaced with proper
class-based selectors. Added color-scheme: light/dark to mood output.

Phase 2: Add LoadTheme plug to admin pipeline, extend AdminLayoutHook
with theme_settings and generated_css assigns, add font preloads and
generated CSS injection to admin_root.html.heex. No visual changes to
admin yet — .themed wrapper added in next phase.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
jamey
2026-02-20 23:53:42 +00:00
parent eb65b11e4d
commit 285aafa0b5
10 changed files with 169 additions and 115 deletions

View File

@@ -13,21 +13,19 @@
color: var(--t-text-primary);
font-family: var(--t-font-body);
/* Accent color - HSL components set dynamically by CSS generator */
--t-accent-h: 24;
--t-accent-s: 95%;
--t-accent-l: 53%;
/* Accent colour — oklch components set dynamically by CSSGenerator */
--t-accent-l: 65%;
--t-accent-c: 0.2;
--t-accent-h: 47;
--t-accent: hsl(var(--t-accent-h) var(--t-accent-s) var(--t-accent-l));
--t-accent-hover: hsl(var(--t-accent-h) var(--t-accent-s) calc(var(--t-accent-l) - 8%));
--t-accent-subtle: hsl(var(--t-accent-h) 40% 95%);
--t-accent-ring: hsl(var(--t-accent-h) var(--t-accent-s) var(--t-accent-l) / 0.4);
--t-accent: oklch(var(--t-accent-l) var(--t-accent-c) var(--t-accent-h));
--t-accent-hover: color-mix(in oklch, var(--t-accent) 85%, black);
--t-accent-subtle: color-mix(in oklch, var(--t-accent) 8%, var(--t-surface-base));
--t-accent-ring: oklch(var(--t-accent-l) var(--t-accent-c) var(--t-accent-h) / 0.4);
/* WCAG AA compliant accent variants for better contrast */
/* Darker accent for text on light backgrounds (4.5:1 with white) */
--t-accent-text: hsl(var(--t-accent-h) var(--t-accent-s) 38%);
/* Darker accent for button backgrounds to ensure 4.5:1 with white text */
--t-accent-button: hsl(var(--t-accent-h) var(--t-accent-s) 42%);
--t-accent-text: color-mix(in oklch, var(--t-accent) 80%, black);
--t-accent-button: color-mix(in oklch, var(--t-accent) 85%, black);
/* Secondary colors */
--t-secondary-accent: #ea580c;
@@ -117,7 +115,7 @@
/* Dark mode accent-subtle override */
&[data-mood="dark"] {
--t-accent-subtle: hsl(var(--t-accent-h) 30% 15%);
--t-accent-subtle: color-mix(in oklch, var(--t-accent) 15%, black);
}
}
@@ -137,7 +135,7 @@
& textarea:focus-visible,
& [tabindex]:focus-visible,
& details summary:focus-visible {
outline: 2px solid hsl(var(--t-accent-h) var(--t-accent-s) var(--t-accent-l));
outline: 2px solid var(--t-accent);
outline-offset: 2px;
}
@@ -230,9 +228,9 @@
}
&.active {
background-color: hsl(var(--t-accent-h) var(--t-accent-s) var(--t-accent-l) / 0.12);
color: hsl(var(--t-accent-h) var(--t-accent-s) calc(var(--t-accent-l) - 15%));
border-color: hsl(var(--t-accent-h) var(--t-accent-s) var(--t-accent-l) / 0.25);
background-color: color-mix(in oklch, var(--t-accent) 12%, transparent);
color: color-mix(in oklch, var(--t-accent) 80%, black);
border-color: color-mix(in oklch, var(--t-accent) 25%, transparent);
font-weight: 600;
}
}
@@ -273,7 +271,7 @@
top: -100px;
left: 50%;
transform: translateX(-50%);
background: hsl(var(--t-accent-h) var(--t-accent-s) var(--t-accent-l));
background: var(--t-accent);
color: var(--t-text-inverse);
padding: 0.75rem 1.5rem;
z-index: 9999;
@@ -312,5 +310,5 @@
/* Active nav underline — must stay unlayered to match the base border above */
.shop-nav [aria-current="page"] {
border-bottom-color: hsl(var(--t-accent-h) var(--t-accent-s) var(--t-accent-l));
border-bottom-color: var(--t-accent);
}