List views: choose which columns to show
A Columns menu next to the List/Tiles toggle hides or shows optional columns in the Library, Card Search, deck builder and Decks list row views. Choices are saved per view on each device. The selection checkbox and name always show. Closes #8 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -19,6 +19,8 @@ import {
|
||||
CardTile,
|
||||
ColorDistributionBar,
|
||||
ColorPips,
|
||||
ColumnDef,
|
||||
ColumnsMenu,
|
||||
ConfirmDialog,
|
||||
DialogFrame,
|
||||
GroupBySelect,
|
||||
@@ -36,6 +38,7 @@ import {
|
||||
groupCards,
|
||||
useClickPreview,
|
||||
useHoverPreview,
|
||||
useColumns,
|
||||
usePersistedState,
|
||||
useTileColumns,
|
||||
useViewMode,
|
||||
@@ -70,6 +73,19 @@ function boardToggleProps(e: DeckEntry) {
|
||||
: { icon: Icons.helpCircle, label: "Move to maybeboard" };
|
||||
}
|
||||
|
||||
type DeckColumn = "image" | "colors" | "type" | "qty" | "owned" | "where" | "actions";
|
||||
|
||||
// The List view's optional columns; the checkbox and name always show.
|
||||
const DECK_COLUMNS: ColumnDef<DeckColumn>[] = [
|
||||
{ id: "image", label: "Image" },
|
||||
{ id: "colors", label: "Colors" },
|
||||
{ id: "type", label: "Type" },
|
||||
{ id: "qty", label: "In deck" },
|
||||
{ id: "owned", label: "Owned" },
|
||||
{ id: "where", label: "Where" },
|
||||
{ id: "actions", label: "Actions" },
|
||||
];
|
||||
|
||||
type DeckDialog =
|
||||
| { kind: "create" }
|
||||
| { kind: "delete"; deck: Deck }
|
||||
@@ -227,6 +243,7 @@ function DeckBuilder({
|
||||
const [contents, setContents] = useState<DeckEntry[]>([]);
|
||||
const [view, setView] = useViewMode("deck-view");
|
||||
const tiles = useTileColumns();
|
||||
const columns = useColumns("deck-columns", DECK_COLUMNS);
|
||||
const [groupBy, setGroupBy] = usePersistedState<GroupMode>("deck-group", "none");
|
||||
const [combineSections, setCombineSections] = usePersistedState("deck-combine-sections", false);
|
||||
const [filterQuery, setFilterQuery] = useState("");
|
||||
@@ -811,14 +828,14 @@ function DeckBuilder({
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th>Colors</th>
|
||||
{columns.shown("image") && <th></th>}
|
||||
{columns.shown("colors") && <th>Colors</th>}
|
||||
<th>Name</th>
|
||||
<th>Type</th>
|
||||
<th>In deck</th>
|
||||
<th>Owned</th>
|
||||
<th>Where</th>
|
||||
<th></th>
|
||||
{columns.shown("type") && <th>Type</th>}
|
||||
{columns.shown("qty") && <th>In deck</th>}
|
||||
{columns.shown("owned") && <th>Owned</th>}
|
||||
{columns.shown("where") && <th>Where</th>}
|
||||
{columns.shown("actions") && <th></th>}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@@ -831,12 +848,16 @@ function DeckBuilder({
|
||||
onChange={() => toggleCard(e.oracle_id)}
|
||||
/>
|
||||
</td>
|
||||
<td className="cell-thumb">
|
||||
<CardThumb card={e} preview={preview} />
|
||||
</td>
|
||||
<td>
|
||||
<ColorPips mask={e.color_identity} />
|
||||
</td>
|
||||
{columns.shown("image") && (
|
||||
<td className="cell-thumb">
|
||||
<CardThumb card={e} preview={preview} />
|
||||
</td>
|
||||
)}
|
||||
{columns.shown("colors") && (
|
||||
<td>
|
||||
<ColorPips mask={e.color_identity} />
|
||||
</td>
|
||||
)}
|
||||
<td className="card-name">
|
||||
{e.is_commander && <span title="Commander">★ </span>}
|
||||
{e.name}
|
||||
@@ -846,26 +867,30 @@ function DeckBuilder({
|
||||
</span>
|
||||
)}
|
||||
</td>
|
||||
<td className="card-type">{e.type_line}</td>
|
||||
<td data-label="In deck">
|
||||
<QtyStepper
|
||||
value={e.quantity}
|
||||
onDecrement={() => setQty(e.oracle_id, e.quantity - 1)}
|
||||
onIncrement={() => setQty(e.oracle_id, e.quantity + 1)}
|
||||
warn={e.quantity_owned > 0 && e.quantity > e.quantity_owned}
|
||||
pending={pendingRemoval.has(e.oracle_id)}
|
||||
/>
|
||||
</td>
|
||||
<td data-label="Owned">{e.quantity_owned}</td>
|
||||
<td data-label="Where">{whereabouts(e)}</td>
|
||||
<td>
|
||||
<span className="row" style={{ gap: 4 }}>
|
||||
<IconButton {...boardToggleProps(e)} onClick={() => setMaybeboard(e, !e.is_maybeboard)} />
|
||||
{e.quantity_owned === 0 && (
|
||||
<IconButton icon={Icons.libraryAdd} label={libraryAddLabel(e)} onClick={() => addToLibrary([e])} />
|
||||
)}
|
||||
</span>
|
||||
</td>
|
||||
{columns.shown("type") && <td className="card-type">{e.type_line}</td>}
|
||||
{columns.shown("qty") && (
|
||||
<td data-label="In deck">
|
||||
<QtyStepper
|
||||
value={e.quantity}
|
||||
onDecrement={() => setQty(e.oracle_id, e.quantity - 1)}
|
||||
onIncrement={() => setQty(e.oracle_id, e.quantity + 1)}
|
||||
warn={e.quantity_owned > 0 && e.quantity > e.quantity_owned}
|
||||
pending={pendingRemoval.has(e.oracle_id)}
|
||||
/>
|
||||
</td>
|
||||
)}
|
||||
{columns.shown("owned") && <td data-label="Owned">{e.quantity_owned}</td>}
|
||||
{columns.shown("where") && <td data-label="Where">{whereabouts(e)}</td>}
|
||||
{columns.shown("actions") && (
|
||||
<td>
|
||||
<span className="row" style={{ gap: 4 }}>
|
||||
<IconButton {...boardToggleProps(e)} onClick={() => setMaybeboard(e, !e.is_maybeboard)} />
|
||||
{e.quantity_owned === 0 && (
|
||||
<IconButton icon={Icons.libraryAdd} label={libraryAddLabel(e)} onClick={() => addToLibrary([e])} />
|
||||
)}
|
||||
</span>
|
||||
</td>
|
||||
)}
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
@@ -1124,6 +1149,7 @@ function DeckBuilder({
|
||||
<span className="spacer" />
|
||||
<GroupBySelect value={groupBy} onChange={setGroupBy} />
|
||||
<ViewToggle mode={view} onChange={setView} />
|
||||
{view === "list" && <ColumnsMenu columns={columns} />}
|
||||
{view === "tiles" && <TileColumnsControl tiles={tiles} />}
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user