Files
MailUI4Agents/client/electron/tailwind.config.js

185 lines
8.1 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/** @type {import('tailwindcss').Config} */
/**
* 颜色走 CSS 变量而不是写死的十六进制。
*
* # 为什么不逐处加 dark: 前缀
*
* 全站约 700 处颜色用法散在 21 个组件里。逐个写 `bg-white dark:bg-gray-900`
* 有两个致命问题:漏一处就是深色下的白底白字(而且只有肉眼能发现),
* 以及此后每加一个组件都要记得写两遍 —— 那种约定活不过三次改动。
*
* # 为什么改调色板就够了
*
* 这套代码里灰阶**本身就是语义色阶**
* - `white` / `gray-50` / `gray-100` = 表面层次(卡片 / 页面底 / 悬停)
* - `gray-200` / `gray-300` = 分隔线
* - `gray-900` → `gray-400` = 文字主次
*
* 深色模式要做的正是把这条色阶**反转**white 变近黑、gray-900 变近白。
* 于是零组件改动就能整体切换,新组件照常写 `bg-white text-gray-900`
* 也自动适配 —— 不需要任何人记得任何约定。
*
* # 为什么是 `rgb(var(--x) / <alpha-value>)` 而不是直接存颜色串
*
* 代码里有 `bg-blue-50/70`、`bg-gray-50/60` 这样的透明度修饰符。
* 变量若存 `#f9fafb`Tailwind 生成的 `rgb(#f9fafb / 0.7)` 是无效 CSS
* 那些半透明高亮会静默失效(不报错,只是不透明)。存 RGB 三元组才行。
*/
const withAlpha = (v) => `rgb(var(${v}) / <alpha-value>)`;
const grayScale = {
50: withAlpha('--c-gray-50'),
100: withAlpha('--c-gray-100'),
200: withAlpha('--c-gray-200'),
300: withAlpha('--c-gray-300'),
400: withAlpha('--c-gray-400'),
500: withAlpha('--c-gray-500'),
600: withAlpha('--c-gray-600'),
700: withAlpha('--c-gray-700'),
800: withAlpha('--c-gray-800'),
900: withAlpha('--c-gray-900'),
950: withAlpha('--c-gray-950')
};
/**
* 强调色blue / red / green / amber / orange / yellow
*
* 这条色阶在这套代码里也是**语义色阶**,与灰阶同理:
* - `50` `300` = 表面chip 底、提示条底、徽标底、边框)
* - `400` `900` = 前景(文字、图标、实心按钮底)
*
* 深色模式下两段的走向**相反**:表面段要变暗(照搬浅色的近白值会在深色页面上
* 糊出一块刺眼亮斑),前景段要变亮(照搬浅色的 red-700 落在深色卡片上只有
* 2.67:1读不动。所以它必须走变量不能写死 —— 见 index.css 的两组定义。
*/
const accent = (name) => ({
50: withAlpha(`--c-${name}-50`),
100: withAlpha(`--c-${name}-100`),
200: withAlpha(`--c-${name}-200`),
300: withAlpha(`--c-${name}-300`),
400: withAlpha(`--c-${name}-400`),
500: withAlpha(`--c-${name}-500`),
600: withAlpha(`--c-${name}-600`),
700: withAlpha(`--c-${name}-700`),
800: withAlpha(`--c-${name}-800`),
900: withAlpha(`--c-${name}-900`)
});
/**
* 实心按钮/徽标的底色 —— `--s-*`,两种模式下**同值**。
*
* 为什么不能跟 accent 的前景段走:那一段在深色下被提亮成了浅色
* red-600 → rgb(246,141,141)),而 `bg-red-600 text-white` 的白字落上去
* 只有 1.6:1。实心按钮的底色本来就该保持饱和 —— 深色模式下变的是页面,
* 不是「危险操作按钮是红的」这件事。
*
* 只覆盖 backgroundColor`text-red-600` / `border-red-600` 仍走 accent()。
* Tailwind 的 backgroundColor 默认继承 colors这里逐档覆写 400900
* 50300 是表面段,仍从 colors 继承 —— 它们在深色下就该变暗)。
*/
const solid = (name) => ({
400: withAlpha(`--s-${name}-400`),
500: withAlpha(`--s-${name}-500`),
600: withAlpha(`--s-${name}-600`),
700: withAlpha(`--s-${name}-700`),
800: withAlpha(`--s-${name}-800`),
900: withAlpha(`--s-${name}-900`)
});
export default {
content: ['./index.html', './src/**/*.{js,ts,jsx,tsx}'],
// class 而不是 media主题要能被人显式选择。跟系统走是**默认值**
// 不是唯一选项 —— 白天开深色主题是常见偏好。
darkMode: 'class',
theme: {
extend: {
/**
* textColor 单独覆盖 white。
*
* `--c-white` 服务两种**互相冲突**的用途:
* - `bg-white` = 卡片表面 → 深色模式必须变暗
* - `text-white` = 彩色按钮上的文字 → 深色模式必须**保持浅色**
*
* 只有一个变量时后者跟着变暗,白字落在 `bg-chrome-700` 的激活导航项上
* 只剩 1.34:1 —— 几乎不可见(实测发现)。按钮底色在深色模式下依然是
* blue-600 那样的彩色,上面的文字本来就该是白的。
*
* Tailwind 的 textColor 默认继承 colors这里只改 white 一项,
* 其余gray/blue/...)仍走反转的色阶。
*/
textColor: {
white: withAlpha('--c-on-accent')
},
/**
* backgroundColor 单独覆盖强调色的 400900 档,让实心按钮底保持饱和。
*
* 每个强调色的 400900 在这套代码里承担**两个冲突用途**
* - `text-red-600` / `border-red-300` = 深色下必须**提亮**才读得动
* - `bg-red-600` + `text-white` = 深色下必须**保持饱和**
*
* 共用一档时后者必坏:深色下 red-600 被提亮到 rgb(246,141,141)
* 白字落上去只有 1.6:1 —— 与 text-white/bg-white 那次是同一类错误
* (一个名字服务两种语义)。
*
* 50300 不覆盖:那是表面段,深色下就该跟着变暗。
*/
backgroundColor: {
blue: solid('blue'),
red: solid('red'),
green: solid('green'),
amber: solid('amber'),
orange: solid('orange'),
yellow: solid('yellow')
},
colors: {
white: withAlpha('--c-white'),
gray: grayScale,
// slate 在这套代码里只用于登录页与少数深色块,与 gray 同源即可 ——
// 保留两个名字是为了不改那些组件,但它们指向同一条色阶。
slate: grayScale,
/**
* chrome —— 应用框架(侧栏 / 底部导航)的专用色阶。
*
* 为什么不能跟 gray 走:这两块**在浅色模式下本来就是深色的**
* (深色侧栏配浅色内容区是这套 UI 的原本设计)。把它们并入反转的
* gray 之后,深色模式下 `bg-slate-900` 变成了近白色 —— 侧栏比内容区
* 还亮,整个层次翻了过来(实测 rgb(243,245,248),而内容区是 rgb(17,19,24))。
*
* 独立成一条色阶后:浅色模式下它是深色框架,深色模式下**微调即可**
* (比内容区略深一点,保持"框架比内容更沉"的关系),两种模式下
* 语义一致。
*/
chrome: {
100: withAlpha('--c-chrome-100'),
200: withAlpha('--c-chrome-200'),
400: withAlpha('--c-chrome-400'),
600: withAlpha('--c-chrome-600'),
700: withAlpha('--c-chrome-700'),
800: withAlpha('--c-chrome-800'),
900: withAlpha('--c-chrome-900')
},
/*
* 强调色。表面段50300在深色下变暗、前景段400900变亮
* 两段走向相反 —— 详见 accent() 的注释与 index.css 的两组定义。
*
* 实心按钮底另走 --s-*(见上面的 backgroundColor
*
* 注意这里**只能有一份定义**JS 对象字面量的重复键后者胜出,
* 而那不会报错。上一版同时写了固定 hex 与 accent() 两份,
* accent() 覆盖了 hex 那份,但 index.css 里当时没有对应的 --c-red-* 等
* 变量 —— `rgb(var(--c-red-600) / 1)` 里的变量未定义使整条声明失效,
* 于是 bg-red-600 退回透明,白字落在白卡片上:按钮看不见但点得动。
*/
blue: accent('blue'),
red: accent('red'),
green: accent('green'),
amber: accent('amber'),
orange: accent('orange'),
yellow: accent('yellow')
}
}
},
plugins: []
};