Merge pull request #14 from wavetermdev/sylvie/backwards-nav

Preview Navigation Chrome
This commit is contained in:
Mike Sawka 2024-06-03 16:25:35 -07:00 committed by GitHub
commit a51be0dc6a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 105 additions and 37 deletions

View File

@ -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 };

View File

@ -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 };

View File

@ -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);
}
}
}

View File

@ -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(),