feat: 侧边栏集成回收站入口和 TrashView

This commit is contained in:
MikiVL 2026-05-05 04:52:47 +08:00
parent 83119adef4
commit 005a608369

View File

@ -15,6 +15,7 @@ import {
} from '@dnd-kit/core' } from '@dnd-kit/core'
import { CSS } from '@dnd-kit/utilities' import { CSS } from '@dnd-kit/utilities'
import { useAppStore } from '../../stores/appStore' import { useAppStore } from '../../stores/appStore'
import { TrashView } from './TrashView'
import { formatDate } from '../../lib/utils' import { formatDate } from '../../lib/utils'
import type { Folder as FolderType, Note } from '../../db' import type { Folder as FolderType, Note } from '../../db'
@ -25,6 +26,7 @@ export function Sidebar() {
updateNote, updateFolder, setActiveNote, setActiveFolder, setSearch, updateNote, updateFolder, setActiveNote, setActiveFolder, setSearch,
toggleTheme, toggleStar, filteredNotes, toggleTheme, toggleStar, filteredNotes,
activeTag, setActiveTag, sortBy, sortOrder, setSortBy, setSortOrder, activeTag, setActiveTag, sortBy, sortOrder, setSortBy, setSortOrder,
trashNotes,
} = useAppStore() } = useAppStore()
const [expandedFolders, setExpandedFolders] = useState<Set<string>>(new Set()) const [expandedFolders, setExpandedFolders] = useState<Set<string>>(new Set())
@ -229,6 +231,13 @@ export function Sidebar() {
<NavItem icon={<BookOpen size={14} />} label="使用指南" active={activeNoteId === '__welcome__'} onClick={() => setActiveNote('__welcome__')} /> <NavItem icon={<BookOpen size={14} />} label="使用指南" active={activeNoteId === '__welcome__'} onClick={() => setActiveNote('__welcome__')} />
<NavItem icon={<FileText size={14} />} label="所有笔记" count={notes.length} active={activeFolderId === 'all' && activeNoteId !== '__welcome__'} onClick={() => { setActiveFolder('all'); if (activeNoteId === '__welcome__') setActiveNote(null) }} /> <NavItem icon={<FileText size={14} />} label="所有笔记" count={notes.length} active={activeFolderId === 'all' && activeNoteId !== '__welcome__'} onClick={() => { setActiveFolder('all'); if (activeNoteId === '__welcome__') setActiveNote(null) }} />
<NavItem icon={<Star size={14} />} label="收藏" count={notes.filter(n => n.starred).length} active={activeFolderId === 'starred'} onClick={() => { setActiveFolder('starred'); if (activeNoteId === '__welcome__') setActiveNote(null) }} /> <NavItem icon={<Star size={14} />} label="收藏" count={notes.filter(n => n.starred).length} active={activeFolderId === 'starred'} onClick={() => { setActiveFolder('starred'); if (activeNoteId === '__welcome__') setActiveNote(null) }} />
<NavItem
icon={<Trash2 size={14} />}
label="回收站"
count={trashNotes().length || undefined}
active={activeFolderId === 'trash'}
onClick={() => { setActiveFolder('trash'); if (activeNoteId === '__welcome__') setActiveNote(null) }}
/>
</nav> </nav>
{/* Folders section */} {/* Folders section */}
@ -264,6 +273,10 @@ export function Sidebar() {
{/* Note list */} {/* Note list */}
<div className="flex-1 overflow-y-auto mt-2" style={{ borderTop: '1px solid var(--border)' }}> <div className="flex-1 overflow-y-auto mt-2" style={{ borderTop: '1px solid var(--border)' }}>
{activeFolderId === 'trash' ? (
<TrashView />
) : (
<>
<div className="px-3 py-2 flex items-center justify-between sticky top-0 z-10" style={{ background: 'var(--bg-subtle)' }}> <div className="px-3 py-2 flex items-center justify-between sticky top-0 z-10" style={{ background: 'var(--bg-subtle)' }}>
<div className="flex items-center gap-1.5"> <div className="flex items-center gap-1.5">
<span className="text-xs font-semibold uppercase tracking-wider" style={{ color: 'var(--text-faint)' }}> <span className="text-xs font-semibold uppercase tracking-wider" style={{ color: 'var(--text-faint)' }}>
@ -343,9 +356,9 @@ export function Sidebar() {
/> />
))} ))}
</div> </div>
</>
)}
</div> </div>
{/* Context menu */}
{contextMenu && ( <div {contextMenu && ( <div
className="fixed z-50 rounded-lg py-1 shadow-xl" className="fixed z-50 rounded-lg py-1 shadow-xl"
style={{ top: contextMenu.y, left: contextMenu.x, background: 'var(--bg)', border: '1px solid var(--border)', minWidth: 160 }} style={{ top: contextMenu.y, left: contextMenu.x, background: 'var(--bg)', border: '1px solid var(--border)', minWidth: 160 }}
@ -436,8 +449,8 @@ export function Sidebar() {
style={{ background: 'var(--bg)', border: '1px solid var(--border)', width: 320 }} style={{ background: 'var(--bg)', border: '1px solid var(--border)', width: 320 }}
onClick={e => e.stopPropagation()} onClick={e => e.stopPropagation()}
> >
<p className="text-sm font-semibold" style={{ color: 'var(--text)' }}></p> <p className="text-sm font-semibold" style={{ color: 'var(--text)' }}></p>
<p className="text-xs" style={{ color: 'var(--muted)' }}></p> <p className="text-xs" style={{ color: 'var(--muted)' }}> 30 </p>
<div className="flex justify-end gap-2"> <div className="flex justify-end gap-2">
<button <button
onClick={() => setDeleteConfirm(null)} onClick={() => setDeleteConfirm(null)}
@ -450,7 +463,7 @@ export function Sidebar() {
onClick={async () => { await deleteNote(deleteConfirm); setDeleteConfirm(null) }} onClick={async () => { await deleteNote(deleteConfirm); setDeleteConfirm(null) }}
className="px-3 py-1.5 rounded-lg text-sm font-medium" className="px-3 py-1.5 rounded-lg text-sm font-medium"
style={{ background: '#ef4444', color: '#fff' }} style={{ background: '#ef4444', color: '#fff' }}
></button> ></button>
</div> </div>
</div> </div>
</div> </div>