modmapper-web/components/CellList.tsx
Tyler Hallada 2bd5227287 Notification message for add/remove mod
Also changed how scrolling resets on pagination.

And tweaked pagination styling.
2022-08-28 23:43:44 -04:00

126 lines
3.4 KiB
TypeScript

import React, { useEffect, useRef, useState } from "react";
import Link from "next/link";
import MiniSearch from "minisearch";
import ReactPaginate from "react-paginate";
import styles from "../styles/CellList.module.css";
import type { CellCoord } from "./ModData";
const PAGE_SIZE = 100;
type Props = {
cells: CellCoord[];
};
const CellList: React.FC<Props> = ({ cells }) => {
const cellSearch = useRef<MiniSearch<CellCoord> | null>(
null
) as React.MutableRefObject<MiniSearch<CellCoord>>;
useEffect(() => {
cellSearch.current = new MiniSearch({
fields: ["id"],
storeFields: ["id", "x", "y"],
tokenize: (s) => [s.replace(/cell\s?|\s/gi, "")],
searchOptions: {
fields: ["id"],
prefix: true,
fuzzy: false,
},
});
cellSearch.current.addAll(
cells.map((cell) => ({ ...cell, id: `${cell.x},${cell.y}` }))
);
}, [cells]);
const [filter, setFilter] = useState<string>("");
const [filterResults, setFilterResults] = useState<Set<string>>(new Set());
const [page, setPage] = useState<number>(0);
const filteredCells = cells
.filter((cell) => !filter || filterResults.has(`${cell.x},${cell.y}`))
.sort((a, b) => (a.x - b.x) * 1000 + a.y - b.y);
useEffect(() => {
if (cellSearch.current) {
setFilterResults(
new Set(cellSearch.current.search(filter).map((result) => result.id))
);
}
}, [filter]);
useEffect(() => {
setPage(0);
}, [filterResults]);
const renderPagination = () => (
<ReactPaginate
breakLabel="..."
nextLabel=">"
forcePage={page}
onPageChange={(event) => {
setPage(event.selected);
document.getElementById("exterior-cells")?.scrollIntoView();
}}
pageRangeDisplayed={3}
marginPagesDisplayed={2}
pageCount={Math.ceil(filteredCells.length / PAGE_SIZE)}
previousLabel="<"
renderOnZeroPageCount={() => null}
className={styles.pagination}
activeClassName={styles["active-page"]}
hrefBuilder={() => "#"}
/>
);
return (
filteredCells && (
<>
<h2 id="exterior-cells">Exterior Cells ({filteredCells.length})</h2>
<div className={styles.filters}>
<hr />
<div className={styles["filter-row"]}>
<label htmlFor="filter">Filter:</label>
<input
type="search"
id="filter"
className={styles.filter}
value={filter}
onChange={(event) => setFilter(event.target.value)}
/>
</div>
<hr />
</div>
{renderPagination()}
<ul className={styles["cell-list"]}>
{filteredCells
.slice(page * PAGE_SIZE, page * PAGE_SIZE + PAGE_SIZE)
.map((cell) => (
<li
key={`cell-${cell.x},${cell.y}`}
className={styles["cell-list-item"]}
>
<div className={styles["cell-title"]}>
<strong>
<Link
href={`/?cell=${encodeURIComponent(
`${cell.x},${cell.y}`
)}`}
>
<a>
{cell.x}, {cell.y}
</a>
</Link>
</strong>
</div>
</li>
))}
</ul>
{renderPagination()}
</>
)
);
};
export default CellList;