code!
This commit is contained in:
parent
3588b5f93c
commit
c6259e3c8d
Binary file not shown.
@ -31,7 +31,7 @@
|
|||||||
},
|
},
|
||||||
"navbarLinks": {
|
"navbarLinks": {
|
||||||
"Player": "/player",
|
"Player": "/player",
|
||||||
"Server": "/player",
|
"Server": "/server",
|
||||||
"Mojang": "/mojang",
|
"Mojang": "/mojang",
|
||||||
"Docs": "/docs"
|
"Docs": "/docs"
|
||||||
},
|
},
|
||||||
|
@ -12,6 +12,8 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@heroicons/react": "^2.1.3",
|
"@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-slot": "^1.0.2",
|
||||||
"@radix-ui/react-tooltip": "^1.0.7",
|
"@radix-ui/react-tooltip": "^1.0.7",
|
||||||
"class-variance-authority": "^0.7.0",
|
"class-variance-authority": "^0.7.0",
|
||||||
@ -22,7 +24,8 @@
|
|||||||
"next-themes": "^0.3.0",
|
"next-themes": "^0.3.0",
|
||||||
"react": "^18",
|
"react": "^18",
|
||||||
"react-dom": "^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",
|
"tailwind-merge": "^2.2.2",
|
||||||
"tailwindcss-animate": "^1.0.7"
|
"tailwindcss-animate": "^1.0.7"
|
||||||
},
|
},
|
||||||
|
BIN
Frontend/public/media/players.webp
Normal file
BIN
Frontend/public/media/players.webp
Normal file
Binary file not shown.
After Width: | Height: | Size: 24 KiB |
@ -11,13 +11,16 @@ import Link from "next/link";
|
|||||||
const DocsPage = (): JSX.Element => (
|
const DocsPage = (): JSX.Element => (
|
||||||
<main className="h-[64vh] flex flex-col gap-3 justify-center items-center">
|
<main className="h-[64vh] flex flex-col gap-3 justify-center items-center">
|
||||||
{/* Creeper */}
|
{/* Creeper */}
|
||||||
<div className="absolute left-28 bottom-16">
|
<div className="absolute left-28 bottom-16 pointer-events-none">
|
||||||
<Creeper />
|
<Creeper />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
<h1
|
<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
|
Documentation
|
||||||
</h1>
|
</h1>
|
||||||
|
72
Frontend/src/app/(pages)/player/[[...slug]]/page.tsx
Normal file
72
Frontend/src/app/(pages)/player/[[...slug]]/page.tsx
Normal file
@ -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,
|
href,
|
||||||
}: FeaturedItemProps): JSX.Element => (
|
}: FeaturedItemProps): JSX.Element => (
|
||||||
<Link
|
<Link
|
||||||
className={cn(
|
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"
|
||||||
"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
|
|
||||||
)}
|
|
||||||
href={href}
|
href={href}
|
||||||
|
style={{
|
||||||
|
backgroundImage: `url(${image})`,
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<h1
|
<h1
|
||||||
className={cn("text-3xl font-semibold text-white", minecrafter.className)}
|
className={cn("text-3xl font-semibold text-white", minecrafter.className)}
|
||||||
|
@ -1,6 +1,21 @@
|
|||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { cn } from "@/lib/utils";
|
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.
|
* A Minecraft styled button.
|
||||||
*
|
*
|
||||||
@ -10,10 +25,8 @@ const MinecraftButton = ({
|
|||||||
className,
|
className,
|
||||||
children,
|
children,
|
||||||
...props
|
...props
|
||||||
}: Readonly<{
|
}: React.ButtonHTMLAttributes<HTMLButtonElement> &
|
||||||
className?: string;
|
MinecraftButtonProps): JSX.Element => (
|
||||||
children: React.ReactNode;
|
|
||||||
}>): JSX.Element => (
|
|
||||||
<Button
|
<Button
|
||||||
className={cn(
|
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
|
"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 GitHubStarCount from "@/components/github-star-count";
|
||||||
import MinecraftButton from "@/components/minecraft-button";
|
import MinecraftButton from "@/components/minecraft-button";
|
||||||
import { Skeleton } from "@/components/ui/skeleton";
|
import { Skeleton } from "@/components/ui/skeleton";
|
||||||
@ -7,6 +9,7 @@ import { cn } from "@/lib/utils";
|
|||||||
import { StarIcon } from "@heroicons/react/24/outline";
|
import { StarIcon } from "@heroicons/react/24/outline";
|
||||||
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 { Suspense } from "react";
|
import { Suspense } from "react";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -14,69 +17,79 @@ import { Suspense } from "react";
|
|||||||
*
|
*
|
||||||
* @returns the navbar jsx
|
* @returns the navbar jsx
|
||||||
*/
|
*/
|
||||||
const Navbar = (): JSX.Element => (
|
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">
|
const path: string = usePathname(); // Get the current path
|
||||||
{/* Left */}
|
return (
|
||||||
<div className="flex gap-7 lg:gap-12 items-center transition-all transform-gpu">
|
<nav className="fixed inset-x-0 flex h-16 px-12 justify-center sm:justify-between items-center bg-navbar-background z-50">
|
||||||
{/* App Branding */}
|
{/* Left */}
|
||||||
<Link
|
<div className="flex gap-7 lg:gap-12 items-center transition-all transform-gpu">
|
||||||
className={cn(
|
{/* App Branding */}
|
||||||
"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">
|
|
||||||
<Link
|
<Link
|
||||||
className="flex gap-1.5 items-center"
|
className={cn(
|
||||||
href="https://github.com/Rainnny7/RESTfulMC"
|
"text-3xl text-minecraft-green-3 hover:opacity-85 transition-all transform-gpu",
|
||||||
rel="noopener noreferrer"
|
minecrafter.className
|
||||||
target="_blank"
|
)}
|
||||||
|
href="/"
|
||||||
>
|
>
|
||||||
{/* Star Count */}
|
{/* Small Screens */}
|
||||||
<Suspense fallback={<Skeleton className="w-4 h-5 rounded-md" />}>
|
<Image
|
||||||
<GitHubStarCount />
|
className="hidden sm:flex lg:hidden"
|
||||||
</Suspense>
|
src="/media/logo.webp"
|
||||||
|
alt="Site Logo"
|
||||||
<StarIcon
|
width={42}
|
||||||
className="group-hover/star:text-orange-400 delay-0 transition-all transform-gpu"
|
height={42}
|
||||||
width={22}
|
|
||||||
height={22}
|
|
||||||
/>
|
/>
|
||||||
<span>Star on GitHub</span>
|
|
||||||
|
{/* Large Screens */}
|
||||||
|
<span className="hidden lg:flex">{config.siteName}</span>
|
||||||
</Link>
|
</Link>
|
||||||
</MinecraftButton>
|
|
||||||
</div>
|
{/* Links */}
|
||||||
</nav>
|
<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;
|
export default Navbar;
|
||||||
|
31
Frontend/src/app/components/player/player-search.tsx
Normal file
31
Frontend/src/app/components/player/player-search.tsx
Normal file
@ -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;
|
25
Frontend/src/app/components/ui/input.tsx
Normal file
25
Frontend/src/app/components/ui/input.tsx
Normal file
@ -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
|
* @returns the page jsx
|
||||||
*/
|
*/
|
||||||
const NotFoundPage = (): JSX.Element => (
|
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 */}
|
||||||
<Creeper />
|
<Creeper />
|
||||||
|
|
||||||
|
7
Frontend/src/app/types/page.d.ts
vendored
Normal file
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",
|
"name": "restfulmc-lib",
|
||||||
"version": "1.0.8",
|
"version": "1.0.9",
|
||||||
"author": "Braydon (Rainnny) <braydonrainnny@gmail.com>",
|
"author": "Braydon (Rainnny) <braydonrainnny@gmail.com>",
|
||||||
"description": "A simple, yet useful RESTful API for Minecraft utilizing Springboot.",
|
"description": "A simple, yet useful RESTful API for Minecraft utilizing Springboot.",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
|
Loading…
x
Reference in New Issue
Block a user