mirror of
https://github.com/wavetermdev/waveterm.git
synced 2024-12-21 16:38:23 +01:00
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:
parent
7a54b79bda
commit
b9f6da57f9
@ -42,6 +42,7 @@
|
||||
|
||||
.dir-table-body-cell {
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
padding: 0.25rem;
|
||||
}
|
||||
}
|
@ -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 };
|
@ -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">
|
||||
|
@ -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",
|
||||
|
@ -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(),
|
||||
|
@ -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",
|
||||
|
29
yarn.lock
29
yarn.lock
@ -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"
|
||||
|
Loading…
Reference in New Issue
Block a user