@theemo/build
Version:
Theme Builder
226 lines (218 loc) • 6.97 kB
JavaScript
//#region rolldown:runtime
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
key = keys[i];
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
get: ((k) => from[k]).bind(null, key),
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
});
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
value: mod,
enumerable: true
}) : target, mod));
//#endregion
const node_fs = __toESM(require("node:fs"));
const node_path = __toESM(require("node:path"));
const lightningcss = __toESM(require("lightningcss"));
const read_pkg = __toESM(require("read-pkg"));
const write_package = __toESM(require("write-package"));
//#region ../theme/dist/index.js
/**
* Color Contrasts
*
* @see https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-contrast
*/
const ColorContrast = {
NoPreference: "no-preference",
More: "more",
Less: "less",
Custom: "custom"
};
/**
* Color Scheme
*
* @see https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme
*/
const ColorScheme = {
Light: "light",
Dark: "dark"
};
/**
* Motion
*
* @see https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-reduced-motion
*/
const Motion = {
NoPreference: "no-preference",
Reduce: "reduce"
};
const BrowserMechanic = {
ColorScheme: "color-scheme",
ColorContrast: "color-contrast",
Motion: "motion"
};
/**
* Checks wether the given feature uses mode behavior
*
* @param feature the feature in question
* @returns `true` for a mode behavior, otherwise `false`
*/
function isModalFeature(feature) {
return feature.defaultOption !== void 0;
}
const queries = {
[BrowserMechanic.ColorScheme]: {
[ColorScheme.Dark]: "(prefers-color-scheme: dark)",
[ColorScheme.Light]: "(prefers-color-scheme: light)"
},
[BrowserMechanic.ColorContrast]: {
[ColorContrast.NoPreference]: "(prefers-color-contrast: no-preference)",
[ColorContrast.More]: "(prefers-color-contrast: more)",
[ColorContrast.Less]: "(prefers-color-contrast: less)",
[ColorContrast.Custom]: "(prefers-color-contrast: custom)"
},
[BrowserMechanic.Motion]: {
[Motion.NoPreference]: "(prefers-reduced-motion: no-preference)",
[Motion.Reduce]: "(prefers-reduced-motion)"
}
};
//#endregion
//#region src/config.ts
const DEFAULT_CONFIG = {
outDir: "dist",
features: [],
lightningcss: true
};
function configWithDefaults(config) {
return {
...DEFAULT_CONFIG,
...config
};
}
//#endregion
//#region src/features.ts
function isModalBuildFeature(feature) {
return isModalFeature(feature);
}
function isColorSchemeFeature(feature) {
return feature.browserFeature === BrowserMechanic.ColorScheme;
}
function isMediaQueryFeature(feature) {
return feature.browserFeature === BrowserMechanic.ColorContrast || feature.browserFeature === BrowserMechanic.Motion;
}
//#endregion
//#region src/build.ts
const MEDIA_QUERY = {
[BrowserMechanic.ColorScheme]: "prefers-color-scheme",
[BrowserMechanic.ColorContrast]: "prefers-contrast",
[BrowserMechanic.Motion]: "prefers-reduced-motion"
};
function readFile(file) {
const contents = node_fs.default.existsSync(file) ? node_fs.default.readFileSync(file, "utf-8") : "";
return contents;
}
function combineFiles(config) {
const contents = [];
for (const file of config.files ?? []) contents.push(readFile(file).trim());
return contents;
}
function buildColorSchemeFeature(feature) {
return `
:root {
color-scheme: ${feature.options.join(" ")};
}
[data-theemo-color-scheme="light"] {
color-scheme: light;
}
[data-theemo-color-scheme="dark"] {
color-scheme: dark;
}
`.trim();
}
function buildFeature(feature) {
const contents = [];
for (const [option, file] of Object.entries(feature.options)) {
const fileContents = readFile(file);
const selectors = option === feature.defaultOption ? [":root"] : [];
selectors.push(`[data-theemo-${feature.name}="${option}"]`);
const css = fileContents.replace(":root", selectors.join(", ")).trim();
contents.push(css);
}
return contents;
}
function buildMediaQueryBrowserFeature(feature) {
const contents = [];
const mediaQuery = MEDIA_QUERY[feature.browserFeature];
for (const [option, file] of Object.entries(feature.options)) {
const fileContents = readFile(file);
const css = `@media (${mediaQuery}: ${option}) {
${fileContents}
}`;
contents.push(css);
}
return contents;
}
function buildFeatures(config) {
const contents = [];
for (const feature of config.features) {
if (isColorSchemeFeature(feature)) contents.push(buildColorSchemeFeature(feature));
else if (isModalBuildFeature(feature)) contents.push(...buildFeature(feature));
if (isMediaQueryFeature(feature)) contents.push(...buildMediaQueryBrowserFeature(feature));
}
return contents;
}
function getThemeName() {
const data = (0, read_pkg.readPackageSync)();
return data.theemo?.name ?? data.name;
}
function buildFiles(config) {
const name = getThemeName();
const contents = [...combineFiles(config), ...buildFeatures(config)];
if (!node_fs.default.existsSync(config.outDir)) node_fs.default.mkdirSync(config.outDir);
const outFile = node_path.default.join(config.outDir, `${name}.css`);
const css = contents.join("\n\n");
node_fs.default.writeFileSync(outFile, css);
if (config.lightningcss !== false) {
const options = typeof config.lightningcss === "object" ? config.lightningcss : {};
const { code } = (0, lightningcss.transform)({
code: Buffer.from(css),
filename: outFile,
...options
});
node_fs.default.writeFileSync(outFile, code);
}
}
function updatePackage(config) {
const packageJson = (0, read_pkg.readPackageSync)({ normalize: false });
const theemo = packageJson.theemo;
theemo.file = node_path.default.join(config.outDir, `${theemo.name}.css`);
theemo.features = config.features.map((f) => ({
...f,
options: Array.isArray(f.options) ? f.options : Object.keys(f.options)
}));
if (!Array.isArray(packageJson.keywords)) packageJson.keywords = [];
if (!packageJson.keywords.includes("theemo-theme")) packageJson.keywords.push("theemo-theme");
(0, write_package.writePackageSync)(packageJson);
}
/**
* Build a theme, which can be managed by theemo
*
* @param config The configuration for the theme and its behavior
*/
function build(config) {
const defaultConfig = configWithDefaults(config);
buildFiles(defaultConfig);
updatePackage(defaultConfig);
}
//#endregion
exports.build = build;
//# sourceMappingURL=index.cjs.map