This commit is contained in:
Braydon 2024-04-16 16:40:25 -04:00
parent 3588b5f93c
commit c6259e3c8d
15 changed files with 242 additions and 76 deletions

Binary file not shown.

@ -31,7 +31,7 @@
},
"navbarLinks": {
"Player": "/player",
"Server": "/player",
"Server": "/server",
"Mojang": "/mojang",
"Docs": "/docs"
},

@ -12,6 +12,8 @@
},
"dependencies": {
"@heroicons/react": "^2.1.3",
"@hookform/resolvers": "^3.3.4",
"@radix-ui/react-label": "^2.0.2",
"@radix-ui/react-slot": "^1.0.2",
"@radix-ui/react-tooltip": "^1.0.7",
"class-variance-authority": "^0.7.0",
@ -22,7 +24,8 @@
"next-themes": "^0.3.0",
"react": "^18",
"react-dom": "^18",
"restfulmc-lib": "^1.0.7",
"react-hook-form": "^7.51.3",
"restfulmc-lib": "^1.0.9",
"tailwind-merge": "^2.2.2",
"tailwindcss-animate": "^1.0.7"
},

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

@ -11,13 +11,16 @@ import Link from "next/link";
const DocsPage = (): JSX.Element => (
<main className="h-[64vh] flex flex-col gap-3 justify-center items-center">
{/* Creeper */}
<div className="absolute left-28 bottom-16">
<div className="absolute left-28 bottom-16 pointer-events-none">
<Creeper />
</div>
{/* Header */}
<h1
className={cn("text-6xl text-minecraft-green-3", minecrafter.className)}
className={cn(
"text-6xl text-minecraft-green-3 pointer-events-none",
minecrafter.className
)}
>
Documentation
</h1>

@ -0,0 +1,72 @@
import PlayerSearch from "@/components/player/player-search";
import { minecrafter } from "@/font/fonts";
import { cn } from "@/lib/utils";
import { PageProps } from "@/types/page";
import { Metadata } from "next";
import Image from "next/image";
import { CachedPlayer, getPlayer, type RestfulMCAPIError } from "restfulmc-lib";
/**
* The page to lookup a player.
*
* @returns the page jsx
*/
const PlayerPage = async ({ params }: PageProps): Promise<JSX.Element> => {
let error: string | undefined = undefined; // The error to display
let result: CachedPlayer | undefined = undefined; // The player to display
const query: string | undefined = params.slug; // The query to search for
try {
result = params.slug ? await getPlayer(query) : undefined; // Get the player to display
} catch (err) {
error = (err as RestfulMCAPIError).message; // Set the error message
}
// Render the page
return (
<main className="h-screen flex flex-col justify-center items-center">
<div className="flex gap-32">
{/* Header */}
<Image
className="pointer-events-none"
src="/media/players.webp"
alt="Minecraft Players"
width={632}
height={632}
/>
<div className="flex flex-col gap-7">
<h1
className={cn(
"mt-20 text-6xl text-minecraft-green-3 pointer-events-none",
minecrafter.className
)}
>
Player Lookup
</h1>
{/* Error */}
{error && <p className="text-red-500">{error}</p>}
{/* Search */}
<PlayerSearch query={query} />
</div>
</div>
</main>
);
};
/**
* Generate metadata for this page.
*
* @param params the route params
* @param searchParams the search params
* @returns the generated metadata
*/
const generateMetadata = async ({ params }: PageProps): Promise<Metadata> => {
console.log("params", params);
return {
title: "bob ross",
};
};
export default PlayerPage;

@ -32,11 +32,11 @@ const FeaturedItem = ({
href,
}: FeaturedItemProps): JSX.Element => (
<Link
className={cn(
"pt-28 w-[19rem] h-80 flex flex-col gap-1 items-center rounded-3xl text-center backdrop-blur-md hover:scale-[1.01] transition-all transform-gpu",
"bg-[url('" + image + "')] bg-center bg-cover bg-no-repeat" // Couldn't do inline variable interpolation, it threw an error
)}
className="pt-28 w-[19rem] h-80 flex flex-col gap-1 items-center bg-center bg-cover bg-no-repeat rounded-3xl text-center backdrop-blur-md hover:scale-[1.01] transition-all transform-gpu"
href={href}
style={{
backgroundImage: `url(${image})`,
}}
>
<h1
className={cn("text-3xl font-semibold text-white", minecrafter.className)}

@ -1,6 +1,21 @@
import { Button } from "@/components/ui/button";
import { cn } from "@/lib/utils";
/**
* Props for this button.
*/
type MinecraftButtonProps = {
/**
* The class name to apply to this button.
*/
className?: string;
/**
* The children of this button.
*/
children: React.ReactNode;
};
/**
* A Minecraft styled button.
*
@ -10,10 +25,8 @@ const MinecraftButton = ({
className,
children,
...props
}: Readonly<{
className?: string;
children: React.ReactNode;
}>): JSX.Element => (
}: React.ButtonHTMLAttributes<HTMLButtonElement> &
MinecraftButtonProps): JSX.Element => (
<Button
className={cn(
"before:absolute before:-inset-x-5 before:rotate-90 before:w-9 before:h-1 before:bg-minecraft-green-1", // Left Green Bar

@ -1,3 +1,5 @@
"use client";
import GitHubStarCount from "@/components/github-star-count";
import MinecraftButton from "@/components/minecraft-button";
import { Skeleton } from "@/components/ui/skeleton";
@ -7,6 +9,7 @@ import { cn } from "@/lib/utils";
import { StarIcon } from "@heroicons/react/24/outline";
import Image from "next/image";
import Link from "next/link";
import { usePathname } from "next/navigation";
import { Suspense } from "react";
/**
@ -14,69 +17,79 @@ import { Suspense } from "react";
*
* @returns the navbar jsx
*/
const Navbar = (): JSX.Element => (
<nav className="fixed inset-x-0 flex h-16 px-12 justify-center sm:justify-between items-center bg-navbar-background z-50">
{/* Left */}
<div className="flex gap-7 lg:gap-12 items-center transition-all transform-gpu">
{/* App Branding */}
<Link
className={cn(
"text-3xl text-minecraft-green-3 hover:opacity-85 transition-all transform-gpu",
minecrafter.className
)}
href="/"
>
{/* Small Screens */}
<Image
className="hidden sm:flex lg:hidden"
src="/media/logo.webp"
alt="Site Logo"
width={42}
height={42}
/>
{/* Large Screens */}
<span className="hidden lg:flex">{config.siteName}</span>
</Link>
{/* Links */}
<div className="flex gap-7">
{Object.entries(config.navbarLinks).map((link, index) => (
<Link
key={index}
className="font-semibold uppercase hover:text-minecraft-green-4 transition-all transform-gpu"
href={link[1]}
>
{link[0]}
</Link>
))}
</div>
</div>
{/* Social Buttons */}
<div className="hidden md:flex">
{/* Star on Github <3 */}
<MinecraftButton className="group/star">
const Navbar = (): JSX.Element => {
const path: string = usePathname(); // Get the current path
return (
<nav className="fixed inset-x-0 flex h-16 px-12 justify-center sm:justify-between items-center bg-navbar-background z-50">
{/* Left */}
<div className="flex gap-7 lg:gap-12 items-center transition-all transform-gpu">
{/* App Branding */}
<Link
className="flex gap-1.5 items-center"
href="https://github.com/Rainnny7/RESTfulMC"
rel="noopener noreferrer"
target="_blank"
className={cn(
"text-3xl text-minecraft-green-3 hover:opacity-85 transition-all transform-gpu",
minecrafter.className
)}
href="/"
>
{/* Star Count */}
<Suspense fallback={<Skeleton className="w-4 h-5 rounded-md" />}>
<GitHubStarCount />
</Suspense>
<StarIcon
className="group-hover/star:text-orange-400 delay-0 transition-all transform-gpu"
width={22}
height={22}
{/* Small Screens */}
<Image
className="hidden sm:flex lg:hidden"
src="/media/logo.webp"
alt="Site Logo"
width={42}
height={42}
/>
<span>Star on GitHub</span>
{/* Large Screens */}
<span className="hidden lg:flex">{config.siteName}</span>
</Link>
</MinecraftButton>
</div>
</nav>
);
{/* Links */}
<div className="flex gap-7">
{Object.entries(config.navbarLinks).map((link, index) => {
const url: string = link[1]; // The href of the link
let active: boolean = path.startsWith(url); // Is this the active link?
return (
<Link
key={index}
className={cn(
"font-semibold uppercase hover:text-minecraft-green-4 transition-all transform-gpu",
active && "text-minecraft-green-4"
)}
href={url}
>
{link[0]}
</Link>
);
})}
</div>
</div>
{/* Social Buttons */}
<div className="hidden md:flex">
{/* Star on Github <3 */}
<MinecraftButton className="group/star">
<Link
className="flex gap-1.5 items-center"
href="https://github.com/Rainnny7/RESTfulMC"
rel="noopener noreferrer"
target="_blank"
>
{/* Star Count */}
<Suspense fallback={<Skeleton className="w-4 h-5 rounded-md" />}>
<GitHubStarCount />
</Suspense>
<StarIcon
className="group-hover/star:text-orange-400 delay-0 transition-all transform-gpu"
width={22}
height={22}
/>
<span>Star on GitHub</span>
</Link>
</MinecraftButton>
</div>
</nav>
);
};
export default Navbar;

@ -0,0 +1,31 @@
import MinecraftButton from "@/components/minecraft-button";
import { Input } from "@/components/ui/input";
import { redirect } from "next/navigation";
/**
* A component for searching for a player.
*
* @param query the query to search for
* @returns the search component jsx
*/
const PlayerSearch = ({
query,
}: {
query: string | undefined;
}): JSX.Element => {
const handleRedirect = async (form: FormData) => {
"use server";
redirect(`/player/${form.get("query")}`);
};
return (
<form
className="flex flex-col gap-7 justify-center items-center"
action={handleRedirect}
>
<Input name="query" placeholder="Username / UUID" defaultValue={query} />
<MinecraftButton type="submit">Search</MinecraftButton>
</form>
);
};
export default PlayerSearch;

@ -0,0 +1,25 @@
import * as React from "react"
import { cn } from "@/app/lib/utils"
export interface InputProps
extends React.InputHTMLAttributes<HTMLInputElement> {}
const Input = React.forwardRef<HTMLInputElement, InputProps>(
({ className, type, ...props }, ref) => {
return (
<input
type={type}
className={cn(
"flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
className
)}
ref={ref}
{...props}
/>
)
}
)
Input.displayName = "Input"
export { Input }

@ -8,7 +8,7 @@ import { cn } from "@/lib/utils";
* @returns the page jsx
*/
const NotFoundPage = (): JSX.Element => (
<main className="h-[84vh] flex flex-col gap-3 justify-center items-center">
<main className="h-[84vh] flex flex-col gap-3 justify-center items-center pointer-events-none">
{/* Creeper */}
<Creeper />

7
Frontend/src/app/types/page.d.ts vendored Normal file

@ -0,0 +1,7 @@
/**
* Props for a page.
*/
export type PageProps = {
params: { slug: string };
searchParams: { [key: string]: string | string[] | undefined };
};

@ -1 +0,0 @@
//registry.npmjs.org/:_authToken=${NPM_TOKEN}

@ -1,6 +1,6 @@
{
"name": "restfulmc-lib",
"version": "1.0.8",
"version": "1.0.9",
"author": "Braydon (Rainnny) <braydonrainnny@gmail.com>",
"description": "A simple, yet useful RESTful API for Minecraft utilizing Springboot.",
"keywords": [