Files
HiveGrid-Wireframes/hivegrid-cloud/apps/web/app/utils/theme/cssConfigParser.ts
T

120 lines
3.4 KiB
TypeScript

import { ThemeConfig, ThemeColors } from "./ThemeConfig";
// Maps CSS variable names to our ThemeConfig keys
const cssVarMap: Record<string, keyof ThemeColors> = {
"--background": "background",
"--foreground": "foreground",
"--card": "card",
"--card-foreground": "cardForeground",
"--popover": "popover",
"--popover-foreground": "popoverForeground",
"--primary": "primary",
"--primary-foreground": "primaryForeground",
"--secondary": "secondary",
"--secondary-foreground": "secondaryForeground",
"--muted": "muted",
"--muted-foreground": "mutedForeground",
"--accent": "accent",
"--accent-foreground": "accentForeground",
"--destructive": "destructive",
"--destructive-foreground": "destructiveForeground",
"--border": "border",
"--input": "input",
"--ring": "ring",
"--sidebar": "sidebar",
"--sidebar-background": "sidebarBackground",
"--sidebar-foreground": "sidebarForeground",
"--sidebar-primary": "sidebarPrimary",
"--sidebar-primary-foreground": "sidebarPrimaryForeground",
"--sidebar-accent": "sidebarAccent",
"--sidebar-accent-foreground": "sidebarAccentForeground",
"--sidebar-border": "sidebarBorder",
"--sidebar-ring": "sidebarRing",
};
export function parseCssConfig(cssText: string): Partial<ThemeConfig> {
const config: Partial<ThemeConfig> = {
colors: {},
darkColors: {},
};
// Parse :root section for light mode colors
const rootMatch = cssText.match(/:root\s*{([^}]*)}/);
if (rootMatch) {
const rootContent = rootMatch[1];
config.colors = parseColorSection(rootContent);
// Parse radius
const radiusMatch = rootContent.match(/--radius:\s*([^;]+);/);
if (radiusMatch) {
const radiusValue = radiusMatch[1].trim();
// Convert px to rem (assuming 16px = 1rem)
if (radiusValue.endsWith("px")) {
const px = parseFloat(radiusValue);
config.radius = `${px / 16}rem`;
} else if (radiusValue.endsWith("rem")) {
config.radius = radiusValue;
} else {
config.radius = radiusValue;
}
}
// Parse font-sans (use as default font family)
const fontMatch = rootContent.match(/--font-sans:\s*([^;]+);/);
if (fontMatch) {
config.fontFamily = fontMatch[1].trim();
}
}
// Parse .dark section for dark mode colors
const darkMatch = cssText.match(/\.dark\s*{([^}]*)}/);
if (darkMatch) {
const darkContent = darkMatch[1];
config.darkColors = parseColorSection(darkContent);
}
return config;
}
function parseColorSection(content: string): ThemeColors {
const colors: ThemeColors = {};
// Extract all CSS variables
const varRegex = /(--[a-zA-Z-]+):\s*([^;]+);/g;
let match;
while ((match = varRegex.exec(content)) !== null) {
const cssVar = match[1];
const value = match[2].trim();
// Check if this CSS variable maps to one of our theme colors
const configKey = cssVarMap[cssVar];
if (configKey) {
colors[configKey] = value;
}
}
return colors;
}
export function formatCssValue(value: string): string {
// If it's already a valid CSS color format, return as is
if (
value.startsWith("hsl(") ||
value.startsWith("hsla(") ||
value.startsWith("oklch(") ||
value.startsWith("rgb(") ||
value.startsWith("rgba(") ||
value.startsWith("#")
) {
return value;
}
// Otherwise, assume it's a hex color without the #
if (/^[0-9A-Fa-f]{6}$/.test(value)) {
return `#${value}`;
}
return value;
}