From 539c72cf6dad103c6f0e0c1e0b2835badff7d851 Mon Sep 17 00:00:00 2001 From: Antigravity Date: Sun, 10 May 2026 07:30:50 +0000 Subject: [PATCH] feat: sidebar tree with visual guides, hover '+' for sub-notebook, collapse/expand, notebook view 'New Sub-Carnet' button --- memento-note/components/home-client.tsx | 21 ++- memento-note/components/sidebar.tsx | 191 ++++++++++++------------ 2 files changed, 119 insertions(+), 93 deletions(-) diff --git a/memento-note/components/home-client.tsx b/memento-note/components/home-client.tsx index d6b5402..bf564ce 100644 --- a/memento-note/components/home-client.tsx +++ b/memento-note/components/home-client.tsx @@ -11,7 +11,7 @@ import { NotesEditorialView } from '@/components/notes-editorial-view' import { MemoryEchoNotification } from '@/components/memory-echo-notification' import { NotebookSuggestionToast } from '@/components/notebook-suggestion-toast' import { Button } from '@/components/ui/button' -import { Plus, ArrowUpDown, Search, Sparkles, FileText } from 'lucide-react' +import { Plus, ArrowUpDown, Search, Sparkles, FileText, FolderOpen } from 'lucide-react' import { useNoteRefresh } from '@/context/NoteRefreshContext' import { useRefresh } from '@/lib/use-refresh' import { useReminderCheck } from '@/hooks/use-reminder-check' @@ -21,6 +21,7 @@ import { cn } from '@/lib/utils' import { useLanguage } from '@/lib/i18n' import { useEditorUI } from '@/context/editor-ui-context' import { NoteHistoryModal } from '@/components/note-history-modal' +import { CreateNotebookDialog } from '@/components/create-notebook-dialog' import { toast } from 'sonner' import { AnimatePresence, motion } from 'motion/react' @@ -89,6 +90,7 @@ export function HomeClient({ initialNotes, initialSettings }: HomeClientProps) { const { shouldSuggest: shouldSuggestLabels, notebookId: suggestNotebookId, dismiss: dismissLabelSuggestion } = useAutoLabelSuggestion() const [autoLabelOpen, setAutoLabelOpen] = useState(false) const [summaryDialogOpen, setSummaryDialogOpen] = useState(false) + const [createSubNotebookOpen, setCreateSubNotebookOpen] = useState(false) useEffect(() => { if (shouldSuggestLabels && suggestNotebookId) { @@ -424,6 +426,16 @@ export function HomeClient({ initialNotes, initialSettings }: HomeClientProps) { {t('notes.newNote') || 'Add Note'} + {currentNotebook && ( + + )} + {/* Inline search — toggles an input within the toolbar */} {showInlineSearch ? (
@@ -638,6 +650,13 @@ export function HomeClient({ initialNotes, initialSettings }: HomeClientProps) { notebookName={currentNotebook?.name} /> )} + {searchParams.get('notebook') && ( + + )}
) } diff --git a/memento-note/components/sidebar.tsx b/memento-note/components/sidebar.tsx index 1edbf50..4121e36 100644 --- a/memento-note/components/sidebar.tsx +++ b/memento-note/components/sidebar.tsx @@ -82,23 +82,30 @@ function SidebarCarnetItem({ activeNoteId, onCarnetClick, onNoteClick, + onAddSubNotebook, children, isDragging, dragHandleProps, + depth = 0, }: { - carnet: { id: string; name: string; initial: string; isPrivate?: boolean } + carnet: { id: string; name: string; initial: string; isPrivate?: boolean; hasChildren?: boolean } isActive: boolean notes: { id: string; title: string }[] activeNoteId: string | null onCarnetClick: () => void onNoteClick: (noteId: string, carnetId: string) => void + onAddSubNotebook?: () => void children?: React.ReactNode isDragging?: boolean dragHandleProps?: React.HTMLAttributes + depth?: number }) { const { t } = useLanguage() + const [expanded, setExpanded] = useState(false) + const showContent = isActive || expanded + return ( -
+
- { e.stopPropagation(); setExpanded(v => !v) }} > + + {depth > 0 && ( +
+ )} +
{carnet.initial}
-
-
- - {carnet.name} - - {carnet.isPrivate && } -
-
- + + + {carnet.name} + + + {carnet.isPrivate && } + + {onAddSubNotebook && ( + + )} +
- {isActive && ( + {showContent && ( - {children} - {notes.map(note => ( - onNoteClick(note.id, carnet.id)} - /> - ))} - {notes.length === 0 && !children && ( -

{t('common.noResults')}

- )} +
0 && 'ml-4 border-l border-border/30 pl-2')}> + {children} + {notes.map(note => ( + onNoteClick(note.id, carnet.id)} + /> + ))} + {notes.length === 0 && !children && ( +

{t('common.noResults')}

+ )} +
)}
@@ -446,14 +468,22 @@ export function Sidebar({ className, user }: { className?: string; user?: any })

{t('nav.notebooks')}

-
+
+
+ {showSortMenu && ( )} +
@@ -558,7 +589,7 @@ export function Sidebar({ className, user }: { className?: string; user?: any }) {/* Notebooks list — draggable */}
e.preventDefault()} > @@ -573,12 +604,7 @@ export function Sidebar({ className, user }: { className?: string; user?: any })
0, }} isActive={isExpanded} notes={notes} activeNoteId={currentNoteId} onCarnetClick={() => handleCarnetClick(notebook.id)} onNoteClick={handleNoteClick} + onAddSubNotebook={() => { + setCreateParentId(notebook.id) + setIsCreateDialogOpen(true) + }} isDragging={isDragging} + depth={0} > - {children.length > 0 && ( -
- {children.map(child => { - const childActive = currentNotebookId === child.id - const childNotes = notebookNotes[child.id] || [] - return ( -
- handleCarnetClick(child.id)} - onNoteClick={handleNoteClick} - /> -
- ) - })} - -
- )} + isActive={childActive} + notes={childNotes} + activeNoteId={currentNoteId} + onCarnetClick={() => handleCarnetClick(child.id)} + onNoteClick={handleNoteClick} + depth={1} + /> + ) + })}
) })} - -
) : (