Harshith Mullapudi 1fa7fd93d5
Feat: spaces (#51)
* feat: Episode ingestion update
Benchmarking CORE

* Feat: Spaces in knowledge graph

* fix: remove daily assignment

* Feat: add spaces

* Feat: spaces

---------

Co-authored-by: Manoj K <saimanoj58@gmail.com>
2025-08-21 11:53:45 +05:30

174 lines
5.4 KiB
TypeScript

import {
Button,
Input,
ScrollArea,
Tabs,
TabsContent,
TabsList,
TabsTrigger,
} from "../ui";
import * as LucideIcons from "lucide-react";
import { useState } from "react";
import { emojiData } from "./emoji-data";
import { cn } from "~/lib/utils";
interface IconPickerProps {
onSelectIcon?: (icon: string, color: string) => void;
onSelectEmoji?: (emoji: string) => void;
onRemove?: () => void;
onUploadIcon?: (file: File) => void;
}
const colorOptions = [
"#000",
"oklch(66% 0.1835 292)",
"oklch(66% 0.1835 169)",
"oklch(66% 0.1835 30)",
"oklch(66% 0.1835 308)",
"oklch(66% 0.1835 339)",
"oklch(66% 0.1835 277)",
"oklch(66% 0.1835 30)",
"oklch(66% 0.1835 71)",
"oklch(66% 0.1835 228)",
];
export function IconPicker({
onSelectIcon,
onSelectEmoji,
onRemove,
}: IconPickerProps) {
const [activeTab, setActiveTab] = useState("icons");
const [iconSearch, setIconSearch] = useState("");
const [emojiSearch, setEmojiSearch] = useState("");
const [selectedColor, setSelectedColor] = useState(colorOptions[0]);
// Filter icons based on search
const filteredIcons = Object.keys(LucideIcons)
.filter(
(iconName) =>
iconName !== "createLucideIcon" &&
iconName.toLowerCase().includes(iconSearch.toLowerCase()),
)
.slice(0, 100); // Limit to 120 icons for performance
// Filter emojis based on search
const filteredEmojis = emojiSearch
? emojiData.filter((emoji) =>
emoji.name.toLowerCase().includes(emojiSearch.toLowerCase()),
)
: emojiData;
return (
<div className="w-full max-w-md overflow-hidden rounded-lg">
<Tabs
defaultValue="icons"
value={activeTab}
onValueChange={setActiveTab}
className="w-full"
>
<TabsList className="grid w-full grid-cols-2">
<TabsTrigger value="icons" className="">
Icons
</TabsTrigger>
<TabsTrigger value="emojis" className="">
Emojis
</TabsTrigger>
</TabsList>
{/* Icons Tab */}
<TabsContent value="icons" className="p-0">
<div className="p-1">
<div className="mb-4 flex flex-wrap gap-2">
{colorOptions.map((color, index) => (
<button
key={index}
className={cn(
"h-6 w-6 rounded-full",
selectedColor === color ? "ring-2 ring-white" : "",
)}
style={{ backgroundColor: color }}
onClick={() => setSelectedColor(color)}
/>
))}
</div>
<div className="relative mb-4">
<LucideIcons.Search className="absolute top-1/2 left-3 h-4 w-4 -translate-y-1/2 transform" />
<Input
placeholder="Search Icons..."
className="pl-9"
value={iconSearch}
onChange={(e) => setIconSearch(e.target.value)}
/>
</div>
<ScrollArea className="h-[250px]">
<div className="grid grid-cols-8 gap-2">
{filteredIcons.map((iconName) => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const IconComponent = (LucideIcons as any)[iconName];
return (
<Button
key={iconName}
className="text-foreground flex items-center justify-center p-1"
size="sm"
variant="ghost"
onClick={() =>
onSelectIcon && onSelectIcon(iconName, selectedColor)
}
>
<IconComponent
style={
selectedColor !== "#000"
? { color: selectedColor }
: {}
}
className={cn("text-foreground")}
/>
</Button>
);
})}
</div>
</ScrollArea>
</div>
</TabsContent>
{/* Emojis Tab */}
<TabsContent value="emojis" className="p-0">
<div className="p-1">
<div className="relative mb-4">
<LucideIcons.Search className="absolute top-1/2 left-3 h-4 w-4 -translate-y-1/2 transform" />
<Input
placeholder="Search Icons..."
className="pl-9"
value={iconSearch}
onChange={(e) => setEmojiSearch(e.target.value)}
/>
</div>
<ScrollArea className="h-[250px]">
<div className="grid grid-cols-8 gap-1">
{filteredEmojis.map((emoji) => (
<Button
key={emoji.id}
className="flex items-center justify-center p-1"
size="sm"
variant="ghost"
onClick={() => onSelectEmoji && onSelectEmoji(emoji.emoji)}
>
{emoji.emoji}
</Button>
))}
</div>
</ScrollArea>
</div>
</TabsContent>
</Tabs>
<div className="border-border flex justify-end border-t pt-1">
<Button variant="secondary" onClick={onRemove}>
Remove
</Button>
</div>
</div>
);
}