colbrush 1.3.0 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.cjs +206 -59
- package/dist/client.cjs +715 -0
- package/dist/client.d.cts +29 -0
- package/dist/client.d.ts +6 -5
- package/dist/client.js +12 -6
- package/package.json +3 -2
package/dist/cli.cjs
CHANGED
|
@@ -23,7 +23,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
23
23
|
mod
|
|
24
24
|
));
|
|
25
25
|
|
|
26
|
-
// src/
|
|
26
|
+
// src/cli/parseFlags.ts
|
|
27
27
|
function parseFlags(argv = process.argv.slice(2)) {
|
|
28
28
|
const out = { _: [] };
|
|
29
29
|
for (const s of argv) {
|
|
@@ -35,19 +35,19 @@ function parseFlags(argv = process.argv.slice(2)) {
|
|
|
35
35
|
return out;
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
// src/constants/regex.ts
|
|
38
|
+
// src/core/constants/regex.ts
|
|
39
39
|
var variableRegex = /(--color-[\w-]+):\s*(#[0-9a-fA-F]{3,8})/g;
|
|
40
40
|
var variationRegex = /^--(.+?)-(50|100|200|300|400|500|600|700|800|900)$/i;
|
|
41
41
|
|
|
42
|
-
// src/
|
|
42
|
+
// src/cli/applyThemes.ts
|
|
43
43
|
var import_node_fs = __toESM(require("fs"), 1);
|
|
44
44
|
var import_postcss = __toESM(require("postcss"), 1);
|
|
45
45
|
var import_postcss_safe_parser = __toESM(require("postcss-safe-parser"), 1);
|
|
46
46
|
|
|
47
|
-
// src/utils/
|
|
47
|
+
// src/core/utils/colorScale.ts
|
|
48
48
|
var import_colorjs = __toESM(require("colorjs.io"), 1);
|
|
49
49
|
|
|
50
|
-
// src/constants/variation.ts
|
|
50
|
+
// src/core/constants/variation.ts
|
|
51
51
|
var DEFAULT_KEYS = [
|
|
52
52
|
"50",
|
|
53
53
|
"100",
|
|
@@ -73,7 +73,7 @@ var DEFAULT_SCALE = {
|
|
|
73
73
|
"900": { dL: -0.3, cMul: 0.88 }
|
|
74
74
|
};
|
|
75
75
|
|
|
76
|
-
// src/utils/
|
|
76
|
+
// src/core/utils/colorScale.ts
|
|
77
77
|
var CLAMP01 = (x) => Math.max(0, Math.min(1, x));
|
|
78
78
|
function hexToOKLCH(hex) {
|
|
79
79
|
const c = new import_colorjs.default(hex);
|
|
@@ -103,11 +103,8 @@ function buildScaleFromBaseHex(baseHex, opts) {
|
|
|
103
103
|
return out;
|
|
104
104
|
}
|
|
105
105
|
|
|
106
|
-
// src/
|
|
106
|
+
// src/cli/applyThemes.ts
|
|
107
107
|
var CSS_PATH = "src/index.css";
|
|
108
|
-
function toThemeColor(hex, _vision) {
|
|
109
|
-
return hex;
|
|
110
|
-
}
|
|
111
108
|
function loadRoot(cssPath = CSS_PATH) {
|
|
112
109
|
const css = import_node_fs.default.readFileSync(cssPath, "utf8");
|
|
113
110
|
return (0, import_postcss.default)().process(css, { parser: import_postcss_safe_parser.default }).root;
|
|
@@ -152,7 +149,7 @@ function getColorVariablesFromRoot(root) {
|
|
|
152
149
|
});
|
|
153
150
|
return vars;
|
|
154
151
|
}
|
|
155
|
-
function applyThemes(input, cssPath = CSS_PATH) {
|
|
152
|
+
function applyThemes(input, cssPath = CSS_PATH, opts) {
|
|
156
153
|
const root = loadRoot(cssPath);
|
|
157
154
|
const originalVars = getColorVariablesFromRoot(root);
|
|
158
155
|
const varsForTheme = {};
|
|
@@ -167,27 +164,31 @@ function applyThemes(input, cssPath = CSS_PATH) {
|
|
|
167
164
|
const [, token] = m;
|
|
168
165
|
const keys = rich.keys && rich.keys.length ? rich.keys : getExistingKeysForToken(root, token).length ? getExistingKeysForToken(root, token) : Array.from(DEFAULT_KEYS);
|
|
169
166
|
if (rich.scale !== false) {
|
|
170
|
-
const scaleMap = buildScaleFromBaseHex(rich.base, {
|
|
167
|
+
const scaleMap = buildScaleFromBaseHex(rich.base, {
|
|
168
|
+
keys
|
|
169
|
+
});
|
|
171
170
|
for (const k of keys) {
|
|
172
171
|
const hex = scaleMap[k];
|
|
173
|
-
varsForTheme[`--${token}-${k}`] =
|
|
172
|
+
varsForTheme[`--${token}-${k}`] = hex;
|
|
174
173
|
}
|
|
175
174
|
} else {
|
|
176
|
-
varsForTheme[varName] =
|
|
175
|
+
varsForTheme[varName] = rich.base;
|
|
177
176
|
}
|
|
178
177
|
} else {
|
|
179
|
-
varsForTheme[varName] =
|
|
178
|
+
varsForTheme[varName] = rich.base;
|
|
180
179
|
}
|
|
181
180
|
}
|
|
182
181
|
upsertBlock(root, `[data-theme='${input.vision}']`, varsForTheme);
|
|
183
182
|
import_node_fs.default.writeFileSync(cssPath, root.toString(), "utf8");
|
|
184
|
-
|
|
183
|
+
if (!opts?.silent) {
|
|
184
|
+
console.log(`\u2705 [${input.vision}] theme updated in ${cssPath}`);
|
|
185
|
+
}
|
|
185
186
|
}
|
|
186
187
|
function inferRich(varName, baseHex) {
|
|
187
188
|
return variationRegex.test(varName) ? { base: baseHex, scale: true } : { base: baseHex, scale: false };
|
|
188
189
|
}
|
|
189
190
|
|
|
190
|
-
// src/
|
|
191
|
+
// src/cli/colorTransform.ts
|
|
191
192
|
var import_chroma_js = __toESM(require("chroma-js"), 1);
|
|
192
193
|
var import_color_blind = __toESM(require("color-blind"), 1);
|
|
193
194
|
var THRESHOLD = 10;
|
|
@@ -199,7 +200,10 @@ function generateCandidates(hex) {
|
|
|
199
200
|
candidates[0] = hex;
|
|
200
201
|
for (let i = 1; i <= CANDIDATE_COUNT / 2; i++) {
|
|
201
202
|
candidates[i * 2 - 1] = (0, import_chroma_js.default)(hex).set("hcl.h", (baseHue + HUE_STEP / CANDIDATE_COUNT * i) % 360).hex();
|
|
202
|
-
candidates[i * 2] = (0, import_chroma_js.default)(hex).set(
|
|
203
|
+
candidates[i * 2] = (0, import_chroma_js.default)(hex).set(
|
|
204
|
+
"hcl.h",
|
|
205
|
+
(baseHue - HUE_STEP / CANDIDATE_COUNT * i + 360) % 360
|
|
206
|
+
).hex();
|
|
203
207
|
}
|
|
204
208
|
return candidates;
|
|
205
209
|
}
|
|
@@ -213,7 +217,7 @@ function findOptimalColorCombination(colorKeys, baseColorsArray, candidateList,
|
|
|
213
217
|
case "protanopia":
|
|
214
218
|
blind = import_color_blind.default.protanopia;
|
|
215
219
|
break;
|
|
216
|
-
// 녹색맹
|
|
220
|
+
// 녹색맹
|
|
217
221
|
case "deuteranopia":
|
|
218
222
|
blind = import_color_blind.default.deuteranopia;
|
|
219
223
|
break;
|
|
@@ -244,12 +248,15 @@ function findOptimalColorCombination(colorKeys, baseColorsArray, candidateList,
|
|
|
244
248
|
}
|
|
245
249
|
dfs(0, [], 0);
|
|
246
250
|
const finalColors = bestColors ?? [...baseColorsArray];
|
|
247
|
-
return colorKeys.reduce(
|
|
248
|
-
acc
|
|
249
|
-
|
|
250
|
-
|
|
251
|
+
return colorKeys.reduce(
|
|
252
|
+
(acc, key, idx) => {
|
|
253
|
+
acc[key] = finalColors[idx];
|
|
254
|
+
return acc;
|
|
255
|
+
},
|
|
256
|
+
{}
|
|
257
|
+
);
|
|
251
258
|
}
|
|
252
|
-
|
|
259
|
+
function prepareCandidates(variables, progress) {
|
|
253
260
|
const scaleGroups = {};
|
|
254
261
|
const filteredVariables = {};
|
|
255
262
|
for (const key in variables) {
|
|
@@ -275,26 +282,30 @@ async function requestColorTransformation(variables) {
|
|
|
275
282
|
}
|
|
276
283
|
const colorKeys = Object.keys(filteredVariables);
|
|
277
284
|
const baseColorsArray = Object.values(filteredVariables).map((v) => v.base);
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
285
|
+
progress?.startSection("Generate candidates");
|
|
286
|
+
const candidateList = [];
|
|
287
|
+
for (let i = 0; i < baseColorsArray.length; i++) {
|
|
288
|
+
candidateList[i] = generateCandidates(baseColorsArray[i]);
|
|
289
|
+
progress?.update((i + 1) / baseColorsArray.length * 100);
|
|
290
|
+
}
|
|
291
|
+
progress?.finishSection("Done");
|
|
292
|
+
return { colorKeys, baseColorsArray, candidateList };
|
|
293
|
+
}
|
|
294
|
+
function buildThemeForVision(colorKeys, baseColorsArray, candidateList, vision) {
|
|
295
|
+
const colors = findOptimalColorCombination(
|
|
296
|
+
colorKeys,
|
|
297
|
+
baseColorsArray,
|
|
298
|
+
candidateList,
|
|
299
|
+
vision
|
|
300
|
+
);
|
|
301
|
+
const variables = Object.entries(colors).reduce(
|
|
302
|
+
(acc, [varName, baseHex]) => {
|
|
293
303
|
acc[varName] = inferRich(varName, baseHex);
|
|
294
304
|
return acc;
|
|
295
|
-
},
|
|
296
|
-
|
|
297
|
-
|
|
305
|
+
},
|
|
306
|
+
{}
|
|
307
|
+
);
|
|
308
|
+
return { vision, variables };
|
|
298
309
|
}
|
|
299
310
|
function getMiddleScaleKey(keys) {
|
|
300
311
|
const scaleNumbers = keys.map((k) => {
|
|
@@ -311,16 +322,17 @@ function getMiddleScaleKey(keys) {
|
|
|
311
322
|
function isValidColors(colors, blind) {
|
|
312
323
|
for (let i = 0; i < colors.length; i++) {
|
|
313
324
|
for (let j = i + 1; j < colors.length; j++) {
|
|
314
|
-
if (import_chroma_js.default.deltaE(blind(colors[i]), blind(colors[j])) < THRESHOLD)
|
|
325
|
+
if (import_chroma_js.default.deltaE(blind(colors[i]), blind(colors[j])) < THRESHOLD)
|
|
326
|
+
return false;
|
|
315
327
|
}
|
|
316
328
|
}
|
|
317
329
|
return true;
|
|
318
330
|
}
|
|
319
331
|
|
|
320
|
-
// src/
|
|
332
|
+
// src/cli/runThemeApply.ts
|
|
321
333
|
var import_node_fs2 = __toESM(require("fs"), 1);
|
|
322
334
|
|
|
323
|
-
// src/
|
|
335
|
+
// src/cli/removeExistingThemeBlocks.ts
|
|
324
336
|
function removeExistingThemeBlocks(content) {
|
|
325
337
|
const visions = ["protanopia", "deuteranopia", "tritanopia"];
|
|
326
338
|
let cleaned = content;
|
|
@@ -334,7 +346,7 @@ function removeExistingThemeBlocks(content) {
|
|
|
334
346
|
return cleaned.trim();
|
|
335
347
|
}
|
|
336
348
|
|
|
337
|
-
// src/
|
|
349
|
+
// src/cli/runThemeApply.ts
|
|
338
350
|
function hexToRgb(hex) {
|
|
339
351
|
let clean = hex.replace("#", "").toLowerCase();
|
|
340
352
|
if (clean.length === 3) {
|
|
@@ -368,19 +380,30 @@ function calculateScale(varName, hexColor) {
|
|
|
368
380
|
}
|
|
369
381
|
return /\d+$/.test(varName);
|
|
370
382
|
}
|
|
371
|
-
async function runThemeApply(cssPath) {
|
|
383
|
+
async function runThemeApply(cssPath, progress) {
|
|
372
384
|
if (!import_node_fs2.default.existsSync(cssPath)) {
|
|
373
385
|
throw new Error(`\u274C CSS \uD30C\uC77C\uC774 \uC874\uC7AC\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4: ${cssPath}`);
|
|
374
386
|
}
|
|
375
387
|
let content = import_node_fs2.default.readFileSync(cssPath, "utf8");
|
|
388
|
+
progress?.startSection("Remove existing theme blocks");
|
|
376
389
|
content = removeExistingThemeBlocks(content);
|
|
390
|
+
progress?.update(100);
|
|
391
|
+
progress?.finishSection("Done");
|
|
377
392
|
const variables = {};
|
|
393
|
+
progress?.startSection("Extract variables");
|
|
394
|
+
const scanRegex = new RegExp(variableRegex.source, variableRegex.flags);
|
|
395
|
+
const all = Array.from(content.matchAll(scanRegex));
|
|
396
|
+
const totalVars = all.length || 1;
|
|
397
|
+
const loopRegex = new RegExp(variableRegex.source, variableRegex.flags);
|
|
378
398
|
let match;
|
|
379
|
-
|
|
399
|
+
let count = 0;
|
|
400
|
+
while ((match = loopRegex.exec(content)) !== null) {
|
|
380
401
|
const [, key, value] = match;
|
|
381
402
|
const cleanKey = key.trim();
|
|
382
403
|
const cleanValue = value.trim().toLowerCase();
|
|
383
404
|
if (isNeutralColor(cleanValue)) {
|
|
405
|
+
count++;
|
|
406
|
+
progress?.update(count / totalVars * 100);
|
|
384
407
|
continue;
|
|
385
408
|
}
|
|
386
409
|
const scale = calculateScale(cleanKey, cleanValue);
|
|
@@ -389,35 +412,159 @@ async function runThemeApply(cssPath) {
|
|
|
389
412
|
scale
|
|
390
413
|
};
|
|
391
414
|
variables[cleanKey] = rich;
|
|
415
|
+
count++;
|
|
416
|
+
progress?.update(count / totalVars * 100);
|
|
392
417
|
}
|
|
418
|
+
progress?.finishSection("Done");
|
|
393
419
|
const visions = ["deuteranopia", "protanopia", "tritanopia"];
|
|
394
420
|
try {
|
|
395
|
-
const
|
|
396
|
-
|
|
397
|
-
|
|
421
|
+
const { colorKeys, baseColorsArray, candidateList } = prepareCandidates(
|
|
422
|
+
variables,
|
|
423
|
+
progress
|
|
424
|
+
);
|
|
425
|
+
for (const vision of visions) {
|
|
426
|
+
const label = `Process \u2014 ${vision}`;
|
|
427
|
+
progress?.startSection(label);
|
|
428
|
+
progress?.update(30, "Optimizing...");
|
|
429
|
+
const themeData = buildThemeForVision(
|
|
430
|
+
colorKeys,
|
|
431
|
+
baseColorsArray,
|
|
432
|
+
candidateList,
|
|
433
|
+
vision
|
|
434
|
+
);
|
|
435
|
+
progress?.update(70, "Applying CSS...");
|
|
436
|
+
await applyThemes(themeData, cssPath, { silent: !!progress });
|
|
437
|
+
progress?.update(100, "Done");
|
|
438
|
+
progress?.finishSection("Done");
|
|
398
439
|
}
|
|
399
440
|
} catch (error) {
|
|
400
441
|
console.log("\u{1F680} ~ runThemeApply ~ error:", error);
|
|
401
442
|
for (const vision of visions) {
|
|
402
|
-
|
|
443
|
+
const label = `Process (fallback) \u2014 ${vision}`;
|
|
444
|
+
progress?.startSection(label);
|
|
445
|
+
await applyThemes({ vision, variables }, cssPath, {
|
|
446
|
+
silent: !!progress
|
|
447
|
+
});
|
|
448
|
+
progress?.finishSection("Done");
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
console.log(`
|
|
452
|
+
\u2705 Colbrush themes applied to ${cssPath}`);
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
// src/cli/progress.ts
|
|
456
|
+
function clampPercent(n) {
|
|
457
|
+
if (Number.isNaN(n)) return 0;
|
|
458
|
+
return Math.max(0, Math.min(100, n));
|
|
459
|
+
}
|
|
460
|
+
function createCliProgress() {
|
|
461
|
+
let hasAnyOutput = false;
|
|
462
|
+
let currentSection = null;
|
|
463
|
+
let sectionStartedAt = 0;
|
|
464
|
+
const isTTY = !!process.stdout.isTTY;
|
|
465
|
+
const A = {
|
|
466
|
+
reset: "\x1B[0m",
|
|
467
|
+
// 리셋
|
|
468
|
+
bold: "\x1B[1m",
|
|
469
|
+
// 굵게
|
|
470
|
+
dim: "\x1B[2m",
|
|
471
|
+
// 흐리게
|
|
472
|
+
green: "\x1B[32m",
|
|
473
|
+
// 초록
|
|
474
|
+
cyan: "\x1B[36m",
|
|
475
|
+
// 청록
|
|
476
|
+
clearLine: "\x1B[2K",
|
|
477
|
+
// 줄 지우기
|
|
478
|
+
carriage: "\r"
|
|
479
|
+
// 캐리지 리턴
|
|
480
|
+
};
|
|
481
|
+
const style = (code, text) => isTTY ? `${code}${text}${A.reset}` : text;
|
|
482
|
+
const bold = (t) => style(A.bold, t);
|
|
483
|
+
const dim = (t) => style(A.dim, t);
|
|
484
|
+
const green = (t) => style(A.green, t);
|
|
485
|
+
const cyan = (t) => style(A.cyan, t);
|
|
486
|
+
function writeSameLine(text) {
|
|
487
|
+
if (isTTY) {
|
|
488
|
+
process.stdout.write(A.clearLine + A.carriage + text);
|
|
489
|
+
} else {
|
|
490
|
+
console.log(text);
|
|
403
491
|
}
|
|
492
|
+
hasAnyOutput = true;
|
|
493
|
+
}
|
|
494
|
+
function newline() {
|
|
495
|
+
if (hasAnyOutput) process.stdout.write("\n");
|
|
404
496
|
}
|
|
405
|
-
|
|
497
|
+
function getTerminalColumns() {
|
|
498
|
+
const c = typeof process.stdout.columns === "number" ? process.stdout.columns : 80;
|
|
499
|
+
return Math.max(40, c);
|
|
500
|
+
}
|
|
501
|
+
function renderBar(pct) {
|
|
502
|
+
const columns = getTerminalColumns();
|
|
503
|
+
const width = Math.max(12, Math.min(30, Math.floor(columns * 0.3)));
|
|
504
|
+
const filled = Math.round(pct / 100 * width);
|
|
505
|
+
const fillChar = "\u2588";
|
|
506
|
+
const emptyChar = "\u2591";
|
|
507
|
+
const body = fillChar.repeat(filled) + emptyChar.repeat(width - filled);
|
|
508
|
+
return pct >= 100 ? green(body) : cyan(body);
|
|
509
|
+
}
|
|
510
|
+
function render(pctRaw, suffixLabel, opts) {
|
|
511
|
+
const p = clampPercent(pctRaw);
|
|
512
|
+
const name = currentSection ? bold(currentSection) : "";
|
|
513
|
+
const bar = renderBar(p);
|
|
514
|
+
const percentText = bold(`${p.toFixed(0).padStart(3, " ")}%`);
|
|
515
|
+
const prefix = isTTY ? `${cyan("\u203A")} ${name ? name + " " : ""}` : name ? name + " " : "";
|
|
516
|
+
const suffix = suffixLabel ? ` ${opts?.styledSuffix ? suffixLabel : dim(suffixLabel)}` : "";
|
|
517
|
+
writeSameLine(`${prefix}[${bar}] ${percentText}${suffix}`);
|
|
518
|
+
}
|
|
519
|
+
return {
|
|
520
|
+
startSection(name) {
|
|
521
|
+
if (currentSection) newline();
|
|
522
|
+
currentSection = name;
|
|
523
|
+
sectionStartedAt = Date.now();
|
|
524
|
+
render(0);
|
|
525
|
+
},
|
|
526
|
+
update(percent, label) {
|
|
527
|
+
if (!currentSection) {
|
|
528
|
+
currentSection = "";
|
|
529
|
+
sectionStartedAt = Date.now();
|
|
530
|
+
}
|
|
531
|
+
render(percent, label);
|
|
532
|
+
},
|
|
533
|
+
finishSection() {
|
|
534
|
+
if (!currentSection) return;
|
|
535
|
+
const ms = Date.now() - sectionStartedAt;
|
|
536
|
+
const secText = (ms / 1e3).toFixed(1) + "s";
|
|
537
|
+
const doneStyled = `${green("\u2714 Done")} ${dim(`(${secText})`)}`;
|
|
538
|
+
render(100, doneStyled, { styledSuffix: true });
|
|
539
|
+
newline();
|
|
540
|
+
process.stdout.write("\n\n");
|
|
541
|
+
currentSection = null;
|
|
542
|
+
},
|
|
543
|
+
// 하위 호환: 단일 바를 하나의 섹션처럼 취급
|
|
544
|
+
start(_totalHint, label) {
|
|
545
|
+
this.startSection(label ?? "");
|
|
546
|
+
},
|
|
547
|
+
finish(label) {
|
|
548
|
+
this.finishSection(label);
|
|
549
|
+
}
|
|
550
|
+
};
|
|
406
551
|
}
|
|
407
552
|
|
|
408
|
-
// src/cli.ts
|
|
553
|
+
// src/cli/index.ts
|
|
409
554
|
async function main() {
|
|
410
555
|
const flags = parseFlags();
|
|
411
556
|
const cmd = flags._[0] ?? "generate";
|
|
412
557
|
const cssPath = typeof flags.css === "string" ? flags.css : "src/index.css";
|
|
413
558
|
if (cmd === "generate") {
|
|
414
|
-
|
|
559
|
+
const progress = createCliProgress();
|
|
560
|
+
await runThemeApply(cssPath, progress);
|
|
415
561
|
process.exit(0);
|
|
416
562
|
}
|
|
417
|
-
console.log(
|
|
418
|
-
-
|
|
419
|
-
|
|
420
|
-
|
|
563
|
+
console.log(`Usage:
|
|
564
|
+
- colbrush generate [--css=src/index.css]
|
|
565
|
+
Extracts color variables from the CSS file and automatically generates color-blind themes,
|
|
566
|
+
then applies them to the same CSS file.
|
|
567
|
+
(Default path: src/index.css)
|
|
421
568
|
`);
|
|
422
569
|
process.exit(1);
|
|
423
570
|
}
|
package/dist/client.cjs
ADDED
|
@@ -0,0 +1,715 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
"use client";
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
+
for (let key of __getOwnPropNames(from))
|
|
14
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
20
|
+
|
|
21
|
+
// src/client.ts
|
|
22
|
+
var client_exports = {};
|
|
23
|
+
__export(client_exports, {
|
|
24
|
+
THEMES: () => THEMES,
|
|
25
|
+
ThemeProvider: () => ThemeProvider,
|
|
26
|
+
ThemeSwitcher: () => ThemeSwitcher,
|
|
27
|
+
useTheme: () => useTheme
|
|
28
|
+
});
|
|
29
|
+
module.exports = __toCommonJS(client_exports);
|
|
30
|
+
|
|
31
|
+
// src/react/ThemeProvider.tsx
|
|
32
|
+
var import_react = require("react");
|
|
33
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
34
|
+
var THEME_KEYS = [
|
|
35
|
+
"default",
|
|
36
|
+
"protanopia",
|
|
37
|
+
"deuteranopia",
|
|
38
|
+
"tritanopia"
|
|
39
|
+
];
|
|
40
|
+
var THEME_LABEL = {
|
|
41
|
+
English: {
|
|
42
|
+
default: "default",
|
|
43
|
+
protanopia: "protanopia",
|
|
44
|
+
deuteranopia: "deuteranopia",
|
|
45
|
+
tritanopia: "tritanopia"
|
|
46
|
+
},
|
|
47
|
+
Korean: {
|
|
48
|
+
default: "\uAE30\uBCF8",
|
|
49
|
+
protanopia: "\uC801\uC0C9\uB9F9",
|
|
50
|
+
deuteranopia: "\uB179\uC0C9\uB9F9",
|
|
51
|
+
tritanopia: "\uCCAD\uC0C9\uB9F9"
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
var getThemeOptions = (lang) => THEME_KEYS.map((key) => ({ key, label: THEME_LABEL[lang][key] }));
|
|
55
|
+
var KEY = "theme";
|
|
56
|
+
var LANG_KEY = "theme_lang";
|
|
57
|
+
var ThemeContext = (0, import_react.createContext)({
|
|
58
|
+
theme: "default",
|
|
59
|
+
language: "English",
|
|
60
|
+
updateTheme: () => {
|
|
61
|
+
},
|
|
62
|
+
updateLanguage: () => {
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
var useTheme = () => (0, import_react.useContext)(ThemeContext);
|
|
66
|
+
function normalizeToKey(value) {
|
|
67
|
+
if (!value) return "default";
|
|
68
|
+
if (THEME_KEYS.includes(value))
|
|
69
|
+
return value;
|
|
70
|
+
const reverse = {};
|
|
71
|
+
["English", "Korean"].forEach((lang) => {
|
|
72
|
+
Object.entries(THEME_LABEL[lang]).forEach(
|
|
73
|
+
([k, label]) => {
|
|
74
|
+
reverse[label] = k;
|
|
75
|
+
}
|
|
76
|
+
);
|
|
77
|
+
});
|
|
78
|
+
return reverse[value] ?? "default";
|
|
79
|
+
}
|
|
80
|
+
function ThemeProvider({ children }) {
|
|
81
|
+
const [theme, setTheme] = (0, import_react.useState)("default");
|
|
82
|
+
const [language, setLanguage] = (0, import_react.useState)("English");
|
|
83
|
+
(0, import_react.useEffect)(() => {
|
|
84
|
+
if (typeof window === "undefined") return;
|
|
85
|
+
const storedTheme = normalizeToKey(localStorage.getItem(KEY));
|
|
86
|
+
const storedLang = localStorage.getItem(LANG_KEY) || "English";
|
|
87
|
+
setTheme(storedTheme);
|
|
88
|
+
setLanguage(storedLang);
|
|
89
|
+
document.documentElement.setAttribute("data-theme", storedTheme);
|
|
90
|
+
}, []);
|
|
91
|
+
const updateTheme = (k) => {
|
|
92
|
+
setTheme(k);
|
|
93
|
+
if (typeof window !== "undefined") {
|
|
94
|
+
localStorage.setItem(KEY, k);
|
|
95
|
+
document.documentElement.setAttribute("data-theme", k);
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
const updateLanguage = (t) => {
|
|
99
|
+
setLanguage(t);
|
|
100
|
+
if (typeof window !== "undefined") {
|
|
101
|
+
localStorage.setItem(LANG_KEY, t);
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
const value = (0, import_react.useMemo)(
|
|
105
|
+
() => ({ theme, language, updateTheme, updateLanguage }),
|
|
106
|
+
[theme, language]
|
|
107
|
+
);
|
|
108
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ThemeContext.Provider, { value, children });
|
|
109
|
+
}
|
|
110
|
+
var THEMES = THEME_LABEL;
|
|
111
|
+
|
|
112
|
+
// src/react/ThemeSwitcher.tsx
|
|
113
|
+
var import_react3 = require("react");
|
|
114
|
+
|
|
115
|
+
// src/icons/Logo.tsx
|
|
116
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
117
|
+
var SvgLogo = (props) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
118
|
+
"svg",
|
|
119
|
+
{
|
|
120
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
121
|
+
width: 39,
|
|
122
|
+
height: 40,
|
|
123
|
+
fill: "none",
|
|
124
|
+
...props,
|
|
125
|
+
children: [
|
|
126
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { fill: "#CE78A9", d: "m.5 17.805 1.516-3.514 16.812-7.924-1.309 3.308z" }),
|
|
127
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
128
|
+
"path",
|
|
129
|
+
{
|
|
130
|
+
fill: "#D55D00",
|
|
131
|
+
d: "M3.187 24.212 1.05 19.32l14.056-7.097-1.378 3.376-9.233 4.685 2.48 5.72z"
|
|
132
|
+
}
|
|
133
|
+
),
|
|
134
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
135
|
+
"path",
|
|
136
|
+
{
|
|
137
|
+
fill: "#E59F01",
|
|
138
|
+
d: "m22.276.741 3.496 1.556 7.732 16.901-3.292-1.347z"
|
|
139
|
+
}
|
|
140
|
+
),
|
|
141
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
142
|
+
"path",
|
|
143
|
+
{
|
|
144
|
+
fill: "#000",
|
|
145
|
+
d: "m15.837 3.355 4.916-2.08L27.69 15.41l-3.36-1.417-4.58-9.285-5.747 2.415z"
|
|
146
|
+
}
|
|
147
|
+
),
|
|
148
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
149
|
+
"path",
|
|
150
|
+
{
|
|
151
|
+
fill: "#0072B1",
|
|
152
|
+
d: "m17.036 39.246-3.493-1.562-7.699-16.917 3.29 1.354z"
|
|
153
|
+
}
|
|
154
|
+
),
|
|
155
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
156
|
+
"path",
|
|
157
|
+
{
|
|
158
|
+
fill: "#F0E442",
|
|
159
|
+
d: "m23.477 36.645-4.92 2.07-6.908-14.149 3.357 1.423 4.562 9.295 5.751-2.404z"
|
|
160
|
+
}
|
|
161
|
+
),
|
|
162
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
163
|
+
"path",
|
|
164
|
+
{
|
|
165
|
+
fill: "#009F73",
|
|
166
|
+
d: "m38.889 22.215-1.482 3.529-16.734 8.087 1.277-3.32z"
|
|
167
|
+
}
|
|
168
|
+
),
|
|
169
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
170
|
+
"path",
|
|
171
|
+
{
|
|
172
|
+
fill: "#56B4E8",
|
|
173
|
+
d: "m36.14 15.833 2.184 4.871-13.987 7.233 1.345-3.389 9.187-4.775-2.536-5.694z"
|
|
174
|
+
}
|
|
175
|
+
)
|
|
176
|
+
]
|
|
177
|
+
}
|
|
178
|
+
);
|
|
179
|
+
var Logo_default = SvgLogo;
|
|
180
|
+
|
|
181
|
+
// src/icons/Us.tsx
|
|
182
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
183
|
+
var SvgUs = (props) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
184
|
+
"svg",
|
|
185
|
+
{
|
|
186
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
187
|
+
width: 28,
|
|
188
|
+
height: 21,
|
|
189
|
+
fill: "none",
|
|
190
|
+
...props,
|
|
191
|
+
children: [
|
|
192
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("g", { clipPath: "url(#a)", filter: "url(#b)", children: [
|
|
193
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { fill: "#fff", d: "M3.996 4.166h20v13.333h-20z" }),
|
|
194
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
195
|
+
"path",
|
|
196
|
+
{
|
|
197
|
+
fill: "#D80027",
|
|
198
|
+
d: "M3.996 4.166h20v1.025h-20zm0 2.05h20v1.026h-20zm0 2.051h20v1.026h-20zm0 2.051h20v1.025h-20zm0 2.055h20v1.025h-20zm0 2.05h20v1.026h-20zm0 2.051h20v1.025h-20z"
|
|
199
|
+
}
|
|
200
|
+
),
|
|
201
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { fill: "#2E52B2", d: "M3.996 4.166h10v7.177h-10z" }),
|
|
202
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
203
|
+
"path",
|
|
204
|
+
{
|
|
205
|
+
fill: "#fff",
|
|
206
|
+
d: "m5.86 9.581-.156-.499-.172.5h-.514l.417.3-.156.498.425-.308.413.308-.16-.499.425-.3zm2.195 0-.16-.499-.164.5h-.515l.418.3-.156.498.417-.308.42.308-.155-.499.417-.3zm2.202 0-.167-.499-.156.5h-.527l.43.3-.164.498.417-.308.429.308-.164-.499.417-.3zm2.191 0-.156-.499-.163.5h-.519l.421.3-.156.498.417-.308.422.308-.168-.499.429-.3zm-4.553-2.48-.164.5h-.515l.418.308-.156.49.417-.303.42.304-.155-.491.417-.308h-.522zm-2.191 0-.172.5h-.514l.417.308-.156.49.425-.303.413.304-.16-.491.425-.308H5.86zm4.386 0-.156.5h-.527l.43.308-.164.49.417-.303.429.304-.164-.491.417-.308h-.515zm2.202 0-.163.5h-.519l.421.308-.156.49.417-.303.422.304-.168-.491.429-.308h-.527zM5.704 5.13l-.172.491h-.514l.417.308-.156.495.425-.308.413.308-.16-.495.425-.308H5.86zm2.19 0-.163.491h-.515l.418.308-.156.495.417-.308.42.308-.155-.495.417-.308h-.522zm2.196 0-.156.491h-.527l.43.308-.164.495.417-.308.429.308-.164-.495.417-.308h-.515zm2.202 0-.163.491h-.519l.421.308-.156.495.417-.308.422.308-.168-.495.429-.308h-.527z"
|
|
207
|
+
}
|
|
208
|
+
)
|
|
209
|
+
] }),
|
|
210
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("defs", { children: [
|
|
211
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("clipPath", { id: "a", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { fill: "#fff", d: "M3.996 4.166h20v13.333h-20z" }) }),
|
|
212
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
213
|
+
"filter",
|
|
214
|
+
{
|
|
215
|
+
id: "b",
|
|
216
|
+
width: 26.973,
|
|
217
|
+
height: 20.307,
|
|
218
|
+
x: 0.509,
|
|
219
|
+
y: 0.679,
|
|
220
|
+
colorInterpolationFilters: "sRGB",
|
|
221
|
+
filterUnits: "userSpaceOnUse",
|
|
222
|
+
children: [
|
|
223
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("feFlood", { floodOpacity: 0, result: "BackgroundImageFix" }),
|
|
224
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
225
|
+
"feColorMatrix",
|
|
226
|
+
{
|
|
227
|
+
in: "SourceAlpha",
|
|
228
|
+
result: "hardAlpha",
|
|
229
|
+
values: "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"
|
|
230
|
+
}
|
|
231
|
+
),
|
|
232
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("feOffset", {}),
|
|
233
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("feGaussianBlur", { stdDeviation: 1.743 }),
|
|
234
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("feComposite", { in2: "hardAlpha", operator: "out" }),
|
|
235
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("feColorMatrix", { values: "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0" }),
|
|
236
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
237
|
+
"feBlend",
|
|
238
|
+
{
|
|
239
|
+
in2: "BackgroundImageFix",
|
|
240
|
+
result: "effect1_dropShadow_306_3300"
|
|
241
|
+
}
|
|
242
|
+
),
|
|
243
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
244
|
+
"feBlend",
|
|
245
|
+
{
|
|
246
|
+
in: "SourceGraphic",
|
|
247
|
+
in2: "effect1_dropShadow_306_3300",
|
|
248
|
+
result: "shape"
|
|
249
|
+
}
|
|
250
|
+
)
|
|
251
|
+
]
|
|
252
|
+
}
|
|
253
|
+
)
|
|
254
|
+
] })
|
|
255
|
+
]
|
|
256
|
+
}
|
|
257
|
+
);
|
|
258
|
+
var Us_default = SvgUs;
|
|
259
|
+
|
|
260
|
+
// src/icons/Kr.tsx
|
|
261
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
262
|
+
var SvgKr = (props) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
263
|
+
"svg",
|
|
264
|
+
{
|
|
265
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
266
|
+
width: 24,
|
|
267
|
+
height: 17,
|
|
268
|
+
fill: "none",
|
|
269
|
+
...props,
|
|
270
|
+
children: [
|
|
271
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("g", { clipPath: "url(#a)", filter: "url(#b)", children: [
|
|
272
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { fill: "#fff", d: "M1.906 2h20v13.333h-20z" }),
|
|
273
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
274
|
+
"path",
|
|
275
|
+
{
|
|
276
|
+
fill: "#000",
|
|
277
|
+
fillRule: "evenodd",
|
|
278
|
+
d: "m4.959 6.04 1.849-2.774.487.324-1.85 2.773zm.693.461 1.85-2.773.486.324-1.85 2.774zm.694.463L8.195 4.19l.486.324-1.849 2.774zm8.782 5.855 1.85-2.774.486.325-1.849 2.773zm.694.462 1.849-2.774.486.325-1.849 2.773zm3.029-1.987L17 14.068l-.486-.325 1.85-2.773z",
|
|
279
|
+
clipRule: "evenodd"
|
|
280
|
+
}
|
|
281
|
+
),
|
|
282
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
283
|
+
"path",
|
|
284
|
+
{
|
|
285
|
+
fill: "#fff",
|
|
286
|
+
fillRule: "evenodd",
|
|
287
|
+
d: "m18.01 13.03-2.31-1.542.27-.405 2.31 1.54z",
|
|
288
|
+
clipRule: "evenodd"
|
|
289
|
+
}
|
|
290
|
+
),
|
|
291
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
292
|
+
"path",
|
|
293
|
+
{
|
|
294
|
+
fill: "#CA163A",
|
|
295
|
+
d: "M14.68 10.514a3.333 3.333 0 1 0-5.548-3.698 3.333 3.333 0 0 0 5.547 3.698"
|
|
296
|
+
}
|
|
297
|
+
),
|
|
298
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
299
|
+
"path",
|
|
300
|
+
{
|
|
301
|
+
fill: "#0E4896",
|
|
302
|
+
d: "M9.132 6.816a1.667 1.667 0 0 0 2.774 1.85 1.667 1.667 0 0 1 2.773 1.848 3.334 3.334 0 0 1-5.547-3.698"
|
|
303
|
+
}
|
|
304
|
+
),
|
|
305
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
306
|
+
"path",
|
|
307
|
+
{
|
|
308
|
+
fill: "#000",
|
|
309
|
+
fillRule: "evenodd",
|
|
310
|
+
d: "m17.002 3.266 1.849 2.773-.487.325-1.849-2.774zm-.694.462 1.85 2.773-.487.325-1.85-2.774zm-.693.462 1.85 2.774-.488.324-1.848-2.773zm-8.783 5.855 1.85 2.774-.487.324-1.85-2.773zm-.693.463 1.849 2.773-.487.324-1.849-2.773zm-.693.462 1.849 2.773-.487.325-1.849-2.774z",
|
|
311
|
+
clipRule: "evenodd"
|
|
312
|
+
}
|
|
313
|
+
),
|
|
314
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
315
|
+
"path",
|
|
316
|
+
{
|
|
317
|
+
fill: "#000",
|
|
318
|
+
d: "m6.475 12.286.693-.462zm9.36-6.24.81-.54zm1.502-1.002.694-.462z"
|
|
319
|
+
}
|
|
320
|
+
),
|
|
321
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
322
|
+
"path",
|
|
323
|
+
{
|
|
324
|
+
fill: "#fff",
|
|
325
|
+
fillRule: "evenodd",
|
|
326
|
+
d: "m18.166 4.784-.693.463-.27-.406.693-.462zm-1.386.925-.81.54-.27-.406.81-.54zm-9.476 6.317-.694.463-.27-.406.693-.462z",
|
|
327
|
+
clipRule: "evenodd"
|
|
328
|
+
}
|
|
329
|
+
)
|
|
330
|
+
] }),
|
|
331
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("defs", { children: [
|
|
332
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("clipPath", { id: "a", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { fill: "#fff", d: "M1.906 2h20v13.333h-20z" }) }),
|
|
333
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
334
|
+
"filter",
|
|
335
|
+
{
|
|
336
|
+
id: "b",
|
|
337
|
+
width: 22.602,
|
|
338
|
+
height: 15.936,
|
|
339
|
+
x: 0.605,
|
|
340
|
+
y: 0.699,
|
|
341
|
+
colorInterpolationFilters: "sRGB",
|
|
342
|
+
filterUnits: "userSpaceOnUse",
|
|
343
|
+
children: [
|
|
344
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("feFlood", { floodOpacity: 0, result: "BackgroundImageFix" }),
|
|
345
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
346
|
+
"feColorMatrix",
|
|
347
|
+
{
|
|
348
|
+
in: "SourceAlpha",
|
|
349
|
+
result: "hardAlpha",
|
|
350
|
+
values: "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"
|
|
351
|
+
}
|
|
352
|
+
),
|
|
353
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("feOffset", {}),
|
|
354
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("feGaussianBlur", { stdDeviation: 0.65 }),
|
|
355
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("feComposite", { in2: "hardAlpha", operator: "out" }),
|
|
356
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("feColorMatrix", { values: "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0" }),
|
|
357
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
358
|
+
"feBlend",
|
|
359
|
+
{
|
|
360
|
+
in2: "BackgroundImageFix",
|
|
361
|
+
result: "effect1_dropShadow_306_2477"
|
|
362
|
+
}
|
|
363
|
+
),
|
|
364
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
365
|
+
"feBlend",
|
|
366
|
+
{
|
|
367
|
+
in: "SourceGraphic",
|
|
368
|
+
in2: "effect1_dropShadow_306_2477",
|
|
369
|
+
result: "shape"
|
|
370
|
+
}
|
|
371
|
+
)
|
|
372
|
+
]
|
|
373
|
+
}
|
|
374
|
+
)
|
|
375
|
+
] })
|
|
376
|
+
]
|
|
377
|
+
}
|
|
378
|
+
);
|
|
379
|
+
var Kr_default = SvgKr;
|
|
380
|
+
|
|
381
|
+
// src/icons/X.tsx
|
|
382
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
383
|
+
var SvgX = (props) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
384
|
+
"svg",
|
|
385
|
+
{
|
|
386
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
387
|
+
width: 30,
|
|
388
|
+
height: 30,
|
|
389
|
+
fill: "none",
|
|
390
|
+
...props,
|
|
391
|
+
children: [
|
|
392
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
393
|
+
"path",
|
|
394
|
+
{
|
|
395
|
+
fill: "#000",
|
|
396
|
+
fillRule: "evenodd",
|
|
397
|
+
d: "M25.977 4.023a.94.94 0 0 1 0 1.328L5.352 25.976a.939.939 0 0 1-1.327-1.328L24.65 4.023a.94.94 0 0 1 1.327 0",
|
|
398
|
+
clipRule: "evenodd"
|
|
399
|
+
}
|
|
400
|
+
),
|
|
401
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
402
|
+
"path",
|
|
403
|
+
{
|
|
404
|
+
fill: "#000",
|
|
405
|
+
fillRule: "evenodd",
|
|
406
|
+
d: "M4.023 4.023a.94.94 0 0 0 0 1.328L24.65 25.976a.939.939 0 0 0 1.327-1.328L5.351 4.023a.94.94 0 0 0-1.328 0",
|
|
407
|
+
clipRule: "evenodd"
|
|
408
|
+
}
|
|
409
|
+
)
|
|
410
|
+
]
|
|
411
|
+
}
|
|
412
|
+
);
|
|
413
|
+
var X_default = SvgX;
|
|
414
|
+
|
|
415
|
+
// src/icons/theme/Tritanopia.tsx
|
|
416
|
+
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
417
|
+
var SvgTritanopia = (props) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
418
|
+
"svg",
|
|
419
|
+
{
|
|
420
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
421
|
+
fill: "none",
|
|
422
|
+
viewBox: "0 0 28 29",
|
|
423
|
+
...props,
|
|
424
|
+
children: [
|
|
425
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
426
|
+
"rect",
|
|
427
|
+
{
|
|
428
|
+
width: 26.18,
|
|
429
|
+
height: 26.18,
|
|
430
|
+
x: 0.91,
|
|
431
|
+
y: 1.41,
|
|
432
|
+
stroke: "currentColor",
|
|
433
|
+
strokeWidth: 1.82,
|
|
434
|
+
rx: 13.09
|
|
435
|
+
}
|
|
436
|
+
),
|
|
437
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
438
|
+
"path",
|
|
439
|
+
{
|
|
440
|
+
fill: "currentColor",
|
|
441
|
+
d: "M8.64 7.152h5.21q1.508 0 2.532.513 1.026.513 1.528 1.405.513.892.513 2.02 0 1.333-.667 2.081-.666.74-1.753 1.036v.144q.717.04 1.415.492.698.45 1.148 1.282.452.819.452 1.938 0 1.158-.534 2.04-.522.882-1.64 1.395-1.118.502-2.81.502H8.641zm5.374 13.207q1.65 0 2.43-.635.79-.636.79-1.682 0-.758-.39-1.395a2.63 2.63 0 0 0-1.097-1.015q-.709-.38-1.63-.38h-3.63v5.107zm-.226-6.706q.8 0 1.456-.307.657-.319 1.036-.892.38-.585.38-1.344 0-1.024-.708-1.671-.708-.646-2.102-.646h-3.364v4.86z"
|
|
442
|
+
}
|
|
443
|
+
),
|
|
444
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
445
|
+
"path",
|
|
446
|
+
{
|
|
447
|
+
stroke: "currentColor",
|
|
448
|
+
strokeWidth: 1.517,
|
|
449
|
+
d: "m3.5 1.666 23.333 23.333"
|
|
450
|
+
}
|
|
451
|
+
)
|
|
452
|
+
]
|
|
453
|
+
}
|
|
454
|
+
);
|
|
455
|
+
var Tritanopia_default = SvgTritanopia;
|
|
456
|
+
|
|
457
|
+
// src/icons/theme/Default.tsx
|
|
458
|
+
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
459
|
+
var SvgDefault = (props) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
460
|
+
"svg",
|
|
461
|
+
{
|
|
462
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
463
|
+
fill: "none",
|
|
464
|
+
viewBox: "0 0 31 31",
|
|
465
|
+
...props,
|
|
466
|
+
children: [
|
|
467
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
468
|
+
"path",
|
|
469
|
+
{
|
|
470
|
+
fill: "currentColor",
|
|
471
|
+
d: "M30.5 15.5s-5.625-10.312-15-10.312S.5 15.5.5 15.5s5.625 10.313 15 10.313 15-10.313 15-10.313m-27.801 0q.16-.245.365-.54c.628-.9 1.554-2.098 2.746-3.29 2.417-2.417 5.716-4.607 9.69-4.607s7.273 2.19 9.69 4.607A24.6 24.6 0 0 1 28.3 15.5q-.16.245-.365.54c-.628.9-1.554 2.098-2.746 3.29-2.417 2.417-5.716 4.608-9.69 4.608s-7.273-2.19-9.69-4.608A24.6 24.6 0 0 1 2.7 15.5"
|
|
472
|
+
}
|
|
473
|
+
),
|
|
474
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
475
|
+
"path",
|
|
476
|
+
{
|
|
477
|
+
fill: "currentColor",
|
|
478
|
+
d: "M15.5 10.813a4.688 4.688 0 1 0 0 9.375 4.688 4.688 0 0 0 0-9.375M8.938 15.5a6.562 6.562 0 1 1 13.124 0 6.562 6.562 0 0 1-13.125 0"
|
|
479
|
+
}
|
|
480
|
+
)
|
|
481
|
+
]
|
|
482
|
+
}
|
|
483
|
+
);
|
|
484
|
+
var Default_default = SvgDefault;
|
|
485
|
+
|
|
486
|
+
// src/icons/theme/Protanopia.tsx
|
|
487
|
+
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
488
|
+
var SvgProtanopia = (props) => /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
|
|
489
|
+
"svg",
|
|
490
|
+
{
|
|
491
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
492
|
+
fill: "none",
|
|
493
|
+
viewBox: "0 0 28 29",
|
|
494
|
+
...props,
|
|
495
|
+
children: [
|
|
496
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
497
|
+
"rect",
|
|
498
|
+
{
|
|
499
|
+
width: 26.18,
|
|
500
|
+
height: 26.18,
|
|
501
|
+
x: 0.91,
|
|
502
|
+
y: 1.41,
|
|
503
|
+
stroke: "currentColor",
|
|
504
|
+
strokeWidth: 1.82,
|
|
505
|
+
rx: 13.09
|
|
506
|
+
}
|
|
507
|
+
),
|
|
508
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
509
|
+
"path",
|
|
510
|
+
{
|
|
511
|
+
fill: "currentColor",
|
|
512
|
+
d: "M9.252 7.152h5.045q1.692 0 2.83.585 1.14.575 1.682 1.61.554 1.024.554 2.379 0 1.507-.697 2.594-.688 1.086-2.072 1.569L19.937 22h-2.153l-3.107-5.773-.36.01h-3.219V22H9.252zm4.984 7.404q1.711 0 2.502-.728.8-.729.8-2.102 0-1.395-.8-2.164t-2.523-.769h-3.117v5.763z"
|
|
513
|
+
}
|
|
514
|
+
),
|
|
515
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
516
|
+
"path",
|
|
517
|
+
{
|
|
518
|
+
stroke: "currentColor",
|
|
519
|
+
strokeWidth: 1.517,
|
|
520
|
+
d: "m3.5 1.666 23.333 23.333"
|
|
521
|
+
}
|
|
522
|
+
)
|
|
523
|
+
]
|
|
524
|
+
}
|
|
525
|
+
);
|
|
526
|
+
var Protanopia_default = SvgProtanopia;
|
|
527
|
+
|
|
528
|
+
// src/icons/theme/Deuteranopia.tsx
|
|
529
|
+
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
530
|
+
var SvgDeuteranopia = (props) => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
531
|
+
"svg",
|
|
532
|
+
{
|
|
533
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
534
|
+
fill: "none",
|
|
535
|
+
viewBox: "0 0 15 15",
|
|
536
|
+
...props,
|
|
537
|
+
children: [
|
|
538
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
539
|
+
"rect",
|
|
540
|
+
{
|
|
541
|
+
width: 13.09,
|
|
542
|
+
height: 13.09,
|
|
543
|
+
x: 1.08,
|
|
544
|
+
y: 0.955,
|
|
545
|
+
stroke: "currentColor",
|
|
546
|
+
strokeWidth: 0.91,
|
|
547
|
+
rx: 6.545
|
|
548
|
+
}
|
|
549
|
+
),
|
|
550
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
551
|
+
"path",
|
|
552
|
+
{
|
|
553
|
+
fill: "currentColor",
|
|
554
|
+
d: "M9.51 5.894q-.245-.734-.789-1.144-.538-.415-1.312-.415-.667 0-1.205.343-.534.345-.846 1.01-.308.667-.308 1.6t.313 1.6q.313.665.861 1.01.549.343 1.246.343.626 0 1.103-.261a1.87 1.87 0 0 0 .748-.754q.271-.492.282-1.138H7.665v-.81h2.84v.8q0 .907-.39 1.594-.389.687-1.081 1.061-.687.37-1.564.37-.984 0-1.738-.462-.748-.466-1.164-1.328-.41-.866-.41-2.025 0-1.153.41-2.015.416-.866 1.154-1.333.738-.465 1.687-.466.774 0 1.42.307.646.303 1.071.851.426.548.564 1.262z"
|
|
555
|
+
}
|
|
556
|
+
),
|
|
557
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
558
|
+
"path",
|
|
559
|
+
{
|
|
560
|
+
stroke: "currentColor",
|
|
561
|
+
strokeWidth: 0.758,
|
|
562
|
+
d: "m2.375 1.082 11.667 11.667"
|
|
563
|
+
}
|
|
564
|
+
)
|
|
565
|
+
]
|
|
566
|
+
}
|
|
567
|
+
);
|
|
568
|
+
var Deuteranopia_default = SvgDeuteranopia;
|
|
569
|
+
|
|
570
|
+
// src/react/ThemeSwitcherPortal.tsx
|
|
571
|
+
var import_react2 = require("react");
|
|
572
|
+
var import_react_dom = require("react-dom");
|
|
573
|
+
var PORTAL_ID = "theme-switcher-portal";
|
|
574
|
+
var portalEl = null;
|
|
575
|
+
var activeOwner = null;
|
|
576
|
+
function ensurePortal() {
|
|
577
|
+
if (typeof document === "undefined") throw new Error("No document");
|
|
578
|
+
if (portalEl && document.body.contains(portalEl)) return portalEl;
|
|
579
|
+
const existing = document.getElementById(PORTAL_ID);
|
|
580
|
+
portalEl = existing ?? Object.assign(document.createElement("div"), { id: PORTAL_ID });
|
|
581
|
+
if (!existing) document.body.appendChild(portalEl);
|
|
582
|
+
return portalEl;
|
|
583
|
+
}
|
|
584
|
+
function ThemeSwitcherPortal({
|
|
585
|
+
children
|
|
586
|
+
}) {
|
|
587
|
+
const [container, setContainer] = (0, import_react2.useState)(null);
|
|
588
|
+
const ownerId = (0, import_react2.useRef)(Symbol("ThemeSwitcherPortal"));
|
|
589
|
+
(0, import_react2.useEffect)(() => {
|
|
590
|
+
const el = ensurePortal();
|
|
591
|
+
setContainer(el);
|
|
592
|
+
if (activeOwner === null) activeOwner = ownerId.current;
|
|
593
|
+
return () => {
|
|
594
|
+
if (activeOwner === ownerId.current) {
|
|
595
|
+
activeOwner = null;
|
|
596
|
+
}
|
|
597
|
+
};
|
|
598
|
+
}, []);
|
|
599
|
+
if (!container) return null;
|
|
600
|
+
const isPrimary = activeOwner === ownerId.current;
|
|
601
|
+
return (0, import_react_dom.createPortal)(isPrimary ? children : null, container);
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
// src/react/ThemeSwitcher.tsx
|
|
605
|
+
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
606
|
+
var THEME_ICON = {
|
|
607
|
+
default: Default_default,
|
|
608
|
+
protanopia: Protanopia_default,
|
|
609
|
+
deuteranopia: Deuteranopia_default,
|
|
610
|
+
tritanopia: Tritanopia_default
|
|
611
|
+
};
|
|
612
|
+
function ThemeSwitcher({ options }) {
|
|
613
|
+
const { theme, updateTheme, language, updateLanguage } = useTheme();
|
|
614
|
+
const [hovered, setHovered] = (0, import_react3.useState)(null);
|
|
615
|
+
const list = (0, import_react3.useMemo)(
|
|
616
|
+
() => options?.length ? options : getThemeOptions(language),
|
|
617
|
+
[options, language]
|
|
618
|
+
);
|
|
619
|
+
const [isOpen, setIsOpen] = (0, import_react3.useState)(false);
|
|
620
|
+
const wrapperRef = (0, import_react3.useRef)(null);
|
|
621
|
+
(0, import_react3.useEffect)(() => {
|
|
622
|
+
const handleClickOutside = (event) => {
|
|
623
|
+
if (wrapperRef.current && !wrapperRef.current.contains(event.target)) {
|
|
624
|
+
setIsOpen(false);
|
|
625
|
+
}
|
|
626
|
+
};
|
|
627
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
628
|
+
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
629
|
+
}, []);
|
|
630
|
+
const toggle = (e) => {
|
|
631
|
+
e.stopPropagation();
|
|
632
|
+
setIsOpen((prev) => !prev);
|
|
633
|
+
};
|
|
634
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ThemeSwitcherPortal, { children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { ref: wrapperRef, className: "z-[10000]", children: [
|
|
635
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
636
|
+
"button",
|
|
637
|
+
{
|
|
638
|
+
type: "button",
|
|
639
|
+
"aria-haspopup": "menu",
|
|
640
|
+
"aria-expanded": isOpen,
|
|
641
|
+
onClick: toggle,
|
|
642
|
+
className: "fixed right-[25px] bottom-[25px] w-[60px] h-[60px] p-[10px] bg-[#ffffff] rounded-full flex justify-center items-center shadow-[0_0_3px_0_rgba(0,0,0,0.17)]",
|
|
643
|
+
children: isOpen ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(X_default, { className: "self-center" }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Logo_default, { className: "self-center" })
|
|
644
|
+
}
|
|
645
|
+
),
|
|
646
|
+
isOpen && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
647
|
+
"div",
|
|
648
|
+
{
|
|
649
|
+
role: "menu",
|
|
650
|
+
"aria-label": "Select theme",
|
|
651
|
+
className: "fixed bottom-[100px] right-[25px] flex-col bg-[#ffffff] rounded-[18px] w-[220px] gap-[11px]",
|
|
652
|
+
children: [
|
|
653
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { children: list.map((opt) => {
|
|
654
|
+
const Icon = THEME_ICON[opt.key];
|
|
655
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { children: [
|
|
656
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
657
|
+
"button",
|
|
658
|
+
{
|
|
659
|
+
type: "button",
|
|
660
|
+
role: "menuitemradio",
|
|
661
|
+
"aria-checked": theme === opt.key,
|
|
662
|
+
onClick: (e) => {
|
|
663
|
+
e.stopPropagation();
|
|
664
|
+
updateTheme(opt.key);
|
|
665
|
+
},
|
|
666
|
+
onMouseEnter: () => setHovered(opt.key),
|
|
667
|
+
onMouseLeave: () => setHovered(null),
|
|
668
|
+
className: [
|
|
669
|
+
"hover:cursor-pointer group text-[18px] text-[#3D4852] py-1 w-full h-[50px] text-center gap-[8px] flex items-center justify-center rounded-[18px] hover:bg-[#3D4852]",
|
|
670
|
+
theme === opt.key ? "bg-[#3D4852] text-[#ffffff]" : ""
|
|
671
|
+
].join(" "),
|
|
672
|
+
children: [
|
|
673
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
674
|
+
Icon,
|
|
675
|
+
{
|
|
676
|
+
width: 24,
|
|
677
|
+
height: 24,
|
|
678
|
+
className: `inline-block ${theme === opt.key || hovered === opt.key ? "text-white" : "text-[#3D4852]"}`
|
|
679
|
+
}
|
|
680
|
+
),
|
|
681
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "group-hover:text-[#ffffff]", children: opt.label })
|
|
682
|
+
]
|
|
683
|
+
},
|
|
684
|
+
opt.key
|
|
685
|
+
),
|
|
686
|
+
opt.key !== "tritanopia" && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "border-b-[0.5px] border-b-[#D9D9D9] w-full" })
|
|
687
|
+
] }, opt.key);
|
|
688
|
+
}) }),
|
|
689
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "w-full border-[0.5px] border-[#B8B8B8]" }),
|
|
690
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "flex justify-evenly items-center gap-[10px] px-[10px] my-[15px]", children: language === "English" ? /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
691
|
+
"div",
|
|
692
|
+
{
|
|
693
|
+
className: `hover:cursor-pointer flex text-[18px] text-[#3D4852] gap-[8px] items-center justify-center`,
|
|
694
|
+
onClick: () => updateLanguage("Korean"),
|
|
695
|
+
children: [
|
|
696
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Us_default, {}),
|
|
697
|
+
"English"
|
|
698
|
+
]
|
|
699
|
+
}
|
|
700
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
701
|
+
"div",
|
|
702
|
+
{
|
|
703
|
+
className: `hover:cursor-pointer flex text-[18px] text-[#3D4852] gap-[8px] items-center justify-center `,
|
|
704
|
+
onClick: () => updateLanguage("English"),
|
|
705
|
+
children: [
|
|
706
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Kr_default, {}),
|
|
707
|
+
"Korean"
|
|
708
|
+
]
|
|
709
|
+
}
|
|
710
|
+
) })
|
|
711
|
+
]
|
|
712
|
+
}
|
|
713
|
+
)
|
|
714
|
+
] }) });
|
|
715
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { ReactNode } from 'react';
|
|
3
|
+
|
|
4
|
+
type TLanguage = 'English' | 'Korean';
|
|
5
|
+
declare const THEME_KEYS: readonly ["default", "protanopia", "deuteranopia", "tritanopia"];
|
|
6
|
+
type ThemeKey = (typeof THEME_KEYS)[number];
|
|
7
|
+
type ThemeContextType = {
|
|
8
|
+
theme: ThemeKey;
|
|
9
|
+
language: TLanguage;
|
|
10
|
+
updateTheme: (k: ThemeKey) => void;
|
|
11
|
+
updateLanguage: (t: TLanguage) => void;
|
|
12
|
+
};
|
|
13
|
+
declare const useTheme: () => ThemeContextType;
|
|
14
|
+
type ThemeProviderProps = {
|
|
15
|
+
children: ReactNode;
|
|
16
|
+
};
|
|
17
|
+
declare function ThemeProvider({ children }: ThemeProviderProps): react_jsx_runtime.JSX.Element;
|
|
18
|
+
type ThemeType = ThemeKey;
|
|
19
|
+
declare const THEMES: Record<TLanguage, Record<"default" | "protanopia" | "deuteranopia" | "tritanopia", string>>;
|
|
20
|
+
|
|
21
|
+
type Props = {
|
|
22
|
+
options?: {
|
|
23
|
+
key: ThemeKey;
|
|
24
|
+
label: string;
|
|
25
|
+
}[];
|
|
26
|
+
};
|
|
27
|
+
declare function ThemeSwitcher({ options }: Props): react_jsx_runtime.JSX.Element;
|
|
28
|
+
|
|
29
|
+
export { THEMES, type TLanguage, ThemeProvider, ThemeSwitcher, type ThemeType, useTheme };
|
package/dist/client.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { ReactNode } from 'react';
|
|
2
3
|
|
|
3
4
|
type TLanguage = 'English' | 'Korean';
|
|
4
5
|
declare const THEME_KEYS: readonly ["default", "protanopia", "deuteranopia", "tritanopia"];
|
|
@@ -10,9 +11,10 @@ type ThemeContextType = {
|
|
|
10
11
|
updateLanguage: (t: TLanguage) => void;
|
|
11
12
|
};
|
|
12
13
|
declare const useTheme: () => ThemeContextType;
|
|
13
|
-
|
|
14
|
-
children:
|
|
15
|
-
}
|
|
14
|
+
type ThemeProviderProps = {
|
|
15
|
+
children: ReactNode;
|
|
16
|
+
};
|
|
17
|
+
declare function ThemeProvider({ children }: ThemeProviderProps): react_jsx_runtime.JSX.Element;
|
|
16
18
|
type ThemeType = ThemeKey;
|
|
17
19
|
declare const THEMES: Record<TLanguage, Record<"default" | "protanopia" | "deuteranopia" | "tritanopia", string>>;
|
|
18
20
|
|
|
@@ -21,8 +23,7 @@ type Props = {
|
|
|
21
23
|
key: ThemeKey;
|
|
22
24
|
label: string;
|
|
23
25
|
}[];
|
|
24
|
-
className?: string;
|
|
25
26
|
};
|
|
26
|
-
declare function ThemeSwitcher({ options
|
|
27
|
+
declare function ThemeSwitcher({ options }: Props): react_jsx_runtime.JSX.Element;
|
|
27
28
|
|
|
28
29
|
export { THEMES, type TLanguage, ThemeProvider, ThemeSwitcher, type ThemeType, useTheme };
|
package/dist/client.js
CHANGED
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
// src/
|
|
4
|
-
import {
|
|
3
|
+
// src/react/ThemeProvider.tsx
|
|
4
|
+
import {
|
|
5
|
+
createContext,
|
|
6
|
+
useContext,
|
|
7
|
+
useEffect,
|
|
8
|
+
useMemo,
|
|
9
|
+
useState
|
|
10
|
+
} from "react";
|
|
5
11
|
import { jsx } from "react/jsx-runtime";
|
|
6
12
|
var THEME_KEYS = [
|
|
7
13
|
"default",
|
|
@@ -81,7 +87,7 @@ function ThemeProvider({ children }) {
|
|
|
81
87
|
}
|
|
82
88
|
var THEMES = THEME_LABEL;
|
|
83
89
|
|
|
84
|
-
// src/
|
|
90
|
+
// src/react/ThemeSwitcher.tsx
|
|
85
91
|
import { useEffect as useEffect3, useRef as useRef2, useState as useState3, useMemo as useMemo2 } from "react";
|
|
86
92
|
|
|
87
93
|
// src/icons/Logo.tsx
|
|
@@ -539,7 +545,7 @@ var SvgDeuteranopia = (props) => /* @__PURE__ */ jsxs8(
|
|
|
539
545
|
);
|
|
540
546
|
var Deuteranopia_default = SvgDeuteranopia;
|
|
541
547
|
|
|
542
|
-
// src/
|
|
548
|
+
// src/react/ThemeSwitcherPortal.tsx
|
|
543
549
|
import { useEffect as useEffect2, useRef, useState as useState2 } from "react";
|
|
544
550
|
import { createPortal } from "react-dom";
|
|
545
551
|
var PORTAL_ID = "theme-switcher-portal";
|
|
@@ -573,7 +579,7 @@ function ThemeSwitcherPortal({
|
|
|
573
579
|
return createPortal(isPrimary ? children : null, container);
|
|
574
580
|
}
|
|
575
581
|
|
|
576
|
-
// src/
|
|
582
|
+
// src/react/ThemeSwitcher.tsx
|
|
577
583
|
import { jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
578
584
|
var THEME_ICON = {
|
|
579
585
|
default: Default_default,
|
|
@@ -581,7 +587,7 @@ var THEME_ICON = {
|
|
|
581
587
|
deuteranopia: Deuteranopia_default,
|
|
582
588
|
tritanopia: Tritanopia_default
|
|
583
589
|
};
|
|
584
|
-
function ThemeSwitcher({ options
|
|
590
|
+
function ThemeSwitcher({ options }) {
|
|
585
591
|
const { theme, updateTheme, language, updateLanguage } = useTheme();
|
|
586
592
|
const [hovered, setHovered] = useState3(null);
|
|
587
593
|
const list = useMemo2(
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "colbrush",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "A React theme switching library that makes it easy to apply color-blind accessible UI themes",
|
|
5
5
|
"homepage": "https://colbrush.vercel.app",
|
|
6
6
|
"repository": {
|
|
@@ -75,6 +75,7 @@
|
|
|
75
75
|
"svgr": "svgr src/assets --out-dir src/icons --typescript --expand-props end --svgo-config svgo.config.js",
|
|
76
76
|
"build:css": "tailwindcss -i ./src/styles.css -o ./dist/styles.css --minify",
|
|
77
77
|
"build": "pnpm svgr && tsup --config tsup.config.ts && pnpm build:css",
|
|
78
|
-
"dev": "tsup --config tsup.config.ts --watch"
|
|
78
|
+
"dev": "tsup --config tsup.config.ts --watch",
|
|
79
|
+
"lint": "eslint ."
|
|
79
80
|
}
|
|
80
81
|
}
|