Files
novalon-website/tailwind.config.js
T
zhangxiang 2593599862 fix(ui,a11y): 修 logo 深色模式不可见 + 补 tailwind font-calligraphy 工具类
修复 A:header logo 深色模式字被吞
- logo.svg 右侧公司名(睿新致遠 + NOVALON)硬编码 fill='#0A0E14',
  深色背景下 background 同色不可见,红色印章下书法字与英文全部被吞。
- 复用既有 logo-white.svg(白字 + 红印章)作为深色版,
  header 渲染双 <Image>,按 html[data-theme] CSS 显隐。
- 双 Image 不占位(display:none),零 JS 闪烁,未来主题切换器自动生效。

修复 B:font-calligraphy 工具类不生成
- tailwind.config.js 的 fontFamily 此前未声明 calligraphy key,
  导致 font-calligraphy utility 永不生成,4 处装饰书法字
  (BrandStamp「值得信赖」/ ChallengeSection「使命」/ WhyUsSection「睿」「我们」)
  静默回退 sans。
- fontFamily 加 calligraphy: ['var(--font-calligraphy-system)']。

审计脚本:
- logo-compare*.mjs:生产 vs 本地 logo 对比定位
- logo-dark-verify.mjs:明暗双版渲染验证
- font-calligraphy-verify.mjs:合成探针验证 utility 生效

验证:
- type-check 0 error · lint 0 error(127 warnings 既有项与本次无关)
- 深浅色 header 截图:明暗版正确切换,书法字 + NOVALON 清晰可见
- font-calligraphy 合成探针 computed fontFamily = STKaiti, KaiTi, 楷体, SimKai, serif ✓
2026-09-02 11:23:47 +08:00

