Make markdown work recursively
Some checks failed
Deploy Frontend / docker (17, 3.8.5) (push) Failing after 2m53s
Some checks failed
Deploy Frontend / docker (17, 3.8.5) (push) Failing after 2m53s
This commit is contained in:
parent
a665d5d0ba
commit
5e67ce1f34
Binary file not shown.
@ -39,6 +39,7 @@
|
||||
"react-hook-form": "^7.51.3",
|
||||
"remark-gfm": "^4.0.0",
|
||||
"restfulmc-lib": "^1.1.3",
|
||||
"shadcn-ui": "0.8.0",
|
||||
"sharp": "^0.33.3",
|
||||
"sonner": "^1.4.41",
|
||||
"tailwind-merge": "^2.2.2",
|
||||
|
@ -3,6 +3,15 @@ import { getDocsContent } from "@/lib/mdxUtils";
|
||||
import { PageProps } from "@/types/page";
|
||||
import { notFound } from "next/navigation";
|
||||
|
||||
import {
|
||||
Breadcrumb,
|
||||
BreadcrumbItem,
|
||||
BreadcrumbLink,
|
||||
BreadcrumbList,
|
||||
BreadcrumbSeparator,
|
||||
} from "@/components/ui/breadcrumb";
|
||||
import { capitalize } from "@/lib/stringUtils";
|
||||
|
||||
/**
|
||||
* The page to display content
|
||||
* from an MDX file on the docs.
|
||||
@ -10,17 +19,47 @@ import { notFound } from "next/navigation";
|
||||
* @param slug the slug of the mdx file
|
||||
* @return the page jsx
|
||||
*/
|
||||
const ContentPage = ({ params: { slug } }: PageProps): ReactElement => {
|
||||
const ContentPage = ({ params }: PageProps): ReactElement => {
|
||||
const slug: string = ((params.slug as string[]) || undefined)?.join("/"); // The slug of the content
|
||||
|
||||
const content: DocsContentMetadata | undefined = getDocsContent().find(
|
||||
(metadata: DocsContentMetadata): boolean =>
|
||||
metadata.slug === (slug ? slug[0] : "home")
|
||||
metadata.slug === (slug || "home")
|
||||
); // Get the content to display based on the provided slug
|
||||
|
||||
// Return a 404 if the content is not found
|
||||
if (!content) {
|
||||
notFound();
|
||||
}
|
||||
const splitSlug: string[] = content.slug?.split("/") || [];
|
||||
|
||||
return <main>{content.title}</main>;
|
||||
return (
|
||||
<main>
|
||||
{/* Breadcrumb */}
|
||||
<Breadcrumb>
|
||||
<BreadcrumbList className="text-minecraft-green-4">
|
||||
{["docs", ...splitSlug].map(
|
||||
(part: string, index: number): ReactElement => (
|
||||
<div className="flex items-center" key={index}>
|
||||
<BreadcrumbItem>
|
||||
<BreadcrumbLink
|
||||
href={
|
||||
(index > 0 ? "/docs" : "") +
|
||||
`/${part}`
|
||||
}
|
||||
>
|
||||
{capitalize(part)}
|
||||
</BreadcrumbLink>
|
||||
</BreadcrumbItem>
|
||||
{index < splitSlug.length && (
|
||||
<BreadcrumbSeparator className="pl-1.5" />
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
)}
|
||||
</BreadcrumbList>
|
||||
</Breadcrumb>
|
||||
</main>
|
||||
);
|
||||
};
|
||||
export default ContentPage;
|
||||
|
@ -12,9 +12,11 @@ const DocumentationLayout = ({
|
||||
}: Readonly<{
|
||||
children: ReactNode;
|
||||
}>): ReactElement => (
|
||||
<section className="h-screen flex flex-col justify-center items-center">
|
||||
<Sidebar />
|
||||
{children}
|
||||
<section className="h-screen flex justify-center items-center">
|
||||
<div className="flex gap-10">
|
||||
<Sidebar />
|
||||
{children}
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
export default DocumentationLayout;
|
||||
|
@ -1,25 +1,40 @@
|
||||
import * as fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import { Stats } from "node:fs";
|
||||
|
||||
/**
|
||||
* The regex to match for metadata.
|
||||
*/
|
||||
const METADATA_REGEX: RegExp = /---\s*([\s\S]*?)\s*---/;
|
||||
|
||||
/**
|
||||
* The directory docs are stored in.
|
||||
*/
|
||||
const DOCS_DIR: string = path.join(process.cwd(), "docs");
|
||||
|
||||
/**
|
||||
* Get the content to
|
||||
* display in the docs.
|
||||
*/
|
||||
export const getDocsContent = (): DocsContentMetadata[] =>
|
||||
getMetadata<DocsContentMetadata>(path.join(process.cwd(), "docs"));
|
||||
export const getDocsContent = (): DocsContentMetadata[] => {
|
||||
const content: DocsContentMetadata[] = [];
|
||||
for (let directory of getRecursiveDirectories(DOCS_DIR)) {
|
||||
content.push(...getMetadata<DocsContentMetadata>(DOCS_DIR, directory));
|
||||
}
|
||||
return content;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the metadata of mdx
|
||||
* files in the given directory.
|
||||
*
|
||||
* @param parent the parent directory to search
|
||||
* @param directory the directory to search
|
||||
*/
|
||||
export const getMetadata = <T extends MDXMetadata>(directory: string): T[] => {
|
||||
const getMetadata = <T extends MDXMetadata>(
|
||||
parent: string,
|
||||
directory: string
|
||||
): T[] => {
|
||||
const files: string[] = fs
|
||||
.readdirSync(directory)
|
||||
.filter((file: string): boolean => {
|
||||
@ -29,8 +44,12 @@ export const getMetadata = <T extends MDXMetadata>(directory: string): T[] => {
|
||||
return files.map((file: string): T => {
|
||||
const filePath: string = path.join(directory, file); // The path of the file
|
||||
return {
|
||||
slug: filePath
|
||||
.replace(parent, "")
|
||||
.replace(/\\/g, "/") // Normalize the path
|
||||
.replace(/\.mdx?$/, "")
|
||||
.substring(1),
|
||||
...parseMetadata<T>(fs.readFileSync(filePath, "utf-8")),
|
||||
slug: path.basename(file, path.extname(file)),
|
||||
}; // Map each file to its metadata
|
||||
});
|
||||
};
|
||||
@ -65,3 +84,24 @@ const parseMetadata = <T extends MDXMetadata>(content: string): T => {
|
||||
// slug is empty, and is defined later on.
|
||||
return { ...metadata, content } as T;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get directories recursively
|
||||
* in the given directory.
|
||||
*
|
||||
* @param directory the directory to search
|
||||
* @return the directories
|
||||
*/
|
||||
const getRecursiveDirectories = (directory: string): string[] => {
|
||||
const directories: string[] = [directory]; // The directories to return
|
||||
|
||||
for (let sub of fs.readdirSync(directory)) {
|
||||
const subDirPath: string = path.join(directory, sub); // The sub dir path
|
||||
const stats: Stats = fs.statSync(subDirPath); // Get file stats
|
||||
if (stats.isDirectory()) {
|
||||
directories.push(...getRecursiveDirectories(subDirPath)); // Recursively get directories
|
||||
}
|
||||
}
|
||||
|
||||
return directories;
|
||||
};
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { ReactElement } from "react";
|
||||
import { Input } from "@/components/ui/input";
|
||||
|
||||
/**
|
||||
* The sidebar for the docs page.
|
||||
@ -6,8 +7,14 @@ import { ReactElement } from "react";
|
||||
* @returns the sidebar jsx
|
||||
*/
|
||||
const Sidebar = (): ReactElement => (
|
||||
<div className="absolute left-20 h-72 p-5 bg-muted rounded-xl">
|
||||
<h1 className="font-semibold uppercase">SIDEBAR</h1>
|
||||
<div className="w-60 h-80 px-3 py-5 flex justify-center bg-muted border border-zinc-700/70 rounded-lg">
|
||||
{/* Search */}
|
||||
<Input
|
||||
type="search"
|
||||
name="search"
|
||||
placeholder="Quick search..."
|
||||
disabled
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
export default Sidebar;
|
||||
|
2
Frontend/src/app/types/mdx.d.ts
vendored
2
Frontend/src/app/types/mdx.d.ts
vendored
@ -25,7 +25,7 @@ type MDXMetadata = {
|
||||
/**
|
||||
* The slug of the file, defined once read.
|
||||
*/
|
||||
slug: string;
|
||||
slug?: string | undefined;
|
||||
|
||||
/**
|
||||
* The metadata of the file.
|
||||
|
4
Frontend/src/app/types/page.d.ts
vendored
4
Frontend/src/app/types/page.d.ts
vendored
@ -2,6 +2,6 @@
|
||||
* Props for a page.
|
||||
*/
|
||||
export type PageProps = {
|
||||
params: { slug: string };
|
||||
searchParams: { [key: string]: string | string[] | undefined };
|
||||
params: { slug: string[] };
|
||||
searchParams: { [key: string]: string | string[] | undefined };
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user