refactor: update UI component usage to match latest shadcn APIs

This commit is contained in:
2026-02-24 16:20:35 +01:00
parent bf4729fa4d
commit 9c6b184f7e
40 changed files with 4463 additions and 465 deletions

View File

@@ -1,9 +1,15 @@
'use client';
import { useState } from 'react';
import { Button } from '@/components/ui/Button';
import { Select } from '@/components/ui/Select';
import { Input } from '@/components/ui/Input';
import { Button } from '@/components/ui/button';
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from '@/components/ui/select';
import { Input } from '@/components/ui/input';
import { PaletteGrid } from '@/components/pastel/color/PaletteGrid';
import { ExportMenu } from '@/components/pastel/tools/ExportMenu';
import { useLighten, useDarken, useSaturate, useDesaturate, useRotate } from '@/lib/pastel/api/queries';
@@ -118,15 +124,19 @@ export default function BatchPage() {
<h2 className="text-sm font-medium mb-4">Operation</h2>
<div className="space-y-4">
<Select
label="Operation"
value={operation}
onChange={(e) => setOperation(e.target.value as Operation)}
onValueChange={(value) => setOperation(value as Operation)}
>
<option value="lighten">Lighten</option>
<option value="darken">Darken</option>
<option value="saturate">Saturate</option>
<option value="desaturate">Desaturate</option>
<option value="rotate">Rotate Hue</option>
<SelectTrigger>
<SelectValue placeholder="Select operation" />
</SelectTrigger>
<SelectContent>
<SelectItem value="lighten">Lighten</SelectItem>
<SelectItem value="darken">Darken</SelectItem>
<SelectItem value="saturate">Saturate</SelectItem>
<SelectItem value="desaturate">Desaturate</SelectItem>
<SelectItem value="rotate">Rotate Hue</SelectItem>
</SelectContent>
</Select>
<div>

View File

@@ -3,8 +3,14 @@
import { useState } from 'react';
import { ColorPicker } from '@/components/pastel/color/ColorPicker';
import { ColorDisplay } from '@/components/pastel/color/ColorDisplay';
import { Button } from '@/components/ui/Button';
import { Select } from '@/components/ui/Select';
import { Button } from '@/components/ui/button';
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from '@/components/ui/select';
import { useSimulateColorBlindness } from '@/lib/pastel/api/queries';
import { Loader2, Eye, Plus, X } from 'lucide-react';
import { toast } from 'sonner';
@@ -113,13 +119,17 @@ export default function ColorBlindPage() {
<h2 className="text-sm font-medium mb-4">Blindness Type</h2>
<div className="space-y-4">
<Select
label="Type"
value={blindnessType}
onChange={(e) => setBlindnessType(e.target.value as ColorBlindnessType)}
onValueChange={(value) => setBlindnessType(value as ColorBlindnessType)}
>
<option value="protanopia">Protanopia (Red-blind)</option>
<option value="deuteranopia">Deuteranopia (Green-blind)</option>
<option value="tritanopia">Tritanopia (Blue-blind)</option>
<SelectTrigger>
<SelectValue placeholder="Select type" />
</SelectTrigger>
<SelectContent>
<SelectItem value="protanopia">Protanopia (Red-blind)</SelectItem>
<SelectItem value="deuteranopia">Deuteranopia (Green-blind)</SelectItem>
<SelectItem value="tritanopia">Tritanopia (Blue-blind)</SelectItem>
</SelectContent>
</Select>
<p className="text-sm text-muted-foreground">

View File

@@ -2,8 +2,8 @@
import { useState, useEffect } from 'react';
import { ColorPicker } from '@/components/pastel/color/ColorPicker';
import { Button } from '@/components/ui/Button';
import { Badge } from '@/components/ui/Badge';
import { Button } from '@/components/ui/button';
import { Badge } from '@/components/ui/badge';
import { getContrastRatio, hexToRgb, checkWCAGCompliance } from '@/lib/pastel/utils/color';
import { ArrowLeftRight, Check, X } from 'lucide-react';
@@ -39,7 +39,7 @@ export default function ContrastPage() {
}) => (
<div className="flex items-center justify-between p-3 bg-muted rounded-lg">
<span className="text-sm">{label}</span>
<Badge variant={passed ? 'success' : 'destructive'}>
<Badge variant={passed ? 'secondary' : 'destructive'}>
{passed ? (
<>
<Check className="h-3 w-3 mr-1" />

View File

@@ -3,9 +3,15 @@
import { useState } from 'react';
import { PaletteGrid } from '@/components/pastel/color/PaletteGrid';
import { ExportMenu } from '@/components/pastel/tools/ExportMenu';
import { Button } from '@/components/ui/Button';
import { Input } from '@/components/ui/Input';
import { Select } from '@/components/ui/Select';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from '@/components/ui/select';
import { useGenerateDistinct } from '@/lib/pastel/api/queries';
import { Loader2 } from 'lucide-react';
import { toast } from 'sonner';
@@ -65,14 +71,23 @@ export default function DistinctPage() {
</p>
</div>
<Select
label="Distance Metric"
value={metric}
onChange={(e) => setMetric(e.target.value as 'cie76' | 'ciede2000')}
>
<option value="cie76">CIE76 (Faster)</option>
<option value="ciede2000">CIEDE2000 (More Accurate)</option>
</Select>
<div className="space-y-2">
<label className="text-sm font-medium block">
Distance Metric
</label>
<Select
value={metric}
onValueChange={(value) => setMetric(value as 'cie76' | 'ciede2000')}
>
<SelectTrigger>
<SelectValue placeholder="Select metric" />
</SelectTrigger>
<SelectContent>
<SelectItem value="cie76">CIE76 (Faster)</SelectItem>
<SelectItem value="ciede2000">CIEDE2000 (More Accurate)</SelectItem>
</SelectContent>
</Select>
</div>
<Button
onClick={handleGenerate}

View File

@@ -4,8 +4,8 @@ import { useState } from 'react';
import { ColorPicker } from '@/components/pastel/color/ColorPicker';
import { PaletteGrid } from '@/components/pastel/color/PaletteGrid';
import { ExportMenu } from '@/components/pastel/tools/ExportMenu';
import { Button } from '@/components/ui/Button';
import { Input } from '@/components/ui/Input';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { useGenerateGradient } from '@/lib/pastel/api/queries';
import { Loader2, Plus, X } from 'lucide-react';
import { toast } from 'sonner';

View File

@@ -4,8 +4,14 @@ import { useState } from 'react';
import { ColorPicker } from '@/components/pastel/color/ColorPicker';
import { PaletteGrid } from '@/components/pastel/color/PaletteGrid';
import { ExportMenu } from '@/components/pastel/tools/ExportMenu';
import { Button } from '@/components/ui/Button';
import { Select } from '@/components/ui/Select';
import { Button } from '@/components/ui/button';
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from '@/components/ui/select';
import { useGeneratePalette } from '@/lib/pastel/api/queries';
import { Loader2, Palette } from 'lucide-react';
import { toast } from 'sonner';
@@ -73,16 +79,20 @@ export default function HarmonyPage() {
<h2 className="text-sm font-medium mb-4">Harmony Type</h2>
<div className="space-y-4">
<Select
label="Harmony"
value={harmonyType}
onChange={(e) => setHarmonyType(e.target.value as HarmonyType)}
onValueChange={(value) => setHarmonyType(value as HarmonyType)}
>
<option value="monochromatic">Monochromatic</option>
<option value="analogous">Analogous</option>
<option value="complementary">Complementary</option>
<option value="split-complementary">Split-Complementary</option>
<option value="triadic">Triadic</option>
<option value="tetradic">Tetradic (Square)</option>
<SelectTrigger>
<SelectValue placeholder="Select harmony" />
</SelectTrigger>
<SelectContent>
<SelectItem value="monochromatic">Monochromatic</SelectItem>
<SelectItem value="analogous">Analogous</SelectItem>
<SelectItem value="complementary">Complementary</SelectItem>
<SelectItem value="split-complementary">Split-Complementary</SelectItem>
<SelectItem value="triadic">Triadic</SelectItem>
<SelectItem value="tetradic">Tetradic (Square)</SelectItem>
</SelectContent>
</Select>
<p className="text-sm text-muted-foreground">

View File

@@ -2,8 +2,14 @@
import { useState, useMemo } from 'react';
import { ColorSwatch } from '@/components/pastel/color/ColorSwatch';
import { Input } from '@/components/ui/Input';
import { Select } from '@/components/ui/Select';
import { Input } from '@/components/ui/input';
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from '@/components/ui/select';
import { useNamedColors } from '@/lib/pastel/api/queries';
import { Loader2 } from 'lucide-react';
import { parse_color } from '@valknarthing/pastel-wasm';
@@ -57,9 +63,14 @@ export default function NamedColorsPage() {
/>
</div>
<div className="w-full sm:w-48">
<Select value={sortBy} onChange={(e) => setSortBy(e.target.value as 'name' | 'hue')}>
<option value="name">Sort by Name</option>
<option value="hue">Sort by Hue</option>
<Select value={sortBy} onValueChange={(value) => setSortBy(value as 'name' | 'hue')}>
<SelectTrigger>
<SelectValue placeholder="Sort by..." />
</SelectTrigger>
<SelectContent>
<SelectItem value="name">Sort by Name</SelectItem>
<SelectItem value="hue">Sort by Hue</SelectItem>
</SelectContent>
</Select>
</div>
</div>

View File

@@ -9,7 +9,7 @@ import { ManipulationPanel } from '@/components/pastel/tools/ManipulationPanel';
import { useColorInfo } from '@/lib/pastel/api/queries';
import { useColorHistory } from '@/lib/pastel/stores/historyStore';
import { Loader2, Share2, History, X } from 'lucide-react';
import { Button } from '@/components/ui/Button';
import { Button } from '@/components/ui/button';
import { toast } from 'sonner';
function PlaygroundContent() {

View File

@@ -3,7 +3,7 @@
import { useState } from 'react';
import { ColorPicker } from '@/components/pastel/color/ColorPicker';
import { ColorDisplay } from '@/components/pastel/color/ColorDisplay';
import { Button } from '@/components/ui/Button';
import { Button } from '@/components/ui/button';
import { useTextColor } from '@/lib/pastel/api/queries';
import { Loader2, Palette, Plus, X, CheckCircle2, XCircle } from 'lucide-react';
import { toast } from 'sonner';

View File

@@ -1,4 +1,8 @@
@import "tailwindcss";
@import "tw-animate-css";
@import "shadcn/tailwind.css";
@custom-variant dark (&:is(.dark *));
@source "../components/*.{js,ts,jsx,tsx}";
@source "../components/ui/*.{js,ts,jsx,tsx}";
@@ -222,3 +226,113 @@ html {
@utility gradient-brand {
background: linear-gradient(to right, #a78bfa, #f472b6, #22d3ee);
}
@theme inline {
--radius-sm: calc(var(--radius) - 4px);
--radius-md: calc(var(--radius) - 2px);
--radius-lg: var(--radius);
--radius-xl: calc(var(--radius) + 4px);
--radius-2xl: calc(var(--radius) + 8px);
--radius-3xl: calc(var(--radius) + 12px);
--radius-4xl: calc(var(--radius) + 16px);
--color-background: var(--background);
--color-foreground: var(--foreground);
--color-card: var(--card);
--color-card-foreground: var(--card-foreground);
--color-popover: var(--popover);
--color-popover-foreground: var(--popover-foreground);
--color-primary: var(--primary);
--color-primary-foreground: var(--primary-foreground);
--color-secondary: var(--secondary);
--color-secondary-foreground: var(--secondary-foreground);
--color-muted: var(--muted);
--color-muted-foreground: var(--muted-foreground);
--color-accent: var(--accent);
--color-accent-foreground: var(--accent-foreground);
--color-destructive: var(--destructive);
--color-border: var(--border);
--color-input: var(--input);
--color-ring: var(--ring);
--color-chart-1: var(--chart-1);
--color-chart-2: var(--chart-2);
--color-chart-3: var(--chart-3);
--color-chart-4: var(--chart-4);
--color-chart-5: var(--chart-5);
--color-sidebar: var(--sidebar);
--color-sidebar-foreground: var(--sidebar-foreground);
--color-sidebar-primary: var(--sidebar-primary);
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
--color-sidebar-accent: var(--sidebar-accent);
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
--color-sidebar-border: var(--sidebar-border);
--color-sidebar-ring: var(--sidebar-ring);
}
:root {
--radius: 0.625rem;
--background: oklch(1 0 0);
--foreground: oklch(0.145 0 0);
--card: oklch(1 0 0);
--card-foreground: oklch(0.145 0 0);
--popover: oklch(1 0 0);
--popover-foreground: oklch(0.145 0 0);
--primary: oklch(0.205 0 0);
--primary-foreground: oklch(0.985 0 0);
--secondary: oklch(0.97 0 0);
--secondary-foreground: oklch(0.205 0 0);
--muted: oklch(0.97 0 0);
--muted-foreground: oklch(0.556 0 0);
--accent: oklch(0.97 0 0);
--accent-foreground: oklch(0.205 0 0);
--destructive: oklch(0.577 0.245 27.325);
--border: oklch(0.922 0 0);
--input: oklch(0.922 0 0);
--ring: oklch(0.708 0 0);
--chart-1: oklch(0.646 0.222 41.116);
--chart-2: oklch(0.6 0.118 184.704);
--chart-3: oklch(0.398 0.07 227.392);
--chart-4: oklch(0.828 0.189 84.429);
--chart-5: oklch(0.769 0.188 70.08);
--sidebar: oklch(0.985 0 0);
--sidebar-foreground: oklch(0.145 0 0);
--sidebar-primary: oklch(0.205 0 0);
--sidebar-primary-foreground: oklch(0.985 0 0);
--sidebar-accent: oklch(0.97 0 0);
--sidebar-accent-foreground: oklch(0.205 0 0);
--sidebar-border: oklch(0.922 0 0);
--sidebar-ring: oklch(0.708 0 0);
}
.dark {
--background: oklch(0.145 0 0);
--foreground: oklch(0.985 0 0);
--card: oklch(0.205 0 0);
--card-foreground: oklch(0.985 0 0);
--popover: oklch(0.205 0 0);
--popover-foreground: oklch(0.985 0 0);
--primary: oklch(0.922 0 0);
--primary-foreground: oklch(0.205 0 0);
--secondary: oklch(0.269 0 0);
--secondary-foreground: oklch(0.985 0 0);
--muted: oklch(0.269 0 0);
--muted-foreground: oklch(0.708 0 0);
--accent: oklch(0.269 0 0);
--accent-foreground: oklch(0.985 0 0);
--destructive: oklch(0.704 0.191 22.216);
--border: oklch(1 0 0 / 10%);
--input: oklch(1 0 0 / 15%);
--ring: oklch(0.556 0 0);
--chart-1: oklch(0.488 0.243 264.376);
--chart-2: oklch(0.696 0.17 162.48);
--chart-3: oklch(0.769 0.188 70.08);
--chart-4: oklch(0.627 0.265 303.9);
--chart-5: oklch(0.645 0.246 16.439);
--sidebar: oklch(0.205 0 0);
--sidebar-foreground: oklch(0.985 0 0);
--sidebar-primary: oklch(0.488 0.243 264.376);
--sidebar-primary-foreground: oklch(0.985 0 0);
--sidebar-accent: oklch(0.269 0 0);
--sidebar-accent-foreground: oklch(0.985 0 0);
--sidebar-border: oklch(1 0 0 / 10%);
--sidebar-ring: oklch(0.556 0 0);
}