Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 | 1x 1x 13x 13x 52x 52x 52x 3x | /**
* Template strip for create collection (blank + starter schemas).
*/
import type { ComponentType } from 'react';
import { FileText, Package, Users, Square } from 'lucide-react';
import { cn } from '@/lib/utils';
import {
BLANK_TEMPLATE_ID,
COLLECTION_TEMPLATES,
type CollectionTemplate,
} from '@/lib/collectionTemplates';
const ICONS: Record<string, ComponentType<{ className?: string }>> = {
[BLANK_TEMPLATE_ID]: Square,
posts: FileText,
products: Package,
contacts: Users,
};
export interface CollectionTemplatePickerProps {
selectedId: string;
onSelect: (templateId: string) => void;
disabled?: boolean;
/** Compact cards for empty-state grids */
variant?: 'strip' | 'grid';
className?: string;
}
const blankCard: Pick<
CollectionTemplate,
'id' | 'label' | 'description'
> = {
id: BLANK_TEMPLATE_ID,
label: 'Blank',
description: 'Start with an empty schema',
};
export default function CollectionTemplatePicker({
selectedId,
onSelect,
disabled = false,
variant = 'strip',
className,
}: CollectionTemplatePickerProps) {
const items = [blankCard, ...COLLECTION_TEMPLATES];
return (
<div
className={cn(
variant === 'grid'
? 'grid gap-2 sm:grid-cols-2'
: 'grid gap-2 sm:grid-cols-2 lg:grid-cols-4',
className,
)}
data-testid="collection-template-picker"
role="listbox"
aria-label="Collection templates"
>
{items.map((item) => {
const Icon = ICONS[item.id] ?? Square;
const selected = selectedId === item.id;
return (
<button
key={item.id}
type="button"
role="option"
aria-selected={selected}
disabled={disabled}
data-testid={`template-${item.id}`}
onClick={() => onSelect(item.id)}
className={cn(
'flex flex-col items-start gap-1 rounded-lg border p-3 text-left transition-colors',
'hover:bg-accent/50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring',
selected && 'border-primary bg-primary/5 ring-1 ring-primary',
disabled && 'pointer-events-none opacity-50',
)}
>
<div className="flex items-center gap-2">
<Icon className="h-4 w-4 text-muted-foreground" />
<span className="text-sm font-medium">{item.label}</span>
</div>
<span className="text-xs text-muted-foreground leading-snug">
{item.description}
</span>
</button>
);
})}
</div>
);
}
|