fix: expand long zone map item lists

This commit is contained in:
Nico 2026-06-04 11:29:52 -07:00
parent 4c42808396
commit 628a4f48c2
3 changed files with 60 additions and 45 deletions

View File

@ -12,7 +12,7 @@ export const MAP_DISPLAY_CONTROLS = [
["showUnmapped", "Unmapped"], ["showUnmapped", "Unmapped"],
]; ];
const UNMAPPED_PREVIEW_LIMIT = 8; const MAP_ITEM_PREVIEW_LIMIT = 8;
function MapItemActionRow({ item, onSelectItem }) { function MapItemActionRow({ item, onSelectItem }) {
const isBought = Boolean(item.bought); const isBought = Boolean(item.bought);
@ -35,6 +35,44 @@ function MapItemActionRow({ item, onSelectItem }) {
); );
} }
function MapItemActionList({ items, onSelectItem, itemGroupLabel }) {
const [showAllItems, setShowAllItems] = useState(false);
useEffect(() => {
if (items.length <= MAP_ITEM_PREVIEW_LIMIT) {
setShowAllItems(false);
}
}, [items.length]);
const visibleItems = showAllItems ? items : items.slice(0, MAP_ITEM_PREVIEW_LIMIT);
const overflowItemCount = items.length - visibleItems.length;
const hasOverflow = items.length > MAP_ITEM_PREVIEW_LIMIT;
return (
<ul>
{visibleItems.map((item) => (
<MapItemActionRow key={item.id} item={item} onSelectItem={onSelectItem} />
))}
{hasOverflow ? (
<li className="location-map-list-more">
<button
type="button"
className="location-map-list-more-button"
onClick={() => setShowAllItems((current) => !current)}
aria-label={
showAllItems
? `Show fewer ${itemGroupLabel}`
: `Show ${overflowItemCount} more ${itemGroupLabel}`
}
>
{showAllItems ? "Show fewer" : `+${overflowItemCount} more`}
</button>
</li>
) : null}
</ul>
);
}
export function LocationMapLayerPanel({ filters, setFilters }) { export function LocationMapLayerPanel({ filters, setFilters }) {
return ( return (
<div className="location-map-display-panel"> <div className="location-map-display-panel">
@ -159,11 +197,11 @@ export function SelectedZoneItemsPanel({
return ( return (
<div className="location-map-zone-items"> <div className="location-map-zone-items">
<ul> <MapItemActionList
{selectedZoneItems.map((item) => ( items={selectedZoneItems}
<MapItemActionRow key={item.id} item={item} onSelectItem={onSelectZoneItem} /> onSelectItem={onSelectZoneItem}
))} itemGroupLabel="zone items"
</ul> />
{hasHiddenSelectedItems ? ( {hasHiddenSelectedItems ? (
<div className="location-map-zone-hidden-note"> <div className="location-map-zone-hidden-note">
<p className="location-map-muted"> <p className="location-map-muted">
@ -185,14 +223,6 @@ export function UnmappedItemsPanel({
onShowUnmappedItems, onShowUnmappedItems,
onSelectUnmappedItem, onSelectUnmappedItem,
}) { }) {
const [showAllUnmappedItems, setShowAllUnmappedItems] = useState(false);
useEffect(() => {
if (visibleUnmappedItems.length <= UNMAPPED_PREVIEW_LIMIT) {
setShowAllUnmappedItems(false);
}
}, [visibleUnmappedItems.length]);
if (visibleUnmappedItems.length === 0 && hasHiddenUnmappedItems) { if (visibleUnmappedItems.length === 0 && hasHiddenUnmappedItems) {
return ( return (
<div className="location-map-unmapped-list"> <div className="location-map-unmapped-list">
@ -213,36 +243,14 @@ export function UnmappedItemsPanel({
return null; return null;
} }
const unmappedItemPreview = showAllUnmappedItems
? visibleUnmappedItems
: visibleUnmappedItems.slice(0, UNMAPPED_PREVIEW_LIMIT);
const overflowUnmappedItemCount = visibleUnmappedItems.length - unmappedItemPreview.length;
const hasUnmappedOverflow = visibleUnmappedItems.length > UNMAPPED_PREVIEW_LIMIT;
return ( return (
<div className="location-map-unmapped-list"> <div className="location-map-unmapped-list">
<strong>Unmapped Items</strong> <strong>Unmapped Items</strong>
<ul> <MapItemActionList
{unmappedItemPreview.map((item) => ( items={visibleUnmappedItems}
<MapItemActionRow key={item.id} item={item} onSelectItem={onSelectUnmappedItem} /> onSelectItem={onSelectUnmappedItem}
))} itemGroupLabel="unmapped items"
{hasUnmappedOverflow ? ( />
<li className="location-map-unmapped-more">
<button
type="button"
className="location-map-list-more-button"
onClick={() => setShowAllUnmappedItems((current) => !current)}
aria-label={
showAllUnmappedItems
? "Show fewer unmapped items"
: `Show ${overflowUnmappedItemCount} more unmapped items`
}
>
{showAllUnmappedItems ? "Show fewer" : `+${overflowUnmappedItemCount} more`}
</button>
</li>
) : null}
</ul>
{hiddenUnmappedItemCount > 0 ? ( {hiddenUnmappedItemCount > 0 ? (
<div className="location-map-zone-hidden-note"> <div className="location-map-zone-hidden-note">
<p className="location-map-muted"> <p className="location-map-muted">

View File

@ -827,7 +827,7 @@
margin-bottom: 0.45rem; margin-bottom: 0.45rem;
} }
.location-map-unmapped-list .location-map-unmapped-more { .location-map-list-more {
padding: 0; padding: 0;
overflow: hidden; overflow: hidden;
border-style: dashed; border-style: dashed;

View File

@ -2696,9 +2696,16 @@ test("viewer handles empty and many-item zone panels without default pins", asyn
await page.locator('[data-object-key="1561"]').locator("rect").first().click(); await page.locator('[data-object-key="1561"]').locator("rect").first().click();
await expect(page.locator(".location-map-sheet-count")).toHaveText("14 items"); await expect(page.locator(".location-map-sheet-count")).toHaveText("14 items");
await expect(page.locator(".location-map-zone-items li")).toHaveCount(14); await expect(page.locator(".location-map-zone-items .location-map-item-row")).toHaveCount(8);
await expect(page.locator(".location-map-zone-items li").first()).toContainText("bulk item 1"); await expect(page.locator(".location-map-zone-items .location-map-item-row").first()).toContainText("bulk item 1");
await expect(page.locator(".location-map-zone-items li").last()).toContainText("bulk item 14"); await expect(page.getByText("bulk item 9")).toHaveCount(0);
await expect(page.getByRole("button", { name: "Show 6 more zone items" })).toHaveText("+6 more");
await page.getByRole("button", { name: "Show 6 more zone items" }).click();
await expect(page.locator(".location-map-zone-items .location-map-item-row")).toHaveCount(14);
await expect(page.locator(".location-map-zone-items .location-map-item-row").last()).toContainText("bulk item 14");
await expect(page.getByRole("button", { name: "Show fewer zone items" })).toHaveText("Show fewer");
await expect(page.locator(".location-map-pin")).toHaveCount(0); await expect(page.locator(".location-map-pin")).toHaveCount(0);
}); });