import React from 'react'; import { Button } from '@/components/ui/button'; import { toast } from '@/components/ui'; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog'; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from '@/components/ui/dropdown-menu'; import { ContextMenu, ContextMenuContent, ContextMenuItem, ContextMenuTrigger } from '@/components/ui/context-menu'; import { useSnippetsStore } from '@/stores/useSnippetsStore'; import { useShallow } from 'zustand/react/shallow'; import { ScrollableOverlay } from '@/components/ui/ScrollableOverlay'; import { cn } from '@/lib/utils'; import type { Snippet } from '@/types/snippet'; import { Icon } from '@/components/icon/Icon'; import { useI18n } from '@/lib/i18n'; import { SETTINGS_PANEL_TITLE_CLASS } from '@/components/sections/shared/SettingsSection'; interface SnippetsSidebarProps { onItemSelect?: () => void; } export const SnippetsSidebar: React.FC = ({ onItemSelect }) => { const { t } = useI18n(); const [confirmDeleteSnippet, setConfirmDeleteSnippet] = React.useState(null); const [openMenuName, setOpenMenuName] = React.useState(null); const [rightClickMenuName, setRightClickMenuName] = React.useState(null); const { selectedSnippetName, snippets, setSelectedSnippet, setSnippetDraft, deleteSnippet, loadSnippets } = useSnippetsStore(useShallow((s) => ({ selectedSnippetName: s.selectedSnippetName, snippets: s.snippets, setSelectedSnippet: s.setSelectedSnippet, setSnippetDraft: s.setSnippetDraft, deleteSnippet: s.deleteSnippet, loadSnippets: s.loadSnippets, }))); React.useEffect(() => { loadSnippets(); }, [loadSnippets]); const handleCreateNew = async () => { const existing = new Set(snippets.map((snippet) => snippet.name)); let name = 'new-snippet'; let counter = 1; while (existing.has(name)) { name = `new-snippet-${counter++}`; } setSnippetDraft({ name, scope: 'global' }); setSelectedSnippet(name); onItemSelect?.(); }; const handleDelete = async () => { if (!confirmDeleteSnippet) return; const success = await deleteSnippet(confirmDeleteSnippet.name); if (success) { toast.success(t('settings.snippets.sidebar.toast.deleted')); setConfirmDeleteSnippet(null); } else { toast.error(t('settings.snippets.sidebar.toast.deleteFailed')); } }; const sortedSnippets = React.useMemo(() => [...snippets].sort((a, b) => a.name.localeCompare(b.name)), [snippets]); return (

{t('settings.snippets.sidebar.title')}

{t('settings.snippets.sidebar.total', { count: snippets.length })}
{sortedSnippets.map((snippet) => ( setRightClickMenuName(open ? snippet.name : null)}> { event.preventDefault(); setRightClickMenuName(snippet.name); }} />}> { if (open) setRightClickMenuName(null); setOpenMenuName(open ? snippet.name : null); }}> { e.stopPropagation(); setConfirmDeleteSnippet(snippet); }} className="text-destructive focus:text-destructive"> {t('settings.common.actions.delete')} { e.stopPropagation(); setConfirmDeleteSnippet(snippet); }} className="text-destructive focus:text-destructive"> {t('settings.common.actions.delete')} ))} { if (!open) setConfirmDeleteSnippet(null); }}> {t('settings.snippets.sidebar.dialog.deleteTitle')} {t('settings.snippets.sidebar.dialog.deleteDescription', { name: confirmDeleteSnippet?.name ?? '' })}
); };