WIP plugin details sourced from static server
This commit is contained in:
parent
559b6600ac
commit
74c8920edf
@ -1,63 +1,65 @@
|
||||
import Head from "next/head";
|
||||
import React from "react";
|
||||
|
||||
import { useAppSelector } from "../lib/hooks";
|
||||
import styles from "../styles/PluginData.module.css";
|
||||
import { Cell } from "./CellData";
|
||||
|
||||
export interface CellCoord {
|
||||
x: number;
|
||||
y: number;
|
||||
export interface Plugin {
|
||||
id: number;
|
||||
name: string;
|
||||
hash: bigint;
|
||||
file_id: number;
|
||||
mod_id: number;
|
||||
version: number;
|
||||
size: number;
|
||||
author?: string;
|
||||
description?: string;
|
||||
masters: string[];
|
||||
file_name: string;
|
||||
file_path: string;
|
||||
updated_at: Date;
|
||||
created_at: Date;
|
||||
cells: Omit<Cell, "mods">[];
|
||||
}
|
||||
|
||||
const NEXUS_MODS_URL = "https://www.nexusmods.com/skyrimspecialedition";
|
||||
|
||||
type Props = {
|
||||
hash: string;
|
||||
plugin: Plugin;
|
||||
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);
|
||||
|
||||
const PluginData: React.FC<Props> = ({ plugin, counts }) => {
|
||||
if (!plugin) {
|
||||
return <h3>Plugin could not be found</h3>;
|
||||
return <h3>Plugin could not be found.</h3>;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<title key="title">{`Modmapper - ${plugin.filename}`}</title>
|
||||
<title key="title">{`Modmapper - ${plugin.file_name}`}</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}`}
|
||||
content={`Map of Skyrim showing ${plugin.cells.length} cell edits from the plugin: ${plugin.file_name}`}
|
||||
/>
|
||||
<meta
|
||||
key="og:title"
|
||||
property="og:title"
|
||||
content={`Modmapper - ${plugin.filename}`}
|
||||
content={`Modmapper - ${plugin.file_name}`}
|
||||
/>
|
||||
<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}`}
|
||||
content={`Map of Skyrim showing ${plugin.cells.length} cell edits from the plugin: ${plugin.file_name}`}
|
||||
/>
|
||||
<meta
|
||||
key="twitter:title"
|
||||
name="twitter:title"
|
||||
content={`Modmapper - ${plugin.filename}`}
|
||||
content={`Modmapper - ${plugin.file_name}`}
|
||||
/>
|
||||
<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}`}
|
||||
content={`Map of Skyrim showing ${plugin.cells.length} cell edits from the plugin: ${plugin.file_name}`}
|
||||
/>
|
||||
<meta
|
||||
key="og:url"
|
||||
@ -65,47 +67,27 @@ const PluginData: React.FC<Props> = ({ hash, counts }) => {
|
||||
content={`https://modmapper.com/?plugin=${plugin.hash}`}
|
||||
/>
|
||||
</Head>
|
||||
<h1 className={styles.name}>{plugin.filename}</h1>
|
||||
{plugin.parsed && (
|
||||
<div>
|
||||
<strong>Version: </strong>
|
||||
{plugin.parsed.header.version}
|
||||
</div>
|
||||
)}
|
||||
{plugin.parsed && plugin.parsed.header.author && (
|
||||
<h1 className={styles.name}>{plugin.file_name}</h1>
|
||||
{plugin.author && (
|
||||
<div>
|
||||
<strong>Author: </strong>
|
||||
{plugin.parsed.header.author}
|
||||
{plugin.author}
|
||||
</div>
|
||||
)}
|
||||
{plugin.parsed && plugin.parsed.header.masters && (
|
||||
{plugin.masters.length > 0 && (
|
||||
<div>
|
||||
<strong>Master plugins: </strong>
|
||||
{plugin.parsed.header.masters.join(", ")}
|
||||
{plugin.masters.join(", ")}
|
||||
</div>
|
||||
)}
|
||||
{plugin.parsed && (
|
||||
<div>
|
||||
<strong>Cell edits: </strong>
|
||||
{plugin.parsed.cells.length}
|
||||
{plugin.cells.length}
|
||||
</div>
|
||||
)}
|
||||
{plugin.parsed && (
|
||||
<div>
|
||||
<strong>World edits: </strong>
|
||||
{plugin.parsed.worlds.length}
|
||||
</div>
|
||||
)}
|
||||
{plugin.parsed && plugin.parsed.header.description && (
|
||||
{plugin.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>
|
||||
<p>{plugin.description}</p>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
|
114
components/PluginDetail.tsx
Normal file
114
components/PluginDetail.tsx
Normal file
@ -0,0 +1,114 @@
|
||||
import React from "react";
|
||||
import useSWRImmutable from "swr/immutable";
|
||||
|
||||
import { useAppSelector } from "../lib/hooks";
|
||||
import { Mod } from "./ModData";
|
||||
import PluginData from "./PluginData";
|
||||
import styles from "../styles/PluginData.module.css";
|
||||
|
||||
export interface File {
|
||||
id: number;
|
||||
name: string;
|
||||
file_name: string;
|
||||
nexus_file_id: number;
|
||||
mod_id: number;
|
||||
category?: string;
|
||||
version?: string;
|
||||
mod_version?: string;
|
||||
size: number;
|
||||
uploaded_at?: Date;
|
||||
has_download_link: boolean;
|
||||
updated_at: Date;
|
||||
created_at: Date;
|
||||
downloaded_at?: Date;
|
||||
has_plugin: boolean;
|
||||
unable_to_extract_plugins: boolean;
|
||||
}
|
||||
|
||||
export interface Plugin {
|
||||
id: number;
|
||||
name: string;
|
||||
hash: bigint;
|
||||
file_id: number;
|
||||
mod_id: number;
|
||||
version: number;
|
||||
size: number;
|
||||
author?: string;
|
||||
description?: string;
|
||||
masters: string[];
|
||||
file_name: string;
|
||||
file_path: string;
|
||||
updated_at: Date;
|
||||
created_at: Date;
|
||||
file: File;
|
||||
mod: Omit<Mod, "cells">;
|
||||
}
|
||||
|
||||
const NEXUS_MODS_URL = "https://www.nexusmods.com/skyrimspecialedition";
|
||||
|
||||
const jsonFetcher = async (url: string): Promise<Plugin | null> => {
|
||||
const res = await fetch(url);
|
||||
|
||||
if (!res.ok) {
|
||||
if (res.status === 404) {
|
||||
return null;
|
||||
}
|
||||
const error = new Error("An error occurred while fetching the data.");
|
||||
throw error;
|
||||
}
|
||||
return res.json();
|
||||
};
|
||||
|
||||
type Props = {
|
||||
hash: string;
|
||||
counts: Record<number, [number, number, number]> | null;
|
||||
};
|
||||
|
||||
const PluginDetail: React.FC<Props> = ({ hash, counts }) => {
|
||||
const { data, error } = useSWRImmutable(
|
||||
`https://plugins.modmapper.com/${hash}.json`,
|
||||
jsonFetcher
|
||||
);
|
||||
|
||||
const plugins = useAppSelector((state) => state.plugins.plugins);
|
||||
const plugin = plugins.find((plugin) => plugin.hash === hash);
|
||||
|
||||
if (!plugin && error && error.status === 404) {
|
||||
return <h3>Plugin could not be found.</h3>;
|
||||
} else if (!plugin && error) {
|
||||
return <div>{`Error loading plugin data: ${error.message}`}</div>;
|
||||
}
|
||||
if (!plugin && data === undefined)
|
||||
return <div className={styles.status}>Loading...</div>;
|
||||
if (!plugin && data === null)
|
||||
return <div className={styles.status}>Plugin could not be found.</div>;
|
||||
|
||||
return (
|
||||
<>
|
||||
<PluginData
|
||||
plugin={
|
||||
// TODO: merge into one common plugin object
|
||||
data || {
|
||||
id: plugin!.id,
|
||||
name: plugin!.name,
|
||||
hash: plugin!.hash,
|
||||
file_id: plugin!.file_id,
|
||||
mod_id: plugin!.mod_id,
|
||||
version: plugin!.version,
|
||||
size: plugin!.size,
|
||||
author: plugin!.author,
|
||||
description: plugin!.description,
|
||||
masters: plugin!.masters,
|
||||
file_name: plugin!.filename,
|
||||
file_path: plugin!.filepath,
|
||||
updated_at: plugin!.updated_at,
|
||||
created_at: plugin!.created_at,
|
||||
cells: plugin!.cells,
|
||||
}
|
||||
}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default PluginDetail;
|
@ -4,7 +4,7 @@ import { formatRelative } from "date-fns";
|
||||
|
||||
import CellData from "./CellData";
|
||||
import ModData from "./ModData";
|
||||
import PluginData from "./PluginData";
|
||||
import PluginDetail from "./PluginDetail";
|
||||
import DataDirPicker from "./DataDirPicker";
|
||||
import PluginTxtEditor from "./PluginTxtEditor";
|
||||
import PluginsList from "./PluginsList";
|
||||
@ -63,7 +63,7 @@ const Sidebar: React.FC<Props> = ({
|
||||
if (countsError) return renderLoadError(countsError);
|
||||
if (!counts) return renderLoading();
|
||||
|
||||
return <PluginData hash={plugin} counts={counts} />;
|
||||
return <PluginDetail hash={plugin} counts={counts} />;
|
||||
};
|
||||
|
||||
const renderOpenSidebar = () => {
|
||||
|
Loading…
Reference in New Issue
Block a user