Split the 316-line vendors index into VendorToolbar, VendorGrid, VendorList, and PerPageSelector under components/vendors/. Page now owns only search-param state and query orchestration. Replace generic Error throws in lib/directus.ts with a DirectusError class carrying status, statusText, collection, url, and parsed body. Surface useLocalStorage read/write failures via console.warn instead of swallowing them.
38 lines
1.0 KiB
TypeScript
38 lines
1.0 KiB
TypeScript
import { Button } from '~/components/ui/button'
|
|
import { cn } from '~/lib/utils'
|
|
|
|
type Props = {
|
|
value: number
|
|
options?: readonly number[]
|
|
onChange: (value: number) => void
|
|
}
|
|
|
|
const DEFAULT_OPTIONS = [12, 24, 48] as const
|
|
|
|
export function PerPageSelector({ value, options = DEFAULT_OPTIONS, onChange }: Props) {
|
|
return (
|
|
<div className="mt-5 flex items-center justify-center gap-2">
|
|
<span className="text-sm">Results per page:</span>
|
|
<div className="inline-flex rounded-md border">
|
|
{options.map((n, i) => (
|
|
<Button
|
|
key={n}
|
|
variant={value === n ? 'secondary' : 'ghost'}
|
|
size="sm"
|
|
disabled={value === n}
|
|
onClick={() => onChange(n)}
|
|
className={cn(
|
|
'rounded-none',
|
|
i === 0 && 'rounded-l-md',
|
|
i === options.length - 1 && 'rounded-r-md',
|
|
i > 0 && 'border-l',
|
|
)}
|
|
>
|
|
{n}
|
|
</Button>
|
|
))}
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|