mirror of
https://github.com/wavetermdev/waveterm.git
synced 2025-02-01 23:21:59 +01:00
Merge pull request #14 from wavetermdev/sylvie/backwards-nav
Preview Navigation Chrome
This commit is contained in:
commit
a51be0dc6a
@ -10,6 +10,7 @@ import "./directorypreview.less";
|
|||||||
|
|
||||||
interface DirectoryTableProps {
|
interface DirectoryTableProps {
|
||||||
data: FileInfo[];
|
data: FileInfo[];
|
||||||
|
cwd: string;
|
||||||
setFileName: (_: string) => void;
|
setFileName: (_: string) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -26,11 +27,11 @@ const defaultColumns = [
|
|||||||
}),
|
}),
|
||||||
columnHelper.accessor("mimetype", {
|
columnHelper.accessor("mimetype", {
|
||||||
cell: (info) => info.getValue(),
|
cell: (info) => info.getValue(),
|
||||||
header: () => <span>Mimetype</span>,
|
header: () => <span>Type</span>,
|
||||||
}),
|
}),
|
||||||
];
|
];
|
||||||
|
|
||||||
function DirectoryTable<T, U>({ data, setFileName }: DirectoryTableProps) {
|
function DirectoryTable({ data, cwd, setFileName }: DirectoryTableProps) {
|
||||||
const [columns] = React.useState<typeof defaultColumns>(() => [...defaultColumns]);
|
const [columns] = React.useState<typeof defaultColumns>(() => [...defaultColumns]);
|
||||||
const table = useReactTable({
|
const table = useReactTable({
|
||||||
data,
|
data,
|
||||||
@ -75,9 +76,9 @@ function DirectoryTable<T, U>({ data, setFileName }: DirectoryTableProps) {
|
|||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
{table.getState().columnSizingInfo.isResizingColumn ? (
|
{table.getState().columnSizingInfo.isResizingColumn ? (
|
||||||
<MemoizedTableBody table={table} setFileName={setFileName} />
|
<MemoizedTableBody table={table} cwd={cwd} setFileName={setFileName} />
|
||||||
) : (
|
) : (
|
||||||
<TableBody table={table} setFileName={setFileName} />
|
<TableBody table={table} cwd={cwd} setFileName={setFileName} />
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@ -85,10 +86,11 @@ function DirectoryTable<T, U>({ data, setFileName }: DirectoryTableProps) {
|
|||||||
|
|
||||||
interface TableBodyProps {
|
interface TableBodyProps {
|
||||||
table: Table<FileInfo>;
|
table: Table<FileInfo>;
|
||||||
|
cwd: string;
|
||||||
setFileName: (_: string) => void;
|
setFileName: (_: string) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
function TableBody({ table, setFileName }: TableBodyProps) {
|
function TableBody({ table, cwd, setFileName }: TableBodyProps) {
|
||||||
return (
|
return (
|
||||||
<div className="dir-table-body">
|
<div className="dir-table-body">
|
||||||
{table.getRowModel().rows.map((row) => (
|
{table.getRowModel().rows.map((row) => (
|
||||||
@ -98,18 +100,21 @@ function TableBody({ table, setFileName }: TableBodyProps) {
|
|||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
onDoubleClick={() => {
|
onDoubleClick={() => {
|
||||||
const newFileName = row.getValue("path") as string;
|
const newFileName = row.getValue("path") as string;
|
||||||
setFileName(newFileName);
|
const fullPath = cwd.concat("/", newFileName);
|
||||||
|
setFileName(fullPath);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{row.getVisibleCells().map((cell) => (
|
{row.getVisibleCells().map((cell) => {
|
||||||
|
return (
|
||||||
<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>()}
|
{cell.renderValue<string>()}
|
||||||
</div>
|
</div>
|
||||||
))}
|
);
|
||||||
|
})}
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
@ -130,7 +135,7 @@ function DirectoryPreview({ contentAtom, fileNameAtom }: DirectoryPreviewProps)
|
|||||||
const contentText = jotai.useAtomValue(contentAtom);
|
const contentText = jotai.useAtomValue(contentAtom);
|
||||||
let content: FileInfo[] = JSON.parse(contentText);
|
let content: FileInfo[] = JSON.parse(contentText);
|
||||||
let [fileName, setFileName] = jotai.useAtom(fileNameAtom);
|
let [fileName, setFileName] = jotai.useAtom(fileNameAtom);
|
||||||
return <DirectoryTable data={content} setFileName={setFileName} />;
|
return <DirectoryTable data={content} cwd={fileName} setFileName={setFileName} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
export { DirectoryPreview };
|
export { DirectoryPreview };
|
||||||
|
@ -14,6 +14,39 @@ import "./view.less";
|
|||||||
|
|
||||||
const MaxFileSize = 1024 * 1024 * 10; // 10MB
|
const MaxFileSize = 1024 * 1024 * 10; // 10MB
|
||||||
|
|
||||||
|
function DirNav({ cwdAtom }: { cwdAtom: jotai.WritableAtom<string, [string], void> }) {
|
||||||
|
const [cwd, setCwd] = jotai.useAtom(cwdAtom);
|
||||||
|
let splitNav = [cwd];
|
||||||
|
let remaining = cwd;
|
||||||
|
|
||||||
|
let idx = remaining.lastIndexOf("/");
|
||||||
|
while (idx !== -1) {
|
||||||
|
remaining = remaining.substring(0, idx);
|
||||||
|
splitNav.unshift(remaining);
|
||||||
|
|
||||||
|
idx = remaining.lastIndexOf("/");
|
||||||
|
}
|
||||||
|
if (splitNav.length === 0) {
|
||||||
|
splitNav = [cwd];
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<div className="view-nav">
|
||||||
|
{splitNav.map((item) => {
|
||||||
|
let splitPath = item.split("/");
|
||||||
|
if (splitPath.length === 0) {
|
||||||
|
splitPath = [item];
|
||||||
|
}
|
||||||
|
const baseName = splitPath[splitPath.length - 1];
|
||||||
|
return (
|
||||||
|
<span className="view-nav-item" key={`nav-item-${item}`} onClick={() => setCwd(item)}>
|
||||||
|
{baseName}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function MarkdownPreview({ contentAtom }: { contentAtom: jotai.Atom<Promise<string>> }) {
|
function MarkdownPreview({ contentAtom }: { contentAtom: jotai.Atom<Promise<string>> }) {
|
||||||
const readmeText = jotai.useAtomValue(contentAtom);
|
const readmeText = jotai.useAtomValue(contentAtom);
|
||||||
return (
|
return (
|
||||||
@ -62,6 +95,7 @@ function StreamingPreview({ fileInfo }: { fileInfo: FileInfo }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
||||||
return (
|
return (
|
||||||
@ -70,6 +104,7 @@ function PreviewView({ blockId }: { blockId: string }) {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
const blockAtom = WOS.getWaveObjectAtom<Block>(`block:${blockId}`);
|
const blockAtom = WOS.getWaveObjectAtom<Block>(`block:${blockId}`);
|
||||||
const fileNameAtom: jotai.WritableAtom<string, [string], void> = useBlockCache(blockId, "preview:filename", () =>
|
const fileNameAtom: jotai.WritableAtom<string, [string], void> = useBlockCache(blockId, "preview:filename", () =>
|
||||||
jotai.atom<string, [string], void>(
|
jotai.atom<string, [string], void>(
|
||||||
@ -121,40 +156,45 @@ function PreviewView({ blockId }: { blockId: string }) {
|
|||||||
mimeType = "";
|
mimeType = "";
|
||||||
}
|
}
|
||||||
const fileInfo = jotai.useAtomValue(statFileAtom);
|
const fileInfo = jotai.useAtomValue(statFileAtom);
|
||||||
|
const fileContent = jotai.useAtomValue(fileContentAtom);
|
||||||
|
|
||||||
// handle streaming files here
|
// handle streaming files here
|
||||||
|
let specializedView: React.ReactNode;
|
||||||
if (
|
if (
|
||||||
mimeType == "application/pdf" ||
|
mimeType == "application/pdf" ||
|
||||||
mimeType.startsWith("video/") ||
|
mimeType.startsWith("video/") ||
|
||||||
mimeType.startsWith("audio/") ||
|
mimeType.startsWith("audio/") ||
|
||||||
mimeType.startsWith("image/")
|
mimeType.startsWith("image/")
|
||||||
) {
|
) {
|
||||||
return <StreamingPreview fileInfo={fileInfo} />;
|
specializedView = <StreamingPreview fileInfo={fileInfo} />;
|
||||||
}
|
} else if (fileInfo == null) {
|
||||||
if (fileInfo == null) {
|
specializedView = <CenteredDiv>File Not Found</CenteredDiv>;
|
||||||
return <CenteredDiv>File Not Found</CenteredDiv>;
|
} else if (fileInfo.size > MaxFileSize) {
|
||||||
}
|
specializedView = <CenteredDiv>File Too Large to Preview</CenteredDiv>;
|
||||||
if (fileInfo.size > MaxFileSize) {
|
} else if (mimeType === "text/markdown") {
|
||||||
return <CenteredDiv>File Too Large to Preview</CenteredDiv>;
|
specializedView = <MarkdownPreview contentAtom={fileContentAtom} />;
|
||||||
}
|
} else if (mimeType.startsWith("text/")) {
|
||||||
if (mimeType === "text/markdown") {
|
specializedView = (
|
||||||
return <MarkdownPreview contentAtom={fileContentAtom} />;
|
|
||||||
}
|
|
||||||
if (mimeType.startsWith("text/")) {
|
|
||||||
return (
|
|
||||||
<div className="view-preview view-preview-text">
|
<div className="view-preview view-preview-text">
|
||||||
<pre>{jotai.useAtomValue(fileContentAtom)}</pre>
|
<pre>{fileContent}</pre>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
} else if (mimeType === "directory") {
|
||||||
if (mimeType === "directory") {
|
specializedView = <DirectoryPreview contentAtom={fileContentAtom} fileNameAtom={fileNameAtom} />;
|
||||||
return <DirectoryPreview contentAtom={fileContentAtom} fileNameAtom={fileNameAtom} />;
|
} else {
|
||||||
}
|
specializedView = (
|
||||||
return (
|
|
||||||
<div className="view-preview">
|
<div className="view-preview">
|
||||||
<div>Preview ({mimeType})</div>
|
<div>Preview ({mimeType})</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="full-preview">
|
||||||
|
<DirNav cwdAtom={fileNameAtom} />
|
||||||
|
{specializedView}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export { PreviewView };
|
export { PreviewView };
|
||||||
|
@ -78,3 +78,27 @@
|
|||||||
align-items: start;
|
align-items: start;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.full-preview {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.view-nav {
|
||||||
|
display: flex;
|
||||||
|
gap: 0.5rem;
|
||||||
|
|
||||||
|
.view-nav-item {
|
||||||
|
background-color: var(--panel-bg-color);
|
||||||
|
border-radius: 3px;
|
||||||
|
padding: 0.2rem;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: var(--highlight-bg-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
background-color: var(--accent-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -77,9 +77,8 @@ 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: fullFilePath,
|
Path: innerFileInfoInt.Name(),
|
||||||
Size: innerFileInfoInt.Size(),
|
Size: innerFileInfoInt.Size(),
|
||||||
Mode: innerFileInfoInt.Mode(),
|
Mode: innerFileInfoInt.Mode(),
|
||||||
ModTime: innerFileInfoInt.ModTime().UnixMilli(),
|
ModTime: innerFileInfoInt.ModTime().UnixMilli(),
|
||||||
|
Loading…
Reference in New Issue
Block a user