Skip to content

Commit

Permalink
Fixup older versions
Browse files Browse the repository at this point in the history
  • Loading branch information
shartte committed Oct 29, 2023
1 parent 0a18858 commit 7a719c1
Show file tree
Hide file tree
Showing 10 changed files with 125 additions and 59 deletions.
13 changes: 9 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"pako": "^2.1.0",
"react": "^18",
"react-dom": "^18",
"semver": "^7.5.4",
"three": "^0.151.3",
"tippy.js": "^6.3.7"
},
Expand All @@ -27,6 +28,7 @@
"@types/pako": "^2.0.2",
"@types/react": "^18",
"@types/react-dom": "^18",
"@types/semver": "^7.5.4",
"@types/three": "^0.152.1",
"autoprefixer": "^10",
"cross-env": "^7.0.3",
Expand Down
36 changes: 1 addition & 35 deletions scripts/download_data.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@ async function downloadVersion(versionInfo) {

// Extract all pages:
const guideData = JSON.parse(unzippedGuideData.toString());
const pages = Object.keys(guideData.pages);

// URL which assets are relative to
const baseUrl = new URL(".", guideDataUrl);
Expand All @@ -68,7 +67,6 @@ async function downloadVersion(versionInfo) {
development,
slug: versionSlug,
dataFilename,
pages,
defaultNamespace: guideData.defaultNamespace,
};
}
Expand All @@ -91,39 +89,7 @@ for (let i = 0; i < results.length; i++) {
}
}

// Build a global page list
const versionInfoList = [];
const pagePaths = [];
for (let { pages, ...versionInfo } of downloadedVersions) {
versionInfoList.push(versionInfo);

// Uses next.js type paths: Array<string | { params: Params; locale?: string }>
const versionSlug = versionInfo.slug;
for (let pageId of pages) {
// Manipulate the page path
const [namespace, markdownPath] = pageId.split(":");
const pathSegments = [];
if (namespace !== versionInfo.defaultNamespace) {
pathSegments.push(namespace);
}
pathSegments.push(...markdownPath.split("/"));
pathSegments[pathSegments.length - 1] = pathSegments[
pathSegments.length - 1
].replace(/\.md$/i, "");

pagePaths.push({
versionSlug,
pagePath: pathSegments,
});
}
}

await writeFile(
path.join(dataFolder, "index.json"),
JSON.stringify(versionInfoList, null, 2),
);

await writeFile(
path.join(dataFolder, "page_paths.json"),
JSON.stringify(pagePaths, null, 2),
JSON.stringify(downloadedVersions, null, 2),
);
86 changes: 77 additions & 9 deletions src/app/[versionSlug]/[...pagePath]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,42 @@
import pagePaths from "../../../../data/page_paths.json";
import { getGuide, getPageIdFromSlugs } from "../../../build-data";
import {
getGuide,
getPageIdFromSlugs,
getPagePath,
getSlugsFromPageId,
} from "../../../build-data";
import { compilePage } from "@component/page-compiler/compilePage";
import { ReactElement } from "react";
import { Metadata } from "next";
import GuidePageTitle from "@component/nav/GuidePageTitle.tsx"; // Return a list of `params` to populate the [slug] dynamic segment
import GuidePageTitle from "@component/nav/GuidePageTitle.tsx";
import { ReactElement } from "react"; // Return a list of `params` to populate the [slug] dynamic segment
import { redirect } from "next/navigation";
import { Guide, NavigationNode } from "../../../build-data/Guide.ts"; // Entry-point for the entire version Slug

// Entry-point for the entire version Slug
function isIndexPage(pagePath: string[]) {
return pagePath.length === 1 && pagePath[0] === "index";
}

