Files
vpinball/components/GameInfoPanel.tsx
T
valknarandClaude Sonnet 5 e493a12e68 Add vpinball: a browser Visual Pinball player
Next.js app that plays real .vpx tables via @valknar/vpinball-wasm
(WebAssembly Visual Pinball). Demo mode with the bundled default
table, drag-and-drop custom table upload, a cabinet-styled UI with a
coin-door HUD (fullscreen/stats/info/eject), a custom 404 page, PWA
support (hand-rolled service worker), and a static Docker Compose
deployment behind nginx.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012hQoM3jJT1Lx7CMTciMzvD
2026-08-23 05:25:15 +02:00

39 lines
1.5 KiB
TypeScript

import { formatBytes, formatDuration } from "@/lib/format";
import { KEY_BINDINGS } from "@/lib/pinball/keyBindings";
import type { TableInfo } from "@/lib/pinball/types";
export interface GameInfoPanelProps {
tableInfo: TableInfo;
loadTimeMs: number | null;
}
export default function GameInfoPanel({ tableInfo, loadTimeMs }: GameInfoPanelProps) {
return (
<div className="w-72 space-y-4 rounded border border-chrome/30 bg-ash/95 p-4 font-mono text-sm text-paper shadow-xl">
<div>
<div className="text-xs tracking-widest text-chrome">TABLE</div>
<div className="truncate text-arc">{tableInfo.name}</div>
</div>
<dl className="grid grid-cols-2 gap-x-2 gap-y-1 text-xs">
<dt className="text-chrome">Source</dt>
<dd>{tableInfo.isDemo ? "Bundled demo" : "Your upload"}</dd>
<dt className="text-chrome">Size</dt>
<dd>{tableInfo.isDemo ? "—" : formatBytes(tableInfo.sizeBytes)}</dd>
<dt className="text-chrome">Load time</dt>
<dd>{loadTimeMs !== null ? formatDuration(loadTimeMs) : "—"}</dd>
</dl>
<div>
<div className="mb-1 text-xs tracking-widest text-chrome">CONTROLS</div>
<ul className="space-y-1 text-xs">
{KEY_BINDINGS.map((binding) => (
<li key={binding.action} className="flex justify-between gap-2">
<span className="text-chrome">{binding.action}</span>
<span className="text-paper">{binding.keys}</span>
</li>
))}
</ul>
</div>
</div>
);
}