code!
This commit is contained in:
parent
3588b5f93c
commit
c6259e3c8d
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"
|
||||
},
|
||||
|
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 => (
|
||||
<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>
|
||||
|
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,
|
||||
}: 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;
|
||||
|
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
|
||||
*/
|
||||
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
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": [
|
||||
|
Loading…
Reference in New Issue
Block a user