tokens.js
5.39 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
/**
* 主题 tokens —— 设计变量的**单一事实来源**(JS 形态)。
*
* 颜色 / 间距 / 圆角 / 字号 / 阴影集中于此。`theme.css` 的 `--drama-*` CSS 变量与本对象一一对齐
* (CSS 形态供组件 `<style>` 引用,JS 形态供调用方在脚本中读取 token 值)。新增品牌主题 = 在
* `theme.css` 增一组 `[data-theme="..."]` 变量并在 `color.dark` 处补对应 JS 值,组件零改动。
*
* 设计语言对齐 `docs/design`:黑白主色、圆角 12–16px、标题 Space Grotesk / 正文 Inter。
*
* @typedef {Object} ColorScale
* @property {string} bg 页面底色
* @property {string} surface 卡片 / 弹层表面色
* @property {string} surfaceAlt 次级表面色
* @property {string} border 描边色
* @property {string} text 主文本色
* @property {string} textMuted 次级文本色
* @property {string} primary 品牌主色
* @property {string} primaryHover 主色 hover 态
* @property {string} onPrimary 主色之上的前景色
* @property {string} danger 危险 / 错误色
* @property {string} dangerHover 危险色 hover 态
* @property {string} success 成功色
* @property {string} warning 警告色
* @property {string} info 信息色
* @property {string} overlay 遮罩色(含透明度)
*
* @typedef {Object} Tokens
* @property {{ light: ColorScale, dark: ColorScale, vgStudio: ColorScale, vgStudioLight: ColorScale, vokoCinemaLight: ColorScale }} color 默认明暗与品牌色板
* @property {Record<'xs'|'sm'|'md'|'lg'|'xl'|'2xl', string>} space 间距刻度
* @property {Record<'sm'|'md'|'lg', string>} control 表单控件高度刻度(各控件共用一把尺,横排才对得齐)
* @property {Record<'sm'|'md'|'lg'|'full', string>} radius 圆角刻度
* @property {{ family:{ heading:string, body:string }, size: Record<'xs'|'sm'|'md'|'lg'|'xl', string>, weight: Record<'normal'|'medium'|'bold', string> }} font 字体
* @property {Record<'sm'|'md'|'lg', string>} shadow 阴影刻度
*/
/** @type {ColorScale} */
const lightColor = {
bg: '#f5f5f8',
surface: '#ffffff',
surfaceAlt: '#ececf3',
border: '#d9d9e3',
text: '#16161d',
textMuted: '#5b5b6b',
primary: '#111111',
primaryHover: '#333333',
onPrimary: '#ffffff',
danger: '#dc2f3c',
dangerHover: '#c01f2c',
success: '#1f9d55',
warning: '#b7791f',
info: '#2b6cb0',
overlay: 'rgba(22, 22, 29, 0.45)',
}
/** @type {ColorScale} */
const darkColor = {
bg: '#0d0d12',
surface: '#16161f',
surfaceAlt: '#20202c',
border: '#2c2c3a',
text: '#f2f2f7',
textMuted: '#9a9ab0',
primary: '#7c5dff',
primaryHover: '#9277ff',
onPrimary: '#ffffff',
danger: '#ff5b66',
dangerHover: '#ff7681',
success: '#34d27b',
warning: '#eab24a',
info: '#5aa9ff',
overlay: 'rgba(0, 0, 0, 0.6)',
}
/** @type {ColorScale} */
const vgStudioColor = {
bg: '#0b0a08',
surface: '#141210',
surfaceAlt: '#1b1815',
border: 'rgba(235, 211, 166, 0.14)',
text: '#f4ecdd',
textMuted: '#c2b295',
primary: '#d3ac63',
primaryHover: '#e6c583',
onPrimary: '#1a1409',
danger: '#b95543',
dangerHover: '#d06a56',
success: '#5f9e6a',
warning: '#c9973f',
info: '#5b8aa6',
overlay: 'rgba(6, 5, 4, 0.72)',
}
/**
* vg-studio 的亮色态:换的是明暗,不是品牌 —— 金色主色压深到能在纸白底上当文字和描边用。
* @type {ColorScale}
*/
const vgStudioLightColor = {
bg: '#f6f1e7',
surface: '#fffdf8',
surfaceAlt: '#f0e8d9',
border: 'rgba(90, 66, 24, 0.16)',
text: '#1f1a12',
textMuted: '#6b6050',
primary: '#8a6520',
primaryHover: '#6f5019',
onPrimary: '#fff9ec',
danger: '#a3372a',
dangerHover: '#8a2c21',
success: '#2f7a45',
warning: '#8a6112',
info: '#2b6382',
overlay: 'rgba(31, 26, 18, 0.35)',
}
/**
* VOKO 用户官网的中性影院亮色主题。
* @type {ColorScale}
*/
const vokoCinemaLightColor = {
bg: '#ffffff',
surface: '#ffffff',
surfaceAlt: '#f5f5f5',
border: '#e5e5e5',
text: '#111111',
textMuted: '#666666',
primary: '#111111',
primaryHover: '#333333',
onPrimary: '#ffffff',
danger: '#b42318',
dangerHover: '#8f1c13',
success: '#257942',
warning: '#8a6112',
info: '#245e86',
overlay: 'rgba(17, 17, 17, 0.42)',
}
/** @type {Tokens} */
export const tokens = Object.freeze({
color: Object.freeze({
light: Object.freeze(lightColor),
dark: Object.freeze(darkColor),
vgStudio: Object.freeze(vgStudioColor),
vgStudioLight: Object.freeze(vgStudioLightColor),
vokoCinemaLight: Object.freeze(vokoCinemaLightColor),
}),
space: Object.freeze({
xs: '4px',
sm: '8px',
md: '12px',
lg: '16px',
xl: '24px',
'2xl': '32px',
}),
control: Object.freeze({
sm: '32px',
md: '40px',
lg: '48px',
}),
radius: Object.freeze({
sm: '8px',
md: '12px',
lg: '16px',
full: '9999px',
}),
font: Object.freeze({
family: Object.freeze({
heading: "'Space Grotesk', system-ui, sans-serif",
body: "'Inter', system-ui, sans-serif",
}),
size: Object.freeze({
xs: '12px',
sm: '14px',
md: '16px',
lg: '20px',
xl: '28px',
}),
weight: Object.freeze({
normal: '400',
medium: '500',
bold: '700',
}),
}),
shadow: Object.freeze({
sm: '0 1px 2px rgba(0, 0, 0, 0.12)',
md: '0 4px 16px rgba(0, 0, 0, 0.18)',
lg: '0 12px 40px rgba(0, 0, 0, 0.28)',
}),
})