BillTracker/client/components/SearchFilterPanel.jsx

65 lines
2.2 KiB
JavaScript

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',
}) {
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>
)}
</div>
{!collapsed && (
<div className={cn(
'space-y-3',
embedded ? 'pt-3' : 'border-t border-border/60 px-4 py-4',
)}>
{children}
</div>
)}
</section>
);
}