UI / Collecting

SetSummary

Set completion panel with standard, master, loading, empty, and error states.

Scarlet & Violet 151

63%
Cards
178/207
Master
228/360
Chase cards
5/7
Missing
+22
import { SetSummary, type SetSummaryProps } from "@cardspark/ui/collecting"; const setSummary = {  name: "Scarlet & Violet 151",  code: "MEW",  game: "Pokemon",  series: "Scarlet & Violet",  releaseDate: "Sep 22, 2023",  mode: "master",  owned: 178,  total: 207,  masterOwned: 228,  masterTotal: 360,  chaseCards: [    { id: "mew-199", name: "Charizard ex", imageUrl: "https://images.pokemontcg.io/sv3pt5/199_hires.png" },    { id: "mew-198", name: "Venusaur ex", imageUrl: "https://images.pokemontcg.io/sv3pt5/198_hires.png" },    { id: "mew-200", name: "Blastoise ex", imageUrl: "https://images.pokemontcg.io/sv3pt5/200_hires.png", owned: false },    { id: "mew-201", name: "Alakazam ex", imageUrl: "https://images.pokemontcg.io/sv3pt5/201_hires.png" },    { id: "mew-202", name: "Zapdos ex", imageUrl: "https://images.pokemontcg.io/sv3pt5/202_hires.png" },    { id: "mew-203", name: "Erika's Invitation", imageUrl: "https://images.pokemontcg.io/sv3pt5/203_hires.png", owned: false },    { id: "mew-204", name: "Giovanni's Charisma", imageUrl: "https://images.pokemontcg.io/sv3pt5/204_hires.png" }  ],  missingCards: [    { id: "mew-167", name: "Ivysaur", imageUrl: "https://images.pokemontcg.io/sv3pt5/167_hires.png" },    { id: "mew-169", name: "Charmeleon", imageUrl: "https://images.pokemontcg.io/sv3pt5/169_hires.png" },    { id: "mew-171", name: "Wartortle", imageUrl: "https://images.pokemontcg.io/sv3pt5/171_hires.png" },    { id: "mew-175", name: "Psyduck", imageUrl: "https://images.pokemontcg.io/sv3pt5/175_hires.png" },    { id: "mew-176", name: "Poliwhirl", imageUrl: "https://images.pokemontcg.io/sv3pt5/176_hires.png" },    { id: "mew-177", name: "Machoke", imageUrl: "https://images.pokemontcg.io/sv3pt5/177_hires.png" },    { id: "mew-178", name: "Tangela", imageUrl: "https://images.pokemontcg.io/sv3pt5/178_hires.png" }  ]} satisfies SetSummaryProps; export function SetSummaryDemo() {  return <SetSummary {...setSummary} />;}

Installation

Install the package.

npm install @cardspark/ui

Import the shared stylesheet layer near your app root.

app/layout.tsx
import "@cardspark/ui/tokens.css";import "@cardspark/ui/themes/basement.css";import "@cardspark/ui/styles.css";

Import and render SetSummary from its package entry point.