278 lines
11 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} */
module.exports = {
content: [
'./src/pages/**/*.{js,ts,jsx,tsx,mdx}',
'./src/components/**/*.{js,ts,jsx,tsx,mdx}',
'./src/app/**/*.{js,ts,jsx,tsx,mdx}',
],
darkMode: 'class',
theme: {
extend: {
colors: {
/* 重要:Tailwind v3 无法对纯 hex 的 CSS 变量套用 /50 这类透明度修饰符,
会生成无效 CSS 并静默失效(样式不报错,但效果不出现)。
故常用色改用 rgb(通道 / <alpha-value>) 形式 —— 无修饰符时 alpha 默认 1,
视觉结果与原来一致,同时 bg-brand/10、border-ink/30 等能正确编译。 */
ink: {
DEFAULT: 'rgb(var(--color-ink-rgb) / <alpha-value>)',
light: 'var(--color-ink-light)',
lighter: 'var(--color-ink-lighter)',
rgb: 'var(--color-ink-rgb)',
},
brand: {
DEFAULT: 'rgb(var(--color-brand-rgb) / <alpha-value>)',
hover: 'var(--color-brand-hover)',
light: 'var(--color-brand-light)',
soft: 'rgb(var(--color-brand-rgb) / calc(0.12 * <alpha-value>))',
bg: 'var(--color-brand-bg)',
rgb: 'var(--color-brand-rgb)',
section: 'var(--color-brand-section)',
'section-text': 'var(--color-brand-section-text)',
'section-muted': 'var(--color-brand-section-muted)',
},
accent: {
blue: 'rgb(var(--color-accent-blue-rgb) / <alpha-value>)',
'blue-soft': 'var(--color-accent-blue-soft)',
teal: 'rgb(var(--color-accent-teal-rgb) / <alpha-value>)',
'teal-soft': 'var(--color-accent-teal-soft)',
amber: 'rgb(var(--color-accent-amber-rgb) / <alpha-value>)',
'amber-soft': 'var(--color-accent-amber-soft)',
purple: 'rgb(var(--color-accent-purple-rgb) / <alpha-value>)',
'purple-soft': 'var(--color-accent-purple-soft)',
cyan: 'rgb(var(--color-accent-cyan-rgb) / <alpha-value>)',
'cyan-soft': 'var(--color-accent-cyan-soft)',
rose: 'rgb(var(--color-accent-rose-rgb) / <alpha-value>)',
'rose-soft': 'var(--color-accent-rose-soft)',
indigo: 'rgb(var(--color-accent-indigo-rgb) / <alpha-value>)',
'indigo-soft': 'var(--color-accent-indigo-soft)',
},
bg: {
primary: 'rgb(var(--color-bg-primary-rgb) / <alpha-value>)',
secondary: 'rgb(var(--color-bg-secondary-rgb) / <alpha-value>)',
tertiary: 'var(--color-bg-tertiary)',
section: 'var(--color-bg-section)',
hover: 'var(--color-bg-hover)',
elevated: 'var(--color-bg-elevated)',
},
text: {
primary: 'var(--color-text-primary)',
secondary: 'rgb(var(--color-text-secondary-rgb) / <alpha-value>)',
tertiary: 'var(--color-text-tertiary)',
muted: 'rgb(var(--color-text-muted-rgb) / <alpha-value>)',
subtle: 'var(--color-text-subtle)',
placeholder: 'var(--color-text-placeholder)',
hint: 'var(--color-text-hint)',
inverse: 'var(--color-text-inverse)',
},
border: {
primary: 'rgb(var(--color-border-primary-rgb) / <alpha-value>)',
secondary: 'rgb(var(--color-border-secondary-rgb) / <alpha-value>)',
accent: 'rgb(var(--color-border-accent-rgb) / <alpha-value>)',
light: 'rgb(var(--color-border-light-rgb) / <alpha-value>)',
dark: 'rgb(var(--color-border-dark-rgb) / <alpha-value>)',
brand: 'rgb(var(--color-border-brand-rgb) / <alpha-value>)',
},
link: {
DEFAULT: 'var(--color-link)',
hover: 'var(--color-link-hover)',
},
success: {
DEFAULT: 'rgb(var(--color-success-rgb) / <alpha-value>)',
hover: 'var(--color-success-hover)',
bg: 'var(--color-success-bg)',
rgb: 'var(--color-success-rgb)',
/** 文字请用此变体:DEFAULT 仅 3.30:1,不达 AA */
text: 'var(--color-success-text)',
},
warning: {
DEFAULT: 'rgb(var(--color-warning-rgb) / <alpha-value>)',
hover: 'var(--color-warning-hover)',
bg: 'var(--color-warning-bg)',
rgb: 'var(--color-warning-rgb)',
/** 文字请用此变体:DEFAULT 仅 3.19:1,不达 AA */
text: 'var(--color-warning-text)',
},
error: {
DEFAULT: 'rgb(var(--color-error-rgb) / <alpha-value>)',
hover: 'var(--color-error-hover)',
bg: 'var(--color-error-bg)',
rgb: 'var(--color-error-rgb)',
/** 文字请用此变体:DEFAULT(品牌红 #C41E3A)在暗黑底仅 3.3:1,不达 AA;
* 本值浅红,暗黑模式经 html[data-theme='dark'] 覆盖后达 AA。 */
text: 'var(--color-error-text)',
},
info: {
DEFAULT: 'rgb(var(--color-info-rgb) / <alpha-value>)',
bg: 'var(--color-info-bg)',
/** 文字请用此变体:DEFAULT 仅 3.68:1,不达 AA */
text: 'var(--color-info-text)',
},
dark: {
bg: 'var(--color-dark-bg)',
'bg-secondary': 'var(--color-dark-bg-secondary)',
'bg-tertiary': 'var(--color-dark-bg-tertiary)',
'text-primary': 'var(--color-dark-text-primary)',
'text-secondary': 'var(--color-dark-text-secondary)',
'text-muted': 'var(--color-dark-text-muted)',
border: 'var(--color-dark-border)',
},
overlay: 'rgb(var(--color-overlay-rgb) / <alpha-value>)',
},
fontFamily: {
sans: ['var(--font-sans)'],
display: ['var(--font-display)'],
mono: ['var(--font-mono)'],
brand: ['var(--font-brand)'],
serif: ['var(--font-serif)'],
// 书法体:globals.css 的 --font-calligraphy-systemSTKaiti / KaiTi 系统字栈)
// 此前 fontFamily 未声明该 key,导致 font-calligraphy utility 不生成,
// 4 处装饰书法字(why-us / challenge / brand-visuals)静默回退 sans。
calligraphy: ['var(--font-calligraphy-system)'],
},
fontSize: {
caption: 'var(--font-size-caption)',
xs: 'var(--font-size-xs)',
sm: 'var(--font-size-sm)',
base: 'var(--font-size-base)',
lg: 'var(--font-size-lg)',
xl: 'var(--font-size-xl)',
'2xl': 'var(--font-size-2xl)',
'3xl': 'var(--font-size-3xl)',
'4xl': 'var(--font-size-4xl)',
'5xl': 'var(--font-size-5xl)',
'6xl': 'var(--font-size-6xl)',
'7xl': 'var(--font-size-7xl)',
display: 'var(--font-size-display)',
},
lineHeight: {
caption: 'var(--line-height-caption)',
tight: 'var(--line-height-tight)',
snug: 'var(--line-height-snug)',
normal: 'var(--line-height-normal)',
relaxed: 'var(--line-height-relaxed)',
},
letterSpacing: {
tighter: 'var(--letter-spacing-tighter)',
tight: 'var(--letter-spacing-tight)',
normal: 'var(--letter-spacing-normal)',
wide: 'var(--letter-spacing-wide)',
wider: 'var(--letter-spacing-wider)',
widest: 'var(--letter-spacing-widest)',
eyebrow: 'var(--letter-spacing-eyebrow)',
},
spacing: {
xs: 'var(--spacing-xs)',
sm: 'var(--spacing-sm)',
md: 'var(--spacing-md)',
lg: 'var(--spacing-lg)',
xl: 'var(--spacing-xl)',
'2xl': 'var(--spacing-2xl)',
'3xl': 'var(--spacing-3xl)',
'4xl': 'var(--spacing-4xl)',
'5xl': 'var(--spacing-5xl)',
'6xl': 'var(--spacing-6xl)',
},
borderRadius: {
xs: 'var(--radius-xs)',
sm: 'var(--radius-sm)',
md: 'var(--radius-md)',
lg: 'var(--radius-lg)',
xl: 'var(--radius-xl)',
'2xl': 'var(--radius-2xl)',
'3xl': 'var(--radius-3xl)',
full: 'var(--radius-full)',
},
boxShadow: {
xs: 'var(--shadow-xs)',
sm: 'var(--shadow-sm)',
md: 'var(--shadow-md)',
lg: 'var(--shadow-lg)',
xl: 'var(--shadow-xl)',
brand: 'var(--shadow-brand)',
'brand-hover': 'var(--shadow-brand-hover)',
inset: 'var(--shadow-inset)',
glow: 'var(--shadow-glow)',
},
transitionDuration: {
instant: 'var(--transition-instant)',
fast: 'var(--transition-fast)',
normal: 'var(--transition-normal)',
slow: 'var(--transition-slow)',
slower: 'var(--transition-slower)',
gentle: 'var(--transition-gentle)',
},
transitionTimingFunction: {
standard: 'var(--ease-standard)',
decelerate: 'var(--ease-decelerate)',
accelerate: 'var(--ease-accelerate)',
'ease-out': 'var(--ease-ink)',
'ease-in-out': 'var(--ease-sharp)',
'ease-spring': 'var(--ease-spring)',
'ease-spring-soft': 'var(--ease-spring-soft)',
sharp: 'var(--ease-sharp)',
ink: 'var(--ease-ink)',
},
maxWidth: {
container: 'var(--container-max)',
},
animation: {
'fade-in-up': 'fadeInUp 0.7s var(--ease-out) forwards',
'fade-in': 'fadeIn 0.5s var(--ease-out) forwards',
'scale-in': 'scaleIn 0.5s var(--ease-out) forwards',
'slide-in-left': 'slideInLeft 0.6s var(--ease-out) forwards',
'slide-in-right': 'slideInRight 0.6s var(--ease-out) forwards',
'pulse-soft': 'pulse-soft 2s ease-in-out infinite',
'ripple': 'ripple 0.6s ease-out forwards',
'skeleton-pulse': 'skeletonPulse 2s ease-in-out infinite',
'accordion-down': 'accordionDown 0.2s ease-out forwards',
'accordion-up': 'accordionUp 0.2s ease-out forwards',
},
keyframes: {
fadeInUp: {
from: { opacity: '0', transform: 'translateY(24px)' },
to: { opacity: '1', transform: 'translateY(0)' },
},
fadeIn: {
from: { opacity: '0' },
to: { opacity: '1' },
},
slideInLeft: {
from: { opacity: '0', transform: 'translateX(-32px)' },
to: { opacity: '1', transform: 'translateX(0)' },
},
slideInRight: {
from: { opacity: '0', transform: 'translateX(32px)' },
to: { opacity: '1', transform: 'translateX(0)' },
},
scaleIn: {
from: { opacity: '0', transform: 'scale(0.95)' },
to: { opacity: '1', transform: 'scale(1)' },
},
'pulse-soft': {
'0%, 100%': { opacity: '1' },
'50%': { opacity: '0.6' },
},
ripple: {
'0%': { transform: 'scale(0)', opacity: '0.5' },
'100%': { transform: 'scale(4)', opacity: '0' },
},
skeletonPulse: {
'0%, 100%': { backgroundColor: 'var(--color-bg-tertiary)', opacity: '1' },
'50%': { backgroundColor: 'color-mix(in srgb, var(--color-brand) 8%, var(--color-bg-tertiary))', opacity: '0.8' },
},
accordionDown: {
from: { height: '0', opacity: '0' },
to: { height: 'var(--radix-accordion-content-height)', opacity: '1' },
},
accordionUp: {
from: { height: 'var(--radix-accordion-content-height)', opacity: '1' },
to: { height: '0', opacity: '0' },
},
},
},
},
plugins: [
require('tailwindcss-animate'),
],
};