openrag/frontend/components/filter-icon-popover.tsx

181 lines
4 KiB
TypeScript

"use client";
import React, { type SVGProps } from "react";
import { Button } from "@/components/ui/button";
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "@/components/ui/popover";
import {
Filter as FilterIcon,
Star,
Book,
FileText,
Folder,
Globe,
Calendar,
User,
Users,
Tag,
Briefcase,
Building2,
Cog,
Database,
Cpu,
Bot,
MessageSquare,
Search,
Shield,
Lock,
Key,
Link,
Mail,
Phone,
Check,
} from "lucide-react";
import { filterAccentClasses } from "./knowledge-filter-panel";
const ICON_MAP = {
Filter: FilterIcon,
Star,
Book,
FileText,
Folder,
Globe,
Calendar,
User,
Users,
Tag,
Briefcase,
Building2,
Cog,
Database,
Cpu,
Bot,
MessageSquare,
Search,
Shield,
Lock,
Key,
Link,
Mail,
Phone,
} as const;
export type IconKey = keyof typeof ICON_MAP;
function iconKeyToComponent(
key: string
): React.ComponentType<SVGProps<SVGSVGElement>> {
return (
(ICON_MAP as Record<string, React.ComponentType<SVGProps<SVGSVGElement>>>)[
key
] || FilterIcon
);
}
const COLORS = [
"zinc",
"pink",
"purple",
"indigo",
"emerald",
"amber",
"red",
] as const;
export type FilterColor = (typeof COLORS)[number];
const colorSwatchClasses = {
zinc: "bg-muted-foreground",
pink: "bg-accent-pink-foreground",
purple: "bg-accent-purple-foreground",
indigo: "bg-accent-indigo-foreground",
emerald: "bg-accent-emerald-foreground",
amber: "bg-accent-amber-foreground",
red: "bg-accent-red-foreground",
"": "bg-muted-foreground",
};
export interface FilterIconPopoverProps {
color: FilterColor;
iconKey: IconKey | string;
onColorChange: (c: FilterColor) => void;
onIconChange: (k: IconKey) => void;
triggerClassName?: string;
}
export function FilterIconPopover({
color,
iconKey,
onColorChange,
onIconChange,
triggerClassName,
}: FilterIconPopoverProps) {
const Icon = iconKeyToComponent(iconKey);
return (
<Popover>
<PopoverTrigger asChild>
<Button
type="button"
variant="outline"
size="icon"
className={"h-8 w-8 p-0 " + (triggerClassName || "")}
>
<span
className={
filterAccentClasses[color || ""] +
" inline-flex items-center justify-center rounded h-6 w-6"
}
>
<Icon className="h-3.5 w-3.5" />
</span>
</Button>
</PopoverTrigger>
<PopoverContent className="w-80" align="start">
<div className="space-y-3">
<div className="grid grid-cols-7 items-center gap-2">
{COLORS.map((c) => (
<button
key={c}
type="button"
onClick={() => onColorChange(c)}
className={
"flex items-center justify-center h-6 w-6 rounded-sm transition-colors " +
colorSwatchClasses[c || ""]
}
aria-label={c}
>
{c === color && <Check className="h-3.5 w-3.5" />}
</button>
))}
</div>
<div className="text-xs font-medium text-muted-foreground mt-2">
Icon
</div>
<div className="grid grid-cols-6 gap-2">
{(Object.keys(ICON_MAP) as IconKey[]).map((k) => {
const OptIcon = ICON_MAP[k];
const active = iconKey === k;
return (
<button
key={k}
type="button"
onClick={() => onIconChange(k)}
className={
"h-8 w-8 inline-flex items-center justify-center rounded border " +
(active ? "border-foreground" : "border-border")
}
aria-label={k}
>
<OptIcon className="h-4 w-4" />
</button>
);
})}
</div>
</div>
</PopoverContent>
</Popover>
);
}