@nice2dev/design-tokens 1.0.28
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/README.md +221 -0
- package/dist/chunk-GJ4A7ZWW.js +1242 -0
- package/dist/chunk-MCKGQKYU.js +15 -0
- package/dist/cli/index.cjs +3018 -0
- package/dist/cli/index.d.cts +1 -0
- package/dist/cli/index.d.ts +1 -0
- package/dist/cli/index.js +363 -0
- package/dist/esm-YLJOW3XL.js +1703 -0
- package/dist/index.cjs +3880 -0
- package/dist/index.d.cts +856 -0
- package/dist/index.d.ts +856 -0
- package/dist/index.js +2628 -0
- package/package.json +59 -0
- package/tokens/animation.json +147 -0
- package/tokens/colors.json +184 -0
- package/tokens/components.json +201 -0
- package/tokens/effects.json +206 -0
- package/tokens/spacing.json +105 -0
- package/tokens/themes.json +193 -0
- package/tokens/typography.json +219 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,3880 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/index.ts
|
|
31
|
+
var index_exports = {};
|
|
32
|
+
__export(index_exports, {
|
|
33
|
+
ENHANCED_ACCESSIBILITY: () => ENHANCED_ACCESSIBILITY,
|
|
34
|
+
ENHANCED_FOCUS: () => ENHANCED_FOCUS,
|
|
35
|
+
ENHANCED_TYPOGRAPHY: () => ENHANCED_TYPOGRAPHY,
|
|
36
|
+
HIGH_CONTRAST: () => HIGH_CONTRAST,
|
|
37
|
+
HIGH_CONTRAST_DARK: () => HIGH_CONTRAST_DARK,
|
|
38
|
+
HIGH_VISIBILITY_FOCUS: () => HIGH_VISIBILITY_FOCUS,
|
|
39
|
+
MAXIMUM_ACCESSIBILITY: () => MAXIMUM_ACCESSIBILITY,
|
|
40
|
+
MAXIMUM_READABILITY_TYPOGRAPHY: () => MAXIMUM_READABILITY_TYPOGRAPHY,
|
|
41
|
+
MINIMAL_MOTION: () => MINIMAL_MOTION,
|
|
42
|
+
PRESETS: () => PRESETS,
|
|
43
|
+
REDUCED_MOTION: () => REDUCED_MOTION,
|
|
44
|
+
STANDARD_ACCESSIBILITY: () => STANDARD_ACCESSIBILITY,
|
|
45
|
+
STANDARD_CONTRAST: () => STANDARD_CONTRAST,
|
|
46
|
+
STANDARD_FOCUS: () => STANDARD_FOCUS,
|
|
47
|
+
STANDARD_MOTION: () => STANDARD_MOTION,
|
|
48
|
+
STANDARD_TYPOGRAPHY: () => STANDARD_TYPOGRAPHY,
|
|
49
|
+
TokenGenerator: () => TokenGenerator,
|
|
50
|
+
analyzeColor: () => analyzeColor,
|
|
51
|
+
buildTokenObject: () => buildTokenObject,
|
|
52
|
+
checkCircularReferences: () => checkCircularReferences,
|
|
53
|
+
checkContrast: () => checkContrast,
|
|
54
|
+
createGenerator: () => createGenerator,
|
|
55
|
+
createTheme: () => createTheme,
|
|
56
|
+
createTokenCollection: () => createTokenCollection,
|
|
57
|
+
cubicBezierToCss: () => cubicBezierToCss,
|
|
58
|
+
darkenColor: () => darkenColor,
|
|
59
|
+
defaultOptions: () => defaultOptions,
|
|
60
|
+
defaultThemes: () => defaultThemes,
|
|
61
|
+
durationToMs: () => durationToMs,
|
|
62
|
+
extractReferencePath: () => extractReferencePath,
|
|
63
|
+
filterTokensByPath: () => filterTokensByPath,
|
|
64
|
+
filterTokensByType: () => filterTokensByType,
|
|
65
|
+
findReferences: () => findReferences,
|
|
66
|
+
flattenTokens: () => flattenTokens,
|
|
67
|
+
fontWeightToNumber: () => fontWeightToNumber,
|
|
68
|
+
generateAccessibilityCss: () => generateAccessibilityCss,
|
|
69
|
+
generateBrandKit: () => generateBrandKit,
|
|
70
|
+
generateColorScale: () => generateColorScale2,
|
|
71
|
+
generateColorScaleAsync: () => generateColorScale,
|
|
72
|
+
generateCompleteStylesheet: () => generateCompleteStylesheet,
|
|
73
|
+
generateComponentStyles: () => generateComponentStyles,
|
|
74
|
+
generateDarkModeTokens: () => generateDarkModeTokens,
|
|
75
|
+
generateFocusCss: () => generateFocusCss,
|
|
76
|
+
generateHighContrastCss: () => generateHighContrastCss,
|
|
77
|
+
generateHighContrastTokens: () => generateHighContrastTokens,
|
|
78
|
+
generateReactThemeContext: () => generateReactThemeContext,
|
|
79
|
+
generateReducedMotionCss: () => generateReducedMotionCss,
|
|
80
|
+
generateThemeSwitcher: () => generateThemeSwitcher,
|
|
81
|
+
generateThemesCss: () => generateThemesCss,
|
|
82
|
+
generateTokenTypes: () => generateTokenTypes,
|
|
83
|
+
generateTokens: () => generateTokens,
|
|
84
|
+
getAccessibleTextColor: () => getAccessibleTextColor,
|
|
85
|
+
getAllCategories: () => getAllCategories,
|
|
86
|
+
getCategories: () => getCategories,
|
|
87
|
+
getContrastRatio: () => getContrastRatio2,
|
|
88
|
+
getContrastRatioAsync: () => getContrastRatio,
|
|
89
|
+
getDependencyGraph: () => getDependencyGraph,
|
|
90
|
+
getPresetByName: () => getPresetByName,
|
|
91
|
+
getPresetsByCategory: () => getPresetsByCategory,
|
|
92
|
+
getTokenByPath: () => getTokenByPath,
|
|
93
|
+
hexToHsl: () => hexToHsl,
|
|
94
|
+
hexToOklch: () => hexToOklch,
|
|
95
|
+
hexToRgb: () => hexToRgb,
|
|
96
|
+
industryBrandKit: () => industryBrandKit,
|
|
97
|
+
isDesignToken: () => isDesignToken,
|
|
98
|
+
isReference: () => isReference,
|
|
99
|
+
isTokenGroup: () => isTokenGroup,
|
|
100
|
+
lightenColor: () => lightenColor,
|
|
101
|
+
mergeTokenFiles: () => mergeTokenFiles,
|
|
102
|
+
parseTokenDirectory: () => parseTokenDirectory,
|
|
103
|
+
parseTokenFile: () => parseTokenFile,
|
|
104
|
+
parseTokenFiles: () => parseTokenFiles,
|
|
105
|
+
pathToCssVariable: () => pathToCssVariable,
|
|
106
|
+
pathToString: () => pathToString,
|
|
107
|
+
presetToCss: () => presetToCss,
|
|
108
|
+
presetToCssVariables: () => presetToCssVariables,
|
|
109
|
+
presetToTokens: () => presetToTokens,
|
|
110
|
+
pxToEm: () => pxToEm,
|
|
111
|
+
pxToRem: () => pxToRem,
|
|
112
|
+
quickBrandKit: () => quickBrandKit,
|
|
113
|
+
remToPx: () => remToPx,
|
|
114
|
+
resolveToVariable: () => resolveToVariable,
|
|
115
|
+
resolveTokenValue: () => resolveTokenValue,
|
|
116
|
+
resolveTokens: () => resolveTokens,
|
|
117
|
+
sortTokensByDependencies: () => sortTokensByDependencies,
|
|
118
|
+
suggestAccessibleColor: () => suggestAccessibleColor,
|
|
119
|
+
tokensToCssVariables: () => tokensToCssVariables,
|
|
120
|
+
transformToCss: () => transformToCss,
|
|
121
|
+
transformToJs: () => transformToJs,
|
|
122
|
+
transformToScss: () => transformToScss,
|
|
123
|
+
transformToTailwind: () => transformToTailwind,
|
|
124
|
+
transformToTs: () => transformToTs
|
|
125
|
+
});
|
|
126
|
+
module.exports = __toCommonJS(index_exports);
|
|
127
|
+
|
|
128
|
+
// src/parser.ts
|
|
129
|
+
var fs = __toESM(require("fs"), 1);
|
|
130
|
+
var path = __toESM(require("path"), 1);
|
|
131
|
+
function isDesignToken(obj) {
|
|
132
|
+
return typeof obj === "object" && obj !== null && "$value" in obj && obj.$value !== void 0;
|
|
133
|
+
}
|
|
134
|
+
function isTokenGroup(obj) {
|
|
135
|
+
if (typeof obj !== "object" || obj === null) {
|
|
136
|
+
return false;
|
|
137
|
+
}
|
|
138
|
+
if (isDesignToken(obj)) {
|
|
139
|
+
return false;
|
|
140
|
+
}
|
|
141
|
+
return Object.keys(obj).some((key) => !key.startsWith("$"));
|
|
142
|
+
}
|
|
143
|
+
function isReference(value) {
|
|
144
|
+
if (typeof value !== "string") {
|
|
145
|
+
return false;
|
|
146
|
+
}
|
|
147
|
+
return /^\{[\w.]+\}$/.test(value);
|
|
148
|
+
}
|
|
149
|
+
function extractReferencePath(ref) {
|
|
150
|
+
const match = ref.match(/^\{([\w.]+)\}$/);
|
|
151
|
+
if (!match) {
|
|
152
|
+
throw new Error(`Invalid reference: ${ref}`);
|
|
153
|
+
}
|
|
154
|
+
return match[1].split(".");
|
|
155
|
+
}
|
|
156
|
+
function pathToCssVariable(path3, prefix = "nice") {
|
|
157
|
+
return `--${prefix}-${path3.join("-")}`;
|
|
158
|
+
}
|
|
159
|
+
function pathToString(path3) {
|
|
160
|
+
return path3.join(".");
|
|
161
|
+
}
|
|
162
|
+
function parseTokenFile(filePath) {
|
|
163
|
+
const content = fs.readFileSync(filePath, "utf-8");
|
|
164
|
+
const parsed = JSON.parse(content);
|
|
165
|
+
return parsed;
|
|
166
|
+
}
|
|
167
|
+
function parseTokenFiles(filePaths) {
|
|
168
|
+
const merged = {};
|
|
169
|
+
for (const filePath of filePaths) {
|
|
170
|
+
const tokens = parseTokenFile(filePath);
|
|
171
|
+
mergeTokenFiles(merged, tokens);
|
|
172
|
+
}
|
|
173
|
+
return merged;
|
|
174
|
+
}
|
|
175
|
+
function mergeTokenFiles(target, source) {
|
|
176
|
+
for (const [key, value] of Object.entries(source)) {
|
|
177
|
+
if (key.startsWith("$")) {
|
|
178
|
+
if (!(key in target)) {
|
|
179
|
+
target[key] = value;
|
|
180
|
+
}
|
|
181
|
+
} else if (typeof value === "object" && value !== null) {
|
|
182
|
+
if (!(key in target)) {
|
|
183
|
+
target[key] = {};
|
|
184
|
+
}
|
|
185
|
+
const targetValue = target[key];
|
|
186
|
+
if (typeof targetValue === "object" && targetValue !== null) {
|
|
187
|
+
mergeTokenFiles(targetValue, value);
|
|
188
|
+
}
|
|
189
|
+
} else {
|
|
190
|
+
target[key] = value;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
function flattenTokens(tokenFile, prefix = [], inheritedType) {
|
|
195
|
+
const tokens = [];
|
|
196
|
+
const currentType = tokenFile.$type ?? inheritedType;
|
|
197
|
+
for (const [key, value] of Object.entries(tokenFile)) {
|
|
198
|
+
if (key.startsWith("$")) {
|
|
199
|
+
continue;
|
|
200
|
+
}
|
|
201
|
+
const currentPath = [...prefix, key];
|
|
202
|
+
if (isDesignToken(value)) {
|
|
203
|
+
const token = value;
|
|
204
|
+
const tokenType = token.$type ?? currentType;
|
|
205
|
+
const references = [];
|
|
206
|
+
findReferences(token.$value, references);
|
|
207
|
+
tokens.push({
|
|
208
|
+
path: currentPath,
|
|
209
|
+
name: key,
|
|
210
|
+
value: token.$value,
|
|
211
|
+
resolvedValue: "",
|
|
212
|
+
// Will be populated by resolver
|
|
213
|
+
type: tokenType,
|
|
214
|
+
description: token.$description,
|
|
215
|
+
cssVariable: pathToCssVariable(currentPath),
|
|
216
|
+
references: references.length > 0 ? references : void 0
|
|
217
|
+
});
|
|
218
|
+
} else if (isTokenGroup(value)) {
|
|
219
|
+
const group = value;
|
|
220
|
+
const groupType = group.$type ?? currentType;
|
|
221
|
+
tokens.push(...flattenTokens(group, currentPath, groupType));
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
return tokens;
|
|
225
|
+
}
|
|
226
|
+
function findReferences(value, refs) {
|
|
227
|
+
if (typeof value === "string" && isReference(value)) {
|
|
228
|
+
refs.push(extractReferencePath(value).join("."));
|
|
229
|
+
} else if (typeof value === "object" && value !== null) {
|
|
230
|
+
if (Array.isArray(value)) {
|
|
231
|
+
for (const item of value) {
|
|
232
|
+
findReferences(item, refs);
|
|
233
|
+
}
|
|
234
|
+
} else {
|
|
235
|
+
for (const v of Object.values(value)) {
|
|
236
|
+
findReferences(v, refs);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
function createTokenCollection(tokens) {
|
|
242
|
+
const byPath = /* @__PURE__ */ new Map();
|
|
243
|
+
const byName = /* @__PURE__ */ new Map();
|
|
244
|
+
for (const token of tokens) {
|
|
245
|
+
const pathStr = pathToString(token.path);
|
|
246
|
+
byPath.set(pathStr, token);
|
|
247
|
+
const existing = byName.get(token.name);
|
|
248
|
+
if (!existing || token.path.length > existing.path.length) {
|
|
249
|
+
byName.set(token.name, token);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
return { tokens, byPath, byName };
|
|
253
|
+
}
|
|
254
|
+
function parseTokenDirectory(dirPath, pattern = "*.json") {
|
|
255
|
+
const glob = require("fast-glob");
|
|
256
|
+
const files = glob.sync(path.join(dirPath, pattern));
|
|
257
|
+
const tokenFile = parseTokenFiles(files);
|
|
258
|
+
const flatTokens = flattenTokens(tokenFile);
|
|
259
|
+
return createTokenCollection(flatTokens);
|
|
260
|
+
}
|
|
261
|
+
function getTokenByPath(collection, path3) {
|
|
262
|
+
const pathStr = Array.isArray(path3) ? pathToString(path3) : path3;
|
|
263
|
+
return collection.byPath.get(pathStr);
|
|
264
|
+
}
|
|
265
|
+
function filterTokensByType(collection, type) {
|
|
266
|
+
return collection.tokens.filter((token) => token.type === type);
|
|
267
|
+
}
|
|
268
|
+
function filterTokensByPath(collection, prefix) {
|
|
269
|
+
return collection.tokens.filter((token) => pathToString(token.path).startsWith(prefix));
|
|
270
|
+
}
|
|
271
|
+
function getCategories(collection) {
|
|
272
|
+
const categories = /* @__PURE__ */ new Set();
|
|
273
|
+
for (const token of collection.tokens) {
|
|
274
|
+
if (token.path.length > 0) {
|
|
275
|
+
categories.add(token.path[0]);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
return Array.from(categories);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// src/generator.ts
|
|
282
|
+
var fs2 = __toESM(require("fs"), 1);
|
|
283
|
+
var path2 = __toESM(require("path"), 1);
|
|
284
|
+
|
|
285
|
+
// src/resolver.ts
|
|
286
|
+
var MAX_RESOLUTION_DEPTH = 10;
|
|
287
|
+
function resolveTokens(collection) {
|
|
288
|
+
const resolvedTokens = collection.tokens.map((token) => {
|
|
289
|
+
const resolved = { ...token };
|
|
290
|
+
resolved.resolvedValue = resolveTokenValue(token.value, collection, 0);
|
|
291
|
+
return resolved;
|
|
292
|
+
});
|
|
293
|
+
return {
|
|
294
|
+
tokens: resolvedTokens,
|
|
295
|
+
byPath: new Map(resolvedTokens.map((t) => [pathToString(t.path), t])),
|
|
296
|
+
byName: new Map(resolvedTokens.map((t) => [t.name, t]))
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
function resolveTokenValue(value, collection, depth) {
|
|
300
|
+
if (depth > MAX_RESOLUTION_DEPTH) {
|
|
301
|
+
throw new Error(`Maximum reference depth exceeded while resolving token`);
|
|
302
|
+
}
|
|
303
|
+
if (typeof value === "string") {
|
|
304
|
+
if (isReference(value)) {
|
|
305
|
+
const refPath = extractReferencePath(value);
|
|
306
|
+
const refPathStr = pathToString(refPath);
|
|
307
|
+
const refToken = collection.byPath.get(refPathStr);
|
|
308
|
+
if (!refToken) {
|
|
309
|
+
console.warn(`Reference not found: ${value}`);
|
|
310
|
+
return value;
|
|
311
|
+
}
|
|
312
|
+
return resolveTokenValue(refToken.value, collection, depth + 1);
|
|
313
|
+
}
|
|
314
|
+
return value;
|
|
315
|
+
}
|
|
316
|
+
if (typeof value === "number") {
|
|
317
|
+
return String(value);
|
|
318
|
+
}
|
|
319
|
+
if (Array.isArray(value)) {
|
|
320
|
+
return value.map((v) => {
|
|
321
|
+
if (typeof v === "string") {
|
|
322
|
+
return v.includes(" ") ? `"${v}"` : v;
|
|
323
|
+
}
|
|
324
|
+
return String(v);
|
|
325
|
+
}).join(", ");
|
|
326
|
+
}
|
|
327
|
+
if (isShadowValue(value)) {
|
|
328
|
+
return resolveShadowValue(value, collection, depth);
|
|
329
|
+
}
|
|
330
|
+
if (Array.isArray(value) && value.length > 0 && isShadowValue(value[0])) {
|
|
331
|
+
return value.map((s) => resolveShadowValue(s, collection, depth)).join(", ");
|
|
332
|
+
}
|
|
333
|
+
if (isTypographyValue(value)) {
|
|
334
|
+
return resolveTypographyValue(value, collection, depth);
|
|
335
|
+
}
|
|
336
|
+
if (isBorderValue(value)) {
|
|
337
|
+
return resolveBorderValue(value, collection, depth);
|
|
338
|
+
}
|
|
339
|
+
return JSON.stringify(value);
|
|
340
|
+
}
|
|
341
|
+
function isShadowValue(value) {
|
|
342
|
+
if (typeof value !== "object" || value === null) {
|
|
343
|
+
return false;
|
|
344
|
+
}
|
|
345
|
+
return "offsetX" in value && "offsetY" in value && "blur" in value;
|
|
346
|
+
}
|
|
347
|
+
function resolveShadowValue(shadow, collection, depth) {
|
|
348
|
+
const offsetX = resolveTokenValue(shadow.offsetX, collection, depth);
|
|
349
|
+
const offsetY = resolveTokenValue(shadow.offsetY, collection, depth);
|
|
350
|
+
const blur = resolveTokenValue(shadow.blur, collection, depth);
|
|
351
|
+
const spread = resolveTokenValue(shadow.spread, collection, depth);
|
|
352
|
+
const color = resolveTokenValue(shadow.color, collection, depth);
|
|
353
|
+
const inset = shadow.inset ? "inset " : "";
|
|
354
|
+
return `${inset}${offsetX} ${offsetY} ${blur} ${spread} ${color}`;
|
|
355
|
+
}
|
|
356
|
+
function isTypographyValue(value) {
|
|
357
|
+
if (typeof value !== "object" || value === null) {
|
|
358
|
+
return false;
|
|
359
|
+
}
|
|
360
|
+
return "fontFamily" in value && "fontSize" in value;
|
|
361
|
+
}
|
|
362
|
+
function resolveTypographyValue(typography, collection, depth) {
|
|
363
|
+
const fontFamily = resolveTokenValue(typography.fontFamily, collection, depth);
|
|
364
|
+
const fontSize = resolveTokenValue(typography.fontSize, collection, depth);
|
|
365
|
+
const fontWeight = resolveTokenValue(typography.fontWeight, collection, depth);
|
|
366
|
+
const lineHeight = typography.lineHeight ? resolveTokenValue(typography.lineHeight, collection, depth) : "normal";
|
|
367
|
+
const fontStyle = typography.fontStyle || "normal";
|
|
368
|
+
return `${fontStyle} ${fontWeight} ${fontSize}/${lineHeight} ${fontFamily}`;
|
|
369
|
+
}
|
|
370
|
+
function isBorderValue(value) {
|
|
371
|
+
if (typeof value !== "object" || value === null) {
|
|
372
|
+
return false;
|
|
373
|
+
}
|
|
374
|
+
return "color" in value && "width" in value && "style" in value;
|
|
375
|
+
}
|
|
376
|
+
function resolveBorderValue(border, collection, depth) {
|
|
377
|
+
const width = resolveTokenValue(border.width, collection, depth);
|
|
378
|
+
const style = resolveTokenValue(border.style, collection, depth);
|
|
379
|
+
const color = resolveTokenValue(border.color, collection, depth);
|
|
380
|
+
return `${width} ${style} ${color}`;
|
|
381
|
+
}
|
|
382
|
+
function resolveToVariable(value, collection, _prefix = "nice") {
|
|
383
|
+
if (typeof value === "string" && isReference(value)) {
|
|
384
|
+
const refPath = extractReferencePath(value);
|
|
385
|
+
const refPathStr = pathToString(refPath);
|
|
386
|
+
const refToken = collection.byPath.get(refPathStr);
|
|
387
|
+
if (refToken) {
|
|
388
|
+
return `var(${refToken.cssVariable})`;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
return resolveTokenValue(value, collection, 0);
|
|
392
|
+
}
|
|
393
|
+
function getDependencyGraph(collection) {
|
|
394
|
+
const graph = /* @__PURE__ */ new Map();
|
|
395
|
+
for (const token of collection.tokens) {
|
|
396
|
+
const pathStr = pathToString(token.path);
|
|
397
|
+
const deps = /* @__PURE__ */ new Set();
|
|
398
|
+
if (token.references) {
|
|
399
|
+
for (const ref of token.references) {
|
|
400
|
+
deps.add(ref);
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
graph.set(pathStr, deps);
|
|
404
|
+
}
|
|
405
|
+
return graph;
|
|
406
|
+
}
|
|
407
|
+
function sortTokensByDependencies(collection) {
|
|
408
|
+
const graph = getDependencyGraph(collection);
|
|
409
|
+
const visited = /* @__PURE__ */ new Set();
|
|
410
|
+
const sorted = [];
|
|
411
|
+
function visit(pathStr) {
|
|
412
|
+
if (visited.has(pathStr)) {
|
|
413
|
+
return;
|
|
414
|
+
}
|
|
415
|
+
visited.add(pathStr);
|
|
416
|
+
const deps = graph.get(pathStr);
|
|
417
|
+
if (deps) {
|
|
418
|
+
for (const dep of deps) {
|
|
419
|
+
visit(dep);
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
const token = collection.byPath.get(pathStr);
|
|
423
|
+
if (token) {
|
|
424
|
+
sorted.push(token);
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
for (const token of collection.tokens) {
|
|
428
|
+
visit(pathToString(token.path));
|
|
429
|
+
}
|
|
430
|
+
return sorted;
|
|
431
|
+
}
|
|
432
|
+
function checkCircularReferences(collection) {
|
|
433
|
+
const graph = getDependencyGraph(collection);
|
|
434
|
+
const circles = [];
|
|
435
|
+
const visiting = /* @__PURE__ */ new Set();
|
|
436
|
+
const visited = /* @__PURE__ */ new Set();
|
|
437
|
+
function visit(pathStr, path3) {
|
|
438
|
+
if (visited.has(pathStr)) {
|
|
439
|
+
return false;
|
|
440
|
+
}
|
|
441
|
+
if (visiting.has(pathStr)) {
|
|
442
|
+
const circleStart = path3.indexOf(pathStr);
|
|
443
|
+
circles.push(path3.slice(circleStart));
|
|
444
|
+
return true;
|
|
445
|
+
}
|
|
446
|
+
visiting.add(pathStr);
|
|
447
|
+
path3.push(pathStr);
|
|
448
|
+
const deps = graph.get(pathStr);
|
|
449
|
+
if (deps) {
|
|
450
|
+
for (const dep of deps) {
|
|
451
|
+
if (visit(dep, [...path3])) {
|
|
452
|
+
return true;
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
visiting.delete(pathStr);
|
|
457
|
+
visited.add(pathStr);
|
|
458
|
+
return false;
|
|
459
|
+
}
|
|
460
|
+
for (const token of collection.tokens) {
|
|
461
|
+
const pathStr = pathToString(token.path);
|
|
462
|
+
if (!visited.has(pathStr)) {
|
|
463
|
+
visit(pathStr, []);
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
return circles;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
// src/transforms.ts
|
|
470
|
+
var chroma = null;
|
|
471
|
+
async function getChroma() {
|
|
472
|
+
if (!chroma) {
|
|
473
|
+
chroma = (await import("chroma-js")).default;
|
|
474
|
+
}
|
|
475
|
+
return chroma;
|
|
476
|
+
}
|
|
477
|
+
async function hexToRgb(hex) {
|
|
478
|
+
const c = await getChroma();
|
|
479
|
+
const [r, g, b] = c(hex).rgb();
|
|
480
|
+
return `rgb(${r}, ${g}, ${b})`;
|
|
481
|
+
}
|
|
482
|
+
async function hexToHsl(hex) {
|
|
483
|
+
const c = await getChroma();
|
|
484
|
+
const [h, s, l] = c(hex).hsl();
|
|
485
|
+
return `hsl(${Math.round(h)}deg ${Math.round(s * 100)}% ${Math.round(l * 100)}%)`;
|
|
486
|
+
}
|
|
487
|
+
async function hexToOklch(hex) {
|
|
488
|
+
const c = await getChroma();
|
|
489
|
+
const [l, a, b] = c(hex).lab();
|
|
490
|
+
const L = l / 100;
|
|
491
|
+
const C = Math.sqrt(a * a + b * b) / 125;
|
|
492
|
+
const H = Math.atan2(b, a) * 180 / Math.PI;
|
|
493
|
+
return `oklch(${(L * 100).toFixed(1)}% ${C.toFixed(3)} ${H < 0 ? H + 360 : H}deg)`;
|
|
494
|
+
}
|
|
495
|
+
async function lightenColor(hex, amount) {
|
|
496
|
+
const c = await getChroma();
|
|
497
|
+
return c(hex).brighten(amount).hex();
|
|
498
|
+
}
|
|
499
|
+
async function darkenColor(hex, amount) {
|
|
500
|
+
const c = await getChroma();
|
|
501
|
+
return c(hex).darken(amount).hex();
|
|
502
|
+
}
|
|
503
|
+
async function getContrastRatio(fg, bg) {
|
|
504
|
+
const c = await getChroma();
|
|
505
|
+
return c.contrast(fg, bg);
|
|
506
|
+
}
|
|
507
|
+
async function getAccessibleTextColor(bgColor) {
|
|
508
|
+
const c = await getChroma();
|
|
509
|
+
const contrastWhite = c.contrast(bgColor, "white");
|
|
510
|
+
const contrastBlack = c.contrast(bgColor, "black");
|
|
511
|
+
return contrastWhite > contrastBlack ? "#ffffff" : "#000000";
|
|
512
|
+
}
|
|
513
|
+
async function generateColorScale(baseColor, steps = 10) {
|
|
514
|
+
const c = await getChroma();
|
|
515
|
+
const scale = {};
|
|
516
|
+
const labels = ["50", "100", "200", "300", "400", "500", "600", "700", "800", "900", "950"];
|
|
517
|
+
const colors = c.scale(["white", baseColor, "black"]).mode("lab").colors(steps + 2);
|
|
518
|
+
for (let i = 0; i < Math.min(labels.length, colors.length - 1); i++) {
|
|
519
|
+
const index = Math.floor(i / (labels.length - 1) * (colors.length - 1));
|
|
520
|
+
scale[labels[i]] = colors[index];
|
|
521
|
+
}
|
|
522
|
+
return scale;
|
|
523
|
+
}
|
|
524
|
+
function pxToRem(px, baseFontSize = 16) {
|
|
525
|
+
const value = typeof px === "string" ? parseFloat(px) : px;
|
|
526
|
+
return `${value / baseFontSize}rem`;
|
|
527
|
+
}
|
|
528
|
+
function remToPx(rem, baseFontSize = 16) {
|
|
529
|
+
const value = typeof rem === "string" ? parseFloat(rem) : rem;
|
|
530
|
+
return `${value * baseFontSize}px`;
|
|
531
|
+
}
|
|
532
|
+
function pxToEm(px, context = 16) {
|
|
533
|
+
const value = typeof px === "string" ? parseFloat(px) : px;
|
|
534
|
+
return `${value / context}em`;
|
|
535
|
+
}
|
|
536
|
+
function fontWeightToNumber(weight) {
|
|
537
|
+
const weights = {
|
|
538
|
+
thin: 100,
|
|
539
|
+
hairline: 100,
|
|
540
|
+
extralight: 200,
|
|
541
|
+
ultralight: 200,
|
|
542
|
+
light: 300,
|
|
543
|
+
normal: 400,
|
|
544
|
+
regular: 400,
|
|
545
|
+
medium: 500,
|
|
546
|
+
semibold: 600,
|
|
547
|
+
demibold: 600,
|
|
548
|
+
bold: 700,
|
|
549
|
+
extrabold: 800,
|
|
550
|
+
ultrabold: 800,
|
|
551
|
+
black: 900,
|
|
552
|
+
heavy: 900
|
|
553
|
+
};
|
|
554
|
+
return (weights[weight.toLowerCase()] ?? parseInt(weight, 10)) || 400;
|
|
555
|
+
}
|
|
556
|
+
function cubicBezierToCss(values) {
|
|
557
|
+
if (values.length !== 4) {
|
|
558
|
+
throw new Error("Cubic bezier must have exactly 4 values");
|
|
559
|
+
}
|
|
560
|
+
return `cubic-bezier(${values.join(", ")})`;
|
|
561
|
+
}
|
|
562
|
+
function durationToMs(duration) {
|
|
563
|
+
if (duration.endsWith("ms")) {
|
|
564
|
+
return parseFloat(duration);
|
|
565
|
+
}
|
|
566
|
+
if (duration.endsWith("s")) {
|
|
567
|
+
return parseFloat(duration) * 1e3;
|
|
568
|
+
}
|
|
569
|
+
return parseFloat(duration);
|
|
570
|
+
}
|
|
571
|
+
function transformToCss(collection, prefix = "nice") {
|
|
572
|
+
const lines = [];
|
|
573
|
+
for (const token of collection.tokens) {
|
|
574
|
+
const varName = `--${prefix}-${token.path.join("-")}`;
|
|
575
|
+
lines.push(` ${varName}: ${token.resolvedValue};`);
|
|
576
|
+
}
|
|
577
|
+
return `:root {
|
|
578
|
+
${lines.join("\n")}
|
|
579
|
+
}`;
|
|
580
|
+
}
|
|
581
|
+
function transformToScss(collection, prefix = "nice") {
|
|
582
|
+
const lines = [];
|
|
583
|
+
for (const token of collection.tokens) {
|
|
584
|
+
const varName = `$${prefix}-${token.path.join("-")}`;
|
|
585
|
+
lines.push(`${varName}: ${token.resolvedValue};`);
|
|
586
|
+
}
|
|
587
|
+
return lines.join("\n");
|
|
588
|
+
}
|
|
589
|
+
function transformToJs(collection, variableName = "tokens") {
|
|
590
|
+
const obj = buildTokenObject(collection);
|
|
591
|
+
return `export const ${variableName} = ${JSON.stringify(obj, null, 2)};`;
|
|
592
|
+
}
|
|
593
|
+
function transformToTs(collection, variableName = "tokens") {
|
|
594
|
+
const obj = buildTokenObject(collection);
|
|
595
|
+
const types = generateTokenTypes(collection);
|
|
596
|
+
return `${types}
|
|
597
|
+
|
|
598
|
+
export const ${variableName}: Tokens = ${JSON.stringify(obj, null, 2)};`;
|
|
599
|
+
}
|
|
600
|
+
function buildTokenObject(collection) {
|
|
601
|
+
const result = {};
|
|
602
|
+
for (const token of collection.tokens) {
|
|
603
|
+
let current = result;
|
|
604
|
+
for (let i = 0; i < token.path.length - 1; i++) {
|
|
605
|
+
const key = token.path[i];
|
|
606
|
+
if (!(key in current)) {
|
|
607
|
+
current[key] = {};
|
|
608
|
+
}
|
|
609
|
+
current = current[key];
|
|
610
|
+
}
|
|
611
|
+
const lastKey = token.path[token.path.length - 1];
|
|
612
|
+
current[lastKey] = token.resolvedValue;
|
|
613
|
+
}
|
|
614
|
+
return result;
|
|
615
|
+
}
|
|
616
|
+
function generateTokenTypes(collection) {
|
|
617
|
+
const typeObj = buildTypeStructure(collection);
|
|
618
|
+
return `interface Tokens ${formatTypeStructure(typeObj)}`;
|
|
619
|
+
}
|
|
620
|
+
function buildTypeStructure(collection) {
|
|
621
|
+
const result = {};
|
|
622
|
+
for (const token of collection.tokens) {
|
|
623
|
+
let current = result;
|
|
624
|
+
for (let i = 0; i < token.path.length - 1; i++) {
|
|
625
|
+
const key = token.path[i];
|
|
626
|
+
if (!(key in current)) {
|
|
627
|
+
current[key] = {};
|
|
628
|
+
}
|
|
629
|
+
current = current[key];
|
|
630
|
+
}
|
|
631
|
+
const lastKey = token.path[token.path.length - 1];
|
|
632
|
+
current[lastKey] = "string";
|
|
633
|
+
}
|
|
634
|
+
return result;
|
|
635
|
+
}
|
|
636
|
+
function formatTypeStructure(obj, indent = 0) {
|
|
637
|
+
const spaces = " ".repeat(indent);
|
|
638
|
+
const lines = ["{"];
|
|
639
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
640
|
+
const safeKey = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(key) ? key : `'${key}'`;
|
|
641
|
+
if (typeof value === "string") {
|
|
642
|
+
lines.push(`${spaces} ${safeKey}: ${value};`);
|
|
643
|
+
} else {
|
|
644
|
+
lines.push(
|
|
645
|
+
`${spaces} ${safeKey}: ${formatTypeStructure(value, indent + 1)};`
|
|
646
|
+
);
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
lines.push(`${spaces}}`);
|
|
650
|
+
return lines.join("\n");
|
|
651
|
+
}
|
|
652
|
+
function transformToTailwind(collection) {
|
|
653
|
+
const colors = {};
|
|
654
|
+
const spacing = {};
|
|
655
|
+
const fontSize = {};
|
|
656
|
+
const fontFamily = {};
|
|
657
|
+
const borderRadius = {};
|
|
658
|
+
const boxShadow = {};
|
|
659
|
+
for (const token of collection.tokens) {
|
|
660
|
+
const path3 = token.path;
|
|
661
|
+
const value = token.resolvedValue;
|
|
662
|
+
if (path3[0] === "color" || path3[0] === "colors") {
|
|
663
|
+
setNestedValue(colors, path3.slice(1), value);
|
|
664
|
+
} else if (path3[0] === "spacing") {
|
|
665
|
+
spacing[path3.slice(1).join("-")] = value;
|
|
666
|
+
} else if (path3[0] === "typography" && path3[1] === "fontSize") {
|
|
667
|
+
fontSize[path3[2]] = value;
|
|
668
|
+
} else if (path3[0] === "typography" && path3[1] === "fontFamily") {
|
|
669
|
+
fontFamily[path3[2]] = value.split(",").map((f) => f.trim());
|
|
670
|
+
} else if (path3[0] === "effects" && path3[1] === "radius") {
|
|
671
|
+
borderRadius[path3[2]] = value;
|
|
672
|
+
} else if (path3[0] === "effects" && path3[1] === "shadow") {
|
|
673
|
+
boxShadow[path3[2]] = value;
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
const config = {
|
|
677
|
+
theme: {
|
|
678
|
+
extend: {
|
|
679
|
+
colors,
|
|
680
|
+
spacing,
|
|
681
|
+
fontSize,
|
|
682
|
+
fontFamily,
|
|
683
|
+
borderRadius,
|
|
684
|
+
boxShadow
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
};
|
|
688
|
+
return `module.exports = ${JSON.stringify(config, null, 2)};`;
|
|
689
|
+
}
|
|
690
|
+
function setNestedValue(obj, path3, value) {
|
|
691
|
+
let current = obj;
|
|
692
|
+
for (let i = 0; i < path3.length - 1; i++) {
|
|
693
|
+
const key = path3[i];
|
|
694
|
+
if (!(key in current)) {
|
|
695
|
+
current[key] = {};
|
|
696
|
+
}
|
|
697
|
+
current = current[key];
|
|
698
|
+
}
|
|
699
|
+
current[path3[path3.length - 1]] = value;
|
|
700
|
+
}
|
|
701
|
+
function applyThemeOverrides(baseCollection, overrides) {
|
|
702
|
+
const mergedTokens = [...baseCollection.tokens];
|
|
703
|
+
for (const override of overrides.tokens) {
|
|
704
|
+
const pathStr = pathToString(override.path);
|
|
705
|
+
const existingIndex = mergedTokens.findIndex((t) => pathToString(t.path) === pathStr);
|
|
706
|
+
if (existingIndex >= 0) {
|
|
707
|
+
mergedTokens[existingIndex] = { ...mergedTokens[existingIndex], ...override };
|
|
708
|
+
} else {
|
|
709
|
+
mergedTokens.push(override);
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
return {
|
|
713
|
+
tokens: mergedTokens,
|
|
714
|
+
byPath: new Map(mergedTokens.map((t) => [pathToString(t.path), t])),
|
|
715
|
+
byName: new Map(mergedTokens.map((t) => [t.name, t]))
|
|
716
|
+
};
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
// src/themes.ts
|
|
720
|
+
var defaultThemes = {
|
|
721
|
+
light: {
|
|
722
|
+
name: "light",
|
|
723
|
+
displayName: "Light",
|
|
724
|
+
mode: "light",
|
|
725
|
+
selector: ':root, [data-theme="light"]'
|
|
726
|
+
},
|
|
727
|
+
dark: {
|
|
728
|
+
name: "dark",
|
|
729
|
+
displayName: "Dark",
|
|
730
|
+
mode: "dark",
|
|
731
|
+
selector: '[data-theme="dark"]',
|
|
732
|
+
mediaQuery: "(prefers-color-scheme: dark)",
|
|
733
|
+
extends: "light"
|
|
734
|
+
},
|
|
735
|
+
"high-contrast": {
|
|
736
|
+
name: "high-contrast",
|
|
737
|
+
displayName: "High Contrast",
|
|
738
|
+
mode: "high-contrast",
|
|
739
|
+
selector: '[data-theme="high-contrast"]',
|
|
740
|
+
mediaQuery: "(prefers-contrast: more)",
|
|
741
|
+
extends: "light"
|
|
742
|
+
},
|
|
743
|
+
"high-contrast-dark": {
|
|
744
|
+
name: "high-contrast-dark",
|
|
745
|
+
displayName: "High Contrast Dark",
|
|
746
|
+
mode: "high-contrast-dark",
|
|
747
|
+
selector: '[data-theme="high-contrast-dark"]',
|
|
748
|
+
extends: "dark"
|
|
749
|
+
},
|
|
750
|
+
dim: {
|
|
751
|
+
name: "dim",
|
|
752
|
+
displayName: "Dim",
|
|
753
|
+
mode: "dim",
|
|
754
|
+
selector: '[data-theme="dim"]',
|
|
755
|
+
extends: "dark"
|
|
756
|
+
}
|
|
757
|
+
};
|
|
758
|
+
function createTheme(name, baseTokens, overrideTokens, config) {
|
|
759
|
+
const tokens = overrideTokens ? applyThemeOverrides(baseTokens, overrideTokens) : baseTokens;
|
|
760
|
+
const resolvedTokens = resolveTokens(tokens);
|
|
761
|
+
const themeConfig = { ...defaultThemes.light, ...config, name };
|
|
762
|
+
return {
|
|
763
|
+
name,
|
|
764
|
+
tokens: resolvedTokens,
|
|
765
|
+
extends: themeConfig.extends,
|
|
766
|
+
selector: themeConfig.selector,
|
|
767
|
+
mediaQuery: themeConfig.mediaQuery
|
|
768
|
+
};
|
|
769
|
+
}
|
|
770
|
+
function generateThemesCss(themes, prefix = "nice") {
|
|
771
|
+
const sections = [];
|
|
772
|
+
for (const theme of themes) {
|
|
773
|
+
const vars = generateThemeVariables(theme, prefix);
|
|
774
|
+
sections.push(`${theme.selector} {
|
|
775
|
+
${vars}
|
|
776
|
+
}`);
|
|
777
|
+
if (theme.mediaQuery) {
|
|
778
|
+
sections.push(
|
|
779
|
+
`@media ${theme.mediaQuery} {
|
|
780
|
+
:root {
|
|
781
|
+
${vars.split("\n").map((l) => ` ${l}`).join("\n")}
|
|
782
|
+
}
|
|
783
|
+
}`
|
|
784
|
+
);
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
return sections.join("\n\n");
|
|
788
|
+
}
|
|
789
|
+
function generateThemeVariables(theme, prefix) {
|
|
790
|
+
const lines = [];
|
|
791
|
+
for (const token of theme.tokens.tokens) {
|
|
792
|
+
const varName = `--${prefix}-${token.path.join("-")}`;
|
|
793
|
+
lines.push(` ${varName}: ${token.resolvedValue};`);
|
|
794
|
+
}
|
|
795
|
+
return lines.join("\n");
|
|
796
|
+
}
|
|
797
|
+
function generateThemeSwitcher() {
|
|
798
|
+
return `
|
|
799
|
+
/**
|
|
800
|
+
* Nice2Dev Theme Switcher
|
|
801
|
+
* Auto-generated by @nice2dev/design-tokens
|
|
802
|
+
*/
|
|
803
|
+
|
|
804
|
+
const THEME_KEY = 'nice-theme';
|
|
805
|
+
const THEMES = ['light', 'dark', 'high-contrast', 'high-contrast-dark', 'dim'];
|
|
806
|
+
|
|
807
|
+
/**
|
|
808
|
+
* Get current theme
|
|
809
|
+
*/
|
|
810
|
+
function getTheme() {
|
|
811
|
+
return document.documentElement.getAttribute('data-theme') || 'light';
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
/**
|
|
815
|
+
* Set theme
|
|
816
|
+
*/
|
|
817
|
+
function setTheme(theme) {
|
|
818
|
+
if (!THEMES.includes(theme)) {
|
|
819
|
+
console.warn(\`Invalid theme: \${theme}\`);
|
|
820
|
+
return;
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
document.documentElement.setAttribute('data-theme', theme);
|
|
824
|
+
localStorage.setItem(THEME_KEY, theme);
|
|
825
|
+
|
|
826
|
+
// Dispatch event
|
|
827
|
+
window.dispatchEvent(new CustomEvent('nice-theme-change', { detail: { theme } }));
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
/**
|
|
831
|
+
* Toggle between light and dark
|
|
832
|
+
*/
|
|
833
|
+
function toggleTheme() {
|
|
834
|
+
const current = getTheme();
|
|
835
|
+
const next = current === 'dark' ? 'light' : 'dark';
|
|
836
|
+
setTheme(next);
|
|
837
|
+
return next;
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
/**
|
|
841
|
+
* Use system preference
|
|
842
|
+
*/
|
|
843
|
+
function useSystemTheme() {
|
|
844
|
+
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
|
|
845
|
+
const prefersHighContrast = window.matchMedia('(prefers-contrast: more)').matches;
|
|
846
|
+
|
|
847
|
+
let theme = 'light';
|
|
848
|
+
if (prefersDark && prefersHighContrast) {
|
|
849
|
+
theme = 'high-contrast-dark';
|
|
850
|
+
} else if (prefersDark) {
|
|
851
|
+
theme = 'dark';
|
|
852
|
+
} else if (prefersHighContrast) {
|
|
853
|
+
theme = 'high-contrast';
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
setTheme(theme);
|
|
857
|
+
return theme;
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
/**
|
|
861
|
+
* Initialize theme on page load
|
|
862
|
+
*/
|
|
863
|
+
function initTheme() {
|
|
864
|
+
const saved = localStorage.getItem(THEME_KEY);
|
|
865
|
+
|
|
866
|
+
if (saved && THEMES.includes(saved)) {
|
|
867
|
+
setTheme(saved);
|
|
868
|
+
} else {
|
|
869
|
+
useSystemTheme();
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
// Listen for system changes
|
|
873
|
+
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => {
|
|
874
|
+
if (!localStorage.getItem(THEME_KEY)) {
|
|
875
|
+
useSystemTheme();
|
|
876
|
+
}
|
|
877
|
+
});
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
// Auto-init
|
|
881
|
+
if (typeof document !== 'undefined') {
|
|
882
|
+
if (document.readyState === 'loading') {
|
|
883
|
+
document.addEventListener('DOMContentLoaded', initTheme);
|
|
884
|
+
} else {
|
|
885
|
+
initTheme();
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
|
|
889
|
+
export { getTheme, setTheme, toggleTheme, useSystemTheme, initTheme, THEMES };
|
|
890
|
+
`.trim();
|
|
891
|
+
}
|
|
892
|
+
function generateReactThemeContext() {
|
|
893
|
+
return `
|
|
894
|
+
'use client';
|
|
895
|
+
|
|
896
|
+
import React, { createContext, useContext, useEffect, useState, useCallback } from 'react';
|
|
897
|
+
|
|
898
|
+
type Theme = 'light' | 'dark' | 'high-contrast' | 'high-contrast-dark' | 'dim';
|
|
899
|
+
|
|
900
|
+
interface ThemeContextValue {
|
|
901
|
+
theme: Theme;
|
|
902
|
+
setTheme: (theme: Theme) => void;
|
|
903
|
+
toggleTheme: () => void;
|
|
904
|
+
useSystemTheme: () => void;
|
|
905
|
+
}
|
|
906
|
+
|
|
907
|
+
const ThemeContext = createContext<ThemeContextValue | undefined>(undefined);
|
|
908
|
+
|
|
909
|
+
const THEME_KEY = 'nice-theme';
|
|
910
|
+
const THEMES: Theme[] = ['light', 'dark', 'high-contrast', 'high-contrast-dark', 'dim'];
|
|
911
|
+
|
|
912
|
+
interface ThemeProviderProps {
|
|
913
|
+
children: React.ReactNode;
|
|
914
|
+
defaultTheme?: Theme;
|
|
915
|
+
}
|
|
916
|
+
|
|
917
|
+
export function ThemeProvider({ children, defaultTheme = 'light' }: ThemeProviderProps) {
|
|
918
|
+
const [theme, setThemeState] = useState<Theme>(defaultTheme);
|
|
919
|
+
|
|
920
|
+
useEffect(() => {
|
|
921
|
+
const saved = localStorage.getItem(THEME_KEY) as Theme | null;
|
|
922
|
+
if (saved && THEMES.includes(saved)) {
|
|
923
|
+
setThemeState(saved);
|
|
924
|
+
document.documentElement.setAttribute('data-theme', saved);
|
|
925
|
+
} else {
|
|
926
|
+
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
|
|
927
|
+
const initial = prefersDark ? 'dark' : 'light';
|
|
928
|
+
setThemeState(initial);
|
|
929
|
+
document.documentElement.setAttribute('data-theme', initial);
|
|
930
|
+
}
|
|
931
|
+
}, []);
|
|
932
|
+
|
|
933
|
+
const setTheme = useCallback((newTheme: Theme) => {
|
|
934
|
+
setThemeState(newTheme);
|
|
935
|
+
document.documentElement.setAttribute('data-theme', newTheme);
|
|
936
|
+
localStorage.setItem(THEME_KEY, newTheme);
|
|
937
|
+
}, []);
|
|
938
|
+
|
|
939
|
+
const toggleTheme = useCallback(() => {
|
|
940
|
+
setTheme(theme === 'dark' ? 'light' : 'dark');
|
|
941
|
+
}, [theme, setTheme]);
|
|
942
|
+
|
|
943
|
+
const useSystemTheme = useCallback(() => {
|
|
944
|
+
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
|
|
945
|
+
const prefersHighContrast = window.matchMedia('(prefers-contrast: more)').matches;
|
|
946
|
+
|
|
947
|
+
let systemTheme: Theme = 'light';
|
|
948
|
+
if (prefersDark && prefersHighContrast) {
|
|
949
|
+
systemTheme = 'high-contrast-dark';
|
|
950
|
+
} else if (prefersDark) {
|
|
951
|
+
systemTheme = 'dark';
|
|
952
|
+
} else if (prefersHighContrast) {
|
|
953
|
+
systemTheme = 'high-contrast';
|
|
954
|
+
}
|
|
955
|
+
|
|
956
|
+
setTheme(systemTheme);
|
|
957
|
+
localStorage.removeItem(THEME_KEY);
|
|
958
|
+
}, [setTheme]);
|
|
959
|
+
|
|
960
|
+
return (
|
|
961
|
+
<ThemeContext.Provider value={{ theme, setTheme, toggleTheme, useSystemTheme }}>
|
|
962
|
+
{children}
|
|
963
|
+
</ThemeContext.Provider>
|
|
964
|
+
);
|
|
965
|
+
}
|
|
966
|
+
|
|
967
|
+
export function useTheme(): ThemeContextValue {
|
|
968
|
+
const context = useContext(ThemeContext);
|
|
969
|
+
if (!context) {
|
|
970
|
+
throw new Error('useTheme must be used within a ThemeProvider');
|
|
971
|
+
}
|
|
972
|
+
return context;
|
|
973
|
+
}
|
|
974
|
+
|
|
975
|
+
export { THEMES };
|
|
976
|
+
export type { Theme };
|
|
977
|
+
`.trim();
|
|
978
|
+
}
|
|
979
|
+
async function generateDarkModeTokens(lightTokens) {
|
|
980
|
+
const darkTokens = [];
|
|
981
|
+
const chroma2 = (await import("chroma-js")).default;
|
|
982
|
+
for (const token of lightTokens.tokens) {
|
|
983
|
+
if (token.type !== "color" || !token.path.includes("semantic")) {
|
|
984
|
+
continue;
|
|
985
|
+
}
|
|
986
|
+
const pathStr = pathToString(token.path);
|
|
987
|
+
if (pathStr.includes("dark")) {
|
|
988
|
+
continue;
|
|
989
|
+
}
|
|
990
|
+
try {
|
|
991
|
+
const color = chroma2(token.resolvedValue);
|
|
992
|
+
let darkValue;
|
|
993
|
+
if (token.name.includes("background") || token.name.includes("bg")) {
|
|
994
|
+
const [h, s, l] = color.hsl();
|
|
995
|
+
darkValue = chroma2.hsl(h, s, 1 - l).hex();
|
|
996
|
+
} else if (token.name.includes("text") || token.name.includes("foreground")) {
|
|
997
|
+
const [h, s, l] = color.hsl();
|
|
998
|
+
darkValue = chroma2.hsl(h, s, 1 - l).hex();
|
|
999
|
+
} else if (token.name.includes("border")) {
|
|
1000
|
+
darkValue = color.brighten(0.5).hex();
|
|
1001
|
+
} else {
|
|
1002
|
+
const [h, s, l] = color.hsl();
|
|
1003
|
+
darkValue = chroma2.hsl(h, Math.min(s * 1.1, 1), Math.min(l * 1.2, 0.9)).hex();
|
|
1004
|
+
}
|
|
1005
|
+
darkTokens.push({
|
|
1006
|
+
...token,
|
|
1007
|
+
value: darkValue,
|
|
1008
|
+
resolvedValue: darkValue
|
|
1009
|
+
});
|
|
1010
|
+
} catch {
|
|
1011
|
+
}
|
|
1012
|
+
}
|
|
1013
|
+
return darkTokens;
|
|
1014
|
+
}
|
|
1015
|
+
async function generateHighContrastTokens(baseTokens, _minContrast = 7) {
|
|
1016
|
+
const contrastTokens = [];
|
|
1017
|
+
const chroma2 = (await import("chroma-js")).default;
|
|
1018
|
+
for (const token of baseTokens.tokens) {
|
|
1019
|
+
if (token.type !== "color") {
|
|
1020
|
+
continue;
|
|
1021
|
+
}
|
|
1022
|
+
try {
|
|
1023
|
+
const color = chroma2(token.resolvedValue);
|
|
1024
|
+
const [, s, l] = color.hsl();
|
|
1025
|
+
let newL = l;
|
|
1026
|
+
if (l > 0.5) {
|
|
1027
|
+
newL = Math.min(l * 1.2, 1);
|
|
1028
|
+
} else {
|
|
1029
|
+
newL = Math.max(l * 0.8, 0);
|
|
1030
|
+
}
|
|
1031
|
+
const newS = Math.min(s * 1.3, 1);
|
|
1032
|
+
const newColor = chroma2.hsl(color.get("hsl.h"), newS, newL);
|
|
1033
|
+
contrastTokens.push({
|
|
1034
|
+
...token,
|
|
1035
|
+
value: newColor.hex(),
|
|
1036
|
+
resolvedValue: newColor.hex()
|
|
1037
|
+
});
|
|
1038
|
+
} catch {
|
|
1039
|
+
}
|
|
1040
|
+
}
|
|
1041
|
+
return contrastTokens;
|
|
1042
|
+
}
|
|
1043
|
+
|
|
1044
|
+
// src/generator.ts
|
|
1045
|
+
var defaultOptions = {
|
|
1046
|
+
formats: ["css"],
|
|
1047
|
+
outputDir: "./dist",
|
|
1048
|
+
prefix: "nice",
|
|
1049
|
+
includePrimitives: true,
|
|
1050
|
+
separateFiles: false,
|
|
1051
|
+
includeDarkMode: true,
|
|
1052
|
+
includeComponents: true
|
|
1053
|
+
};
|
|
1054
|
+
var TokenGenerator = class {
|
|
1055
|
+
constructor(options = {}) {
|
|
1056
|
+
this.plugins = [];
|
|
1057
|
+
this.collection = null;
|
|
1058
|
+
this.themes = [];
|
|
1059
|
+
this.options = { ...defaultOptions, ...options };
|
|
1060
|
+
}
|
|
1061
|
+
/**
|
|
1062
|
+
* Add plugin
|
|
1063
|
+
*/
|
|
1064
|
+
use(plugin) {
|
|
1065
|
+
this.plugins.push(plugin);
|
|
1066
|
+
return this;
|
|
1067
|
+
}
|
|
1068
|
+
/**
|
|
1069
|
+
* Load tokens from files
|
|
1070
|
+
*/
|
|
1071
|
+
load(files) {
|
|
1072
|
+
const tokenFile = parseTokenFiles(files);
|
|
1073
|
+
let processedTokens = [tokenFile];
|
|
1074
|
+
for (const plugin of this.plugins) {
|
|
1075
|
+
if (plugin.beforeResolve) {
|
|
1076
|
+
processedTokens = plugin.beforeResolve(processedTokens);
|
|
1077
|
+
}
|
|
1078
|
+
}
|
|
1079
|
+
const flatTokens = flattenTokens(processedTokens[0]);
|
|
1080
|
+
let collection = createTokenCollection(flatTokens);
|
|
1081
|
+
collection = resolveTokens(collection);
|
|
1082
|
+
for (const plugin of this.plugins) {
|
|
1083
|
+
if (plugin.afterResolve) {
|
|
1084
|
+
collection = plugin.afterResolve(collection);
|
|
1085
|
+
}
|
|
1086
|
+
}
|
|
1087
|
+
this.collection = collection;
|
|
1088
|
+
return this;
|
|
1089
|
+
}
|
|
1090
|
+
/**
|
|
1091
|
+
* Load tokens from directory
|
|
1092
|
+
*/
|
|
1093
|
+
loadDirectory(dir, pattern = "**/*.json") {
|
|
1094
|
+
const glob = require("fast-glob");
|
|
1095
|
+
const files = glob.sync(path2.join(dir, pattern));
|
|
1096
|
+
return this.load(files);
|
|
1097
|
+
}
|
|
1098
|
+
/**
|
|
1099
|
+
* Add theme
|
|
1100
|
+
*/
|
|
1101
|
+
addTheme(name, overrideTokens) {
|
|
1102
|
+
if (!this.collection) {
|
|
1103
|
+
throw new Error("Load tokens first before adding themes");
|
|
1104
|
+
}
|
|
1105
|
+
const theme = createTheme(name, this.collection, overrideTokens);
|
|
1106
|
+
this.themes.push(theme);
|
|
1107
|
+
return this;
|
|
1108
|
+
}
|
|
1109
|
+
/**
|
|
1110
|
+
* Generate output files
|
|
1111
|
+
*/
|
|
1112
|
+
async generate() {
|
|
1113
|
+
if (!this.collection) {
|
|
1114
|
+
throw new Error("No tokens loaded");
|
|
1115
|
+
}
|
|
1116
|
+
fs2.mkdirSync(this.options.outputDir, { recursive: true });
|
|
1117
|
+
for (const format of this.options.formats) {
|
|
1118
|
+
await this.generateFormat(format);
|
|
1119
|
+
}
|
|
1120
|
+
if (this.themes.length > 0) {
|
|
1121
|
+
await this.generateThemeFiles();
|
|
1122
|
+
}
|
|
1123
|
+
}
|
|
1124
|
+
/**
|
|
1125
|
+
* Generate single format
|
|
1126
|
+
*/
|
|
1127
|
+
async generateFormat(format) {
|
|
1128
|
+
if (!this.collection) {
|
|
1129
|
+
return;
|
|
1130
|
+
}
|
|
1131
|
+
for (const plugin of this.plugins) {
|
|
1132
|
+
if (plugin.customFormat) {
|
|
1133
|
+
const output = plugin.customFormat(this.collection, this.options);
|
|
1134
|
+
if (output) {
|
|
1135
|
+
const ext = this.getExtension(format);
|
|
1136
|
+
fs2.writeFileSync(
|
|
1137
|
+
path2.join(this.options.outputDir, `tokens.${plugin.name}.${ext}`),
|
|
1138
|
+
output
|
|
1139
|
+
);
|
|
1140
|
+
}
|
|
1141
|
+
}
|
|
1142
|
+
}
|
|
1143
|
+
if (this.options.separateFiles) {
|
|
1144
|
+
await this.generateSeparateFiles(format);
|
|
1145
|
+
} else {
|
|
1146
|
+
await this.generateSingleFile(format);
|
|
1147
|
+
}
|
|
1148
|
+
}
|
|
1149
|
+
/**
|
|
1150
|
+
* Generate single output file
|
|
1151
|
+
*/
|
|
1152
|
+
async generateSingleFile(format) {
|
|
1153
|
+
if (!this.collection) {
|
|
1154
|
+
return;
|
|
1155
|
+
}
|
|
1156
|
+
const content = this.transform(this.collection, format);
|
|
1157
|
+
const filename = `tokens.${this.getExtension(format)}`;
|
|
1158
|
+
const filepath = path2.join(this.options.outputDir, filename);
|
|
1159
|
+
fs2.writeFileSync(filepath, content);
|
|
1160
|
+
console.log(`Generated: ${filepath}`);
|
|
1161
|
+
}
|
|
1162
|
+
/**
|
|
1163
|
+
* Generate separate files by category
|
|
1164
|
+
*/
|
|
1165
|
+
async generateSeparateFiles(format) {
|
|
1166
|
+
if (!this.collection) {
|
|
1167
|
+
return;
|
|
1168
|
+
}
|
|
1169
|
+
const categories = getCategories(this.collection);
|
|
1170
|
+
const ext = this.getExtension(format);
|
|
1171
|
+
for (const category of categories) {
|
|
1172
|
+
const tokens = this.collection.tokens.filter((t) => t.path[0] === category);
|
|
1173
|
+
const catCollection = {
|
|
1174
|
+
tokens,
|
|
1175
|
+
byPath: new Map(tokens.map((t) => [t.path.join("."), t])),
|
|
1176
|
+
byName: new Map(tokens.map((t) => [t.name, t]))
|
|
1177
|
+
};
|
|
1178
|
+
const content = this.transform(catCollection, format);
|
|
1179
|
+
const filename = `${category}.${ext}`;
|
|
1180
|
+
const filepath = path2.join(this.options.outputDir, filename);
|
|
1181
|
+
fs2.writeFileSync(filepath, content);
|
|
1182
|
+
console.log(`Generated: ${filepath}`);
|
|
1183
|
+
}
|
|
1184
|
+
this.generateIndexFile(categories, format);
|
|
1185
|
+
}
|
|
1186
|
+
/**
|
|
1187
|
+
* Generate index file for separated files
|
|
1188
|
+
*/
|
|
1189
|
+
generateIndexFile(categories, format) {
|
|
1190
|
+
const ext = this.getExtension(format);
|
|
1191
|
+
let content = "";
|
|
1192
|
+
switch (format) {
|
|
1193
|
+
case "css":
|
|
1194
|
+
content = categories.map((c) => `@import './${c}.css';`).join("\n");
|
|
1195
|
+
break;
|
|
1196
|
+
case "scss":
|
|
1197
|
+
content = categories.map((c) => `@import './${c}';`).join("\n");
|
|
1198
|
+
break;
|
|
1199
|
+
case "js":
|
|
1200
|
+
case "ts":
|
|
1201
|
+
content = categories.map((c) => `export * from './${c}';`).join("\n");
|
|
1202
|
+
break;
|
|
1203
|
+
default:
|
|
1204
|
+
return;
|
|
1205
|
+
}
|
|
1206
|
+
const filepath = path2.join(this.options.outputDir, `index.${ext}`);
|
|
1207
|
+
fs2.writeFileSync(filepath, content);
|
|
1208
|
+
console.log(`Generated: ${filepath}`);
|
|
1209
|
+
}
|
|
1210
|
+
/**
|
|
1211
|
+
* Transform collection to format
|
|
1212
|
+
*/
|
|
1213
|
+
transform(collection, format) {
|
|
1214
|
+
const prefix = this.options.prefix ?? "nice";
|
|
1215
|
+
switch (format) {
|
|
1216
|
+
case "css":
|
|
1217
|
+
return transformToCss(collection, prefix);
|
|
1218
|
+
case "scss":
|
|
1219
|
+
return transformToScss(collection, prefix);
|
|
1220
|
+
case "js":
|
|
1221
|
+
return transformToJs(collection);
|
|
1222
|
+
case "ts":
|
|
1223
|
+
return transformToTs(collection);
|
|
1224
|
+
case "json":
|
|
1225
|
+
return JSON.stringify(this.buildNestedObject(collection), null, 2);
|
|
1226
|
+
case "tailwind":
|
|
1227
|
+
return transformToTailwind(collection);
|
|
1228
|
+
default:
|
|
1229
|
+
throw new Error(`Unsupported format: ${format}`);
|
|
1230
|
+
}
|
|
1231
|
+
}
|
|
1232
|
+
/**
|
|
1233
|
+
* Build nested object from flat tokens
|
|
1234
|
+
*/
|
|
1235
|
+
buildNestedObject(collection) {
|
|
1236
|
+
const result = {};
|
|
1237
|
+
for (const token of collection.tokens) {
|
|
1238
|
+
let current = result;
|
|
1239
|
+
for (let i = 0; i < token.path.length - 1; i++) {
|
|
1240
|
+
const key = token.path[i];
|
|
1241
|
+
if (!(key in current)) {
|
|
1242
|
+
current[key] = {};
|
|
1243
|
+
}
|
|
1244
|
+
current = current[key];
|
|
1245
|
+
}
|
|
1246
|
+
current[token.path[token.path.length - 1]] = token.resolvedValue;
|
|
1247
|
+
}
|
|
1248
|
+
return result;
|
|
1249
|
+
}
|
|
1250
|
+
/**
|
|
1251
|
+
* Get file extension for format
|
|
1252
|
+
*/
|
|
1253
|
+
getExtension(format) {
|
|
1254
|
+
switch (format) {
|
|
1255
|
+
case "css":
|
|
1256
|
+
return "css";
|
|
1257
|
+
case "scss":
|
|
1258
|
+
return "scss";
|
|
1259
|
+
case "js":
|
|
1260
|
+
return "js";
|
|
1261
|
+
case "ts":
|
|
1262
|
+
return "ts";
|
|
1263
|
+
case "json":
|
|
1264
|
+
return "json";
|
|
1265
|
+
case "tailwind":
|
|
1266
|
+
return "tailwind.js";
|
|
1267
|
+
default:
|
|
1268
|
+
return "txt";
|
|
1269
|
+
}
|
|
1270
|
+
}
|
|
1271
|
+
/**
|
|
1272
|
+
* Generate theme-related files
|
|
1273
|
+
*/
|
|
1274
|
+
async generateThemeFiles() {
|
|
1275
|
+
const prefix = this.options.prefix ?? "nice";
|
|
1276
|
+
const themesCss = generateThemesCss(this.themes, prefix);
|
|
1277
|
+
fs2.writeFileSync(path2.join(this.options.outputDir, "themes.css"), themesCss);
|
|
1278
|
+
console.log(`Generated: themes.css`);
|
|
1279
|
+
const switcherJs = generateThemeSwitcher();
|
|
1280
|
+
fs2.writeFileSync(path2.join(this.options.outputDir, "theme-switcher.js"), switcherJs);
|
|
1281
|
+
console.log(`Generated: theme-switcher.js`);
|
|
1282
|
+
const reactContext = generateReactThemeContext();
|
|
1283
|
+
fs2.writeFileSync(path2.join(this.options.outputDir, "ThemeContext.tsx"), reactContext);
|
|
1284
|
+
console.log(`Generated: ThemeContext.tsx`);
|
|
1285
|
+
}
|
|
1286
|
+
/**
|
|
1287
|
+
* Get generated token collection
|
|
1288
|
+
*/
|
|
1289
|
+
getCollection() {
|
|
1290
|
+
return this.collection;
|
|
1291
|
+
}
|
|
1292
|
+
/**
|
|
1293
|
+
* Get generated themes
|
|
1294
|
+
*/
|
|
1295
|
+
getThemes() {
|
|
1296
|
+
return this.themes;
|
|
1297
|
+
}
|
|
1298
|
+
};
|
|
1299
|
+
function createGenerator(options) {
|
|
1300
|
+
return new TokenGenerator(options);
|
|
1301
|
+
}
|
|
1302
|
+
async function generateTokens(tokenDir, outputDir, options) {
|
|
1303
|
+
const generator = createGenerator({
|
|
1304
|
+
...options,
|
|
1305
|
+
outputDir
|
|
1306
|
+
});
|
|
1307
|
+
generator.loadDirectory(tokenDir);
|
|
1308
|
+
await generator.generate();
|
|
1309
|
+
}
|
|
1310
|
+
|
|
1311
|
+
// src/presets.ts
|
|
1312
|
+
function generateColorScale2(baseColor) {
|
|
1313
|
+
return {
|
|
1314
|
+
50: lighten(baseColor, 0.95),
|
|
1315
|
+
100: lighten(baseColor, 0.9),
|
|
1316
|
+
200: lighten(baseColor, 0.75),
|
|
1317
|
+
300: lighten(baseColor, 0.6),
|
|
1318
|
+
400: lighten(baseColor, 0.3),
|
|
1319
|
+
500: baseColor,
|
|
1320
|
+
600: darken(baseColor, 0.1),
|
|
1321
|
+
700: darken(baseColor, 0.25),
|
|
1322
|
+
800: darken(baseColor, 0.4),
|
|
1323
|
+
900: darken(baseColor, 0.55),
|
|
1324
|
+
950: darken(baseColor, 0.7)
|
|
1325
|
+
};
|
|
1326
|
+
}
|
|
1327
|
+
function hexToHsl2(hex) {
|
|
1328
|
+
const r = parseInt(hex.slice(1, 3), 16) / 255;
|
|
1329
|
+
const g = parseInt(hex.slice(3, 5), 16) / 255;
|
|
1330
|
+
const b = parseInt(hex.slice(5, 7), 16) / 255;
|
|
1331
|
+
const max = Math.max(r, g, b);
|
|
1332
|
+
const min = Math.min(r, g, b);
|
|
1333
|
+
let h = 0;
|
|
1334
|
+
let s = 0;
|
|
1335
|
+
const l = (max + min) / 2;
|
|
1336
|
+
if (max !== min) {
|
|
1337
|
+
const d = max - min;
|
|
1338
|
+
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
|
|
1339
|
+
switch (max) {
|
|
1340
|
+
case r:
|
|
1341
|
+
h = ((g - b) / d + (g < b ? 6 : 0)) / 6;
|
|
1342
|
+
break;
|
|
1343
|
+
case g:
|
|
1344
|
+
h = ((b - r) / d + 2) / 6;
|
|
1345
|
+
break;
|
|
1346
|
+
case b:
|
|
1347
|
+
h = ((r - g) / d + 4) / 6;
|
|
1348
|
+
break;
|
|
1349
|
+
}
|
|
1350
|
+
}
|
|
1351
|
+
return [h * 360, s * 100, l * 100];
|
|
1352
|
+
}
|
|
1353
|
+
function hslToHex(h, s, l) {
|
|
1354
|
+
h /= 360;
|
|
1355
|
+
s /= 100;
|
|
1356
|
+
l /= 100;
|
|
1357
|
+
const hue2rgb = (p, q, t) => {
|
|
1358
|
+
if (t < 0) {
|
|
1359
|
+
t += 1;
|
|
1360
|
+
}
|
|
1361
|
+
if (t > 1) {
|
|
1362
|
+
t -= 1;
|
|
1363
|
+
}
|
|
1364
|
+
if (t < 1 / 6) {
|
|
1365
|
+
return p + (q - p) * 6 * t;
|
|
1366
|
+
}
|
|
1367
|
+
if (t < 1 / 2) {
|
|
1368
|
+
return q;
|
|
1369
|
+
}
|
|
1370
|
+
if (t < 2 / 3) {
|
|
1371
|
+
return p + (q - p) * (2 / 3 - t) * 6;
|
|
1372
|
+
}
|
|
1373
|
+
return p;
|
|
1374
|
+
};
|
|
1375
|
+
let r, g, b;
|
|
1376
|
+
if (s === 0) {
|
|
1377
|
+
r = g = b = l;
|
|
1378
|
+
} else {
|
|
1379
|
+
const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
|
|
1380
|
+
const p = 2 * l - q;
|
|
1381
|
+
r = hue2rgb(p, q, h + 1 / 3);
|
|
1382
|
+
g = hue2rgb(p, q, h);
|
|
1383
|
+
b = hue2rgb(p, q, h - 1 / 3);
|
|
1384
|
+
}
|
|
1385
|
+
const toHex = (n) => Math.round(n * 255).toString(16).padStart(2, "0");
|
|
1386
|
+
return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
|
|
1387
|
+
}
|
|
1388
|
+
function lighten(hex, amount) {
|
|
1389
|
+
const [h, s, l] = hexToHsl2(hex);
|
|
1390
|
+
return hslToHex(h, s, Math.min(100, l + (100 - l) * amount));
|
|
1391
|
+
}
|
|
1392
|
+
function darken(hex, amount) {
|
|
1393
|
+
const [h, s, l] = hexToHsl2(hex);
|
|
1394
|
+
return hslToHex(h, s, Math.max(0, l * (1 - amount)));
|
|
1395
|
+
}
|
|
1396
|
+
var GRAY_NEUTRAL = {
|
|
1397
|
+
50: "#f9fafb",
|
|
1398
|
+
100: "#f3f4f6",
|
|
1399
|
+
200: "#e5e7eb",
|
|
1400
|
+
300: "#d1d5db",
|
|
1401
|
+
400: "#9ca3af",
|
|
1402
|
+
500: "#6b7280",
|
|
1403
|
+
600: "#4b5563",
|
|
1404
|
+
700: "#374151",
|
|
1405
|
+
800: "#1f2937",
|
|
1406
|
+
900: "#111827",
|
|
1407
|
+
950: "#030712"
|
|
1408
|
+
};
|
|
1409
|
+
var SLATE_NEUTRAL = {
|
|
1410
|
+
50: "#f8fafc",
|
|
1411
|
+
100: "#f1f5f9",
|
|
1412
|
+
200: "#e2e8f0",
|
|
1413
|
+
300: "#cbd5e1",
|
|
1414
|
+
400: "#94a3b8",
|
|
1415
|
+
500: "#64748b",
|
|
1416
|
+
600: "#475569",
|
|
1417
|
+
700: "#334155",
|
|
1418
|
+
800: "#1e293b",
|
|
1419
|
+
900: "#0f172a",
|
|
1420
|
+
950: "#020617"
|
|
1421
|
+
};
|
|
1422
|
+
var ZINC_NEUTRAL = {
|
|
1423
|
+
50: "#fafafa",
|
|
1424
|
+
100: "#f4f4f5",
|
|
1425
|
+
200: "#e4e4e7",
|
|
1426
|
+
300: "#d4d4d8",
|
|
1427
|
+
400: "#a1a1aa",
|
|
1428
|
+
500: "#71717a",
|
|
1429
|
+
600: "#52525b",
|
|
1430
|
+
700: "#3f3f46",
|
|
1431
|
+
800: "#27272a",
|
|
1432
|
+
900: "#18181b",
|
|
1433
|
+
950: "#09090b"
|
|
1434
|
+
};
|
|
1435
|
+
var WARM_NEUTRAL = {
|
|
1436
|
+
50: "#faf5f0",
|
|
1437
|
+
100: "#f0e8dd",
|
|
1438
|
+
200: "#e0d0bb",
|
|
1439
|
+
300: "#cdb899",
|
|
1440
|
+
400: "#b89d77",
|
|
1441
|
+
500: "#9a7f5a",
|
|
1442
|
+
600: "#7d6548",
|
|
1443
|
+
700: "#604c37",
|
|
1444
|
+
800: "#443527",
|
|
1445
|
+
900: "#2a1f18",
|
|
1446
|
+
950: "#150f0c"
|
|
1447
|
+
};
|
|
1448
|
+
var PRESETS = [
|
|
1449
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
1450
|
+
// BRAND COLORS
|
|
1451
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
1452
|
+
{
|
|
1453
|
+
name: "ocean-blue",
|
|
1454
|
+
displayName: "Ocean Blue",
|
|
1455
|
+
description: "Deep blue tones inspired by the ocean",
|
|
1456
|
+
category: "brand",
|
|
1457
|
+
colors: {
|
|
1458
|
+
primary: generateColorScale2("#0077b6"),
|
|
1459
|
+
secondary: generateColorScale2("#00b4d8"),
|
|
1460
|
+
neutral: SLATE_NEUTRAL,
|
|
1461
|
+
success: "#22c55e",
|
|
1462
|
+
warning: "#f59e0b",
|
|
1463
|
+
error: "#ef4444",
|
|
1464
|
+
info: "#3b82f6"
|
|
1465
|
+
}
|
|
1466
|
+
},
|
|
1467
|
+
{
|
|
1468
|
+
name: "forest-green",
|
|
1469
|
+
displayName: "Forest Green",
|
|
1470
|
+
description: "Natural green tones inspired by forests",
|
|
1471
|
+
category: "brand",
|
|
1472
|
+
colors: {
|
|
1473
|
+
primary: generateColorScale2("#15803d"),
|
|
1474
|
+
secondary: generateColorScale2("#84cc16"),
|
|
1475
|
+
neutral: GRAY_NEUTRAL,
|
|
1476
|
+
success: "#22c55e",
|
|
1477
|
+
warning: "#f59e0b",
|
|
1478
|
+
error: "#ef4444",
|
|
1479
|
+
info: "#3b82f6"
|
|
1480
|
+
}
|
|
1481
|
+
},
|
|
1482
|
+
{
|
|
1483
|
+
name: "sunset-orange",
|
|
1484
|
+
displayName: "Sunset Orange",
|
|
1485
|
+
description: "Warm orange and coral tones",
|
|
1486
|
+
category: "brand",
|
|
1487
|
+
colors: {
|
|
1488
|
+
primary: generateColorScale2("#ea580c"),
|
|
1489
|
+
secondary: generateColorScale2("#facc15"),
|
|
1490
|
+
neutral: WARM_NEUTRAL,
|
|
1491
|
+
success: "#22c55e",
|
|
1492
|
+
warning: "#f59e0b",
|
|
1493
|
+
error: "#dc2626",
|
|
1494
|
+
info: "#0ea5e9"
|
|
1495
|
+
}
|
|
1496
|
+
},
|
|
1497
|
+
{
|
|
1498
|
+
name: "royal-purple",
|
|
1499
|
+
displayName: "Royal Purple",
|
|
1500
|
+
description: "Elegant purple and violet tones",
|
|
1501
|
+
category: "brand",
|
|
1502
|
+
colors: {
|
|
1503
|
+
primary: generateColorScale2("#7c3aed"),
|
|
1504
|
+
secondary: generateColorScale2("#c026d3"),
|
|
1505
|
+
neutral: SLATE_NEUTRAL,
|
|
1506
|
+
success: "#22c55e",
|
|
1507
|
+
warning: "#f59e0b",
|
|
1508
|
+
error: "#ef4444",
|
|
1509
|
+
info: "#3b82f6"
|
|
1510
|
+
}
|
|
1511
|
+
},
|
|
1512
|
+
{
|
|
1513
|
+
name: "cherry-red",
|
|
1514
|
+
displayName: "Cherry Red",
|
|
1515
|
+
description: "Bold red with dark accents",
|
|
1516
|
+
category: "bold",
|
|
1517
|
+
colors: {
|
|
1518
|
+
primary: generateColorScale2("#dc2626"),
|
|
1519
|
+
secondary: generateColorScale2("#1f2937"),
|
|
1520
|
+
neutral: ZINC_NEUTRAL,
|
|
1521
|
+
success: "#22c55e",
|
|
1522
|
+
warning: "#f59e0b",
|
|
1523
|
+
error: "#b91c1c",
|
|
1524
|
+
info: "#3b82f6"
|
|
1525
|
+
}
|
|
1526
|
+
},
|
|
1527
|
+
{
|
|
1528
|
+
name: "rose-gold",
|
|
1529
|
+
displayName: "Rose Gold",
|
|
1530
|
+
description: "Elegant rose and gold combination",
|
|
1531
|
+
category: "brand",
|
|
1532
|
+
colors: {
|
|
1533
|
+
primary: generateColorScale2("#f43f5e"),
|
|
1534
|
+
secondary: generateColorScale2("#d4a574"),
|
|
1535
|
+
neutral: WARM_NEUTRAL,
|
|
1536
|
+
success: "#22c55e",
|
|
1537
|
+
warning: "#f59e0b",
|
|
1538
|
+
error: "#e11d48",
|
|
1539
|
+
info: "#3b82f6"
|
|
1540
|
+
}
|
|
1541
|
+
},
|
|
1542
|
+
{
|
|
1543
|
+
name: "midnight",
|
|
1544
|
+
displayName: "Midnight",
|
|
1545
|
+
description: "Dark blue with cyan accents",
|
|
1546
|
+
category: "professional",
|
|
1547
|
+
colors: {
|
|
1548
|
+
primary: generateColorScale2("#1e3a5f"),
|
|
1549
|
+
secondary: generateColorScale2("#06b6d4"),
|
|
1550
|
+
neutral: SLATE_NEUTRAL,
|
|
1551
|
+
success: "#22c55e",
|
|
1552
|
+
warning: "#f59e0b",
|
|
1553
|
+
error: "#ef4444",
|
|
1554
|
+
info: "#0ea5e9"
|
|
1555
|
+
}
|
|
1556
|
+
},
|
|
1557
|
+
{
|
|
1558
|
+
name: "teal-modern",
|
|
1559
|
+
displayName: "Teal Modern",
|
|
1560
|
+
description: "Modern teal with warm accents",
|
|
1561
|
+
category: "technology",
|
|
1562
|
+
colors: {
|
|
1563
|
+
primary: generateColorScale2("#0d9488"),
|
|
1564
|
+
secondary: generateColorScale2("#f97316"),
|
|
1565
|
+
neutral: GRAY_NEUTRAL,
|
|
1566
|
+
success: "#22c55e",
|
|
1567
|
+
warning: "#f59e0b",
|
|
1568
|
+
error: "#ef4444",
|
|
1569
|
+
info: "#14b8a6"
|
|
1570
|
+
}
|
|
1571
|
+
},
|
|
1572
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
1573
|
+
// HEALTHCARE
|
|
1574
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
1575
|
+
{
|
|
1576
|
+
name: "healthcare-trust",
|
|
1577
|
+
displayName: "Healthcare Trust",
|
|
1578
|
+
description: "Trustworthy blue for medical applications",
|
|
1579
|
+
category: "healthcare",
|
|
1580
|
+
colors: {
|
|
1581
|
+
primary: generateColorScale2("#0077b6"),
|
|
1582
|
+
secondary: generateColorScale2("#48cae4"),
|
|
1583
|
+
neutral: SLATE_NEUTRAL,
|
|
1584
|
+
success: "#22c55e",
|
|
1585
|
+
warning: "#f59e0b",
|
|
1586
|
+
error: "#ef4444",
|
|
1587
|
+
info: "#3b82f6"
|
|
1588
|
+
},
|
|
1589
|
+
typography: {
|
|
1590
|
+
fontFamily: "Inter, system-ui, sans-serif"
|
|
1591
|
+
},
|
|
1592
|
+
borderRadius: "md"
|
|
1593
|
+
},
|
|
1594
|
+
{
|
|
1595
|
+
name: "healthcare-calm",
|
|
1596
|
+
displayName: "Healthcare Calm",
|
|
1597
|
+
description: "Soothing green for wellness apps",
|
|
1598
|
+
category: "healthcare",
|
|
1599
|
+
colors: {
|
|
1600
|
+
primary: generateColorScale2("#059669"),
|
|
1601
|
+
secondary: generateColorScale2("#a7f3d0"),
|
|
1602
|
+
neutral: GRAY_NEUTRAL,
|
|
1603
|
+
success: "#22c55e",
|
|
1604
|
+
warning: "#f59e0b",
|
|
1605
|
+
error: "#ef4444",
|
|
1606
|
+
info: "#3b82f6"
|
|
1607
|
+
},
|
|
1608
|
+
borderRadius: "lg"
|
|
1609
|
+
},
|
|
1610
|
+
{
|
|
1611
|
+
name: "healthcare-clean",
|
|
1612
|
+
displayName: "Healthcare Clean",
|
|
1613
|
+
description: "Clean, minimal healthcare theme",
|
|
1614
|
+
category: "healthcare",
|
|
1615
|
+
colors: {
|
|
1616
|
+
primary: generateColorScale2("#0284c7"),
|
|
1617
|
+
secondary: generateColorScale2("#e0f2fe"),
|
|
1618
|
+
neutral: SLATE_NEUTRAL,
|
|
1619
|
+
success: "#16a34a",
|
|
1620
|
+
warning: "#ca8a04",
|
|
1621
|
+
error: "#dc2626",
|
|
1622
|
+
info: "#0284c7"
|
|
1623
|
+
},
|
|
1624
|
+
borderRadius: "sm",
|
|
1625
|
+
shadows: "sm"
|
|
1626
|
+
},
|
|
1627
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
1628
|
+
// FINANCE
|
|
1629
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
1630
|
+
{
|
|
1631
|
+
name: "finance-corporate",
|
|
1632
|
+
displayName: "Finance Corporate",
|
|
1633
|
+
description: "Professional corporate finance theme",
|
|
1634
|
+
category: "finance",
|
|
1635
|
+
colors: {
|
|
1636
|
+
primary: generateColorScale2("#1e40af"),
|
|
1637
|
+
secondary: generateColorScale2("#047857"),
|
|
1638
|
+
neutral: SLATE_NEUTRAL,
|
|
1639
|
+
success: "#22c55e",
|
|
1640
|
+
warning: "#f59e0b",
|
|
1641
|
+
error: "#dc2626",
|
|
1642
|
+
info: "#3b82f6"
|
|
1643
|
+
},
|
|
1644
|
+
typography: {
|
|
1645
|
+
fontFamily: "Inter, system-ui, sans-serif",
|
|
1646
|
+
headingFontFamily: "Inter, system-ui, sans-serif"
|
|
1647
|
+
},
|
|
1648
|
+
borderRadius: "sm"
|
|
1649
|
+
},
|
|
1650
|
+
{
|
|
1651
|
+
name: "finance-modern",
|
|
1652
|
+
displayName: "Finance Modern",
|
|
1653
|
+
description: "Modern fintech startup theme",
|
|
1654
|
+
category: "finance",
|
|
1655
|
+
colors: {
|
|
1656
|
+
primary: generateColorScale2("#4f46e5"),
|
|
1657
|
+
secondary: generateColorScale2("#10b981"),
|
|
1658
|
+
neutral: ZINC_NEUTRAL,
|
|
1659
|
+
success: "#10b981",
|
|
1660
|
+
warning: "#f59e0b",
|
|
1661
|
+
error: "#ef4444",
|
|
1662
|
+
info: "#6366f1"
|
|
1663
|
+
},
|
|
1664
|
+
borderRadius: "lg"
|
|
1665
|
+
},
|
|
1666
|
+
{
|
|
1667
|
+
name: "finance-luxury",
|
|
1668
|
+
displayName: "Finance Luxury",
|
|
1669
|
+
description: "Premium private banking theme",
|
|
1670
|
+
category: "finance",
|
|
1671
|
+
colors: {
|
|
1672
|
+
primary: generateColorScale2("#1f2937"),
|
|
1673
|
+
secondary: generateColorScale2("#b8860b"),
|
|
1674
|
+
accent: generateColorScale2("#c4a35a"),
|
|
1675
|
+
neutral: ZINC_NEUTRAL,
|
|
1676
|
+
success: "#16a34a",
|
|
1677
|
+
warning: "#d97706",
|
|
1678
|
+
error: "#b91c1c",
|
|
1679
|
+
info: "#1d4ed8"
|
|
1680
|
+
},
|
|
1681
|
+
borderRadius: "none"
|
|
1682
|
+
},
|
|
1683
|
+
{
|
|
1684
|
+
name: "finance-crypto",
|
|
1685
|
+
displayName: "Finance Crypto",
|
|
1686
|
+
description: "Dark theme for crypto trading",
|
|
1687
|
+
category: "finance",
|
|
1688
|
+
colors: {
|
|
1689
|
+
primary: generateColorScale2("#f7931a"),
|
|
1690
|
+
secondary: generateColorScale2("#627eea"),
|
|
1691
|
+
neutral: {
|
|
1692
|
+
50: "#0a0a0a",
|
|
1693
|
+
100: "#171717",
|
|
1694
|
+
200: "#262626",
|
|
1695
|
+
300: "#404040",
|
|
1696
|
+
400: "#525252",
|
|
1697
|
+
500: "#737373",
|
|
1698
|
+
600: "#a3a3a3",
|
|
1699
|
+
700: "#d4d4d4",
|
|
1700
|
+
800: "#e5e5e5",
|
|
1701
|
+
900: "#f5f5f5",
|
|
1702
|
+
950: "#fafafa"
|
|
1703
|
+
},
|
|
1704
|
+
success: "#22c55e",
|
|
1705
|
+
warning: "#f59e0b",
|
|
1706
|
+
error: "#ef4444",
|
|
1707
|
+
info: "#3b82f6"
|
|
1708
|
+
},
|
|
1709
|
+
borderRadius: "md"
|
|
1710
|
+
},
|
|
1711
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
1712
|
+
// EDUCATION
|
|
1713
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
1714
|
+
{
|
|
1715
|
+
name: "education-academic",
|
|
1716
|
+
displayName: "Education Academic",
|
|
1717
|
+
description: "Traditional academic institution theme",
|
|
1718
|
+
category: "education",
|
|
1719
|
+
colors: {
|
|
1720
|
+
primary: generateColorScale2("#1e3a8a"),
|
|
1721
|
+
secondary: generateColorScale2("#991b1b"),
|
|
1722
|
+
neutral: GRAY_NEUTRAL,
|
|
1723
|
+
success: "#22c55e",
|
|
1724
|
+
warning: "#f59e0b",
|
|
1725
|
+
error: "#dc2626",
|
|
1726
|
+
info: "#3b82f6"
|
|
1727
|
+
},
|
|
1728
|
+
typography: {
|
|
1729
|
+
fontFamily: "Georgia, serif",
|
|
1730
|
+
headingFontFamily: "Georgia, serif"
|
|
1731
|
+
},
|
|
1732
|
+
borderRadius: "sm"
|
|
1733
|
+
},
|
|
1734
|
+
{
|
|
1735
|
+
name: "education-modern",
|
|
1736
|
+
displayName: "Education Modern",
|
|
1737
|
+
description: "Modern e-learning platform theme",
|
|
1738
|
+
category: "education",
|
|
1739
|
+
colors: {
|
|
1740
|
+
primary: generateColorScale2("#4f46e5"),
|
|
1741
|
+
secondary: generateColorScale2("#f97316"),
|
|
1742
|
+
neutral: SLATE_NEUTRAL,
|
|
1743
|
+
success: "#22c55e",
|
|
1744
|
+
warning: "#f59e0b",
|
|
1745
|
+
error: "#ef4444",
|
|
1746
|
+
info: "#6366f1"
|
|
1747
|
+
},
|
|
1748
|
+
borderRadius: "lg"
|
|
1749
|
+
},
|
|
1750
|
+
{
|
|
1751
|
+
name: "education-kids",
|
|
1752
|
+
displayName: "Education Kids",
|
|
1753
|
+
description: "Fun, colorful theme for children",
|
|
1754
|
+
category: "education",
|
|
1755
|
+
colors: {
|
|
1756
|
+
primary: generateColorScale2("#8b5cf6"),
|
|
1757
|
+
secondary: generateColorScale2("#ec4899"),
|
|
1758
|
+
accent: generateColorScale2("#fbbf24"),
|
|
1759
|
+
neutral: GRAY_NEUTRAL,
|
|
1760
|
+
success: "#22c55e",
|
|
1761
|
+
warning: "#f59e0b",
|
|
1762
|
+
error: "#ef4444",
|
|
1763
|
+
info: "#3b82f6"
|
|
1764
|
+
},
|
|
1765
|
+
borderRadius: "full"
|
|
1766
|
+
},
|
|
1767
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
1768
|
+
// TECHNOLOGY
|
|
1769
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
1770
|
+
{
|
|
1771
|
+
name: "tech-startup",
|
|
1772
|
+
displayName: "Tech Startup",
|
|
1773
|
+
description: "Modern tech startup theme",
|
|
1774
|
+
category: "technology",
|
|
1775
|
+
colors: {
|
|
1776
|
+
primary: generateColorScale2("#2563eb"),
|
|
1777
|
+
secondary: generateColorScale2("#7c3aed"),
|
|
1778
|
+
neutral: SLATE_NEUTRAL,
|
|
1779
|
+
success: "#22c55e",
|
|
1780
|
+
warning: "#f59e0b",
|
|
1781
|
+
error: "#ef4444",
|
|
1782
|
+
info: "#3b82f6"
|
|
1783
|
+
},
|
|
1784
|
+
borderRadius: "lg"
|
|
1785
|
+
},
|
|
1786
|
+
{
|
|
1787
|
+
name: "tech-saas",
|
|
1788
|
+
displayName: "Tech SaaS",
|
|
1789
|
+
description: "Clean SaaS product theme",
|
|
1790
|
+
category: "technology",
|
|
1791
|
+
colors: {
|
|
1792
|
+
primary: generateColorScale2("#0ea5e9"),
|
|
1793
|
+
secondary: generateColorScale2("#8b5cf6"),
|
|
1794
|
+
neutral: GRAY_NEUTRAL,
|
|
1795
|
+
success: "#22c55e",
|
|
1796
|
+
warning: "#f59e0b",
|
|
1797
|
+
error: "#ef4444",
|
|
1798
|
+
info: "#0ea5e9"
|
|
1799
|
+
},
|
|
1800
|
+
borderRadius: "md"
|
|
1801
|
+
},
|
|
1802
|
+
{
|
|
1803
|
+
name: "tech-dark",
|
|
1804
|
+
displayName: "Tech Dark",
|
|
1805
|
+
description: "Developer-focused dark theme",
|
|
1806
|
+
category: "technology",
|
|
1807
|
+
colors: {
|
|
1808
|
+
primary: generateColorScale2("#22d3ee"),
|
|
1809
|
+
secondary: generateColorScale2("#a78bfa"),
|
|
1810
|
+
neutral: {
|
|
1811
|
+
50: "#030712",
|
|
1812
|
+
100: "#0a0f1a",
|
|
1813
|
+
200: "#1f2937",
|
|
1814
|
+
300: "#374151",
|
|
1815
|
+
400: "#6b7280",
|
|
1816
|
+
500: "#9ca3af",
|
|
1817
|
+
600: "#d1d5db",
|
|
1818
|
+
700: "#e5e7eb",
|
|
1819
|
+
800: "#f3f4f6",
|
|
1820
|
+
900: "#f9fafb",
|
|
1821
|
+
950: "#ffffff"
|
|
1822
|
+
},
|
|
1823
|
+
success: "#4ade80",
|
|
1824
|
+
warning: "#fbbf24",
|
|
1825
|
+
error: "#f87171",
|
|
1826
|
+
info: "#38bdf8"
|
|
1827
|
+
}
|
|
1828
|
+
},
|
|
1829
|
+
{
|
|
1830
|
+
name: "tech-github",
|
|
1831
|
+
displayName: "GitHub Style",
|
|
1832
|
+
description: "GitHub-inspired developer theme",
|
|
1833
|
+
category: "technology",
|
|
1834
|
+
colors: {
|
|
1835
|
+
primary: generateColorScale2("#238636"),
|
|
1836
|
+
secondary: generateColorScale2("#1f6feb"),
|
|
1837
|
+
neutral: ZINC_NEUTRAL,
|
|
1838
|
+
success: "#238636",
|
|
1839
|
+
warning: "#d29922",
|
|
1840
|
+
error: "#da3633",
|
|
1841
|
+
info: "#58a6ff"
|
|
1842
|
+
},
|
|
1843
|
+
borderRadius: "md"
|
|
1844
|
+
},
|
|
1845
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
1846
|
+
// E-COMMERCE
|
|
1847
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
1848
|
+
{
|
|
1849
|
+
name: "ecommerce-modern",
|
|
1850
|
+
displayName: "E-commerce Modern",
|
|
1851
|
+
description: "Clean modern e-commerce theme",
|
|
1852
|
+
category: "ecommerce",
|
|
1853
|
+
colors: {
|
|
1854
|
+
primary: generateColorScale2("#111827"),
|
|
1855
|
+
secondary: generateColorScale2("#6366f1"),
|
|
1856
|
+
neutral: GRAY_NEUTRAL,
|
|
1857
|
+
success: "#22c55e",
|
|
1858
|
+
warning: "#f59e0b",
|
|
1859
|
+
error: "#ef4444",
|
|
1860
|
+
info: "#3b82f6"
|
|
1861
|
+
},
|
|
1862
|
+
borderRadius: "md"
|
|
1863
|
+
},
|
|
1864
|
+
{
|
|
1865
|
+
name: "ecommerce-fashion",
|
|
1866
|
+
displayName: "E-commerce Fashion",
|
|
1867
|
+
description: "Stylish fashion e-commerce theme",
|
|
1868
|
+
category: "ecommerce",
|
|
1869
|
+
colors: {
|
|
1870
|
+
primary: generateColorScale2("#000000"),
|
|
1871
|
+
secondary: generateColorScale2("#c4a35a"),
|
|
1872
|
+
neutral: ZINC_NEUTRAL,
|
|
1873
|
+
success: "#22c55e",
|
|
1874
|
+
warning: "#f59e0b",
|
|
1875
|
+
error: "#ef4444",
|
|
1876
|
+
info: "#3b82f6"
|
|
1877
|
+
},
|
|
1878
|
+
borderRadius: "none"
|
|
1879
|
+
},
|
|
1880
|
+
{
|
|
1881
|
+
name: "ecommerce-organic",
|
|
1882
|
+
displayName: "E-commerce Organic",
|
|
1883
|
+
description: "Natural products theme",
|
|
1884
|
+
category: "ecommerce",
|
|
1885
|
+
colors: {
|
|
1886
|
+
primary: generateColorScale2("#166534"),
|
|
1887
|
+
secondary: generateColorScale2("#92400e"),
|
|
1888
|
+
neutral: WARM_NEUTRAL,
|
|
1889
|
+
success: "#22c55e",
|
|
1890
|
+
warning: "#f59e0b",
|
|
1891
|
+
error: "#dc2626",
|
|
1892
|
+
info: "#0284c7"
|
|
1893
|
+
},
|
|
1894
|
+
borderRadius: "lg"
|
|
1895
|
+
},
|
|
1896
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
1897
|
+
// ENTERTAINMENT
|
|
1898
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
1899
|
+
{
|
|
1900
|
+
name: "entertainment-streaming",
|
|
1901
|
+
displayName: "Streaming Service",
|
|
1902
|
+
description: "Dark streaming platform theme",
|
|
1903
|
+
category: "entertainment",
|
|
1904
|
+
colors: {
|
|
1905
|
+
primary: generateColorScale2("#e50914"),
|
|
1906
|
+
secondary: generateColorScale2("#ffffff"),
|
|
1907
|
+
neutral: {
|
|
1908
|
+
50: "#0a0a0a",
|
|
1909
|
+
100: "#141414",
|
|
1910
|
+
200: "#1f1f1f",
|
|
1911
|
+
300: "#2d2d2d",
|
|
1912
|
+
400: "#525252",
|
|
1913
|
+
500: "#737373",
|
|
1914
|
+
600: "#a3a3a3",
|
|
1915
|
+
700: "#d4d4d4",
|
|
1916
|
+
800: "#e5e5e5",
|
|
1917
|
+
900: "#f5f5f5",
|
|
1918
|
+
950: "#fafafa"
|
|
1919
|
+
},
|
|
1920
|
+
success: "#22c55e",
|
|
1921
|
+
warning: "#f59e0b",
|
|
1922
|
+
error: "#e50914",
|
|
1923
|
+
info: "#3b82f6"
|
|
1924
|
+
}
|
|
1925
|
+
},
|
|
1926
|
+
{
|
|
1927
|
+
name: "entertainment-gaming",
|
|
1928
|
+
displayName: "Gaming",
|
|
1929
|
+
description: "Vibrant gaming theme",
|
|
1930
|
+
category: "entertainment",
|
|
1931
|
+
colors: {
|
|
1932
|
+
primary: generateColorScale2("#9333ea"),
|
|
1933
|
+
secondary: generateColorScale2("#22d3ee"),
|
|
1934
|
+
accent: generateColorScale2("#f43f5e"),
|
|
1935
|
+
neutral: {
|
|
1936
|
+
50: "#09090b",
|
|
1937
|
+
100: "#18181b",
|
|
1938
|
+
200: "#27272a",
|
|
1939
|
+
300: "#3f3f46",
|
|
1940
|
+
400: "#52525b",
|
|
1941
|
+
500: "#71717a",
|
|
1942
|
+
600: "#a1a1aa",
|
|
1943
|
+
700: "#d4d4d8",
|
|
1944
|
+
800: "#e4e4e7",
|
|
1945
|
+
900: "#f4f4f5",
|
|
1946
|
+
950: "#fafafa"
|
|
1947
|
+
},
|
|
1948
|
+
success: "#4ade80",
|
|
1949
|
+
warning: "#fbbf24",
|
|
1950
|
+
error: "#f43f5e",
|
|
1951
|
+
info: "#22d3ee"
|
|
1952
|
+
},
|
|
1953
|
+
borderRadius: "md"
|
|
1954
|
+
},
|
|
1955
|
+
{
|
|
1956
|
+
name: "entertainment-music",
|
|
1957
|
+
displayName: "Music",
|
|
1958
|
+
description: "Music streaming theme",
|
|
1959
|
+
category: "entertainment",
|
|
1960
|
+
colors: {
|
|
1961
|
+
primary: generateColorScale2("#1db954"),
|
|
1962
|
+
secondary: generateColorScale2("#ffffff"),
|
|
1963
|
+
neutral: {
|
|
1964
|
+
50: "#121212",
|
|
1965
|
+
100: "#181818",
|
|
1966
|
+
200: "#282828",
|
|
1967
|
+
300: "#3d3d3d",
|
|
1968
|
+
400: "#535353",
|
|
1969
|
+
500: "#7a7a7a",
|
|
1970
|
+
600: "#b3b3b3",
|
|
1971
|
+
700: "#d9d9d9",
|
|
1972
|
+
800: "#ebebeb",
|
|
1973
|
+
900: "#f5f5f5",
|
|
1974
|
+
950: "#ffffff"
|
|
1975
|
+
},
|
|
1976
|
+
success: "#1db954",
|
|
1977
|
+
warning: "#f59e0b",
|
|
1978
|
+
error: "#e91429",
|
|
1979
|
+
info: "#1e90ff"
|
|
1980
|
+
}
|
|
1981
|
+
},
|
|
1982
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
1983
|
+
// GOVERNMENT
|
|
1984
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
1985
|
+
{
|
|
1986
|
+
name: "government-official",
|
|
1987
|
+
displayName: "Government Official",
|
|
1988
|
+
description: "Official government portal theme",
|
|
1989
|
+
category: "government",
|
|
1990
|
+
colors: {
|
|
1991
|
+
primary: generateColorScale2("#1e3a8a"),
|
|
1992
|
+
secondary: generateColorScale2("#991b1b"),
|
|
1993
|
+
neutral: SLATE_NEUTRAL,
|
|
1994
|
+
success: "#16a34a",
|
|
1995
|
+
warning: "#ca8a04",
|
|
1996
|
+
error: "#b91c1c",
|
|
1997
|
+
info: "#1e40af"
|
|
1998
|
+
},
|
|
1999
|
+
borderRadius: "sm",
|
|
2000
|
+
shadows: "sm"
|
|
2001
|
+
},
|
|
2002
|
+
{
|
|
2003
|
+
name: "government-accessible",
|
|
2004
|
+
displayName: "Government Accessible",
|
|
2005
|
+
description: "High contrast accessible theme",
|
|
2006
|
+
category: "government",
|
|
2007
|
+
colors: {
|
|
2008
|
+
primary: generateColorScale2("#0f172a"),
|
|
2009
|
+
secondary: generateColorScale2("#1e40af"),
|
|
2010
|
+
neutral: SLATE_NEUTRAL,
|
|
2011
|
+
success: "#15803d",
|
|
2012
|
+
warning: "#a16207",
|
|
2013
|
+
error: "#b91c1c",
|
|
2014
|
+
info: "#1d4ed8"
|
|
2015
|
+
},
|
|
2016
|
+
borderRadius: "none"
|
|
2017
|
+
},
|
|
2018
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
2019
|
+
// NATURE / ORGANIC
|
|
2020
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
2021
|
+
{
|
|
2022
|
+
name: "nature-earth",
|
|
2023
|
+
displayName: "Earth Tones",
|
|
2024
|
+
description: "Warm earthy natural tones",
|
|
2025
|
+
category: "nature",
|
|
2026
|
+
colors: {
|
|
2027
|
+
primary: generateColorScale2("#78350f"),
|
|
2028
|
+
secondary: generateColorScale2("#166534"),
|
|
2029
|
+
neutral: WARM_NEUTRAL,
|
|
2030
|
+
success: "#22c55e",
|
|
2031
|
+
warning: "#f59e0b",
|
|
2032
|
+
error: "#dc2626",
|
|
2033
|
+
info: "#0284c7"
|
|
2034
|
+
},
|
|
2035
|
+
borderRadius: "lg"
|
|
2036
|
+
},
|
|
2037
|
+
{
|
|
2038
|
+
name: "nature-ocean",
|
|
2039
|
+
displayName: "Ocean",
|
|
2040
|
+
description: "Ocean-inspired blues and teals",
|
|
2041
|
+
category: "nature",
|
|
2042
|
+
colors: {
|
|
2043
|
+
primary: generateColorScale2("#0369a1"),
|
|
2044
|
+
secondary: generateColorScale2("#0d9488"),
|
|
2045
|
+
neutral: SLATE_NEUTRAL,
|
|
2046
|
+
success: "#22c55e",
|
|
2047
|
+
warning: "#f59e0b",
|
|
2048
|
+
error: "#ef4444",
|
|
2049
|
+
info: "#0ea5e9"
|
|
2050
|
+
},
|
|
2051
|
+
borderRadius: "md"
|
|
2052
|
+
},
|
|
2053
|
+
{
|
|
2054
|
+
name: "nature-forest",
|
|
2055
|
+
displayName: "Forest",
|
|
2056
|
+
description: "Deep forest greens",
|
|
2057
|
+
category: "nature",
|
|
2058
|
+
colors: {
|
|
2059
|
+
primary: generateColorScale2("#14532d"),
|
|
2060
|
+
secondary: generateColorScale2("#365314"),
|
|
2061
|
+
neutral: GRAY_NEUTRAL,
|
|
2062
|
+
success: "#22c55e",
|
|
2063
|
+
warning: "#f59e0b",
|
|
2064
|
+
error: "#dc2626",
|
|
2065
|
+
info: "#3b82f6"
|
|
2066
|
+
},
|
|
2067
|
+
borderRadius: "md"
|
|
2068
|
+
},
|
|
2069
|
+
{
|
|
2070
|
+
name: "nature-sunset",
|
|
2071
|
+
displayName: "Sunset",
|
|
2072
|
+
description: "Warm sunset gradient colors",
|
|
2073
|
+
category: "nature",
|
|
2074
|
+
colors: {
|
|
2075
|
+
primary: generateColorScale2("#ea580c"),
|
|
2076
|
+
secondary: generateColorScale2("#be185d"),
|
|
2077
|
+
neutral: WARM_NEUTRAL,
|
|
2078
|
+
success: "#22c55e",
|
|
2079
|
+
warning: "#f59e0b",
|
|
2080
|
+
error: "#dc2626",
|
|
2081
|
+
info: "#0ea5e9"
|
|
2082
|
+
},
|
|
2083
|
+
borderRadius: "lg"
|
|
2084
|
+
},
|
|
2085
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
2086
|
+
// MINIMAL
|
|
2087
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
2088
|
+
{
|
|
2089
|
+
name: "minimal-mono",
|
|
2090
|
+
displayName: "Monochrome",
|
|
2091
|
+
description: "Pure black and white minimal",
|
|
2092
|
+
category: "minimal",
|
|
2093
|
+
colors: {
|
|
2094
|
+
primary: generateColorScale2("#000000"),
|
|
2095
|
+
neutral: ZINC_NEUTRAL,
|
|
2096
|
+
success: "#22c55e",
|
|
2097
|
+
warning: "#f59e0b",
|
|
2098
|
+
error: "#ef4444",
|
|
2099
|
+
info: "#3b82f6"
|
|
2100
|
+
},
|
|
2101
|
+
borderRadius: "none",
|
|
2102
|
+
shadows: "none"
|
|
2103
|
+
},
|
|
2104
|
+
{
|
|
2105
|
+
name: "minimal-soft",
|
|
2106
|
+
displayName: "Minimal Soft",
|
|
2107
|
+
description: "Soft grays with subtle accents",
|
|
2108
|
+
category: "minimal",
|
|
2109
|
+
colors: {
|
|
2110
|
+
primary: generateColorScale2("#4b5563"),
|
|
2111
|
+
secondary: generateColorScale2("#6366f1"),
|
|
2112
|
+
neutral: GRAY_NEUTRAL,
|
|
2113
|
+
success: "#22c55e",
|
|
2114
|
+
warning: "#f59e0b",
|
|
2115
|
+
error: "#ef4444",
|
|
2116
|
+
info: "#3b82f6"
|
|
2117
|
+
},
|
|
2118
|
+
borderRadius: "sm",
|
|
2119
|
+
shadows: "sm"
|
|
2120
|
+
},
|
|
2121
|
+
{
|
|
2122
|
+
name: "minimal-paper",
|
|
2123
|
+
displayName: "Paper",
|
|
2124
|
+
description: "Clean paper-like minimal theme",
|
|
2125
|
+
category: "minimal",
|
|
2126
|
+
colors: {
|
|
2127
|
+
primary: generateColorScale2("#525252"),
|
|
2128
|
+
neutral: {
|
|
2129
|
+
50: "#fefefe",
|
|
2130
|
+
100: "#fafafa",
|
|
2131
|
+
200: "#f5f5f5",
|
|
2132
|
+
300: "#e5e5e5",
|
|
2133
|
+
400: "#d4d4d4",
|
|
2134
|
+
500: "#a3a3a3",
|
|
2135
|
+
600: "#737373",
|
|
2136
|
+
700: "#525252",
|
|
2137
|
+
800: "#404040",
|
|
2138
|
+
900: "#262626",
|
|
2139
|
+
950: "#171717"
|
|
2140
|
+
},
|
|
2141
|
+
success: "#16a34a",
|
|
2142
|
+
warning: "#ca8a04",
|
|
2143
|
+
error: "#dc2626",
|
|
2144
|
+
info: "#2563eb"
|
|
2145
|
+
},
|
|
2146
|
+
borderRadius: "sm",
|
|
2147
|
+
shadows: "sm"
|
|
2148
|
+
},
|
|
2149
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
2150
|
+
// BOLD
|
|
2151
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
2152
|
+
{
|
|
2153
|
+
name: "bold-neon",
|
|
2154
|
+
displayName: "Neon",
|
|
2155
|
+
description: "Vibrant neon colors on dark",
|
|
2156
|
+
category: "bold",
|
|
2157
|
+
colors: {
|
|
2158
|
+
primary: generateColorScale2("#f0abfc"),
|
|
2159
|
+
secondary: generateColorScale2("#22d3ee"),
|
|
2160
|
+
accent: generateColorScale2("#a3e635"),
|
|
2161
|
+
neutral: {
|
|
2162
|
+
50: "#0a0a0a",
|
|
2163
|
+
100: "#171717",
|
|
2164
|
+
200: "#262626",
|
|
2165
|
+
300: "#404040",
|
|
2166
|
+
400: "#525252",
|
|
2167
|
+
500: "#737373",
|
|
2168
|
+
600: "#a3a3a3",
|
|
2169
|
+
700: "#d4d4d4",
|
|
2170
|
+
800: "#e5e5e5",
|
|
2171
|
+
900: "#f5f5f5",
|
|
2172
|
+
950: "#fafafa"
|
|
2173
|
+
},
|
|
2174
|
+
success: "#a3e635",
|
|
2175
|
+
warning: "#fbbf24",
|
|
2176
|
+
error: "#f87171",
|
|
2177
|
+
info: "#38bdf8"
|
|
2178
|
+
},
|
|
2179
|
+
borderRadius: "full"
|
|
2180
|
+
},
|
|
2181
|
+
{
|
|
2182
|
+
name: "bold-gradient",
|
|
2183
|
+
displayName: "Gradient Bold",
|
|
2184
|
+
description: "Bold gradient-ready colors",
|
|
2185
|
+
category: "bold",
|
|
2186
|
+
colors: {
|
|
2187
|
+
primary: generateColorScale2("#ec4899"),
|
|
2188
|
+
secondary: generateColorScale2("#8b5cf6"),
|
|
2189
|
+
accent: generateColorScale2("#06b6d4"),
|
|
2190
|
+
neutral: ZINC_NEUTRAL,
|
|
2191
|
+
success: "#22c55e",
|
|
2192
|
+
warning: "#f59e0b",
|
|
2193
|
+
error: "#ef4444",
|
|
2194
|
+
info: "#3b82f6"
|
|
2195
|
+
},
|
|
2196
|
+
borderRadius: "lg"
|
|
2197
|
+
},
|
|
2198
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
2199
|
+
// PLAYFUL
|
|
2200
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
2201
|
+
{
|
|
2202
|
+
name: "playful-candy",
|
|
2203
|
+
displayName: "Candy",
|
|
2204
|
+
description: "Sweet candy-inspired colors",
|
|
2205
|
+
category: "playful",
|
|
2206
|
+
colors: {
|
|
2207
|
+
primary: generateColorScale2("#ec4899"),
|
|
2208
|
+
secondary: generateColorScale2("#a855f7"),
|
|
2209
|
+
accent: generateColorScale2("#22d3ee"),
|
|
2210
|
+
neutral: GRAY_NEUTRAL,
|
|
2211
|
+
success: "#22c55e",
|
|
2212
|
+
warning: "#fbbf24",
|
|
2213
|
+
error: "#f43f5e",
|
|
2214
|
+
info: "#3b82f6"
|
|
2215
|
+
},
|
|
2216
|
+
borderRadius: "full"
|
|
2217
|
+
},
|
|
2218
|
+
{
|
|
2219
|
+
name: "playful-retro",
|
|
2220
|
+
displayName: "Retro",
|
|
2221
|
+
description: "Retro 80s inspired colors",
|
|
2222
|
+
category: "playful",
|
|
2223
|
+
colors: {
|
|
2224
|
+
primary: generateColorScale2("#f472b6"),
|
|
2225
|
+
secondary: generateColorScale2("#38bdf8"),
|
|
2226
|
+
accent: generateColorScale2("#facc15"),
|
|
2227
|
+
neutral: ZINC_NEUTRAL,
|
|
2228
|
+
success: "#4ade80",
|
|
2229
|
+
warning: "#fbbf24",
|
|
2230
|
+
error: "#f87171",
|
|
2231
|
+
info: "#38bdf8"
|
|
2232
|
+
},
|
|
2233
|
+
borderRadius: "lg"
|
|
2234
|
+
},
|
|
2235
|
+
{
|
|
2236
|
+
name: "playful-pastel",
|
|
2237
|
+
displayName: "Pastel",
|
|
2238
|
+
description: "Soft pastel colors",
|
|
2239
|
+
category: "playful",
|
|
2240
|
+
colors: {
|
|
2241
|
+
primary: generateColorScale2("#93c5fd"),
|
|
2242
|
+
secondary: generateColorScale2("#fda4af"),
|
|
2243
|
+
accent: generateColorScale2("#fde047"),
|
|
2244
|
+
neutral: GRAY_NEUTRAL,
|
|
2245
|
+
success: "#86efac",
|
|
2246
|
+
warning: "#fde047",
|
|
2247
|
+
error: "#fda4af",
|
|
2248
|
+
info: "#93c5fd"
|
|
2249
|
+
},
|
|
2250
|
+
borderRadius: "full"
|
|
2251
|
+
},
|
|
2252
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
2253
|
+
// PROFESSIONAL
|
|
2254
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
2255
|
+
{
|
|
2256
|
+
name: "professional-corporate",
|
|
2257
|
+
displayName: "Corporate",
|
|
2258
|
+
description: "Traditional corporate blue",
|
|
2259
|
+
category: "professional",
|
|
2260
|
+
colors: {
|
|
2261
|
+
primary: generateColorScale2("#1e40af"),
|
|
2262
|
+
secondary: generateColorScale2("#0f766e"),
|
|
2263
|
+
neutral: SLATE_NEUTRAL,
|
|
2264
|
+
success: "#22c55e",
|
|
2265
|
+
warning: "#f59e0b",
|
|
2266
|
+
error: "#dc2626",
|
|
2267
|
+
info: "#3b82f6"
|
|
2268
|
+
},
|
|
2269
|
+
borderRadius: "sm"
|
|
2270
|
+
},
|
|
2271
|
+
{
|
|
2272
|
+
name: "professional-law",
|
|
2273
|
+
displayName: "Legal",
|
|
2274
|
+
description: "Serious legal/consulting theme",
|
|
2275
|
+
category: "professional",
|
|
2276
|
+
colors: {
|
|
2277
|
+
primary: generateColorScale2("#1f2937"),
|
|
2278
|
+
secondary: generateColorScale2("#7c2d12"),
|
|
2279
|
+
neutral: GRAY_NEUTRAL,
|
|
2280
|
+
success: "#16a34a",
|
|
2281
|
+
warning: "#ca8a04",
|
|
2282
|
+
error: "#b91c1c",
|
|
2283
|
+
info: "#1d4ed8"
|
|
2284
|
+
},
|
|
2285
|
+
typography: {
|
|
2286
|
+
fontFamily: "Georgia, serif",
|
|
2287
|
+
headingFontFamily: "Georgia, serif"
|
|
2288
|
+
},
|
|
2289
|
+
borderRadius: "none"
|
|
2290
|
+
},
|
|
2291
|
+
{
|
|
2292
|
+
name: "professional-consulting",
|
|
2293
|
+
displayName: "Consulting",
|
|
2294
|
+
description: "Clean consulting firm theme",
|
|
2295
|
+
category: "professional",
|
|
2296
|
+
colors: {
|
|
2297
|
+
primary: generateColorScale2("#0f172a"),
|
|
2298
|
+
secondary: generateColorScale2("#0369a1"),
|
|
2299
|
+
neutral: SLATE_NEUTRAL,
|
|
2300
|
+
success: "#22c55e",
|
|
2301
|
+
warning: "#f59e0b",
|
|
2302
|
+
error: "#dc2626",
|
|
2303
|
+
info: "#0284c7"
|
|
2304
|
+
},
|
|
2305
|
+
borderRadius: "sm"
|
|
2306
|
+
}
|
|
2307
|
+
];
|
|
2308
|
+
function getPresetsByCategory(category) {
|
|
2309
|
+
return PRESETS.filter((p) => p.category === category);
|
|
2310
|
+
}
|
|
2311
|
+
function getPresetByName(name) {
|
|
2312
|
+
return PRESETS.find((p) => p.name === name);
|
|
2313
|
+
}
|
|
2314
|
+
function getAllCategories() {
|
|
2315
|
+
return Array.from(new Set(PRESETS.map((p) => p.category)));
|
|
2316
|
+
}
|
|
2317
|
+
function presetToCssVariables(preset, prefix = "nice") {
|
|
2318
|
+
const lines = [];
|
|
2319
|
+
for (const [shade, value] of Object.entries(preset.colors.primary)) {
|
|
2320
|
+
lines.push(` --${prefix}-color-primary-${shade}: ${value};`);
|
|
2321
|
+
}
|
|
2322
|
+
if (preset.colors.secondary) {
|
|
2323
|
+
for (const [shade, value] of Object.entries(preset.colors.secondary)) {
|
|
2324
|
+
lines.push(` --${prefix}-color-secondary-${shade}: ${value};`);
|
|
2325
|
+
}
|
|
2326
|
+
}
|
|
2327
|
+
if (preset.colors.accent) {
|
|
2328
|
+
for (const [shade, value] of Object.entries(preset.colors.accent)) {
|
|
2329
|
+
lines.push(` --${prefix}-color-accent-${shade}: ${value};`);
|
|
2330
|
+
}
|
|
2331
|
+
}
|
|
2332
|
+
for (const [shade, value] of Object.entries(preset.colors.neutral)) {
|
|
2333
|
+
lines.push(` --${prefix}-color-neutral-${shade}: ${value};`);
|
|
2334
|
+
}
|
|
2335
|
+
lines.push(` --${prefix}-color-success: ${preset.colors.success};`);
|
|
2336
|
+
lines.push(` --${prefix}-color-warning: ${preset.colors.warning};`);
|
|
2337
|
+
lines.push(` --${prefix}-color-error: ${preset.colors.error};`);
|
|
2338
|
+
lines.push(` --${prefix}-color-info: ${preset.colors.info};`);
|
|
2339
|
+
return `:root {
|
|
2340
|
+
${lines.join("\n")}
|
|
2341
|
+
}`;
|
|
2342
|
+
}
|
|
2343
|
+
function presetToTokens(preset) {
|
|
2344
|
+
const colorToToken = (value) => ({ $value: value, $type: "color" });
|
|
2345
|
+
const scaleToTokens = (scale) => {
|
|
2346
|
+
const tokens = {};
|
|
2347
|
+
for (const [shade, value] of Object.entries(scale)) {
|
|
2348
|
+
tokens[shade] = colorToToken(value);
|
|
2349
|
+
}
|
|
2350
|
+
return tokens;
|
|
2351
|
+
};
|
|
2352
|
+
return {
|
|
2353
|
+
$name: preset.displayName,
|
|
2354
|
+
$description: preset.description,
|
|
2355
|
+
color: {
|
|
2356
|
+
primary: scaleToTokens(preset.colors.primary),
|
|
2357
|
+
secondary: preset.colors.secondary ? scaleToTokens(preset.colors.secondary) : void 0,
|
|
2358
|
+
accent: preset.colors.accent ? scaleToTokens(preset.colors.accent) : void 0,
|
|
2359
|
+
neutral: scaleToTokens(preset.colors.neutral),
|
|
2360
|
+
semantic: {
|
|
2361
|
+
success: colorToToken(preset.colors.success),
|
|
2362
|
+
warning: colorToToken(preset.colors.warning),
|
|
2363
|
+
error: colorToToken(preset.colors.error),
|
|
2364
|
+
info: colorToToken(preset.colors.info)
|
|
2365
|
+
}
|
|
2366
|
+
}
|
|
2367
|
+
};
|
|
2368
|
+
}
|
|
2369
|
+
|
|
2370
|
+
// src/brand-kit.ts
|
|
2371
|
+
function analyzeColor(hex) {
|
|
2372
|
+
const rgb = hexToRgb2(hex);
|
|
2373
|
+
const hsl = rgbToHsl(rgb);
|
|
2374
|
+
const luminance = calculateLuminance(rgb);
|
|
2375
|
+
return {
|
|
2376
|
+
hsl,
|
|
2377
|
+
rgb,
|
|
2378
|
+
luminance,
|
|
2379
|
+
isLight: luminance > 0.5,
|
|
2380
|
+
complementary: hslToHex2((hsl[0] + 180) % 360, hsl[1], hsl[2]),
|
|
2381
|
+
analogous: [
|
|
2382
|
+
hslToHex2((hsl[0] + 30) % 360, hsl[1], hsl[2]),
|
|
2383
|
+
hslToHex2((hsl[0] - 30 + 360) % 360, hsl[1], hsl[2])
|
|
2384
|
+
],
|
|
2385
|
+
triadic: [
|
|
2386
|
+
hslToHex2((hsl[0] + 120) % 360, hsl[1], hsl[2]),
|
|
2387
|
+
hslToHex2((hsl[0] + 240) % 360, hsl[1], hsl[2])
|
|
2388
|
+
],
|
|
2389
|
+
splitComplementary: [
|
|
2390
|
+
hslToHex2((hsl[0] + 150) % 360, hsl[1], hsl[2]),
|
|
2391
|
+
hslToHex2((hsl[0] + 210) % 360, hsl[1], hsl[2])
|
|
2392
|
+
]
|
|
2393
|
+
};
|
|
2394
|
+
}
|
|
2395
|
+
function hexToRgb2(hex) {
|
|
2396
|
+
const r = parseInt(hex.slice(1, 3), 16);
|
|
2397
|
+
const g = parseInt(hex.slice(3, 5), 16);
|
|
2398
|
+
const b = parseInt(hex.slice(5, 7), 16);
|
|
2399
|
+
return [r, g, b];
|
|
2400
|
+
}
|
|
2401
|
+
function rgbToHsl([r, g, b]) {
|
|
2402
|
+
r /= 255;
|
|
2403
|
+
g /= 255;
|
|
2404
|
+
b /= 255;
|
|
2405
|
+
const max = Math.max(r, g, b);
|
|
2406
|
+
const min = Math.min(r, g, b);
|
|
2407
|
+
let h = 0;
|
|
2408
|
+
let s = 0;
|
|
2409
|
+
const l = (max + min) / 2;
|
|
2410
|
+
if (max !== min) {
|
|
2411
|
+
const d = max - min;
|
|
2412
|
+
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
|
|
2413
|
+
switch (max) {
|
|
2414
|
+
case r:
|
|
2415
|
+
h = ((g - b) / d + (g < b ? 6 : 0)) / 6;
|
|
2416
|
+
break;
|
|
2417
|
+
case g:
|
|
2418
|
+
h = ((b - r) / d + 2) / 6;
|
|
2419
|
+
break;
|
|
2420
|
+
case b:
|
|
2421
|
+
h = ((r - g) / d + 4) / 6;
|
|
2422
|
+
break;
|
|
2423
|
+
}
|
|
2424
|
+
}
|
|
2425
|
+
return [h * 360, s * 100, l * 100];
|
|
2426
|
+
}
|
|
2427
|
+
function hslToHex2(h, s, l) {
|
|
2428
|
+
s /= 100;
|
|
2429
|
+
l /= 100;
|
|
2430
|
+
h /= 360;
|
|
2431
|
+
const hue2rgb = (p, q, t) => {
|
|
2432
|
+
if (t < 0) {
|
|
2433
|
+
t += 1;
|
|
2434
|
+
}
|
|
2435
|
+
if (t > 1) {
|
|
2436
|
+
t -= 1;
|
|
2437
|
+
}
|
|
2438
|
+
if (t < 1 / 6) {
|
|
2439
|
+
return p + (q - p) * 6 * t;
|
|
2440
|
+
}
|
|
2441
|
+
if (t < 1 / 2) {
|
|
2442
|
+
return q;
|
|
2443
|
+
}
|
|
2444
|
+
if (t < 2 / 3) {
|
|
2445
|
+
return p + (q - p) * (2 / 3 - t) * 6;
|
|
2446
|
+
}
|
|
2447
|
+
return p;
|
|
2448
|
+
};
|
|
2449
|
+
let r, g, b;
|
|
2450
|
+
if (s === 0) {
|
|
2451
|
+
r = g = b = l;
|
|
2452
|
+
} else {
|
|
2453
|
+
const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
|
|
2454
|
+
const p = 2 * l - q;
|
|
2455
|
+
r = hue2rgb(p, q, h + 1 / 3);
|
|
2456
|
+
g = hue2rgb(p, q, h);
|
|
2457
|
+
b = hue2rgb(p, q, h - 1 / 3);
|
|
2458
|
+
}
|
|
2459
|
+
const toHex = (n) => Math.round(n * 255).toString(16).padStart(2, "0");
|
|
2460
|
+
return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
|
|
2461
|
+
}
|
|
2462
|
+
function calculateLuminance([r, g, b]) {
|
|
2463
|
+
const [rs, gs, bs] = [r, g, b].map((c) => {
|
|
2464
|
+
c /= 255;
|
|
2465
|
+
return c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
|
|
2466
|
+
});
|
|
2467
|
+
return 0.2126 * rs + 0.7152 * gs + 0.0722 * bs;
|
|
2468
|
+
}
|
|
2469
|
+
var INDUSTRY_DEFAULTS = {
|
|
2470
|
+
technology: {
|
|
2471
|
+
typography: "modern-sans",
|
|
2472
|
+
borderRadius: "lg",
|
|
2473
|
+
shadows: "md",
|
|
2474
|
+
style: "modern"
|
|
2475
|
+
},
|
|
2476
|
+
healthcare: {
|
|
2477
|
+
typography: "modern-sans",
|
|
2478
|
+
borderRadius: "md",
|
|
2479
|
+
shadows: "sm",
|
|
2480
|
+
style: "professional"
|
|
2481
|
+
},
|
|
2482
|
+
finance: {
|
|
2483
|
+
typography: "classic-serif",
|
|
2484
|
+
borderRadius: "sm",
|
|
2485
|
+
shadows: "sm",
|
|
2486
|
+
style: "professional"
|
|
2487
|
+
},
|
|
2488
|
+
education: {
|
|
2489
|
+
typography: "modern-sans",
|
|
2490
|
+
borderRadius: "md",
|
|
2491
|
+
shadows: "md",
|
|
2492
|
+
style: "modern"
|
|
2493
|
+
},
|
|
2494
|
+
retail: {
|
|
2495
|
+
typography: "modern-sans",
|
|
2496
|
+
borderRadius: "md",
|
|
2497
|
+
shadows: "md",
|
|
2498
|
+
style: "modern"
|
|
2499
|
+
},
|
|
2500
|
+
hospitality: {
|
|
2501
|
+
typography: "classic-serif",
|
|
2502
|
+
borderRadius: "lg",
|
|
2503
|
+
shadows: "md",
|
|
2504
|
+
style: "luxury"
|
|
2505
|
+
},
|
|
2506
|
+
manufacturing: {
|
|
2507
|
+
typography: "modern-sans",
|
|
2508
|
+
borderRadius: "sm",
|
|
2509
|
+
shadows: "sm",
|
|
2510
|
+
style: "professional"
|
|
2511
|
+
},
|
|
2512
|
+
creative: {
|
|
2513
|
+
typography: "geometric",
|
|
2514
|
+
borderRadius: "lg",
|
|
2515
|
+
shadows: "lg",
|
|
2516
|
+
style: "bold"
|
|
2517
|
+
},
|
|
2518
|
+
nonprofit: {
|
|
2519
|
+
typography: "modern-sans",
|
|
2520
|
+
borderRadius: "md",
|
|
2521
|
+
shadows: "sm",
|
|
2522
|
+
style: "organic"
|
|
2523
|
+
},
|
|
2524
|
+
government: {
|
|
2525
|
+
typography: "modern-sans",
|
|
2526
|
+
borderRadius: "none",
|
|
2527
|
+
shadows: "sm",
|
|
2528
|
+
style: "professional"
|
|
2529
|
+
}
|
|
2530
|
+
};
|
|
2531
|
+
var TYPOGRAPHY_STACKS = {
|
|
2532
|
+
"modern-sans": {
|
|
2533
|
+
body: "Inter, system-ui, -apple-system, sans-serif",
|
|
2534
|
+
heading: "Inter, system-ui, -apple-system, sans-serif"
|
|
2535
|
+
},
|
|
2536
|
+
"classic-serif": {
|
|
2537
|
+
body: 'Georgia, Cambria, "Times New Roman", serif',
|
|
2538
|
+
heading: 'Georgia, Cambria, "Times New Roman", serif'
|
|
2539
|
+
},
|
|
2540
|
+
geometric: {
|
|
2541
|
+
body: 'Poppins, "Segoe UI", Roboto, sans-serif',
|
|
2542
|
+
heading: 'Poppins, "Segoe UI", Roboto, sans-serif'
|
|
2543
|
+
},
|
|
2544
|
+
rounded: {
|
|
2545
|
+
body: 'Nunito, "Segoe UI", Roboto, sans-serif',
|
|
2546
|
+
heading: 'Nunito, "Segoe UI", Roboto, sans-serif'
|
|
2547
|
+
},
|
|
2548
|
+
monospace: {
|
|
2549
|
+
body: '"JetBrains Mono", "Fira Code", Consolas, monospace',
|
|
2550
|
+
heading: '"JetBrains Mono", "Fira Code", Consolas, monospace'
|
|
2551
|
+
}
|
|
2552
|
+
};
|
|
2553
|
+
function generateNeutralPalette(primaryColor) {
|
|
2554
|
+
const analysis = analyzeColor(primaryColor);
|
|
2555
|
+
const [h] = analysis.hsl;
|
|
2556
|
+
return {
|
|
2557
|
+
50: hslToHex2(h, 5, 98),
|
|
2558
|
+
100: hslToHex2(h, 5, 96),
|
|
2559
|
+
200: hslToHex2(h, 5, 90),
|
|
2560
|
+
300: hslToHex2(h, 5, 83),
|
|
2561
|
+
400: hslToHex2(h, 5, 64),
|
|
2562
|
+
500: hslToHex2(h, 5, 45),
|
|
2563
|
+
600: hslToHex2(h, 5, 32),
|
|
2564
|
+
700: hslToHex2(h, 5, 25),
|
|
2565
|
+
800: hslToHex2(h, 5, 15),
|
|
2566
|
+
900: hslToHex2(h, 5, 9),
|
|
2567
|
+
950: hslToHex2(h, 5, 4)
|
|
2568
|
+
};
|
|
2569
|
+
}
|
|
2570
|
+
function generateBrandKit(config) {
|
|
2571
|
+
const defaults = config.industry ? INDUSTRY_DEFAULTS[config.industry] : {};
|
|
2572
|
+
const mergedConfig = { ...defaults, ...config };
|
|
2573
|
+
const primaryAnalysis = analyzeColor(config.primaryColor);
|
|
2574
|
+
const secondaryColor = config.secondaryColor || primaryAnalysis.complementary;
|
|
2575
|
+
const accentColor = config.accentColor || primaryAnalysis.analogous[0];
|
|
2576
|
+
const primaryScale = generateColorScale2(config.primaryColor);
|
|
2577
|
+
const secondaryScale = generateColorScale2(secondaryColor);
|
|
2578
|
+
const accentScale = generateColorScale2(accentColor);
|
|
2579
|
+
const neutralScale = generateNeutralPalette(config.primaryColor);
|
|
2580
|
+
const semanticColors = generateSemanticColors(mergedConfig.style || "modern");
|
|
2581
|
+
const preset = {
|
|
2582
|
+
name: `brand-${config.brandName.toLowerCase().replace(/\s+/g, "-")}`,
|
|
2583
|
+
displayName: config.brandName,
|
|
2584
|
+
description: `Custom brand theme for ${config.brandName}`,
|
|
2585
|
+
category: "brand",
|
|
2586
|
+
colors: {
|
|
2587
|
+
primary: primaryScale,
|
|
2588
|
+
secondary: secondaryScale,
|
|
2589
|
+
accent: accentScale,
|
|
2590
|
+
neutral: neutralScale,
|
|
2591
|
+
...semanticColors
|
|
2592
|
+
},
|
|
2593
|
+
typography: {
|
|
2594
|
+
fontFamily: TYPOGRAPHY_STACKS[mergedConfig.typography || "modern-sans"].body,
|
|
2595
|
+
headingFontFamily: TYPOGRAPHY_STACKS[mergedConfig.typography || "modern-sans"].heading
|
|
2596
|
+
},
|
|
2597
|
+
borderRadius: mergedConfig.borderRadius,
|
|
2598
|
+
shadows: mergedConfig.shadows
|
|
2599
|
+
};
|
|
2600
|
+
const darkMode = generateDarkModePreset(preset);
|
|
2601
|
+
const css = generateCssFromPreset(preset);
|
|
2602
|
+
const tokens = generateTokensFromPreset(preset);
|
|
2603
|
+
const assets = generateBrandAssets(preset, mergedConfig);
|
|
2604
|
+
return {
|
|
2605
|
+
preset,
|
|
2606
|
+
css,
|
|
2607
|
+
tokens,
|
|
2608
|
+
darkMode,
|
|
2609
|
+
assets
|
|
2610
|
+
};
|
|
2611
|
+
}
|
|
2612
|
+
function generateSemanticColors(style) {
|
|
2613
|
+
const semantics = {
|
|
2614
|
+
professional: { success: "#16a34a", warning: "#ca8a04", error: "#dc2626", info: "#2563eb" },
|
|
2615
|
+
modern: { success: "#22c55e", warning: "#f59e0b", error: "#ef4444", info: "#3b82f6" },
|
|
2616
|
+
playful: { success: "#4ade80", warning: "#fbbf24", error: "#f87171", info: "#60a5fa" },
|
|
2617
|
+
minimal: { success: "#22c55e", warning: "#f59e0b", error: "#ef4444", info: "#3b82f6" },
|
|
2618
|
+
bold: { success: "#22c55e", warning: "#f59e0b", error: "#ef4444", info: "#3b82f6" },
|
|
2619
|
+
luxury: { success: "#15803d", warning: "#a16207", error: "#b91c1c", info: "#1e40af" },
|
|
2620
|
+
organic: { success: "#16a34a", warning: "#d97706", error: "#dc2626", info: "#0284c7" }
|
|
2621
|
+
};
|
|
2622
|
+
return semantics[style];
|
|
2623
|
+
}
|
|
2624
|
+
function generateDarkModePreset(lightPreset) {
|
|
2625
|
+
const invertedNeutral = {
|
|
2626
|
+
50: lightPreset.colors.neutral[950],
|
|
2627
|
+
100: lightPreset.colors.neutral[900],
|
|
2628
|
+
200: lightPreset.colors.neutral[800],
|
|
2629
|
+
300: lightPreset.colors.neutral[700],
|
|
2630
|
+
400: lightPreset.colors.neutral[600],
|
|
2631
|
+
500: lightPreset.colors.neutral[500],
|
|
2632
|
+
600: lightPreset.colors.neutral[400],
|
|
2633
|
+
700: lightPreset.colors.neutral[300],
|
|
2634
|
+
800: lightPreset.colors.neutral[200],
|
|
2635
|
+
900: lightPreset.colors.neutral[100],
|
|
2636
|
+
950: lightPreset.colors.neutral[50]
|
|
2637
|
+
};
|
|
2638
|
+
return {
|
|
2639
|
+
...lightPreset,
|
|
2640
|
+
name: `${lightPreset.name}-dark`,
|
|
2641
|
+
displayName: `${lightPreset.displayName} (Dark)`,
|
|
2642
|
+
colors: {
|
|
2643
|
+
...lightPreset.colors,
|
|
2644
|
+
neutral: invertedNeutral
|
|
2645
|
+
}
|
|
2646
|
+
};
|
|
2647
|
+
}
|
|
2648
|
+
function generateCssFromPreset(preset) {
|
|
2649
|
+
const lines = [
|
|
2650
|
+
`/* ${preset.displayName} Theme */`,
|
|
2651
|
+
`/* Generated by Nice2Dev Brand Kit */`,
|
|
2652
|
+
"",
|
|
2653
|
+
":root {"
|
|
2654
|
+
];
|
|
2655
|
+
for (const [shade, value] of Object.entries(preset.colors.primary)) {
|
|
2656
|
+
lines.push(` --nice-color-primary-${shade}: ${value};`);
|
|
2657
|
+
}
|
|
2658
|
+
if (preset.colors.secondary) {
|
|
2659
|
+
for (const [shade, value] of Object.entries(preset.colors.secondary)) {
|
|
2660
|
+
lines.push(` --nice-color-secondary-${shade}: ${value};`);
|
|
2661
|
+
}
|
|
2662
|
+
}
|
|
2663
|
+
if (preset.colors.accent) {
|
|
2664
|
+
for (const [shade, value] of Object.entries(preset.colors.accent)) {
|
|
2665
|
+
lines.push(` --nice-color-accent-${shade}: ${value};`);
|
|
2666
|
+
}
|
|
2667
|
+
}
|
|
2668
|
+
for (const [shade, value] of Object.entries(preset.colors.neutral)) {
|
|
2669
|
+
lines.push(` --nice-color-neutral-${shade}: ${value};`);
|
|
2670
|
+
}
|
|
2671
|
+
lines.push(` --nice-color-success: ${preset.colors.success};`);
|
|
2672
|
+
lines.push(` --nice-color-warning: ${preset.colors.warning};`);
|
|
2673
|
+
lines.push(` --nice-color-error: ${preset.colors.error};`);
|
|
2674
|
+
lines.push(` --nice-color-info: ${preset.colors.info};`);
|
|
2675
|
+
if (preset.typography) {
|
|
2676
|
+
lines.push(` --nice-font-family-body: ${preset.typography.fontFamily};`);
|
|
2677
|
+
lines.push(
|
|
2678
|
+
` --nice-font-family-heading: ${preset.typography.headingFontFamily || preset.typography.fontFamily};`
|
|
2679
|
+
);
|
|
2680
|
+
}
|
|
2681
|
+
const radiusMap = { none: "0", sm: "0.25rem", md: "0.5rem", lg: "1rem", full: "9999px" };
|
|
2682
|
+
if (preset.borderRadius) {
|
|
2683
|
+
lines.push(` --nice-radius-base: ${radiusMap[preset.borderRadius]};`);
|
|
2684
|
+
}
|
|
2685
|
+
lines.push("}");
|
|
2686
|
+
return lines.join("\n");
|
|
2687
|
+
}
|
|
2688
|
+
function generateTokensFromPreset(preset) {
|
|
2689
|
+
const colorToToken = (value) => ({ $value: value, $type: "color" });
|
|
2690
|
+
const scaleToTokens = (scale) => {
|
|
2691
|
+
const tokens = {};
|
|
2692
|
+
for (const [shade, value] of Object.entries(scale)) {
|
|
2693
|
+
tokens[shade] = colorToToken(value);
|
|
2694
|
+
}
|
|
2695
|
+
return tokens;
|
|
2696
|
+
};
|
|
2697
|
+
return {
|
|
2698
|
+
$name: preset.displayName,
|
|
2699
|
+
$description: preset.description,
|
|
2700
|
+
color: {
|
|
2701
|
+
primary: scaleToTokens(preset.colors.primary),
|
|
2702
|
+
secondary: preset.colors.secondary ? scaleToTokens(preset.colors.secondary) : void 0,
|
|
2703
|
+
accent: preset.colors.accent ? scaleToTokens(preset.colors.accent) : void 0,
|
|
2704
|
+
neutral: scaleToTokens(preset.colors.neutral),
|
|
2705
|
+
semantic: {
|
|
2706
|
+
success: colorToToken(preset.colors.success),
|
|
2707
|
+
warning: colorToToken(preset.colors.warning),
|
|
2708
|
+
error: colorToToken(preset.colors.error),
|
|
2709
|
+
info: colorToToken(preset.colors.info)
|
|
2710
|
+
}
|
|
2711
|
+
},
|
|
2712
|
+
typography: preset.typography ? {
|
|
2713
|
+
fontFamily: {
|
|
2714
|
+
body: { $value: [preset.typography.fontFamily], $type: "fontFamily" },
|
|
2715
|
+
heading: {
|
|
2716
|
+
$value: [preset.typography.headingFontFamily || preset.typography.fontFamily],
|
|
2717
|
+
$type: "fontFamily"
|
|
2718
|
+
}
|
|
2719
|
+
}
|
|
2720
|
+
} : void 0
|
|
2721
|
+
};
|
|
2722
|
+
}
|
|
2723
|
+
function generateBrandAssets(preset, config) {
|
|
2724
|
+
const colorPalette = [
|
|
2725
|
+
{
|
|
2726
|
+
name: "Primary",
|
|
2727
|
+
colors: Object.entries(preset.colors.primary).map(([shade, hex]) => ({
|
|
2728
|
+
shade,
|
|
2729
|
+
hex,
|
|
2730
|
+
usage: shade === "500" ? "Main brand color" : shade === "600" ? "Hover states" : shade === "700" ? "Active states" : "Supporting"
|
|
2731
|
+
}))
|
|
2732
|
+
}
|
|
2733
|
+
];
|
|
2734
|
+
if (preset.colors.secondary) {
|
|
2735
|
+
colorPalette.push({
|
|
2736
|
+
name: "Secondary",
|
|
2737
|
+
colors: Object.entries(preset.colors.secondary).map(([shade, hex]) => ({
|
|
2738
|
+
shade,
|
|
2739
|
+
hex,
|
|
2740
|
+
usage: shade === "500" ? "Secondary actions" : "Supporting"
|
|
2741
|
+
}))
|
|
2742
|
+
});
|
|
2743
|
+
}
|
|
2744
|
+
const typographyScale = [
|
|
2745
|
+
{
|
|
2746
|
+
name: "Display",
|
|
2747
|
+
size: "3.75rem",
|
|
2748
|
+
weight: 700,
|
|
2749
|
+
lineHeight: 1,
|
|
2750
|
+
usage: "Hero sections, large headings"
|
|
2751
|
+
},
|
|
2752
|
+
{ name: "H1", size: "2.25rem", weight: 700, lineHeight: 1.2, usage: "Page titles" },
|
|
2753
|
+
{ name: "H2", size: "1.875rem", weight: 600, lineHeight: 1.3, usage: "Section headings" },
|
|
2754
|
+
{ name: "H3", size: "1.5rem", weight: 600, lineHeight: 1.4, usage: "Card titles" },
|
|
2755
|
+
{ name: "H4", size: "1.25rem", weight: 600, lineHeight: 1.4, usage: "Subsections" },
|
|
2756
|
+
{
|
|
2757
|
+
name: "Body Large",
|
|
2758
|
+
size: "1.125rem",
|
|
2759
|
+
weight: 400,
|
|
2760
|
+
lineHeight: 1.6,
|
|
2761
|
+
usage: "Lead paragraphs"
|
|
2762
|
+
},
|
|
2763
|
+
{ name: "Body", size: "1rem", weight: 400, lineHeight: 1.5, usage: "Main content" },
|
|
2764
|
+
{ name: "Body Small", size: "0.875rem", weight: 400, lineHeight: 1.5, usage: "Secondary text" },
|
|
2765
|
+
{ name: "Caption", size: "0.75rem", weight: 400, lineHeight: 1.4, usage: "Labels, hints" }
|
|
2766
|
+
];
|
|
2767
|
+
const spacingScale = [
|
|
2768
|
+
{ name: "xs", value: "0.25rem", usage: "Tight spacing" },
|
|
2769
|
+
{ name: "sm", value: "0.5rem", usage: "Compact elements" },
|
|
2770
|
+
{ name: "md", value: "1rem", usage: "Standard spacing" },
|
|
2771
|
+
{ name: "lg", value: "1.5rem", usage: "Section spacing" },
|
|
2772
|
+
{ name: "xl", value: "2rem", usage: "Large gaps" },
|
|
2773
|
+
{ name: "2xl", value: "3rem", usage: "Section dividers" }
|
|
2774
|
+
];
|
|
2775
|
+
const logoUsageGuidelines = `
|
|
2776
|
+
# ${config.brandName || "Brand"} Logo Usage Guidelines
|
|
2777
|
+
|
|
2778
|
+
## Minimum Size
|
|
2779
|
+
- Digital: 24px height minimum
|
|
2780
|
+
- Print: 12mm height minimum
|
|
2781
|
+
|
|
2782
|
+
## Clear Space
|
|
2783
|
+
- Maintain clear space equal to the height of the logo mark
|
|
2784
|
+
|
|
2785
|
+
## Color Variations
|
|
2786
|
+
- Primary: Use on light backgrounds (${preset.colors.primary[500]})
|
|
2787
|
+
- Reversed: Use on dark backgrounds (white or ${preset.colors.neutral[50]})
|
|
2788
|
+
- Monochrome: For limited color applications
|
|
2789
|
+
|
|
2790
|
+
## Don'ts
|
|
2791
|
+
- Don't stretch or distort
|
|
2792
|
+
- Don't rotate
|
|
2793
|
+
- Don't apply effects or shadows
|
|
2794
|
+
- Don't change colors outside brand palette
|
|
2795
|
+
- Don't place on busy backgrounds
|
|
2796
|
+
`.trim();
|
|
2797
|
+
return {
|
|
2798
|
+
colorPalette,
|
|
2799
|
+
typographyScale,
|
|
2800
|
+
spacingScale,
|
|
2801
|
+
logoUsageGuidelines
|
|
2802
|
+
};
|
|
2803
|
+
}
|
|
2804
|
+
function quickBrandKit(primaryColor, brandName = "My Brand") {
|
|
2805
|
+
return generateBrandKit({
|
|
2806
|
+
primaryColor,
|
|
2807
|
+
brandName,
|
|
2808
|
+
industry: "technology",
|
|
2809
|
+
style: "modern"
|
|
2810
|
+
});
|
|
2811
|
+
}
|
|
2812
|
+
function industryBrandKit(primaryColor, brandName, industry) {
|
|
2813
|
+
return generateBrandKit({
|
|
2814
|
+
primaryColor,
|
|
2815
|
+
brandName,
|
|
2816
|
+
industry
|
|
2817
|
+
});
|
|
2818
|
+
}
|
|
2819
|
+
|
|
2820
|
+
// src/accessibility.ts
|
|
2821
|
+
var STANDARD_MOTION = {
|
|
2822
|
+
duration: {
|
|
2823
|
+
instant: "0ms",
|
|
2824
|
+
fast: "100ms",
|
|
2825
|
+
normal: "200ms",
|
|
2826
|
+
slow: "300ms",
|
|
2827
|
+
slower: "500ms",
|
|
2828
|
+
slowest: "1000ms"
|
|
2829
|
+
},
|
|
2830
|
+
easing: {
|
|
2831
|
+
linear: "linear",
|
|
2832
|
+
easeIn: "cubic-bezier(0.4, 0, 1, 1)",
|
|
2833
|
+
easeOut: "cubic-bezier(0, 0, 0.2, 1)",
|
|
2834
|
+
easeInOut: "cubic-bezier(0.4, 0, 0.2, 1)",
|
|
2835
|
+
spring: "cubic-bezier(0.175, 0.885, 0.32, 1.275)",
|
|
2836
|
+
bounce: "cubic-bezier(0.68, -0.55, 0.265, 1.55)"
|
|
2837
|
+
},
|
|
2838
|
+
transition: {
|
|
2839
|
+
none: "none",
|
|
2840
|
+
all: "all 200ms cubic-bezier(0.4, 0, 0.2, 1)",
|
|
2841
|
+
colors: "color, background-color, border-color 200ms cubic-bezier(0.4, 0, 0.2, 1)",
|
|
2842
|
+
opacity: "opacity 200ms cubic-bezier(0.4, 0, 0.2, 1)",
|
|
2843
|
+
transform: "transform 200ms cubic-bezier(0.4, 0, 0.2, 1)",
|
|
2844
|
+
shadow: "box-shadow 200ms cubic-bezier(0.4, 0, 0.2, 1)"
|
|
2845
|
+
}
|
|
2846
|
+
};
|
|
2847
|
+
var REDUCED_MOTION = {
|
|
2848
|
+
duration: {
|
|
2849
|
+
instant: "0ms",
|
|
2850
|
+
fast: "0ms",
|
|
2851
|
+
normal: "0ms",
|
|
2852
|
+
slow: "0ms",
|
|
2853
|
+
slower: "0ms",
|
|
2854
|
+
slowest: "0ms"
|
|
2855
|
+
},
|
|
2856
|
+
easing: {
|
|
2857
|
+
linear: "linear",
|
|
2858
|
+
easeIn: "linear",
|
|
2859
|
+
easeOut: "linear",
|
|
2860
|
+
easeInOut: "linear",
|
|
2861
|
+
spring: "linear",
|
|
2862
|
+
bounce: "linear"
|
|
2863
|
+
},
|
|
2864
|
+
transition: {
|
|
2865
|
+
none: "none",
|
|
2866
|
+
all: "none",
|
|
2867
|
+
colors: "none",
|
|
2868
|
+
opacity: "opacity 0ms linear",
|
|
2869
|
+
transform: "none",
|
|
2870
|
+
shadow: "none"
|
|
2871
|
+
}
|
|
2872
|
+
};
|
|
2873
|
+
var MINIMAL_MOTION = {
|
|
2874
|
+
duration: {
|
|
2875
|
+
instant: "0ms",
|
|
2876
|
+
fast: "50ms",
|
|
2877
|
+
normal: "100ms",
|
|
2878
|
+
slow: "150ms",
|
|
2879
|
+
slower: "200ms",
|
|
2880
|
+
slowest: "300ms"
|
|
2881
|
+
},
|
|
2882
|
+
easing: {
|
|
2883
|
+
linear: "linear",
|
|
2884
|
+
easeIn: "linear",
|
|
2885
|
+
easeOut: "linear",
|
|
2886
|
+
easeInOut: "linear",
|
|
2887
|
+
spring: "linear",
|
|
2888
|
+
bounce: "linear"
|
|
2889
|
+
},
|
|
2890
|
+
transition: {
|
|
2891
|
+
none: "none",
|
|
2892
|
+
all: "opacity 100ms linear",
|
|
2893
|
+
colors: "color, background-color 100ms linear",
|
|
2894
|
+
opacity: "opacity 100ms linear",
|
|
2895
|
+
transform: "none",
|
|
2896
|
+
shadow: "none"
|
|
2897
|
+
}
|
|
2898
|
+
};
|
|
2899
|
+
var STANDARD_FOCUS = {
|
|
2900
|
+
ring: {
|
|
2901
|
+
width: "2px",
|
|
2902
|
+
offset: "2px",
|
|
2903
|
+
color: "var(--nice-color-primary-500)",
|
|
2904
|
+
style: "solid"
|
|
2905
|
+
},
|
|
2906
|
+
outline: {
|
|
2907
|
+
width: "2px",
|
|
2908
|
+
style: "solid",
|
|
2909
|
+
color: "var(--nice-color-primary-500)",
|
|
2910
|
+
offset: "2px"
|
|
2911
|
+
}
|
|
2912
|
+
};
|
|
2913
|
+
var ENHANCED_FOCUS = {
|
|
2914
|
+
ring: {
|
|
2915
|
+
width: "3px",
|
|
2916
|
+
offset: "3px",
|
|
2917
|
+
color: "var(--nice-color-primary-600)",
|
|
2918
|
+
style: "solid"
|
|
2919
|
+
},
|
|
2920
|
+
outline: {
|
|
2921
|
+
width: "3px",
|
|
2922
|
+
style: "solid",
|
|
2923
|
+
color: "var(--nice-color-primary-600)",
|
|
2924
|
+
offset: "3px"
|
|
2925
|
+
}
|
|
2926
|
+
};
|
|
2927
|
+
var HIGH_VISIBILITY_FOCUS = {
|
|
2928
|
+
ring: {
|
|
2929
|
+
width: "4px",
|
|
2930
|
+
offset: "4px",
|
|
2931
|
+
color: "#000000",
|
|
2932
|
+
style: "solid"
|
|
2933
|
+
},
|
|
2934
|
+
outline: {
|
|
2935
|
+
width: "4px",
|
|
2936
|
+
style: "solid",
|
|
2937
|
+
color: "#000000",
|
|
2938
|
+
offset: "4px"
|
|
2939
|
+
}
|
|
2940
|
+
};
|
|
2941
|
+
var STANDARD_CONTRAST = {
|
|
2942
|
+
text: {
|
|
2943
|
+
primary: "#111827",
|
|
2944
|
+
secondary: "#374151",
|
|
2945
|
+
tertiary: "#6b7280",
|
|
2946
|
+
disabled: "#9ca3af",
|
|
2947
|
+
inverse: "#ffffff"
|
|
2948
|
+
},
|
|
2949
|
+
background: {
|
|
2950
|
+
primary: "#ffffff",
|
|
2951
|
+
secondary: "#f9fafb",
|
|
2952
|
+
tertiary: "#f3f4f6",
|
|
2953
|
+
elevated: "#ffffff",
|
|
2954
|
+
overlay: "rgba(0, 0, 0, 0.5)"
|
|
2955
|
+
},
|
|
2956
|
+
border: {
|
|
2957
|
+
default: "#e5e7eb",
|
|
2958
|
+
strong: "#d1d5db",
|
|
2959
|
+
focus: "#3b82f6"
|
|
2960
|
+
}
|
|
2961
|
+
};
|
|
2962
|
+
var HIGH_CONTRAST = {
|
|
2963
|
+
text: {
|
|
2964
|
+
primary: "#000000",
|
|
2965
|
+
secondary: "#1a1a1a",
|
|
2966
|
+
tertiary: "#333333",
|
|
2967
|
+
disabled: "#666666",
|
|
2968
|
+
inverse: "#ffffff"
|
|
2969
|
+
},
|
|
2970
|
+
background: {
|
|
2971
|
+
primary: "#ffffff",
|
|
2972
|
+
secondary: "#f5f5f5",
|
|
2973
|
+
tertiary: "#ebebeb",
|
|
2974
|
+
elevated: "#ffffff",
|
|
2975
|
+
overlay: "rgba(0, 0, 0, 0.7)"
|
|
2976
|
+
},
|
|
2977
|
+
border: {
|
|
2978
|
+
default: "#000000",
|
|
2979
|
+
strong: "#000000",
|
|
2980
|
+
focus: "#0000cc"
|
|
2981
|
+
}
|
|
2982
|
+
};
|
|
2983
|
+
var HIGH_CONTRAST_DARK = {
|
|
2984
|
+
text: {
|
|
2985
|
+
primary: "#ffffff",
|
|
2986
|
+
secondary: "#f0f0f0",
|
|
2987
|
+
tertiary: "#e0e0e0",
|
|
2988
|
+
disabled: "#999999",
|
|
2989
|
+
inverse: "#000000"
|
|
2990
|
+
},
|
|
2991
|
+
background: {
|
|
2992
|
+
primary: "#000000",
|
|
2993
|
+
secondary: "#0a0a0a",
|
|
2994
|
+
tertiary: "#141414",
|
|
2995
|
+
elevated: "#1a1a1a",
|
|
2996
|
+
overlay: "rgba(255, 255, 255, 0.3)"
|
|
2997
|
+
},
|
|
2998
|
+
border: {
|
|
2999
|
+
default: "#ffffff",
|
|
3000
|
+
strong: "#ffffff",
|
|
3001
|
+
focus: "#ffff00"
|
|
3002
|
+
}
|
|
3003
|
+
};
|
|
3004
|
+
var STANDARD_TYPOGRAPHY = {
|
|
3005
|
+
minSize: "1rem",
|
|
3006
|
+
lineHeight: "1.5",
|
|
3007
|
+
letterSpacing: "normal",
|
|
3008
|
+
wordSpacing: "normal"
|
|
3009
|
+
};
|
|
3010
|
+
var ENHANCED_TYPOGRAPHY = {
|
|
3011
|
+
minSize: "1.125rem",
|
|
3012
|
+
lineHeight: "1.75",
|
|
3013
|
+
letterSpacing: "0.02em",
|
|
3014
|
+
wordSpacing: "0.05em"
|
|
3015
|
+
};
|
|
3016
|
+
var MAXIMUM_READABILITY_TYPOGRAPHY = {
|
|
3017
|
+
minSize: "1.25rem",
|
|
3018
|
+
lineHeight: "2",
|
|
3019
|
+
letterSpacing: "0.05em",
|
|
3020
|
+
wordSpacing: "0.1em"
|
|
3021
|
+
};
|
|
3022
|
+
function generateReducedMotionCss(config = {}) {
|
|
3023
|
+
const motion = config.allowReducedAnimations ? MINIMAL_MOTION : REDUCED_MOTION;
|
|
3024
|
+
return `
|
|
3025
|
+
/* Reduced Motion Styles */
|
|
3026
|
+
@media (prefers-reduced-motion: reduce) {
|
|
3027
|
+
*,
|
|
3028
|
+
*::before,
|
|
3029
|
+
*::after {
|
|
3030
|
+
animation-duration: ${motion.duration.instant} !important;
|
|
3031
|
+
animation-iteration-count: 1 !important;
|
|
3032
|
+
transition-duration: ${motion.duration.instant} !important;
|
|
3033
|
+
scroll-behavior: auto !important;
|
|
3034
|
+
}
|
|
3035
|
+
|
|
3036
|
+
/* Preserve essential state changes */
|
|
3037
|
+
[data-state] {
|
|
3038
|
+
transition: opacity ${config.allowReducedAnimations ? "100ms" : "0ms"} linear !important;
|
|
3039
|
+
}
|
|
3040
|
+
}
|
|
3041
|
+
|
|
3042
|
+
/* Reduced motion utility classes */
|
|
3043
|
+
.reduce-motion {
|
|
3044
|
+
animation: none !important;
|
|
3045
|
+
transition: none !important;
|
|
3046
|
+
}
|
|
3047
|
+
|
|
3048
|
+
.reduce-motion-safe {
|
|
3049
|
+
animation-duration: ${motion.duration.normal} !important;
|
|
3050
|
+
transition-duration: ${motion.duration.normal} !important;
|
|
3051
|
+
}
|
|
3052
|
+
|
|
3053
|
+
${config.disableParallax ? `
|
|
3054
|
+
/* Disable parallax */
|
|
3055
|
+
.parallax,
|
|
3056
|
+
[data-parallax] {
|
|
3057
|
+
transform: none !important;
|
|
3058
|
+
position: relative !important;
|
|
3059
|
+
}
|
|
3060
|
+
` : ""}
|
|
3061
|
+
|
|
3062
|
+
${config.disableAutoPlay ? `
|
|
3063
|
+
/* Disable autoplay */
|
|
3064
|
+
video[autoplay],
|
|
3065
|
+
[data-autoplay] {
|
|
3066
|
+
animation-play-state: paused !important;
|
|
3067
|
+
}
|
|
3068
|
+
` : ""}
|
|
3069
|
+
`.trim();
|
|
3070
|
+
}
|
|
3071
|
+
function generateFocusCss(tokens = ENHANCED_FOCUS) {
|
|
3072
|
+
return `
|
|
3073
|
+
/* Enhanced Focus Styles */
|
|
3074
|
+
:focus-visible {
|
|
3075
|
+
outline: ${tokens.outline.width} ${tokens.outline.style} ${tokens.outline.color};
|
|
3076
|
+
outline-offset: ${tokens.outline.offset};
|
|
3077
|
+
}
|
|
3078
|
+
|
|
3079
|
+
/* Focus ring utility */
|
|
3080
|
+
.focus-ring:focus-visible {
|
|
3081
|
+
box-shadow: 0 0 0 ${tokens.ring.offset} var(--nice-color-background, #fff),
|
|
3082
|
+
0 0 0 calc(${tokens.ring.offset} + ${tokens.ring.width}) ${tokens.ring.color};
|
|
3083
|
+
}
|
|
3084
|
+
|
|
3085
|
+
/* Skip links */
|
|
3086
|
+
.skip-link {
|
|
3087
|
+
position: absolute;
|
|
3088
|
+
top: -40px;
|
|
3089
|
+
left: 0;
|
|
3090
|
+
padding: 8px 16px;
|
|
3091
|
+
background: ${tokens.ring.color};
|
|
3092
|
+
color: white;
|
|
3093
|
+
z-index: 100;
|
|
3094
|
+
transition: top 200ms ease;
|
|
3095
|
+
}
|
|
3096
|
+
|
|
3097
|
+
.skip-link:focus {
|
|
3098
|
+
top: 0;
|
|
3099
|
+
}
|
|
3100
|
+
`.trim();
|
|
3101
|
+
}
|
|
3102
|
+
function generateHighContrastCss(tokens = HIGH_CONTRAST) {
|
|
3103
|
+
return `
|
|
3104
|
+
/* High Contrast Mode */
|
|
3105
|
+
@media (prefers-contrast: more) {
|
|
3106
|
+
:root {
|
|
3107
|
+
--nice-text-primary: ${tokens.text.primary};
|
|
3108
|
+
--nice-text-secondary: ${tokens.text.secondary};
|
|
3109
|
+
--nice-text-tertiary: ${tokens.text.tertiary};
|
|
3110
|
+
--nice-text-disabled: ${tokens.text.disabled};
|
|
3111
|
+
--nice-bg-primary: ${tokens.background.primary};
|
|
3112
|
+
--nice-bg-secondary: ${tokens.background.secondary};
|
|
3113
|
+
--nice-bg-tertiary: ${tokens.background.tertiary};
|
|
3114
|
+
--nice-border-default: ${tokens.border.default};
|
|
3115
|
+
--nice-border-strong: ${tokens.border.strong};
|
|
3116
|
+
--nice-border-focus: ${tokens.border.focus};
|
|
3117
|
+
}
|
|
3118
|
+
|
|
3119
|
+
/* Ensure minimum contrast */
|
|
3120
|
+
* {
|
|
3121
|
+
border-color: ${tokens.border.default} !important;
|
|
3122
|
+
}
|
|
3123
|
+
|
|
3124
|
+
/* No transparent backgrounds */
|
|
3125
|
+
button,
|
|
3126
|
+
input,
|
|
3127
|
+
select,
|
|
3128
|
+
textarea {
|
|
3129
|
+
background-color: ${tokens.background.primary} !important;
|
|
3130
|
+
border: 2px solid ${tokens.border.default} !important;
|
|
3131
|
+
}
|
|
3132
|
+
}
|
|
3133
|
+
|
|
3134
|
+
/* High contrast utility classes */
|
|
3135
|
+
.high-contrast {
|
|
3136
|
+
--nice-text-primary: ${tokens.text.primary};
|
|
3137
|
+
--nice-bg-primary: ${tokens.background.primary};
|
|
3138
|
+
--nice-border-default: ${tokens.border.default};
|
|
3139
|
+
}
|
|
3140
|
+
`.trim();
|
|
3141
|
+
}
|
|
3142
|
+
function generateAccessibilityCss(options = {}) {
|
|
3143
|
+
const sections = [];
|
|
3144
|
+
sections.push(generateReducedMotionCss(options.reducedMotion));
|
|
3145
|
+
sections.push(generateFocusCss(options.focus));
|
|
3146
|
+
sections.push(generateHighContrastCss(options.contrast));
|
|
3147
|
+
if (options.typography) {
|
|
3148
|
+
sections.push(
|
|
3149
|
+
`
|
|
3150
|
+
/* Enhanced Typography */
|
|
3151
|
+
.enhanced-readability {
|
|
3152
|
+
font-size: ${options.typography.minSize};
|
|
3153
|
+
line-height: ${options.typography.lineHeight};
|
|
3154
|
+
letter-spacing: ${options.typography.letterSpacing};
|
|
3155
|
+
word-spacing: ${options.typography.wordSpacing};
|
|
3156
|
+
}
|
|
3157
|
+
`.trim()
|
|
3158
|
+
);
|
|
3159
|
+
}
|
|
3160
|
+
return sections.join("\n\n");
|
|
3161
|
+
}
|
|
3162
|
+
var STANDARD_ACCESSIBILITY = {
|
|
3163
|
+
motion: STANDARD_MOTION,
|
|
3164
|
+
focus: STANDARD_FOCUS,
|
|
3165
|
+
contrast: STANDARD_CONTRAST,
|
|
3166
|
+
typography: STANDARD_TYPOGRAPHY
|
|
3167
|
+
};
|
|
3168
|
+
var ENHANCED_ACCESSIBILITY = {
|
|
3169
|
+
motion: MINIMAL_MOTION,
|
|
3170
|
+
focus: ENHANCED_FOCUS,
|
|
3171
|
+
contrast: STANDARD_CONTRAST,
|
|
3172
|
+
typography: ENHANCED_TYPOGRAPHY
|
|
3173
|
+
};
|
|
3174
|
+
var MAXIMUM_ACCESSIBILITY = {
|
|
3175
|
+
motion: REDUCED_MOTION,
|
|
3176
|
+
focus: HIGH_VISIBILITY_FOCUS,
|
|
3177
|
+
contrast: HIGH_CONTRAST,
|
|
3178
|
+
typography: MAXIMUM_READABILITY_TYPOGRAPHY
|
|
3179
|
+
};
|
|
3180
|
+
function getLuminance(hex) {
|
|
3181
|
+
const rgb = hex.slice(1).match(/.{2}/g).map((c) => parseInt(c, 16) / 255).map((c) => c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4));
|
|
3182
|
+
return 0.2126 * rgb[0] + 0.7152 * rgb[1] + 0.0722 * rgb[2];
|
|
3183
|
+
}
|
|
3184
|
+
function getContrastRatio2(color1, color2) {
|
|
3185
|
+
const l1 = getLuminance(color1);
|
|
3186
|
+
const l2 = getLuminance(color2);
|
|
3187
|
+
const lighter = Math.max(l1, l2);
|
|
3188
|
+
const darker = Math.min(l1, l2);
|
|
3189
|
+
return (lighter + 0.05) / (darker + 0.05);
|
|
3190
|
+
}
|
|
3191
|
+
function checkContrast(foreground, background, level = "AA", isLargeText = false) {
|
|
3192
|
+
const ratio = getContrastRatio2(foreground, background);
|
|
3193
|
+
let required;
|
|
3194
|
+
if (level === "AAA") {
|
|
3195
|
+
required = isLargeText ? 4.5 : 7;
|
|
3196
|
+
} else {
|
|
3197
|
+
required = isLargeText ? 3 : 4.5;
|
|
3198
|
+
}
|
|
3199
|
+
return {
|
|
3200
|
+
passes: ratio >= required,
|
|
3201
|
+
ratio: Math.round(ratio * 100) / 100,
|
|
3202
|
+
required
|
|
3203
|
+
};
|
|
3204
|
+
}
|
|
3205
|
+
function suggestAccessibleColor(color, background, targetRatio = 4.5) {
|
|
3206
|
+
const currentRatio = getContrastRatio2(color, background);
|
|
3207
|
+
if (currentRatio >= targetRatio) {
|
|
3208
|
+
return color;
|
|
3209
|
+
}
|
|
3210
|
+
const r = parseInt(color.slice(1, 3), 16);
|
|
3211
|
+
const g = parseInt(color.slice(3, 5), 16);
|
|
3212
|
+
const b = parseInt(color.slice(5, 7), 16);
|
|
3213
|
+
const bgLuminance = getLuminance(background);
|
|
3214
|
+
const shouldDarken = bgLuminance > 0.5;
|
|
3215
|
+
const factor = shouldDarken ? 0.9 : 1.1;
|
|
3216
|
+
let adjustedR = r, adjustedG = g, adjustedB = b;
|
|
3217
|
+
for (let i = 0; i < 50; i++) {
|
|
3218
|
+
if (shouldDarken) {
|
|
3219
|
+
adjustedR = Math.max(0, Math.floor(adjustedR * factor));
|
|
3220
|
+
adjustedG = Math.max(0, Math.floor(adjustedG * factor));
|
|
3221
|
+
adjustedB = Math.max(0, Math.floor(adjustedB * factor));
|
|
3222
|
+
} else {
|
|
3223
|
+
adjustedR = Math.min(255, Math.floor(adjustedR * factor));
|
|
3224
|
+
adjustedG = Math.min(255, Math.floor(adjustedG * factor));
|
|
3225
|
+
adjustedB = Math.min(255, Math.floor(adjustedB * factor));
|
|
3226
|
+
}
|
|
3227
|
+
const adjusted = `#${adjustedR.toString(16).padStart(2, "0")}${adjustedG.toString(16).padStart(2, "0")}${adjustedB.toString(16).padStart(2, "0")}`;
|
|
3228
|
+
if (getContrastRatio2(adjusted, background) >= targetRatio) {
|
|
3229
|
+
return adjusted;
|
|
3230
|
+
}
|
|
3231
|
+
}
|
|
3232
|
+
return shouldDarken ? "#000000" : "#ffffff";
|
|
3233
|
+
}
|
|
3234
|
+
|
|
3235
|
+
// src/css-only.ts
|
|
3236
|
+
function tokensToCssVariables(tokens, config = {}) {
|
|
3237
|
+
const prefix = config.prefix || "nice";
|
|
3238
|
+
const flatTokens = flattenTokensToVariables(tokens.tokens, prefix);
|
|
3239
|
+
const rootLines = [":root {", ...flatTokens.map((t) => ` ${t.variable}: ${t.value};`), "}"];
|
|
3240
|
+
const root = rootLines.join("\n");
|
|
3241
|
+
let dark;
|
|
3242
|
+
if (config.includeDarkMode && tokens.themes?.dark) {
|
|
3243
|
+
const darkTokens = flattenTokensToVariables(tokens.themes.dark, prefix);
|
|
3244
|
+
dark = [
|
|
3245
|
+
"@media (prefers-color-scheme: dark) {",
|
|
3246
|
+
" :root {",
|
|
3247
|
+
...darkTokens.map((t) => ` ${t.variable}: ${t.value};`),
|
|
3248
|
+
" }",
|
|
3249
|
+
"}",
|
|
3250
|
+
"",
|
|
3251
|
+
'[data-theme="dark"] {',
|
|
3252
|
+
...darkTokens.map((t) => ` ${t.variable}: ${t.value};`),
|
|
3253
|
+
"}"
|
|
3254
|
+
].join("\n");
|
|
3255
|
+
}
|
|
3256
|
+
let highContrast;
|
|
3257
|
+
if (config.includeHighContrast && tokens.themes?.["high-contrast"]) {
|
|
3258
|
+
const hcTokens = flattenTokensToVariables(tokens.themes["high-contrast"], prefix);
|
|
3259
|
+
highContrast = [
|
|
3260
|
+
"@media (prefers-contrast: more) {",
|
|
3261
|
+
" :root {",
|
|
3262
|
+
...hcTokens.map((t) => ` ${t.variable}: ${t.value};`),
|
|
3263
|
+
" }",
|
|
3264
|
+
"}",
|
|
3265
|
+
"",
|
|
3266
|
+
'[data-theme="high-contrast"] {',
|
|
3267
|
+
...hcTokens.map((t) => ` ${t.variable}: ${t.value};`),
|
|
3268
|
+
"}"
|
|
3269
|
+
].join("\n");
|
|
3270
|
+
}
|
|
3271
|
+
let reducedMotion;
|
|
3272
|
+
if (config.includeReducedMotion) {
|
|
3273
|
+
reducedMotion = generateReducedMotionStyles(prefix);
|
|
3274
|
+
}
|
|
3275
|
+
const utilities = generateUtilityClasses(prefix);
|
|
3276
|
+
const reset = generateMinimalReset(prefix);
|
|
3277
|
+
const sections = [root];
|
|
3278
|
+
if (dark) {
|
|
3279
|
+
sections.push(dark);
|
|
3280
|
+
}
|
|
3281
|
+
if (highContrast) {
|
|
3282
|
+
sections.push(highContrast);
|
|
3283
|
+
}
|
|
3284
|
+
if (reducedMotion) {
|
|
3285
|
+
sections.push(reducedMotion);
|
|
3286
|
+
}
|
|
3287
|
+
if (reset) {
|
|
3288
|
+
sections.push(reset);
|
|
3289
|
+
}
|
|
3290
|
+
if (utilities) {
|
|
3291
|
+
sections.push(utilities);
|
|
3292
|
+
}
|
|
3293
|
+
let combined = sections.join("\n\n");
|
|
3294
|
+
if (config.useLayers) {
|
|
3295
|
+
combined = wrapInLayers(combined);
|
|
3296
|
+
}
|
|
3297
|
+
return {
|
|
3298
|
+
root,
|
|
3299
|
+
dark,
|
|
3300
|
+
highContrast,
|
|
3301
|
+
reducedMotion,
|
|
3302
|
+
utilities,
|
|
3303
|
+
reset,
|
|
3304
|
+
combined
|
|
3305
|
+
};
|
|
3306
|
+
}
|
|
3307
|
+
function flattenTokensToVariables(input, prefix, path3 = []) {
|
|
3308
|
+
const result = [];
|
|
3309
|
+
if (Array.isArray(input)) {
|
|
3310
|
+
for (const token of input) {
|
|
3311
|
+
result.push({
|
|
3312
|
+
variable: token.cssVariable || `--${prefix}-${token.path.join("-")}`,
|
|
3313
|
+
value: token.resolvedValue,
|
|
3314
|
+
path: token.path.join(".")
|
|
3315
|
+
});
|
|
3316
|
+
}
|
|
3317
|
+
return result;
|
|
3318
|
+
}
|
|
3319
|
+
for (const [key, value] of Object.entries(input)) {
|
|
3320
|
+
const currentPath = [...path3, key];
|
|
3321
|
+
if (typeof value === "object" && value !== null && "$value" in value) {
|
|
3322
|
+
const token = value;
|
|
3323
|
+
const variable = `--${prefix}-${currentPath.join("-")}`;
|
|
3324
|
+
result.push({
|
|
3325
|
+
variable,
|
|
3326
|
+
value: formatTokenValue(token.$value, token.$type),
|
|
3327
|
+
path: currentPath.join(".")
|
|
3328
|
+
});
|
|
3329
|
+
} else if (typeof value === "object" && value !== null) {
|
|
3330
|
+
result.push(
|
|
3331
|
+
...flattenTokensToVariables(value, prefix, currentPath)
|
|
3332
|
+
);
|
|
3333
|
+
}
|
|
3334
|
+
}
|
|
3335
|
+
return result;
|
|
3336
|
+
}
|
|
3337
|
+
function formatTokenValue(value, type) {
|
|
3338
|
+
if (typeof value === "string") {
|
|
3339
|
+
if (value.startsWith("{") && value.endsWith("}")) {
|
|
3340
|
+
const path3 = value.slice(1, -1).replace(/\./g, "-");
|
|
3341
|
+
return `var(--nice-${path3})`;
|
|
3342
|
+
}
|
|
3343
|
+
return value;
|
|
3344
|
+
}
|
|
3345
|
+
if (typeof value === "number") {
|
|
3346
|
+
if (type === "dimension") {
|
|
3347
|
+
return `${value}px`;
|
|
3348
|
+
}
|
|
3349
|
+
return String(value);
|
|
3350
|
+
}
|
|
3351
|
+
if (Array.isArray(value)) {
|
|
3352
|
+
if (type === "fontFamily") {
|
|
3353
|
+
return value.join(", ");
|
|
3354
|
+
}
|
|
3355
|
+
return value.join(" ");
|
|
3356
|
+
}
|
|
3357
|
+
if (typeof value === "object" && value !== null) {
|
|
3358
|
+
const obj = value;
|
|
3359
|
+
if (type === "shadow") {
|
|
3360
|
+
const offsetX = obj.offsetX || "0";
|
|
3361
|
+
const offsetY = obj.offsetY || "0";
|
|
3362
|
+
const blur = obj.blur || "0";
|
|
3363
|
+
const spread = obj.spread || "0";
|
|
3364
|
+
const color = obj.color || "rgba(0,0,0,0.1)";
|
|
3365
|
+
return `${offsetX} ${offsetY} ${blur} ${spread} ${color}`;
|
|
3366
|
+
}
|
|
3367
|
+
if (type === "typography") {
|
|
3368
|
+
const fontSize = obj.fontSize || "1rem";
|
|
3369
|
+
const fontWeight = obj.fontWeight || "400";
|
|
3370
|
+
const lineHeight = obj.lineHeight || "1.5";
|
|
3371
|
+
const fontFamily = Array.isArray(obj.fontFamily) ? obj.fontFamily.join(", ") : obj.fontFamily || "inherit";
|
|
3372
|
+
return `${fontWeight} ${fontSize}/${lineHeight} ${fontFamily}`;
|
|
3373
|
+
}
|
|
3374
|
+
}
|
|
3375
|
+
return String(value);
|
|
3376
|
+
}
|
|
3377
|
+
function presetToCss(preset, config = {}) {
|
|
3378
|
+
const prefix = config.prefix || "nice";
|
|
3379
|
+
const lines = [];
|
|
3380
|
+
lines.push(`/* ${preset.displayName} Theme */`);
|
|
3381
|
+
lines.push(`/* Generated by Nice2Dev Design Tokens */`);
|
|
3382
|
+
lines.push("");
|
|
3383
|
+
lines.push(":root {");
|
|
3384
|
+
for (const [colorName, colorValue] of Object.entries(preset.colors)) {
|
|
3385
|
+
if (typeof colorValue === "string") {
|
|
3386
|
+
lines.push(` --${prefix}-color-${colorName}: ${colorValue};`);
|
|
3387
|
+
} else if (typeof colorValue === "object" && colorValue !== null) {
|
|
3388
|
+
const scale = colorValue;
|
|
3389
|
+
for (const [shade, hex] of Object.entries(scale)) {
|
|
3390
|
+
lines.push(` --${prefix}-color-${colorName}-${shade}: ${hex};`);
|
|
3391
|
+
}
|
|
3392
|
+
}
|
|
3393
|
+
}
|
|
3394
|
+
if (preset.typography) {
|
|
3395
|
+
lines.push(` --${prefix}-font-body: ${preset.typography.fontFamily};`);
|
|
3396
|
+
if (preset.typography.headingFontFamily) {
|
|
3397
|
+
lines.push(` --${prefix}-font-heading: ${preset.typography.headingFontFamily};`);
|
|
3398
|
+
}
|
|
3399
|
+
}
|
|
3400
|
+
if (preset.borderRadius) {
|
|
3401
|
+
const radii = {
|
|
3402
|
+
none: "0",
|
|
3403
|
+
sm: "0.25rem",
|
|
3404
|
+
md: "0.5rem",
|
|
3405
|
+
lg: "1rem",
|
|
3406
|
+
full: "9999px"
|
|
3407
|
+
};
|
|
3408
|
+
lines.push(` --${prefix}-radius: ${radii[preset.borderRadius]};`);
|
|
3409
|
+
}
|
|
3410
|
+
if (preset.shadows) {
|
|
3411
|
+
const shadowMap = {
|
|
3412
|
+
none: { sm: "none", md: "none", lg: "none" },
|
|
3413
|
+
sm: {
|
|
3414
|
+
sm: "0 1px 2px rgba(0,0,0,0.05)",
|
|
3415
|
+
md: "0 2px 4px rgba(0,0,0,0.05)",
|
|
3416
|
+
lg: "0 4px 8px rgba(0,0,0,0.05)"
|
|
3417
|
+
},
|
|
3418
|
+
md: {
|
|
3419
|
+
sm: "0 1px 3px rgba(0,0,0,0.1)",
|
|
3420
|
+
md: "0 4px 6px rgba(0,0,0,0.1)",
|
|
3421
|
+
lg: "0 10px 15px rgba(0,0,0,0.1)"
|
|
3422
|
+
},
|
|
3423
|
+
lg: {
|
|
3424
|
+
sm: "0 2px 4px rgba(0,0,0,0.15)",
|
|
3425
|
+
md: "0 8px 16px rgba(0,0,0,0.15)",
|
|
3426
|
+
lg: "0 20px 40px rgba(0,0,0,0.15)"
|
|
3427
|
+
}
|
|
3428
|
+
};
|
|
3429
|
+
const shadows = shadowMap[preset.shadows];
|
|
3430
|
+
lines.push(` --${prefix}-shadow-sm: ${shadows.sm};`);
|
|
3431
|
+
lines.push(` --${prefix}-shadow-md: ${shadows.md};`);
|
|
3432
|
+
lines.push(` --${prefix}-shadow-lg: ${shadows.lg};`);
|
|
3433
|
+
}
|
|
3434
|
+
lines.push("}");
|
|
3435
|
+
return lines.join("\n");
|
|
3436
|
+
}
|
|
3437
|
+
function generateUtilityClasses(prefix) {
|
|
3438
|
+
return `
|
|
3439
|
+
/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
3440
|
+
UTILITY CLASSES
|
|
3441
|
+
Generated CSS utilities using CSS variables
|
|
3442
|
+
\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */
|
|
3443
|
+
|
|
3444
|
+
/* Colors */
|
|
3445
|
+
.text-primary { color: var(--${prefix}-color-primary-500); }
|
|
3446
|
+
.text-secondary { color: var(--${prefix}-color-secondary-500); }
|
|
3447
|
+
.text-accent { color: var(--${prefix}-color-accent-500); }
|
|
3448
|
+
.text-success { color: var(--${prefix}-color-success); }
|
|
3449
|
+
.text-warning { color: var(--${prefix}-color-warning); }
|
|
3450
|
+
.text-error { color: var(--${prefix}-color-error); }
|
|
3451
|
+
.text-info { color: var(--${prefix}-color-info); }
|
|
3452
|
+
|
|
3453
|
+
.bg-primary { background-color: var(--${prefix}-color-primary-500); }
|
|
3454
|
+
.bg-secondary { background-color: var(--${prefix}-color-secondary-500); }
|
|
3455
|
+
.bg-accent { background-color: var(--${prefix}-color-accent-500); }
|
|
3456
|
+
.bg-success { background-color: var(--${prefix}-color-success); }
|
|
3457
|
+
.bg-warning { background-color: var(--${prefix}-color-warning); }
|
|
3458
|
+
.bg-error { background-color: var(--${prefix}-color-error); }
|
|
3459
|
+
.bg-info { background-color: var(--${prefix}-color-info); }
|
|
3460
|
+
|
|
3461
|
+
/* Border */
|
|
3462
|
+
.border-primary { border-color: var(--${prefix}-color-primary-500); }
|
|
3463
|
+
.rounded { border-radius: var(--${prefix}-radius); }
|
|
3464
|
+
.rounded-sm { border-radius: calc(var(--${prefix}-radius) * 0.5); }
|
|
3465
|
+
.rounded-lg { border-radius: calc(var(--${prefix}-radius) * 2); }
|
|
3466
|
+
.rounded-full { border-radius: 9999px; }
|
|
3467
|
+
|
|
3468
|
+
/* Shadows */
|
|
3469
|
+
.shadow-sm { box-shadow: var(--${prefix}-shadow-sm); }
|
|
3470
|
+
.shadow-md { box-shadow: var(--${prefix}-shadow-md); }
|
|
3471
|
+
.shadow-lg { box-shadow: var(--${prefix}-shadow-lg); }
|
|
3472
|
+
.shadow-none { box-shadow: none; }
|
|
3473
|
+
|
|
3474
|
+
/* Typography */
|
|
3475
|
+
.font-body { font-family: var(--${prefix}-font-body); }
|
|
3476
|
+
.font-heading { font-family: var(--${prefix}-font-heading, var(--${prefix}-font-body)); }
|
|
3477
|
+
|
|
3478
|
+
/* Focus */
|
|
3479
|
+
.focus-ring:focus-visible {
|
|
3480
|
+
outline: 2px solid var(--${prefix}-color-primary-500);
|
|
3481
|
+
outline-offset: 2px;
|
|
3482
|
+
}
|
|
3483
|
+
`.trim();
|
|
3484
|
+
}
|
|
3485
|
+
function generateMinimalReset(prefix) {
|
|
3486
|
+
return `
|
|
3487
|
+
/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
3488
|
+
MINIMAL RESET
|
|
3489
|
+
Component-ready CSS reset using design tokens
|
|
3490
|
+
\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */
|
|
3491
|
+
|
|
3492
|
+
*, *::before, *::after {
|
|
3493
|
+
box-sizing: border-box;
|
|
3494
|
+
margin: 0;
|
|
3495
|
+
padding: 0;
|
|
3496
|
+
}
|
|
3497
|
+
|
|
3498
|
+
html {
|
|
3499
|
+
font-family: var(--${prefix}-font-body, system-ui, sans-serif);
|
|
3500
|
+
line-height: 1.5;
|
|
3501
|
+
-webkit-text-size-adjust: 100%;
|
|
3502
|
+
-webkit-font-smoothing: antialiased;
|
|
3503
|
+
-moz-osx-font-smoothing: grayscale;
|
|
3504
|
+
}
|
|
3505
|
+
|
|
3506
|
+
body {
|
|
3507
|
+
min-height: 100vh;
|
|
3508
|
+
color: var(--${prefix}-color-neutral-900);
|
|
3509
|
+
background-color: var(--${prefix}-color-neutral-50);
|
|
3510
|
+
}
|
|
3511
|
+
|
|
3512
|
+
h1, h2, h3, h4, h5, h6 {
|
|
3513
|
+
font-family: var(--${prefix}-font-heading, var(--${prefix}-font-body));
|
|
3514
|
+
font-weight: 600;
|
|
3515
|
+
line-height: 1.25;
|
|
3516
|
+
}
|
|
3517
|
+
|
|
3518
|
+
a {
|
|
3519
|
+
color: var(--${prefix}-color-primary-500);
|
|
3520
|
+
text-decoration: none;
|
|
3521
|
+
}
|
|
3522
|
+
|
|
3523
|
+
a:hover {
|
|
3524
|
+
color: var(--${prefix}-color-primary-600);
|
|
3525
|
+
text-decoration: underline;
|
|
3526
|
+
}
|
|
3527
|
+
|
|
3528
|
+
button, input, select, textarea {
|
|
3529
|
+
font-family: inherit;
|
|
3530
|
+
font-size: inherit;
|
|
3531
|
+
line-height: inherit;
|
|
3532
|
+
}
|
|
3533
|
+
|
|
3534
|
+
button {
|
|
3535
|
+
cursor: pointer;
|
|
3536
|
+
border: none;
|
|
3537
|
+
background: transparent;
|
|
3538
|
+
}
|
|
3539
|
+
|
|
3540
|
+
img, svg, video {
|
|
3541
|
+
display: block;
|
|
3542
|
+
max-width: 100%;
|
|
3543
|
+
height: auto;
|
|
3544
|
+
}
|
|
3545
|
+
`.trim();
|
|
3546
|
+
}
|
|
3547
|
+
function generateReducedMotionStyles(prefix) {
|
|
3548
|
+
return `
|
|
3549
|
+
/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
3550
|
+
REDUCED MOTION
|
|
3551
|
+
Respect user preferences for reduced motion
|
|
3552
|
+
\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */
|
|
3553
|
+
|
|
3554
|
+
@media (prefers-reduced-motion: reduce) {
|
|
3555
|
+
*, *::before, *::after {
|
|
3556
|
+
animation-duration: 0.01ms !important;
|
|
3557
|
+
animation-iteration-count: 1 !important;
|
|
3558
|
+
transition-duration: 0.01ms !important;
|
|
3559
|
+
scroll-behavior: auto !important;
|
|
3560
|
+
}
|
|
3561
|
+
}
|
|
3562
|
+
|
|
3563
|
+
/* Motion-safe utilities */
|
|
3564
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
3565
|
+
.animate-fade-in {
|
|
3566
|
+
animation: ${prefix}-fade-in 200ms ease-out;
|
|
3567
|
+
}
|
|
3568
|
+
|
|
3569
|
+
.animate-slide-up {
|
|
3570
|
+
animation: ${prefix}-slide-up 200ms ease-out;
|
|
3571
|
+
}
|
|
3572
|
+
|
|
3573
|
+
.animate-scale-in {
|
|
3574
|
+
animation: ${prefix}-scale-in 200ms ease-out;
|
|
3575
|
+
}
|
|
3576
|
+
}
|
|
3577
|
+
|
|
3578
|
+
@keyframes ${prefix}-fade-in {
|
|
3579
|
+
from { opacity: 0; }
|
|
3580
|
+
to { opacity: 1; }
|
|
3581
|
+
}
|
|
3582
|
+
|
|
3583
|
+
@keyframes ${prefix}-slide-up {
|
|
3584
|
+
from { opacity: 0; transform: translateY(10px); }
|
|
3585
|
+
to { opacity: 1; transform: translateY(0); }
|
|
3586
|
+
}
|
|
3587
|
+
|
|
3588
|
+
@keyframes ${prefix}-scale-in {
|
|
3589
|
+
from { opacity: 0; transform: scale(0.95); }
|
|
3590
|
+
to { opacity: 1; transform: scale(1); }
|
|
3591
|
+
}
|
|
3592
|
+
`.trim();
|
|
3593
|
+
}
|
|
3594
|
+
function wrapInLayers(css) {
|
|
3595
|
+
return `
|
|
3596
|
+
/* Define layer order */
|
|
3597
|
+
@layer reset, tokens, utilities, components;
|
|
3598
|
+
|
|
3599
|
+
@layer tokens {
|
|
3600
|
+
${css.split("\n").map((l) => ` ${l}`).join("\n")}
|
|
3601
|
+
}
|
|
3602
|
+
`.trim();
|
|
3603
|
+
}
|
|
3604
|
+
function generateComponentStyles(prefix = "nice") {
|
|
3605
|
+
return `
|
|
3606
|
+
/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
3607
|
+
CSS-ONLY COMPONENT STYLES
|
|
3608
|
+
No CSS-in-JS required \u2014 pure CSS variables approach
|
|
3609
|
+
\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */
|
|
3610
|
+
|
|
3611
|
+
/* Button */
|
|
3612
|
+
.${prefix}-button {
|
|
3613
|
+
display: inline-flex;
|
|
3614
|
+
align-items: center;
|
|
3615
|
+
justify-content: center;
|
|
3616
|
+
gap: 0.5rem;
|
|
3617
|
+
padding: 0.5rem 1rem;
|
|
3618
|
+
font-weight: 500;
|
|
3619
|
+
border-radius: var(--${prefix}-radius, 0.5rem);
|
|
3620
|
+
transition: all 150ms ease;
|
|
3621
|
+
}
|
|
3622
|
+
|
|
3623
|
+
.${prefix}-button--primary {
|
|
3624
|
+
background-color: var(--${prefix}-color-primary-500);
|
|
3625
|
+
color: white;
|
|
3626
|
+
}
|
|
3627
|
+
|
|
3628
|
+
.${prefix}-button--primary:hover {
|
|
3629
|
+
background-color: var(--${prefix}-color-primary-600);
|
|
3630
|
+
}
|
|
3631
|
+
|
|
3632
|
+
.${prefix}-button--secondary {
|
|
3633
|
+
background-color: var(--${prefix}-color-neutral-100);
|
|
3634
|
+
color: var(--${prefix}-color-neutral-900);
|
|
3635
|
+
}
|
|
3636
|
+
|
|
3637
|
+
.${prefix}-button--secondary:hover {
|
|
3638
|
+
background-color: var(--${prefix}-color-neutral-200);
|
|
3639
|
+
}
|
|
3640
|
+
|
|
3641
|
+
.${prefix}-button--outline {
|
|
3642
|
+
border: 1px solid var(--${prefix}-color-primary-500);
|
|
3643
|
+
color: var(--${prefix}-color-primary-500);
|
|
3644
|
+
background: transparent;
|
|
3645
|
+
}
|
|
3646
|
+
|
|
3647
|
+
.${prefix}-button--outline:hover {
|
|
3648
|
+
background-color: var(--${prefix}-color-primary-50);
|
|
3649
|
+
}
|
|
3650
|
+
|
|
3651
|
+
.${prefix}-button:disabled {
|
|
3652
|
+
opacity: 0.5;
|
|
3653
|
+
cursor: not-allowed;
|
|
3654
|
+
}
|
|
3655
|
+
|
|
3656
|
+
/* Input */
|
|
3657
|
+
.${prefix}-input {
|
|
3658
|
+
width: 100%;
|
|
3659
|
+
padding: 0.5rem 0.75rem;
|
|
3660
|
+
border: 1px solid var(--${prefix}-color-neutral-300);
|
|
3661
|
+
border-radius: var(--${prefix}-radius, 0.5rem);
|
|
3662
|
+
background-color: var(--${prefix}-color-neutral-50);
|
|
3663
|
+
transition: border-color 150ms ease, box-shadow 150ms ease;
|
|
3664
|
+
}
|
|
3665
|
+
|
|
3666
|
+
.${prefix}-input:focus {
|
|
3667
|
+
outline: none;
|
|
3668
|
+
border-color: var(--${prefix}-color-primary-500);
|
|
3669
|
+
box-shadow: 0 0 0 3px var(--${prefix}-color-primary-100);
|
|
3670
|
+
}
|
|
3671
|
+
|
|
3672
|
+
.${prefix}-input:disabled {
|
|
3673
|
+
opacity: 0.5;
|
|
3674
|
+
cursor: not-allowed;
|
|
3675
|
+
}
|
|
3676
|
+
|
|
3677
|
+
.${prefix}-input--error {
|
|
3678
|
+
border-color: var(--${prefix}-color-error);
|
|
3679
|
+
}
|
|
3680
|
+
|
|
3681
|
+
/* Card */
|
|
3682
|
+
.${prefix}-card {
|
|
3683
|
+
background-color: var(--${prefix}-color-neutral-50);
|
|
3684
|
+
border: 1px solid var(--${prefix}-color-neutral-200);
|
|
3685
|
+
border-radius: var(--${prefix}-radius, 0.5rem);
|
|
3686
|
+
box-shadow: var(--${prefix}-shadow-sm);
|
|
3687
|
+
}
|
|
3688
|
+
|
|
3689
|
+
.${prefix}-card__header {
|
|
3690
|
+
padding: 1rem 1.5rem;
|
|
3691
|
+
border-bottom: 1px solid var(--${prefix}-color-neutral-200);
|
|
3692
|
+
}
|
|
3693
|
+
|
|
3694
|
+
.${prefix}-card__body {
|
|
3695
|
+
padding: 1.5rem;
|
|
3696
|
+
}
|
|
3697
|
+
|
|
3698
|
+
.${prefix}-card__footer {
|
|
3699
|
+
padding: 1rem 1.5rem;
|
|
3700
|
+
border-top: 1px solid var(--${prefix}-color-neutral-200);
|
|
3701
|
+
}
|
|
3702
|
+
|
|
3703
|
+
/* Badge */
|
|
3704
|
+
.${prefix}-badge {
|
|
3705
|
+
display: inline-flex;
|
|
3706
|
+
align-items: center;
|
|
3707
|
+
padding: 0.25rem 0.5rem;
|
|
3708
|
+
font-size: 0.75rem;
|
|
3709
|
+
font-weight: 500;
|
|
3710
|
+
border-radius: 9999px;
|
|
3711
|
+
}
|
|
3712
|
+
|
|
3713
|
+
.${prefix}-badge--primary {
|
|
3714
|
+
background-color: var(--${prefix}-color-primary-100);
|
|
3715
|
+
color: var(--${prefix}-color-primary-700);
|
|
3716
|
+
}
|
|
3717
|
+
|
|
3718
|
+
.${prefix}-badge--success {
|
|
3719
|
+
background-color: #dcfce7;
|
|
3720
|
+
color: #166534;
|
|
3721
|
+
}
|
|
3722
|
+
|
|
3723
|
+
.${prefix}-badge--warning {
|
|
3724
|
+
background-color: #fef3c7;
|
|
3725
|
+
color: #92400e;
|
|
3726
|
+
}
|
|
3727
|
+
|
|
3728
|
+
.${prefix}-badge--error {
|
|
3729
|
+
background-color: #fee2e2;
|
|
3730
|
+
color: #991b1b;
|
|
3731
|
+
}
|
|
3732
|
+
|
|
3733
|
+
/* Alert */
|
|
3734
|
+
.${prefix}-alert {
|
|
3735
|
+
display: flex;
|
|
3736
|
+
gap: 0.75rem;
|
|
3737
|
+
padding: 1rem;
|
|
3738
|
+
border-radius: var(--${prefix}-radius, 0.5rem);
|
|
3739
|
+
}
|
|
3740
|
+
|
|
3741
|
+
.${prefix}-alert--info {
|
|
3742
|
+
background-color: #eff6ff;
|
|
3743
|
+
border: 1px solid #bfdbfe;
|
|
3744
|
+
color: #1e40af;
|
|
3745
|
+
}
|
|
3746
|
+
|
|
3747
|
+
.${prefix}-alert--success {
|
|
3748
|
+
background-color: #f0fdf4;
|
|
3749
|
+
border: 1px solid #bbf7d0;
|
|
3750
|
+
color: #166534;
|
|
3751
|
+
}
|
|
3752
|
+
|
|
3753
|
+
.${prefix}-alert--warning {
|
|
3754
|
+
background-color: #fffbeb;
|
|
3755
|
+
border: 1px solid #fde68a;
|
|
3756
|
+
color: #92400e;
|
|
3757
|
+
}
|
|
3758
|
+
|
|
3759
|
+
.${prefix}-alert--error {
|
|
3760
|
+
background-color: #fef2f2;
|
|
3761
|
+
border: 1px solid #fecaca;
|
|
3762
|
+
color: #991b1b;
|
|
3763
|
+
}
|
|
3764
|
+
`.trim();
|
|
3765
|
+
}
|
|
3766
|
+
function generateCompleteStylesheet(preset, config = {}) {
|
|
3767
|
+
const prefix = config.prefix || "nice";
|
|
3768
|
+
const sections = [];
|
|
3769
|
+
sections.push(`/**
|
|
3770
|
+
* ${preset.displayName} Theme Stylesheet
|
|
3771
|
+
* Generated by Nice2Dev Design Tokens
|
|
3772
|
+
* CSS-only approach \u2014 no CSS-in-JS runtime
|
|
3773
|
+
*/`);
|
|
3774
|
+
if (config.useLayers) {
|
|
3775
|
+
sections.push("@layer reset, tokens, utilities, components;");
|
|
3776
|
+
}
|
|
3777
|
+
sections.push(presetToCss(preset, config));
|
|
3778
|
+
sections.push(generateMinimalReset(prefix));
|
|
3779
|
+
sections.push(generateUtilityClasses(prefix));
|
|
3780
|
+
sections.push(generateComponentStyles(prefix));
|
|
3781
|
+
if (config.includeReducedMotion) {
|
|
3782
|
+
sections.push(generateReducedMotionStyles(prefix));
|
|
3783
|
+
}
|
|
3784
|
+
return sections.join("\n\n");
|
|
3785
|
+
}
|
|
3786
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
3787
|
+
0 && (module.exports = {
|
|
3788
|
+
ENHANCED_ACCESSIBILITY,
|
|
3789
|
+
ENHANCED_FOCUS,
|
|
3790
|
+
ENHANCED_TYPOGRAPHY,
|
|
3791
|
+
HIGH_CONTRAST,
|
|
3792
|
+
HIGH_CONTRAST_DARK,
|
|
3793
|
+
HIGH_VISIBILITY_FOCUS,
|
|
3794
|
+
MAXIMUM_ACCESSIBILITY,
|
|
3795
|
+
MAXIMUM_READABILITY_TYPOGRAPHY,
|
|
3796
|
+
MINIMAL_MOTION,
|
|
3797
|
+
PRESETS,
|
|
3798
|
+
REDUCED_MOTION,
|
|
3799
|
+
STANDARD_ACCESSIBILITY,
|
|
3800
|
+
STANDARD_CONTRAST,
|
|
3801
|
+
STANDARD_FOCUS,
|
|
3802
|
+
STANDARD_MOTION,
|
|
3803
|
+
STANDARD_TYPOGRAPHY,
|
|
3804
|
+
TokenGenerator,
|
|
3805
|
+
analyzeColor,
|
|
3806
|
+
buildTokenObject,
|
|
3807
|
+
checkCircularReferences,
|
|
3808
|
+
checkContrast,
|
|
3809
|
+
createGenerator,
|
|
3810
|
+
createTheme,
|
|
3811
|
+
createTokenCollection,
|
|
3812
|
+
cubicBezierToCss,
|
|
3813
|
+
darkenColor,
|
|
3814
|
+
defaultOptions,
|
|
3815
|
+
defaultThemes,
|
|
3816
|
+
durationToMs,
|
|
3817
|
+
extractReferencePath,
|
|
3818
|
+
filterTokensByPath,
|
|
3819
|
+
filterTokensByType,
|
|
3820
|
+
findReferences,
|
|
3821
|
+
flattenTokens,
|
|
3822
|
+
fontWeightToNumber,
|
|
3823
|
+
generateAccessibilityCss,
|
|
3824
|
+
generateBrandKit,
|
|
3825
|
+
generateColorScale,
|
|
3826
|
+
generateColorScaleAsync,
|
|
3827
|
+
generateCompleteStylesheet,
|
|
3828
|
+
generateComponentStyles,
|
|
3829
|
+
generateDarkModeTokens,
|
|
3830
|
+
generateFocusCss,
|
|
3831
|
+
generateHighContrastCss,
|
|
3832
|
+
generateHighContrastTokens,
|
|
3833
|
+
generateReactThemeContext,
|
|
3834
|
+
generateReducedMotionCss,
|
|
3835
|
+
generateThemeSwitcher,
|
|
3836
|
+
generateThemesCss,
|
|
3837
|
+
generateTokenTypes,
|
|
3838
|
+
generateTokens,
|
|
3839
|
+
getAccessibleTextColor,
|
|
3840
|
+
getAllCategories,
|
|
3841
|
+
getCategories,
|
|
3842
|
+
getContrastRatio,
|
|
3843
|
+
getContrastRatioAsync,
|
|
3844
|
+
getDependencyGraph,
|
|
3845
|
+
getPresetByName,
|
|
3846
|
+
getPresetsByCategory,
|
|
3847
|
+
getTokenByPath,
|
|
3848
|
+
hexToHsl,
|
|
3849
|
+
hexToOklch,
|
|
3850
|
+
hexToRgb,
|
|
3851
|
+
industryBrandKit,
|
|
3852
|
+
isDesignToken,
|
|
3853
|
+
isReference,
|
|
3854
|
+
isTokenGroup,
|
|
3855
|
+
lightenColor,
|
|
3856
|
+
mergeTokenFiles,
|
|
3857
|
+
parseTokenDirectory,
|
|
3858
|
+
parseTokenFile,
|
|
3859
|
+
parseTokenFiles,
|
|
3860
|
+
pathToCssVariable,
|
|
3861
|
+
pathToString,
|
|
3862
|
+
presetToCss,
|
|
3863
|
+
presetToCssVariables,
|
|
3864
|
+
presetToTokens,
|
|
3865
|
+
pxToEm,
|
|
3866
|
+
pxToRem,
|
|
3867
|
+
quickBrandKit,
|
|
3868
|
+
remToPx,
|
|
3869
|
+
resolveToVariable,
|
|
3870
|
+
resolveTokenValue,
|
|
3871
|
+
resolveTokens,
|
|
3872
|
+
sortTokensByDependencies,
|
|
3873
|
+
suggestAccessibleColor,
|
|
3874
|
+
tokensToCssVariables,
|
|
3875
|
+
transformToCss,
|
|
3876
|
+
transformToJs,
|
|
3877
|
+
transformToScss,
|
|
3878
|
+
transformToTailwind,
|
|
3879
|
+
transformToTs
|
|
3880
|
+
});
|