SetSummaryDemo.tsx
import { SetSummary, type SetSummaryProps } from "@cardspark/ui/collecting"; const setSummary = {  name: "Scarlet & Violet 151",  code: "MEW",  game: "Pokemon",  series: "Scarlet & Violet",  releaseDate: "Sep 22, 2023",  mode: "master",  owned: 178,  total: 207,  masterOwned: 228,  masterTotal: 360,  chaseCards: [    { id: "mew-199", name: "Charizard ex", imageUrl: "https://images.pokemontcg.io/sv3pt5/199_hires.png" },    { id: "mew-198", name: "Venusaur ex", imageUrl: "https://images.pokemontcg.io/sv3pt5/198_hires.png" },    { id: "mew-200", name: "Blastoise ex", imageUrl: "https://images.pokemontcg.io/sv3pt5/200_hires.png", owned: false },    { id: "mew-201", name: "Alakazam ex", imageUrl: "https://images.pokemontcg.io/sv3pt5/201_hires.png" },    { id: "mew-202", name: "Zapdos ex", imageUrl: "https://images.pokemontcg.io/sv3pt5/202_hires.png" },    { id: "mew-203", name: "Erika's Invitation", imageUrl: "https://images.pokemontcg.io/sv3pt5/203_hires.png", owned: false },    { id: "mew-204", name: "Giovanni's Charisma", imageUrl: "https://images.pokemontcg.io/sv3pt5/204_hires.png" }  ],  missingCards: [    { id: "mew-167", name: "Ivysaur", imageUrl: "https://images.pokemontcg.io/sv3pt5/167_hires.png" },    { id: "mew-169", name: "Charmeleon", imageUrl: "https://images.pokemontcg.io/sv3pt5/169_hires.png" },    { id: "mew-171", name: "Wartortle", imageUrl: "https://images.pokemontcg.io/sv3pt5/171_hires.png" },    { id: "mew-175", name: "Psyduck", imageUrl: "https://images.pokemontcg.io/sv3pt5/175_hires.png" },    { id: "mew-176", name: "Poliwhirl", imageUrl: "https://images.pokemontcg.io/sv3pt5/176_hires.png" },    { id: "mew-177", name: "Machoke", imageUrl: "https://images.pokemontcg.io/sv3pt5/177_hires.png" },    { id: "mew-178", name: "Tangela", imageUrl: "https://images.pokemontcg.io/sv3pt5/178_hires.png" }  ]} satisfies SetSummaryProps; export function SetSummaryDemo() {  return <SetSummary {...setSummary} />;}

Usage

SetSummaryDemo.tsx
import { SetSummary, type SetSummaryProps } from "@cardspark/ui/collecting"; const setSummary = {  name: "Scarlet & Violet 151",  code: "MEW",  game: "Pokemon",  series: "Scarlet & Violet",  releaseDate: "Sep 22, 2023",  mode: "master",  owned: 178,  total: 207,  masterOwned: 228,  masterTotal: 360,  chaseCards: [    { id: "mew-199", name: "Charizard ex", imageUrl: "https://images.pokemontcg.io/sv3pt5/199_hires.png" },    { id: "mew-198", name: "Venusaur ex", imageUrl: "https://images.pokemontcg.io/sv3pt5/198_hires.png" },    { id: "mew-200", name: "Blastoise ex", imageUrl: "https://images.pokemontcg.io/sv3pt5/200_hires.png", owned: false },    { id: "mew-201", name: "Alakazam ex", imageUrl: "https://images.pokemontcg.io/sv3pt5/201_hires.png" },    { id: "mew-202", name: "Zapdos ex", imageUrl: "https://images.pokemontcg.io/sv3pt5/202_hires.png" },    { id: "mew-203", name: "Erika's Invitation", imageUrl: "https://images.pokemontcg.io/sv3pt5/203_hires.png", owned: false },    { id: "mew-204", name: "Giovanni's Charisma", imageUrl: "https://images.pokemontcg.io/sv3pt5/204_hires.png" }  ],  missingCards: [    { id: "mew-167", name: "Ivysaur", imageUrl: "https://images.pokemontcg.io/sv3pt5/167_hires.png" },    { id: "mew-169", name: "Charmeleon", imageUrl: "https://images.pokemontcg.io/sv3pt5/169_hires.png" },    { id: "mew-171", name: "Wartortle", imageUrl: "https://images.pokemontcg.io/sv3pt5/171_hires.png" },    { id: "mew-175", name: "Psyduck", imageUrl: "https://images.pokemontcg.io/sv3pt5/175_hires.png" },    { id: "mew-176", name: "Poliwhirl", imageUrl: "https://images.pokemontcg.io/sv3pt5/176_hires.png" },    { id: "mew-177", name: "Machoke", imageUrl: "https://images.pokemontcg.io/sv3pt5/177_hires.png" },    { id: "mew-178", name: "Tangela", imageUrl: "https://images.pokemontcg.io/sv3pt5/178_hires.png" }  ]} satisfies SetSummaryProps; export function SetSummaryDemo() {  return <SetSummary {...setSummary} />;}

Composition

Use SetSummary as the set-completion shell; pass set counts and preview-card arrays while the component handles the nested rails and thumbnail art.

SetSummary├── header│   ├── set identity│   ├── metadata / import state│   └── active completion value├── progress meter├── metric cells│   ├── cards count│   ├── optional master count│   ├── chase-card rail│   │   └── small CardArt thumbnails│   ├── missing-card rail│   │   └── small CardArt thumbnails│   └── complete collected-card rail│       ├── value-sorted small CardArt thumbnails│       └── adaptive +N count├── importing rail│   └── small CardArt thumbnails└── optional breakdown rows    └── RarityMark labels

