diff --git a/apps/x/apps/renderer/src/App.tsx b/apps/x/apps/renderer/src/App.tsx index 5c072b2a..a77aaeb4 100644 --- a/apps/x/apps/renderer/src/App.tsx +++ b/apps/x/apps/renderer/src/App.tsx @@ -5506,7 +5506,11 @@ function App() { remove: knowledgeActions.remove, copyPath: knowledgeActions.copyPath, revealInFileManager: knowledgeActions.revealInFileManager, + createNote: knowledgeActions.createNote, + createFolder: knowledgeActions.createFolder, + onOpenInNewTab: knowledgeActions.onOpenInNewTab, }} + onNavigate={(path) => { void navigateToView({ type: 'workspace', path: path === WORKSPACE_ROOT ? undefined : path }) }} onOpenNote={(path) => navigateToFile(path)} onCreateWorkspace={async (name) => { await knowledgeActions.createWorkspace(name) }} /> diff --git a/apps/x/apps/renderer/src/components/workspace-view.tsx b/apps/x/apps/renderer/src/components/workspace-view.tsx index 6cbd1075..6923ac1c 100644 --- a/apps/x/apps/renderer/src/components/workspace-view.tsx +++ b/apps/x/apps/renderer/src/components/workspace-view.tsx @@ -1,7 +1,8 @@ -import { useCallback, useEffect, useMemo, useRef, useState } from 'react' +import { useCallback, useMemo, useRef, useState } from 'react' import { ChevronRight, Copy, + ExternalLink, File as FileIcon, FilePlus, Folder as FolderIcon, @@ -53,12 +54,18 @@ type WorkspaceActions = { remove: (path: string) => Promise copyPath: (path: string) => void revealInFileManager: (path: string, isDir: boolean) => void + createNote: (parentPath?: string) => void + createFolder: (parentPath?: string) => Promise + onOpenInNewTab?: (path: string) => void } type WorkspaceViewProps = { tree: TreeNode[] initialPath?: string | null actions: WorkspaceActions + // Folder currently being browsed. Controlled by the app so drill-down + // participates in the global back/forward history. + onNavigate: (path: string) => void onOpenNote: (path: string) => void onCreateWorkspace: (name: string) => Promise } @@ -71,6 +78,12 @@ function getFileManagerName(): string { return 'File Manager' } +function fileExtensionLabel(name: string): string { + const dot = name.lastIndexOf('.') + if (dot <= 0 || dot === name.length - 1) return 'File' + return `${name.slice(dot + 1).toUpperCase()} file` +} + function findNode(nodes: TreeNode[] | undefined, path: string): TreeNode | null { if (!nodes) return null for (const node of nodes) { @@ -113,8 +126,8 @@ function readFileAsBase64(file: File): Promise { }) } -export function WorkspaceView({ tree, initialPath, actions, onOpenNote, onCreateWorkspace }: WorkspaceViewProps) { - const [currentPath, setCurrentPath] = useState(initialPath || WORKSPACE_ROOT) +export function WorkspaceView({ tree, initialPath, actions, onNavigate, onOpenNote, onCreateWorkspace }: WorkspaceViewProps) { + const currentPath = initialPath || WORKSPACE_ROOT const [addOpen, setAddOpen] = useState(false) const [newName, setNewName] = useState('') const [creating, setCreating] = useState(false) @@ -127,10 +140,6 @@ export function WorkspaceView({ tree, initialPath, actions, onOpenNote, onCreate const filesInputRef = useRef(null) const folderInputRef = useRef(null) - useEffect(() => { - if (initialPath) setCurrentPath(initialPath) - }, [initialPath]) - const isRoot = currentPath === WORKSPACE_ROOT const fileManagerName = getFileManagerName() @@ -160,12 +169,12 @@ export function WorkspaceView({ tree, initialPath, actions, onOpenNote, onCreate (item: TreeNode) => { if (renameTarget) return if (item.kind === 'dir') { - setCurrentPath(item.path) + onNavigate(item.path) } else { onOpenNote(item.path) } }, - [onOpenNote, renameTarget], + [onNavigate, onOpenNote, renameTarget], ) const beginRename = useCallback((item: TreeNode) => { @@ -295,7 +304,7 @@ export function WorkspaceView({ tree, initialPath, actions, onOpenNote, onCreate
- {isRoot ? ( - - ) : ( - - - - - - filesInputRef.current?.click()}> - - Add files… - - folderInputRef.current?.click()}> - - Add folder… - - - - )} + {isRoot ? ( + + ) : ( + + + + + + filesInputRef.current?.click()}> + + Add files… + + folderInputRef.current?.click()}> + + Add folder… + + + + )} + {item.name} )} - {item.kind === 'dir' && !isRenaming && ( -
- {childCount} {childCount === 1 ? 'item' : 'items'} + {!isRenaming && ( +
+ {item.kind === 'dir' + ? `${childCount} ${childCount === 1 ? 'item' : 'items'}` + : fileExtensionLabel(item.name)}
)}
) + const isDir = item.kind === 'dir' return ( {card} - - beginRename(item)}> - - Rename - + e.preventDefault()}> + {isDir && ( + <> + actions.createNote(item.path)}> + + New Note + + void actions.createFolder(item.path)}> + + New Folder + + + + )} + {!isDir && actions.onOpenInNewTab && ( + <> + actions.onOpenInNewTab!(item.path)}> + + Open in new tab + + + + )} { actions.copyPath(item.path); toast('Path copied', 'success') }}> Copy Path - actions.revealInFileManager(item.path, item.kind === 'dir')}> + actions.revealInFileManager(item.path, isDir)}> - Show in {fileManagerName} + Open in {fileManagerName} + beginRename(item)}> + + Rename + void handleDelete(item)}> Delete