diff --git a/src/components/features/QuickPhraseItem.tsx b/src/components/features/QuickPhraseItem.tsx new file mode 100644 index 0000000..385bf65 --- /dev/null +++ b/src/components/features/QuickPhraseItem.tsx @@ -0,0 +1,123 @@ +'use client'; + +import { useState } from 'react'; +import * as LucideIcons from 'lucide-react'; +import type { QuickPhrase } from '@/types'; +import { cn } from '@/lib/utils'; +import { Tooltip } from '@/components/ui/Tooltip'; + +interface QuickPhraseItemProps { + phrase: QuickPhrase; + onSelect: (phrase: QuickPhrase) => void; + onEdit?: (phrase: QuickPhrase) => void; + onDelete?: (id: string) => void; + showActions?: boolean; +} + +/** + * 快捷短语列表项组件 + */ +export function QuickPhraseItem({ + phrase, + onSelect, + onEdit, + onDelete, + showActions = true, +}: QuickPhraseItemProps) { + const [isHovered, setIsHovered] = useState(false); + + // 获取图标组件 + const IconComponent = phrase.icon + ? (LucideIcons[phrase.icon as keyof typeof LucideIcons] as React.ComponentType<{ size?: number; className?: string }>) + : LucideIcons.MessageSquare; + + // 截断内容预览(最多显示 50 个字符) + const contentPreview = phrase.content.length > 50 + ? phrase.content.substring(0, 50) + '...' + : phrase.content; + + const handleSelect = () => { + onSelect(phrase); + }; + + const handleEdit = (e: React.MouseEvent) => { + e.stopPropagation(); + onEdit?.(phrase); + }; + + const handleDelete = (e: React.MouseEvent) => { + e.stopPropagation(); + onDelete?.(phrase.id); + }; + + return ( +
setIsHovered(true)} + onMouseLeave={() => setIsHovered(false)} + onClick={handleSelect} + > + {/* 图标 */} + {IconComponent && ( +
+ +
+ )} + + {/* 内容区域 */} +
+ {/* 标题 */} +
+ {phrase.title} +
+ + {/* 内容预览 */} +
+ {contentPreview} +
+
+ + {/* 操作按钮 */} + {showActions && (isHovered || false) && ( +
+ {onEdit && ( + + + + )} + + {onDelete && ( + + + + )} +
+ )} +
+ ); +} diff --git a/src/components/features/QuickPhrasesModal.tsx b/src/components/features/QuickPhrasesModal.tsx new file mode 100644 index 0000000..d4da30b --- /dev/null +++ b/src/components/features/QuickPhrasesModal.tsx @@ -0,0 +1,327 @@ +'use client'; + +import { useState, useEffect } from 'react'; +import { Plus, Trash2, Check } from 'lucide-react'; +import { Modal } from '@/components/ui/Modal'; +import { IconPicker } from '@/components/ui/IconPicker'; +import { cn } from '@/lib/utils'; +import type { QuickPhrase } from '@/types'; + +interface QuickPhrasesModalProps { + isOpen: boolean; + onClose: () => void; + phrases: QuickPhrase[]; + onAdd: (phrase: Omit) => void; + onUpdate: (id: string, updates: Partial>) => void; + onDelete: (id: string) => void; +} + +/** + * 快捷短语管理模态框 + */ +export function QuickPhrasesModal({ + isOpen, + onClose, + phrases, + onAdd, + onUpdate, + onDelete, +}: QuickPhrasesModalProps) { + const [selectedPhraseId, setSelectedPhraseId] = useState(null); + const [isEditing, setIsEditing] = useState(false); + + // 表单状态 + const [formData, setFormData] = useState({ + title: '', + content: '', + icon: 'MessageSquare' as string, + category: '', + }); + + // 当选中短语变化时,更新表单数据 + useEffect(() => { + if (selectedPhraseId) { + const phrase = phrases.find((p) => p.id === selectedPhraseId); + if (phrase) { + setFormData({ + title: phrase.title, + content: phrase.content, + icon: phrase.icon || 'MessageSquare', + category: phrase.category || '', + }); + setIsEditing(true); + } + } else { + // 重置表单 + setFormData({ + title: '', + content: '', + icon: 'MessageSquare', + category: '', + }); + setIsEditing(false); + } + }, [selectedPhraseId, phrases]); + + const handleSelectPhrase = (id: string) => { + setSelectedPhraseId(id); + }; + + const handleNewPhrase = () => { + setSelectedPhraseId(null); + setFormData({ + title: '', + content: '', + icon: 'MessageSquare', + category: '', + }); + setIsEditing(false); + }; + + const handleSave = () => { + // 验证表单 + if (!formData.title.trim() || !formData.content.trim()) { + alert('请填写标题和内容'); + return; + } + + if (isEditing && selectedPhraseId) { + // 更新现有短语 + onUpdate(selectedPhraseId, { + title: formData.title.trim(), + content: formData.content.trim(), + icon: formData.icon, + category: formData.category.trim() || undefined, + }); + } else { + // 添加新短语 + onAdd({ + title: formData.title.trim(), + content: formData.content.trim(), + icon: formData.icon, + category: formData.category.trim() || undefined, + }); + } + + // 重置表单 + handleNewPhrase(); + }; + + const handleDelete = (id: string) => { + if (confirm('确定要删除这个快捷短语吗?')) { + onDelete(id); + if (selectedPhraseId === id) { + handleNewPhrase(); + } + } + }; + + return ( + + {/* 标题 */} +
+

+ 管理快捷短语 +

+
+ + {/* 内容区域 */} +
+ {/* 左侧:短语列表 - 固定300px宽度 */} +
+ {/* 新建按钮 */} +
+ +
+ + {/* 短语列表 */} +
+ {phrases.length === 0 ? ( +
+

暂无快捷短语

+

点击上方按钮添加

+
+ ) : ( + phrases.map((phrase) => ( +
handleSelectPhrase(phrase.id)} + > +
+
+ {phrase.title} +
+
+ {phrase.content.substring(0, 30)}... +
+
+ +
+ )) + )} +
+
+ + {/* 右侧:编辑表单 - flex-1占据剩余空间 */} +
+
+
+ {/* 标题输入 */} +
+ + setFormData({ ...formData, title: e.target.value })} + placeholder="输入短语标题" + className={cn( + 'w-full px-3 py-2.5 rounded border-2 border-[var(--color-border)]', + 'bg-[var(--color-bg-primary)] text-[var(--color-text-primary)]', + 'placeholder:text-[var(--color-text-placeholder)]', + 'focus:outline-none focus:border-[var(--color-primary)] focus:ring-2 focus:ring-[var(--color-primary)]/10', + 'transition-all text-sm' + )} + /> +
+ + {/* 内容输入 */} +
+ +