Docs page
All checks were successful
Deploy Frontend / docker (17, 3.8.5) (push) Successful in 2m40s

This commit is contained in:
Braydon 2024-04-20 01:33:33 -04:00
parent ab05ad8a3e
commit a8cf72e981
42 changed files with 241 additions and 94 deletions

Binary file not shown.

@ -1,5 +1,8 @@
import createMDX from '@next/mdx'
/** @type {import('next').NextConfig} */ /** @type {import('next').NextConfig} */
const nextConfig = { const nextConfig = {
pageExtensions: ["ts", "tsx", "js", "jsx", "md", "mdx"],
images: { images: {
remotePatterns: [ remotePatterns: [
{ {
@ -8,6 +11,12 @@ const nextConfig = {
}, },
], ],
}, },
experimental: {
mdxRs: true,
},
}; };
export default nextConfig; const withMDX = createMDX({})
// Merge MDX config with Next.js config
export default withMDX(nextConfig)

@ -14,6 +14,9 @@
"dependencies": { "dependencies": {
"@heroicons/react": "^2.1.3", "@heroicons/react": "^2.1.3",
"@hookform/resolvers": "^3.3.4", "@hookform/resolvers": "^3.3.4",
"@mdx-js/loader": "^3.0.1",
"@mdx-js/react": "^3.0.1",
"@next/mdx": "^14.2.2",
"@radix-ui/react-context-menu": "^2.1.5", "@radix-ui/react-context-menu": "^2.1.5",
"@radix-ui/react-label": "^2.0.2", "@radix-ui/react-label": "^2.0.2",
"@radix-ui/react-navigation-menu": "^1.1.4", "@radix-ui/react-navigation-menu": "^1.1.4",
@ -22,6 +25,7 @@
"@radix-ui/react-slot": "^1.0.2", "@radix-ui/react-slot": "^1.0.2",
"@radix-ui/react-toast": "^1.1.5", "@radix-ui/react-toast": "^1.1.5",
"@radix-ui/react-tooltip": "^1.0.7", "@radix-ui/react-tooltip": "^1.0.7",
"@types/mdx": "^2.0.13",
"class-variance-authority": "^0.7.0", "class-variance-authority": "^0.7.0",
"clipboard-copy": "^4.0.1", "clipboard-copy": "^4.0.1",
"clsx": "^2.1.0", "clsx": "^2.1.0",
@ -33,6 +37,7 @@
"react-countup": "^6.5.3", "react-countup": "^6.5.3",
"react-dom": "^18", "react-dom": "^18",
"react-hook-form": "^7.51.3", "react-hook-form": "^7.51.3",
"remark-gfm": "^4.0.0",
"restfulmc-lib": "^1.1.3", "restfulmc-lib": "^1.1.3",
"sonner": "^1.4.41", "sonner": "^1.4.41",
"tailwind-merge": "^2.2.2", "tailwind-merge": "^2.2.2",

@ -0,0 +1,26 @@
import { ReactElement } from "react";
import { getDocsContent } from "@/lib/mdxUtils";
import { PageProps } from "@/types/page";
import { notFound } from "next/navigation";
/**
* The page to display content
* from an MDX file on the docs.
*
* @param slug the slug of the mdx file
* @return the page jsx
*/
const ContentPage = ({ params: { slug } }: PageProps): ReactElement => {
const content: DocsContentMetadata | undefined = getDocsContent().find(
(metadata: DocsContentMetadata): boolean =>
metadata.slug === (slug ? slug[0] : "home")
); // Get the content to display based on the provided slug
// Return a 404 if the content is not found
if (!content) {
notFound();
}
return <main>{content.title}</main>;
};
export default ContentPage;

@ -0,0 +1,20 @@
import { ReactElement, ReactNode } from "react";
import Sidebar from "@/components/docs/sidebar";
/**
* The layout for the docs page.
*
* @param children the children of this layout
* @returns the layout jsx
*/
const DocumentationLayout = ({
children,
}: Readonly<{
children: ReactNode;
}>): ReactElement => (
<section className="h-screen flex flex-col justify-center items-center">
<Sidebar />
{children}
</section>
);
export default DocumentationLayout;

@ -1,48 +0,0 @@
import Creeper from "@/components/creeper";
import { minecrafter } from "@/font/fonts";
import { cn } from "@/lib/utils";
import { Metadata } from "next";
import Link from "next/link";
import { ReactElement } from "react";
/**
* Page metadata.
*/
export const metadata: Metadata = {
title: "Docs",
};
/**
* The documentation page.
*
* @returns the page jsx
*/
const DocsPage = (): ReactElement => (
<main className="h-screen flex flex-col gap-3 justify-center items-center text-center pointer-events-none">
{/* Creeper */}
<Creeper />
{/* Header */}
<h1
className={cn(
"text-5xl sm:text-6xl text-minecraft-green-3",
minecrafter.className
)}
>
Documentation
</h1>
{/* Error */}
<h2 className="text-2xl">
This page is still under construction, however we do have a{" "}
<Link
className="text-minecraft-green-4 pointer-events-auto"
href="https://git.rainnny.club/Rainnny/RESTfulMC/wiki"
>
Wiki
</Link>
!
</h2>
</main>
);
export default DocsPage;

@ -1,5 +1,5 @@
import { minecrafter } from "@/font/fonts"; import { minecrafter } from "@/font/fonts";
import { cn } from "@/lib/utils"; import { cn } from "@/app/common/utils";
import { Metadata } from "next"; import { Metadata } from "next";
import Link from "next/link"; import Link from "next/link";
import { ReactElement } from "react"; import { ReactElement } from "react";

@ -3,7 +3,7 @@ import PlayerResult from "@/components/player/player-result";
import PlayerSearch from "@/components/player/player-search"; import PlayerSearch from "@/components/player/player-search";
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"; import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
import { minecrafter } from "@/font/fonts"; import { minecrafter } from "@/font/fonts";
import { cn } from "@/lib/utils"; import { cn } from "@/app/common/utils";
import { PageProps } from "@/types/page"; import { PageProps } from "@/types/page";
import { ExclamationCircleIcon } from "@heroicons/react/24/outline"; import { ExclamationCircleIcon } from "@heroicons/react/24/outline";
import { Metadata, Viewport } from "next"; import { Metadata, Viewport } from "next";
@ -70,7 +70,7 @@ const PlayerPage = async ({ params }: PageProps): Promise<ReactElement> => {
export const generateMetadata = async ({ export const generateMetadata = async ({
params, params,
}: PageProps): Promise<Metadata> => { }: PageProps): Promise<Metadata> => {
const embed: Metadata | undefined = await getPageEmbed( const embed: Metadata | undefined = await getPlayerEmbed(
trimQuery(params.slug?.[0]) trimQuery(params.slug?.[0])
); // Get the page embed ); // Get the page embed
@ -92,10 +92,10 @@ export const generateMetadata = async ({
export const generateViewport = async ({ export const generateViewport = async ({
params, params,
}: PageProps): Promise<Viewport> => { }: PageProps): Promise<Viewport> => {
const embed: Metadata | undefined = await getPageEmbed( const embed: Metadata | undefined = await getPlayerEmbed(
trimQuery(params.slug?.[0]) trimQuery(params.slug?.[0])
); // Get the page embed ); // Get the page embed
return embed ? {} : { themeColor: "#FF5555" }; return embed ? {} : { themeColor: "#AA0000" };
}; };
/** /**
@ -118,7 +118,7 @@ const trimQuery = (query: string | undefined): string | undefined => {
* @param query the query to embed, if any * @param query the query to embed, if any
* @returns the page embed * @returns the page embed
*/ */
const getPageEmbed = async ( const getPlayerEmbed = async (
query: string | undefined query: string | undefined
): Promise<Metadata | undefined> => { ): Promise<Metadata | undefined> => {
if (!query) { if (!query) {

@ -3,8 +3,8 @@ import ServerResult from "@/components/server/server-result";
import ServerSearch from "@/components/server/server-search"; import ServerSearch from "@/components/server/server-search";
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"; import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
import { minecrafter } from "@/font/fonts"; import { minecrafter } from "@/font/fonts";
import { capitalize } from "@/lib/stringUtils"; import { capitalize } from "@/app/common/stringUtils";
import { cn } from "@/lib/utils"; import { cn } from "@/app/common/utils";
import { PageProps } from "@/types/page"; import { PageProps } from "@/types/page";
import { ExclamationCircleIcon } from "@heroicons/react/24/outline"; import { ExclamationCircleIcon } from "@heroicons/react/24/outline";
import { Metadata } from "next"; import { Metadata } from "next";

@ -0,0 +1,66 @@
import * as fs from "node:fs";
import path from "node:path";
/**
* The regex to match for metadata.
*/
const METADATA_REGEX: RegExp = /---\s*([\s\S]*?)\s*---/;
/**
* Get the content to
* display in the docs.
*/
export const getDocsContent = (): DocsContentMetadata[] =>
getMetadata<DocsContentMetadata>(
path.join(process.cwd(), "src", "markdown", "docs")
);
/**
* Get the metadata of mdx
* files in the given directory.
*
* @param directory the directory to search
*/
export const getMetadata = <T extends MDXMetadata>(directory: string): T[] => {
const files: string[] = fs
.readdirSync(directory)
.filter((file: string): boolean => path.extname(file) === ".mdx"); // Read the MDX files
return files.map((file: string): T => {
const filePath: string = path.join(directory, file); // The path of the file
return {
...parseMetadata<T>(fs.readFileSync(filePath, "utf-8")),
slug: path.basename(file, path.extname(file)),
}; // Map each file to its metadata
});
};
/**
* Parse the metadata from
* the given content.
*
* @param content the content to parse
* @returns the metadata and content
* @template T the type of metadata
*/
const parseMetadata = <T extends MDXMetadata>(content: string): T => {
const metadataBlock: string = METADATA_REGEX.exec(content)![1]; // Get the block of metadata
content = content.replace(METADATA_REGEX, "").trim(); // Remove the metadata block from the content
let metadata: Partial<{
[key: string]: string;
}> = {}; // The metadata to return
// Parse the metadata block as a key-value pair
metadataBlock
.trim() // Trim any leading or trailing whitespace
.split("\n") // Get each line
.forEach((line: string): void => {
const split: string[] = line.split(": "); // Split the metadata by the colon
let value: string = split[1].trim(); // The value of the metadata
value = value.replace(/^['"](.*)['"]$/, "$1"); // Remove quotes
metadata[split[0].trim()] = value; // Add the metadata to the object
});
// Return the metadata and content. The initial
// slug is empty, and is defined later on.
return { ...metadata, content } as T;
};

@ -1,7 +1,7 @@
"use client"; "use client";
import { minecrafter } from "@/font/fonts"; import { minecrafter } from "@/font/fonts";
import { cn } from "@/lib/utils"; import { cn } from "@/app/common/utils";
import CountUp from "react-countup"; import CountUp from "react-countup";
import { ReactElement } from "react"; import { ReactElement } from "react";

@ -0,0 +1,13 @@
import { ReactElement } from "react";
/**
* The sidebar for the docs page.
*
* @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>
);
export default Sidebar;

@ -3,7 +3,7 @@ import Link from "next/link";
import { ReactElement } from "react"; import { ReactElement } from "react";
import config from "@/config"; import config from "@/config";
import { minecrafter } from "@/font/fonts"; import { minecrafter } from "@/font/fonts";
import { cn } from "@/lib/utils"; import { cn } from "@/app/common/utils";
import { FooterLinks } from "@/types/config"; import { FooterLinks } from "@/types/config";
/** /**

@ -4,14 +4,7 @@ import MinecraftButton from "@/components/minecraft-button";
import { Skeleton } from "@/components/ui/skeleton"; import { Skeleton } from "@/components/ui/skeleton";
import { StarIcon } from "@heroicons/react/24/outline"; import { StarIcon } from "@heroicons/react/24/outline";
import Link from "next/link"; import Link from "next/link";
import { import { Dispatch, ReactElement, SetStateAction, Suspense, useEffect, useState } from "react";
Dispatch,
ReactElement,
SetStateAction,
Suspense,
useEffect,
useState,
} from "react";
/** /**
* The button to display the amount * The button to display the amount

@ -1,5 +1,5 @@
import { ReactElement } from "react"; import { ReactElement } from "react";
import { cn } from "../../lib/utils"; import { cn } from "@/app/common/utils";
/** /**
* The background hero component. * The background hero component.

@ -1,6 +1,6 @@
import config from "@/config"; import config from "@/config";
import { minecrafter } from "@/font/fonts"; import { minecrafter } from "@/font/fonts";
import { cn } from "@/lib/utils"; import { cn } from "@/app/common/utils";
import { FeaturedItemProps } from "@/types/config"; import { FeaturedItemProps } from "@/types/config";
import Link from "next/link"; import Link from "next/link";
import { ReactElement } from "react"; import { ReactElement } from "react";

@ -2,7 +2,7 @@ import GitHubStarButton from "@/components/github-star-button";
import MinecraftButton from "@/components/minecraft-button"; import MinecraftButton from "@/components/minecraft-button";
import config from "@/config"; import config from "@/config";
import { minecrafter } from "@/font/fonts"; import { minecrafter } from "@/font/fonts";
import { cn } from "@/lib/utils"; import { cn } from "@/app/common/utils";
import Link from "next/link"; import Link from "next/link";
import { ReactElement } from "react"; import { ReactElement } from "react";

@ -1,5 +1,5 @@
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { cn } from "@/lib/utils"; import { cn } from "@/app/common/utils";
import { ButtonHTMLAttributes, ReactElement, ReactNode } from "react"; import { ButtonHTMLAttributes, ReactElement, ReactNode } from "react";
/** /**

@ -3,7 +3,7 @@
import GitHubStarButton from "@/components/github-star-button"; import GitHubStarButton from "@/components/github-star-button";
import config from "@/config"; import config from "@/config";
import { minecrafter } from "@/font/fonts"; import { minecrafter } from "@/font/fonts";
import { cn } from "@/lib/utils"; import { cn } from "@/app/common/utils";
import Image from "next/image"; import Image from "next/image";
import Link from "next/link"; import Link from "next/link";
import { usePathname } from "next/navigation"; import { usePathname } from "next/navigation";

@ -1,11 +1,6 @@
import CopyButton from "@/components/copy-button"; import CopyButton from "@/components/copy-button";
import { Badge } from "@/components/ui/badge"; import { Badge } from "@/components/ui/badge";
import { import { ContextMenu, ContextMenuContent, ContextMenuItem, ContextMenuTrigger } from "@/components/ui/context-menu";
ContextMenu,
ContextMenuContent,
ContextMenuItem,
ContextMenuTrigger,
} from "@/components/ui/context-menu";
import config from "@/config"; import config from "@/config";
import Image from "next/image"; import Image from "next/image";
import Link from "next/link"; import Link from "next/link";

@ -1,4 +1,4 @@
import { cn } from "@/lib/utils"; import { cn } from "@/app/common/utils";
import Image from "next/image"; import Image from "next/image";
import { ReactElement } from "react"; import { ReactElement } from "react";
import { import {

@ -9,7 +9,7 @@ import {
SelectTrigger, SelectTrigger,
SelectValue, SelectValue,
} from "@/components/ui/select"; } from "@/components/ui/select";
import { capitalize } from "@/lib/stringUtils"; import { capitalize } from "@/app/common/stringUtils";
import { redirect } from "next/navigation"; import { redirect } from "next/navigation";
import { ReactElement } from "react"; import { ReactElement } from "react";
import { ServerPlatform } from "restfulmc-lib"; import { ServerPlatform } from "restfulmc-lib";

@ -1,7 +1,7 @@
import { cva, type VariantProps } from "class-variance-authority"; import { cva, type VariantProps } from "class-variance-authority";
import * as React from "react"; import * as React from "react";
import { cn } from "@/app/lib/utils"; import { cn } from "@/app/common/utils";
const alertVariants = cva( const alertVariants = cva(
"relative w-full rounded-lg border p-4 [&>svg~*]:pl-7 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground", "relative w-full rounded-lg border p-4 [&>svg~*]:pl-7 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground",

@ -1,7 +1,7 @@
import * as React from "react"; import * as React from "react";
import { cva, type VariantProps } from "class-variance-authority"; import { cva, type VariantProps } from "class-variance-authority";
import { cn } from "@/app/lib/utils"; import { cn } from "@/app/common/utils";
const badgeVariants = cva( const badgeVariants = cva(
"inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2", "inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",

@ -2,7 +2,7 @@ import * as React from "react";
import { Slot } from "@radix-ui/react-slot"; import { Slot } from "@radix-ui/react-slot";
import { cva, type VariantProps } from "class-variance-authority"; import { cva, type VariantProps } from "class-variance-authority";
import { cn } from "@/app/lib/utils"; import { cn } from "@/app/common/utils";
const buttonVariants = cva( const buttonVariants = cva(
"inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50", "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",

@ -4,7 +4,7 @@ import * as React from "react";
import * as ContextMenuPrimitive from "@radix-ui/react-context-menu"; import * as ContextMenuPrimitive from "@radix-ui/react-context-menu";
import { Check, ChevronRight, Circle } from "lucide-react"; import { Check, ChevronRight, Circle } from "lucide-react";
import { cn } from "@/app/lib/utils"; import { cn } from "@/app/common/utils";
const ContextMenu = ContextMenuPrimitive.Root; const ContextMenu = ContextMenuPrimitive.Root;

@ -1,6 +1,6 @@
import * as React from "react"; import * as React from "react";
import { cn } from "@/app/lib/utils"; import { cn } from "@/app/common/utils";
export interface InputProps export interface InputProps
extends React.InputHTMLAttributes<HTMLInputElement> {} extends React.InputHTMLAttributes<HTMLInputElement> {}

@ -4,7 +4,7 @@ import * as LabelPrimitive from "@radix-ui/react-label";
import { cva, type VariantProps } from "class-variance-authority"; import { cva, type VariantProps } from "class-variance-authority";
import * as React from "react"; import * as React from "react";
import { cn } from "@/app/lib/utils"; import { cn } from "@/app/common/utils";
const labelVariants = cva( const labelVariants = cva(
"text-sm font-medium text-zinc-300 leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70" "text-sm font-medium text-zinc-300 leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"

@ -4,7 +4,7 @@ import * as React from "react";
import * as SelectPrimitive from "@radix-ui/react-select"; import * as SelectPrimitive from "@radix-ui/react-select";
import { Check, ChevronDown, ChevronUp } from "lucide-react"; import { Check, ChevronDown, ChevronUp } from "lucide-react";
import { cn } from "@/app/lib/utils"; import { cn } from "@/app/common/utils";
const Select = SelectPrimitive.Root; const Select = SelectPrimitive.Root;

@ -1,4 +1,4 @@
import { cn } from "@/app/lib/utils"; import { cn } from "@/app/common/utils";
function Skeleton({ function Skeleton({
className, className,

@ -5,7 +5,7 @@ import { cva, type VariantProps } from "class-variance-authority";
import { X } from "lucide-react"; import { X } from "lucide-react";
import * as React from "react"; import * as React from "react";
import { cn } from "@/app/lib/utils"; import { cn } from "@/app/common/utils";
const ToastProvider = ToastPrimitives.Provider; const ToastProvider = ToastPrimitives.Provider;

@ -3,7 +3,7 @@
import * as React from "react"; import * as React from "react";
import * as TooltipPrimitive from "@radix-ui/react-tooltip"; import * as TooltipPrimitive from "@radix-ui/react-tooltip";
import { cn } from "@/app/lib/utils"; import { cn } from "@/app/common/utils";
const TooltipProvider = TooltipPrimitive.Provider; const TooltipProvider = TooltipPrimitive.Provider;

@ -4,7 +4,7 @@ import { Toaster } from "@/components/ui/sonner";
import { TooltipProvider } from "@/components/ui/tooltip"; import { TooltipProvider } from "@/components/ui/tooltip";
import config from "@/config"; import config from "@/config";
import { notoSans } from "@/font/fonts"; import { notoSans } from "@/font/fonts";
import { cn } from "@/lib/utils"; import { cn } from "@/app/common/utils";
import type { Metadata, Viewport } from "next"; import type { Metadata, Viewport } from "next";
import PlausibleProvider from "next-plausible"; import PlausibleProvider from "next-plausible";
import { ReactElement, ReactNode } from "react"; import { ReactElement, ReactNode } from "react";

@ -1,6 +1,6 @@
import Creeper from "@/components/creeper"; import Creeper from "@/components/creeper";
import { minecrafter } from "@/font/fonts"; import { minecrafter } from "@/font/fonts";
import { cn } from "@/lib/utils"; import { cn } from "@/app/common/utils";
import { ReactElement } from "react"; import { ReactElement } from "react";
/** /**

41
Frontend/src/app/types/mdx.d.ts vendored Normal file

@ -0,0 +1,41 @@
/**
* Metadata for documentation content.
*/
type DocsContentMetadata = MDXMetadata & {
/**
* The title of this content.
*/
title: string;
/**
* The date this content was published.
*/
published: string;
/**
* The summary of this content.
*/
summary: string;
};
/**
* Metadata for an MDX file.
*/
type MDXMetadata = {
/**
* The slug of the file, defined once read.
*/
slug: string;
/**
* The metadata of the file.
*/
metadata: {
[key: string]: string;
};
/**
* The content of the file.
*/
content: string;
};

@ -0,0 +1,8 @@
---
title: 'option utinam malorum tempor sapien.'
published: '04-19-2024'
summary: 'utinam delicata nominavi ornare eirmod pharetra decore interesset necessitatibus.'
---
# bob
HELLO JOHN

@ -0,0 +1,8 @@
---
title: 'HOME YES.'
published: '04-19-2024'
summary: 'utinam delicata nominavi ornare eirmod pharetra decore interesset necessitatibus.'
---
# bob
HELLO JOHN

@ -0,0 +1,10 @@
import type { MDXComponents } from "mdx/types";
export const useMDXComponents = (components: MDXComponents): MDXComponents => {
return {
h1: ({ children }) => (
<h1 className="text-6xl font-semibold">{children}</h1>
),
...components,
};
};

@ -4,7 +4,7 @@ const { screens } = require("tailwindcss/defaultTheme");
const config = { const config = {
darkMode: ["class"], darkMode: ["class"],
content: ["./src/app/**/*.{ts,tsx}"], content: ["./src/app/**/*.{ts,tsx,mdx}"],
theme: { theme: {
container: { container: {
center: true, center: true,

@ -24,7 +24,8 @@
"@/provider/*": ["./src/app/provider/*"], "@/provider/*": ["./src/app/provider/*"],
"@/font/*": ["./src/app/font/*"], "@/font/*": ["./src/app/font/*"],
"@/types/*": ["./src/app/types/*"], "@/types/*": ["./src/app/types/*"],
"@/lib/*": ["./src/app/lib/*"], "@/lib/*": ["./src/app/common/*"],
"@/markdown/*": ["./src/markdown/*"],
"@/configJson": ["./config.json"] "@/configJson": ["./config.json"]
} }
}, },