'use client'; import { useState } from 'react'; import { ColorPicker } from '@/components/color/ColorPicker'; import { PaletteGrid } from '@/components/color/PaletteGrid'; import { ExportMenu } from '@/components/tools/ExportMenu'; import { Button } from '@/components/ui/button'; import { Select } from '@/components/ui/select'; import { useComplement, useRotate } from '@/lib/api/queries'; import { Loader2, Palette } from 'lucide-react'; import { toast } from 'sonner'; type HarmonyType = | 'monochromatic' | 'analogous' | 'complementary' | 'split-complementary' | 'triadic' | 'tetradic'; export default function HarmonyPage() { const [baseColor, setBaseColor] = useState('#ff0099'); const [harmonyType, setHarmonyType] = useState('complementary'); const [palette, setPalette] = useState([]); const complementMutation = useComplement(); const rotateMutation = useRotate(); const generateHarmony = async () => { try { let colors: string[] = [baseColor]; switch (harmonyType) { case 'monochromatic': // Base color with lightness variations colors = [baseColor]; toast.info('Monochromatic harmony uses variations of the base color'); break; case 'analogous': // Base + 30° and -30° const analog1 = await rotateMutation.mutateAsync({ colors: [baseColor], amount: 30, }); const analog2 = await rotateMutation.mutateAsync({ colors: [baseColor], amount: -30, }); colors = [analog2.colors[0], baseColor, analog1.colors[0]]; break; case 'complementary': // Base + opposite (180°) const complement = await complementMutation.mutateAsync([baseColor]); colors = [baseColor, complement.colors[0]]; break; case 'split-complementary': // Base + 150° and 210° (flanking the complement) const split1 = await rotateMutation.mutateAsync({ colors: [baseColor], amount: 150, }); const split2 = await rotateMutation.mutateAsync({ colors: [baseColor], amount: 210, }); colors = [baseColor, split1.colors[0], split2.colors[0]]; break; case 'triadic': // Base + 120° and 240° (evenly spaced) const tri1 = await rotateMutation.mutateAsync({ colors: [baseColor], amount: 120, }); const tri2 = await rotateMutation.mutateAsync({ colors: [baseColor], amount: 240, }); colors = [baseColor, tri1.colors[0], tri2.colors[0]]; break; case 'tetradic': // Base + 90°, 180°, 270° (square) const tet1 = await rotateMutation.mutateAsync({ colors: [baseColor], amount: 90, }); const tet2 = await rotateMutation.mutateAsync({ colors: [baseColor], amount: 180, }); const tet3 = await rotateMutation.mutateAsync({ colors: [baseColor], amount: 270, }); colors = [baseColor, tet1.colors[0], tet2.colors[0], tet3.colors[0]]; break; } setPalette(colors); toast.success(`Generated ${harmonyType} harmony palette`); } catch (error) { toast.error('Failed to generate harmony palette'); console.error(error); } }; const harmonyDescriptions: Record = { monochromatic: 'Single color with variations', analogous: 'Colors adjacent on the color wheel (±30°)', complementary: 'Colors opposite on the color wheel (180°)', 'split-complementary': 'Base color + two colors flanking its complement', triadic: 'Three colors evenly spaced on the color wheel (120°)', tetradic: 'Four colors evenly spaced on the color wheel (90°)', }; return (

Harmony Palette Generator

Create color harmonies based on color theory principles

{/* Controls */}

Base Color

Harmony Type

{harmonyDescriptions[harmonyType]}

{/* Results */}
{palette.length > 0 && ( <>

Generated Palette ({palette.length} colors)

)} {palette.length === 0 && (

Select a harmony type and click Generate to create your palette

)}
); }