Files
novalon-website/src/lib/constants/design-system.ts
T
zhangxiang e527b16cbc refactor(animations): annotate design-system.ts compliance trap
Task #16 残留陷阱治理(保留待用、不动代码):

scope: src/lib/constants/design-system.ts(零生产消费者的死代码)
action: 仅加注释,不改令牌值、不动 design-system.test.ts、零行为变化

- 文件头警示块:声明本文件为合规陷阱、令牌与 CONTEXT.md 冲突、
  test 用 // @ts-nocheck 断言错误值、勿在新代码 import
- 7 处冲突令牌行内 ⚠️ 注释:
  normal 0.4s 超目标 / slow 0.6s P1 / slower 0.8s P0 硬上限 /
  smooth 非 ease-ink / bounce 弹性缓动 / stagger 0.08 P2 / scroll 0.6s P1

verified:
- eslint design-system.ts: 0 errors (ESLINT_EXIT=0)
- jest design-system.test.ts: 20/20 passed (JEST_EXIT=0)
- 纯注释改动,tsc 无语法变化(已隔离单文件 diff)

note: 此前决策「保留待用、不动代码」——本提交仅显性化陷阱,
未来修正须同步改测试,否则必挂(P1 阶段已实践过该回退)。
2026-09-20 11:50:58 +08:00

