From 52873a218023c2af95a14265cfc3e7e7f34c3e5a Mon Sep 17 00:00:00 2001 From: Garrett Mills Date: Fri, 23 Oct 2026 23:18:27 -0500 Subject: [PATCH] Deck analysis shows total cost; tidier analysis layout A "cost" tile totals the USD price of every copy in the deck (commander included, maybeboard not). The stat tiles now span the panel and size to their values, with the color bars and mana curve sharing the row below, and the left-hand panels no longer spread out to match the analysis panel's height. Closes #20 --- src/styles.css | 27 ++++++++++++++++++++++----- src/views/DeckView.tsx | 30 ++++++++++++++++++++++++------ 2 files changed, 46 insertions(+), 11 deletions(-) diff --git a/src/styles.css b/src/styles.css index c12b9a7..00a4a19 100644 --- a/src/styles.css +++ b/src/styles.css @@ -2620,7 +2620,11 @@ tbody tr:hover { grid-template-areas: "commander stats" "meta stats" - "legality stats"; + "legality stats" + ". stats"; + /* The last row takes whatever height the analysis panel adds, so the + left-hand panels stack together instead of spreading out to match. */ + grid-template-rows: auto auto auto 1fr; align-items: start; } } @@ -2701,12 +2705,25 @@ tbody tr:hover { display: flex; flex-direction: column; gap: 8px; - min-width: 220px; + flex: 1 1 240px; + min-width: 0; +} +/* The analysis tiles span the panel above the bars and curve. They size to + their value (a "$1,234" cost is wider than a card count) and share out any + spare width, wrapping on narrow screens rather than squeezing a value past + its tile's edges. */ +.deck-stats .stat-tiles-row { + flex-wrap: wrap; +} +.deck-stats .stat-tile { + flex: 1 0 auto; + padding: 8px 10px; } .deck-stats-curve { - flex: 1; - min-width: 220px; - max-width: 420px; + /* Shares the row with the color bars, or takes the full width once they + wrap onto separate lines. */ + flex: 1 1 240px; + min-width: 0; display: flex; flex-direction: column; } diff --git a/src/views/DeckView.tsx b/src/views/DeckView.tsx index 4b38fc2..af01a56 100644 --- a/src/views/DeckView.tsx +++ b/src/views/DeckView.tsx @@ -88,6 +88,9 @@ interface DeckStats { uniqueCards: number; landCount: number; avgManaValue: number; + /** USD for every copy in the deck, commander included; cards without a + * known price count as $0. */ + totalCost: number; curve: { label: string; count: number; @@ -175,11 +178,17 @@ function computeDeckStats(contents: DeckEntry[]): DeckStats { } } + // Unlike the rest, cost counts the commander: it's a card you have to buy. + const totalCost = contents + .filter((e) => !e.is_maybeboard) + .reduce((sum, e) => sum + e.price_usd * e.quantity, 0); + return { totalCards, uniqueCards: cards.length, landCount, avgManaValue, + totalCost, curve, colorCounts, colorlessCount, @@ -190,6 +199,14 @@ function computeDeckStats(contents: DeckEntry[]): DeckStats { }; } +/** "$84.50", or whole dollars once it's big enough that cents are noise. */ +function formatCost(usd: number): string { + return `$${usd.toLocaleString(undefined, { + minimumFractionDigits: usd >= 100 ? 0 : 2, + maximumFractionDigits: usd >= 100 ? 0 : 2, + })}`; +} + /** A prominent, art-forward display for a deck's commander (Commander/Brawl). */ function CommanderHero({ card, @@ -1207,14 +1224,15 @@ export function DeckView({
Deck analysis
+
+ + + + + +
-
- - - - -
Color identity