stylebot-harmony/scripts/build-theme.tsx
2023-08-03 20:09:32 -04:00

111 lines
3.7 KiB
JavaScript
Executable File

#!/usr/bin/env -S node -r esbin
import { promises as fs } from "fs"
import { resolve } from "path"
import sass from "sass"
import { kebabCase } from "lodash"
import { tokenSource } from "~/shared/theme/tokens"
const trim = (s: string) => s.trim()
const [, outdir] = process.argv.slice(2)
// This file is used to `make theme`.
namespace primer {
// https://github.com/primer/github-vscode-theme/commit/5f08d0cc4de8abc33e13c3f63fe92288824a11cf
// prettier-ignore
const classic = {
black: "#1b1f23",
white: "#fff",
gray: ["#fafbfc", "#f6f8fa", "#e1e4e8", "#d1d5da", "#959da5", "#6a737d", "#586069", "#444d56", "#2f363d", "#24292e"],
blue: ["#f1f8ff", "#dbedff", "#c8e1ff", "#79b8ff", "#2188ff", "#0366d6", "#005cc5", "#044289", "#032f62", "#05264c"],
green: ["#f0fff4", "#dcffe4", "#bef5cb", "#85e89d", "#34d058", "#28a745", "#22863a", "#176f2c", "#165c26", "#144620"],
yellow: ["#fffdef", "#fffbdd", "#fff5b1", "#ffea7f", "#ffdf5d", "#ffd33d", "#f9c513", "#dbab09", "#b08800", "#735c0f"],
orange: ["#fff8f2", "#ffebda", "#ffd1ac", "#ffab70", "#fb8532", "#f66a0a", "#e36209", "#d15704", "#c24e00", "#a04100"],
red: ["#ffeef0", "#ffdce0", "#fdaeb7", "#f97583", "#ea4a5a", "#d73a49", "#cb2431", "#b31d28", "#9e1c23", "#86181d"],
purple: ["#f5f0ff", "#e6dcfd", "#d1bcf9", "#b392f0", "#8a63d2", "#6f42c1", "#5a32a3", "#4c2889", "#3a1d6e", "#29134e"],
pink: ["#ffeef8", "#fedbf0", "#f9b3dd", "#f692ce", "#ec6cb9", "#ea4aaa", "#d03592", "#b93a86", "#99306f", "#6d224f"]
};
function addClassic(css: string, dark: boolean) {
const r = (name: string, value?: string) =>
(css = css.replace(
RegExp(/(--color-NAME: )([^;]+);/.source.replace("NAME", name)),
(_, name, originalValue) => `${name}${value ?? originalValue};`,
))
r("canvas-default", dark ? "#1f2428" : undefined)
return css
}
function sassCompile(code: string) {
return sass.compileString(code, {
loadPaths: [resolve(__dirname, "../node_modules")],
style: "compressed",
}).css
}
export async function main() {
const outputDir = resolve(__dirname, "../dist/vendor/primer")
await fs.mkdir(outputDir, { recursive: true })
const themes = {
dark: "dark-default",
dark_colorblind: undefined,
dark_dimmed: undefined,
dark_high_contrast: undefined,
dark_tritanopia: undefined,
light: "light-default",
light_colorblind: undefined,
light_high_contrast: undefined,
light_tritanopia: undefined,
}
const toRoot = (name: string, themeName = name) =>
sassCompile(/* scss */ `
@use "@primer/primitives/dist/scss/colors/_${name}.scss" as *;
:root[data-theme="github-${themeName}"] {
@include primer-colors-${name};
}
`)
await Promise.all([
...Object.entries(themes).map(([source, name = source]) =>
fs.writeFile(resolve(outputDir, `github-${name}.css`), toRoot(source, name)),
),
fs.writeFile(
resolve(outputDir, "github-dark.css"),
addClassic(toRoot("dark"), true),
),
fs.writeFile(
resolve(outputDir, "github-light.css"),
addClassic(toRoot("light"), false),
),
])
}
}
async function tokens() {
const declarations = Object.entries(tokenSource).map(([name, value]) => {
const [light, dark] = value.trim().split(",").map(trim)
return { name, light, dark }
})
await fs.writeFile(
resolve(outdir, "tokens.generated.css"),
[
"body{",
...declarations.map(({ name, light }) => `--${kebabCase(name)}:${light};`),
"}",
"body.dark{",
...declarations.map(({ name, dark }) => `--${kebabCase(name)}:${dark};`),
"}",
].join(""),
)
}
async function main() {
await tokens()
await primer.main()
}
main()