@qlover/tailwind-theme 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +15 -0
- package/README.md +198 -0
- package/README_EN.md +109 -0
- package/dist/index.cjs +13 -0
- package/dist/index.d.ts +88 -0
- package/dist/index.js +343 -0
- package/dist/plugin.cjs +296 -0
- package/dist/plugin.d.cts +52 -0
- package/dist/plugin.d.ts +52 -0
- package/dist/plugin.js +273 -0
- package/dist/theme-block.css +21 -0
- package/dist/theme-layer-base.css +158 -0
- package/dist/theme.css +180 -0
- package/package.json +58 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
// src/utils.ts
|
|
2
|
+
function resolveTokenValue(value, prefix) {
|
|
3
|
+
return value.replace(/\$\{prefix\}/g, prefix);
|
|
4
|
+
}
|
|
5
|
+
function deepMerge(target, source) {
|
|
6
|
+
const result = { ...target };
|
|
7
|
+
for (const key in source) {
|
|
8
|
+
if (Object.prototype.hasOwnProperty.call(source, key)) {
|
|
9
|
+
const sourceVal = source[key];
|
|
10
|
+
const targetVal = result[key];
|
|
11
|
+
if (sourceVal && typeof sourceVal === "object" && !Array.isArray(sourceVal) && targetVal && typeof targetVal === "object") {
|
|
12
|
+
result[key] = deepMerge(
|
|
13
|
+
targetVal,
|
|
14
|
+
sourceVal
|
|
15
|
+
);
|
|
16
|
+
} else {
|
|
17
|
+
result[key] = sourceVal;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return result;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// src/config.ts
|
|
25
|
+
var themePrimaryBgOpacity = {
|
|
26
|
+
light: "0.08",
|
|
27
|
+
dark: "0.12",
|
|
28
|
+
pink: "0.12",
|
|
29
|
+
amber: "0.12",
|
|
30
|
+
forest: "0.1",
|
|
31
|
+
ocean: "0.1"
|
|
32
|
+
};
|
|
33
|
+
var builtinThemes = {
|
|
34
|
+
light: {
|
|
35
|
+
"color-primary": "246 248 250",
|
|
36
|
+
"color-secondary": "255 255 255",
|
|
37
|
+
"color-elevated": "240 242 244",
|
|
38
|
+
"color-primary-text": "31 35 40",
|
|
39
|
+
"color-primary-text-hover": "101 109 118",
|
|
40
|
+
"color-secondary-text": "101 109 118",
|
|
41
|
+
"color-tertiary-text": "140 149 159",
|
|
42
|
+
"color-primary-border": "208 215 222",
|
|
43
|
+
"color-brand": "124 58 237",
|
|
44
|
+
"color-brand-hover": "109 40 217",
|
|
45
|
+
"color-brand-active": "91 33 182",
|
|
46
|
+
"color-success": "#1a7f37",
|
|
47
|
+
"color-warning": "#faad14",
|
|
48
|
+
"color-error": "#cf222e",
|
|
49
|
+
"border-radius": "6px"
|
|
50
|
+
},
|
|
51
|
+
dark: {
|
|
52
|
+
"color-primary": "15 17 21",
|
|
53
|
+
"color-secondary": "22 27 34",
|
|
54
|
+
"color-elevated": "33 38 45",
|
|
55
|
+
"color-primary-text": "230 237 243",
|
|
56
|
+
"color-primary-text-hover": "139 148 158",
|
|
57
|
+
"color-secondary-text": "139 148 158",
|
|
58
|
+
"color-tertiary-text": "110 118 129",
|
|
59
|
+
"color-primary-border": "48 54 61",
|
|
60
|
+
"color-brand": "139 92 246",
|
|
61
|
+
"color-brand-hover": "124 58 237",
|
|
62
|
+
"color-brand-active": "109 40 217",
|
|
63
|
+
"color-success": "#3fb950",
|
|
64
|
+
"color-warning": "#faad14",
|
|
65
|
+
"color-error": "#f85149",
|
|
66
|
+
"border-radius": "6px"
|
|
67
|
+
},
|
|
68
|
+
pink: {
|
|
69
|
+
"color-primary": "26 13 20",
|
|
70
|
+
"color-secondary": "37 16 27",
|
|
71
|
+
"color-elevated": "48 21 34",
|
|
72
|
+
"color-primary-text": "252 232 240",
|
|
73
|
+
"color-primary-text-hover": "196 144 168",
|
|
74
|
+
"color-secondary-text": "196 144 168",
|
|
75
|
+
"color-tertiary-text": "138 88 112",
|
|
76
|
+
"color-primary-border": "92 45 66",
|
|
77
|
+
"color-brand": "244 114 182",
|
|
78
|
+
"color-brand-hover": "236 72 153",
|
|
79
|
+
"color-brand-active": "219 39 119",
|
|
80
|
+
"color-success": "#34d399",
|
|
81
|
+
"color-warning": "#faad14",
|
|
82
|
+
"color-error": "#fb7185",
|
|
83
|
+
"border-radius": "8px"
|
|
84
|
+
},
|
|
85
|
+
amber: {
|
|
86
|
+
"color-primary": "30 18 0",
|
|
87
|
+
"color-secondary": "40 26 0",
|
|
88
|
+
"color-elevated": "50 31 0",
|
|
89
|
+
"color-primary-text": "242 232 213",
|
|
90
|
+
"color-primary-text-hover": "184 166 138",
|
|
91
|
+
"color-secondary-text": "184 166 138",
|
|
92
|
+
"color-tertiary-text": "122 106 86",
|
|
93
|
+
"color-primary-border": "74 56 0",
|
|
94
|
+
"color-brand": "232 148 58",
|
|
95
|
+
"color-brand-hover": "208 120 40",
|
|
96
|
+
"color-brand-active": "180 100 30",
|
|
97
|
+
"color-success": "#5aad6e",
|
|
98
|
+
"color-warning": "#faad14",
|
|
99
|
+
"color-error": "#c85a4a",
|
|
100
|
+
"border-radius": "6px"
|
|
101
|
+
},
|
|
102
|
+
forest: {
|
|
103
|
+
"color-primary": "6 21 8",
|
|
104
|
+
"color-secondary": "12 31 14",
|
|
105
|
+
"color-elevated": "19 39 22",
|
|
106
|
+
"color-primary-text": "216 240 220",
|
|
107
|
+
"color-primary-text-hover": "136 173 142",
|
|
108
|
+
"color-secondary-text": "136 173 142",
|
|
109
|
+
"color-tertiary-text": "90 122 94",
|
|
110
|
+
"color-primary-border": "44 66 48",
|
|
111
|
+
"color-brand": "74 222 128",
|
|
112
|
+
"color-brand-hover": "34 197 94",
|
|
113
|
+
"color-brand-active": "22 163 74",
|
|
114
|
+
"color-success": "#86efac",
|
|
115
|
+
"color-warning": "#faad14",
|
|
116
|
+
"color-error": "#f87171",
|
|
117
|
+
"border-radius": "6px"
|
|
118
|
+
},
|
|
119
|
+
ocean: {
|
|
120
|
+
"color-primary": "6 14 26",
|
|
121
|
+
"color-secondary": "13 26 46",
|
|
122
|
+
"color-elevated": "18 36 62",
|
|
123
|
+
"color-primary-text": "218 238 255",
|
|
124
|
+
"color-primary-text-hover": "122 181 212",
|
|
125
|
+
"color-secondary-text": "122 181 212",
|
|
126
|
+
"color-tertiary-text": "74 126 154",
|
|
127
|
+
"color-primary-border": "30 58 92",
|
|
128
|
+
"color-brand": "56 189 248",
|
|
129
|
+
"color-brand-hover": "14 165 233",
|
|
130
|
+
"color-brand-active": "2 132 199",
|
|
131
|
+
"color-success": "#34d399",
|
|
132
|
+
"color-warning": "#faad14",
|
|
133
|
+
"color-error": "#f87171",
|
|
134
|
+
"border-radius": "6px"
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
var getDerivedTokens = (prefix, themeName) => {
|
|
138
|
+
const opacity = themeName ? themePrimaryBgOpacity[themeName] ?? "0.1" : "0.1";
|
|
139
|
+
return {
|
|
140
|
+
"color-bg-container": `rgb(var(--${prefix}-color-secondary))`,
|
|
141
|
+
"color-text": `rgb(var(--${prefix}-color-primary-text) / 0.85)`,
|
|
142
|
+
"color-text-heading": `rgb(var(--${prefix}-color-primary-text))`,
|
|
143
|
+
"color-text-disabled": `rgb(var(--${prefix}-color-primary-text) / 0.25)`,
|
|
144
|
+
"color-primary-hover": `rgb(var(--${prefix}-color-brand-hover))`,
|
|
145
|
+
"color-primary-active": `rgb(var(--${prefix}-color-brand-active))`,
|
|
146
|
+
"color-primary-bg": `rgb(var(--${prefix}-color-brand) / ${opacity})`,
|
|
147
|
+
"line-height": "1.5715"
|
|
148
|
+
};
|
|
149
|
+
};
|
|
150
|
+
var defaultTokenMapping = {
|
|
151
|
+
"color-primary": "rgb(var(--${prefix}-color-primary))",
|
|
152
|
+
"color-primary-active": "rgb(var(--${prefix}-color-primary-active))",
|
|
153
|
+
"color-primary-hover": "rgb(var(--${prefix}-color-primary-hover))",
|
|
154
|
+
"color-primary-bg": "rgb(var(--${prefix}-color-primary-bg))",
|
|
155
|
+
"color-secondary": "rgb(var(--${prefix}-color-secondary))",
|
|
156
|
+
"color-elevated": "rgb(var(--${prefix}-color-elevated))",
|
|
157
|
+
"color-primary-text": "rgb(var(--${prefix}-color-primary-text))",
|
|
158
|
+
"color-primary-text-hover": "rgb(var(--${prefix}-color-primary-text-hover))",
|
|
159
|
+
"color-secondary-text": "rgb(var(--${prefix}-color-secondary-text))",
|
|
160
|
+
"color-tertiary-text": "rgb(var(--${prefix}-color-tertiary-text))",
|
|
161
|
+
"color-primary-border": "rgb(var(--${prefix}-color-primary-border))",
|
|
162
|
+
"color-brand": "rgb(var(--${prefix}-color-brand))",
|
|
163
|
+
"color-brand-hover": "rgb(var(--${prefix}-color-brand-hover))",
|
|
164
|
+
"color-brand-active": "rgb(var(--${prefix}-color-brand-active))",
|
|
165
|
+
/** Text/icons on brand-colored surfaces (buttons, badges) */
|
|
166
|
+
"color-on-brand": "#ffffff",
|
|
167
|
+
"color-progress-track": "rgb(var(--${prefix}-color-primary-border) / 0.5)",
|
|
168
|
+
"color-bg-container": "rgb(var(--${prefix}-color-bg-container))",
|
|
169
|
+
"font-sans": 'var(--font-inter), ui-sans-serif, system-ui, "PingFang SC", "Microsoft YaHei UI", "Microsoft YaHei", "Noto Sans SC", sans-serif',
|
|
170
|
+
"animate-dashboard-skeleton-shimmer": "dashboard-skeleton-shimmer 1.6s ease-in-out infinite"
|
|
171
|
+
};
|
|
172
|
+
function getDefaultSelector(themeName, root) {
|
|
173
|
+
if (root) {
|
|
174
|
+
return `:root, html[data-theme="${themeName}"], [data-theme="${themeName}"]`;
|
|
175
|
+
}
|
|
176
|
+
return `html[data-theme="${themeName}"], [data-theme="${themeName}"]`;
|
|
177
|
+
}
|
|
178
|
+
var defaultConfig = {
|
|
179
|
+
prefix: "fe",
|
|
180
|
+
themes: {},
|
|
181
|
+
tokenMapping: defaultTokenMapping,
|
|
182
|
+
cssSelector: getDefaultSelector
|
|
183
|
+
};
|
|
184
|
+
function getConfig(options) {
|
|
185
|
+
const allThemes = deepMerge(builtinThemes, options?.themes || {});
|
|
186
|
+
const allMappings = deepMerge(
|
|
187
|
+
defaultTokenMapping,
|
|
188
|
+
options?.tokenMapping || {}
|
|
189
|
+
);
|
|
190
|
+
const config = Object.assign(
|
|
191
|
+
{},
|
|
192
|
+
defaultConfig,
|
|
193
|
+
options,
|
|
194
|
+
{
|
|
195
|
+
themes: allThemes,
|
|
196
|
+
tokenMapping: allMappings
|
|
197
|
+
}
|
|
198
|
+
);
|
|
199
|
+
if (!config.defaultTheme && config.themes) {
|
|
200
|
+
config.defaultTheme = Object.keys(config.themes)[0];
|
|
201
|
+
}
|
|
202
|
+
return config;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// src/core.ts
|
|
206
|
+
function generateLayerBaseCSS(options = {}) {
|
|
207
|
+
const config = getConfig(options);
|
|
208
|
+
const { prefix, themes, cssSelector, defaultTheme } = config;
|
|
209
|
+
let css = "";
|
|
210
|
+
for (const [themeName, vars] of Object.entries(themes)) {
|
|
211
|
+
const isDefault = themeName === defaultTheme;
|
|
212
|
+
const selector = cssSelector(themeName, isDefault);
|
|
213
|
+
const themeDerived = getDerivedTokens(prefix, themeName);
|
|
214
|
+
const merged = {
|
|
215
|
+
...vars,
|
|
216
|
+
...themeDerived
|
|
217
|
+
};
|
|
218
|
+
css += `${selector} {
|
|
219
|
+
`;
|
|
220
|
+
for (const [varName, value] of Object.entries(merged)) {
|
|
221
|
+
css += ` --${prefix}-${varName}: ${value};
|
|
222
|
+
`;
|
|
223
|
+
}
|
|
224
|
+
css += "}\n\n";
|
|
225
|
+
}
|
|
226
|
+
return css;
|
|
227
|
+
}
|
|
228
|
+
function generateThemeBlockCSS(options = {}) {
|
|
229
|
+
const config = getConfig(options);
|
|
230
|
+
const { prefix, tokenMapping = defaultTokenMapping } = config;
|
|
231
|
+
let css = "@theme {\n";
|
|
232
|
+
for (const [tokenName, tokenValue] of Object.entries(tokenMapping)) {
|
|
233
|
+
const finalValue = resolveTokenValue(tokenValue, prefix);
|
|
234
|
+
css += ` --${tokenName}: ${finalValue};
|
|
235
|
+
`;
|
|
236
|
+
}
|
|
237
|
+
css += "}\n";
|
|
238
|
+
return css;
|
|
239
|
+
}
|
|
240
|
+
function generateThemeCSS(options = {}) {
|
|
241
|
+
let css = "";
|
|
242
|
+
const layerBaseContent = generateLayerBaseCSS(options);
|
|
243
|
+
if (layerBaseContent) {
|
|
244
|
+
css += "@layer base {\n" + layerBaseContent + "}\n\n";
|
|
245
|
+
}
|
|
246
|
+
css += generateThemeBlockCSS(options);
|
|
247
|
+
return css;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// src/generater.ts
|
|
251
|
+
import fs from "fs";
|
|
252
|
+
import path from "path";
|
|
253
|
+
var DEFAULT_OUTPUT_PATHS = {
|
|
254
|
+
"layer-base": "theme-layer-base.css",
|
|
255
|
+
"theme-block": "theme-block.css",
|
|
256
|
+
full: "theme.css"
|
|
257
|
+
};
|
|
258
|
+
function resolveCssContent(variant, options) {
|
|
259
|
+
switch (variant) {
|
|
260
|
+
case "layer-base": {
|
|
261
|
+
const layerBaseContent = generateLayerBaseCSS(options);
|
|
262
|
+
return layerBaseContent ? `@layer base {
|
|
263
|
+
${layerBaseContent}}
|
|
264
|
+
` : "";
|
|
265
|
+
}
|
|
266
|
+
case "theme-block":
|
|
267
|
+
return generateThemeBlockCSS(options);
|
|
268
|
+
case "full":
|
|
269
|
+
return generateThemeCSS(options);
|
|
270
|
+
default: {
|
|
271
|
+
const _exhaustive = variant;
|
|
272
|
+
return _exhaustive;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
async function writeCssFile(absolutePath, css, overwrite) {
|
|
277
|
+
if (fs.existsSync(absolutePath)) {
|
|
278
|
+
if (overwrite) {
|
|
279
|
+
console.warn(
|
|
280
|
+
`\u26A0\uFE0F Warning: File already exists at ${absolutePath}. It will be overwritten.`
|
|
281
|
+
);
|
|
282
|
+
} else {
|
|
283
|
+
throw new Error(
|
|
284
|
+
`File already exists at ${absolutePath} and overwrite is set to false.`
|
|
285
|
+
);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
const dir = path.dirname(absolutePath);
|
|
289
|
+
if (!fs.existsSync(dir)) {
|
|
290
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
291
|
+
}
|
|
292
|
+
await fs.promises.writeFile(absolutePath, css, "utf-8");
|
|
293
|
+
console.log(`\u2705 Theme CSS generated at ${absolutePath}`);
|
|
294
|
+
}
|
|
295
|
+
function resolveOutputPath(variant, options) {
|
|
296
|
+
if (options.outputPath) {
|
|
297
|
+
return path.resolve(process.cwd(), options.outputPath);
|
|
298
|
+
}
|
|
299
|
+
return path.resolve(process.cwd(), DEFAULT_OUTPUT_PATHS[variant]);
|
|
300
|
+
}
|
|
301
|
+
async function generateThemeFile(options = {}) {
|
|
302
|
+
const {
|
|
303
|
+
variant = "full",
|
|
304
|
+
overwrite = true,
|
|
305
|
+
outputPath,
|
|
306
|
+
...restOptions
|
|
307
|
+
} = options;
|
|
308
|
+
const absolutePath = outputPath ? path.resolve(process.cwd(), outputPath) : resolveOutputPath(variant, options);
|
|
309
|
+
const css = resolveCssContent(variant, restOptions);
|
|
310
|
+
await writeCssFile(absolutePath, css, overwrite);
|
|
311
|
+
return absolutePath;
|
|
312
|
+
}
|
|
313
|
+
async function generateThemeFiles(options = {}) {
|
|
314
|
+
const {
|
|
315
|
+
outputDir = ".",
|
|
316
|
+
outputPaths = {},
|
|
317
|
+
overwrite = true,
|
|
318
|
+
...restOptions
|
|
319
|
+
} = options;
|
|
320
|
+
const variants = Object.keys(DEFAULT_OUTPUT_PATHS);
|
|
321
|
+
const result = {};
|
|
322
|
+
for (const variant of variants) {
|
|
323
|
+
const relativePath = outputPaths[variant] ?? path.join(outputDir, DEFAULT_OUTPUT_PATHS[variant]);
|
|
324
|
+
const absolutePath = path.resolve(process.cwd(), relativePath);
|
|
325
|
+
const css = resolveCssContent(variant, restOptions);
|
|
326
|
+
await writeCssFile(absolutePath, css, overwrite);
|
|
327
|
+
result[variant] = absolutePath;
|
|
328
|
+
}
|
|
329
|
+
return result;
|
|
330
|
+
}
|
|
331
|
+
export {
|
|
332
|
+
builtinThemes,
|
|
333
|
+
defaultConfig,
|
|
334
|
+
defaultTokenMapping,
|
|
335
|
+
generateLayerBaseCSS,
|
|
336
|
+
generateThemeBlockCSS,
|
|
337
|
+
generateThemeCSS,
|
|
338
|
+
generateThemeFile,
|
|
339
|
+
generateThemeFiles,
|
|
340
|
+
getConfig,
|
|
341
|
+
getDefaultSelector,
|
|
342
|
+
getDerivedTokens
|
|
343
|
+
};
|
package/dist/plugin.cjs
ADDED
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/plugin.ts
|
|
21
|
+
var plugin_exports = {};
|
|
22
|
+
__export(plugin_exports, {
|
|
23
|
+
default: () => plugin_default
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(plugin_exports);
|
|
26
|
+
|
|
27
|
+
// src/utils.ts
|
|
28
|
+
function resolveTokenValue(value, prefix) {
|
|
29
|
+
return value.replace(/\$\{prefix\}/g, prefix);
|
|
30
|
+
}
|
|
31
|
+
function deepMerge(target, source) {
|
|
32
|
+
const result = { ...target };
|
|
33
|
+
for (const key in source) {
|
|
34
|
+
if (Object.prototype.hasOwnProperty.call(source, key)) {
|
|
35
|
+
const sourceVal = source[key];
|
|
36
|
+
const targetVal = result[key];
|
|
37
|
+
if (sourceVal && typeof sourceVal === "object" && !Array.isArray(sourceVal) && targetVal && typeof targetVal === "object") {
|
|
38
|
+
result[key] = deepMerge(
|
|
39
|
+
targetVal,
|
|
40
|
+
sourceVal
|
|
41
|
+
);
|
|
42
|
+
} else {
|
|
43
|
+
result[key] = sourceVal;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return result;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// src/config.ts
|
|
51
|
+
var themePrimaryBgOpacity = {
|
|
52
|
+
light: "0.08",
|
|
53
|
+
dark: "0.12",
|
|
54
|
+
pink: "0.12",
|
|
55
|
+
amber: "0.12",
|
|
56
|
+
forest: "0.1",
|
|
57
|
+
ocean: "0.1"
|
|
58
|
+
};
|
|
59
|
+
var builtinThemes = {
|
|
60
|
+
light: {
|
|
61
|
+
"color-primary": "246 248 250",
|
|
62
|
+
"color-secondary": "255 255 255",
|
|
63
|
+
"color-elevated": "240 242 244",
|
|
64
|
+
"color-primary-text": "31 35 40",
|
|
65
|
+
"color-primary-text-hover": "101 109 118",
|
|
66
|
+
"color-secondary-text": "101 109 118",
|
|
67
|
+
"color-tertiary-text": "140 149 159",
|
|
68
|
+
"color-primary-border": "208 215 222",
|
|
69
|
+
"color-brand": "124 58 237",
|
|
70
|
+
"color-brand-hover": "109 40 217",
|
|
71
|
+
"color-brand-active": "91 33 182",
|
|
72
|
+
"color-success": "#1a7f37",
|
|
73
|
+
"color-warning": "#faad14",
|
|
74
|
+
"color-error": "#cf222e",
|
|
75
|
+
"border-radius": "6px"
|
|
76
|
+
},
|
|
77
|
+
dark: {
|
|
78
|
+
"color-primary": "15 17 21",
|
|
79
|
+
"color-secondary": "22 27 34",
|
|
80
|
+
"color-elevated": "33 38 45",
|
|
81
|
+
"color-primary-text": "230 237 243",
|
|
82
|
+
"color-primary-text-hover": "139 148 158",
|
|
83
|
+
"color-secondary-text": "139 148 158",
|
|
84
|
+
"color-tertiary-text": "110 118 129",
|
|
85
|
+
"color-primary-border": "48 54 61",
|
|
86
|
+
"color-brand": "139 92 246",
|
|
87
|
+
"color-brand-hover": "124 58 237",
|
|
88
|
+
"color-brand-active": "109 40 217",
|
|
89
|
+
"color-success": "#3fb950",
|
|
90
|
+
"color-warning": "#faad14",
|
|
91
|
+
"color-error": "#f85149",
|
|
92
|
+
"border-radius": "6px"
|
|
93
|
+
},
|
|
94
|
+
pink: {
|
|
95
|
+
"color-primary": "26 13 20",
|
|
96
|
+
"color-secondary": "37 16 27",
|
|
97
|
+
"color-elevated": "48 21 34",
|
|
98
|
+
"color-primary-text": "252 232 240",
|
|
99
|
+
"color-primary-text-hover": "196 144 168",
|
|
100
|
+
"color-secondary-text": "196 144 168",
|
|
101
|
+
"color-tertiary-text": "138 88 112",
|
|
102
|
+
"color-primary-border": "92 45 66",
|
|
103
|
+
"color-brand": "244 114 182",
|
|
104
|
+
"color-brand-hover": "236 72 153",
|
|
105
|
+
"color-brand-active": "219 39 119",
|
|
106
|
+
"color-success": "#34d399",
|
|
107
|
+
"color-warning": "#faad14",
|
|
108
|
+
"color-error": "#fb7185",
|
|
109
|
+
"border-radius": "8px"
|
|
110
|
+
},
|
|
111
|
+
amber: {
|
|
112
|
+
"color-primary": "30 18 0",
|
|
113
|
+
"color-secondary": "40 26 0",
|
|
114
|
+
"color-elevated": "50 31 0",
|
|
115
|
+
"color-primary-text": "242 232 213",
|
|
116
|
+
"color-primary-text-hover": "184 166 138",
|
|
117
|
+
"color-secondary-text": "184 166 138",
|
|
118
|
+
"color-tertiary-text": "122 106 86",
|
|
119
|
+
"color-primary-border": "74 56 0",
|
|
120
|
+
"color-brand": "232 148 58",
|
|
121
|
+
"color-brand-hover": "208 120 40",
|
|
122
|
+
"color-brand-active": "180 100 30",
|
|
123
|
+
"color-success": "#5aad6e",
|
|
124
|
+
"color-warning": "#faad14",
|
|
125
|
+
"color-error": "#c85a4a",
|
|
126
|
+
"border-radius": "6px"
|
|
127
|
+
},
|
|
128
|
+
forest: {
|
|
129
|
+
"color-primary": "6 21 8",
|
|
130
|
+
"color-secondary": "12 31 14",
|
|
131
|
+
"color-elevated": "19 39 22",
|
|
132
|
+
"color-primary-text": "216 240 220",
|
|
133
|
+
"color-primary-text-hover": "136 173 142",
|
|
134
|
+
"color-secondary-text": "136 173 142",
|
|
135
|
+
"color-tertiary-text": "90 122 94",
|
|
136
|
+
"color-primary-border": "44 66 48",
|
|
137
|
+
"color-brand": "74 222 128",
|
|
138
|
+
"color-brand-hover": "34 197 94",
|
|
139
|
+
"color-brand-active": "22 163 74",
|
|
140
|
+
"color-success": "#86efac",
|
|
141
|
+
"color-warning": "#faad14",
|
|
142
|
+
"color-error": "#f87171",
|
|
143
|
+
"border-radius": "6px"
|
|
144
|
+
},
|
|
145
|
+
ocean: {
|
|
146
|
+
"color-primary": "6 14 26",
|
|
147
|
+
"color-secondary": "13 26 46",
|
|
148
|
+
"color-elevated": "18 36 62",
|
|
149
|
+
"color-primary-text": "218 238 255",
|
|
150
|
+
"color-primary-text-hover": "122 181 212",
|
|
151
|
+
"color-secondary-text": "122 181 212",
|
|
152
|
+
"color-tertiary-text": "74 126 154",
|
|
153
|
+
"color-primary-border": "30 58 92",
|
|
154
|
+
"color-brand": "56 189 248",
|
|
155
|
+
"color-brand-hover": "14 165 233",
|
|
156
|
+
"color-brand-active": "2 132 199",
|
|
157
|
+
"color-success": "#34d399",
|
|
158
|
+
"color-warning": "#faad14",
|
|
159
|
+
"color-error": "#f87171",
|
|
160
|
+
"border-radius": "6px"
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
var getDerivedTokens = (prefix, themeName) => {
|
|
164
|
+
const opacity = themeName ? themePrimaryBgOpacity[themeName] ?? "0.1" : "0.1";
|
|
165
|
+
return {
|
|
166
|
+
"color-bg-container": `rgb(var(--${prefix}-color-secondary))`,
|
|
167
|
+
"color-text": `rgb(var(--${prefix}-color-primary-text) / 0.85)`,
|
|
168
|
+
"color-text-heading": `rgb(var(--${prefix}-color-primary-text))`,
|
|
169
|
+
"color-text-disabled": `rgb(var(--${prefix}-color-primary-text) / 0.25)`,
|
|
170
|
+
"color-primary-hover": `rgb(var(--${prefix}-color-brand-hover))`,
|
|
171
|
+
"color-primary-active": `rgb(var(--${prefix}-color-brand-active))`,
|
|
172
|
+
"color-primary-bg": `rgb(var(--${prefix}-color-brand) / ${opacity})`,
|
|
173
|
+
"line-height": "1.5715"
|
|
174
|
+
};
|
|
175
|
+
};
|
|
176
|
+
var defaultTokenMapping = {
|
|
177
|
+
"color-primary": "rgb(var(--${prefix}-color-primary))",
|
|
178
|
+
"color-primary-active": "rgb(var(--${prefix}-color-primary-active))",
|
|
179
|
+
"color-primary-hover": "rgb(var(--${prefix}-color-primary-hover))",
|
|
180
|
+
"color-primary-bg": "rgb(var(--${prefix}-color-primary-bg))",
|
|
181
|
+
"color-secondary": "rgb(var(--${prefix}-color-secondary))",
|
|
182
|
+
"color-elevated": "rgb(var(--${prefix}-color-elevated))",
|
|
183
|
+
"color-primary-text": "rgb(var(--${prefix}-color-primary-text))",
|
|
184
|
+
"color-primary-text-hover": "rgb(var(--${prefix}-color-primary-text-hover))",
|
|
185
|
+
"color-secondary-text": "rgb(var(--${prefix}-color-secondary-text))",
|
|
186
|
+
"color-tertiary-text": "rgb(var(--${prefix}-color-tertiary-text))",
|
|
187
|
+
"color-primary-border": "rgb(var(--${prefix}-color-primary-border))",
|
|
188
|
+
"color-brand": "rgb(var(--${prefix}-color-brand))",
|
|
189
|
+
"color-brand-hover": "rgb(var(--${prefix}-color-brand-hover))",
|
|
190
|
+
"color-brand-active": "rgb(var(--${prefix}-color-brand-active))",
|
|
191
|
+
/** Text/icons on brand-colored surfaces (buttons, badges) */
|
|
192
|
+
"color-on-brand": "#ffffff",
|
|
193
|
+
"color-progress-track": "rgb(var(--${prefix}-color-primary-border) / 0.5)",
|
|
194
|
+
"color-bg-container": "rgb(var(--${prefix}-color-bg-container))",
|
|
195
|
+
"font-sans": 'var(--font-inter), ui-sans-serif, system-ui, "PingFang SC", "Microsoft YaHei UI", "Microsoft YaHei", "Noto Sans SC", sans-serif',
|
|
196
|
+
"animate-dashboard-skeleton-shimmer": "dashboard-skeleton-shimmer 1.6s ease-in-out infinite"
|
|
197
|
+
};
|
|
198
|
+
function getDefaultSelector(themeName, root) {
|
|
199
|
+
if (root) {
|
|
200
|
+
return `:root, html[data-theme="${themeName}"], [data-theme="${themeName}"]`;
|
|
201
|
+
}
|
|
202
|
+
return `html[data-theme="${themeName}"], [data-theme="${themeName}"]`;
|
|
203
|
+
}
|
|
204
|
+
var defaultConfig = {
|
|
205
|
+
prefix: "fe",
|
|
206
|
+
themes: {},
|
|
207
|
+
tokenMapping: defaultTokenMapping,
|
|
208
|
+
cssSelector: getDefaultSelector
|
|
209
|
+
};
|
|
210
|
+
function getConfig(options) {
|
|
211
|
+
const allThemes = deepMerge(builtinThemes, options?.themes || {});
|
|
212
|
+
const allMappings = deepMerge(
|
|
213
|
+
defaultTokenMapping,
|
|
214
|
+
options?.tokenMapping || {}
|
|
215
|
+
);
|
|
216
|
+
const config = Object.assign(
|
|
217
|
+
{},
|
|
218
|
+
defaultConfig,
|
|
219
|
+
options,
|
|
220
|
+
{
|
|
221
|
+
themes: allThemes,
|
|
222
|
+
tokenMapping: allMappings
|
|
223
|
+
}
|
|
224
|
+
);
|
|
225
|
+
if (!config.defaultTheme && config.themes) {
|
|
226
|
+
config.defaultTheme = Object.keys(config.themes)[0];
|
|
227
|
+
}
|
|
228
|
+
return config;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// src/core.ts
|
|
232
|
+
function generateLayerBaseCSS(options = {}) {
|
|
233
|
+
const config = getConfig(options);
|
|
234
|
+
const { prefix, themes, cssSelector, defaultTheme } = config;
|
|
235
|
+
let css = "";
|
|
236
|
+
for (const [themeName, vars] of Object.entries(themes)) {
|
|
237
|
+
const isDefault = themeName === defaultTheme;
|
|
238
|
+
const selector = cssSelector(themeName, isDefault);
|
|
239
|
+
const themeDerived = getDerivedTokens(prefix, themeName);
|
|
240
|
+
const merged = {
|
|
241
|
+
...vars,
|
|
242
|
+
...themeDerived
|
|
243
|
+
};
|
|
244
|
+
css += `${selector} {
|
|
245
|
+
`;
|
|
246
|
+
for (const [varName, value] of Object.entries(merged)) {
|
|
247
|
+
css += ` --${prefix}-${varName}: ${value};
|
|
248
|
+
`;
|
|
249
|
+
}
|
|
250
|
+
css += "}\n\n";
|
|
251
|
+
}
|
|
252
|
+
return css;
|
|
253
|
+
}
|
|
254
|
+
function generateThemeBlockCSS(options = {}) {
|
|
255
|
+
const config = getConfig(options);
|
|
256
|
+
const { prefix, tokenMapping = defaultTokenMapping } = config;
|
|
257
|
+
let css = "@theme {\n";
|
|
258
|
+
for (const [tokenName, tokenValue] of Object.entries(tokenMapping)) {
|
|
259
|
+
const finalValue = resolveTokenValue(tokenValue, prefix);
|
|
260
|
+
css += ` --${tokenName}: ${finalValue};
|
|
261
|
+
`;
|
|
262
|
+
}
|
|
263
|
+
css += "}\n";
|
|
264
|
+
return css;
|
|
265
|
+
}
|
|
266
|
+
function generateThemeCSS(options = {}) {
|
|
267
|
+
let css = "";
|
|
268
|
+
const layerBaseContent = generateLayerBaseCSS(options);
|
|
269
|
+
if (layerBaseContent) {
|
|
270
|
+
css += "@layer base {\n" + layerBaseContent + "}\n\n";
|
|
271
|
+
}
|
|
272
|
+
css += generateThemeBlockCSS(options);
|
|
273
|
+
return css;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// src/plugin.ts
|
|
277
|
+
var themePlugin = (userOptions = {}) => {
|
|
278
|
+
const { includePaths = ["/styles/index.css", "/styles/tailwind.css"] } = userOptions;
|
|
279
|
+
return {
|
|
280
|
+
postcssPlugin: "tailwind-theme-plugin",
|
|
281
|
+
Once(root, { postcss, result }) {
|
|
282
|
+
const from = result.opts.from ?? root.source?.input?.file ?? "";
|
|
283
|
+
const normalized = from.replace(/\\/g, "/");
|
|
284
|
+
const shouldProcess = includePaths.some(
|
|
285
|
+
(pattern) => normalized.endsWith(pattern)
|
|
286
|
+
);
|
|
287
|
+
if (normalized && !shouldProcess) {
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
const finalCss = generateThemeCSS(userOptions);
|
|
291
|
+
root.prepend(postcss.parse(finalCss));
|
|
292
|
+
}
|
|
293
|
+
};
|
|
294
|
+
};
|
|
295
|
+
themePlugin.postcss = true;
|
|
296
|
+
var plugin_default = themePlugin;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { Plugin } from 'postcss';
|
|
2
|
+
|
|
3
|
+
type RGBChannels = string;
|
|
4
|
+
type ColorValue = string;
|
|
5
|
+
type ThemeTokens = Record<string, ColorValue | RGBChannels>;
|
|
6
|
+
/** Named themes → token sets (avoids index-signature confusion with `Record<string, ThemeTokens>`) */
|
|
7
|
+
type ThemesMap = Record<string, ThemeTokens>;
|
|
8
|
+
/**
|
|
9
|
+
* Token mapping for the theme.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* {
|
|
13
|
+
* 'color-primary': 'rgb(var(--${prefix}-color-primary))',
|
|
14
|
+
* 'color-secondary': 'rgb(var(--${prefix}-color-secondary))',
|
|
15
|
+
* 'color-elevated': 'rgb(var(--${prefix}-color-elevated))',
|
|
16
|
+
* 'color-primary-text': 'rgb(var(--${prefix}-color-primary-text))',
|
|
17
|
+
* 'color-primary-text-hover': 'rgb(var(--${prefix}-color-primary-text-hover))',
|
|
18
|
+
* 'color-secondary-text': 'rgb(var(--${prefix}-color-secondary-text))',
|
|
19
|
+
* 'color-tertiary-text': 'rgb(var(--${prefix}-color-tertiary-text))',
|
|
20
|
+
* }
|
|
21
|
+
*
|
|
22
|
+
* 最后结果可能=>
|
|
23
|
+
* {
|
|
24
|
+
* '--color-primary': 'rgb(var(--fe-color-primary))',
|
|
25
|
+
* '--color-secondary': 'rgb(var(--fe-color-secondary))',
|
|
26
|
+
* '--color-elevated': 'rgb(var(--fe-color-elevated))',
|
|
27
|
+
* '--color-primary-text': 'rgb(var(--fe-color-primary-text))',
|
|
28
|
+
* '--color-primary-text-hover': 'rgb(var(--fe-color-primary-text-hover))',
|
|
29
|
+
* '--color-secondary-text': 'rgb(var(--fe-color-secondary-text))',
|
|
30
|
+
* '--color-tertiary-text': 'rgb(var(--fe-color-tertiary-text))',
|
|
31
|
+
* }
|
|
32
|
+
*/
|
|
33
|
+
type TokenMapping = Record<string, string>;
|
|
34
|
+
interface UiThemeOptions {
|
|
35
|
+
prefix?: string;
|
|
36
|
+
defaultTheme?: string;
|
|
37
|
+
themes?: ThemesMap;
|
|
38
|
+
tokenMapping?: TokenMapping;
|
|
39
|
+
cssSelector?: (themeName: string, root: boolean) => string;
|
|
40
|
+
outputPath?: string;
|
|
41
|
+
overwrite?: boolean;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
interface ThemePluginOptions extends UiThemeOptions {
|
|
45
|
+
includePaths?: string[];
|
|
46
|
+
}
|
|
47
|
+
declare const themePlugin: {
|
|
48
|
+
(userOptions?: ThemePluginOptions): Plugin;
|
|
49
|
+
postcss: boolean;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export { type ThemePluginOptions, themePlugin as default };
|