Skip to content

Commit 5c0efe1

Browse files
committed
feat(app): move build cost into a "Building summary" slideout drawer
The one-time build cost (buildings + materials to construct the block) is a shopping list you rarely need inline — it just pushed the recipe grid down. Drop the inline card and put it behind a hammer icon in the block header that opens a right-side drawer (reusing the Sheet primitive). Zero inline real estate; the recipe grid now sits right under the block balance.
1 parent 4071457 commit 5c0efe1

1 file changed

Lines changed: 63 additions & 54 deletions

File tree

app/src/routes/block.$id.tsx

Lines changed: 63 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ import {
5858
Gamepad2,
5959
Grid2x2,
6060
GripVertical,
61+
Hammer,
6162
Lock,
6263
MapPin,
6364
Pencil,
@@ -71,6 +72,13 @@ import {
7172
import { ItemHover, RecipeHover, TechLine } from "../lib/recipe-card";
7273
import { Badge } from "#/components/ui/badge.tsx";
7374
import { Card, CardContent, CardHeader, CardTitle } from "#/components/ui/card.tsx";
75+
import {
76+
Sheet,
77+
SheetContent,
78+
SheetHeader,
79+
SheetTitle,
80+
SheetTrigger,
81+
} from "#/components/ui/sheet.tsx";
7482
import { HelpButton } from "#/components/help-drawer.tsx";
7583
import { Input } from "#/components/ui/input.tsx";
7684

@@ -1021,6 +1029,61 @@ function Block({ blockId }: { blockId: number }) {
10211029
>
10221030
<Gamepad2 className={`size-4 ${showInGame.isPending ? "animate-pulse" : ""}`} />
10231031
</button>
1032+
{res?.buildCost && res.buildCost.buildings.length > 0 && (
1033+
<Sheet>
1034+
<SheetTrigger asChild>
1035+
<button
1036+
title="Building summary — the buildings + one-time materials to construct this block"
1037+
className="flex size-7 items-center justify-center rounded border border-border text-muted-foreground hover:bg-muted hover:text-foreground"
1038+
>
1039+
<Hammer className="size-4" />
1040+
</button>
1041+
</SheetTrigger>
1042+
<SheetContent side="right" className="w-96 max-w-[92vw] font-mono">
1043+
<SheetHeader>
1044+
<SheetTitle>Building summary</SheetTitle>
1045+
</SheetHeader>
1046+
<div className="min-h-0 flex-1 space-y-4 overflow-auto p-3">
1047+
<p className="text-xs text-muted-foreground">
1048+
The buildings to construct this block, and the one-time materials to build them —
1049+
a shopping list, separate from the per-second flows.
1050+
</p>
1051+
<div>
1052+
<div className="mb-1.5 text-xs font-semibold text-muted-foreground">
1053+
Buildings
1054+
</div>
1055+
<div className="flex flex-wrap gap-2">
1056+
{res.buildCost.buildings.map((b) => (
1057+
<span key={b.name} className={cellChip} title={b.display}>
1058+
<Icon kind="item" name={b.name} size="sm" />
1059+
<span className="tabular-nums">×{b.count}</span>
1060+
</span>
1061+
))}
1062+
</div>
1063+
</div>
1064+
<div>
1065+
<div className="mb-1.5 text-xs font-semibold text-muted-foreground">
1066+
Materials to build them
1067+
</div>
1068+
{res.buildCost.materials.length === 0 ? (
1069+
<span className="text-sm text-muted-foreground">
1070+
— (no build recipe found for these buildings)
1071+
</span>
1072+
) : (
1073+
<div className="flex flex-wrap gap-2">
1074+
{res.buildCost.materials.map((m) => (
1075+
<span key={m.name} className={cellChip} title={m.display}>
1076+
<Icon kind={m.kind as "item" | "fluid"} name={m.name} size="sm" />
1077+
<span className="tabular-nums">{fmtAmt(m.amount)}</span>
1078+
</span>
1079+
))}
1080+
</div>
1081+
)}
1082+
</div>
1083+
</div>
1084+
</SheetContent>
1085+
</Sheet>
1086+
)}
10241087
{showInGame.data && !showInGame.data.sent && (
10251088
<span className="text-xs text-amber-300">game not connected</span>
10261089
)}
@@ -1557,60 +1620,6 @@ function Block({ blockId }: { blockId: number }) {
15571620
</Card>
15581621
</div>
15591622

1560-
{/* One-time build cost: the materials to construct this block's buildings (#38)
1561-
— why e.g. steel is needed even when no recipe in the chain consumes it. */}
1562-
{res?.buildCost && res.buildCost.buildings.length > 0 && (
1563-
<Card className="mb-4">
1564-
<CardHeader className="justify-between">
1565-
<CardTitle>Build cost (one-time)</CardTitle>
1566-
<HelpButton title="Build cost">
1567-
<p>
1568-
The materials needed to{" "}
1569-
<span className="text-foreground">construct this block&apos;s buildings</span> — the
1570-
&quot;build the stuff to build the stuff&quot; requirement. It&apos;s a one-time
1571-
cost (not a per-second rate), and it&apos;s why something like steel is required
1572-
even when no recipe in the chain consumes it.
1573-
</p>
1574-
<p>
1575-
Direct ingredients of each building&apos;s own recipe, summed over the building
1576-
counts (rounded up to whole machines). Producing those materials&apos; own sub-chain
1577-
is the factory ledger&apos;s job.
1578-
</p>
1579-
</HelpButton>
1580-
</CardHeader>
1581-
<CardContent className="space-y-3">
1582-
<div>
1583-
<div className="mb-1 text-xs text-muted-foreground">Buildings</div>
1584-
<div className="flex flex-wrap gap-2">
1585-
{res.buildCost.buildings.map((b) => (
1586-
<span key={b.name} className={cellChip} title={b.display}>
1587-
<Icon kind="item" name={b.name} size="sm" />
1588-
<span className="tabular-nums">×{b.count}</span>
1589-
</span>
1590-
))}
1591-
</div>
1592-
</div>
1593-
<div>
1594-
<div className="mb-1 text-xs text-muted-foreground">Materials to build them</div>
1595-
{res.buildCost.materials.length === 0 ? (
1596-
<span className="text-sm text-muted-foreground">
1597-
— (no build recipe found for these buildings)
1598-
</span>
1599-
) : (
1600-
<div className="flex flex-wrap gap-2">
1601-
{res.buildCost.materials.map((m) => (
1602-
<span key={m.name} className={cellChip} title={m.display}>
1603-
<Icon kind={m.kind as "item" | "fluid"} name={m.name} size="sm" />
1604-
<span className="tabular-nums">{fmtAmt(m.amount)}</span>
1605-
</span>
1606-
))}
1607-
</div>
1608-
)}
1609-
</div>
1610-
</CardContent>
1611-
</Card>
1612-
)}
1613-
16141623
<BlockTasks blockId={blockId} />
16151624

16161625
{/* Recipe grid: each row's I/O at the solved rate. Click any item to add a

0 commit comments

Comments
 (0)