Keep/keep-notes/components/label-filter.tsx

131 lines
3.8 KiB
TypeScript

'use client'
import { useState, useEffect } from 'react'
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuTrigger,
DropdownMenuCheckboxItem,
DropdownMenuSeparator,
DropdownMenuLabel,
} from '@/components/ui/dropdown-menu'
import { Button } from '@/components/ui/button'
import { Badge } from '@/components/ui/badge'
import { Filter, X } from 'lucide-react'
import { getAllLabelColors, getLabelColor } from '@/lib/label-storage'
import { LABEL_COLORS } from '@/lib/types'
import { cn } from '@/lib/utils'
interface LabelFilterProps {
selectedLabels: string[]
onFilterChange: (labels: string[]) => void
}
export function LabelFilter({ selectedLabels, onFilterChange }: LabelFilterProps) {
const [allLabels, setAllLabels] = useState<string[]>([])
useEffect(() => {
// Load all labels from localStorage
const labelColors = getAllLabelColors()
setAllLabels(Object.keys(labelColors).sort())
}, [])
const handleToggleLabel = (label: string) => {
if (selectedLabels.includes(label)) {
onFilterChange(selectedLabels.filter(l => l !== label))
} else {
onFilterChange([...selectedLabels, label])
}
}
const handleClearAll = () => {
onFilterChange([])
}
if (allLabels.length === 0) return null
return (
<div className="flex items-center gap-2">
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="ghost" size="sm" className="h-9">
<Filter className="h-4 w-4 mr-2" />
Filter by Label
{selectedLabels.length > 0 && (
<Badge variant="secondary" className="ml-2 h-5 min-w-5 px-1.5">
{selectedLabels.length}
</Badge>
)}
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end" className="w-64">
<DropdownMenuLabel className="flex items-center justify-between">
Filter by Labels
{selectedLabels.length > 0 && (
<Button
variant="ghost"
size="sm"
onClick={handleClearAll}
className="h-6 text-xs"
>
Clear
</Button>
)}
</DropdownMenuLabel>
<DropdownMenuSeparator />
{allLabels.map((label) => {
const colorName = getLabelColor(label)
const colorClasses = LABEL_COLORS[colorName]
const isSelected = selectedLabels.includes(label)
return (
<DropdownMenuCheckboxItem
key={label}
checked={isSelected}
onCheckedChange={() => handleToggleLabel(label)}
>
<Badge
className={cn(
'text-xs border mr-2',
colorClasses.bg,
colorClasses.text,
colorClasses.border
)}
>
{label}
</Badge>
</DropdownMenuCheckboxItem>
)
})}
</DropdownMenuContent>
</DropdownMenu>
{/* Active filters display */}
{selectedLabels.length > 0 && (
<div className="flex flex-wrap gap-1">
{selectedLabels.map((label) => {
const colorName = getLabelColor(label)
const colorClasses = LABEL_COLORS[colorName]
return (
<Badge
key={label}
className={cn(
'text-xs border cursor-pointer pr-1',
colorClasses.bg,
colorClasses.text,
colorClasses.border
)}
onClick={() => handleToggleLabel(label)}
>
{label}
<X className="h-3 w-3 ml-1" />
</Badge>
)
})}
</div>
)}
</div>
)
}