Deck builder: sorting and a Price column
Adds the Library's Sort by control (plus a Quantity in deck option) to the deck builder, applied within each section and group. The card table gets an optional Price column showing the per-copy price, with the total for the deck's copies in its tooltip. The toolbar now wraps on narrow screens. Refs #6 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -22,6 +22,7 @@ import {
|
||||
ColumnDef,
|
||||
ColumnsMenu,
|
||||
ConfirmDialog,
|
||||
DECK_SORT_OPTIONS,
|
||||
DialogFrame,
|
||||
GroupBySelect,
|
||||
GroupMode,
|
||||
@@ -32,10 +33,14 @@ import {
|
||||
PromptDialog,
|
||||
QtyStepper,
|
||||
SampleHandModal,
|
||||
SortBySelect,
|
||||
SortDir,
|
||||
SortMode,
|
||||
StatTile,
|
||||
TileColumnsControl,
|
||||
ViewToggle,
|
||||
groupCards,
|
||||
sortCards,
|
||||
useClickPreview,
|
||||
useHoverPreview,
|
||||
useColumns,
|
||||
@@ -73,7 +78,7 @@ function boardToggleProps(e: DeckEntry) {
|
||||
: { icon: Icons.helpCircle, label: "Move to maybeboard" };
|
||||
}
|
||||
|
||||
type DeckColumn = "image" | "colors" | "type" | "qty" | "owned" | "where" | "actions";
|
||||
type DeckColumn = "image" | "colors" | "type" | "qty" | "owned" | "price" | "where" | "actions";
|
||||
|
||||
// The List view's optional columns; the checkbox and name always show.
|
||||
const DECK_COLUMNS: ColumnDef<DeckColumn>[] = [
|
||||
@@ -82,6 +87,7 @@ const DECK_COLUMNS: ColumnDef<DeckColumn>[] = [
|
||||
{ id: "type", label: "Type" },
|
||||
{ id: "qty", label: "In deck" },
|
||||
{ id: "owned", label: "Owned" },
|
||||
{ id: "price", label: "Price" },
|
||||
{ id: "where", label: "Where" },
|
||||
{ id: "actions", label: "Actions" },
|
||||
];
|
||||
@@ -342,6 +348,8 @@ function DeckBuilder({
|
||||
const tiles = useTileColumns();
|
||||
const columns = useColumns("deck-columns", DECK_COLUMNS);
|
||||
const [groupBy, setGroupBy] = usePersistedState<GroupMode>("deck-group", "none");
|
||||
const [sortBy, setSortBy] = usePersistedState<SortMode>("deck-sort", "name");
|
||||
const [sortDir, setSortDir] = usePersistedState<SortDir>("deck-sort-dir", "asc");
|
||||
const [combineSections, setCombineSections] = usePersistedState("deck-combine-sections", false);
|
||||
const [filterQuery, setFilterQuery] = useState("");
|
||||
|
||||
@@ -994,6 +1002,7 @@ function DeckBuilder({
|
||||
{columns.shown("type") && <th>Type</th>}
|
||||
{columns.shown("qty") && <th>In deck</th>}
|
||||
{columns.shown("owned") && <th>Owned</th>}
|
||||
{columns.shown("price") && <th>Price</th>}
|
||||
{columns.shown("where") && <th>Where</th>}
|
||||
{columns.shown("actions") && <th></th>}
|
||||
</tr>
|
||||
@@ -1040,6 +1049,19 @@ function DeckBuilder({
|
||||
</td>
|
||||
)}
|
||||
{columns.shown("owned") && <td data-label="Owned">{e.quantity_owned}</td>}
|
||||
{columns.shown("price") && (
|
||||
<td
|
||||
data-label="Price"
|
||||
className="cell-price"
|
||||
title={
|
||||
e.price_usd > 0 && e.quantity > 1
|
||||
? `${formatCost(e.price_usd * e.quantity)} for ${e.quantity} copies`
|
||||
: undefined
|
||||
}
|
||||
>
|
||||
{e.price_usd > 0 ? `$${e.price_usd.toFixed(2)}` : "—"}
|
||||
</td>
|
||||
)}
|
||||
{columns.shown("where") && <td data-label="Where">{whereabouts(e)}</td>}
|
||||
{columns.shown("actions") && (
|
||||
<td>
|
||||
@@ -1060,7 +1082,7 @@ function DeckBuilder({
|
||||
|
||||
function cardsGroup(entries: DeckEntry[]) {
|
||||
if (entries.length === 0) return <p className="hint">None yet.</p>;
|
||||
return groupCards(entries, groupBy).map((g) => (
|
||||
return groupCards(sortCards(entries, sortBy, sortDir), groupBy).map((g) => (
|
||||
<div key={g.label || "all"} style={{ marginBottom: g.label ? 14 : 0 }}>
|
||||
{g.label && (
|
||||
<h4 className="group-header">
|
||||
@@ -1277,7 +1299,7 @@ function DeckBuilder({
|
||||
|
||||
<hr className="deck-section-divider" />
|
||||
|
||||
<div className="row" style={{ gap: 16 }}>
|
||||
<div className="row" style={{ gap: 16, flexWrap: "wrap" }}>
|
||||
<label className="row" style={{ gap: 6, cursor: "pointer" }} title="Select all cards">
|
||||
<input
|
||||
ref={selectAllRef}
|
||||
@@ -1302,6 +1324,13 @@ function DeckBuilder({
|
||||
</label>
|
||||
<span className="spacer" />
|
||||
<GroupBySelect value={groupBy} onChange={setGroupBy} />
|
||||
<SortBySelect
|
||||
value={sortBy}
|
||||
dir={sortDir}
|
||||
onChangeValue={setSortBy}
|
||||
onToggleDir={() => setSortDir(sortDir === "asc" ? "desc" : "asc")}
|
||||
options={DECK_SORT_OPTIONS}
|
||||
/>
|
||||
<ViewToggle mode={view} onChange={setView} />
|
||||
{view === "list" && <ColumnsMenu columns={columns} />}
|
||||
{view === "tiles" && <TileColumnsControl tiles={tiles} />}
|
||||
|
||||
Reference in New Issue
Block a user