feat: add basic directory navigation in preview

Note: this does not add backwards navigation and will break if
attempting to open certain types of files.
This commit is contained in:
Sylvia Crowe 2024-05-29 00:00:36 -07:00
parent 7a54b79bda
commit b9f6da57f9
7 changed files with 85 additions and 23 deletions

View File

@ -42,6 +42,7 @@
.dir-table-body-cell {
overflow: hidden;
white-space: nowrap;
padding: 0.25rem;
}
}

View File

@ -3,12 +3,15 @@
import { FileInfo } from "@/bindings/fileservice";
import { Table, createColumnHelper, flexRender, getCoreRowModel, useReactTable } from "@tanstack/react-table";
import * as jotai from "jotai";
import path from "path";
import React from "react";
import "./directorytable.less";
import "./directorypreview.less";
interface DirectoryTableProps {
data: FileInfo[];
setFileName: (_: string) => void;
}
const columnHelper = createColumnHelper<FileInfo>();
@ -28,7 +31,7 @@ const defaultColumns = [
}),
];
function DirectoryTable<T, U>({ data }: DirectoryTableProps) {
function DirectoryTable<T, U>({ data, setFileName }: DirectoryTableProps) {
const [columns] = React.useState<typeof defaultColumns>(() => [...defaultColumns]);
const table = useReactTable({
data,
@ -73,26 +76,39 @@ function DirectoryTable<T, U>({ data }: DirectoryTableProps) {
))}
</div>
{table.getState().columnSizingInfo.isResizingColumn ? (
<MemoizedTableBody table={table} />
<MemoizedTableBody table={table} setFileName={setFileName} />
) : (
<TableBody table={table} />
<TableBody table={table} setFileName={setFileName} />
)}
</div>
);
}
function TableBody({ table }: { table: Table<FileInfo> }) {
interface TableBodyProps {
table: Table<FileInfo>;
setFileName: (_: string) => void;
}
function TableBody({ table, setFileName }: TableBodyProps) {
return (
<div className="dir-table-body">
{table.getRowModel().rows.map((row) => (
<div className="dir-table-body-row" key={row.id} tabIndex={0}>
<div
className="dir-table-body-row"
key={row.id}
tabIndex={0}
onDoubleClick={() => {
const newFileName = row.getValue("path") as string;
setFileName(newFileName);
}}
>
{row.getVisibleCells().map((cell) => (
<div
className="dir-table-body-cell"
key={cell.id}
style={{ width: `calc(var(--col-${cell.column.id}-size) * 1px)` }}
>
{cell.renderValue<any>()}
{path.basename(cell.renderValue<any>())}
</div>
))}
</div>
@ -106,4 +122,16 @@ const MemoizedTableBody = React.memo(
(prev, next) => prev.table.options.data == next.table.options.data
) as typeof TableBody;
export { DirectoryTable };
interface DirectoryPreviewProps {
contentAtom: jotai.Atom<Promise<string>>;
fileNameAtom: jotai.WritableAtom<string, [string], void>;
}
function DirectoryPreview({ contentAtom, fileNameAtom }: DirectoryPreviewProps) {
const contentText = jotai.useAtomValue(contentAtom);
let content: FileInfo[] = JSON.parse(contentText);
let [fileName, setFileName] = jotai.useAtom(fileNameAtom);
return <DirectoryTable data={content} setFileName={setFileName} />;
}
export { DirectoryPreview };

View File

@ -2,13 +2,13 @@
// SPDX-License-Identifier: Apache-2.0
import { FileInfo, FileService, FullFile } from "@/bindings/fileservice";
import { DirectoryTable } from "@/element/directorytable";
import { Markdown } from "@/element/markdown";
import { useBlockAtom } from "@/store/global";
import { useBlockAtom, useBlockCache } from "@/store/global";
import * as WOS from "@/store/wos";
import * as util from "@/util/util";
import * as jotai from "jotai";
import { CenteredDiv } from "../element/quickelems";
import { DirectoryPreview } from "./directorypreview";
import "./view.less";
@ -54,12 +54,6 @@ function StreamingPreview({ fileInfo }: { fileInfo: FileInfo }) {
return <CenteredDiv>Preview Not Supported</CenteredDiv>;
}
function DirectoryPreview({ contentAtom }: { contentAtom: jotai.Atom<Promise<string>> }) {
const contentText = jotai.useAtomValue(contentAtom);
let content: FileInfo[] = JSON.parse(contentText);
return <DirectoryTable data={content} />;
}
function PreviewView({ blockId }: { blockId: string }) {
const blockData = WOS.useWaveObjectValueWithSuspense<Block>(WOS.makeORef("block", blockId));
if (blockData == null) {
@ -69,11 +63,20 @@ function PreviewView({ blockId }: { blockId: string }) {
</div>
);
}
const fileNameAtom = useBlockAtom(blockId, "preview:filename", () =>
jotai.atom<string>((get) => {
return blockData?.meta?.file;
})
const blockAtom = WOS.getWaveObjectAtom<Block>(`block:${blockId}`);
const fileNameAtom: jotai.WritableAtom<string, [string], void> = useBlockCache(blockId, "preview:filename", () =>
jotai.atom<string, [string], void>(
(get) => {
return get(blockAtom)?.meta?.file;
},
(get, set, update) => {
const blockId = get(blockAtom)?.oid;
WOS.UpdateObjectMeta(`block:${blockId}`, { file: update });
}
)
);
let name = jotai.useAtomValue(fileNameAtom);
console.log("file: ", name);
const statFileAtom = useBlockAtom(blockId, "preview:statfile", () =>
jotai.atom<Promise<FileInfo>>(async (get) => {
const fileName = get(fileNameAtom);
@ -133,7 +136,7 @@ function PreviewView({ blockId }: { blockId: string }) {
);
}
if (mimeType === "directory") {
return <DirectoryPreview contentAtom={fileContentAtom} />;
return <DirectoryPreview contentAtom={fileContentAtom} fileNameAtom={fileNameAtom} />;
}
return (
<div className="view-preview">

View File

@ -49,6 +49,7 @@
"clsx": "^2.1.1",
"immer": "^10.1.1",
"jotai": "^2.8.0",
"path": "^0.12.7",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-markdown": "^9.0.1",

View File

@ -73,8 +73,9 @@ func (fs *FileService) ReadFile(path string) (*FullFile, error) {
var innerFilesInfo []FileInfo
for _, innerFileEntry := range innerFilesEntries {
innerFileInfoInt, _ := innerFileEntry.Info()
fullFilePath := filepath.Join(finfo.Path, innerFileInfoInt.Name())
innerFileInfo := FileInfo{
Path: innerFileInfoInt.Name(),
Path: fullFilePath,
Size: innerFileInfoInt.Size(),
Mode: innerFileInfoInt.Mode(),
ModTime: innerFileInfoInt.ModTime().UnixMilli(),

View File

@ -4,6 +4,7 @@ import tsconfigPaths from "vite-tsconfig-paths";
export default defineConfig({
plugins: [react({}), tsconfigPaths()],
define: { "process.env": process.env },
publicDir: "public",
build: {
target: "es6",

View File

@ -7001,6 +7001,13 @@ __metadata:
languageName: node
linkType: hard
"inherits@npm:2.0.3":
version: 2.0.3
resolution: "inherits@npm:2.0.3"
checksum: 10c0/6e56402373149ea076a434072671f9982f5fad030c7662be0332122fe6c0fa490acb3cc1010d90b6eff8d640b1167d77674add52dfd1bb85d545cf29e80e73e7
languageName: node
linkType: hard
"inline-style-parser@npm:0.2.3":
version: 0.2.3
resolution: "inline-style-parser@npm:0.2.3"
@ -9337,6 +9344,16 @@ __metadata:
languageName: node
linkType: hard
"path@npm:^0.12.7":
version: 0.12.7
resolution: "path@npm:0.12.7"
dependencies:
process: "npm:^0.11.1"
util: "npm:^0.10.3"
checksum: 10c0/f795ce5438a988a590c7b6dfd450ec9baa1c391a8be4c2dea48baa6e0f5b199e56cd83b8c9ebf3991b81bea58236d2c32bdafe2c17a2e70c3a2e4c69891ade59
languageName: node
linkType: hard
"pathe@npm:^1.1.1, pathe@npm:^1.1.2":
version: 1.1.2
resolution: "pathe@npm:1.1.2"
@ -9551,7 +9568,7 @@ __metadata:
languageName: node
linkType: hard
"process@npm:^0.11.10":
"process@npm:^0.11.1, process@npm:^0.11.10":
version: 0.11.10
resolution: "process@npm:0.11.10"
checksum: 10c0/40c3ce4b7e6d4b8c3355479df77aeed46f81b279818ccdc500124e6a5ab882c0cc81ff7ea16384873a95a74c4570b01b120f287abbdd4c877931460eca6084b3
@ -10957,6 +10974,7 @@ __metadata:
immer: "npm:^10.1.1"
jotai: "npm:^2.8.0"
less: "npm:^4.2.0"
path: "npm:^0.12.7"
prettier: "npm:^3.2.5"
prettier-plugin-jsdoc: "npm:^1.3.0"
prettier-plugin-organize-imports: "npm:^3.2.4"
@ -11511,6 +11529,15 @@ __metadata:
languageName: node
linkType: hard
"util@npm:^0.10.3":
version: 0.10.4
resolution: "util@npm:0.10.4"
dependencies:
inherits: "npm:2.0.3"
checksum: 10c0/d29f6893e406b63b088ce9924da03201df89b31490d4d011f1c07a386ea4b3dbe907464c274023c237da470258e1805d806c7e4009a5974cd6b1d474b675852a
languageName: node
linkType: hard
"util@npm:^0.12.4, util@npm:^0.12.5":
version: 0.12.5
resolution: "util@npm:0.12.5"