131 lines
4.3 KiB
TypeScript
131 lines
4.3 KiB
TypeScript
"use client";
|
||
|
||
import { Button } from "@/components/ui/button";
|
||
import {
|
||
LayoutGridIcon,
|
||
ListIcon,
|
||
RotateCwIcon,
|
||
ScissorsIcon,
|
||
ShuffleIcon,
|
||
SlidersHorizontalIcon,
|
||
TrashIcon,
|
||
} from "lucide-react";
|
||
import {
|
||
findLockerEmptySpot,
|
||
getAssetTypeLabel,
|
||
getLockerGridOccupancy,
|
||
getLockerItemFootprint,
|
||
type LockerGridItem,
|
||
lockerIsRotatable,
|
||
lockerIsStackable,
|
||
} from "@/lib/locker";
|
||
|
||
interface LockerGridToolbarProps {
|
||
gridWidth: number;
|
||
gridHeight: number;
|
||
items: LockerGridItem[];
|
||
selectedItem: LockerGridItem | null;
|
||
viewMode: "grid" | "list";
|
||
onViewModeChange: (mode: "grid" | "list") => void;
|
||
onAutoArrange: () => Promise<void>;
|
||
onRotate: (entryId: string) => Promise<void>;
|
||
onRemove: (entryId: string) => Promise<void>;
|
||
onSplit: (entryId: string, amount: number) => Promise<void>;
|
||
onCustomize: () => void;
|
||
}
|
||
|
||
export function LockerGridToolbar({
|
||
gridWidth,
|
||
gridHeight,
|
||
items,
|
||
selectedItem,
|
||
viewMode,
|
||
onViewModeChange,
|
||
onAutoArrange,
|
||
onRotate,
|
||
onRemove,
|
||
onSplit,
|
||
onCustomize,
|
||
}: LockerGridToolbarProps) {
|
||
const occupancy = getLockerGridOccupancy(items, gridWidth, gridHeight);
|
||
const asset = selectedItem?.asset ?? null;
|
||
const fp = selectedItem && asset ? getLockerItemFootprint(asset, selectedItem.rotated) : null;
|
||
const displayName = selectedItem?.equipment?.customName?.trim() || asset?.name || null;
|
||
const hasCustomName =
|
||
selectedItem?.equipment?.customName?.trim() != null &&
|
||
selectedItem.equipment.customName.trim() !== "";
|
||
const canSplit =
|
||
selectedItem && asset && fp
|
||
? findLockerEmptySpot(items, fp.width, fp.height, gridWidth, gridHeight) !== null
|
||
: false;
|
||
|
||
return (
|
||
<div className="flex flex-col gap-3">
|
||
<div className="flex items-center justify-between">
|
||
<div className="flex items-center gap-2">
|
||
<Button variant="outline" size="sm" onClick={onAutoArrange}>
|
||
<ShuffleIcon className="size-3.5 mr-1" />
|
||
Auto-Arrange
|
||
</Button>
|
||
</div>
|
||
|
||
<div className="flex items-center gap-1">
|
||
<Button
|
||
variant={viewMode === "grid" ? "default" : "outline"}
|
||
size="sm"
|
||
onClick={() => onViewModeChange("grid")}
|
||
>
|
||
<LayoutGridIcon className="size-3.5" />
|
||
</Button>
|
||
<Button
|
||
variant={viewMode === "list" ? "default" : "outline"}
|
||
size="sm"
|
||
onClick={() => onViewModeChange("list")}
|
||
>
|
||
<ListIcon className="size-3.5" />
|
||
</Button>
|
||
</div>
|
||
</div>
|
||
|
||
{selectedItem && asset && (
|
||
<div className="flex items-center gap-3 p-2 rounded-md border bg-muted/30 text-xs">
|
||
<div className="flex-1 min-w-0">
|
||
<div className="font-medium truncate">{displayName}</div>
|
||
<div className="text-muted-foreground">
|
||
{selectedItem.quantity.toLocaleString()}× · {getAssetTypeLabel(asset.assetType)}
|
||
{hasCustomName && asset && displayName !== asset.name && ` · as "${asset.name}"`}
|
||
{fp && ` · ${fp.width}x${fp.height}`}
|
||
{selectedItem.rotated && " · rotated"}
|
||
</div>
|
||
</div>
|
||
<div className="flex items-center gap-1">
|
||
{asset?.assetType === "weapon" && (
|
||
<Button variant="outline" size="sm" onClick={onCustomize}>
|
||
<SlidersHorizontalIcon className="size-3.5" />
|
||
Customize
|
||
</Button>
|
||
)}
|
||
{lockerIsRotatable(asset) && (
|
||
<Button variant="outline" size="sm" onClick={() => onRotate(selectedItem.id)}>
|
||
<RotateCwIcon className="size-3.5" />
|
||
</Button>
|
||
)}
|
||
{lockerIsStackable(asset) && selectedItem.quantity > 1 && (
|
||
<Button
|
||
variant="outline"
|
||
size="sm"
|
||
disabled={!canSplit}
|
||
onClick={() => onSplit(selectedItem.id, Math.floor(selectedItem.quantity / 2))}
|
||
>
|
||
<ScissorsIcon className="size-3.5" />
|
||
</Button>
|
||
)}
|
||
<Button variant="outline" size="sm" onClick={() => onRemove(selectedItem.id)}>
|
||
<TrashIcon className="size-3.5" />
|
||
</Button>
|
||
</div>
|
||
</div>
|
||
)}
|
||
</div>
|
||
);
|
||
}
|