Restructure into pnpm monorepo with game shell, docs, and SpacetimeDB backend
- Restructure flat static prototype into pnpm workspace monorepo - apps/game: playable shell with R3F 3D scene, HUD, SpacetimeDB connection - apps/docs: design docs and prototypes - apps/site: landing page - packages/ui: shared Button and Panel primitives - services/spacetimedb: backend module (9 tables, 11 reducers) - Archive legacy static files to archive/legacy-static/ - Game loop: connect, undock, target, approach, dock, mine, sell - Add pnpm-workspace.yaml, tsconfig.base.json, spacetime.json
This commit is contained in:
59
apps/game/src/ui/TargetPanel.tsx
Normal file
59
apps/game/src/ui/TargetPanel.tsx
Normal file
@@ -0,0 +1,59 @@
|
||||
import { Button, Panel } from "@void-nav/ui";
|
||||
import type { PointOfInterest, Ship } from "../module_bindings/types";
|
||||
|
||||
export function TargetPanel({
|
||||
ship,
|
||||
pois,
|
||||
selected,
|
||||
onSelect,
|
||||
}: {
|
||||
ship?: Ship;
|
||||
pois: PointOfInterest[];
|
||||
selected?: PointOfInterest;
|
||||
onSelect: (poiId: string) => void;
|
||||
}) {
|
||||
const current = pois.find((poi) => poi.poiId === ship?.currentPoiId);
|
||||
|
||||
return (
|
||||
<Panel className="p-4">
|
||||
<div className="flex items-start justify-between gap-3">
|
||||
<div>
|
||||
<p className="m-0 font-mono text-xs uppercase tracking-[0.1em] text-muted">Selected Target</p>
|
||||
<h2 className="m-0 mt-1 text-lg leading-tight text-fg-bright">{selected?.name ?? "No target selected"}</h2>
|
||||
</div>
|
||||
<span className="rounded-md border border-border bg-bg-subtle px-2 py-1 font-mono text-xs uppercase tracking-[0.08em] text-fg-dim">
|
||||
{ship?.flightMode ?? "offline"}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<dl className="mt-3 grid gap-2 text-sm">
|
||||
<InfoRow label="Current" value={current?.name ?? "Unknown"} />
|
||||
<InfoRow label="Target type" value={selected?.poiType.replace("_", " ") ?? "Select in scene or list"} />
|
||||
</dl>
|
||||
|
||||
<div className="mt-4 grid gap-2">
|
||||
{pois.map((poi) => (
|
||||
<Button
|
||||
key={poi.poiId}
|
||||
tone={selected?.poiId === poi.poiId ? "primary" : "secondary"}
|
||||
className="min-h-9 w-full justify-between px-3 text-left"
|
||||
onClick={() => onSelect(poi.poiId)}
|
||||
disabled={!ship}
|
||||
>
|
||||
<span className="flex-1 text-left">{poi.name}</span>
|
||||
<span className="shrink-0 pl-3 font-mono text-xs opacity-75">{poi.poiType === "asteroid_belt" ? "Belt" : "Station"}</span>
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
</Panel>
|
||||
);
|
||||
}
|
||||
|
||||
function InfoRow({ label, value }: { label: string; value: string }) {
|
||||
return (
|
||||
<div className="grid grid-cols-[5.5rem_1fr] gap-2 border-t border-border pt-2">
|
||||
<dt className="font-mono text-xs uppercase tracking-[0.08em] text-muted">{label}</dt>
|
||||
<dd className="m-0 text-fg">{value}</dd>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user