Use `mode` only for standard versus master completion math. Use `chaseCards`, `missingCards`, `collectedCards`, and `importingCards` as rail data; those nested rails render compact CardArt previews and adaptive counts.

Features

  • Presents set completion through mode, owned, total, and label props for standard and master views.
  • Handles status plus importing and complete states through props rather than hard-coded examples.
  • Uses stable preview-card ids, forwards native article props and refs, and exposes the native click event.

Examples

Standard Progress

Use the default standard mode when the main bar should track ordinary set completion from `owned` and `total`; the layout still supports the same chase and missing rails as master progress.

Scarlet & Violet 151

86%
Cards
178/207
Chase cards
5/7
Missing
+22
import { SetSummary } from "@cardspark/ui/collecting"; const chaseCards = [  { id: "mew-199", name: "Charizard ex", imageUrl: "https://images.pokemontcg.io/sv3pt5/199_hires.png" },  { id: "mew-198", name: "Venusaur ex", imageUrl: "https://images.pokemontcg.io/sv3pt5/198_hires.png" },  { id: "mew-200", name: "Blastoise ex", imageUrl: "https://images.pokemontcg.io/sv3pt5/200_hires.png", owned: false }]; const missingCards = [  { id: "mew-167", name: "Ivysaur", imageUrl: "https://images.pokemontcg.io/sv3pt5/167_hires.png" },  { id: "mew-169", name: "Charmeleon", imageUrl: "https://images.pokemontcg.io/sv3pt5/169_hires.png" },  { id: "mew-171", name: "Wartortle", imageUrl: "https://images.pokemontcg.io/sv3pt5/171_hires.png" }]; export function StandardSetSummaryDemo() {  return (    <SetSummary      name="Scarlet & Violet 151"      game="Pokemon"      series="Scarlet & Violet"      releaseDate="Sep 22, 2023"      owned={178}      total={207}      chaseCards={chaseCards}      missingCards={missingCards}    />  );}

Master Progress

Use `mode="master"` when the main bar should use master-set counts; the extra master metric appears when master counts are provided.

Scarlet & Violet 151

63%
Cards
178/207
Master
228/360
Chase cards
5/7
Missing
+22
import { SetSummary } from "@cardspark/ui/collecting"; const chaseCards = [  { id: "mew-199", name: "Charizard ex", imageUrl: "https://images.pokemontcg.io/sv3pt5/199_hires.png" },  { id: "mew-198", name: "Venusaur ex", imageUrl: "https://images.pokemontcg.io/sv3pt5/198_hires.png" },  { id: "mew-200", name: "Blastoise ex", imageUrl: "https://images.pokemontcg.io/sv3pt5/200_hires.png", owned: false }]; export function MasterSetSummaryDemo() {  return (    <SetSummary      name="Scarlet & Violet 151"      game="Pokemon"      series="Scarlet & Violet"      releaseDate="Sep 22, 2023"      mode="master"      owned={178}      total={207}      masterOwned={228}      masterTotal={360}      chaseCards={chaseCards}    />  );}

Importing State

Pass `importingCards` when an import or sync is in flight; the component swaps the stats grid for an importing rail.

Scarlet & Violet 151

import { SetSummary } from "@cardspark/ui/collecting"; const importingCards = [  { id: "mew-001", name: "Bulbasaur", imageUrl: "https://images.pokemontcg.io/sv3pt5/1_hires.png" },  { id: "mew-002", name: "Ivysaur", imageUrl: "https://images.pokemontcg.io/sv3pt5/2_hires.png" },  { id: "mew-003", name: "Venusaur ex", imageUrl: "https://images.pokemontcg.io/sv3pt5/3_hires.png" }]; export function ImportingSetSummaryDemo() {  return (    <SetSummary      name="Scarlet & Violet 151"      owned={0}      total={165}      importingCards={importingCards}      importingCardsLoadedCount={2}    />  );}

Loading, Empty, and Error

Use `status` for non-ready states while preserving the same shell and spacing.

Loading Set

--

Loading set summary