// Return a list of `params` to populate the [slug] dynamic segment
export async function generateStaticParams() {
return pagePaths;
export async function generateStaticParams({ params: { versionSlug } }: any) {
const guide = await getGuide(versionSlug);

let hadIndexPage = false;
const pages = Object.keys(guide.index.pages).map((pageId) => {
const [_, pagePath] = getSlugsFromPageId(guide, pageId);
if (isIndexPage(pagePath)) {
hadIndexPage = true;
}
return { pagePath };
});

// Ensure an index page is present. This will be auto-generated on-demand if needed.
if (!hadIndexPage) {
pages.push({
pagePath: ["index"],
});
}

return pages;
}

function getTextContent(elem: ReactElement | string): string {
Expand All @@ -27,33 +56,72 @@ function getTextContent(elem: ReactElement | string): string {
}
}

function shouldRedirectToIndexPage(guide: Guide, pagePath: string[]) {
return (
isIndexPage(pagePath) &&
!guide.pageExists(guide.defaultNamespace + ":index.md")
);
}

export async function generateMetadata({
params: { pagePath, versionSlug },
}: any): Promise<Metadata> {
const guide = await getGuide(versionSlug);
if (shouldRedirectToIndexPage(guide, pagePath)) {
return {};
}
const pageId = await getPageIdFromSlugs(versionSlug, pagePath);
if (!guide.pageExists(pageId)) {
}
const page = guide.getPage(pageId);
const { title } = compilePage(guide, pageId, page);

if (title) {
const titleText = getTextContent(title);
return {
title:
getTextContent(title) + " - AE2 Players Guide for " + guide.gameVersion,
title: titleText + " - AE2 Players Guide for " + guide.gameVersion,
};
} else {
return {};
}
}

function findFirstPageNavigationNode(
nodes: NavigationNode[],
): string | undefined {
for (const node of nodes) {
if (node.hasPage) {
return node.pageId;
}
const firstPageId = findFirstPageNavigationNode(node.children);
if (firstPageId) {
return firstPageId;
}
}
return undefined;
}

export default async function Page({ params: { pagePath, versionSlug } }: any) {
const guide = await getGuide(versionSlug);

if (shouldRedirectToIndexPage(guide, pagePath)) {
// Pick the first navigation nodes target
const firstPageId = findFirstPageNavigationNode(
guide.index.navigationRootNodes,
);
if (!firstPageId) {
throw new Error("Couldn't find a suitable index navigation node");
}
redirect(getPagePath(guide, firstPageId));
}

const pageId = await getPageIdFromSlugs(versionSlug, pagePath);
const page = guide.getPage(pageId);
const { title, content } = compilePage(guide, pageId, page);
return (
<>
{content}
{title && <GuidePageTitle title={getTextContent(title)} />}
{title && <GuidePageTitle title={title} />}
</>
);
}
7 changes: 7 additions & 0 deletions src/app/[versionSlug]/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,14 @@ import { NavBarNode } from "@component/nav/GuideNavBar.tsx";
import GuideShell from "@component/nav/GuideShell.tsx";
import { getGuide, getPagePath } from "../../build-data";
import { Guide, NavigationNode } from "../../build-data/Guide.ts";
import { guideVersions } from "../../build-data/GuideVersionIndex.ts";

// Return a list of `params` to populate the [slug] dynamic segment
export function generateStaticParams() {
return guideVersions.map((version) => ({
versionSlug: version.slug,
}));
}
function buildNavigationNode(guide: Guide, node: NavigationNode): NavBarNode {
let href: string | undefined;
let icon: string | undefined;
Expand Down
8 changes: 5 additions & 3 deletions src/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,11 @@ function GuideVersionSelection() {
return (
<div className={css.root}>
<h1>Guide Versions</h1>
{guideVersions.reverse().map((version) => (
<GuideVersion key={version.slug} version={version} />
))}
{guideVersions
.filter((gv) => !gv.development)
.map((version) => (
<GuideVersion key={version.slug} version={version} />
))}
</div>
);
}
Expand Down
11 changes: 11 additions & 0 deletions src/build-data/GuideVersionIndex.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import data from "../../data/index.json";
import { coerce, compare } from "semver";

export type GuideVersion = {
baseUrl: string;
Expand All @@ -15,6 +16,16 @@ export type GuideVersionIndex = GuideVersion[];

export const guideVersions: GuideVersionIndex = data;

function compareMinecraftVersion(a: string, b: string) {
const aVersion = coerce(a) ?? "0.0.0";
const bVersion = coerce(b) ?? "0.0.0";
return compare(aVersion, bVersion);
}

guideVersions.sort((a, b) =>
compareMinecraftVersion(b.gameVersion, a.gameVersion),
);

/**
* Find the Version that uses the given path-segment.
*/
Expand Down
8 changes: 4 additions & 4 deletions src/components/nav/GuidePageTitle.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
"use client";
import { useEffect } from "react";
import { ReactElement, useEffect } from "react";
import { useGuidePageTitleSetter } from "@component/nav/GuidePageTitleProvider.tsx";

export interface GuidePageTitleProps {
title: string;
title: ReactElement | undefined;
}

function GuidePageTitle({ title }: GuidePageTitleProps) {
const setPageTitle = useGuidePageTitleSetter();
useEffect(() => {
setPageTitle(title);
setPageTitle(title ?? null);
return () => {
setPageTitle("");
setPageTitle(null);
};
}, [setPageTitle, title]);
return null;
Expand Down
4 changes: 2 additions & 2 deletions src/components/nav/GuidePageTitleProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
"use client";

import { createContext, useContext } from "react";
import { createContext, ReactElement, useContext } from "react";

type GuidePageTitleSetter = (title: string) => void;
type GuidePageTitleSetter = (title: ReactElement | null) => void;

const context = createContext<GuidePageTitleSetter>(() => {});

Expand Down
9 changes: 7 additions & 2 deletions src/components/nav/GuideShell.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
"use client";

import React, { PropsWithChildren, useCallback, useState } from "react";
import React, {
PropsWithChildren,
ReactElement,
useCallback,
useState,
} from "react";
import css from "../../app/[versionSlug]/layout.module.css";
import Link from "next/link";
import Image from "next/image";
Expand All @@ -18,7 +23,7 @@ function GuideShell({
gameVersion,
navigationNodes,
}: PropsWithChildren<GuideShellProps>) {
const [pageTitle, setPageTitle] = useState<string>("");
const [pageTitle, setPageTitle] = useState<ReactElement | null>(null);
const [menuExpanded, setMenuExpanded] = useState(false);
const toggleMenu = useCallback(() => {
setMenuExpanded((expanded) => !expanded);
Expand Down

0 comments on commit 7a719c1

Please sign in to comment.