UNPKG

alouette

Version:

A modern, customizable design system built on top of NativeWind v5 with configurable defaults

119 lines (104 loc) 4.19 kB
/* eslint-disable import-x/extensions */ // Build-script driver: turn palette params into the two files an app imports. // Node-only — call it from a script, never from app code. import { mkdirSync, writeFileSync } from "node:fs"; import { join } from "node:path"; import type { GenerateThemeResult } from "./generateTheme.ts"; import { generateTheme } from "./generateTheme.ts"; import type { AccentName, PaletteSpec } from "./paletteSpecs.ts"; const generatedHeader = "/* Generated by alouette writeTheme. DO NOT EDIT. */"; // Emitted the way a formatter would leave it — unquoted theme keys (hence the // camelcase disable in the file header) and trailing commas — so a generated // file never churns the first time the app runs prettier/oxfmt over it. const serializeThemeVariables = ( themeVariables: GenerateThemeResult["themeVariables"], ): string => `{\n${Object.entries(themeVariables) .map(([theme, variables]) => { const entries = Object.entries(variables) .map(([name, value]) => ` "${name}": "${value}",`) .join("\n"); return ` ${theme}: {\n${entries}\n },`; }) .join("\n")}\n}`; const themeVariablesModule = ( themeVariables: GenerateThemeResult["themeVariables"], ): string => `${generatedHeader} /* eslint-disable camelcase */ import type { ThemeVariablesMap } from "alouette"; /** * Resolved CSS-variable maps for every theme, paired with the generated palette * CSS. Pass to \`<AlouetteProvider themeVariables={...}>\`. */ export const themeVariables: ThemeVariablesMap = ${serializeThemeVariables(themeVariables)}; `; export interface WriteThemeParams { /** Directory the files are written to, created if missing. */ outDir: string; /** * Per-accent params merged over the alouette defaults, so only the accents * the app re-colors need to be listed. Omit to reproduce the default palette. */ overrides?: Partial<Record<AccentName, PaletteSpec>>; /** * Skip the `oklch()` overlay entirely and ship sRGB hex on every platform. * @default false */ srgbOnly?: boolean; cssFileName?: string; themeVariablesFileName?: string; } export interface WriteThemeResult { cssPath: string; /** * The wide-gamut overlay, named after `cssFileName` (`palette-oklch.css`). * `undefined` when `srgbOnly` is set. */ oklchCssPath: string | undefined; themeVariablesPath: string; } /** * Generate an app's palette and write it to disk: the palette CSS to import * after `alouette/core.css`, and the `themeVariables` module to pass to * `<AlouetteProvider themeVariables={...}>`. Writing them from one call is what * keeps the className tokens and the JS token reads on the same colors. * * - `palette.css` (hex, complete on its own) + `palette-oklch.css`, imported * after it only if the app wants display-p3 chroma on web. * - `themeVariables.ts` in sRGB hex, the only format native can parse. The map * feeds native token reads only — web resolves every token from the CSS — so * there is no oklch counterpart. */ export const writeTheme = ({ outDir, overrides, srgbOnly = false, cssFileName = "palette.css", themeVariablesFileName = "themeVariables.ts", }: WriteThemeParams): WriteThemeResult => { const { css, oklchCss, themeVariables } = generateTheme(overrides); mkdirSync(outDir, { recursive: true }); const cssPath = join(outDir, cssFileName); writeFileSync( cssPath, `${generatedHeader} /* App palette. Import after "alouette/core.css", instead of "alouette/global.css" — which carries alouette's default palette. */ ${css}`, ); const themeVariablesPath = join(outDir, themeVariablesFileName); writeFileSync(themeVariablesPath, themeVariablesModule(themeVariables)); if (srgbOnly) { return { cssPath, oklchCssPath: undefined, themeVariablesPath }; } const oklchCssPath = join(outDir, cssFileName.replace(/\.css$/, "-oklch$&")); writeFileSync( oklchCssPath, `${generatedHeader} /* Wide-gamut half of the app palette. Optional — import after "${cssFileName}" to opt web into the display-p3 ramp. */ ${oklchCss}`, ); return { cssPath, oklchCssPath, themeVariablesPath }; };