mirror of
https://github.com/danny-avila/LibreChat.git
synced 2026-08-04 14:57:42 +00:00
refactor: unify Tailwind color tokens into a single source
Both the client SPA and @librechat/client Tailwind configs now consume one createTailwindColors() map, eliminating config drift. Fixes the package-side build along the way: shadcn tokens are wrapped in hsl(), the broken opacity helper is removed, and text-destructive/border-destructive/switch-unchecked plus the gray/green palettes are included.
This commit is contained in:
parent
cdb60e74c2
commit
837ddedb95
2 changed files with 121 additions and 162 deletions
|
|
@ -1,4 +1,7 @@
|
|||
// const { fontFamily } = require('tailwindcss/defaultTheme');
|
||||
const {
|
||||
createTailwindColors,
|
||||
} = require('../packages/client/src/theme/utils/createTailwindColors.js');
|
||||
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
|
|
@ -63,101 +66,7 @@ module.exports = {
|
|||
'slide-out-right': 'slide-out-right 300ms cubic-bezier(0.25, 0.1, 0.25, 1)',
|
||||
'shortcut-shake': 'shortcut-shake 0.25s ease-in-out',
|
||||
},
|
||||
colors: {
|
||||
gray: {
|
||||
20: '#ececf1',
|
||||
50: '#f7f7f8',
|
||||
100: '#ececec',
|
||||
200: '#e3e3e3',
|
||||
300: '#cdcdcd',
|
||||
400: '#999696',
|
||||
500: '#595959',
|
||||
600: '#424242',
|
||||
700: '#2f2f2f',
|
||||
800: '#212121',
|
||||
850: '#171717',
|
||||
900: '#0d0d0d',
|
||||
},
|
||||
green: {
|
||||
50: '#f1f9f7',
|
||||
100: '#def2ed',
|
||||
200: '#a6e5d6',
|
||||
300: '#6dc8b9',
|
||||
400: '#41a79d',
|
||||
500: '#10a37f',
|
||||
550: '#349072',
|
||||
600: '#126e6b',
|
||||
700: '#0a4f53',
|
||||
800: '#06373e',
|
||||
900: '#031f29',
|
||||
},
|
||||
'brand-purple': 'var(--brand-purple)',
|
||||
presentation: 'var(--presentation)',
|
||||
'text-primary': 'var(--text-primary)',
|
||||
'text-secondary': 'var(--text-secondary)',
|
||||
'text-secondary-alt': 'var(--text-secondary-alt)',
|
||||
'text-tertiary': 'var(--text-tertiary)',
|
||||
'text-warning': 'var(--text-warning)',
|
||||
'text-destructive': 'var(--text-destructive)',
|
||||
'ring-primary': 'var(--ring-primary)',
|
||||
'header-primary': 'var(--header-primary)',
|
||||
'header-hover': 'var(--header-hover)',
|
||||
'header-button-hover': 'var(--header-button-hover)',
|
||||
'surface-active': 'var(--surface-active)',
|
||||
'surface-active-alt': 'var(--surface-active-alt)',
|
||||
'surface-hover': 'var(--surface-hover)',
|
||||
'surface-hover-alt': 'var(--surface-hover-alt)',
|
||||
'surface-primary': 'var(--surface-primary)',
|
||||
'surface-primary-alt': 'var(--surface-primary-alt)',
|
||||
'surface-primary-contrast': 'var(--surface-primary-contrast)',
|
||||
'surface-secondary': 'var(--surface-secondary)',
|
||||
'surface-secondary-alt': 'var(--surface-secondary-alt)',
|
||||
'surface-tertiary': 'var(--surface-tertiary)',
|
||||
'surface-tertiary-alt': 'var(--surface-tertiary-alt)',
|
||||
'surface-dialog': 'var(--surface-dialog)',
|
||||
'surface-submit': 'var(--surface-submit)',
|
||||
'surface-submit-hover': 'var(--surface-submit-hover)',
|
||||
'surface-destructive': 'var(--surface-destructive)',
|
||||
'surface-destructive-hover': 'var(--surface-destructive-hover)',
|
||||
'surface-chat': 'var(--surface-chat)',
|
||||
'border-light': 'var(--border-light)',
|
||||
'border-medium': 'var(--border-medium)',
|
||||
'border-medium-alt': 'var(--border-medium-alt)',
|
||||
'border-heavy': 'var(--border-heavy)',
|
||||
'border-xheavy': 'var(--border-xheavy)',
|
||||
'border-destructive': 'var(--border-destructive)',
|
||||
/* These are test styles */
|
||||
border: 'hsl(var(--border))',
|
||||
input: 'hsl(var(--input))',
|
||||
['switch-unchecked']: 'hsl(var(--switch-unchecked))',
|
||||
ring: 'hsl(var(--ring))',
|
||||
background: 'hsl(var(--background))',
|
||||
foreground: 'hsl(var(--foreground))',
|
||||
primary: {
|
||||
DEFAULT: 'hsl(var(--primary))',
|
||||
foreground: 'hsl(var(--primary-foreground))',
|
||||
},
|
||||
secondary: {
|
||||
DEFAULT: 'hsl(var(--secondary))',
|
||||
foreground: 'hsl(var(--secondary-foreground))',
|
||||
},
|
||||
destructive: {
|
||||
DEFAULT: 'hsl(var(--destructive))',
|
||||
foreground: 'hsl(var(--destructive-foreground))',
|
||||
},
|
||||
muted: {
|
||||
DEFAULT: 'hsl(var(--muted))',
|
||||
foreground: 'hsl(var(--muted-foreground))',
|
||||
},
|
||||
accent: {
|
||||
DEFAULT: 'hsl(var(--accent))',
|
||||
foreground: 'hsl(var(--accent-foreground))',
|
||||
},
|
||||
card: {
|
||||
DEFAULT: 'hsl(var(--card))',
|
||||
foreground: 'hsl(var(--card-foreground))',
|
||||
},
|
||||
},
|
||||
colors: createTailwindColors(),
|
||||
borderRadius: {
|
||||
lg: 'var(--radius)',
|
||||
md: 'calc(var(--radius) - 2px)',
|
||||
|
|
|
|||
|
|
@ -1,84 +1,134 @@
|
|||
/**
|
||||
* Helper function to create a color value that uses CSS variables with alpha support
|
||||
* This is a CommonJS version for use in tailwind.config.js
|
||||
* Single source of truth for the Tailwind semantic color palette.
|
||||
*
|
||||
* Both Tailwind configs consume this so the `client` SPA and the
|
||||
* `@librechat/client` package generate identical color utilities and can
|
||||
* never drift apart:
|
||||
* - client/tailwind.config.cjs
|
||||
* - packages/client/tailwind.config.js
|
||||
*
|
||||
* Semantic tokens resolve to CSS custom properties defined in
|
||||
* client/src/style.css (`html`, `.dark`, `.gizmo` blocks). shadcn-compatible
|
||||
* tokens hold HSL triplets, so they are wrapped in `hsl(...)`.
|
||||
*
|
||||
* Opacity modifiers (e.g. `bg-surface-primary/50`) are intentionally not
|
||||
* supported yet: the underlying variables hold hex/`rgb()` values rather than
|
||||
* bare channels. Migrating the variables to `R G B` triplets and switching to
|
||||
* `rgb(var(--x) / <alpha-value>)` is tracked as a follow-up.
|
||||
*/
|
||||
function withOpacity(variableName) {
|
||||
return ({ opacityValue }) => {
|
||||
if (opacityValue !== undefined) {
|
||||
// The CSS variable already contains rgb() so we need to extract the values
|
||||
return `rgba(var(${variableName}), ${opacityValue})`.replace('rgb(', '').replace(')', '');
|
||||
}
|
||||
return `var(${variableName})`;
|
||||
};
|
||||
}
|
||||
|
||||
const palette = {
|
||||
gray: {
|
||||
20: '#ececf1',
|
||||
50: '#f7f7f8',
|
||||
100: '#ececec',
|
||||
200: '#e3e3e3',
|
||||
300: '#cdcdcd',
|
||||
400: '#999696',
|
||||
500: '#595959',
|
||||
600: '#424242',
|
||||
700: '#2f2f2f',
|
||||
800: '#212121',
|
||||
850: '#171717',
|
||||
900: '#0d0d0d',
|
||||
},
|
||||
green: {
|
||||
50: '#f1f9f7',
|
||||
100: '#def2ed',
|
||||
200: '#a6e5d6',
|
||||
300: '#6dc8b9',
|
||||
400: '#41a79d',
|
||||
500: '#10a37f',
|
||||
550: '#349072',
|
||||
600: '#126e6b',
|
||||
700: '#0a4f53',
|
||||
800: '#06373e',
|
||||
900: '#031f29',
|
||||
},
|
||||
};
|
||||
|
||||
const cssVar = (name) => `var(${name})`;
|
||||
const hslVar = (name) => `hsl(var(${name}))`;
|
||||
|
||||
/**
|
||||
* Creates Tailwind color configuration that uses CSS variables
|
||||
* This allows dynamic theme switching by changing CSS variable values
|
||||
* Creates the Tailwind `theme.extend.colors` object backed by CSS variables.
|
||||
* This allows dynamic theme switching by changing CSS variable values at
|
||||
* runtime (see ThemeProvider / applyTheme).
|
||||
*/
|
||||
function createTailwindColors() {
|
||||
return {
|
||||
'text-primary': withOpacity('--text-primary'),
|
||||
'text-secondary': withOpacity('--text-secondary'),
|
||||
'text-secondary-alt': withOpacity('--text-secondary-alt'),
|
||||
'text-tertiary': withOpacity('--text-tertiary'),
|
||||
'text-warning': withOpacity('--text-warning'),
|
||||
'ring-primary': withOpacity('--ring-primary'),
|
||||
'header-primary': withOpacity('--header-primary'),
|
||||
'header-hover': withOpacity('--header-hover'),
|
||||
'header-button-hover': withOpacity('--header-button-hover'),
|
||||
'surface-active': withOpacity('--surface-active'),
|
||||
'surface-active-alt': withOpacity('--surface-active-alt'),
|
||||
'surface-hover': withOpacity('--surface-hover'),
|
||||
'surface-hover-alt': withOpacity('--surface-hover-alt'),
|
||||
'surface-primary': withOpacity('--surface-primary'),
|
||||
'surface-primary-alt': withOpacity('--surface-primary-alt'),
|
||||
'surface-primary-contrast': withOpacity('--surface-primary-contrast'),
|
||||
'surface-secondary': withOpacity('--surface-secondary'),
|
||||
'surface-secondary-alt': withOpacity('--surface-secondary-alt'),
|
||||
'surface-tertiary': withOpacity('--surface-tertiary'),
|
||||
'surface-tertiary-alt': withOpacity('--surface-tertiary-alt'),
|
||||
'surface-dialog': withOpacity('--surface-dialog'),
|
||||
'surface-submit': withOpacity('--surface-submit'),
|
||||
'surface-submit-hover': withOpacity('--surface-submit-hover'),
|
||||
'surface-destructive': withOpacity('--surface-destructive'),
|
||||
'surface-destructive-hover': withOpacity('--surface-destructive-hover'),
|
||||
'surface-chat': withOpacity('--surface-chat'),
|
||||
'border-light': withOpacity('--border-light'),
|
||||
'border-medium': withOpacity('--border-medium'),
|
||||
'border-medium-alt': withOpacity('--border-medium-alt'),
|
||||
'border-heavy': withOpacity('--border-heavy'),
|
||||
'border-xheavy': withOpacity('--border-xheavy'),
|
||||
'brand-purple': withOpacity('--brand-purple'),
|
||||
presentation: withOpacity('--presentation'),
|
||||
background: withOpacity('--background'),
|
||||
foreground: withOpacity('--foreground'),
|
||||
...palette,
|
||||
|
||||
'brand-purple': cssVar('--brand-purple'),
|
||||
presentation: cssVar('--presentation'),
|
||||
|
||||
'text-primary': cssVar('--text-primary'),
|
||||
'text-secondary': cssVar('--text-secondary'),
|
||||
'text-secondary-alt': cssVar('--text-secondary-alt'),
|
||||
'text-tertiary': cssVar('--text-tertiary'),
|
||||
'text-warning': cssVar('--text-warning'),
|
||||
'text-destructive': cssVar('--text-destructive'),
|
||||
|
||||
'ring-primary': cssVar('--ring-primary'),
|
||||
|
||||
'header-primary': cssVar('--header-primary'),
|
||||
'header-hover': cssVar('--header-hover'),
|
||||
'header-button-hover': cssVar('--header-button-hover'),
|
||||
|
||||
'surface-active': cssVar('--surface-active'),
|
||||
'surface-active-alt': cssVar('--surface-active-alt'),
|
||||
'surface-hover': cssVar('--surface-hover'),
|
||||
'surface-hover-alt': cssVar('--surface-hover-alt'),
|
||||
'surface-primary': cssVar('--surface-primary'),
|
||||
'surface-primary-alt': cssVar('--surface-primary-alt'),
|
||||
'surface-primary-contrast': cssVar('--surface-primary-contrast'),
|
||||
'surface-secondary': cssVar('--surface-secondary'),
|
||||
'surface-secondary-alt': cssVar('--surface-secondary-alt'),
|
||||
'surface-tertiary': cssVar('--surface-tertiary'),
|
||||
'surface-tertiary-alt': cssVar('--surface-tertiary-alt'),
|
||||
'surface-dialog': cssVar('--surface-dialog'),
|
||||
'surface-submit': cssVar('--surface-submit'),
|
||||
'surface-submit-hover': cssVar('--surface-submit-hover'),
|
||||
'surface-destructive': cssVar('--surface-destructive'),
|
||||
'surface-destructive-hover': cssVar('--surface-destructive-hover'),
|
||||
'surface-chat': cssVar('--surface-chat'),
|
||||
|
||||
'border-light': cssVar('--border-light'),
|
||||
'border-medium': cssVar('--border-medium'),
|
||||
'border-medium-alt': cssVar('--border-medium-alt'),
|
||||
'border-heavy': cssVar('--border-heavy'),
|
||||
'border-xheavy': cssVar('--border-xheavy'),
|
||||
'border-destructive': cssVar('--border-destructive'),
|
||||
|
||||
border: hslVar('--border'),
|
||||
input: hslVar('--input'),
|
||||
'switch-unchecked': hslVar('--switch-unchecked'),
|
||||
ring: hslVar('--ring'),
|
||||
background: hslVar('--background'),
|
||||
foreground: hslVar('--foreground'),
|
||||
primary: {
|
||||
DEFAULT: withOpacity('--primary'),
|
||||
foreground: withOpacity('--primary-foreground'),
|
||||
DEFAULT: hslVar('--primary'),
|
||||
foreground: hslVar('--primary-foreground'),
|
||||
},
|
||||
secondary: {
|
||||
DEFAULT: withOpacity('--secondary'),
|
||||
foreground: withOpacity('--secondary-foreground'),
|
||||
},
|
||||
muted: {
|
||||
DEFAULT: withOpacity('--muted'),
|
||||
foreground: withOpacity('--muted-foreground'),
|
||||
},
|
||||
accent: {
|
||||
DEFAULT: withOpacity('--accent'),
|
||||
foreground: withOpacity('--accent-foreground'),
|
||||
DEFAULT: hslVar('--secondary'),
|
||||
foreground: hslVar('--secondary-foreground'),
|
||||
},
|
||||
destructive: {
|
||||
DEFAULT: withOpacity('--surface-destructive'),
|
||||
foreground: withOpacity('--destructive-foreground'),
|
||||
DEFAULT: hslVar('--destructive'),
|
||||
foreground: hslVar('--destructive-foreground'),
|
||||
},
|
||||
muted: {
|
||||
DEFAULT: hslVar('--muted'),
|
||||
foreground: hslVar('--muted-foreground'),
|
||||
},
|
||||
accent: {
|
||||
DEFAULT: hslVar('--accent'),
|
||||
foreground: hslVar('--accent-foreground'),
|
||||
},
|
||||
border: withOpacity('--border'),
|
||||
input: withOpacity('--input'),
|
||||
ring: withOpacity('--ring'),
|
||||
card: {
|
||||
DEFAULT: withOpacity('--card'),
|
||||
foreground: withOpacity('--card-foreground'),
|
||||
DEFAULT: hslVar('--card'),
|
||||
foreground: hslVar('--card-foreground'),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue