diff --git a/packages/theme/lib/tokens/color.js b/packages/theme/lib/tokens/color.js deleted file mode 100644 index c28ef6ddb1..0000000000 --- a/packages/theme/lib/tokens/color.js +++ /dev/null @@ -1,56 +0,0 @@ -/** - * @file Color tokens — semantic surface, text, state, and brand colors. - * - * Light values are declared via `variable()`. Dark values are declared inside - * the `dark` theme block so they emit under `html[data-theme="dark"]`. - * - * Link tokens are wired through `ref()` so brand overrides to `color.primary` - * cascade to links without separate overrides. The dark theme intentionally - * re-points links to their own oklab values rather than chaining through - * primary because dark mode links need higher luminance than primary buttons. - * - * `warning` and `danger` deliberately stay on light values in dark mode — state - * colors keep consistent intensity across themes so warnings read as urgent. - */ - -import { ref, theme, variable } from "../shared.js"; - -export const colorAccent = variable("color.accent", "#fd4b2d"); -export const colorPrimary = variable("color.primary", "oklab(0.522 -0.0434 -0.1717)"); -export const colorPrimaryHover = variable("color.primary-hover", "oklab(0.3763 -0.0324 -0.1182)"); -export const colorText = variable("color.text", "oklab(0.1957 -0 0)"); -export const colorTextMuted = variable("color.text-muted", "oklab(0.5364 -0.0026 -0.0089)"); - -export const colorLink = variable("color.link", ref(colorPrimary)); -export const colorLinkHover = variable("color.link-hover", ref(colorPrimaryHover)); -export const colorLinkVisited = variable("color.link-visited", "oklab(0.3679 0.0535 -0.1797)"); - -export const colorSurface = variable("color.surface", "oklab(1 -0 0)"); -export const colorSurfaceMuted = variable("color.surface-muted", "oklab(0.9551 -0 0)"); -export const colorSurfaceRaised = variable("color.surface-raised", "oklab(0.9851 -0 0)"); - -export const colorBorder = variable("color.border", "#d2d2d2"); -export const colorBorderStrong = variable("color.border-strong", "#8a8d90"); - -export const colorInfo = variable("color.info", "oklab(0.6689 -0.0608 -0.1513)"); -export const colorSuccess = variable("color.success", "oklab(0.5549 -0.1071 0.0852)"); -export const colorWarning = variable("color.warning", "oklab(0.7864 0.0298 0.1604)"); -export const colorDanger = variable("color.danger", "oklab(0.5331 0.1798 0.1034)"); - -// Dark theme overrides. Surface values are pinned near PatternFly 4's -// BackgroundColor--100 (#151515) and the legacy drawer surface (#18191a) — the -// earlier oklab(0.23) value visibly brightened every PF-backed dark panel. -theme("dark", (ctx) => { - ctx.variable(colorText, "oklab(0.9067 -0 0)"); - ctx.variable(colorTextMuted, "oklab(0.7407 -0.0007 -0.0017)"); - ctx.variable(colorLink, "oklab(70.367% -0.07498 -0.139)"); - ctx.variable(colorLinkHover, "oklab(0.7706 -0.0485 -0.1012)"); - ctx.variable(colorLinkVisited, "oklab(0.7137 0.0522 -0.151)"); - ctx.variable(colorSurface, "oklab(0.183 -0 0)"); - ctx.variable(colorSurfaceMuted, "oklab(0.14 -0 0)"); - ctx.variable(colorSurfaceRaised, "oklab(0.225 -0 0)"); - ctx.variable(colorBorder, "oklab(0.3906 0.0001 -0.0052)"); - ctx.variable(colorBorderStrong, "oklab(0.4602 -0.0003 -0.0034)"); - ctx.variable(colorInfo, "oklab(0.7706 -0.0485 -0.1012)"); - ctx.variable(colorSuccess, "oklab(0.6488 -0.1066 0.0846)"); -}); diff --git a/packages/theme/package-lock.json b/packages/theme/package-lock.json index 964f81a723..af0e29dacf 100644 --- a/packages/theme/package-lock.json +++ b/packages/theme/package-lock.json @@ -21,7 +21,10 @@ "@goauthentik/prettier-config": "../prettier-config", "@goauthentik/tsconfig": "../tsconfig", "@styleframe/cli": "^4.0.0", + "@types/culori": "^4.0.1", "@types/node": "^25.7.0", + "@typescript/native-preview": "^7.0.0-dev.20260616.1", + "culori": "^4.0.2", "eslint": "^9.39.3", "pino": "^10.3.1", "pino-pretty": "^13.1.2", @@ -638,6 +641,13 @@ "@styleframe/license": "^2.0.2" } }, + "node_modules/@types/culori": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@types/culori/-/culori-4.0.1.tgz", + "integrity": "sha512-43M51r/22CjhbOXyGT361GZ9vncSVQ39u62x5eJdBQFviI8zWp2X5jzqg7k4M6PVgDQAClpy2bUe2dtwEgEDVQ==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/estree": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", @@ -944,6 +954,147 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/@typescript/native-preview": { + "version": "7.0.0-dev.20260616.1", + "resolved": "https://registry.npmjs.org/@typescript/native-preview/-/native-preview-7.0.0-dev.20260616.1.tgz", + "integrity": "sha512-+AuZUl7nkLPXL1rwsyZZF7iasu0HkrL5O6aWwUC0cObD5EvNgxz3hXbBhsSvuJ8tb2JRpVwFsE0BHPcYVe5GkA==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsgo": "bin/tsgo.js" + }, + "engines": { + "node": ">=16.20.0" + }, + "optionalDependencies": { + "@typescript/native-preview-darwin-arm64": "7.0.0-dev.20260616.1", + "@typescript/native-preview-darwin-x64": "7.0.0-dev.20260616.1", + "@typescript/native-preview-linux-arm": "7.0.0-dev.20260616.1", + "@typescript/native-preview-linux-arm64": "7.0.0-dev.20260616.1", + "@typescript/native-preview-linux-x64": "7.0.0-dev.20260616.1", + "@typescript/native-preview-win32-arm64": "7.0.0-dev.20260616.1", + "@typescript/native-preview-win32-x64": "7.0.0-dev.20260616.1" + } + }, + "node_modules/@typescript/native-preview-darwin-arm64": { + "version": "7.0.0-dev.20260616.1", + "resolved": "https://registry.npmjs.org/@typescript/native-preview-darwin-arm64/-/native-preview-darwin-arm64-7.0.0-dev.20260616.1.tgz", + "integrity": "sha512-9SwegwwE7fYutnZJjTi2PeUXhKGFg82MGjSpCFD2cj5v9YQcs5oO5QsmeeMit4fMG8Z83Jy8knOF97d9NaQ7Bg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/native-preview-darwin-x64": { + "version": "7.0.0-dev.20260616.1", + "resolved": "https://registry.npmjs.org/@typescript/native-preview-darwin-x64/-/native-preview-darwin-x64-7.0.0-dev.20260616.1.tgz", + "integrity": "sha512-gl7R8OiwEBNxzs5wjbM9XOibTs5b6/gAgu0+En9pLpYuWR/EITs8Eh0mNQui4JYTp1SkoHvn09aRZKTQf21XTg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/native-preview-linux-arm": { + "version": "7.0.0-dev.20260616.1", + "resolved": "https://registry.npmjs.org/@typescript/native-preview-linux-arm/-/native-preview-linux-arm-7.0.0-dev.20260616.1.tgz", + "integrity": "sha512-QWXQS2CrhSpXbng7vBtCVDszFgwVBuJU8MCFhxZL0hH6s+XjQDSNNkGO1oHueBr+7HbSkkyqfNYVNXvgVMUJLQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/native-preview-linux-arm64": { + "version": "7.0.0-dev.20260616.1", + "resolved": "https://registry.npmjs.org/@typescript/native-preview-linux-arm64/-/native-preview-linux-arm64-7.0.0-dev.20260616.1.tgz", + "integrity": "sha512-CJjplWoE+EeYtbyNeP4fyuh0QcPiQBZJSLqPS07E3ugo3d9M/IG8WnL+3GFQ0g1p4c6QC/+OC0oTTQnGcNdd2Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/native-preview-linux-x64": { + "version": "7.0.0-dev.20260616.1", + "resolved": "https://registry.npmjs.org/@typescript/native-preview-linux-x64/-/native-preview-linux-x64-7.0.0-dev.20260616.1.tgz", + "integrity": "sha512-UVySBNnGTAnul2kO2/EhlVZl0CeTDcd6Lzi+WkvgyCgapTcU0BX1selQ4MEPtbVWKUbt9HBhxNku2dyaCcmKVw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/native-preview-win32-arm64": { + "version": "7.0.0-dev.20260616.1", + "resolved": "https://registry.npmjs.org/@typescript/native-preview-win32-arm64/-/native-preview-win32-arm64-7.0.0-dev.20260616.1.tgz", + "integrity": "sha512-kdX0QcDXiESH0o5DFdSWw15Hth0EtQobT9tX28ofqBUwGU1FFhwTKzA6qo7chaYUSW5MMd6XIME9rBwk+WizLw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/native-preview-win32-x64": { + "version": "7.0.0-dev.20260616.1", + "resolved": "https://registry.npmjs.org/@typescript/native-preview-win32-x64/-/native-preview-win32-x64-7.0.0-dev.20260616.1.tgz", + "integrity": "sha512-EB0Pj/0+nXifS3+wN0HdR1mKu7IieSpjMXoDjdXtJAdiPGlmKazBgHj97qn6CBvXisgLx0Eyb7tLCEQNDG53cA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=16.20.0" + } + }, "node_modules/acorn": { "version": "8.16.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", diff --git a/packages/theme/package.json b/packages/theme/package.json index b94300a79c..8062dd67b6 100644 --- a/packages/theme/package.json +++ b/packages/theme/package.json @@ -55,11 +55,14 @@ }, "devDependencies": { "@eslint/js": "^9.39.3", - "@goauthentik/prettier-config": "../prettier-config", "@goauthentik/eslint-config": "../eslint-config", + "@goauthentik/prettier-config": "../prettier-config", "@goauthentik/tsconfig": "../tsconfig", "@styleframe/cli": "^4.0.0", + "@types/culori": "^4.0.1", "@types/node": "^25.7.0", + "@typescript/native-preview": "^7.0.0-dev.20260616.1", + "culori": "^4.0.2", "eslint": "^9.39.3", "pino": "^10.3.1", "pino-pretty": "^13.1.2", diff --git a/packages/theme/scripts/build.mjs b/packages/theme/scripts/build.mjs deleted file mode 100644 index ac50a82e88..0000000000 --- a/packages/theme/scripts/build.mjs +++ /dev/null @@ -1,212 +0,0 @@ -/** - * @file Build script for `@goauthentik/theme`. - * - * Runs the styleframe transpiler against the configured token tree, then - * fans out the single emitted CSS string into one file per category - * (color, typography, spacing, shape, shadow, motion, z-index) and a top- - * level `index.css` that `@import`s them in deterministic order. - * - * Consumers can import the whole surface - * (`@import "@goauthentik/theme/index.css"`) or cherry-pick a category - * (`@import "@goauthentik/theme/color.css"`). - * - * Invoked by `npm run build:assets` and chained from `npm run build`. - */ - -import { mkdir, writeFile } from "node:fs/promises"; -import { dirname, resolve } from "node:path"; -import { fileURLToPath } from "node:url"; - -import { build } from "../lib/node.js"; - -const __dirname = dirname(fileURLToPath(import.meta.url)); -const PACKAGE_ROOT = resolve(__dirname, ".."); -const OUT_DIR = resolve(PACKAGE_ROOT, "dist"); - -/** - * @typedef {object} Category - * @property {string} name Slug used for the output filename. - * @property {string[]} prefixes - * Token-name prefixes (after the `--ak-` strip) that belong to this category. - */ - -/** @type {Category[]} */ -const CATEGORIES = [ - { name: "color", prefixes: ["color-"] }, - { - name: "typography", - prefixes: ["font-family-", "font-size-", "font-weight-", "line-height-"], - }, - { name: "spacing", prefixes: ["space-"] }, - { name: "shape", prefixes: ["radius-", "border-width-"] }, - { name: "shadow", prefixes: ["shadow-"] }, - { name: "motion", prefixes: ["duration-", "easing-"] }, - { name: "z-index", prefixes: ["z-index-"] }, -]; - -const HEADER = [ - "/*", - " * ⚠️ GENERATED FILE — do not edit directly.", - " *", - " * Source: packages/theme/lib/tokens/*.js", - " * Built: packages/theme/scripts/build.mjs", - " */", - "", -].join("\n"); - -/** - * One emitted block within the styleframe CSS output. `header` is the line - * that opens the block (`:root {`, `@media (...) {`, `html[data-theme="..."] {`). - * `prefix` is whitespace that should precede declarations inside the block, - * preserved verbatim from the source. `closer` is the closing brace(s). - * - * @typedef {object} ParsedBlock - * @property {string} header - * @property {string[]} declarations - * @property {string} closer - */ - -/** - * Split the styleframe CSS output into top-level blocks. Each block is one of: - * - * :root { … } - * html[data-theme="…"] { … } - * @media (…) { :root { … } } - * - * Nested `:root` inside `@media` is preserved as part of the block — the - * inner declarations are kept as a flat list and re-wrapped on emit. - * - * @param {string} css - * @returns {ParsedBlock[]} - */ -function parseBlocks(css) { - /** @type {ParsedBlock[]} */ - const blocks = []; - - // Top-level blocks separated by blank lines in styleframe's output. - // Each block ends with a balanced closing brace at column zero. We don't - // need a real CSS parser — the styleframe emitter is regular enough that - // a small line-based state machine handles it. - const lines = css.split("\n"); - let i = 0; - - while (i < lines.length) { - while (i < lines.length && (lines[i] ?? "").trim() === "") i++; - if (i >= lines.length) break; - - const opener = lines[i] ?? ""; - const header = opener.trim(); - if (!header.endsWith("{")) { - i++; - continue; - } - - const openerIndent = opener.match(/^\s*/)?.[0] ?? ""; - i++; - /** @type {string[]} */ - const innerLines = []; - while (i < lines.length) { - const line = lines[i] ?? ""; - const trimmed = line.trim(); - const indent = line.match(/^\s*/)?.[0] ?? ""; - if (trimmed === "}" && indent === openerIndent) { - i++; - break; - } - innerLines.push(line); - i++; - } - - blocks.push({ - header, - declarations: innerLines, - closer: "}", - }); - } - - return blocks; -} - -/** - * Extract every `--ak-*: …;` declaration from a flat list of lines (which may - * include a nested `:root { … }` wrapper from an `@media` block). - * - * @param {string[]} lines - * @returns {string[]} - */ -function flattenDeclarations(lines) { - return lines.filter((line) => /^\s*--ak-[a-z0-9-]+\s*:/.test(line)); -} - -/** - * Build the CSS for one category by filtering each parsed block to that - * category's declarations and re-wrapping them. - * - * @param {Category} category - * @param {ParsedBlock[]} blocks - */ -function buildCategoryFile(category, blocks) { - /** @param {string} line */ - const matches = (line) => { - const declaration = line.match(/--ak-([a-z0-9-]+):/); - if (!declaration || !declaration[1]) return false; - const name = declaration[1]; - return category.prefixes.some((prefix) => name.startsWith(prefix)); - }; - - /** @type {string[]} */ - const sections = []; - - for (const block of blocks) { - if (block.header.startsWith("@media")) { - // Drill into the inner `:root { … }` wrapper. - const inner = flattenDeclarations(block.declarations).filter(matches); - if (inner.length === 0) continue; - sections.push( - `${block.header}\n\t:root {\n${inner - .map((line) => "\t\t" + line.trim()) - .join("\n")}\n\t}\n}`, - ); - continue; - } - - const filtered = block.declarations.filter(matches); - if (filtered.length === 0) continue; - sections.push( - `${block.header}\n${filtered.map((line) => "\t" + line.trim()).join("\n")}\n}`, - ); - } - - if (sections.length === 0) return null; - return HEADER + sections.join("\n\n") + "\n"; -} - -/** - * Build the index.css that `@import`s every emitted category file in order. - * - * @param {string[]} emittedNames - */ -function buildIndex(emittedNames) { - const imports = emittedNames.map((name) => `@import "./${name}.css";`).join("\n"); - return HEADER + imports + "\n"; -} - -await mkdir(OUT_DIR, { recursive: true }); - -const { css } = await build(); -const blocks = parseBlocks(css); - -const emitted = []; -for (const category of CATEGORIES) { - const content = buildCategoryFile(category, blocks); - if (content === null) { - console.warn(`⚠️ No declarations found for category ${category.name}; skipping.`); - continue; - } - await writeFile(resolve(OUT_DIR, `${category.name}.css`), content, "utf-8"); - emitted.push(category.name); -} - -await writeFile(resolve(OUT_DIR, "index.css"), buildIndex(emitted), "utf-8"); - -console.log(`✅ Wrote dist/index.css + ${emitted.length} category files (${emitted.join(", ")})`); diff --git a/packages/theme/index.js b/packages/theme/src/index.ts similarity index 77% rename from packages/theme/index.js rename to packages/theme/src/index.ts index ed99681683..ff0a055b22 100644 --- a/packages/theme/index.js +++ b/packages/theme/src/index.ts @@ -9,5 +9,5 @@ * filesystem live in `./lib/node.js` (exposed via the `./build` subpath). */ -export { instance, ref, selector, theme, variable } from "./lib/shared.js"; -export * from "./lib/tokens/index.js"; +export { instance, ref, selector, theme, variable } from "./shared.js"; +export * from "./tokens/index.js"; diff --git a/packages/theme/lib/node.js b/packages/theme/src/node.ts similarity index 87% rename from packages/theme/lib/node.js rename to packages/theme/src/node.ts index f22884f787..3168715467 100644 --- a/packages/theme/lib/node.js +++ b/packages/theme/src/node.ts @@ -1,4 +1,4 @@ -/** +/* * @file Node-only build helpers for `@goauthentik/theme`. * * Re-exports everything the browser entry exports, plus filesystem-touching @@ -7,7 +7,8 @@ * @import { OutputFile } from "@styleframe/transpiler"; */ -/// + +import type { OutputFile } from "@styleframe/transpiler"; import { writeFile } from "node:fs/promises"; @@ -28,6 +29,10 @@ export * from "./tokens/index.js"; * this absolute path in addition to being returned. */ +interface BuildOptions { + outFile?: string; +} + /** * @typedef {object} BuildResult * @property {string} css The full CSS string emitted by styleframe. @@ -35,6 +40,11 @@ export * from "./tokens/index.js"; * to inspect every file styleframe produced. */ +interface BuildResult { + css: string; + files: OutputFile[]; +} + /** * Transpile the configured token tree to CSS. * @@ -44,7 +54,7 @@ export * from "./tokens/index.js"; * @param {BuildOptions} [options] * @returns {Promise} */ -export async function build(options = {}) { +export async function build(options: BuildOptions = {}): Promise { const output = await transpile(instance, { type: "css" }); const cssFile = output.files.find((file) => file.name.endsWith(".css")); const css = cssFile?.content ?? ""; diff --git a/packages/theme/lib/shared.js b/packages/theme/src/shared.ts similarity index 89% rename from packages/theme/lib/shared.js rename to packages/theme/src/shared.ts index 6c80be7d59..cadf95fa2f 100644 --- a/packages/theme/lib/shared.js +++ b/packages/theme/src/shared.ts @@ -25,11 +25,12 @@ import { styleframe } from "styleframe"; * @type {StyleframeOptions} */ export const authentikStyleframeOptions = { + indent: " ", variables: { - name: ({ name }) => "ak-" + name.replace(/\./g, "-"), + name: ({ name }: { name: string }) => `ak-${name.replace(/\./g, "-")}` }, themes: { - selector: ({ name }) => `html[data-theme="${name}"]`, + selector: ({ name }: { name: string}) => `html[data-theme="${name}"]`, }, }; diff --git a/packages/theme/src/tokens/color.ts b/packages/theme/src/tokens/color.ts new file mode 100644 index 0000000000..73fc198b9c --- /dev/null +++ b/packages/theme/src/tokens/color.ts @@ -0,0 +1,106 @@ +/** + * @file Color tokens — semantic surface, text, state, and brand colors. + * + * Light values are declared via `variable()`. Dark values are declared inside + * the `dark` theme block so they emit under `html[data-theme="dark"]`. + * + * Link tokens are wired through `ref()` so brand overrides to `color.primary` + * cascade to links without separate overrides. The dark theme intentionally + * re-points links to their own oklab values rather than chaining through + * primary because dark mode links need higher luminance than primary buttons. + * + * `warning` and `danger` deliberately stay on light values in dark mode — state + * colors keep consistent intensity across themes so warnings read as urgent. + */ + +import { instance, theme } from "../shared.js"; + +import { createVariableFunction } from "styleframe"; +import { createUseVariable } from "@styleframe/theme"; +import { formatHex, oklch as toOklch, toGamut } from "culori"; + +/* + * Restrict the OKLCH values to six decimal places; Javascript will give it to you accurate to 16 + * places, but OKLCH doesn't much care past six, and 16 is just unreadable. + * + * Includes in each OKLCH output line a comment containing the RGB value, to help IDEs show the + * color accurately. + */ + + +const toSrgb = toGamut("rgb", "oklch"); +const round = (v: number, precision = 6) => Number(v.toFixed(precision)).toString(); +const oklchTransform = (value: string) => { + const c = toOklch(value); + if (!c || c.l == null || c.c == null) { + return value; + } + + const result = `oklch(${round(c.l)} ${round(c.c)} ${round(c.h ?? 0)} / ${round(c.alpha ?? 1)})`; + return `${result} /* ${formatHex(toSrgb(c))} */`; +}; +const useColorDesignTokens = createUseVariable("color", { transform: oklchTransform }); + +export const { + colorAccent, + colorPrimary, + colorPrimaryHover, + colorText, + colorTextMuted, + colorLink, + colorLinkHover, + colorLinkVisited, + colorSurface, + colorSurfaceRaised, + colorSurfaceMuted, + colorBorder, + colorBorderStrong, + colorInfo, + colorSuccess, + colorWarning, + colorDanger, +} = useColorDesignTokens(instance, { + "accent": "#fd4b2d", + "primary": "#0066cc", + "primary-hover": "#004080", + "text": "#151515", + "text-muted": "#6a6e73", + "link": "@color.primary", + "link-hover": "@color.primary-hover", + "link-visited": "#40199a", + "surface": "#ffffff", + "surface-raised": "#fafafa", + "surface-muted": "#f0f0f0", + "border": "#d2d2d2", + "border-strong": "#8a8d90", + "info": "#2b9af3", + "success": "#3e8635", + "warning": "#f0ab00", + "danger": "#c9190b", +}); + +type Variable = ReturnType>; +type VPPair = [Variable, string]; + +// Dark theme overrides. Surface values are pinned near PatternFly 4's +// BackgroundColor--100 (#151515) and the legacy drawer surface (#18191a) — the +// earlier oklab(0.23) value visibly brightened every PF-backed dark panel. +theme("dark", (ctx) => { + + const darkColors: VPPair[] = [ + [colorText, "#e0e0e0"], + [colorTextMuted, "#aaabac"], + [colorLink, "#20a9f8"], + [colorLinkHover, "#73bcf7"], + [colorLinkVisited, "#a18fff"], + [colorSurface, "#121212"], + [colorSurfaceMuted, "#090909"], + [colorSurfaceRaised, "#1c1c1c"], + [colorBorder, "#444548"], + [colorBorderStrong, "#57585a"], + [colorInfo, "#73bcf7"], + [colorSuccess, "#5ba352"] + ]; + + darkColors.forEach(([v, p]) => ctx.variable(v, oklchTransform(p))); +}); diff --git a/packages/theme/lib/tokens/index.js b/packages/theme/src/tokens/index.ts similarity index 100% rename from packages/theme/lib/tokens/index.js rename to packages/theme/src/tokens/index.ts diff --git a/packages/theme/lib/tokens/motion.js b/packages/theme/src/tokens/motion.ts similarity index 100% rename from packages/theme/lib/tokens/motion.js rename to packages/theme/src/tokens/motion.ts diff --git a/packages/theme/lib/tokens/shadow.js b/packages/theme/src/tokens/shadow.ts similarity index 100% rename from packages/theme/lib/tokens/shadow.js rename to packages/theme/src/tokens/shadow.ts diff --git a/packages/theme/lib/tokens/shape.js b/packages/theme/src/tokens/shape.ts similarity index 100% rename from packages/theme/lib/tokens/shape.js rename to packages/theme/src/tokens/shape.ts diff --git a/packages/theme/lib/tokens/spacing.js b/packages/theme/src/tokens/spacing.ts similarity index 100% rename from packages/theme/lib/tokens/spacing.js rename to packages/theme/src/tokens/spacing.ts diff --git a/packages/theme/lib/tokens/typography.js b/packages/theme/src/tokens/typography.ts similarity index 100% rename from packages/theme/lib/tokens/typography.js rename to packages/theme/src/tokens/typography.ts diff --git a/packages/theme/lib/tokens/z-index.js b/packages/theme/src/tokens/z-index.ts similarity index 100% rename from packages/theme/lib/tokens/z-index.js rename to packages/theme/src/tokens/z-index.ts diff --git a/packages/theme/styleframe.config.mjs b/packages/theme/styleframe.config.ts similarity index 88% rename from packages/theme/styleframe.config.mjs rename to packages/theme/styleframe.config.ts index 568da47c0c..2a9664d16f 100644 --- a/packages/theme/styleframe.config.mjs +++ b/packages/theme/styleframe.config.ts @@ -11,8 +11,8 @@ * the same tree the rest of the package uses. */ -import "./lib/tokens/index.js"; +import "./src/tokens/index.js"; -import { instance } from "./lib/shared.js"; +import { instance } from "./src/shared.js"; export default instance; diff --git a/packages/theme/types/node.d.ts b/packages/theme/types/node.d.ts deleted file mode 100644 index c118164b66..0000000000 --- a/packages/theme/types/node.d.ts +++ /dev/null @@ -1,27 +0,0 @@ -declare module "process" { - import { Level } from "pino"; - - global { - namespace NodeJS { - interface ProcessEnv { - /** - * An environment variable used to determine - * whether Node.js is running in production mode. - * - * @see {@link https://nodejs.org/en/learn/getting-started/nodejs-the-difference-between-development-and-production | The difference between development and production} - */ - readonly NODE_ENV?: "development" | "production"; - - /** - * Whether or not we are running on a CI server. - */ - readonly CI?: string; - - /** - * The application log level. - */ - readonly AK_LOG_LEVEL?: Level; - } - } - } -}