make filter icon required
This commit is contained in:
parent
ef98a5a826
commit
60cb732ce2
7 changed files with 48 additions and 61 deletions
|
|
@ -7,7 +7,6 @@ import {
|
|||
PopoverTrigger,
|
||||
} from "@/components/ui/popover";
|
||||
import {
|
||||
File,
|
||||
Book,
|
||||
Scroll,
|
||||
Library,
|
||||
|
|
@ -32,13 +31,13 @@ import {
|
|||
ShoppingCart,
|
||||
ShoppingBag,
|
||||
Check,
|
||||
Plus,
|
||||
Filter,
|
||||
} from "lucide-react";
|
||||
import { filterAccentClasses } from "./knowledge-filter-panel";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
const ICON_MAP = {
|
||||
file: File,
|
||||
filter: Filter,
|
||||
book: Book,
|
||||
scroll: Scroll,
|
||||
library: Library,
|
||||
|
|
@ -87,21 +86,20 @@ const COLORS = [
|
|||
export type FilterColor = (typeof COLORS)[number];
|
||||
|
||||
const colorSwatchClasses = {
|
||||
zinc: "bg-muted-foreground text-accent-foreground",
|
||||
pink: "bg-accent-pink-foreground text-accent-pink",
|
||||
purple: "bg-accent-purple-foreground text-accent-purple",
|
||||
indigo: "bg-accent-indigo-foreground text-accent-indigo",
|
||||
emerald: "bg-accent-emerald-foreground text-accent-emerald",
|
||||
amber: "bg-accent-amber-foreground text-accent-amber",
|
||||
red: "bg-accent-red-foreground text-accent-red",
|
||||
"": "bg-muted-foreground text-accent-foreground",
|
||||
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",
|
||||
};
|
||||
|
||||
export interface FilterIconPopoverProps {
|
||||
color: FilterColor;
|
||||
iconKey?: IconKey | undefined;
|
||||
iconKey: IconKey;
|
||||
onColorChange: (c: FilterColor) => void;
|
||||
onIconChange: (k: IconKey | undefined) => void;
|
||||
onIconChange: (k: IconKey) => void;
|
||||
triggerClassName?: string;
|
||||
}
|
||||
|
||||
|
|
@ -118,13 +116,12 @@ export function FilterIconPopover({
|
|||
<PopoverTrigger asChild>
|
||||
<button
|
||||
className={cn(
|
||||
"h-10 w-10 min-w-10 min-h-10 rounded-sm flex items-center justify-center transition-colors",
|
||||
filterAccentClasses[color || ""],
|
||||
"h-10 w-10 min-w-10 min-h-10 rounded-md flex items-center justify-center transition-colors",
|
||||
filterAccentClasses[color],
|
||||
triggerClassName
|
||||
)}
|
||||
>
|
||||
{Icon && <Icon className="h-5 w-5" />}
|
||||
{!Icon && <Plus className="h-5 w-5" />}
|
||||
</button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-80" align="start">
|
||||
|
|
@ -136,8 +133,8 @@ export function FilterIconPopover({
|
|||
type="button"
|
||||
onClick={() => onColorChange(c)}
|
||||
className={cn(
|
||||
"flex items-center justify-center h-6 w-6 rounded-sm transition-colors",
|
||||
colorSwatchClasses[c || ""]
|
||||
"flex items-center justify-center h-6 w-6 rounded-sm transition-colors text-primary",
|
||||
colorSwatchClasses[c]
|
||||
)}
|
||||
aria-label={c}
|
||||
>
|
||||
|
|
@ -153,18 +150,10 @@ export function FilterIconPopover({
|
|||
<button
|
||||
key={k}
|
||||
type="button"
|
||||
onClick={() => {
|
||||
if (active) {
|
||||
onIconChange(undefined);
|
||||
} else {
|
||||
onIconChange(k as IconKey);
|
||||
}
|
||||
}}
|
||||
onClick={() => onIconChange(k as IconKey)}
|
||||
className={
|
||||
"h-8 w-8 inline-flex items-center hover:text-foreground justify-center rounded border " +
|
||||
(active
|
||||
? "border-muted-foreground text-foreground"
|
||||
: "border-0 text-muted-foreground")
|
||||
"h-8 w-8 inline-flex items-center hover:text-foreground justify-center rounded " +
|
||||
(active ? "bg-muted text-primary" : "text-muted-foreground")
|
||||
}
|
||||
aria-label={k}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
import { useState } from "react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Loader2, Plus, X } from "lucide-react";
|
||||
import { Loader2, Plus } from "lucide-react";
|
||||
import { cn } from "@/lib/utils";
|
||||
import {
|
||||
useGetFiltersSearchQuery,
|
||||
|
|
@ -25,8 +25,8 @@ interface ParsedQueryData {
|
|||
};
|
||||
limit: number;
|
||||
scoreThreshold: number;
|
||||
color?: FilterColor;
|
||||
icon?: IconKey;
|
||||
color: FilterColor;
|
||||
icon: IconKey;
|
||||
}
|
||||
|
||||
interface KnowledgeFilterListProps {
|
||||
|
|
@ -106,13 +106,13 @@ export function KnowledgeFilterList({
|
|||
<div className="flex flex-col gap-1 flex-1 min-w-0">
|
||||
<div className="flex items-center gap-2">
|
||||
{(() => {
|
||||
const parsed = parseQueryData(filter.query_data);
|
||||
const parsed = parseQueryData(filter.query_data) as ParsedQueryData;
|
||||
const Icon = iconKeyToComponent(parsed.icon);
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
"flex items-center justify-center w-5 h-5 rounded transition-colors",
|
||||
filterAccentClasses[parsed.color || ""],
|
||||
filterAccentClasses[parsed.color],
|
||||
parsed.color === "zinc" &&
|
||||
"group-hover:bg-background group-[.active]:bg-background"
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,11 @@ import { useDeleteFilter } from "@/app/api/mutations/useDeleteFilter";
|
|||
import { useUpdateFilter } from "@/app/api/mutations/useUpdateFilter";
|
||||
import { useCreateFilter } from "@/app/api/mutations/useCreateFilter";
|
||||
import { useGetSearchAggregations } from "@/src/app/api/queries/useGetSearchAggregations";
|
||||
import { FilterIconPopover, IconKey } from "@/components/filter-icon-popover";
|
||||
import {
|
||||
FilterColor,
|
||||
FilterIconPopover,
|
||||
IconKey,
|
||||
} from "@/components/filter-icon-popover";
|
||||
|
||||
interface FacetBucket {
|
||||
key: string;
|
||||
|
|
@ -28,18 +32,14 @@ interface AvailableFacets {
|
|||
connector_types: FacetBucket[];
|
||||
}
|
||||
|
||||
export const filterAccentClasses: Record<
|
||||
"zinc" | "pink" | "purple" | "indigo" | "emerald" | "amber" | "red" | "",
|
||||
string
|
||||
> = {
|
||||
zinc: "bg-accent text-muted-foreground",
|
||||
export const filterAccentClasses: Record<FilterColor, string> = {
|
||||
zinc: "bg-muted text-muted-foreground",
|
||||
pink: "bg-accent-pink text-accent-pink-foreground",
|
||||
purple: "bg-accent-purple text-accent-purple-foreground",
|
||||
indigo: "bg-accent-indigo text-accent-indigo-foreground",
|
||||
emerald: "bg-accent-emerald text-accent-emerald-foreground",
|
||||
amber: "bg-accent-amber text-accent-amber-foreground",
|
||||
red: "bg-accent-red text-accent-red-foreground",
|
||||
"": "bg-accent text-muted-foreground",
|
||||
};
|
||||
|
||||
export function KnowledgeFilterPanel() {
|
||||
|
|
@ -59,10 +59,8 @@ export function KnowledgeFilterPanel() {
|
|||
const [name, setName] = useState("");
|
||||
const [description, setDescription] = useState("");
|
||||
const [isSaving, setIsSaving] = useState(false);
|
||||
const [color, setColor] = useState<
|
||||
"zinc" | "pink" | "purple" | "indigo" | "emerald" | "amber" | "red"
|
||||
>("zinc");
|
||||
const [iconKey, setIconKey] = useState<IconKey>();
|
||||
const [color, setColor] = useState<FilterColor>("zinc");
|
||||
const [iconKey, setIconKey] = useState<IconKey>("filter");
|
||||
|
||||
// Filter configuration states (mirror search page exactly)
|
||||
const [query, setQuery] = useState("");
|
||||
|
|
@ -107,8 +105,8 @@ export function KnowledgeFilterPanel() {
|
|||
setScoreThreshold(parsedFilterData.scoreThreshold || 0);
|
||||
setName(selectedFilter.name);
|
||||
setDescription(selectedFilter.description || "");
|
||||
setColor(parsedFilterData.color || "zinc");
|
||||
setIconKey(parsedFilterData.icon as IconKey);
|
||||
setColor(parsedFilterData.color);
|
||||
setIconKey(parsedFilterData.icon);
|
||||
}
|
||||
}, [selectedFilter, parsedFilterData]);
|
||||
|
||||
|
|
@ -121,8 +119,8 @@ export function KnowledgeFilterPanel() {
|
|||
setScoreThreshold(parsedFilterData.scoreThreshold || 0);
|
||||
setName("");
|
||||
setDescription("");
|
||||
setColor(parsedFilterData.color || "zinc");
|
||||
setIconKey(parsedFilterData.icon as IconKey);
|
||||
setColor(parsedFilterData.color);
|
||||
setIconKey(parsedFilterData.icon);
|
||||
}
|
||||
}, [createMode, parsedFilterData]);
|
||||
|
||||
|
|
@ -268,7 +266,7 @@ export function KnowledgeFilterPanel() {
|
|||
color={color}
|
||||
iconKey={iconKey}
|
||||
onColorChange={setColor}
|
||||
onIconChange={(k) => setIconKey(k)}
|
||||
onIconChange={setIconKey}
|
||||
/>
|
||||
<Input
|
||||
id="filter-name"
|
||||
|
|
|
|||
|
|
@ -2116,7 +2116,7 @@ function ChatPage() {
|
|||
<div className="flex items-center gap-2 px-4 pt-3 pb-1">
|
||||
<span
|
||||
className={`inline-flex items-center gap-1 px-2 py-1 rounded-full text-xs font-medium transition-colors ${
|
||||
filterAccentClasses[parsedFilterData?.color || ""]
|
||||
filterAccentClasses[parsedFilterData?.color || "zinc"]
|
||||
}`}
|
||||
>
|
||||
@filter:{selectedFilter.name}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,8 @@
|
|||
--accent-foreground: 0 0% 0%;
|
||||
--destructive: 0 72% 51%;
|
||||
--destructive-foreground: 0 0% 100%;
|
||||
--warning: 48, 96%, 89%;
|
||||
--warning-foreground: 26, 90%, 37%;
|
||||
--border: 240 4.8% 95.9%;
|
||||
--input: 240 6% 90%;
|
||||
--ring: 0 0% 0%;
|
||||
|
|
@ -49,10 +51,6 @@
|
|||
--component-icon: #d8598a;
|
||||
--flow-icon: #2f67d0;
|
||||
|
||||
/* Warning */
|
||||
--warning: 48 96.6% 76.7%;
|
||||
--warning-foreground: 240 6% 10%;
|
||||
|
||||
--radius: 0.5rem;
|
||||
}
|
||||
|
||||
|
|
@ -75,6 +73,8 @@
|
|||
--accent-foreground: 0 0% 100%;
|
||||
--destructive: 0 84% 60%;
|
||||
--destructive-foreground: 0 0% 100%;
|
||||
--warning: 22, 78%, 26%;
|
||||
--warning-foreground: 46, 97%, 65%;
|
||||
--border: 240 3.7% 15.9%;
|
||||
--input: 240 5% 34%;
|
||||
--ring: 0 0% 100%;
|
||||
|
|
|
|||
|
|
@ -256,7 +256,7 @@ function SearchPage() {
|
|||
{selectedFilter?.name && (
|
||||
<div
|
||||
className={`flex items-center gap-1 h-full px-1.5 py-0.5 rounded max-w-[300px] ${
|
||||
filterAccentClasses[parsedFilterData?.color || ""]
|
||||
filterAccentClasses[parsedFilterData?.color || "zinc"]
|
||||
}`}
|
||||
>
|
||||
<span className="truncate">{selectedFilter?.name}</span>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
"use client";
|
||||
|
||||
import { FilterColor, IconKey } from "@/components/filter-icon-popover";
|
||||
import React, {
|
||||
createContext,
|
||||
type ReactNode,
|
||||
|
|
@ -27,9 +28,8 @@ export interface ParsedQueryData {
|
|||
};
|
||||
limit: number;
|
||||
scoreThreshold: number;
|
||||
// Optional visual metadata for UI
|
||||
color?: "zinc" | "pink" | "purple" | "indigo" | "emerald" | "amber" | "red";
|
||||
icon?: string; // lucide icon key we store in the UI mapping
|
||||
color: FilterColor;
|
||||
icon: IconKey;
|
||||
}
|
||||
|
||||
interface KnowledgeFilterContextType {
|
||||
|
|
@ -54,7 +54,7 @@ export function useKnowledgeFilter() {
|
|||
const context = useContext(KnowledgeFilterContext);
|
||||
if (context === undefined) {
|
||||
throw new Error(
|
||||
"useKnowledgeFilter must be used within a KnowledgeFilterProvider",
|
||||
"useKnowledgeFilter must be used within a KnowledgeFilterProvider"
|
||||
);
|
||||
}
|
||||
return context;
|
||||
|
|
@ -127,7 +127,7 @@ export function KnowledgeFilterProvider({
|
|||
limit: 10,
|
||||
scoreThreshold: 0,
|
||||
color: "zinc",
|
||||
icon: "Filter",
|
||||
icon: "filter",
|
||||
});
|
||||
setIsPanelOpen(true);
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue