fix(ui): opacity modifiers for theme colours (bg-accent/15 etc. were never generated)

Theme colours are CSS variables, so Tailwind produced no CSS for /NN
modifiers and all tinted backgrounds were missing. Colours now mix the
variable with transparent via color-mix() for modifiers only; plain
classes keep the bare variable. Aliases for colour names used but never
defined (primary, secondary, success, warning, danger, info).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
sandrodachandClaude Opus 5.5 committed 2026-10-28 23:56:13 +01:00
1 parent a62b1893b4
commit 1fac1a80b7
1 file changed
+49 -32
+49 -32
View File
@@ -1,3 +1,11 @@
// Theme colours are CSS variables, so Tailwind cannot apply opacity modifiers (bg-accent/15) by itself.
// v() mixes the variable with transparent for a modifier; plain classes keep the bare variable, so only
// the tints depend on color-mix() support.
const v = (name) => ({ opacityValue }) =>
opacityValue === undefined || opacityValue === '1' || String(opacityValue).startsWith('var(')
? `var(${name})`
: `color-mix(in srgb, var(${name}) calc(${opacityValue} * 100%), transparent)`;
/** @type {import('tailwindcss').Config} */ /** @type {import('tailwindcss').Config} */
export default { export default {
content: ['./index.html', './src/**/*.{js,ts,jsx,tsx}'], content: ['./index.html', './src/**/*.{js,ts,jsx,tsx}'],
@@ -5,48 +13,57 @@ export default {
theme: { theme: {
extend: { extend: {
colors: { colors: {
canvas: 'var(--bg-app)', canvas: v('--bg-app'),
panel: { panel: {
DEFAULT: 'var(--bg-panel)', DEFAULT: v('--bg-panel'),
elevated: 'var(--bg-panel-elevated)', elevated: v('--bg-panel-elevated'),
hover: 'var(--bg-panel-hover)', hover: v('--bg-panel-hover'),
}, },
surface: { surface: {
DEFAULT: 'var(--bg-panel)', DEFAULT: v('--bg-panel'),
elevated: 'var(--bg-panel-elevated)', elevated: v('--bg-panel-elevated'),
hover: 'var(--bg-panel-hover)', hover: v('--bg-panel-hover'),
border: 'var(--border-color)', border: v('--border-color'),
}, },
input: 'var(--bg-input)', input: v('--bg-input'),
overlay: 'var(--bg-overlay)', overlay: v('--bg-overlay'),
code: 'var(--bg-code)', code: v('--bg-code'),
main: 'var(--text-main)', main: v('--text-main'),
muted: 'var(--text-muted)', muted: v('--text-muted'),
faint: 'var(--text-faint)', faint: v('--text-faint'),
'on-accent': 'var(--text-on-accent)', 'on-accent': v('--text-on-accent'),
accent: { accent: {
DEFAULT: 'var(--accent-primary)', DEFAULT: v('--accent-primary'),
hover: 'var(--accent-hover)', hover: v('--accent-hover'),
dim: 'var(--accent-dim)', dim: v('--accent-dim'),
border: 'var(--accent-border)', border: v('--accent-border'),
}, },
brand: { brand: {
DEFAULT: 'var(--accent-primary)', DEFAULT: v('--accent-primary'),
hover: 'var(--accent-hover)', hover: v('--accent-hover'),
dark: 'var(--accent-primary)', dark: v('--accent-primary'),
}, },
status: { status: {
ok: 'var(--color-success)', ok: v('--color-success'),
'ok-bg': 'var(--bg-success)', 'ok-bg': v('--bg-success'),
'ok-border': 'var(--border-success)', 'ok-border': v('--border-success'),
err: 'var(--color-danger)', err: v('--color-danger'),
'err-bg': 'var(--bg-danger)', 'err-bg': v('--bg-danger'),
'err-border': 'var(--border-danger)', 'err-border': v('--border-danger'),
warn: 'var(--color-warning)', warn: v('--color-warning'),
'warn-bg': 'var(--bg-warning)', 'warn-bg': v('--bg-warning'),
'warn-border': 'var(--border-warning)', 'warn-border': v('--border-warning'),
info: v('--accent-hover'),
danger: v('--color-danger'),
}, },
border: 'var(--border-color)', border: v('--border-color'),
// Aliases for names used in components (e.g. avatar initials), mapped to theme colours
primary: v('--accent-primary'),
secondary: v('--text-muted'),
info: v('--accent-hover'),
success: v('--color-success'),
warning: v('--color-warning'),
danger: v('--color-danger'),
}, },
borderColor: { borderColor: {
DEFAULT: 'var(--border-color)', DEFAULT: 'var(--border-color)',