update 2026-09-26 11:07:27

This commit is contained in:
action committed 2026-09-26 11:07:27 +08:00
1 parent 7b88b273d0
commit 97ae9f68da
4898 files changed
-1712274

No files matched your search

@@ -1,40 +0,0 @@
/**
* Copyright (C) 2025 eamonxg <eamonxiong@gmail.com>
* Licensed under the Apache License, Version 2.0.
*/
import { readFile } from "node:fs/promises";
import { resolve } from "node:path";
const outputDir = resolve(
import.meta.dirname,
"../../htdocs/luci-static/shadcn",
);
const files = ["main.css", "login.css"];
const forbidden = [
{
label: "token-based color-mix()",
pattern: /color-mix\([^)]*var\(--/g,
},
{
label: "relative oklch()",
pattern: /oklch\(from/g,
},
];
const failures = [];
for (const file of files) {
const css = await readFile(resolve(outputDir, file), "utf8");
for (const { label, pattern } of forbidden) {
const count = css.match(pattern)?.length ?? 0;
if (count > 0) failures.push(`${file}: ${label} × ${count}`);
}
}
if (failures.length > 0) {
console.error(`Runtime token color functions found:\n${failures.join("\n")}`);
process.exitCode = 1;
} else {
console.log("Built CSS contains no runtime token color functions.");
}
@@ -1,41 +0,0 @@
/**
* Copyright (C) 2025 eamonxg <eamonxiong@gmail.com>
* Licensed under the Apache License, Version 2.0.
*/
import Color from "colorjs.io";
import { resolveMode } from "../tokens/resolve.js";
const MIN_TEXT_CONTRAST = 4.5;
const checks = [
["muted_foreground", "background"],
["sidebar_muted", "sidebar_bg"],
];
const failures = [];
for (const mode of ["light", "dark"]) {
const tokens = resolveMode(mode);
for (const [foreground, background] of checks) {
const ratio = Color.contrast(
new Color(tokens[background]),
new Color(tokens[foreground]),
"WCAG21",
);
if (ratio < MIN_TEXT_CONTRAST) {
failures.push(
`${mode}: ${foreground} on ${background} is ${ratio.toFixed(2)}:1`,
);
}
}
}
if (failures.length > 0) {
console.error(
`Text token contrast must be at least ${MIN_TEXT_CONTRAST}:1:\n${failures.join("\n")}`,
);
process.exitCode = 1;
} else {
console.log("Text token contrast meets WCAG AA.");
}
@@ -1,98 +0,0 @@
/**
* Copyright (C) 2025 eamonxg <eamonxiong@gmail.com>
* Licensed under the Apache License, Version 2.0.
*/
import { writeFile } from "node:fs/promises";
import { resolve } from "node:path";
import { alpha, toOklch } from "@eamonxg/luci-theme-tokens/engine";
import { block, themeColors } from "@eamonxg/luci-theme-tokens/emit";
import { resolveMode } from "../tokens/resolve.js";
import { ALPHAS } from "../tokens/spec.js";
const snake = (s) => s.replace(/-/g, "_");
const withAlpha = (oklchStr, pct) => toOklch(alpha(oklchStr, pct / 100));
function alphaTokens(resolved) {
const out = {};
for (const [base, list] of Object.entries(ALPHAS)) {
const val = resolved[snake(base)];
if (val === undefined) throw new Error(`ALPHAS base not resolved: ${base}`);
for (const a of list) out[`${base}-a${a}`] = withAlpha(val, a);
}
return out;
}
const light = resolveMode("light");
const dark = resolveMode("dark");
const lightA = alphaTokens(light);
const darkA = alphaTokens(dark);
const STRUCTURE = `
--font-sans: "Inter Variable", ui-sans-serif, system-ui, sans-serif;
--font-mono: ui-monospace, "SF Mono", Menlo, Monaco, Consolas, monospace;
--radius-base: 0.5rem;
/* Elevation. Emitted on :root (not just inlined into the shadow-* utilities)
so on-demand patches/*.css -- standalone entries that carry no Tailwind
helper output -- can reach it as var(--shadow-sm). */
--shadow-sm:
0 1px 3px 0 oklch(0% 0 0 / 0.1), 0 1px 2px -1px oklch(0% 0 0 / 0.1);
`;
const themeColorsCss = themeColors([
...Object.keys(light),
...Object.keys(lightA),
]);
// Add aliases for backward compatibility
const aliases = [
` --color-sidebar-fg: var(--sidebar-foreground);`,
` --color-terminal-fg: var(--terminal-foreground);`,
].join("\n");
const THEME = `@theme inline {
${themeColorsCss}
${aliases}
--font-sans: var(--font-sans);
--font-mono: var(--font-mono);
--shadow-sm: var(--shadow-sm);
/* Radius ladder driven by a single knob; at 0.5rem it matches the
Tailwind default scale (rounded-lg = 0.5rem). Tune --radius-base
to scale all corners for custom-radius support. */
--radius-sm: calc(var(--radius-base) * 0.5);
--radius: calc(var(--radius-base) * 0.5);
--radius-md: calc(var(--radius-base) * 0.75);
--radius-lg: var(--radius-base);
--radius-xl: calc(var(--radius-base) * 1.5);
}
`;
const HEADER = `/**
* luci-theme-shadcn: design tokens -- GENERATED, DO NOT EDIT.
* Run \`pnpm gen:tokens\`. Source: tokens/defaults.js + tokens/spec.js
* All color values are flat oklch() literals; no dynamic color functions.
* Dark mode overrides must stay after light mode block.
*/
`;
const css =
HEADER +
"\n" +
block(":root", light, lightA) +
STRUCTURE +
"}\n\n" +
block('[data-darkmode="true"]', dark, darkA) +
"}\n\n" +
THEME;
await writeFile(
resolve(import.meta.dirname, "../src/media/_tokens.css"),
css,
"utf-8",
);
console.log("gen-tokens: wrote src/media/_tokens.css");