recode most things - still wip
All checks were successful
Deploy App / docker (ubuntu-latest) (push) Successful in 2m0s
All checks were successful
Deploy App / docker (ubuntu-latest) (push) Successful in 2m0s
This commit is contained in:
parent
c054a31008
commit
59acc3a7db
46
src/app/player/[id]/page.tsx
Normal file
46
src/app/player/[id]/page.tsx
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
import { NotFound } from "@/components/not-found";
|
||||||
|
import { Card } from "@/components/ui/card";
|
||||||
|
import { getPlayer } from "mcutils-library";
|
||||||
|
import { Player } from "mcutils-library/dist/types/player/player";
|
||||||
|
import { Metadata } from "next";
|
||||||
|
|
||||||
|
export const metadata: Metadata = {
|
||||||
|
title: "Lookup Player",
|
||||||
|
};
|
||||||
|
|
||||||
|
async function getData(id: string): Promise<Player | null> {
|
||||||
|
try {
|
||||||
|
const cachedPlayer = await getPlayer(id);
|
||||||
|
return cachedPlayer.player;
|
||||||
|
} catch (error) {
|
||||||
|
return null; // Player not found
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Params = {
|
||||||
|
params: {
|
||||||
|
id: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default async function Page({ params }: Params) {
|
||||||
|
const player = await getData(params.id);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="h-full flex flex-col items-center">
|
||||||
|
<div className="mb-4 text-center">
|
||||||
|
<h1 className="text-xl">Lookup a Player</h1>
|
||||||
|
<p>You can enter a players uuid or username to get information about the player.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Card>
|
||||||
|
{player == null && <NotFound message="Player not found" />}
|
||||||
|
{player != null && (
|
||||||
|
<div className="flex flex-col items-center gap-2">
|
||||||
|
<p>Username: {player.username}</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
@ -1,18 +0,0 @@
|
|||||||
import PlayerSearch from "@/components/player-search";
|
|
||||||
import { Metadata } from "next";
|
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
|
||||||
title: "Lookup Player",
|
|
||||||
};
|
|
||||||
|
|
||||||
export default function Player() {
|
|
||||||
return (
|
|
||||||
<div className="h-full flex flex-col items-center">
|
|
||||||
<div className="mb-4 text-center">
|
|
||||||
<h1 className="text-xl">Lookup a Player</h1>
|
|
||||||
<p>You can enter a players uuid or username to get information about the player.</p>
|
|
||||||
</div>
|
|
||||||
<PlayerSearch />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
88
src/app/server/[platform]/[hostname]/page.tsx
Normal file
88
src/app/server/[platform]/[hostname]/page.tsx
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
import { capitalizeFirstLetter } from "@/common/string-utils";
|
||||||
|
import { LookupServer } from "@/components/lookup-server";
|
||||||
|
import { NotFound } from "@/components/not-found";
|
||||||
|
import { Card } from "@/components/ui/card";
|
||||||
|
import { getServer } from "mcutils-library";
|
||||||
|
import JavaMinecraftServer from "mcutils-library/dist/types/server/javaServer";
|
||||||
|
import { ServerPlatform } from "mcutils-library/dist/types/server/platform";
|
||||||
|
import { MinecraftServer } from "mcutils-library/dist/types/server/server";
|
||||||
|
import { Metadata } from "next";
|
||||||
|
|
||||||
|
type Params = {
|
||||||
|
params: {
|
||||||
|
platform: ServerPlatform;
|
||||||
|
hostname: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export async function generateMetadata({ params: { platform, hostname } }: Params): Promise<Metadata> {
|
||||||
|
const server = await getData(platform, hostname);
|
||||||
|
if (!server) {
|
||||||
|
return {
|
||||||
|
title: "Unknown Server",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const { hostname: serverHostname, players } = server;
|
||||||
|
let favicon = null;
|
||||||
|
|
||||||
|
if (platform === ServerPlatform.Java) {
|
||||||
|
const javaServer = server as JavaMinecraftServer;
|
||||||
|
favicon = javaServer.favicon && javaServer.favicon.url;
|
||||||
|
}
|
||||||
|
|
||||||
|
const description = `
|
||||||
|
${capitalizeFirstLetter(platform)} Server
|
||||||
|
Hostname: ${serverHostname}
|
||||||
|
${players.online}/${players.max} players online`;
|
||||||
|
|
||||||
|
return {
|
||||||
|
title: `${hostname}`,
|
||||||
|
openGraph: {
|
||||||
|
title: `${hostname}`,
|
||||||
|
description: description,
|
||||||
|
images: [
|
||||||
|
{
|
||||||
|
url: favicon || "",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
twitter: {
|
||||||
|
card: "summary",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getData(platform: ServerPlatform, id: string): Promise<MinecraftServer | null> {
|
||||||
|
console.log(platform, id);
|
||||||
|
try {
|
||||||
|
const cachedServer = await getServer(platform, id);
|
||||||
|
return cachedServer.server;
|
||||||
|
} catch (error) {
|
||||||
|
return null; // Server not found
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default async function Page({ params: { platform, hostname } }: Params) {
|
||||||
|
const server = await getData(platform, hostname);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="h-full flex flex-col items-center">
|
||||||
|
<div className="mb-4 text-center">
|
||||||
|
<h1 className="text-xl">Lookup a Server</h1>
|
||||||
|
<p>You can enter a server hostname to get information about the server.</p>
|
||||||
|
|
||||||
|
<LookupServer />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Card>
|
||||||
|
{server == null && <NotFound message="Server not found" />}
|
||||||
|
{server != null && (
|
||||||
|
<div className="flex flex-col items-center gap-2">
|
||||||
|
<p>Hostname: {server.hostname}</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
@ -1,18 +0,0 @@
|
|||||||
import ServerSearch from "@/components/server-search";
|
|
||||||
import { Metadata } from "next";
|
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
|
||||||
title: "Lookup Server",
|
|
||||||
};
|
|
||||||
|
|
||||||
export default function Server() {
|
|
||||||
return (
|
|
||||||
<div className="h-full flex flex-col items-center">
|
|
||||||
<div className="mb-4 text-center">
|
|
||||||
<h1 className="text-xl">Lookup a Server</h1>
|
|
||||||
<p>You can enter a server ip or domain to get information about the server.</p>
|
|
||||||
</div>
|
|
||||||
<ServerSearch />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
9
src/common/string-utils.ts
Normal file
9
src/common/string-utils.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
/**
|
||||||
|
* Capitalizes the first letter of a string
|
||||||
|
*
|
||||||
|
* @param str the string to change
|
||||||
|
* @returns the updated string
|
||||||
|
*/
|
||||||
|
export function capitalizeFirstLetter(str: string) {
|
||||||
|
return str.charAt(0).toUpperCase() + str.slice(1);
|
||||||
|
}
|
9
src/components/loading-card.tsx
Normal file
9
src/components/loading-card.tsx
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import { Card } from "./ui/card";
|
||||||
|
|
||||||
|
export function LoadingCard() {
|
||||||
|
return (
|
||||||
|
<Card>
|
||||||
|
<p>Loading...</p>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
}
|
38
src/components/lookup-server.tsx
Normal file
38
src/components/lookup-server.tsx
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { ServerPlatform } from "mcutils-library/dist/types/server/platform";
|
||||||
|
import { useRouter } from "next/navigation";
|
||||||
|
import { useState } from "react";
|
||||||
|
import { Button } from "./ui/button";
|
||||||
|
import { Input } from "./ui/input";
|
||||||
|
|
||||||
|
export function LookupServer() {
|
||||||
|
const router = useRouter();
|
||||||
|
const [hostname, setHostname] = useState("");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the hostname value
|
||||||
|
*
|
||||||
|
* @param event the input event
|
||||||
|
*/
|
||||||
|
const setHostnameValue = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
setHostname(event.target.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lookup a server based on the platform
|
||||||
|
*
|
||||||
|
* @param platform the server platform
|
||||||
|
*/
|
||||||
|
const lookupServer = (platform: ServerPlatform) => {
|
||||||
|
router.push(`/server/${platform}/${hostname}`);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex gap-2 justify-center mt-2">
|
||||||
|
<Input className="w-fit" placeholder="Server hostname" value={hostname} onChange={setHostnameValue} />
|
||||||
|
<Button onClick={() => lookupServer(ServerPlatform.Java)}>Java</Button>
|
||||||
|
<Button onClick={() => lookupServer(ServerPlatform.Bedrock)}>Bedrock</Button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
@ -7,8 +7,8 @@ type Page = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const pages: Page[] = [
|
const pages: Page[] = [
|
||||||
{ title: "Player", url: "/player" },
|
{ title: "Player", url: "/player/Notch" },
|
||||||
{ title: "Server", url: "/server" },
|
{ title: "Server", url: "/server/java/hypixel.net" },
|
||||||
];
|
];
|
||||||
|
|
||||||
export default function NavBar() {
|
export default function NavBar() {
|
||||||
|
12
src/components/not-found.tsx
Normal file
12
src/components/not-found.tsx
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
type NotFoundProps = {
|
||||||
|
message: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function NotFound({ message }: NotFoundProps) {
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col justify-center text-center">
|
||||||
|
<h1 className="text-xl text-red-400">Not Found</h1>
|
||||||
|
<p>{message}</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
@ -1,87 +0,0 @@
|
|||||||
"use client";
|
|
||||||
|
|
||||||
import { getPlayer } from "mcutils-library";
|
|
||||||
import { Player } from "mcutils-library/dist/types/player/player";
|
|
||||||
import Image from "next/image";
|
|
||||||
import Link from "next/link";
|
|
||||||
import { useState } from "react";
|
|
||||||
import { toast } from "react-toastify";
|
|
||||||
import { Button } from "./ui/button";
|
|
||||||
import { Card } from "./ui/card";
|
|
||||||
import { Input } from "./ui/input";
|
|
||||||
|
|
||||||
const defaultPlayerId = "Notch";
|
|
||||||
|
|
||||||
export default function PlayerSearch() {
|
|
||||||
const [playerId, setPlayerId] = useState<string>(defaultPlayerId);
|
|
||||||
const [player, setPlayer] = useState<Player | null>(null);
|
|
||||||
|
|
||||||
const handleLookup = async () => {
|
|
||||||
if (playerId === null || playerId.length <= 0) {
|
|
||||||
toast.error("Please enter a player ID");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
const cachedPlayer = await getPlayer(playerId);
|
|
||||||
const { player } = cachedPlayer;
|
|
||||||
|
|
||||||
setPlayer(player);
|
|
||||||
} catch (error) {
|
|
||||||
toast.error("Unknown player");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleKeyDown = (e: any) => {
|
|
||||||
if (e.key === "Enter") {
|
|
||||||
handleLookup();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="flex flex-col items-center gap-8">
|
|
||||||
<div className="flex items-center gap-2">
|
|
||||||
<Input
|
|
||||||
className="w-[200px]"
|
|
||||||
placeholder="Player ID"
|
|
||||||
defaultValue={defaultPlayerId}
|
|
||||||
onChange={(e) => setPlayerId(e.target.value)}
|
|
||||||
onKeyDown={handleKeyDown}
|
|
||||||
/>
|
|
||||||
<Button onClick={() => handleLookup()}>Lookup</Button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{player && (
|
|
||||||
<Card>
|
|
||||||
<div className="w-full flex flex-col md:flex-row gap-2">
|
|
||||||
<div className="flex justify-center">
|
|
||||||
<Image src={player.skin.parts.head} alt="The player's Head" width={150} height={150} />
|
|
||||||
</div>
|
|
||||||
<div className="flex flex-col gap-1 mt-2">
|
|
||||||
<p>
|
|
||||||
UUID: <span className="font-bold">{player.uniqueId}</span>
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
Name: <span className="font-bold">{player.username}</span>
|
|
||||||
</p>
|
|
||||||
<div className="mt-2">
|
|
||||||
<p>Skin Parts</p>
|
|
||||||
<div className="flex gap-2">
|
|
||||||
{Object.keys(player.skin.parts).map((part: any, index: number) => {
|
|
||||||
return (
|
|
||||||
<p key={index}>
|
|
||||||
<Link className="text-primary" href={player.skin.parts[part]} target="_blank">
|
|
||||||
{part}
|
|
||||||
</Link>
|
|
||||||
</p>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</Card>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,82 +0,0 @@
|
|||||||
"use client";
|
|
||||||
|
|
||||||
import { cn } from "@/common/utils";
|
|
||||||
import { getServer } from "mcutils-library";
|
|
||||||
import JavaMinecraftServer from "mcutils-library/dist/types/server/javaServer";
|
|
||||||
import { ServerPlatform } from "mcutils-library/dist/types/server/platform";
|
|
||||||
import Image from "next/image";
|
|
||||||
import { useState } from "react";
|
|
||||||
import { toast } from "react-toastify";
|
|
||||||
import { Button } from "./ui/button";
|
|
||||||
import { Card } from "./ui/card";
|
|
||||||
import { Input } from "./ui/input";
|
|
||||||
|
|
||||||
const defaultServerHostname = "play.hypixel.net";
|
|
||||||
|
|
||||||
export default function ServerSearch() {
|
|
||||||
const [serverHostname, setServerHostname] = useState<string>(defaultServerHostname);
|
|
||||||
const [server, setServer] = useState<JavaMinecraftServer | null>(null);
|
|
||||||
|
|
||||||
const handleLookup = async () => {
|
|
||||||
if (serverHostname === null || serverHostname.length <= 0) {
|
|
||||||
toast.error("Please enter a server hostname");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
const cachedServer = await getServer(ServerPlatform.Java, serverHostname);
|
|
||||||
const { server } = cachedServer;
|
|
||||||
setServer(server as JavaMinecraftServer);
|
|
||||||
} catch (error) {
|
|
||||||
toast.error("Unknown server");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleKeyDown = (e: any) => {
|
|
||||||
if (e.key === "Enter") {
|
|
||||||
handleLookup();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="flex flex-col items-center gap-8">
|
|
||||||
<div className="flex items-center gap-2">
|
|
||||||
<Input
|
|
||||||
className="w-[200px]"
|
|
||||||
placeholder="Server Domain or IP"
|
|
||||||
defaultValue={defaultServerHostname}
|
|
||||||
onChange={(e) => setServerHostname(e.target.value)}
|
|
||||||
onKeyDown={handleKeyDown}
|
|
||||||
/>
|
|
||||||
<Button onClick={() => handleLookup()}>Lookup</Button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{server && (
|
|
||||||
<Card>
|
|
||||||
<div className="w-full flex flex-col gap-2">
|
|
||||||
<div className="flex flex-col md:flex-row gap-2">
|
|
||||||
<div className="flex justify-center">
|
|
||||||
<Image src={server.favicon.url} alt="The server's Favicon" width={64} height={64} />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className={cn("flex flex-col gap-2")}>
|
|
||||||
{server.motd.html.map((line, index) => {
|
|
||||||
return <div key={index} dangerouslySetInnerHTML={{ __html: line }} />;
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex flex-col gap-1">
|
|
||||||
<div>
|
|
||||||
<span className="font-bold">Host:</span> {server.hostname}
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<span className="font-bold">Players:</span> {server.players.online}/{server.players.max}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</Card>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
@ -3,5 +3,5 @@ export function Card({
|
|||||||
}: Readonly<{
|
}: Readonly<{
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
}>) {
|
}>) {
|
||||||
return <div className="bg-secondary rounded-lg p-4 w-full">{children}</div>;
|
return <div className="bg-secondary rounded-lg p-4">{children}</div>;
|
||||||
}
|
}
|
||||||
|
@ -1 +0,0 @@
|
|||||||
export const API_ENDPOINT = "https://api.mcutils.xyz";
|
|
Loading…
Reference in New Issue
Block a user