@@ -0,0 +1,55 @@
|
||||
import { readFile, writeFile } from "node:fs/promises";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import path from "node:path";
|
||||
|
||||
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
||||
const tokenPath = path.join(root, "src/lib/tokens.json");
|
||||
const outputPath = path.join(root, "src/styles/theme.generated.css");
|
||||
const source = JSON.parse(await readFile(tokenPath, "utf8"));
|
||||
|
||||
const variableName = (key) =>
|
||||
`--${key
|
||||
.replace(/([a-z0-9])([A-Z])/g, "$1-$2")
|
||||
.replace(/([a-zA-Z])([0-9])/g, "$1-$2")
|
||||
.toLowerCase()}`;
|
||||
|
||||
function hexToHsl(hex) {
|
||||
const value = hex.replace("#", "");
|
||||
const [r, g, b] = [0, 2, 4].map((offset) => parseInt(value.slice(offset, offset + 2), 16) / 255);
|
||||
const max = Math.max(r, g, b);
|
||||
const min = Math.min(r, g, b);
|
||||
const lightness = (max + min) / 2;
|
||||
let hue = 0;
|
||||
let saturation = 0;
|
||||
|
||||
if (max !== min) {
|
||||
const delta = max - min;
|
||||
saturation = lightness > 0.5 ? delta / (2 - max - min) : delta / (max + min);
|
||||
if (max === r) hue = (g - b) / delta + (g < b ? 6 : 0);
|
||||
if (max === g) hue = (b - r) / delta + 2;
|
||||
if (max === b) hue = (r - g) / delta + 4;
|
||||
hue /= 6;
|
||||
}
|
||||
|
||||
return `${Math.round(hue * 360)} ${Math.round(saturation * 100)}% ${Math.round(lightness * 100)}%`;
|
||||
}
|
||||
|
||||
function block(selector, colors) {
|
||||
const variables = Object.entries(colors)
|
||||
.map(([name, value]) => ` ${variableName(name)}: ${hexToHsl(value)};`)
|
||||
.join("\n");
|
||||
return `${selector} {\n${variables}\n}`;
|
||||
}
|
||||
|
||||
const generated = `/* Generated by scripts/generate-theme.mjs from src/lib/tokens.json. */\n${block(":root, .dark", source.color.dark)}\n\n${block(".light", source.color.light)}\n`;
|
||||
const check = process.argv.includes("--check");
|
||||
|
||||
if (check) {
|
||||
const current = await readFile(outputPath, "utf8").catch(() => "");
|
||||
if (current !== generated) {
|
||||
console.error("Generated theme is stale. Run npm run tokens:generate.");
|
||||
process.exit(1);
|
||||
}
|
||||
} else {
|
||||
await writeFile(outputPath, generated);
|
||||
}
|
||||
Reference in New Issue
Block a user