diff --git a/lara.lock b/lara.lock index 9387bd6e..35801758 100644 --- a/lara.lock +++ b/lara.lock @@ -36,6 +36,7 @@ files: command.navigation.showArchivedNotes: 241399b908884adfe8608a3ab827ca74 command.navigation.listType: 4f70c27c6826a37543c8ada561397c22 command.note.newNote: 23c4edda8b815f750782f01870d27271 + command.note.newNoteInCurrentFolder: 167b765903c70ab1b645908ff8a899ab command.note.newType: adce5108f18945cc502a06c02445e32d command.note.newTypedNote: 1493eda772c2179cb6247169d00723b2 command.note.saveNote: 2a309cda46e95b00d2a5a8afb3cc0047 @@ -366,6 +367,7 @@ files: sidebar.action.createFolder: 5dc1e97c14fbe72d8b566ce29c39f010 sidebar.action.renameFolder: db76034f8218cda07dadb746a5643019 sidebar.action.deleteFolder: 2a2f15300f6f7c81d69860ac1796b517 + sidebar.action.createNodeInFolderMenu: 857a479229a4ab0bc62bbfb621d3180a sidebar.action.revealFolderMenu: 76f4ed52da9937ae432dcf5a108fabb4 sidebar.action.copyFolderPathMenu: 1779ec6018a385912c1a5499a1bbf2b2 sidebar.action.renameFolderMenu: deb1d8fa030292e7eda2c244b313aca2 diff --git a/src/components/FolderTree.test.tsx b/src/components/FolderTree.test.tsx index b50fbd04..e4b3e33f 100644 --- a/src/components/FolderTree.test.tsx +++ b/src/components/FolderTree.test.tsx @@ -4,6 +4,7 @@ import { describe, it, expect, vi } from 'vitest' import { FolderTree } from './FolderTree' import { FOLDER_ROW_SINGLE_CLICK_DELAY_MS } from './folder-tree/useFolderRowInteractions' import { FOLDER_ROW_NESTING_INDENT, getFolderConnectorLeft } from './folder-tree/folderTreeLayout' +import { CREATE_NOTE_IN_FOLDER_EVENT } from '../hooks/noteCreationRequests' import type { FolderNode, SidebarSelection } from '../types' const mockFolders: FolderNode[] = [ @@ -526,6 +527,44 @@ describe('FolderTree', () => { expect(onCopyFolderPath).toHaveBeenCalledWith('projects') }) + it('creates a note in the right-clicked mounted folder', () => { + const onCreateNoteInFolder = vi.fn() + const folders: FolderNode[] = [ + { + name: 'Personal', + path: '', + rootPath: '/Users/luca/Personal', + children: [{ name: 'projects', path: 'projects', rootPath: '/Users/luca/Personal', children: [] }], + }, + { + name: 'Team', + path: '', + rootPath: '/Users/luca/Team', + children: [{ name: 'projects', path: 'projects', rootPath: '/Users/luca/Team', children: [] }], + }, + ] + + render( + , + ) + + window.addEventListener(CREATE_NOTE_IN_FOLDER_EVENT, onCreateNoteInFolder) + fireEvent.contextMenu(screen.getAllByTestId('folder-row:projects')[1]) + fireEvent.click(screen.getByTestId('create-node-in-folder-menu-item')) + + expect(onCreateNoteInFolder).toHaveBeenCalledOnce() + expect((onCreateNoteInFolder.mock.calls[0][0] as CustomEvent).detail).toEqual({ + folderPath: 'projects', + rootPath: '/Users/luca/Team', + }) + window.removeEventListener(CREATE_NOTE_IN_FOLDER_EVENT, onCreateNoteInFolder) + }) + it('keeps destructive folder actions off the vault root row and menu', () => { render( diff --git a/src/components/MermaidDiagram.tsx b/src/components/MermaidDiagram.tsx index 1bead6f3..16245aad 100644 --- a/src/components/MermaidDiagram.tsx +++ b/src/components/MermaidDiagram.tsx @@ -1,5 +1,5 @@ import { ArrowsOut as Maximize2 } from '@phosphor-icons/react' -import { useEffect, useId, useMemo, useRef, useState, type SyntheticEvent } from 'react' +import { useEffect, useId, useMemo, useState, type SyntheticEvent } from 'react' import { Button } from '@/components/ui/button' import { Dialog, @@ -159,13 +159,7 @@ function MermaidLightbox({ svg }: { svg: string }) { } function MermaidSourceFallback({ source }: { source: string }) { - const sourceRef = useRef(null) - - useEffect(() => { - sourceRef.current?.setAttribute('aria-label', 'Mermaid source') - }, []) - - return
{source}
+ return
{source}
} export function MermaidDiagram({ diagram, source }: MermaidDiagramProps) { diff --git a/src/components/NoteList.rendering.test.tsx b/src/components/NoteList.rendering.test.tsx index 9a5a9cd5..6b1b6345 100644 --- a/src/components/NoteList.rendering.test.tsx +++ b/src/components/NoteList.rendering.test.tsx @@ -188,6 +188,26 @@ describe('NoteList rendering', () => { expect(onCreateNote).toHaveBeenCalledWith(undefined) }) + it('shows the active folder name and creates notes inside that folder', () => { + const { onCreateNote } = renderNoteList({ + selection: { + kind: 'folder', + path: 'Projects/2026 Planning', + rootPath: '/Users/luca/Laputa', + }, + }) + + expect(screen.getByRole('heading', { name: '2026 Planning' })).toBeInTheDocument() + + fireEvent.click(screen.getByTitle('Create new note')) + + expect(onCreateNote).toHaveBeenCalledWith(undefined, { + creationPath: 'folder_header', + folderPath: 'Projects/2026 Planning', + vaultPath: '/Users/luca/Laputa', + }) + }) + it('pins the current entity and shows grouped children', () => { renderNoteList({ selection: { kind: 'entity', entry: mockEntries[0] } }) expect(screen.getAllByText('Build Laputa App').length).toBeGreaterThanOrEqual(1) diff --git a/src/components/folder-tree/FolderContextMenu.tsx b/src/components/folder-tree/FolderContextMenu.tsx index abec475c..8721f549 100644 --- a/src/components/folder-tree/FolderContextMenu.tsx +++ b/src/components/folder-tree/FolderContextMenu.tsx @@ -1,10 +1,11 @@ import type { RefObject } from 'react' -import { ClipboardText, FolderOpen, PencilSimple, Trash } from '@phosphor-icons/react' +import { ClipboardText, FolderOpen, PencilSimple, Plus, Trash } from '@phosphor-icons/react' import { Button } from '@/components/ui/button' import { translate, type AppLocale } from '../../lib/i18n' export interface FolderContextMenuState { path: string + rootPath?: string x: number y: number } @@ -15,6 +16,7 @@ interface FolderContextMenuProps { onDelete?: (folderPath: string) => void onReveal?: (folderPath: string) => void onCopyPath?: (folderPath: string) => void + onCreateNote?: (folderPath: string, rootPath?: string) => void onRename: (folderPath: string) => void locale?: AppLocale } @@ -25,6 +27,7 @@ export function FolderContextMenu({ onDelete, onReveal, onCopyPath, + onCreateNote, onRename, locale = 'en', }: FolderContextMenuProps) { @@ -38,6 +41,18 @@ export function FolderContextMenu({ style={{ left: menu.x, top: menu.y, minWidth: 180 }} data-testid="folder-context-menu" > + {onCreateNote && ( + + )} {onReveal && (