mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-06-27 07:54:19 +00:00
b73847f1a6
* feat: add emoji support to knowledge bases and pipelines * feat: add optional emoji property to ExternalKBCardVO for enhanced knowledge base representation
254 lines
4.9 KiB
TypeScript
254 lines
4.9 KiB
TypeScript
import React, { useState } from 'react';
|
|
import { Button } from '@/components/ui/button';
|
|
import {
|
|
Popover,
|
|
PopoverContent,
|
|
PopoverTrigger,
|
|
} from '@/components/ui/popover';
|
|
|
|
interface EmojiPickerProps {
|
|
value?: string;
|
|
onChange: (emoji: string) => void;
|
|
disabled?: boolean;
|
|
}
|
|
|
|
// 扩展的emoji分类
|
|
const EMOJI_CATEGORIES = {
|
|
common: [
|
|
'⚙️',
|
|
'📚',
|
|
'🔗',
|
|
'📁',
|
|
'💡',
|
|
'🎯',
|
|
'✨',
|
|
'🚀',
|
|
'📝',
|
|
'🔧',
|
|
'⚡',
|
|
'🔥',
|
|
'💎',
|
|
'🎨',
|
|
'🎭',
|
|
],
|
|
objects: [
|
|
'📦',
|
|
'📂',
|
|
'📋',
|
|
'📌',
|
|
'🔖',
|
|
'💼',
|
|
'🗂️',
|
|
'📮',
|
|
'🗃️',
|
|
'📊',
|
|
'📈',
|
|
'📉',
|
|
'🗄️',
|
|
'📇',
|
|
'🗳️',
|
|
],
|
|
symbols: [
|
|
'🔴',
|
|
'🟠',
|
|
'🟡',
|
|
'🟢',
|
|
'🔵',
|
|
'🟣',
|
|
'⚪',
|
|
'⚫',
|
|
'🟤',
|
|
'🔺',
|
|
'🔻',
|
|
'🔶',
|
|
'🔷',
|
|
'🔸',
|
|
'🔹',
|
|
],
|
|
nature: [
|
|
'🌟',
|
|
'⭐',
|
|
'🌈',
|
|
'💧',
|
|
'🌍',
|
|
'🌙',
|
|
'☀️',
|
|
'🌱',
|
|
'🌲',
|
|
'🌳',
|
|
'🌴',
|
|
'🌵',
|
|
'🌾',
|
|
'🍀',
|
|
'🌻',
|
|
],
|
|
faces: [
|
|
'😀',
|
|
'😊',
|
|
'🤔',
|
|
'😎',
|
|
'🤖',
|
|
'👾',
|
|
'💬',
|
|
'💭',
|
|
'❤️',
|
|
'⚠️',
|
|
'✅',
|
|
'❌',
|
|
'🎉',
|
|
'🎊',
|
|
'🎈',
|
|
],
|
|
tech: [
|
|
'💻',
|
|
'📱',
|
|
'⌨️',
|
|
'🖥️',
|
|
'🖱️',
|
|
'💾',
|
|
'💿',
|
|
'📀',
|
|
'🔌',
|
|
'🔋',
|
|
'📡',
|
|
'🛰️',
|
|
'🖨️',
|
|
'🖲️',
|
|
'💽',
|
|
],
|
|
science: [
|
|
'🔬',
|
|
'🔭',
|
|
'⚗️',
|
|
'🧪',
|
|
'🧬',
|
|
'🧫',
|
|
'🩺',
|
|
'💊',
|
|
'💉',
|
|
'🌡️',
|
|
'🧲',
|
|
'⚛️',
|
|
'🧬',
|
|
'🦠',
|
|
'🧫',
|
|
],
|
|
business: [
|
|
'💼',
|
|
'📊',
|
|
'📈',
|
|
'💰',
|
|
'💵',
|
|
'💴',
|
|
'💶',
|
|
'💷',
|
|
'💳',
|
|
'💸',
|
|
'📉',
|
|
'💹',
|
|
'🏦',
|
|
'🏢',
|
|
'🏭',
|
|
],
|
|
};
|
|
|
|
const CATEGORY_LABELS: { [key: string]: string } = {
|
|
common: '常用',
|
|
objects: '物品',
|
|
symbols: '符号',
|
|
nature: '自然',
|
|
faces: '表情',
|
|
tech: '科技',
|
|
science: '科学',
|
|
business: '商业',
|
|
};
|
|
|
|
// 每个分类的代表性 emoji(用于分页按钮)
|
|
const CATEGORY_ICONS: { [key: string]: string } = {
|
|
common: '⭐',
|
|
objects: '📦',
|
|
symbols: '🔴',
|
|
nature: '🌟',
|
|
faces: '😀',
|
|
tech: '💻',
|
|
science: '🔬',
|
|
business: '💼',
|
|
};
|
|
|
|
export default function EmojiPicker({
|
|
value,
|
|
onChange,
|
|
disabled,
|
|
}: EmojiPickerProps) {
|
|
const [open, setOpen] = useState(false);
|
|
const [activeCategory, setActiveCategory] = useState<string>('common');
|
|
|
|
const handleEmojiSelect = (emoji: string) => {
|
|
onChange(emoji);
|
|
setOpen(false);
|
|
};
|
|
|
|
const currentEmojis =
|
|
EMOJI_CATEGORIES[activeCategory as keyof typeof EMOJI_CATEGORIES];
|
|
|
|
return (
|
|
<Popover open={open} onOpenChange={setOpen}>
|
|
<PopoverTrigger asChild>
|
|
<Button
|
|
variant="outline"
|
|
disabled={disabled}
|
|
className="w-16 h-16 text-3xl p-0 hover:bg-gray-100 dark:hover:bg-gray-800"
|
|
type="button"
|
|
>
|
|
{value || '😀'}
|
|
</Button>
|
|
</PopoverTrigger>
|
|
<PopoverContent className="w-80 p-4" align="start">
|
|
<div className="space-y-3">
|
|
{/* 分类标题 */}
|
|
<h3 className="text-sm font-medium text-gray-700 dark:text-gray-300">
|
|
{CATEGORY_LABELS[activeCategory]}
|
|
</h3>
|
|
|
|
{/* Emoji 网格 */}
|
|
<div className="grid grid-cols-6 gap-1">
|
|
{currentEmojis.map((emoji, index) => (
|
|
<button
|
|
key={`${activeCategory}-${index}`}
|
|
type="button"
|
|
onClick={() => handleEmojiSelect(emoji)}
|
|
className={`w-10 h-10 text-xl rounded hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors flex items-center justify-center ${
|
|
value === emoji ? 'bg-gray-200 dark:bg-gray-700' : ''
|
|
}`}
|
|
>
|
|
{emoji}
|
|
</button>
|
|
))}
|
|
</div>
|
|
|
|
{/* 分类切换按钮 */}
|
|
<div className="pt-2 border-t border-gray-200 dark:border-gray-700">
|
|
<div className="flex justify-center gap-1">
|
|
{Object.keys(EMOJI_CATEGORIES).map((category) => (
|
|
<button
|
|
key={category}
|
|
type="button"
|
|
onClick={() => setActiveCategory(category)}
|
|
className={`w-7 h-7 text-base rounded transition-colors flex items-center justify-center ${
|
|
activeCategory === category
|
|
? 'bg-gray-200 dark:bg-gray-700'
|
|
: 'hover:bg-gray-100 dark:hover:bg-gray-800'
|
|
}`}
|
|
title={CATEGORY_LABELS[category]}
|
|
>
|
|
{CATEGORY_ICONS[category]}
|
|
</button>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</PopoverContent>
|
|
</Popover>
|
|
);
|
|
}
|