From 5da325703118320013957651bfaeae9ef5092474 Mon Sep 17 00:00:00 2001 From: Sylvie Crowe <107814465+oneirocosm@users.noreply.github.com> Date: Wed, 26 Jun 2024 16:59:45 -0700 Subject: [PATCH] Directory Search (#82) This adds a frontend directory search by filtering out files that don't match. It also allows navigation of the directory using the arrow keys while maintaining focus on the search box. --- frontend/app/view/directorypreview.less | 24 ++++- frontend/app/view/directorypreview.tsx | 137 +++++++++++++++++++++--- frontend/app/view/preview.tsx | 2 +- 3 files changed, 149 insertions(+), 14 deletions(-) diff --git a/frontend/app/view/directorypreview.less b/frontend/app/view/directorypreview.less index 31f5afa09..c8b130779 100644 --- a/frontend/app/view/directorypreview.less +++ b/frontend/app/view/directorypreview.less @@ -50,11 +50,15 @@ display: flex; border-radius: 3px; + &.focused { + background-color: var(--accent-color); + } + &:focus { background-color: var(--accent-color); } - &:hover:not(:focus) { + &:hover:not(:focus):not(.focused) { background-color: var(--highlight-bg-color); } @@ -78,3 +82,21 @@ } } } + +.dir-table-search-line { + display: flex; + gap: 0.7rem; + + .dir-table-search-box { + background-color: var(--panel-bg-color); + margin-bottom: 0.5rem; + border: none; + width: 15rem; + color: var(--main-text-color); + border-radius: 4px; + + &:focus { + outline-color: var(--accent-color); + } + } +} diff --git a/frontend/app/view/directorypreview.tsx b/frontend/app/view/directorypreview.tsx index 90c0d0b58..2bdb794ae 100644 --- a/frontend/app/view/directorypreview.tsx +++ b/frontend/app/view/directorypreview.tsx @@ -22,6 +22,9 @@ import "./directorypreview.less"; interface DirectoryTableProps { data: FileInfo[]; cwd: string; + focusIndex: number; + enter: boolean; + setFocusIndex: (_: number) => void; setFileName: (_: string) => void; } @@ -151,7 +154,7 @@ function cleanMimetype(input: string): string { return truncated.trim(); } -function DirectoryTable({ data, cwd, setFileName }: DirectoryTableProps) { +function DirectoryTable({ data, cwd, focusIndex, enter, setFocusIndex, setFileName }: DirectoryTableProps) { let settings = jotai.useAtomValue(atoms.settingsConfigAtom); const getIconFromMimeType = React.useCallback( (mimeType: string): string => { @@ -279,9 +282,23 @@ function DirectoryTable({ data, cwd, setFileName }: DirectoryTableProps) { ))} {table.getState().columnSizingInfo.isResizingColumn ? ( - + ) : ( - + )} ); @@ -290,24 +307,37 @@ function DirectoryTable({ data, cwd, setFileName }: DirectoryTableProps) { interface TableBodyProps { table: Table; cwd: string; + focusIndex: number; + enter: boolean; + setFocusIndex: (_: number) => void; setFileName: (_: string) => void; } -function TableBody({ table, cwd, setFileName }: TableBodyProps) { +function TableBody({ table, cwd, focusIndex, enter, setFocusIndex, setFileName }: TableBodyProps) { let [refresh, setRefresh] = React.useState(false); + React.useEffect(() => { + const selected = (table.getSortedRowModel()?.flatRows[focusIndex]?.getValue("path") as string) ?? null; + if (selected != null) { + console.log("yipee"); + const fullPath = cwd.concat("/", selected); + setFileName(fullPath); + } + }, [enter]); + + table.getRow; return (
- {table.getRowModel().rows.map((row) => ( + {table.getRowModel().rows.map((row, idx) => (
{ const newFileName = row.getValue("path") as string; const fullPath = cwd.concat("/", newFileName); setFileName(fullPath); }} + onClick={() => setFocusIndex(idx)} onContextMenu={(e) => handleFileContextMenu(e, cwd.concat("/", row.getValue("path") as string))} > {row.getVisibleCells().map((cell) => { @@ -333,15 +363,98 @@ const MemoizedTableBody = React.memo( ) as typeof TableBody; interface DirectoryPreviewProps { - contentAtom: jotai.Atom>; fileNameAtom: jotai.WritableAtom; } -function DirectoryPreview({ contentAtom, fileNameAtom }: DirectoryPreviewProps) { - const contentText = jotai.useAtomValue(contentAtom); - let content: FileInfo[] = JSON.parse(contentText); +function DirectoryPreview({ fileNameAtom }: DirectoryPreviewProps) { + const [searchText, setSearchText] = React.useState(""); + let [focusIndex, setFocusIndex] = React.useState(0); + const [content, setContent] = React.useState([]); let [fileName, setFileName] = jotai.useAtom(fileNameAtom); - return ; + const [enter, setEnter] = React.useState(false); + + React.useEffect(() => { + const getContent = async () => { + const file = await services.FileService.ReadFile(fileName); + const serializedContent = util.base64ToString(file?.data64); + let content: FileInfo[] = JSON.parse(serializedContent); + let filtered = content.filter((fileInfo) => { + return fileInfo.path.toLowerCase().includes(searchText); + }); + setContent(filtered); + }; + getContent(); + }, [fileName, searchText]); + + const handleKeyDown = React.useCallback( + (e) => { + switch (e.key) { + case "Escape": + //todo: escape block focus + break; + case "ArrowUp": + e.preventDefault(); + setFocusIndex((idx) => Math.max(idx - 1, 0)); + break; + case "ArrowDown": + e.preventDefault(); + setFocusIndex((idx) => Math.min(idx + 1, content.length - 1)); + break; + case "Enter": + e.preventDefault(); + console.log("enter thinks focus Index is ", focusIndex); + let newFileName = content[focusIndex].path; + console.log( + "enter thinks contents are", + content.slice(0, focusIndex + 1).map((fi) => fi.path) + ); + setEnter((current) => !current); + /* + const fullPath = fileName.concat("/", newFileName); + setFileName(fullPath); + */ + break; + default: + } + }, + [content, focusIndex, setEnter] + ); + + React.useEffect(() => { + console.log(focusIndex); + }, [focusIndex]); + + React.useEffect(() => { + document.addEventListener("keydown", handleKeyDown); + + return () => { + document.removeEventListener("keydown", handleKeyDown); + }; + }, [handleKeyDown]); + + return ( + <> +
+ + + setSearchText(e.target.value.toLowerCase())} + maxLength={400} + autoFocus={true} + /> +
+ + + ); } export { DirectoryPreview }; diff --git a/frontend/app/view/preview.tsx b/frontend/app/view/preview.tsx index 34627378b..37f3e3d92 100644 --- a/frontend/app/view/preview.tsx +++ b/frontend/app/view/preview.tsx @@ -251,7 +251,7 @@ function PreviewView({ blockId }: { blockId: string }) { ) { specializedView = ; } else if (mimeType === "directory") { - specializedView = ; + specializedView = ; } else { specializedView = (