@ogasphere/theme-manager
Version:
A reusable theme management package for Next.js and Vite applications
81 lines (79 loc) ⢠3.41 kB
JavaScript
import { execSync } from "child_process";
import fs from "fs";
import path from "path";
import { formatThemeLabel } from "../core/theme-parser";
const DEFAULT_CSS_PATH = path.join(process.cwd(), "app", "globals.css");
function extractVariables(css, selector) {
const regex = new RegExp(`${selector.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\s*\\{([^}]+)\\}`, "s");
const match = css.match(regex);
if (!match) {
throw new Error(`Could not find ${selector} in CSS`);
}
const variables = match[1]
.split("\n")
.map((line) => line.trim())
.filter((line) => line.startsWith("--"))
.map((line) => ` ${line}`)
.join("\n");
return variables;
}
function addTheme(themeName, themeUrl, cssPath) {
const globalsPath = cssPath ?? DEFAULT_CSS_PATH;
const backupPath = `${globalsPath}.backup-${Date.now()}`;
console.log(`\nšØ Adding theme: ${themeName}`);
console.log(`š¦ From: ${themeUrl}\n`);
try {
console.log("š 1. Backing up globals.css...");
fs.copyFileSync(globalsPath, backupPath);
console.log(` ā Backup created: ${backupPath}`);
console.log("\nš„ 2. Installing Shadcn theme...");
execSync(`pnpm dlx shadcn@latest add ${themeUrl}`, { stdio: "inherit" });
console.log("\nš 3. Extracting theme variables...");
const modifiedCss = fs.readFileSync(globalsPath, "utf-8");
const rootVars = extractVariables(modifiedCss, ":root");
const darkVars = extractVariables(modifiedCss, ".dark");
console.log("\nā»ļø 4. Restoring original globals.css...");
fs.copyFileSync(backupPath, globalsPath);
console.log("\nā 5. Adding new theme class...");
const originalCss = fs.readFileSync(globalsPath, "utf-8");
const newThemeSection = `
/* Theme: ${formatThemeLabel(themeName)} */
.theme-${themeName} {
${rootVars}
}
.dark .theme-${themeName} {
${darkVars}
}
`;
const updatedCss = originalCss + newThemeSection;
fs.writeFileSync(globalsPath, updatedCss);
console.log(` ā Theme class .theme-${themeName} added`);
fs.unlinkSync(backupPath);
console.log("\nā
Theme added successfully!");
console.log(`\nš You can now use the theme:`);
console.log(` - It will automatically appear in the theme selector`);
console.log(` - Theme ID: ${themeName}`);
console.log(` - Theme Label: ${formatThemeLabel(themeName)}`);
}
catch (error) {
console.error("\nā Error adding theme:", error);
if (fs.existsSync(backupPath)) {
console.log("\nā»ļø Restoring backup...");
fs.copyFileSync(backupPath, globalsPath);
fs.unlinkSync(backupPath);
console.log(" ā Original globals.css restored");
}
process.exit(1);
}
}
const args = process.argv.slice(2);
if (args.length < 2) {
console.error("ā Usage: theme-manager-add <theme-name> <theme-url> [css-path]");
console.error("\nExample:");
console.error(" theme-manager-add modern-minimal https://tweakcn.com/r/themes/modern-minimal.json");
console.error(" theme-manager-add modern-minimal https://tweakcn.com/r/themes/modern-minimal.json app/globals.css");
process.exit(1);
}
const [themeName, themeUrl, cssPath] = args;
addTheme(themeName, themeUrl, cssPath);