Empty Set

--

No set summary yet

Unavailable Set

--

Set summary unavailable

import { SetSummary } from "@cardspark/ui/collecting"; export function SetSummaryStatusDemo() {  return (    <>      <SetSummary name="Loading Set" status="loading" owned={0} total={165} />      <SetSummary name="Empty Set" status="empty" owned={0} total={0} />      <SetSummary name="Unavailable Set" status="error" owned={0} total={165} />    </>  );}

Complete With Collected Rail

When a set is complete, pass collected cards to show the highest-value owned cards in a one-line rail with an adaptive `+N` count.

Scarlet & Violet 151

100%
+187
import { SetSummary } from "@cardspark/ui/collecting"; const collectedCards = [  { id: "mew-199", name: "Charizard ex", value: "$118.90", imageUrl: "https://images.pokemontcg.io/sv3pt5/199_hires.png" },  { id: "mew-200", name: "Blastoise ex", value: "$57.80", imageUrl: "https://images.pokemontcg.io/sv3pt5/200_hires.png" },  { id: "mew-198", name: "Venusaur ex", value: "$48.20", imageUrl: "https://images.pokemontcg.io/sv3pt5/198_hires.png" },  { id: "mew-201", name: "Alakazam ex", value: "$37.40", imageUrl: "https://images.pokemontcg.io/sv3pt5/201_hires.png" },  { id: "mew-202", name: "Zapdos ex", value: "$34.10", imageUrl: "https://images.pokemontcg.io/sv3pt5/202_hires.png" },  { id: "mew-203", name: "Erika's Invitation", value: "$28.60", imageUrl: "https://images.pokemontcg.io/sv3pt5/203_hires.png" },  { id: "mew-204", name: "Giovanni's Charisma", value: "$18.90", imageUrl: "https://images.pokemontcg.io/sv3pt5/204_hires.png" },  { id: "mew-205", name: "Mew ex", value: "$16.50", imageUrl: "https://images.pokemontcg.io/sv3pt5/205_hires.png" },  { id: "mew-173", name: "Pikachu", value: "$12.30", imageUrl: "https://images.pokemontcg.io/sv3pt5/173_hires.png" },  { id: "mew-167", name: "Ivysaur", value: "$10.90", imageUrl: "https://images.pokemontcg.io/sv3pt5/167_hires.png" },  { id: "mew-169", name: "Charmeleon", value: "$10.40", imageUrl: "https://images.pokemontcg.io/sv3pt5/169_hires.png" },  { id: "mew-171", name: "Wartortle", value: "$9.80", imageUrl: "https://images.pokemontcg.io/sv3pt5/171_hires.png" }]; export function CompleteSetSummaryDemo() {  return (    <SetSummary      name="Scarlet & Violet 151"      game="Pokemon"      series="Scarlet & Violet"      releaseDate="Sep 22, 2023"      owned={207}      total={207}      collectedCards={collectedCards}    />  );}

API Reference

PropTypeDefaultDescription
namestring-Primary display name.
codestring-Compact set, finish, or metadata code.
gamestring-Game label shown in set metadata.
seriesstring-Series label used to format set metadata.
releaseDatestring-Formatted set release date.
mode"standard" | "master""standard"Progress count used to calculate and present completion.
status"ready" | "loading" | "error" | "empty""ready"Progress presentation state.
ownednumber-Owned count used for progress calculation.
totalnumber-Total count used for progress calculation.
masterOwnednumber-Owned master-set count used in master mode.
masterTotalnumber-Total master-set count used in master mode.
missingCardsSetSummaryPreviewCard[][]Stable-id preview cards used for missing-card progress states.
chaseCardsSetSummaryChaseCard[][]Stable-id preview cards shown in the chase-card metric rail.
collectedCardsSetSummaryPreviewCard[][]Stable-id collected cards shown in the complete-state rail, sorted by value or price.
importingCardsSetSummaryPreviewCard[][]Stable-id preview cards shown while an import is in progress.
importingCardsLoadedCountnumber0Number of importing preview cards already loaded.
breakdownSetSummaryBreakdownItem[][]Progress breakdown rows such as rarity, finish, or set subset counts.
onClickMouseEventHandler<HTMLElement>-Optional native click handler that also enables keyboard activation where supported.