import {
AppBar,
Box,
Button,
Chip,
Divider,
IconButton,
Stack,
Toolbar,
Tooltip,
Typography,
} from "@mui/material";
import OpenInNewRoundedIcon from "@mui/icons-material/OpenInNewRounded";
import RefreshRoundedIcon from "@mui/icons-material/RefreshRounded";
import HubRoundedIcon from "@mui/icons-material/HubRounded";
import type { IRGraphMeta, ResolvedModel } from "../types";
import { GranularitySlider } from "./GranularitySlider";
interface Props {
resolved: ResolvedModel | null;
meta: IRGraphMeta | null;
onReset: () => void;
granularity: number;
maxGranularity: number;
visibleNodeCount: number;
onGranularityChange: (v: number) => void;
bytesTransferred: number;
}
function bytesPretty(n: number): string {
if (n < 1024) return `${n} B`;
if (n < 1024 * 1024) return `${(n / 1024).toFixed(1)} KB`;
if (n < 1024 * 1024 * 1024) return `${(n / (1024 * 1024)).toFixed(1)} MB`;
return `${(n / (1024 * 1024 * 1024)).toFixed(2)} GB`;
}
function formatParams(n: number): string {
if (n === 0) return "0";
if (n < 1_000_000) return `${(n / 1_000).toFixed(1)}K`;
if (n < 1_000_000_000) return `${(n / 1_000_000).toFixed(1)}M`;
return `${(n / 1_000_000_000).toFixed(2)}B`;
}
/** Split `owner/name` into a 2-tuple. Falls back gracefully on malformed input. */
function splitRepo(repoId: string): { owner: string; name: string } {
const i = repoId.indexOf("/");
if (i < 0) return { owner: "", name: repoId };
return { owner: repoId.slice(0, i), name: repoId.slice(i + 1) };
}
const MONO_FONT =
'"JetBrains Mono", "SFMono-Regular", ui-monospace, Menlo, Consolas, monospace';
const verticalRule = (
);
export function Header({
resolved,
meta,
onReset,
granularity,
maxGranularity,
visibleNodeCount,
onGranularityChange,
bytesTransferred,
}: Props) {
// Effective bandwidth savings: compare the *expected* full-file size to the
// bytes we actually pulled over the wire (just header metadata thanks to
// raw_data skipping + external-data detection).
const totalSize = resolved?.sizeBytes ?? 0;
const savings =
totalSize > 0 && bytesTransferred > 0 && bytesTransferred < totalSize
? 1 - bytesTransferred / totalSize
: 0;
const savingsLabel =
savings > 0.05 ? `${(savings * 100).toFixed(0)}% saved` : null;
const { owner, name } = splitRepo(resolved?.repoId ?? "");
return (
{/* ──────────── Brand ──────────── */}
HF Model Viewer
architecture explorer
{resolved && (
<>
{verticalRule}
{/* ──────────── Repo crumb ──────────── */}
{owner && (
{owner}
/
)}
{name}
{meta?.modelType && (
)}
{/* ──────────── Granularity (full-width second row on mobile) ──────────── */}
{maxGranularity > 0 && (
)}
{verticalRule}
{/* ──────────── Stats + actions ──────────── */}
{meta && (
)}
{savingsLabel && (
)}
}
href={`https://huggingface.co/${resolved.repoId}`}
target="_blank"
rel="noreferrer"
sx={{
fontSize: 12,
fontWeight: 600,
textTransform: "none",
whiteSpace: "nowrap",
color: "rgba(220,228,255,0.85)",
px: { xs: 0.8, sm: 1.2 },
minWidth: { xs: 32, sm: "auto" },
"&:hover": {
background: "rgba(155,180,255,0.08)",
color: "rgba(245,248,255,0.96)",
},
"& .MuiButton-endIcon": {
ml: { xs: 0, sm: 0.5 },
},
}}
>
View on HF
>
)}
{!resolved && }
);
}