UNPKG

create-roadkit

Version:

Beautiful Next.js roadmap website generator with full-screen kanban boards, dark/light mode, and static export

391 lines (347 loc) 13.8 kB
/** * Predefined theme configurations based on shadcn/ui design principles * * This file contains all the built-in themes that come with roadkit, * following shadcn/ui color schemes and accessibility guidelines. */ import type { Theme, ColorPalette, ThemeConfig, ColorScheme, ShadcnStyle } from './types'; /** * Creates a consistent color palette for light mode themes * Base colors are derived from shadcn/ui's color system * All colors are WCAG AA compliant with minimum 4.5:1 contrast ratios */ function createLightPalette(baseHue: number, saturation: number): ColorPalette { // For light mode, we need darker primary colors for sufficient contrast with white text // Adjust lightness based on saturation to ensure WCAG AA compliance // Special handling for problematic high-saturation colors like green and yellow let primaryLightness: number; if (saturation >= 90) { primaryLightness = 28; // Much darker for very high saturation (yellow) } else if (saturation > 60) { primaryLightness = 30; // Darker for high saturation (green, blue) } else { primaryLightness = 41; // Standard lightness for lower saturation } return { background: { name: 'background', value: '0 0% 100%', description: 'Default page background' }, foreground: { name: 'foreground', value: `${baseHue} 6% 10%`, description: 'Default text color' }, card: { name: 'card', value: '0 0% 100%', description: 'Card background' }, 'card-foreground': { name: 'card-foreground', value: `${baseHue} 6% 10%`, description: 'Card text color' }, popover: { name: 'popover', value: '0 0% 100%', description: 'Popover background' }, 'popover-foreground': { name: 'popover-foreground', value: `${baseHue} 6% 10%`, description: 'Popover text color' }, primary: { name: 'primary', value: `${baseHue} ${Math.min(saturation, 70)}% ${primaryLightness}%`, description: 'Primary brand color' }, 'primary-foreground': { name: 'primary-foreground', value: '0 0% 100%', description: 'Primary button text' }, secondary: { name: 'secondary', value: `${baseHue} 4% 96%`, description: 'Secondary button background' }, 'secondary-foreground': { name: 'secondary-foreground', value: `${baseHue} 6% 10%`, description: 'Secondary button text' }, muted: { name: 'muted', value: `${baseHue} 4% 96%`, description: 'Muted background' }, 'muted-foreground': { name: 'muted-foreground', value: `${baseHue} 4% 38%`, description: 'Muted text' }, accent: { name: 'accent', value: `${baseHue} 4% 96%`, description: 'Accent background' }, 'accent-foreground': { name: 'accent-foreground', value: `${baseHue} 6% 10%`, description: 'Accent text' }, destructive: { name: 'destructive', value: '0 72% 50%', description: 'Error/destructive color' }, 'destructive-foreground': { name: 'destructive-foreground', value: '0 0% 100%', description: 'Error button text' }, border: { name: 'border', value: `${baseHue} 6% 89%`, description: 'Default border color' }, input: { name: 'input', value: `${baseHue} 6% 89%`, description: 'Input border color' }, ring: { name: 'ring', value: `${baseHue} ${Math.min(saturation, 70)}% 41%`, description: 'Focus ring color' }, // Chart colors for data visualization 'chart-1': { name: 'chart-1', value: `${baseHue} ${Math.min(saturation, 70)}% 41%`, description: 'First chart color' }, 'chart-2': { name: 'chart-2', value: `${(baseHue + 60) % 360} ${Math.min(saturation, 70)}% 41%`, description: 'Second chart color' }, 'chart-3': { name: 'chart-3', value: `${(baseHue + 120) % 360} ${Math.min(saturation, 70)}% 41%`, description: 'Third chart color' }, 'chart-4': { name: 'chart-4', value: `${(baseHue + 180) % 360} ${Math.min(saturation, 70)}% 41%`, description: 'Fourth chart color' }, 'chart-5': { name: 'chart-5', value: `${(baseHue + 240) % 360} ${Math.min(saturation, 70)}% 41%`, description: 'Fifth chart color' }, }; } /** * Creates a consistent color palette for dark mode themes * Ensures proper contrast ratios while maintaining brand consistency * All colors are WCAG AA compliant with minimum 4.5:1 contrast ratios */ function createDarkPalette(baseHue: number, saturation: number): ColorPalette { // For dark mode, we need lighter primary colors for sufficient contrast with dark text // Adjust lightness based on saturation to ensure WCAG AA compliance const primaryLightness = saturation > 60 ? 65 : 59; // Lighter for high saturation colors return { background: { name: 'background', value: `${baseHue} 6% 3%`, description: 'Dark mode page background' }, foreground: { name: 'foreground', value: `${baseHue} 5% 90%`, description: 'Dark mode text color' }, card: { name: 'card', value: `${baseHue} 6% 3%`, description: 'Dark mode card background' }, 'card-foreground': { name: 'card-foreground', value: `${baseHue} 5% 90%`, description: 'Dark mode card text' }, popover: { name: 'popover', value: `${baseHue} 6% 3%`, description: 'Dark mode popover background' }, 'popover-foreground': { name: 'popover-foreground', value: `${baseHue} 5% 90%`, description: 'Dark mode popover text' }, primary: { name: 'primary', value: `${baseHue} ${Math.min(saturation, 70)}% ${primaryLightness}%`, description: 'Dark mode primary color' }, 'primary-foreground': { name: 'primary-foreground', value: `${baseHue} 6% 10%`, description: 'Dark mode primary text' }, secondary: { name: 'secondary', value: `${baseHue} 6% 10%`, description: 'Dark mode secondary background' }, 'secondary-foreground': { name: 'secondary-foreground', value: `${baseHue} 5% 90%`, description: 'Dark mode secondary text' }, muted: { name: 'muted', value: `${baseHue} 6% 10%`, description: 'Dark mode muted background' }, 'muted-foreground': { name: 'muted-foreground', value: `${baseHue} 4% 70%`, description: 'Dark mode muted text' }, accent: { name: 'accent', value: `${baseHue} 6% 10%`, description: 'Dark mode accent background' }, 'accent-foreground': { name: 'accent-foreground', value: `${baseHue} 5% 90%`, description: 'Dark mode accent text' }, destructive: { name: 'destructive', value: '0 63% 51%', description: 'Dark mode error color' }, 'destructive-foreground': { name: 'destructive-foreground', value: '0 0% 100%', description: 'Dark mode error text' }, border: { name: 'border', value: `${baseHue} 6% 10%`, description: 'Dark mode border color' }, input: { name: 'input', value: `${baseHue} 6% 10%`, description: 'Dark mode input border' }, ring: { name: 'ring', value: `${baseHue} ${Math.min(saturation, 70)}% 59%`, description: 'Dark mode focus ring' }, // Chart colors optimized for dark mode 'chart-1': { name: 'chart-1', value: `${baseHue} ${Math.min(saturation, 70)}% 59%`, description: 'First dark chart color' }, 'chart-2': { name: 'chart-2', value: `${(baseHue + 60) % 360} ${Math.min(saturation, 70)}% 59%`, description: 'Second dark chart color' }, 'chart-3': { name: 'chart-3', value: `${(baseHue + 120) % 360} ${Math.min(saturation, 70)}% 59%`, description: 'Third dark chart color' }, 'chart-4': { name: 'chart-4', value: `${(baseHue + 180) % 360} ${Math.min(saturation, 70)}% 59%`, description: 'Fourth dark chart color' }, 'chart-5': { name: 'chart-5', value: `${(baseHue + 240) % 360} ${Math.min(saturation, 70)}% 59%`, description: 'Fifth dark chart color' }, }; } /** * Standard border radius values following shadcn/ui conventions */ const BORDER_RADIUS = { sm: '0.375rem', // 6px md: '0.5rem', // 8px lg: '0.75rem', // 12px xl: '1rem', // 16px }; /** * Creates a complete theme configuration with both light and dark modes * Ensures all themes meet WCAG AA accessibility standards */ function createTheme( id: string, name: string, colorScheme: ColorScheme, style: ShadcnStyle, baseHue: number, saturation: number, description: string ): Theme { const lightConfig: ThemeConfig = { id: `${id}-light`, name: `${name} Light`, mode: 'light', colorScheme, style, palette: createLightPalette(baseHue, saturation), borderRadius: BORDER_RADIUS, }; const darkConfig: ThemeConfig = { id: `${id}-dark`, name: `${name} Dark`, mode: 'dark', colorScheme, style, palette: createDarkPalette(baseHue, saturation), borderRadius: BORDER_RADIUS, }; return { id, name, colorScheme, style, light: lightConfig, dark: darkConfig, meta: { description, author: 'roadkit', version: '1.0.0', accessible: true, // All presets are designed to meet WCAG AA tags: ['preset', 'shadcn', colorScheme], }, }; } /** * Blue theme - Default shadcn/ui blue theme * Professional and trustworthy, excellent for business applications */ export const blueTheme: Theme = createTheme( 'blue', 'Blue', 'blue', 'new-york', 221, // Blue hue 83, // High saturation for vibrant blue 'Professional blue theme perfect for business applications' ); /** * Green theme - Natural and calming * Great for environmental, health, or growth-focused applications */ export const greenTheme: Theme = createTheme( 'green', 'Green', 'green', 'new-york', 142, // Green hue 71, // Balanced saturation 'Fresh green theme ideal for eco-friendly and health applications' ); /** * Orange theme - Energetic and warm * Perfect for creative and energetic brand identities */ export const orangeTheme: Theme = createTheme( 'orange', 'Orange', 'orange', 'new-york', 25, // Orange hue 95, // High saturation for vibrant orange 'Vibrant orange theme for creative and energetic brands' ); /** * Red theme - Bold and attention-grabbing * Suitable for alerts, warnings, or bold brand statements */ export const redTheme: Theme = createTheme( 'red', 'Red', 'red', 'new-york', 0, // Pure red hue 84, // High saturation 'Bold red theme for attention-grabbing interfaces' ); /** * Rose theme - Elegant and sophisticated * Perfect for fashion, beauty, or premium brand experiences */ export const roseTheme: Theme = createTheme( 'rose', 'Rose', 'rose', 'new-york', 350, // Rose/pink hue 89, // High saturation 'Elegant rose theme for sophisticated and premium brands' ); /** * Stone theme - Warm neutral * Excellent for content-heavy applications with a warm, approachable feel */ export const stoneTheme: Theme = createTheme( 'stone', 'Stone', 'stone', 'new-york', 25, // Warm hue 5, // Low saturation for neutral feel 'Warm neutral stone theme for content-focused applications' ); /** * Slate theme - Cool neutral * Modern and clean, perfect for technical or professional interfaces */ export const slateTheme: Theme = createTheme( 'slate', 'Slate', 'slate', 'new-york', 215, // Cool blue-gray hue 14, // Low saturation 'Modern slate theme for clean, professional interfaces' ); /** * Gray theme - Pure neutral * Versatile and timeless, works for any application type */ export const grayTheme: Theme = createTheme( 'gray', 'Gray', 'gray', 'new-york', 0, // No hue (pure gray) 0, // No saturation 'Timeless gray theme that works for any application' ); /** * Neutral theme - Balanced neutral * Similar to gray but with slight warmth, very versatile */ export const neutralTheme: Theme = createTheme( 'neutral', 'Neutral', 'neutral', 'new-york', 0, // No hue 0, // No saturation 'Balanced neutral theme with universal appeal' ); /** * Zinc theme - Modern neutral * Contemporary and clean with a slightly cool feel */ export const zincTheme: Theme = createTheme( 'zinc', 'Zinc', 'zinc', 'new-york', 240, // Cool hue 5, // Very low saturation 'Modern zinc theme with a clean, contemporary feel' ); /** * Violet theme - Creative and modern * Perfect for creative agencies, startups, or innovative products */ export const violetTheme: Theme = createTheme( 'violet', 'Violet', 'violet', 'new-york', 263, // Violet hue 70, // Moderate saturation 'Creative violet theme for innovative and modern brands' ); /** * Yellow theme - Bright and optimistic * Great for educational, children's, or happiness-focused applications */ export const yellowTheme: Theme = createTheme( 'yellow', 'Yellow', 'yellow', 'new-york', 48, // Yellow hue 96, // High saturation 'Bright yellow theme for optimistic and cheerful interfaces' ); /** * Collection of all preset themes * These are the themes available out-of-the-box with roadkit */ export const presetThemes: Theme[] = [ blueTheme, greenTheme, orangeTheme, redTheme, roseTheme, stoneTheme, slateTheme, grayTheme, neutralTheme, zincTheme, violetTheme, yellowTheme, ]; /** * Default theme used when no specific theme is selected * Blue theme is chosen as it's professional and widely accepted */ export const defaultTheme: Theme = blueTheme; /** * Get theme by ID from presets * @param id - Theme identifier * @returns Theme if found, undefined otherwise */ export function getPresetTheme(id: string): Theme | undefined { return presetThemes.find(theme => theme.id === id); } /** * Get all available theme IDs * @returns Array of theme identifiers */ export function getPresetThemeIds(): string[] { return presetThemes.map(theme => theme.id); } /** * Get themes by color scheme * @param colorScheme - Color scheme to filter by * @returns Array of themes matching the color scheme */ export function getThemesByColorScheme(colorScheme: string): Theme[] { return presetThemes.filter(theme => theme.colorScheme === colorScheme); }