Files
crawler-plugin/admin-frontend-vue/src/styles/theme.ts
T

70 lines
2.4 KiB
TypeScript
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.
/**
* Admin 主题 token 单源(任务 4 契约,module 13 task 241 翻转为蓝白浅色)。
* main.css 使用同名 --admin-* CSS 变量承载渲染值;tests 用本模块校验
* “侧边栏与内容区均为浅色、主色为蓝灰、正文对比度达标”的不变量,防止回退到靛蓝深色侧栏。
*/
export const ADMIN_THEME = {
sidebar: '#f8fbfe',
sidebarDeep: '#edf3f9',
primary: '#4f78a5',
primarySoft: '#e7f0f8',
bg: '#f4f7fb',
border: '#d8e3ee',
text: '#24384d',
muted: '#5b6f83',
} as const
export type AdminThemeKey = keyof typeof ADMIN_THEME
export const ADMIN_THEME_KEYS = Object.keys(ADMIN_THEME) as AdminThemeKey[]
/** CSS 变量名:camelCase -> kebabsidebarDeep -> --admin-sidebar-deep)。 */
export function cssVarName(key: AdminThemeKey): string {
const kebab = key.replace(/[A-Z]/g, (c) => `-${c.toLowerCase()}`)
return `--admin-${kebab}`
}
function parseHex(hex: string): { r: number; g: number; b: number } {
if (!/^#[0-9a-fA-F]{6}$/.test(hex)) {
throw new Error(`主题色必须是 #rrggbb 六位十六进制: ${hex}`)
}
const raw = hex.slice(1)
return {
r: parseInt(raw.slice(0, 2), 16),
g: parseInt(raw.slice(2, 4), 16),
b: parseInt(raw.slice(4, 6), 16),
}
}
/** sRGB 通道 -> 线性亮度。 */
function channelLuminance(channel: number): number {
const s = channel / 255
return s <= 0.03928 ? s / 12.92 : ((s + 0.055) / 1.055) ** 2.4
}
/** 相对亮度(0 纯黑 ~ 1 纯白)。 */
export function relativeLuminance(hex: string): number {
const { r, g, b } = parseHex(hex)
return 0.2126 * channelLuminance(r) + 0.7152 * channelLuminance(g) + 0.0722 * channelLuminance(b)
}
export function isDarkSurface(hex: string, threshold = 0.2): boolean {
return relativeLuminance(hex) < threshold
}
/** WCAG 对比度(1 ~ 21),fg/bg 可为 8 位 hex。 */
export function contrastRatio(fgHex: string, bgHex: string): number {
const lighter = Math.max(relativeLuminance(fgHex), relativeLuminance(bgHex))
const darker = Math.min(relativeLuminance(fgHex), relativeLuminance(bgHex))
return (lighter + 0.05) / (darker + 0.05)
}
/** 取某个语义 token 的 hex;未知 key 给出可操作错误。 */
export function tokenHex(key: AdminThemeKey): string {
const value = ADMIN_THEME[key]
if (!value) {
throw new Error(`未知 Admin 主题 token: ${String(key)},允许值: ${ADMIN_THEME_KEYS.join(', ')}`)
}
return value
}