436 lines
12 KiB
JavaScript
436 lines
12 KiB
JavaScript
#!/usr/bin/env node
|
|
|
|
/**
|
|
* Color Update Utility for Inogen Project
|
|
*
|
|
* This script helps update all color values across the project
|
|
* when new colors are extracted from Figma designs.
|
|
*/
|
|
|
|
const fs = require("fs");
|
|
const path = require("path");
|
|
|
|
// Figma color configuration
|
|
// Replace these values with actual colors from Figma
|
|
const FIGMA_COLORS = {
|
|
// Primary Brand Colors (Teal)
|
|
primary: {
|
|
50: "#f0fdfa",
|
|
100: "#ccfbf1",
|
|
200: "#99f6e4",
|
|
300: "#5eead4",
|
|
400: "#2dd4bf",
|
|
500: "#48D1CC", // Main brand color from current design
|
|
600: "#40C4C4", // Hover state from current design
|
|
700: "#0f766e",
|
|
800: "#115e59",
|
|
900: "#134e4a",
|
|
950: "#042f2e",
|
|
},
|
|
|
|
// Dark Theme Colors
|
|
dark: {
|
|
50: "#f8fafc",
|
|
100: "#f1f5f9",
|
|
200: "#e2e8f0",
|
|
300: "#cbd5e1",
|
|
400: "#94a3b8",
|
|
500: "#64748b",
|
|
600: "#475569",
|
|
700: "#334155",
|
|
800: "#1A202C", // Login background from current design
|
|
900: "#0f172a",
|
|
950: "#020617",
|
|
},
|
|
|
|
// Neutral Colors
|
|
neutral: {
|
|
50: "#fafafa",
|
|
100: "#f5f5f5",
|
|
200: "#e5e5e5",
|
|
300: "#d4d4d4",
|
|
400: "#a3a3a3",
|
|
500: "#737373",
|
|
600: "#525252",
|
|
700: "#404040",
|
|
800: "#262626",
|
|
900: "#171717",
|
|
950: "#0a0a0a",
|
|
},
|
|
|
|
// Status Colors
|
|
success: {
|
|
50: "#f0fdf4",
|
|
100: "#dcfce7",
|
|
200: "#bbf7d0",
|
|
300: "#86efac",
|
|
400: "#4ade80",
|
|
500: "#22c55e",
|
|
600: "#16a34a",
|
|
700: "#15803d",
|
|
800: "#166534",
|
|
900: "#14532d",
|
|
},
|
|
|
|
error: {
|
|
50: "#fef2f2",
|
|
100: "#fee2e2",
|
|
200: "#fecaca",
|
|
300: "#fca5a5",
|
|
400: "#f87171",
|
|
500: "#ef4444",
|
|
600: "#dc2626",
|
|
700: "#b91c1c",
|
|
800: "#991b1b",
|
|
900: "#7f1d1d",
|
|
},
|
|
|
|
warning: {
|
|
50: "#fffbeb",
|
|
100: "#fef3c7",
|
|
200: "#fde68a",
|
|
300: "#fcd34d",
|
|
400: "#fbbf24",
|
|
500: "#f59e0b",
|
|
600: "#d97706",
|
|
700: "#b45309",
|
|
800: "#92400e",
|
|
900: "#78350f",
|
|
},
|
|
|
|
info: {
|
|
50: "#eff6ff",
|
|
100: "#dbeafe",
|
|
200: "#bfdbfe",
|
|
300: "#93c5fd",
|
|
400: "#60a5fa",
|
|
500: "#3b82f6",
|
|
600: "#2563eb",
|
|
700: "#1d4ed8",
|
|
800: "#1e40af",
|
|
900: "#1e3a8a",
|
|
},
|
|
|
|
// Login specific colors
|
|
login: {
|
|
primary: "#3aea83",
|
|
darkStart: "#464861",
|
|
darkEnd: "#111628",
|
|
},
|
|
};
|
|
|
|
// Semantic color mappings
|
|
const SEMANTIC_COLORS = {
|
|
light: {
|
|
background: "#ffffff",
|
|
foreground: "#0a0a0a",
|
|
card: "#ffffff",
|
|
cardForeground: "#0a0a0a",
|
|
popover: "#ffffff",
|
|
popoverForeground: "#0a0a0a",
|
|
primary: FIGMA_COLORS.primary[500],
|
|
primaryForeground: FIGMA_COLORS.dark[800],
|
|
secondary: FIGMA_COLORS.neutral[100],
|
|
secondaryForeground: FIGMA_COLORS.neutral[900],
|
|
muted: FIGMA_COLORS.neutral[100],
|
|
mutedForeground: FIGMA_COLORS.neutral[500],
|
|
accent: FIGMA_COLORS.neutral[100],
|
|
accentForeground: FIGMA_COLORS.neutral[900],
|
|
destructive: FIGMA_COLORS.error[500],
|
|
destructiveForeground: "#ffffff",
|
|
border: FIGMA_COLORS.neutral[200],
|
|
input: FIGMA_COLORS.neutral[200],
|
|
ring: FIGMA_COLORS.primary[500],
|
|
loginPrimary: FIGMA_COLORS.login.primary,
|
|
loginDarkStart: FIGMA_COLORS.login.darkStart,
|
|
loginDarkEnd: FIGMA_COLORS.login.darkEnd,
|
|
},
|
|
|
|
dark: {
|
|
background: FIGMA_COLORS.dark[950],
|
|
foreground: FIGMA_COLORS.neutral[50],
|
|
card: FIGMA_COLORS.dark[900],
|
|
cardForeground: FIGMA_COLORS.neutral[50],
|
|
popover: FIGMA_COLORS.dark[900],
|
|
popoverForeground: FIGMA_COLORS.neutral[50],
|
|
primary: FIGMA_COLORS.primary[500],
|
|
primaryForeground: FIGMA_COLORS.dark[800],
|
|
secondary: FIGMA_COLORS.dark[800],
|
|
secondaryForeground: FIGMA_COLORS.neutral[50],
|
|
muted: FIGMA_COLORS.dark[800],
|
|
mutedForeground: FIGMA_COLORS.neutral[400],
|
|
accent: FIGMA_COLORS.dark[800],
|
|
accentForeground: FIGMA_COLORS.neutral[50],
|
|
destructive: FIGMA_COLORS.error[500],
|
|
destructiveForeground: FIGMA_COLORS.neutral[50],
|
|
border: FIGMA_COLORS.dark[800],
|
|
input: FIGMA_COLORS.dark[800],
|
|
ring: FIGMA_COLORS.primary[400],
|
|
loginPrimary: FIGMA_COLORS.login.primary,
|
|
loginDarkStart: FIGMA_COLORS.login.darkStart,
|
|
loginDarkEnd: FIGMA_COLORS.login.darkEnd,
|
|
},
|
|
};
|
|
|
|
/**
|
|
* Update CSS custom properties in app.css
|
|
*/
|
|
function updateAppCSS() {
|
|
const cssPath = path.join(__dirname, "../app/app.css");
|
|
let cssContent = fs.readFileSync(cssPath, "utf8");
|
|
|
|
// Generate CSS custom properties
|
|
let newProperties = "";
|
|
|
|
// Add color scales
|
|
Object.entries(FIGMA_COLORS).forEach(([colorName, colorScale]) => {
|
|
newProperties += `\n /* ${colorName.charAt(0).toUpperCase() + colorName.slice(1)} color scale */\n`;
|
|
if (typeof colorScale === "object" && colorScale !== null) {
|
|
Object.entries(colorScale).forEach(([shade, value]) => {
|
|
newProperties += ` --color-${colorName}-${shade}: ${value};\n`;
|
|
});
|
|
}
|
|
});
|
|
|
|
// Update semantic colors for light theme
|
|
const lightThemeStart = ":root {";
|
|
const lightThemeEnd = "}";
|
|
|
|
let lightThemeContent = `${lightThemeStart}
|
|
--radius: 0.5rem;
|
|
|
|
/* Light theme colors */
|
|
--background: ${SEMANTIC_COLORS.light.background};
|
|
--foreground: ${SEMANTIC_COLORS.light.foreground};
|
|
--card: ${SEMANTIC_COLORS.light.card};
|
|
--card-foreground: ${SEMANTIC_COLORS.light.cardForeground};
|
|
--popover: ${SEMANTIC_COLORS.light.popover};
|
|
--popover-foreground: ${SEMANTIC_COLORS.light.popoverForeground};
|
|
--primary: ${SEMANTIC_COLORS.light.primary};
|
|
--primary-foreground: ${SEMANTIC_COLORS.light.primaryForeground};
|
|
--secondary: ${SEMANTIC_COLORS.light.secondary};
|
|
--secondary-foreground: ${SEMANTIC_COLORS.light.secondaryForeground};
|
|
--muted: ${SEMANTIC_COLORS.light.muted};
|
|
--muted-foreground: ${SEMANTIC_COLORS.light.mutedForeground};
|
|
--accent: ${SEMANTIC_COLORS.light.accent};
|
|
--accent-foreground: ${SEMANTIC_COLORS.light.accentForeground};
|
|
--destructive: ${SEMANTIC_COLORS.light.destructive};
|
|
--destructive-foreground: ${SEMANTIC_COLORS.light.destructiveForeground};
|
|
--border: ${SEMANTIC_COLORS.light.border};
|
|
--input: ${SEMANTIC_COLORS.light.input};
|
|
--ring: ${SEMANTIC_COLORS.light.ring};
|
|
|
|
/* Login specific colors */
|
|
--color-login-primary: ${SEMANTIC_COLORS.light.loginPrimary};
|
|
--color-login-dark-start: ${SEMANTIC_COLORS.light.loginDarkStart};
|
|
--color-login-dark-end: ${SEMANTIC_COLORS.light.loginDarkEnd};
|
|
${newProperties}
|
|
${lightThemeEnd}`;
|
|
|
|
// Update dark theme
|
|
let darkThemeContent = `.dark {
|
|
/* Dark theme colors */
|
|
--background: ${SEMANTIC_COLORS.dark.background};
|
|
--foreground: ${SEMANTIC_COLORS.dark.foreground};
|
|
--card: ${SEMANTIC_COLORS.dark.card};
|
|
--card-foreground: ${SEMANTIC_COLORS.dark.cardForeground};
|
|
--popover: ${SEMANTIC_COLORS.dark.popover};
|
|
--popover-foreground: ${SEMANTIC_COLORS.dark.popoverForeground};
|
|
--primary: ${SEMANTIC_COLORS.dark.primary};
|
|
--primary-foreground: ${SEMANTIC_COLORS.dark.primaryForeground};
|
|
--secondary: ${SEMANTIC_COLORS.dark.secondary};
|
|
--secondary-foreground: ${SEMANTIC_COLORS.dark.secondaryForeground};
|
|
--muted: ${SEMANTIC_COLORS.dark.muted};
|
|
--muted-foreground: ${SEMANTIC_COLORS.dark.mutedForeground};
|
|
--accent: ${SEMANTIC_COLORS.dark.accent};
|
|
--accent-foreground: ${SEMANTIC_COLORS.dark.accentForeground};
|
|
--destructive: ${SEMANTIC_COLORS.dark.destructive};
|
|
--destructive-foreground: ${SEMANTIC_COLORS.dark.destructiveForeground};
|
|
--border: ${SEMANTIC_COLORS.dark.border};
|
|
--input: ${SEMANTIC_COLORS.dark.input};
|
|
--ring: ${SEMANTIC_COLORS.dark.ring};
|
|
|
|
/* Login specific colors */
|
|
--color-login-primary: ${SEMANTIC_COLORS.dark.loginPrimary};
|
|
--color-login-dark-start: ${SEMANTIC_COLORS.dark.loginDarkStart};
|
|
--color-login-dark-end: ${SEMANTIC_COLORS.dark.loginDarkEnd};
|
|
}`;
|
|
|
|
// Replace existing color definitions
|
|
cssContent = cssContent.replace(/:root\s*{[^}]*}/s, lightThemeContent);
|
|
|
|
cssContent = cssContent.replace(/\.dark\s*{[^}]*}/s, darkThemeContent);
|
|
|
|
fs.writeFileSync(cssPath, cssContent);
|
|
console.log("✅ Updated app.css with new colors");
|
|
}
|
|
|
|
/**
|
|
* Update TypeScript design tokens
|
|
*/
|
|
function updateDesignTokens() {
|
|
const tokensPath = path.join(__dirname, "../app/lib/design-tokens.ts");
|
|
|
|
const designTokensContent = `export const colors = {
|
|
// Primary Colors
|
|
primary: ${JSON.stringify(FIGMA_COLORS.primary, null, 4).replace(/"/g, '"')},
|
|
|
|
// Secondary Colors (Info/Blue)
|
|
secondary: ${JSON.stringify(FIGMA_COLORS.info, null, 4).replace(/"/g, '"')},
|
|
|
|
// Dark Colors (Brand dark)
|
|
dark: ${JSON.stringify(FIGMA_COLORS.dark, null, 4).replace(/"/g, '"')},
|
|
|
|
// Neutral Colors
|
|
neutral: ${JSON.stringify(FIGMA_COLORS.neutral, null, 4).replace(/"/g, '"')},
|
|
|
|
// Status Colors
|
|
success: ${JSON.stringify(FIGMA_COLORS.success, null, 4).replace(/"/g, '"')},
|
|
|
|
error: ${JSON.stringify(FIGMA_COLORS.error, null, 4).replace(/"/g, '"')},
|
|
|
|
warning: ${JSON.stringify(FIGMA_COLORS.warning, null, 4).replace(/"/g, '"')},
|
|
|
|
info: ${JSON.stringify(FIGMA_COLORS.info, null, 4).replace(/"/g, '"')},
|
|
};
|
|
|
|
export const typography = {
|
|
fontFamily: {
|
|
sans: ["Vazirmatn", "Inter", "ui-sans-serif", "system-ui", "sans-serif"],
|
|
mono: ["ui-monospace", "SFMono-Regular", "Consolas", "monospace"],
|
|
},
|
|
|
|
fontSize: {
|
|
xs: ["0.75rem", { lineHeight: "1rem" }],
|
|
sm: ["0.875rem", { lineHeight: "1.25rem" }],
|
|
base: ["1rem", { lineHeight: "1.5rem" }],
|
|
lg: ["1.125rem", { lineHeight: "1.75rem" }],
|
|
xl: ["1.25rem", { lineHeight: "1.75rem" }],
|
|
"2xl": ["1.5rem", { lineHeight: "2rem" }],
|
|
"3xl": ["1.875rem", { lineHeight: "2.25rem" }],
|
|
"4xl": ["2.25rem", { lineHeight: "2.5rem" }],
|
|
"5xl": ["3rem", { lineHeight: "1" }],
|
|
"6xl": ["3.75rem", { lineHeight: "1" }],
|
|
},
|
|
|
|
fontWeight: {
|
|
thin: "100",
|
|
extralight: "200",
|
|
light: "300",
|
|
normal: "400",
|
|
medium: "500",
|
|
semibold: "600",
|
|
bold: "700",
|
|
extrabold: "800",
|
|
black: "900",
|
|
},
|
|
};
|
|
|
|
export const spacing = {
|
|
px: "1px",
|
|
0: "0px",
|
|
0.5: "0.125rem",
|
|
1: "0.25rem",
|
|
1.5: "0.375rem",
|
|
2: "0.5rem",
|
|
2.5: "0.625rem",
|
|
3: "0.75rem",
|
|
3.5: "0.875rem",
|
|
4: "1rem",
|
|
5: "1.25rem",
|
|
6: "1.5rem",
|
|
7: "1.75rem",
|
|
8: "2rem",
|
|
9: "2.25rem",
|
|
10: "2.5rem",
|
|
11: "2.75rem",
|
|
12: "3rem",
|
|
14: "3.5rem",
|
|
16: "4rem",
|
|
20: "5rem",
|
|
24: "6rem",
|
|
28: "7rem",
|
|
32: "8rem",
|
|
36: "9rem",
|
|
40: "10rem",
|
|
44: "11rem",
|
|
48: "12rem",
|
|
52: "13rem",
|
|
56: "14rem",
|
|
60: "15rem",
|
|
64: "16rem",
|
|
72: "18rem",
|
|
80: "20rem",
|
|
96: "24rem",
|
|
};
|
|
|
|
export const borderRadius = {
|
|
none: "0px",
|
|
sm: "0.125rem",
|
|
DEFAULT: "0.25rem",
|
|
md: "0.375rem",
|
|
lg: "0.5rem",
|
|
xl: "0.75rem",
|
|
"2xl": "1rem",
|
|
"3xl": "1.5rem",
|
|
full: "9999px",
|
|
};
|
|
|
|
export const shadows = {
|
|
sm: "0 1px 2px 0 rgb(0 0 0 / 0.05)",
|
|
DEFAULT: "0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1)",
|
|
md: "0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1)",
|
|
lg: "0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1)",
|
|
xl: "0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1)",
|
|
"2xl": "0 25px 50px -12px rgb(0 0 0 / 0.25)",
|
|
inner: "inset 0 2px 4px 0 rgb(0 0 0 / 0.05)",
|
|
none: "0 0 #0000",
|
|
};
|
|
|
|
// Theme variants
|
|
export const themes = {
|
|
light: ${JSON.stringify(SEMANTIC_COLORS.light, null, 4).replace(/"/g, '"')},
|
|
dark: ${JSON.stringify(SEMANTIC_COLORS.dark, null, 4).replace(/"/g, '"')},
|
|
};
|
|
`;
|
|
|
|
fs.writeFileSync(tokensPath, designTokensContent);
|
|
console.log("✅ Updated design-tokens.ts with new colors");
|
|
}
|
|
|
|
/**
|
|
* Main execution function
|
|
*/
|
|
function updateColors() {
|
|
console.log("🎨 Updating colors from Figma design...\n");
|
|
|
|
try {
|
|
updateAppCSS();
|
|
updateDesignTokens();
|
|
|
|
console.log("\n✨ Color update completed successfully!");
|
|
console.log("\nUpdated files:");
|
|
console.log("- app/app.css");
|
|
console.log("- app/lib/design-tokens.ts");
|
|
console.log("\nNext steps:");
|
|
console.log("1. Review the changes");
|
|
console.log("2. Test the application");
|
|
console.log("3. Verify colors match Figma design");
|
|
console.log("4. Update any hardcoded colors in components");
|
|
} catch (error) {
|
|
console.error("❌ Error updating colors:", error.message);
|
|
process.exit(1);
|
|
}
|
|
}
|
|
|
|
// Run the script if called directly
|
|
if (require.main === module) {
|
|
updateColors();
|
|
}
|
|
|
|
module.exports = {
|
|
FIGMA_COLORS,
|
|
SEMANTIC_COLORS,
|
|
updateColors,
|
|
};
|