- Add quotaExceeded flag to response for better error UX - Show dedicated quota exceeded state with upgrade button - Improve AI prompt to better detect data patterns - Add chart type-specific colors (blue, indigo, emerald, violet, etc.) - Replace generic primary/10 colors with varied accent colors Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
90 lines
6.2 KiB
TypeScript
90 lines
6.2 KiB
TypeScript
/**
|
|
* Palette definitions and resolution helpers.
|
|
* Shared between slides.tool.ts (server) and slides-renderer.tsx (client).
|
|
*/
|
|
import type { Palette, PresentationSpec } from '@/lib/types/presentation'
|
|
|
|
export type { Palette }
|
|
|
|
export const PALETTES: Record<string, Palette> = {
|
|
// ── Dark / Keynote ───────────────────────────────────────────────────────────
|
|
keynote: { primary: '#f1f5f9', secondary: '#7dd3fc', accent: '#6366f1', light: '#334155', bg: '#0f172a', isDark: true },
|
|
galaxy: { primary: '#e2e8f0', secondary: '#a78bfa', accent: '#f472b6', light: '#1e1b4b', bg: '#0d1117', isDark: true },
|
|
stage_dark: { primary: '#f9fafb', secondary: '#34d399', accent: '#fbbf24', light: '#1f2937', bg: '#111827', isDark: true },
|
|
tech_night: { primary: '#e0e0e0', secondary: '#ffc300', accent: '#ffd60a', light: '#003566', bg: '#001d3d', isDark: true },
|
|
luxury_mystery: { primary: '#f2e9e4', secondary: '#c9ada7', accent: '#9a8c98', light: '#4a4e69', bg: '#22223b', isDark: true },
|
|
vibrant_orange_mint: { primary: '#f1f1f1', secondary: '#2ec4b6', accent: '#ff9f1c', light: '#0d2137', bg: '#1a1a2e', isDark: true },
|
|
platinum_white_gold: { primary: '#0a0a0a', secondary: '#0070F3', accent: '#D4AF37', light: '#f5f5f5', bg: '#ffffff', isDark: false },
|
|
// ── Light / Pro ──────────────────────────────────────────────────────────────
|
|
modern_wellness: { primary: '#006d77', secondary: '#83c5be', accent: '#e29578', light: '#ffddd2', bg: '#edf6f9', isDark: false },
|
|
business_authority: { primary: '#2b2d42', secondary: '#8d99ae', accent: '#ef233c', light: '#edf2f4', bg: '#edf2f4', isDark: false },
|
|
nature_outdoors: { primary: '#606c38', secondary: '#283618', accent: '#dda15e', light: '#fefae0', bg: '#fefae0', isDark: false },
|
|
vintage_academic: { primary: '#780000', secondary: '#669bbc', accent: '#c1121f', light: '#fdf0d5', bg: '#fdf0d5', isDark: false },
|
|
soft_creative: { primary: '#7c6c8a', secondary: '#a89bbd', accent: '#d4a5c9', light: '#e8dff0', bg: '#f3eef8', isDark: false },
|
|
bohemian: { primary: '#8a7e5e', secondary: '#a89e72', accent: '#c4a06a', light: '#e9dcc0', bg: '#f5eed8', isDark: false },
|
|
vibrant_tech: { primary: '#023047', secondary: '#219ebc', accent: '#ffb703', light: '#8ecae6', bg: '#f8fbff', isDark: false },
|
|
craft_artisan: { primary: '#5e3e28', secondary: '#8a6548', accent: '#a68a64', light: '#d4c4a8', bg: '#ede0d4', isDark: false },
|
|
education_charts: { primary: '#264653', secondary: '#2a9d8f', accent: '#e76f51', light: '#e9c46a', bg: '#f4f1eb', isDark: false },
|
|
forest_eco: { primary: '#344e41', secondary: '#588157', accent: '#a3b18a', light: '#dad7cd', bg: '#eae8e3', isDark: false },
|
|
elegant_fashion: { primary: '#4a5759', secondary: '#8f9fa2', accent: '#b0c4b1', light: '#c9ada7', bg: '#f2e9e4', isDark: false },
|
|
art_food: { primary: '#335c67', secondary: '#5e8a6f', accent: '#e09f3e', light: '#f3d97a', bg: '#fff8e1', isDark: false },
|
|
pure_tech_blue: { primary: '#03045e', secondary: '#0077b6', accent: '#00b4d8', light: '#90e0ef', bg: '#caf0f8', isDark: false },
|
|
coastal_coral: { primary: '#0081a7', secondary: '#00afb9', accent: '#f07167', light: '#fed9b7', bg: '#fdfcdc', isDark: false },
|
|
architectural_mono: { primary: '#1C1C1C', secondary: '#D4A373', accent: '#A47148', light: '#F9F8F6', bg: '#F9F8F6', isDark: false },
|
|
minimal_silk: { primary: '#212529', secondary: '#6c757d', accent: '#dee2e6', light: '#f8f9fa', bg: '#ffffff', isDark: false },
|
|
}
|
|
|
|
export const PALETTE_ALIASES: Record<string, string> = {
|
|
modern: 'vibrant_tech', corporate: 'business_authority', minimal: 'elegant_fashion',
|
|
dark: 'keynote', midnight: 'galaxy', night: 'tech_night', forest: 'forest_eco',
|
|
coral: 'coastal_coral', ocean: 'pure_tech_blue', charcoal: 'platinum_white_gold',
|
|
teal: 'education_charts', berry: 'art_food', cherry: 'vintage_academic',
|
|
clair: 'pure_tech_blue', light: 'modern_wellness', warm: 'bohemian',
|
|
premium: 'platinum_white_gold', clean: 'vibrant_tech', stage: 'stage_dark',
|
|
architectural: 'architectural_mono', silk: 'minimal_silk',
|
|
black: 'keynote', white: 'platinum_white_gold', nuit: 'galaxy', sombre: 'stage_dark',
|
|
|
|
// Recipe explicit theme mappings
|
|
architectural_saas: 'architectural_mono',
|
|
midnight_cathedral: 'keynote',
|
|
aurora_borealis: 'galaxy',
|
|
tokyo_neon: 'vibrant_tech',
|
|
sunlit_gallery: 'bohemian',
|
|
clinical_precision: 'modern_wellness',
|
|
venture_pitch: 'vibrant_orange_mint',
|
|
forest_floor: 'forest_eco',
|
|
steel_glass: 'luxury_mystery',
|
|
cyberpunk_terminal: 'tech_night',
|
|
editorial_ink: 'vintage_academic',
|
|
coastal_morning: 'coastal_coral',
|
|
paper_studio: 'craft_artisan',
|
|
}
|
|
|
|
export const THEME_NAMES: Record<string, string> = {
|
|
modern_wellness: 'Modern & Wellness', business_authority: 'Business & Authority',
|
|
nature_outdoors: 'Nature & Outdoors', vintage_academic: 'Vintage & Academic',
|
|
soft_creative: 'Soft & Creative', bohemian: 'Bohemian',
|
|
vibrant_tech: 'Vibrant & Tech', craft_artisan: 'Craft & Artisan',
|
|
tech_night: 'Tech & Night', education_charts: 'Education & Charts',
|
|
forest_eco: 'Forest & Eco', elegant_fashion: 'Elegant & Fashion',
|
|
art_food: 'Art & Food', luxury_mystery: 'Luxury & Mystery',
|
|
pure_tech_blue: 'Pure Tech Blue', coastal_coral: 'Coastal Coral',
|
|
vibrant_orange_mint: 'Vibrant Orange Mint', platinum_white_gold: 'Platinum White Gold',
|
|
architectural_mono: 'Architectural Mono', minimal_silk: 'Minimal Silk',
|
|
}
|
|
|
|
export function resolvePalette(spec: Pick<PresentationSpec, 'theme'>): { palette: Palette; key: string } {
|
|
const name = (spec.theme || '').toLowerCase().replace(/[\s-]/g, '_')
|
|
const key = PALETTE_ALIASES[name] || (PALETTES[name] ? name : 'keynote')
|
|
return { palette: PALETTES[key]!, key }
|
|
}
|
|
|
|
export function resolveRadius(style?: string): string {
|
|
const s = (style || '').toLowerCase()
|
|
if (s === 'sharp' || s === 'professional') return '4px'
|
|
if (s === 'brutalist') return '0px'
|
|
if (s === 'creative' || s === 'rounded') return '18px'
|
|
if (s === 'pill') return '28px'
|
|
return '12px'
|
|
}
|