file browser small UI improvements

This commit is contained in:
makearmy 2025-10-15 21:45:00 -04:00
parent 2dfeb4e2bb
commit edcde5ba55

View file

@ -1,7 +1,15 @@
"use client"; "use client";
import React, { useEffect, useMemo, useState, useCallback } from "react"; import React, { useEffect, useMemo, useState, useCallback } from "react";
import { Loader2, Download, Folder, FileText, RefreshCw, ArrowUp, Home } from "lucide-react"; import {
Loader2,
Download,
Folder,
FileText,
RefreshCw,
ArrowUp,
Home,
} from "lucide-react";
type FileItem = { type FileItem = {
name: string; name: string;
@ -117,119 +125,131 @@ export default function FileBrowserPanel() {
return ( return (
<div className="space-y-3"> <div className="space-y-3">
<div className="flex items-center gap-2"> <style>{`
<button @media (min-width: 1024px) {
onClick={onHome} .fs-grid {
className="inline-flex items-center gap-2 rounded-md border px-3 py-1.5 text-sm hover:bg-muted" display: grid;
title="Root" grid-template-columns: 1fr clamp(340px, 36vw, 480px);
> gap: 1rem;
<Home className="h-4 w-4" /> root }
</button> }
<div className="ml-auto flex items-center gap-2"> `}</style>
<button
onClick={fetchList}
className="inline-flex items-center gap-2 rounded-md border px-3 py-1.5 text-sm hover:bg-muted"
title="Refresh"
>
<RefreshCw className="h-4 w-4" /> Refresh
</button>
<button
onClick={onUp}
className="inline-flex items-center gap-2 rounded-md border px-3 py-1.5 text-sm hover:bg-muted"
title="Up one folder"
>
<ArrowUp className="h-4 w-4" /> Up
</button>
</div>
</div>
<div className="text-xs text-muted-foreground select-all">{path}</div> <div className="flex items-center gap-2">
<button
{/* Wider table, same preview: left has min 760px; table can scroll horizontally if cramped */} onClick={onHome}
<div className="grid grid-cols-1 lg:grid-cols-[minmax(760px,1fr),420px] gap-4"> className="inline-flex items-center gap-2 rounded-md border px-3 py-1.5 text-sm hover:bg-muted"
{/* TABLE */} title="Root"
<div className="rounded-md border overflow-hidden"> >
<div className="overflow-x-auto"> <Home className="h-4 w-4" /> root
<div className="min-w-[740px]"> </button>
<div className="grid grid-cols-[minmax(340px,1fr),110px,120px,170px,120px] items-center bg-muted px-3 py-2 text-sm font-medium whitespace-nowrap"> <div className="ml-auto flex items-center gap-2">
<div>Name</div> <button
<div>Type</div> onClick={fetchList}
<div>Size</div> className="inline-flex items-center gap-2 rounded-md border px-3 py-1.5 text-sm hover:bg-muted"
<div>Modified</div> title="Refresh"
<div className="text-right">Actions</div> >
</div> <RefreshCw className="h-4 w-4" /> Refresh
</button>
<div className="divide-y"> <button
{loading ? ( onClick={onUp}
<div className="p-6 text-sm text-muted-foreground flex items-center gap-2"> className="inline-flex items-center gap-2 rounded-md border px-3 py-1.5 text-sm hover:bg-muted"
<Loader2 className="h-4 w-4 animate-spin" /> Loading title="Up one folder"
>
<ArrowUp className="h-4 w-4" /> Up
</button>
</div> </div>
) : error ? ( </div>
<div className="p-6 text-sm text-rose-400">Error: {error}</div>
) : items.length === 0 ? ( <div className="text-xs text-muted-foreground select-all">{path || "/"}</div>
<div className="p-6 text-sm text-muted-foreground">Empty folder.</div>
) : ( <div className="fs-grid">
items.map((it) => ( {/* TABLE */}
<div <div className="rounded-md border overflow-hidden">
key={it.name + it.type} <div className="overflow-x-auto">
className="grid grid-cols-[minmax(340px,1fr),110px,120px,170px,120px] items-center px-3 py-2 text-sm hover:bg-muted/50" <div className="min-w-[560px]">
> {/* compact column plan: name grows; others stay tidy */}
<button <div className="grid grid-cols-[minmax(260px,1fr),88px,92px,156px,auto] items-center bg-muted px-3 py-2 text-sm font-medium">
className="text-left inline-flex items-center gap-2 hover:underline" <div>Name</div>
onClick={() => onOpen(it)} <div>Type</div>
title={it.type === "dir" ? "Open folder" : "Preview"} <div>Size</div>
> <div>Modified</div>
{it.type === "dir" ? ( <div className="text-right">Actions</div>
<Folder className="h-4 w-4" /> </div>
) : (
<FileText className="h-4 w-4" /> <div className="divide-y">
)} {loading ? (
<span className="truncate">{it.name}</span> <div className="p-6 text-sm text-muted-foreground flex items-center gap-2">
</button> <Loader2 className="h-4 w-4 animate-spin" /> Loading
<div className="uppercase tracking-wide text-[11px] text-muted-foreground">
{it.type}
</div> </div>
<div className="text-muted-foreground">{formatSize(it.size)}</div> ) : error ? (
<div className="text-muted-foreground"> <div className="p-6 text-sm text-rose-400">Error: {error}</div>
{it.mtimeMs ? new Date(it.mtimeMs).toLocaleString() : "—"} ) : items.length === 0 ? (
</div> <div className="p-6 text-sm text-muted-foreground">Empty folder.</div>
<div className="text-right"> ) : (
{it.type === "file" && ( items.map((it) => (
<button <div
onClick={() => onDownload(it)} key={it.name + it.type}
className="inline-flex items-center gap-1 rounded-md border px-2 py-1 text-xs hover:bg-muted" className="grid grid-cols-[minmax(260px,1fr),88px,92px,156px,auto] items-center px-3 py-2 text-sm hover:bg-muted/50"
title="Download"
> >
<Download className="h-3.5 w-3.5" /> <button
Download className="text-left inline-flex items-center gap-2 hover:underline min-w-0"
onClick={() => onOpen(it)}
title={it.type === "dir" ? "Open folder" : "Preview"}
>
{it.type === "dir" ? (
<Folder className="h-4 w-4 shrink-0" />
) : (
<FileText className="h-4 w-4 shrink-0" />
)}
<span className="truncate">{it.name}</span>
</button> </button>
)} <div className="uppercase tracking-wide text-[11px] text-muted-foreground">
</div> {it.type}
</div> </div>
)) <div className="text-muted-foreground">{formatSize(it.size)}</div>
)} <div className="text-muted-foreground">
</div> {it.mtimeMs ? new Date(it.mtimeMs).toLocaleString() : "—"}
</div> </div>
</div> <div className="text-right">
</div> {it.type === "file" && (
<button
{/* PREVIEW (unchanged size) */} onClick={() => onDownload(it)}
<div className="rounded-md border p-3"> className="inline-flex items-center gap-1 rounded-md border px-2 py-1 text-xs hover:bg-muted"
<div className="mb-2 text-sm font-medium">Preview</div> title="Download"
{previewHref ? ( >
<div className="border rounded overflow-hidden"> <Download className="h-3.5 w-3.5" />
<iframe Download
key={previewHref} </button>
src={previewHref} )}
className="w-full h-[420px]" </div>
title="Preview" </div>
/> ))
)}
</div>
</div>
</div>
</div>
{/* PREVIEW */}
<div className="rounded-md border p-3">
<div className="mb-2 text-sm font-medium">Preview</div>
{previewHref ? (
<div className="border rounded overflow-hidden">
<iframe
key={previewHref}
src={previewHref}
className="w-full h-[420px]"
title="Preview"
/>
</div>
) : (
<div className="text-sm text-muted-foreground">
Select a file to preview.
</div>
)}
</div>
</div>
</div> </div>
) : (
<div className="text-sm text-muted-foreground">Select a file to preview.</div>
)}
</div>
</div>
</div>
); );
} }