import { useMemo, useState } from "react"; import { Card, Input, Space, Table, Tag, Typography } from "antd"; import { useExportPrototypeMetadata } from "../model/export_prototype_metadata"; import PageHeader from "./PageHeader"; import PageLayout from "./PageLayout"; import FactorioIcon from "./FactorioIcon"; import { useParams } from "react-router-dom"; import { useModPack } from "../model/mod_pack"; import { PrototypeMetadataEntry } from "../store/export_prototype_metadata_store"; const { Text } = Typography; function filterPrototypes( prototypes: Map> | undefined, filter: string ) { const query = filter.trim().toLowerCase(); return new Map( [...prototypes ?? []].map(([baseType, entries]) => [ baseType, new Map([...entries.entries()].filter(([name, entry]) => ( `${entry.base_type}.${name}`.includes(query) || `${entry.type}.${name}`.includes(query) ))), ]), ); } function countPrototypes( prototypes: Map> | undefined, ) { return prototypes ? [...prototypes.values()].reduce((a, e) => a + e.size, 0) : 0; } export default function IconReferencePage() { let params = useParams(); let modPackId = Number(params.id); const [filter, setFilter] = useState(""); const [expandedGroups, setExpandedGroups] = useState>(new Set()); const [modPack] = useModPack(modPackId); const manifest = modPack?.exportManifest; const prototypes = useExportPrototypeMetadata(modPack); const filtered = useMemo(() => filterPrototypes(prototypes, filter), [prototypes, filter]); const groups = useMemo(() => ( [...filtered] .map(([baseType, entries]) => ({ baseType, entries: [...entries.values()] })) .filter(group => group.entries.length) ), [filtered]); const visibleCount = countPrototypes(filtered); const totalCount = countPrototypes(prototypes); const autoExpand = visibleCount <= 20; const isExpanded = (category: string) => autoExpand || expandedGroups.has(category); const toggleGroup = (category: string) => { setExpandedGroups(prev => { const next = new Set(prev); if (next.has(category)) { next.delete(category); } else { next.add(category); } return next; }); }; const columns = [ { title: "Icon", key: "icon", width: 48, render: (prototype: PrototypeMetadataEntry) => ( ), }, { title: "Name", dataIndex: "name", key: "name", render: (name: string) => ( {name} ), }, { title: "Path", dataIndex: ["icon", "path"], key: "path", render: (p: string | undefined) => (p ? {p} : null), }, ]; let nav = [ { name: "Mods", path: "/mods" }, { name: "Mod Packs" }, { name: modPack?.name ?? String(modPackId), path: `/mods/mod-packs/${modPackId}/view` }, { name: "Icon Reference" }, ]; return (
{!modPack?.exportManifest && ( No export data available. Run export-data on an instance to generate icons. )} {manifest && manifest.exportedAt && (
{manifest.exportedAt && (
Exported: {new Date(manifest.exportedAt).toLocaleString()}
)}
Prototypes: {totalCount}
)} setFilter(e.target.value)} allowClear style={{ width: 320 }} /> {visibleCount === totalCount ? `${totalCount} icons` : `${visibleCount} / ${totalCount} icons`} {groups.map(({ baseType, entries }) => { const expanded = isExpanded(baseType); return (
toggleGroup(baseType)} style={{ display: "flex", alignItems: "center", gap: 8, padding: "6px 12px", background: "#1d1d1d", border: "1px solid #333", borderRadius: expanded ? "4px 4px 0 0" : 4, cursor: "pointer", userSelect: "none", }} > {expanded ? "▾" : "►"} {baseType} {entries.length}
{expanded && ( columns={columns} dataSource={entries} rowKey="key" size="small" showHeader={false} pagination={false} style={{ borderTop: "none" }} /> )}
); })}
); }