// screens-library.jsx — library / asset grid + asset detail
const { ASSETS: ALL_ASSETS, BINS, COMMENTS, PROJECTS } = window.ZAMPP_DATA;
function Library({ navigate, onOpenAsset, project = "Protour 2026" }) {
const [bin, setBin] = React.useState("b1");
const [view, setView] = React.useState("grid");
const [filter, setFilter] = React.useState("all");
const [search, setSearch] = React.useState("");
let assets = ALL_ASSETS;
if (filter !== "all") assets = assets.filter(a => a.status === filter);
if (search) assets = assets.filter(a => a.name.toLowerCase().includes(search.toLowerCase()));
return (
{project}
· {assets.length} assets
setSearch(e.target.value)} placeholder="Filter assets…" />
{["all", "ready", "processing", "live", "error"].map(f => (
))}
{view === "grid" ? (
{assets.map(a =>
onOpenAsset(a)} />)}
) : (
Name
Duration
Resolution
Codec
Size
Updated
{assets.map(a => (
onOpenAsset(a)}>
{a.name}
{a.status}
{a.comments > 0 && · {a.comments} comments}
{a.duration}
{a.res}
{a.codec}
{a.size}
{a.updated}
))}
)}
);
}
function AssetCard({ asset, onOpen }) {
return (
{asset.status === "live" && LIVE}
{asset.status === "processing" && Proxy {asset.progress}%}
{asset.status === "error" && Error}
{asset.type === "video" &&
{asset.duration}
}
{asset.status === "processing" && (
)}
{asset.name}
{asset.res}
·
{asset.size}
{asset.comments > 0 && (
{asset.comments}
)}
);
}
function binIcon(name) {
return { grid: "library", live: "record", film: "film", proxy: "proxy", audio: "audio", package: "package" }[name] || "folder";
}
window.Library = Library;
window.AssetCard = AssetCard;