149 lines
6.1 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.
// Design System Constants — L3 Detail Pages
// Color tokens reference global CSS variables for dark-mode support.
// Layout / spacing / animation / easing remain as JS constants.
//
// ⚠️ COMPLIANCE TRAP(Task #16 残留,刻意保留待用):
// 本文件动画令牌与 CONTEXT.md 动效约束冲突(见下方各 ⚠️ 行),且
// design-system.test.ts 用 `// @ts-nocheck` 断言了这些「错误值」。
// 它是零生产消费者的死代码,仅作历史参考。请勿照抄带 ⚠️ 的令牌;
// 新代码请直接用 ScrollReveal 默认(duration 0.3 / stagger 0.05 /
// easing ease-ink [0.22, 1, 0.36, 1])。要修正须同步改测试,否则必挂。
export const DESIGN_SYSTEM = Object.freeze({
animation: {
duration: {
fast: '0.2s',
normal: '0.4s', // ⚠️ 超目标:CONTEXT.md 入场目标 200-300ms,0.4s=400ms 超时
slow: '0.6s', // ⚠️ P1:>300ms 目标(仍 ≤700ms 硬上限)
slower: '0.8s', // ⚠️ P0:>700ms 硬上限违规(最严重)
countUp: '2s',
},
easing: {
smooth: 'cubic-bezier(0.4, 0, 0.2, 1)', // ⚠️ 非 ease-ink [0.22,1,0.36,1]
bounce: 'cubic-bezier(0.34, 1.56, 0.64, 1)', // ⚠️ 弹性缓动,违反「禁 spring 内容入场」
easeOut: 'cubic-bezier(0, 0, 0.2, 1)',
easeInOut: 'cubic-bezier(0.4, 0, 0.6, 1)',
},
delay: {
stagger: 0.08, // ⚠️ P2:>60ms(应为 ≤0.06,对齐 ScrollReveal 0.05)
section: 0.15,
},
},
spacing: {
section: {
py: 'py-20 lg:py-28',
pyCompact: 'py-16 lg:py-20',
},
container: {
default: 'max-w-7xl mx-auto px-4 sm:px-6 lg:px-8',
narrow: 'max-w-5xl mx-auto px-4 sm:px-6 lg:px-8',
wide: 'max-w-[1400px] mx-auto px-4 sm:px-6 lg:px-8',
},
grid: {
gap: 'gap-6 lg:gap-8',
gapSmall: 'gap-4 lg:gap-6',
},
},
// Typography classes reference CSS variables for theme-aware sizing
typography: {
hero: {
title: 'text-4xl md:text-5xl lg:text-6xl font-bold tracking-tight text-[var(--color-text-primary)]',
subtitle: 'text-lg md:text-xl leading-relaxed text-[var(--color-text-secondary)]',
description: 'text-base mt-4 max-w-2xl text-[var(--color-text-muted)]',
},
section: {
title: 'text-3xl md:text-4xl font-bold tracking-tight text-[var(--color-text-primary)]',
subtitle: 'text-lg mt-2 text-[var(--color-text-secondary)]',
body: 'text-base leading-relaxed text-[var(--color-text-secondary)]',
},
card: {
title: 'text-lg font-semibold text-[var(--color-text-primary)]',
description: 'text-sm leading-relaxed text-[var(--color-text-muted)]',
},
},
effects: {
inkGlow: {
border: 'conic-gradient(from var(--angle), transparent 0%, var(--color-brand) 10%, transparent 20%)',
glow: 'radial-gradient(circle at var(--mouse-x) var(--mouse-y), rgba(var(--color-brand-rgb), 0.15) 0%, transparent 50%)',
speed: '3s',
},
hover: {
translateY: '-4px',
shadow: 'shadow-xl',
transition: 'all 0.3s cubic-bezier(0.4, 0, 0.2, 1)',
},
scroll: {
fadeInUp: {
initial: { opacity: 0, y: 24 },
animate: { opacity: 1, y: 0 },
viewport: { once: true, margin: '-80px' },
transition: { duration: 0.6, ease: [0.16, 1, 0.3, 1] as const }, // ⚠️ P1:0.6s 超 300ms 目标
},
staggerChildren: {
delay: 0.08,
},
},
},
// Color references map to CSS custom properties defined in globals.css
// These are used for inline styles where Tailwind classes aren't feasible
colors: {
brand: {
primary: 'var(--color-brand)',
light: 'var(--color-brand-bg)',
lighter: 'rgba(var(--color-brand-rgb), 0.04)',
gradient: 'linear-gradient(135deg, var(--color-brand) 0%, #99182d 100%)',
},
neutral: {
50: 'var(--color-bg-primary)',
100: 'var(--color-bg-section)',
200: 'var(--color-border-primary)',
300: 'var(--color-text-hint)',
400: 'var(--color-text-subtle)',
500: 'var(--color-text-muted)',
600: 'var(--color-text-secondary)',
700: 'var(--color-text-primary)',
800: 'var(--color-text-primary)',
900: 'var(--color-text-primary)',
},
ink: {
light: 'rgba(0, 0, 0, 0.03)',
medium: 'rgba(0, 0, 0, 0.06)',
texture: 'repeating-linear-gradient(45deg, transparent, transparent 10px, rgba(0,0,0,.02) 10px, rgba(0,0,0,.02) 11px)',
},
},
components: {
card: {
base: 'rounded-2xl border border-[var(--color-border-primary)] overflow-hidden transition-all duration-300 bg-[var(--color-bg-primary)]',
hover: 'hover:border-[rgba(var(--color-brand-rgb),0.2)] hover:shadow-lg hover:-translate-y-1',
padding: 'p-6 lg:p-8',
},
badge: {
base: 'inline-flex items-center gap-1.5 px-3 py-1 rounded-full text-xs font-medium',
variants: {
primary: 'bg-[var(--color-brand-bg)] text-[var(--color-brand)]',
secondary: 'bg-[var(--color-bg-tertiary)] text-[var(--color-text-secondary)]',
success: 'bg-green-50 text-green-700',
warning: 'bg-yellow-50 text-yellow-700',
},
},
button: {
primary: 'inline-flex items-center gap-2 px-6 py-3 text-white font-semibold rounded-lg shadow-md transition-all duration-200 bg-[var(--color-brand)] hover:brightness-110 hover:shadow-lg',
secondary: 'inline-flex items-center gap-2 px-6 py-3 font-semibold rounded-lg border transition-all duration-200 bg-[var(--color-bg-primary)] text-[var(--color-text-secondary)] border-[var(--color-border-primary)] hover:border-[var(--color-text-hint)] hover:shadow-sm',
ghost: 'inline-flex items-center gap-2 px-4 py-2 font-medium rounded-lg transition-colors duration-200 text-[var(--color-brand)] hover:bg-[var(--color-brand-bg)]',
},
metric: {
container: 'text-center p-6 rounded-xl border bg-[var(--color-bg-section)] border-[var(--color-border-primary)]',
value: 'text-3xl md:text-4xl font-bold mb-1 text-[var(--color-text-primary)]',
label: 'text-sm text-[var(--color-text-subtle)]',
description: 'text-xs mt-1 text-[var(--color-text-hint)]',
},
},
});
export type DesignSystem = typeof DESIGN_SYSTEM;