1
0
Fork 0
polaris-task-force/src/components/frontend/storage/ResourceList.tsx

124 lines
4.4 KiB
TypeScript

import { GameStructure, Resource } from "@/payload-types";
import { convertLexicalToPlaintext } from "@payloadcms/richtext-lexical/plaintext";
import { pluralize } from "@/lib/utils";
import {
Item,
ItemContent,
ItemDescription,
ItemHeader,
ItemMedia,
ItemSeparator,
ItemTitle,
} from "@/components/ui/item";
import { BrainIcon, DropletIcon, PackageOpenIcon, ZapIcon } from "lucide-react";
interface ResourceListProps {
storedResources: GameStructure["storedResources"];
maxCapacityMass: number | null;
}
function getResourceIcon(type: Resource["type"]) {
switch (type) {
case "fluid":
return <DropletIcon className="size-4" />;
case "energy":
return <ZapIcon className="size-4" />;
case "abstract":
return <BrainIcon className="size-4" />;
default:
return <PackageOpenIcon className="size-4" />;
}
}
export function ResourceList({ storedResources, maxCapacityMass }: ResourceListProps) {
const resources = storedResources ?? [];
if (resources.length === 0) {
return (
<Item variant="outline">
<ItemHeader>
<ItemTitle className="flex items-center gap-2">
<PackageOpenIcon className="size-4 text-muted-foreground" />
Stored Resources
</ItemTitle>
</ItemHeader>
<ItemContent>
<p className="text-sm text-muted-foreground py-2">No resources currently stored.</p>
</ItemContent>
</Item>
);
}
return (
<Item variant="outline">
<ItemHeader>
<ItemTitle className="flex items-center gap-2">
<PackageOpenIcon className="size-4 text-muted-foreground" />
Stored Resources
</ItemTitle>
<ItemDescription>
{resources.length} resource type{resources.length !== 1 ? "s" : ""}
</ItemDescription>
</ItemHeader>
<ItemContent>
<div className="flex flex-col">
{resources.map((entry, index) => {
const resource = entry.resource as Resource;
if (!resource || typeof resource === "number") return null;
const mass = (resource.massPerUnit ?? 0) * entry.amount;
const description = resource.description
? convertLexicalToPlaintext({ data: resource.description })
: null;
return (
<div key={entry.id ?? index}>
<div className="flex items-center gap-3 py-2.5">
<ItemMedia variant="icon">
{resource.icon ? (
<img
src={typeof resource.icon === "object" ? (resource.icon.url ?? "") : ""}
alt={resource.name}
className="size-4 object-contain"
/>
) : (
getResourceIcon(resource.type)
)}
</ItemMedia>
<ItemContent className="flex-1 min-w-0">
<ItemTitle>
<span
className="w-2 h-2 rounded-full shrink-0"
style={{ backgroundColor: resource.color ?? "#888" }}
/>
<span>{resource.name}</span>
<span className="text-xs font-normal text-muted-foreground">
{entry.amount.toLocaleString()}{" "}
{pluralize(entry.amount, resource.unitOfMeasure)}
</span>
</ItemTitle>
{description && (
<ItemDescription className="line-clamp-1">{description}</ItemDescription>
)}
</ItemContent>
<div className="text-right shrink-0">
<div className="text-sm font-medium">
{entry.amount.toLocaleString()}{" "}
{pluralize(entry.amount, resource.unitOfMeasure)}
</div>
<div className="text-xs text-muted-foreground">
{mass > 0 && `${mass.toLocaleString()} kg mass`}
{mass > 0 && " · "}
{(resource.baseValue * entry.amount).toLocaleString()} value
</div>
</div>
</div>
{index < resources.length - 1 && <ItemSeparator />}
</div>
);
})}
</div>
</ItemContent>
</Item>
);
}