mirror of
https://github.com/wavetermdev/waveterm.git
synced 2025-01-04 18:59:08 +01:00
Merge pull request #10 from wavetermdev/sylvie/directory-nav
feat: add basic directory navigation in preview
This commit is contained in:
commit
78f2358f47
@ -42,6 +42,7 @@
|
|||||||
|
|
||||||
.dir-table-body-cell {
|
.dir-table-body-cell {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
padding: 0.25rem;
|
padding: 0.25rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -3,12 +3,15 @@
|
|||||||
|
|
||||||
import { FileInfo } from "@/bindings/fileservice";
|
import { FileInfo } from "@/bindings/fileservice";
|
||||||
import { Table, createColumnHelper, flexRender, getCoreRowModel, useReactTable } from "@tanstack/react-table";
|
import { Table, createColumnHelper, flexRender, getCoreRowModel, useReactTable } from "@tanstack/react-table";
|
||||||
|
import * as jotai from "jotai";
|
||||||
|
import path from "path";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
import "./directorytable.less";
|
import "./directorypreview.less";
|
||||||
|
|
||||||
interface DirectoryTableProps {
|
interface DirectoryTableProps {
|
||||||
data: FileInfo[];
|
data: FileInfo[];
|
||||||
|
setFileName: (_: string) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const columnHelper = createColumnHelper<FileInfo>();
|
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 [columns] = React.useState<typeof defaultColumns>(() => [...defaultColumns]);
|
||||||
const table = useReactTable({
|
const table = useReactTable({
|
||||||
data,
|
data,
|
||||||
@ -73,26 +76,39 @@ function DirectoryTable<T, U>({ data }: DirectoryTableProps) {
|
|||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
{table.getState().columnSizingInfo.isResizingColumn ? (
|
{table.getState().columnSizingInfo.isResizingColumn ? (
|
||||||
<MemoizedTableBody table={table} />
|
<MemoizedTableBody table={table} setFileName={setFileName} />
|
||||||
) : (
|
) : (
|
||||||
<TableBody table={table} />
|
<TableBody table={table} setFileName={setFileName} />
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function TableBody({ table }: { table: Table<FileInfo> }) {
|
interface TableBodyProps {
|
||||||
|
table: Table<FileInfo>;
|
||||||
|
setFileName: (_: string) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
function TableBody({ table, setFileName }: TableBodyProps) {
|
||||||
return (
|
return (
|
||||||
<div className="dir-table-body">
|
<div className="dir-table-body">
|
||||||
{table.getRowModel().rows.map((row) => (
|
{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) => (
|
{row.getVisibleCells().map((cell) => (
|
||||||
<div
|
<div
|
||||||
className="dir-table-body-cell"
|
className="dir-table-body-cell"
|
||||||
key={cell.id}
|
key={cell.id}
|
||||||
style={{ width: `calc(var(--col-${cell.column.id}-size) * 1px)` }}
|
style={{ width: `calc(var(--col-${cell.column.id}-size) * 1px)` }}
|
||||||
>
|
>
|
||||||
{cell.renderValue<any>()}
|
{path.basename(cell.renderValue<any>())}
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
@ -106,4 +122,16 @@ const MemoizedTableBody = React.memo(
|
|||||||
(prev, next) => prev.table.options.data == next.table.options.data
|
(prev, next) => prev.table.options.data == next.table.options.data
|
||||||
) as typeof TableBody;
|
) 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
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
import { FileInfo, FileService, FullFile } from "@/bindings/fileservice";
|
import { FileInfo, FileService, FullFile } from "@/bindings/fileservice";
|
||||||
import { DirectoryTable } from "@/element/directorytable";
|
|
||||||
import { Markdown } from "@/element/markdown";
|
import { Markdown } from "@/element/markdown";
|
||||||
import { useBlockAtom } from "@/store/global";
|
import { useBlockAtom, useBlockCache } from "@/store/global";
|
||||||
import * as WOS from "@/store/wos";
|
import * as WOS from "@/store/wos";
|
||||||
import * as util from "@/util/util";
|
import * as util from "@/util/util";
|
||||||
import * as jotai from "jotai";
|
import * as jotai from "jotai";
|
||||||
import { CenteredDiv } from "../element/quickelems";
|
import { CenteredDiv } from "../element/quickelems";
|
||||||
|
import { DirectoryPreview } from "./directorypreview";
|
||||||
|
|
||||||
import "./view.less";
|
import "./view.less";
|
||||||
|
|
||||||
@ -54,12 +54,6 @@ function StreamingPreview({ fileInfo }: { fileInfo: FileInfo }) {
|
|||||||
return <CenteredDiv>Preview Not Supported</CenteredDiv>;
|
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 }) {
|
function PreviewView({ blockId }: { blockId: string }) {
|
||||||
const blockData = WOS.useWaveObjectValueWithSuspense<Block>(WOS.makeORef("block", blockId));
|
const blockData = WOS.useWaveObjectValueWithSuspense<Block>(WOS.makeORef("block", blockId));
|
||||||
if (blockData == null) {
|
if (blockData == null) {
|
||||||
@ -69,11 +63,20 @@ function PreviewView({ blockId }: { blockId: string }) {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
const fileNameAtom = useBlockAtom(blockId, "preview:filename", () =>
|
const blockAtom = WOS.getWaveObjectAtom<Block>(`block:${blockId}`);
|
||||||
jotai.atom<string>((get) => {
|
const fileNameAtom: jotai.WritableAtom<string, [string], void> = useBlockCache(blockId, "preview:filename", () =>
|
||||||
return blockData?.meta?.file;
|
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", () =>
|
const statFileAtom = useBlockAtom(blockId, "preview:statfile", () =>
|
||||||
jotai.atom<Promise<FileInfo>>(async (get) => {
|
jotai.atom<Promise<FileInfo>>(async (get) => {
|
||||||
const fileName = get(fileNameAtom);
|
const fileName = get(fileNameAtom);
|
||||||
@ -133,7 +136,7 @@ function PreviewView({ blockId }: { blockId: string }) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (mimeType === "directory") {
|
if (mimeType === "directory") {
|
||||||
return <DirectoryPreview contentAtom={fileContentAtom} />;
|
return <DirectoryPreview contentAtom={fileContentAtom} fileNameAtom={fileNameAtom} />;
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<div className="view-preview">
|
<div className="view-preview">
|
||||||
|
@ -49,6 +49,7 @@
|
|||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"immer": "^10.1.1",
|
"immer": "^10.1.1",
|
||||||
"jotai": "^2.8.0",
|
"jotai": "^2.8.0",
|
||||||
|
"path": "^0.12.7",
|
||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
"react-dom": "^18.3.1",
|
"react-dom": "^18.3.1",
|
||||||
"react-markdown": "^9.0.1",
|
"react-markdown": "^9.0.1",
|
||||||
|
@ -73,8 +73,9 @@ func (fs *FileService) ReadFile(path string) (*FullFile, error) {
|
|||||||
var innerFilesInfo []FileInfo
|
var innerFilesInfo []FileInfo
|
||||||
for _, innerFileEntry := range innerFilesEntries {
|
for _, innerFileEntry := range innerFilesEntries {
|
||||||
innerFileInfoInt, _ := innerFileEntry.Info()
|
innerFileInfoInt, _ := innerFileEntry.Info()
|
||||||
|
fullFilePath := filepath.Join(finfo.Path, innerFileInfoInt.Name())
|
||||||
innerFileInfo := FileInfo{
|
innerFileInfo := FileInfo{
|
||||||
Path: innerFileInfoInt.Name(),
|
Path: fullFilePath,
|
||||||
Size: innerFileInfoInt.Size(),
|
Size: innerFileInfoInt.Size(),
|
||||||
Mode: innerFileInfoInt.Mode(),
|
Mode: innerFileInfoInt.Mode(),
|
||||||
ModTime: innerFileInfoInt.ModTime().UnixMilli(),
|
ModTime: innerFileInfoInt.ModTime().UnixMilli(),
|
||||||
|
@ -4,6 +4,7 @@ import tsconfigPaths from "vite-tsconfig-paths";
|
|||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [react({}), tsconfigPaths()],
|
plugins: [react({}), tsconfigPaths()],
|
||||||
|
define: { "process.env": process.env },
|
||||||
publicDir: "public",
|
publicDir: "public",
|
||||||
build: {
|
build: {
|
||||||
target: "es6",
|
target: "es6",
|
||||||
|
29
yarn.lock
29
yarn.lock
@ -7001,6 +7001,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
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":
|
"inline-style-parser@npm:0.2.3":
|
||||||
version: 0.2.3
|
version: 0.2.3
|
||||||
resolution: "inline-style-parser@npm:0.2.3"
|
resolution: "inline-style-parser@npm:0.2.3"
|
||||||
@ -9337,6 +9344,16 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
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":
|
"pathe@npm:^1.1.1, pathe@npm:^1.1.2":
|
||||||
version: 1.1.2
|
version: 1.1.2
|
||||||
resolution: "pathe@npm:1.1.2"
|
resolution: "pathe@npm:1.1.2"
|
||||||
@ -9551,7 +9568,7 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"process@npm:^0.11.10":
|
"process@npm:^0.11.1, process@npm:^0.11.10":
|
||||||
version: 0.11.10
|
version: 0.11.10
|
||||||
resolution: "process@npm:0.11.10"
|
resolution: "process@npm:0.11.10"
|
||||||
checksum: 10c0/40c3ce4b7e6d4b8c3355479df77aeed46f81b279818ccdc500124e6a5ab882c0cc81ff7ea16384873a95a74c4570b01b120f287abbdd4c877931460eca6084b3
|
checksum: 10c0/40c3ce4b7e6d4b8c3355479df77aeed46f81b279818ccdc500124e6a5ab882c0cc81ff7ea16384873a95a74c4570b01b120f287abbdd4c877931460eca6084b3
|
||||||
@ -10957,6 +10974,7 @@ __metadata:
|
|||||||
immer: "npm:^10.1.1"
|
immer: "npm:^10.1.1"
|
||||||
jotai: "npm:^2.8.0"
|
jotai: "npm:^2.8.0"
|
||||||
less: "npm:^4.2.0"
|
less: "npm:^4.2.0"
|
||||||
|
path: "npm:^0.12.7"
|
||||||
prettier: "npm:^3.2.5"
|
prettier: "npm:^3.2.5"
|
||||||
prettier-plugin-jsdoc: "npm:^1.3.0"
|
prettier-plugin-jsdoc: "npm:^1.3.0"
|
||||||
prettier-plugin-organize-imports: "npm:^3.2.4"
|
prettier-plugin-organize-imports: "npm:^3.2.4"
|
||||||
@ -11511,6 +11529,15 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
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":
|
"util@npm:^0.12.4, util@npm:^0.12.5":
|
||||||
version: 0.12.5
|
version: 0.12.5
|
||||||
resolution: "util@npm:0.12.5"
|
resolution: "util@npm:0.12.5"
|
||||||
|
Loading…
Reference in New Issue
Block a user