Basic plugin data page

This commit is contained in:
Tyler Hallada 2022-02-27 02:25:34 -05:00
parent 761ef80669
commit f6d02c6d33
4 changed files with 193 additions and 8 deletions

View File

@ -143,6 +143,7 @@ const Map: React.FC = () => {
const selectCells = useCallback( const selectCells = useCallback(
(cells: { x: number; y: number }[]) => { (cells: { x: number; y: number }[]) => {
console.log("selectCells");
if (!map.current) return; if (!map.current) return;
if (map.current && !map.current.getSource("grid-source")) return; if (map.current && !map.current.getSource("grid-source")) return;
@ -233,6 +234,7 @@ const Map: React.FC = () => {
); );
const clearSelectedCell = useCallback(() => { const clearSelectedCell = useCallback(() => {
console.log("clearSelectedCell");
setSelectedCell(null); setSelectedCell(null);
if (map.current) map.current.removeFeatureState({ source: "grid-source" }); if (map.current) map.current.removeFeatureState({ source: "grid-source" });
if (map.current) { if (map.current) {
@ -245,6 +247,7 @@ const Map: React.FC = () => {
}, [map]); }, [map]);
const clearSelectedCells = useCallback(() => { const clearSelectedCells = useCallback(() => {
console.log("clearSelectedCells");
setSelectedCells(null); setSelectedCells(null);
if (map.current) { if (map.current) {
map.current.removeFeatureState({ source: "selected-cell-source" }); map.current.removeFeatureState({ source: "selected-cell-source" });
@ -295,24 +298,45 @@ const Map: React.FC = () => {
clearSelectedCell(); clearSelectedCell();
setSidebarOpen(true); setSidebarOpen(true);
selectCells(selectedCells); selectCells(selectedCells);
} else { } else if (router.query.plugin && typeof router.query.plugin === "string") {
if (selectedCell) {
clearSelectedCell();
}
if (selectedCells) {
clearSelectedCells(); clearSelectedCells();
setSidebarOpen(true);
if (plugins && plugins.length > 0 && pluginsPending === 0) {
const plugin = plugins.find((p) => p.hash === router.query.plugin);
if (plugin && plugin.parsed) {
const cells = [];
const cellSet = new Set<number>();
for (const cell of plugin.parsed.cells) {
if (
cell.x !== undefined &&
cell.y !== undefined &&
cell.world_form_id === 60 &&
cellSet.has(cell.x + cell.y * 1000) === false
) {
cells.push({ x: cell.x, y: cell.y });
cellSet.add(cell.x + cell.y * 1000);
} }
} }
selectCells(cells);
}
}
} else {
clearSelectedCell();
clearSelectedCells();
}
}, [ }, [
selectedCell, selectedCell,
selectedCells, selectedCells,
router.query.cell, router.query.cell,
router.query.mod, router.query.mod,
router.query.plugin,
selectCell, selectCell,
selectCells, selectCells,
clearSelectedCell, clearSelectedCell,
clearSelectedCells, clearSelectedCells,
heatmapLoaded, heatmapLoaded,
plugins,
pluginsPending,
]); ]);
useEffect(() => { useEffect(() => {
@ -324,7 +348,14 @@ const Map: React.FC = () => {
useEffect(() => { useEffect(() => {
if (!heatmapLoaded) return; // wait for all map layers to load if (!heatmapLoaded) return; // wait for all map layers to load
if (plugins && plugins.length > 0 && pluginsPending === 0) { if (
plugins &&
plugins.length > 0 &&
pluginsPending === 0 &&
!router.query.cell &&
!router.query.mod &&
!router.query.plugin
) {
clearSelectedCells(); clearSelectedCells();
const cells = plugins.reduce( const cells = plugins.reduce(
(acc: { x: number; y: number }[], plugin: PluginFile) => { (acc: { x: number; y: number }[], plugin: PluginFile) => {
@ -347,7 +378,16 @@ const Map: React.FC = () => {
); );
selectCells(cells); selectCells(cells);
} }
}, [plugins, pluginsPending, heatmapLoaded, clearSelectedCells, selectCells]); }, [
plugins,
pluginsPending,
heatmapLoaded,
clearSelectedCells,
selectCells,
router.query.cell,
router.query.mod,
router.query.plugin,
]);
useEffect(() => { useEffect(() => {
if (map.current) return; // initialize map only once if (map.current) return; // initialize map only once

115
components/PluginData.tsx Normal file
View File

@ -0,0 +1,115 @@
import Head from "next/head";
import React from "react";
import { useAppSelector } from "../lib/hooks";
import styles from "../styles/PluginData.module.css";
export interface CellCoord {
x: number;
y: number;
}
const NEXUS_MODS_URL = "https://www.nexusmods.com/skyrimspecialedition";
type Props = {
hash: string;
counts: Record<number, [number, number, number]> | null;
};
const PluginData: React.FC<Props> = ({ hash, counts }) => {
const plugins = useAppSelector((state) => state.plugins.plugins);
const plugin = plugins.find((plugin) => plugin.hash === hash);
if (!plugin) {
return <h3>Plugin could not be found</h3>;
}
return (
<>
<Head>
<title key="title">{`Modmapper - ${plugin.filename}`}</title>
<meta
key="description"
name="description"
content={`Map of Skyrim showing ${
plugin.parsed ? plugin.parsed.cells.length : 0
} cell edits from the plugin: ${plugin.filename}`}
/>
<meta
key="og:title"
property="og:title"
content={`Modmapper - ${plugin.filename}`}
/>
<meta
key="og:description"
property="og:description"
content={`Map of Skyrim showing ${
plugin.parsed ? plugin.parsed.cells.length : 0
} cell edits from the plugin: ${plugin.filename}`}
/>
<meta
key="twitter:title"
name="twitter:title"
content={`Modmapper - ${plugin.filename}`}
/>
<meta
key="twitter:description"
name="twitter:description"
content={`Map of Skyrim showing ${
plugin.parsed ? plugin.parsed.cells.length : 0
} cell edits from the plugin: ${plugin.filename}`}
/>
<meta
key="og:url"
property="og:url"
content={`https://modmapper.com/?plugin=${plugin.hash}`}
/>
</Head>
<h1 className={styles.name}>{plugin.filename}</h1>
{plugin.parsed && (
<div>
<strong>Version:&nbsp;</strong>
{plugin.parsed.header.version}
</div>
)}
{plugin.parsed && plugin.parsed.header.author && (
<div>
<strong>Author:&nbsp;</strong>
{plugin.parsed.header.author}
</div>
)}
{plugin.parsed && plugin.parsed.header.masters && (
<div>
<strong>Master plugins:&nbsp;</strong>
{plugin.parsed.header.masters.join(", ")}
</div>
)}
{plugin.parsed && (
<div>
<strong>Cell edits:&nbsp;</strong>
{plugin.parsed.cells.length}
</div>
)}
{plugin.parsed && (
<div>
<strong>World edits:&nbsp;</strong>
{plugin.parsed.worlds.length}
</div>
)}
{plugin.parsed && plugin.parsed.header.description && (
<div>
<h3>Description:</h3>
<p>{plugin.parsed.header.description}</p>
</div>
)}
{plugin.parseError && (
<div>
<h3>Failed to parse plugin:</h3>
<p>{plugin.parseError}</p>
</div>
)}
</>
);
};
export default PluginData;

View File

@ -4,6 +4,7 @@ import { formatRelative } from "date-fns";
import CellData from "./CellData"; import CellData from "./CellData";
import ModData from "./ModData"; import ModData from "./ModData";
import PluginData from "./PluginData";
import PluginsLoader from "./PluginsLoader"; import PluginsLoader from "./PluginsLoader";
import styles from "../styles/Sidebar.module.css"; import styles from "../styles/Sidebar.module.css";
@ -56,6 +57,13 @@ const Sidebar: React.FC<Props> = ({
); );
}; };
const renderPluginData = (plugin: string) => {
if (countsError) return renderLoadError(countsError);
if (!counts) return renderLoading();
return <PluginData hash={plugin} counts={counts} />;
};
const renderOpenSidebar = () => { const renderOpenSidebar = () => {
if (selectedCell) { if (selectedCell) {
return ( return (
@ -89,6 +97,24 @@ const Sidebar: React.FC<Props> = ({
{!Number.isNaN(modId) && renderModData(modId)} {!Number.isNaN(modId) && renderModData(modId)}
</div> </div>
); );
} else if (router.query.plugin) {
return (
<div
className={styles.sidebar}
style={!open ? { display: "none" } : {}}
>
<div className={styles["sidebar-header"]}>
<button className={styles.close} onClick={onClose}>
</button>
</div>
{renderPluginData(
typeof router.query.plugin === "string"
? router.query.plugin
: router.query.plugin[0]
)}
</div>
);
} else { } else {
return ( return (
<div <div

View File

@ -0,0 +1,4 @@
h1.name {
line-height: 1.75rem;
word-wrap: break-word;
}