sitegen/framework/css.ts
chloe caruso af60d1172f i accidentally deleted the repo, but recovered it. i'll start committing
it was weird. i pressed delete on a subfolder, i think one of the
pages.off folders that i was using. and then, suddenly, nvim on windows
7 decided to delete every file in the directory. they weren't shred off
the space time continuum, but just marked deleted. i had to pay $80 to
get access to a software that could see them. bleh!

just seeing all my work, a little over a week, was pretty heart
shattering. but i remembered that long ago, a close friend said i could
call them whenever i was feeling sad. i finally took them up on that
offer. the first time i've ever called someone for emotional support.
but it's ok. i got it back. and the site framework is better than ever.

i'm gonna commit and push more often. the repo is private anyways.
2025-06-06 23:38:02 -07:00

87 lines
2.2 KiB
TypeScript

export interface Theme {
bg: string;
fg: string;
primary?: string;
h1?: string;
}
export function stringifyTheme(theme: Theme) {
return [
":root {",
"--bg: " + theme.bg + ";",
"--fg: " + theme.fg + ";",
theme.primary ? "--primary: " + theme.primary + ";" : null,
"}",
theme.h1 ? "h1 { color: " + theme.h1 + "}" : null,
].filter(Boolean).join("\n");
}
export function preprocess(css: string, theme: Theme): string {
const keys = Object.keys(theme);
const regex = new RegExp(
`([{};\\n][^{};\\n]*var\\(--(${keys.join("|")})\\).*?(?=[;{}\\n]))`,
"gs",
);
const regex2 = new RegExp(`var\\(--(${keys.join("|")})\\)`);
return css.replace(
regex,
(_, line) =>
line.replace(regex2, (_: string, varName: string) => theme[varName]) +
";" + line.slice(1),
);
}
export async function bundleCssFiles(
cssImports: string[],
theme: Theme,
dev: boolean = false,
): Promise<string> {
const plugin = {
name: "clover",
setup(b) {
b.onResolve(
{ filter: /^\$input\$$/ },
() => ({ path: ".", namespace: "input" }),
);
b.onLoad(
{ filter: /./, namespace: "input" },
() => ({
loader: "css",
contents:
cssImports.map((path) => `@import url(${JSON.stringify(path)});`)
.join("\n") + stringifyTheme(theme),
resolveDir: ".",
}),
);
b.onLoad(
{ filter: /\.css$/ },
async ({ path: file }) => ({
loader: "css",
contents: preprocess(await fs.readFile(file, "utf-8"), theme),
}),
);
},
} satisfies Plugin;
const build = await esbuild.build({
bundle: true,
entryPoints: ["$input$"],
write: false,
external: ["*.woff2"],
target: ["ie11"],
plugins: [plugin],
minify: !dev,
});
const { errors, warnings, outputFiles } = build;
if (errors.length > 0) {
throw new AggregateError(errors, "CSS Build Failed");
}
if (warnings.length > 0) {
throw new AggregateError(warnings, "CSS Build Failed");
}
if (outputFiles.length > 1) throw new Error("Too many output files");
return outputFiles[0].text;
}
import type { Plugin } from "esbuild";
import * as esbuild from "esbuild";
import * as fs from "./fs.ts";