Files
kit-ui/app/(app)/pastel/names/page.tsx

123 lines
4.0 KiB
TypeScript

'use client';
import { useState, useMemo } from 'react';
import { ColorSwatch } from '@/components/pastel/ColorSwatch';
import { Input } from '@/components/ui/input';
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from '@/components/ui/select';
import { Card, CardContent } from '@/components/ui/card';
import { AppPage } from '@/components/layout/AppPage';
import { useNamedColors } from '@/lib/pastel/api/queries';
import { Loader2 } from 'lucide-react';
import { parse_color } from '@valknarthing/pastel-wasm';
export default function NamedColorsPage() {
const [search, setSearch] = useState('');
const [sortBy, setSortBy] = useState<'name' | 'hue'>('name');
const { data, isLoading, isError } = useNamedColors();
const filteredColors = useMemo(() => {
if (!data) return [];
let colors = data.colors.filter(
(color) =>
color.name.toLowerCase().includes(search.toLowerCase()) ||
color.hex.toLowerCase().includes(search.toLowerCase())
);
if (sortBy === 'name') {
colors.sort((a, b) => a.name.localeCompare(b.name));
} else if (sortBy === 'hue') {
colors.sort((a, b) => {
const infoA = parse_color(a.hex);
const infoB = parse_color(b.hex);
return infoA.hsl[0] - infoB.hsl[0];
});
}
return colors;
}, [data, search, sortBy]);
return (
<AppPage
title="Named Colors"
description="Explore 148 CSS/X11 named colors"
>
<div className="space-y-8">
{/* Search and Filters */}
<div className="flex flex-col sm:flex-row gap-4">
<div className="flex-1">
<Input
type="text"
placeholder="Search by name or hex..."
value={search}
onChange={(e) => setSearch(e.target.value)}
/>
</div>
<div className="w-full sm:w-48">
<Select value={sortBy} onValueChange={(value) => setSortBy(value as 'name' | 'hue')}>
<SelectTrigger className="w-full">
<SelectValue placeholder="Sort by..." />
</SelectTrigger>
<SelectContent>
<SelectItem value="name">Sort by Name</SelectItem>
<SelectItem value="hue">Sort by Hue</SelectItem>
</SelectContent>
</Select>
</div>
</div>
{/* Colors Grid */}
<Card>
<CardContent className="pt-6">
{isLoading && (
<div className="flex items-center justify-center py-12">
<Loader2 className="h-8 w-8 animate-spin text-muted-foreground" />
</div>
)}
{isError && (
<div className="text-center py-12 text-destructive">
Failed to load named colors
</div>
)}
{filteredColors.length > 0 && (
<>
<div className="mb-4 text-sm text-muted-foreground">
Showing {filteredColors.length} colors
</div>
<div className="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-6 gap-6">
{filteredColors.map((color) => (
<div key={color.name} className="flex flex-col items-center gap-2">
<ColorSwatch color={color.hex} showLabel={false} />
<div className="text-center">
<div className="text-sm font-medium">{color.name}</div>
<div className="text-xs font-mono text-muted-foreground">
{color.hex}
</div>
</div>
</div>
))}
</div>
</>
)}
{filteredColors.length === 0 && !isLoading && !isError && (
<div className="text-center py-12 text-muted-foreground">
No colors match your search
</div>
)}
</CardContent>
</Card>
</div>
</AppPage>
);
}