2026-06-07 01:28:35 -05:00
|
|
|
import { ChevronDown, ChevronUp, Search, X } from 'lucide-react';
|
|
|
|
|
import { Button } from '@/components/ui/button';
|
|
|
|
|
import { cn } from '@/lib/utils';
|
|
|
|
|
|
|
|
|
|
export default function SearchFilterPanel({
|
|
|
|
|
title = 'Search & filters',
|
|
|
|
|
collapsed,
|
|
|
|
|
onCollapsedChange,
|
|
|
|
|
hasFilters,
|
|
|
|
|
resultLabel,
|
|
|
|
|
sortLabel,
|
|
|
|
|
onClear,
|
|
|
|
|
children,
|
|
|
|
|
className,
|
|
|
|
|
variant = 'default',
|
2026-06-07 17:33:31 -05:00
|
|
|
headerActions,
|
2026-06-07 01:28:35 -05:00
|
|
|
}) {
|
|
|
|
|
const embedded = variant === 'embedded';
|
|
|
|
|
const ToggleIcon = collapsed ? ChevronUp : ChevronDown;
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<section className={cn(
|
|
|
|
|
embedded
|
|
|
|
|
? 'rounded-lg'
|
|
|
|
|
: 'rounded-xl border border-border/80 bg-card/95 shadow-sm shadow-black/15',
|
|
|
|
|
className,
|
|
|
|
|
)}>
|
|
|
|
|
<div className={cn('flex flex-wrap items-center gap-3', embedded ? 'py-1' : 'px-4 py-3')}>
|
|
|
|
|
<button
|
|
|
|
|
type="button"
|
|
|
|
|
onClick={() => onCollapsedChange?.(!collapsed)}
|
|
|
|
|
aria-expanded={!collapsed}
|
|
|
|
|
className="group inline-flex min-w-0 flex-1 items-center gap-3 rounded-md text-left focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
|
|
|
|
>
|
|
|
|
|
<span className="flex h-8 w-8 shrink-0 items-center justify-center rounded-lg border border-primary/15 bg-primary/10 text-primary">
|
|
|
|
|
<Search className="h-4 w-4" />
|
|
|
|
|
</span>
|
|
|
|
|
<span className="min-w-0">
|
|
|
|
|
<span className="block text-sm font-semibold text-foreground">{title}</span>
|
|
|
|
|
<span className="block truncate text-xs text-muted-foreground">
|
|
|
|
|
{[resultLabel, hasFilters ? 'filters active' : 'no filters', sortLabel].filter(Boolean).join(' · ')}
|
|
|
|
|
</span>
|
|
|
|
|
</span>
|
|
|
|
|
<ToggleIcon className="ml-auto h-4 w-4 shrink-0 text-muted-foreground transition-colors group-hover:text-foreground" />
|
|
|
|
|
</button>
|
|
|
|
|
|
|
|
|
|
{hasFilters && onClear && (
|
|
|
|
|
<Button type="button" variant="ghost" onClick={onClear} className="h-8 gap-2 px-2.5 text-xs">
|
|
|
|
|
<X className="h-3.5 w-3.5" />
|
|
|
|
|
Clear
|
|
|
|
|
</Button>
|
|
|
|
|
)}
|
2026-06-07 17:33:31 -05:00
|
|
|
{headerActions}
|
2026-06-07 01:28:35 -05:00
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{!collapsed && (
|
|
|
|
|
<div className={cn(
|
|
|
|
|
'space-y-3',
|
|
|
|
|
embedded ? 'pt-3' : 'border-t border-border/60 px-4 py-4',
|
|
|
|
|
)}>
|
|
|
|
|
{children}
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
</section>
|
|
|
|
|
);
|
|
|
|
|
}
|