feat: hierarchical notebook system - trash, selectors, breadcrumb, sidebar tree
All checks were successful
Deploy to Production / Build and Deploy (push) Successful in 2m9s
All checks were successful
Deploy to Production / Build and Deploy (push) Successful in 2m9s
- Schema: soft delete with trashedAt on Notebook model - API: PATCH/GET notebooks support trashedAt filtering with cascade - Sidebar: recursive tree rendering with collapse/expand, visual guides, hover actions - HierarchicalNotebookSelector: portal-based dropdown with search, breadcrumbs, dropUp support - AI chat: context selector with Toutes mes notes + notebook selector - Agent detail: flat selects replaced with HierarchicalNotebookSelector - Breadcrumb: notebook path display on home page - Trash view: card grid with countdown, restore/permanent delete - CSS: design tokens (ink, paper, blueprint, concrete, etc.) - Types: parentId, trashedAt added to Notebook interface
This commit is contained in:
@@ -510,35 +510,49 @@ export const NoteCard = memo(function NoteCard({
|
||||
<StickyNote className="h-4 w-4 mr-2" />
|
||||
{t('notebookSuggestion.generalNotes')}
|
||||
</DropdownMenuItem>
|
||||
{notebooks.filter(nb => !nb.parentId).map((notebook: any) => {
|
||||
const NotebookIcon = getNotebookIcon(notebook.icon || 'folder')
|
||||
const children = notebooks.filter((c: any) => c.parentId === notebook.id)
|
||||
if (children.length > 0) {
|
||||
return (
|
||||
<DropdownMenuSub key={notebook.id}>
|
||||
<DropdownMenuSubTrigger className="gap-2">
|
||||
<NotebookIcon className="h-4 w-4" />
|
||||
{notebook.name}
|
||||
<ChevronRight className="h-3 w-3 ml-auto opacity-50" />
|
||||
</DropdownMenuSubTrigger>
|
||||
<DropdownMenuSubContent>
|
||||
<DropdownMenuItem onClick={() => handleMoveToNotebook(notebook.id)}>
|
||||
<NotebookIcon className="h-4 w-4 mr-2" />
|
||||
{notebook.name}
|
||||
</DropdownMenuItem>
|
||||
{children.map((child: any) => {
|
||||
const ChildIcon = getNotebookIcon(child.icon || 'folder')
|
||||
return (
|
||||
<DropdownMenuItem key={child.id} onClick={() => handleMoveToNotebook(child.id)}>
|
||||
<ChildIcon className="h-4 w-4 mr-2" />
|
||||
{child.name}
|
||||
</DropdownMenuItem>
|
||||
)
|
||||
})}
|
||||
</DropdownMenuSubContent>
|
||||
</DropdownMenuSub>
|
||||
)
|
||||
}
|
||||
{notebooks.filter(nb => !nb.parentId && !nb.trashedAt).map((notebook: any) => {
|
||||
const NotebookIcon = getNotebookIcon(notebook.icon || 'folder')
|
||||
const allDescendants = (parentId: string): any[] => {
|
||||
const kids = notebooks.filter((c: any) => c.parentId === parentId && !c.trashedAt)
|
||||
return kids.flatMap((k: any) => [k, ...allDescendants(k.id)])
|
||||
}
|
||||
const descendants = allDescendants(notebook.id)
|
||||
if (descendants.length > 0) {
|
||||
return (
|
||||
<DropdownMenuSub key={notebook.id}>
|
||||
<DropdownMenuSubTrigger className="gap-2">
|
||||
<NotebookIcon className="h-4 w-4" />
|
||||
{notebook.name}
|
||||
<ChevronRight className="h-3 w-3 ml-auto opacity-50" />
|
||||
</DropdownMenuSubTrigger>
|
||||
<DropdownMenuSubContent>
|
||||
<DropdownMenuItem onClick={() => handleMoveToNotebook(notebook.id)}>
|
||||
<NotebookIcon className="h-4 w-4 mr-2" />
|
||||
{notebook.name}
|
||||
</DropdownMenuItem>
|
||||
{descendants.map((child: any) => {
|
||||
const ChildIcon = getNotebookIcon(child.icon || 'folder')
|
||||
const depth = (() => {
|
||||
let d = 0
|
||||
let current = child
|
||||
while (current.parentId && current.parentId !== notebook.id) {
|
||||
d++
|
||||
current = notebooks.find((nb: any) => nb.id === current.parentId)
|
||||
if (!current) break
|
||||
}
|
||||
return d
|
||||
})()
|
||||
return (
|
||||
<DropdownMenuItem key={child.id} onClick={() => handleMoveToNotebook(child.id)}>
|
||||
<NotebookIcon className="h-4 w-4 mr-2" />
|
||||
<span className="ml-{depth * 2}">{child.name}</span>
|
||||
</DropdownMenuItem>
|
||||
)
|
||||
})}
|
||||
</DropdownMenuSubContent>
|
||||
</DropdownMenuSub>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<DropdownMenuItem key={notebook.id} onClick={() => handleMoveToNotebook(notebook.id)}>
|
||||
<NotebookIcon className="h-4 w-4 mr-2" />
|
||||
|
||||
Reference in New Issue
Block a user