From 724c301a709c85dd58176ac51ed072eaf57c090e Mon Sep 17 00:00:00 2001 From: dvelo <52332868+DeveloLongScript@users.noreply.github.com> Date: Sat, 3 Aug 2024 09:51:45 -0500 Subject: [PATCH] new release: 0.6 --- README.md | 2 +- package.json | 3 + src/allTags.ts | 4 +- src/app/globals.css | 5 + src/app/layout.tsx | 13 +- src/components/CommandBar.tsx | 335 ++++++++++++++++++ src/components/FavoritesView.tsx | 43 +-- src/components/HistoricalView.tsx | 0 src/components/NewChart.tsx | 30 +- src/components/ServerCard.tsx | 27 +- src/components/ServerList.tsx | 89 +---- src/components/ServerView.tsx | 183 +++------- src/components/Stat.tsx | 3 + src/components/clerk/LoggedInPopover.tsx | 4 +- src/components/clerk/SignInPopoverButton.tsx | 4 +- src/components/clerk/Topbar.tsx | 54 ++- src/components/effects/border-beam.tsx | 49 +++ src/components/misc/InfoPopover.tsx | 12 +- src/components/misc/TabServer.tsx | 6 +- src/components/ui/loading-button.tsx | 81 +++++ src/lib/api.ts | 175 +++++++++ src/lib/commandEvent.ts | 23 ++ src/lib/list.ts | 25 +- .../{miniMessage2HTML.ts => motdEngine.ts} | 5 +- src/lib/single.ts | 8 +- src/lib/top-loader.tsx | 21 ++ src/lib/types/server.ts | 81 +++++ src/lib/useRouter.tsx | 32 ++ src/pages/api/inngest.ts | 10 +- src/pages/api/isAuthenticating.ts | 8 - .../[server]/community-favorites.ts} | 8 +- .../favorites/[server]/favorite-server.ts} | 10 +- .../favorites/[server]/favorited.ts} | 10 +- .../favorites/account-favorites.ts} | 8 +- .../history/[server]/get-historical-data.ts} | 4 +- .../history/[server]/get-short-term-data.ts} | 4 +- .../history/meta-short-term-data.ts} | 0 src/pages/api/{getMOTD.ts => v1/motd.ts} | 4 +- src/pages/api/{ => v1}/status.ts | 0 src/version.tsx | 14 +- tailwind.config.ts | 8 + yarn.lock | 18 + 42 files changed, 1043 insertions(+), 380 deletions(-) create mode 100644 src/components/CommandBar.tsx delete mode 100644 src/components/HistoricalView.tsx create mode 100644 src/components/effects/border-beam.tsx create mode 100644 src/components/ui/loading-button.tsx create mode 100644 src/lib/api.ts create mode 100644 src/lib/commandEvent.ts rename src/lib/{miniMessage2HTML.ts => motdEngine.ts} (98%) create mode 100644 src/lib/top-loader.tsx create mode 100644 src/lib/types/server.ts create mode 100644 src/lib/useRouter.tsx delete mode 100644 src/pages/api/isAuthenticating.ts rename src/pages/api/{favorites/getCommunityNum.ts => v0/favorites/[server]/community-favorites.ts} (86%) rename src/pages/api/{favorites/favoriteServer.ts => v0/favorites/[server]/favorite-server.ts} (85%) rename src/pages/api/{favorites/isFavorited.ts => v0/favorites/[server]/favorited.ts} (73%) rename src/pages/api/{favorites/getAllFavorites.ts => v0/favorites/account-favorites.ts} (78%) rename src/pages/api/{history/getHistoricalData.ts => v0/history/[server]/get-historical-data.ts} (90%) rename src/pages/api/{history/getShortTermData.ts => v0/history/[server]/get-short-term-data.ts} (90%) rename src/pages/api/{history/getMetaShortTermData.ts => v0/history/meta-short-term-data.ts} (100%) rename src/pages/api/{getMOTD.ts => v1/motd.ts} (92%) rename src/pages/api/{ => v1}/status.ts (100%) diff --git a/README.md b/README.md index b9a4e54..c2b0ac2 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ Clone the repo! First, you must supply the following services with API keys: -- [Clerk](https://clerk.com): Create an app and put the respective keys in `.env.local`. Also, add `IS_AUTH=true`. +- [Clerk](https://clerk.com): Create an app and put the respective keys in `.env.local` - MongoDB: Create a database, can be anywhere, and put the location to connect in `.env.local` for the key `MONGO_DB` (this isn't required by any means, but if you want to store any short term or historical data, use this.) - Inngest: Inngest is a smaller library, but runs the `cron` jobs which will make servers automaticly get added to the database. diff --git a/package.json b/package.json index 5d93cdb..2424cef 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,7 @@ "@radix-ui/react-slot": "^1.0.2", "@radix-ui/react-tabs": "^1.1.0", "@radix-ui/react-tooltip": "^1.0.7", + "@types/nprogress": "^0.2.3", "@types/react-twemoji": "^0.4.3", "@unocss/eslint-plugin": "^0.61.5", "@unocss/postcss": "^0.61.5", @@ -47,6 +48,8 @@ "next": "14.2.3", "next-css-obfuscator": "^2.2.16", "next-themes": "^0.3.0", + "nextjs-toploader": "^1.6.12", + "nprogress": "^0.2.0", "postcss-obfuscator": "^1.6.1", "prettier": "^3.3.1", "react": "^18", diff --git a/src/allTags.ts b/src/allTags.ts index 6b928db..a642419 100644 --- a/src/allTags.ts +++ b/src/allTags.ts @@ -1,4 +1,4 @@ -import { OnlineServer, ServerResponse } from "./components/ServerView"; +import { OnlineServer, ServerResponse } from "./lib/types/server"; const serverCache: any = {}; @@ -262,7 +262,7 @@ export var allCategories: Array<{ async function requestServer(s: OnlineServer): Promise { if (serverCache[s.name] == undefined) { const re = await fetch( - "https://api.minehut.com/server/" + s.name + "?byName=true", + "https://api.minehut.com/server/" + s.name + "?byName=true" ); const json = await re.json(); serverCache[s.name] = json.server; diff --git a/src/app/globals.css b/src/app/globals.css index 33059bd..a99c7ac 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -95,6 +95,11 @@ } } +.backdrop-blur { + -webkit-backdrop-filter: blur(8px)!important; + backdrop-filter: blur(8px)!important; +} + /* width */ ::-webkit-scrollbar { width: 10px; diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 32b4ba0..fe56663 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -1,6 +1,6 @@ import type { Metadata } from "next"; import { GeistSans } from "geist/font/sans"; -import { Github, CodeXml, Server } from "lucide-react"; +import { Github, CodeXml, Server, Command } from "lucide-react"; import "./globals.css"; import { Toaster } from "react-hot-toast"; @@ -12,6 +12,7 @@ import { ThemeProvider } from "@/components/ThemeProvider"; import Image from "next/image"; import { ClerkThemeProvider } from "@/components/clerk/ClerkThemeProvider"; import { useEffectOnce } from "@/lib/useEffectOnce"; +import NextTopLoader from '@/lib/top-loader'; import { banner } from "@/banner"; import { Breadcrumb, @@ -24,6 +25,12 @@ import Link from "next/link"; import TopBar from "@/components/clerk/Topbar"; import TextFromPathname from "@/components/TextFromPathname"; import { Inter as interFont } from "next/font/google"; +import { + CommandBar, + CommandBarer, + SearchCommandBar, + SubLinkCommandBar, +} from "@/components/CommandBar"; const inter = interFont({ variable: "--font-inter", subsets: ["latin"] }); export default async function RootLayout({ @@ -40,6 +47,7 @@ export default async function RootLayout({ disableTransitionOnChange > + {banner.isBanner && (
{banner.bannerText} @@ -65,8 +73,9 @@ export default async function RootLayout({
-
{children}
{" "} +
{children}
{" "} +
diff --git a/src/components/CommandBar.tsx b/src/components/CommandBar.tsx new file mode 100644 index 0000000..5e7035b --- /dev/null +++ b/src/components/CommandBar.tsx @@ -0,0 +1,335 @@ +"use client"; +import { + Command, + CommandDialog, + CommandEmpty, + CommandGroup, + CommandInput, + CommandItem, + CommandList, + CommandSeparator, + CommandShortcut, +} from "@/components/ui/command"; +import { TagShower } from "./ServerList"; +import { useEffect, useState } from "react"; +import { OnlineServer } from "@/lib/types/server"; +import events from "@/lib/commandEvent"; +import { useHotkeys } from "react-hotkeys-hook"; +import Link from "next/link"; +import { + ArrowDown01, + ArrowLeft, + CommandIcon, + LinkIcon, + Server, + Settings, + Star, +} from "lucide-react"; +import { useEffectOnce } from "@/lib/useEffectOnce"; +import { useClerk, useUser } from "@clerk/nextjs"; +import { useRouter } from '@/lib/useRouter' + +export function SearchCommandBar() { + const [serverList, setServerList] = useState([]); + const [open, setOpen] = useState(false); + const [backEnabled, setBackEnabled] = useState(false); + const [searchRes, setSearchRes] = useState(undefined); + const router = useRouter() + useHotkeys("mod+shift+k", () => setOpen(true), []); + + useEffectOnce(() => { + events.on("search-request-event", () => { + setOpen(true); + }); + events.on("search-request-event-back", () => { + setOpen(true); + setBackEnabled(true); + }); + + fetch("https://api.minehut.com/servers").then((c) => + c.json().then((b: { servers: OnlineServer[] }) => { + setServerList(b.servers.slice(0, 20)); + }) + ); + }); + + return ( + + { + fetch("https://api.minehut.com/server/" + c + "?byName=true").then( + (l) => { + if (l.ok) { + console.log("found!"); + l.json().then((m: any) => { + setSearchRes(m.server); + console.log(searchRes); + }); + } else { + setSearchRes(undefined); + } + } + ); + }} + /> + + + { + setOpen(false); + if (backEnabled) events.emit("cmd-event"); + setBackEnabled(false); + }} + > + + Go back + + + + No results found. (Minehut deleted legacy servers) + + {searchRes == undefined ? ( + "" + ) : ( + + { + router.push("/server/" + searchRes.name); + }} + > +
+ {searchRes.name}
+ + {searchRes.joins} total joins •{" "} + {searchRes.online ? "Online" : "Offline"} + +
+
+
+ )} + + + {serverList.map((b: OnlineServer) => ( + { + router.push("/server/" + b.name); + }} + > +
+ {b.name}
+ + + +
+
+ ))} +
+
+
+ ); +} + +export function CommandBar() { + const [open, setOpen] = useState(false); + const clerk = useClerk(); + const { user } = useUser(); + useHotkeys("mod+k", () => setOpen(true), []); + + useEffectOnce(() => { + events.on("cmd-event", () => { + setOpen(true); + }); + }); + + return ( + + + + No results found. + + { + setOpen(false); + events.emit("search-request-event-back"); + }} + > + + Servers + + + +Shift+K + + + + + + Sort Servers - coming soon + + + { + setOpen(false); + events.emit("cmd-event-link"); + }} + > + + Links + + + + + events.emit("cmd-event-favorites")}> + + Favorites + + { + setOpen(false); + try { + clerk.openUserProfile(); + } catch { + clerk.openSignIn(); + } + }} + > + + User Settings + + + + + ); +} + +export function SubLinkCommandBar() { + const [open, setOpen] = useState(false); + + useEffectOnce(() => { + events.on("cmd-event-link", () => { + setOpen(true); + }); + }); + + return ( + + + + No results found. + { + setOpen(false); + events.emit("cmd-event"); + }} + > + + Go back + + + + { + window + .open("https://github.com/DeveloLongScript/MHSF", "_blank") + ?.focus(); + }} + > + + GitHub + + + { + window.open("https://mhsf.betteruptime.com", "_blank")?.focus(); + }} + > + + Status Page + + + + + ); +} +import * as React from "react"; +import type { SVGProps } from "react"; +import { getAccountFavorites } from "@/lib/api"; +const Github = (props: SVGProps) => ( + + + +); +export function FavoriteBar() { + const [isOpen, setOpen] = useState(false); + const [favorites, setFavorites] = useState | undefined>( + undefined + ); + const clerk = useClerk(); + const router = useRouter() + + useEffectOnce(() => { + events.on("cmd-event-favorites", () => setOpen(true)); + getAccountFavorites().then((c) => setFavorites(c)); + }); + + return ( + + + + No results found. + + { + setOpen(false); + events.emit("cmd-event"); + }} + > + + Go back + + + + + {favorites == undefined && ( + clerk.openSignIn()}> + Login to see favorites + + )} + {favorites != undefined && ( + <> + {favorites.map((c) => ( + { + router.push("/server/" + c); + }} + > + {c} + + ))} + + )} + + + + ); +} +export function CommandBarer() { + return ( + <> + + + + + + ); +} diff --git a/src/components/FavoritesView.tsx b/src/components/FavoritesView.tsx index a693328..0bae68c 100644 --- a/src/components/FavoritesView.tsx +++ b/src/components/FavoritesView.tsx @@ -2,37 +2,38 @@ import { useEffect, useState } from "react"; import { Spinner } from "./ui/spinner"; import { Card, CardHeader, CardTitle } from "./ui/card"; -import { ServerResponse } from "./ServerView"; +import { ServerResponse } from "@/lib/types/server"; import { useEffectOnce } from "@/lib/useEffectOnce"; import { Button } from "./ui/button"; -import { Copy, Layers, X, XIcon } from "lucide-react"; +import { Copy, Layers, XIcon } from "lucide-react"; import toast from "react-hot-toast"; import { Tooltip, TooltipContent, TooltipTrigger } from "./ui/tooltip"; +import { getAccountFavorites } from "@/lib/api"; +import { useRouter } from '@/lib/useRouter' export default function FavoritesView() { const [apiFavorites, setApiFavorites] = useState([]); const [loading, setLoading] = useState(true); + const router = useRouter() useEffectOnce(() => { - fetch("/api/favorites/getAllFavorites").then((c) => { - c.json().then((d) => { - let num = 0; - d.result.forEach((a: any, i: number) => { - fetch("https://api.minehut.com/server/" + a + "?byName=true").then( - (b) => - b.json().then((c) => { - num++; - var apiClone = apiFavorites; - apiClone.push(c.server); - setApiFavorites(apiClone); - if (num == d.result.length) { - setLoading(false); - } - }) - ); - }); - if (d.result.length == 0) setLoading(false); + getAccountFavorites().then((d) => { + let num = 0; + d.forEach((a: any, i: number) => { + fetch("https://api.minehut.com/server/" + a + "?byName=true").then( + (b) => + b.json().then((c) => { + num++; + var apiClone = apiFavorites; + apiClone.push(c.server); + setApiFavorites(apiClone); + if (num == d.length) { + setLoading(false); + } + }) + ); }); + if (d.length == 0) setLoading(false); }); }); @@ -80,7 +81,7 @@ export default function FavoritesView() { variant="secondary" className=" w-[32px] h-[32px] mb-2 ml-2 max-md:hidden" onClick={() => { - window.location.href = "/server/" + server.name; + router.push("/server/" + server.name); }} > diff --git a/src/components/HistoricalView.tsx b/src/components/HistoricalView.tsx deleted file mode 100644 index e69de29..0000000 diff --git a/src/components/NewChart.tsx b/src/components/NewChart.tsx index b015123..4e30b98 100644 --- a/src/components/NewChart.tsx +++ b/src/components/NewChart.tsx @@ -17,7 +17,8 @@ import { ChartTooltipContent, } from "@/components/ui/chart"; import { useEffectOnce } from "@/lib/useEffectOnce"; -import { ServerResponse } from "./ServerView"; +import { ServerResponse } from "@/lib/types/server"; +import { getCommunityServerFavorites, getShortTermData } from "@/lib/api"; const chartConfig = { player_count: { @@ -40,25 +41,10 @@ export function NewChart({ server }: { server: string }) { const allNums = { player_count: joins, favorites }; useEffectOnce(() => { - fetch("/api/history/getShortTermData", { - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ - scopes: ["player_count", "favorites", "time"], - server, - }), - method: "POST", - }).then((c) => { - c.json().then((b) => { - setChartData(b.data); - fetch("/api/favorites/getCommunityNum", { - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ server }), - method: "POST", - }).then((b) => - b.json().then((f) => { - setFavorites(f.result); - }) - ); + getShortTermData(server, ["player_count", "favorites", "time"]).then( + (c) => { + setChartData(c); + getCommunityServerFavorites(server).then((b) => setFavorites(b)); fetch("https://api.minehut.com/server/" + server + "?byName=true").then( (k) => { k.json().then((p: { server: ServerResponse }) => { @@ -66,8 +52,8 @@ export function NewChart({ server }: { server: string }) { }); } ); - }); - }); + } + ); }); return ( diff --git a/src/components/ServerCard.tsx b/src/components/ServerCard.tsx index 5035905..c3adb89 100644 --- a/src/components/ServerCard.tsx +++ b/src/components/ServerCard.tsx @@ -15,7 +15,7 @@ import { } from "./ui/card"; import IconDisplay from "./IconDisplay"; import { TagShower } from "./ServerList"; -import { Copy, EllipsisVertical, Layers, MoveRight } from "lucide-react"; +import { Copy, EllipsisVertical, Layers, MoveRight, Router } from "lucide-react"; import { Button } from "./ui/button"; import { Drawer, @@ -30,8 +30,11 @@ import { import { useEffect, useState } from "react"; import { Tooltip } from "@radix-ui/react-tooltip"; import { TooltipContent, TooltipTrigger } from "./ui/tooltip"; +import { useRouter } from '@/lib/useRouter' +import Link from "next/link"; export default function ServerCard({ b, motd }: any) { + const router = useRouter() return ( @@ -72,7 +75,7 @@ export default function ServerCard({ b, motd }: any) { + + Open up the server page to see more information about @@ -171,20 +173,19 @@ export default function ServerCard({ b, motd }: any) { + { - window.location.href = "/server/" + b.name; - }} + > Open server page - + - {b.name != "Skylegendz" && ( - - )} + + + @@ -204,7 +205,7 @@ export default function ServerCard({ b, motd }: any) { { - window.location.href = "/server/" + b.name; + router.push("/server/" + b.name); }} > Open server page diff --git a/src/components/ServerList.tsx b/src/components/ServerList.tsx index b192118..50fc66e 100644 --- a/src/components/ServerList.tsx +++ b/src/components/ServerList.tsx @@ -79,24 +79,25 @@ import { import remarkGfm from "remark-gfm"; import { Checkbox } from "@/components/ui/checkbox"; import { Spinner } from "./ui/spinner"; +import { CommandIcon } from "lucide-react"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; -import { OnlineServer, ServerResponse } from "./ServerView"; +import { OnlineServer, ServerResponse } from "@/lib/types/server"; import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"; import { useEffectOnce } from "@/lib/useEffectOnce"; import ServerCard from "./ServerCard"; import { useHotkeys } from "react-hotkeys-hook"; +import events from "@/lib/commandEvent"; +import { BorderBeam } from "@/components/effects/border-beam"; export default function ServerList() { const [loading, setLoading]: any = useState(true); - const [command, setCommand] = useState(false); const [randomText, setRandomText] = useState(""); const [motdList, setMotdList] = useState({}); const allText = [""]; const getRandomText = () => { return allText[Math.floor(Math.random() * allText.length)]; }; - const [searchRes, setSearchRes] = useState(undefined); const [templateFilter, setTemplateFilter] = useState(false); const [random, setRandom] = useState(false); const [serverList, setServerList] = useState(new ServersList([])); @@ -108,14 +109,13 @@ export default function ServerList() { server.playerData.playerCount < 15 && server.playerData.playerCount > 7; const [nameFilters, setNameFilters] = useState({}); - useHotkeys("ctrl+k", () => setCommand(true), []); const [inErrState, setErrState] = useState(false); const [servers, setServers] = useState>([]); const [filters, setFilters] = useState< Array<(server: OnlineServer) => Promise> >([]); const [randomData, setRandomData] = useState( - undefined, + undefined ); useEffectOnce(() => { @@ -175,9 +175,10 @@ export default function ServerList() {
+ >
@@ -338,7 +343,7 @@ export default function ServerList() { error: "Error while changing filters", loading: "Changing filters...", success: "Changed filters!", - }, + } ); }} defaultValue={(() => { @@ -571,7 +576,7 @@ export default function ServerList() { success: "Succesfully refreshed servers", loading: "Refreshing...", error: "Error while refreshing", - }, + } ); }} > @@ -636,7 +641,7 @@ export default function ServerList() { onClick={() => { setTextCopied(true); navigator.clipboard.writeText( - randomData.name + ".mshf.minehut.gg", + randomData.name + ".mshf.minehut.gg" ); toast.success("Copied!"); setTimeout(() => setTextCopied(false), 1000); @@ -655,68 +660,6 @@ export default function ServerList() {
- - { - fetch("https://api.minehut.com/server/" + c + "?byName=true").then( - (l) => { - if (l.ok) { - console.log("found!"); - l.json().then((m: any) => { - setSearchRes(m.server); - console.log(searchRes); - }); - } else { - setSearchRes(undefined); - } - }, - ); - }} - /> - - - No results found. (Minehut deleted legacy servers) - - {searchRes == undefined ? ( - "" - ) : ( - - { - window.location.replace("/server/" + searchRes.name); - }} - > -
- {searchRes.name}
- - {searchRes.joins} total joins •{" "} - {searchRes.online ? "Online" : "Offline"} - -
-
-
- )} - - - {serverList.currentServers.map((b: OnlineServer) => ( - { - window.location.replace("/server/" + b.name); - }} - > -
- {b.name}
- - - -
-
- ))} -
-
-

{ setRandomText(getRandomText()); single.init().then(() => { - fetch("/api/favorites/isFavorited", { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ - server: single.grabOffline()?.name, - }), - }) + isFavorited(single.grabOffline()?.name as string) .then((b) => { - b.json().then((c) => { - setFavorited(c.result); - setLoading(false); - var online = single.grabOffline()?.last_online; - if (online != undefined) { - setLastOnline(online); - } - }); + setFavorited(b); + setLoading(false); + var online = single.grabOffline()?.last_online; + if (online != undefined) { + setLastOnline(online); + } }) .catch(() => { setLoading(false); @@ -208,42 +203,46 @@ export default function ServerView(props: { server: string }) { - + {loadingFavorite && ( + Favorite Server + )} + {!loadingFavorite && ( + + )} @@ -269,85 +268,3 @@ function timeConverter(UNIX_timestamp: any) { var time = month + "/" + date + "/" + year; return time; } - -export interface ServerResponse { - __unix?: string; - deletion?: Deletion; - _id: string; - categories: string[]; - inheritedCategories: any[]; - purchased_icons: string[]; - backup_slots: number; - suspended: boolean; - server_version_type: string; - proxy: boolean; - connectedServers: any[]; - motd: string; - visibility: boolean; - server_plan: string; - storage_node: string; - default_banner_image: string; - default_banner_tint: string; - owner: string; - name: string; - name_lower: string; - creation: number; - platform: string; - credits_per_day: number; - in_game: boolean; - using_cosmetics: boolean; - __v: number; - port: number; - last_online: number; - joins: number; - active_icon: string; - expired: boolean; - icon: string; - online: boolean; - maxPlayers: number; - playerCount: number; - rawPlan: string; - activeServerPlan: string; -} - -export interface Deletion { - started: boolean; - started_at: number; - reason: string; - completed: boolean; - completed_at: number; - storage_completed: boolean; - storage_completed_at: number; -} - -export interface OnlineServer { - staticInfo: StaticInfo; - maxPlayers: number; - name: string; - motd: string; - icon: string; - playerData: PlayerData; - connectable: boolean; - visibility: boolean; - allCategories: string[]; - usingCosmetics: boolean; - author?: string; - authorRank: string; -} - -export interface StaticInfo { - _id: string; - serverPlan: string; - serviceStartDate: number; - platform: string; - planMaxPlayers: number; - planRam: number; - alwaysOnline: boolean; - rawPlan: string; - connectedServers: any[]; -} - -export interface PlayerData { - playerCount: number; - timeNoPlayers: number; -} diff --git a/src/components/Stat.tsx b/src/components/Stat.tsx index d210203..74e47dd 100644 --- a/src/components/Stat.tsx +++ b/src/components/Stat.tsx @@ -1,14 +1,17 @@ import { DollarSign } from "lucide-react"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; +import { Children } from "react"; export default function Component(props: { title: string; desc: string | JSX.Element; icon: any; className?: string; + children?: any; }) { return ( + {props.children} {props.title} diff --git a/src/components/clerk/LoggedInPopover.tsx b/src/components/clerk/LoggedInPopover.tsx index d15d70a..3e0103c 100644 --- a/src/components/clerk/LoggedInPopover.tsx +++ b/src/components/clerk/LoggedInPopover.tsx @@ -1,9 +1,11 @@ import { useClerk, useUser } from "@clerk/nextjs"; import { Button } from "../ui/button"; import { Star, UserCog, X } from "lucide-react"; +import { useRouter } from '@/lib/useRouter' export default function LoggedInPopover() { const clerk = useClerk(); + const router = useRouter() const { user } = useUser(); return ( @@ -19,7 +21,7 @@ export default function LoggedInPopover() { diff --git a/src/components/clerk/SignInPopoverButton.tsx b/src/components/clerk/SignInPopoverButton.tsx index c69190d..ec7c1c7 100644 --- a/src/components/clerk/SignInPopoverButton.tsx +++ b/src/components/clerk/SignInPopoverButton.tsx @@ -11,15 +11,17 @@ import { SignIn, useClerk } from "@clerk/nextjs"; export default function SignInPopoverButton({ className, + variant }: { className?: string; + variant?: "default" | "destructive" | "secondary" | "outline" | "ghost" | "link"; }) { const clerk = useClerk(); return ( - +
diff --git a/src/components/clerk/Topbar.tsx b/src/components/clerk/Topbar.tsx index a56a751..b760602 100644 --- a/src/components/clerk/Topbar.tsx +++ b/src/components/clerk/Topbar.tsx @@ -14,28 +14,24 @@ import InfoPopover from "../misc/InfoPopover"; import Link from "next/link"; export default function TopBar({ inter }: { inter: string }) { - const [loading, setLoading] = useState(true); - const [isAuthenticating, setAuthenticating] = useState(false); const clerk = useClerk(); const { user } = useUser(); - useEffect(() => { - fetch("/api/isAuthenticating").then((b) => { - b.json().then((m) => { - setAuthenticating(m.message); - setLoading(false); - }); - }); - }, []); - return ( <>
- {isAuthenticating && } - + + + + + + + + + -
); diff --git a/src/components/misc/TabServer.tsx b/src/components/misc/TabServer.tsx index 19d50cd..8608b27 100644 --- a/src/components/misc/TabServer.tsx +++ b/src/components/misc/TabServer.tsx @@ -3,6 +3,7 @@ import { useState } from "react"; import { Tabs, TabsList, TabsTrigger } from "../ui/tabs"; import { Spinner } from "../ui/spinner"; +import { useRouter } from '@/lib/useRouter' export default function TabServer({ server, @@ -13,6 +14,7 @@ export default function TabServer({ }) { const [tab, setTab] = useState(tabDef); const [tabLoading, setTabLoading] = useState(false); + const router = useRouter() return (
@@ -22,8 +24,8 @@ export default function TabServer({ setTab(tac); setTabLoading(true); if (tac == "historical") - window.location.replace(`/server/${server}/short-term`); - if (tac == "general") window.location.replace(`/server/${server}`); + router.push(`/server/${server}/short-term`); + if (tac == "general") router.push(`/server/${server}`); }} className="w-[300px]" > diff --git a/src/components/ui/loading-button.tsx b/src/components/ui/loading-button.tsx new file mode 100644 index 0000000..edb0fd6 --- /dev/null +++ b/src/components/ui/loading-button.tsx @@ -0,0 +1,81 @@ +import * as React from 'react'; +import { Slot } from '@radix-ui/react-slot'; +import { cva, type VariantProps } from 'class-variance-authority'; +import { cn } from '@/lib/utils'; +import { Loader2 } from 'lucide-react'; + +const buttonVariants = cva( + 'inline-flex items-center justify-center 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', + { + variants: { + variant: { + default: 'bg-primary text-primary-foreground hover:bg-primary/90', + destructive: 'bg-destructive text-destructive-foreground hover:bg-destructive/90', + outline: 'border border-input bg-background hover:bg-accent hover:text-accent-foreground', + secondary: 'bg-secondary text-secondary-foreground hover:bg-secondary/80', + ghost: 'hover:bg-accent hover:text-accent-foreground', + link: 'text-primary underline-offset-4 hover:underline', + }, + size: { + default: 'h-10 px-4 py-2', + sm: 'h-9 rounded-md px-3', + lg: 'h-11 rounded-md px-8', + icon: 'h-10 w-10', + }, + }, + defaultVariants: { + variant: 'default', + size: 'default', + }, + }, +); + +export interface ButtonProps + extends React.ButtonHTMLAttributes, + VariantProps { + asChild?: boolean; + loading?: boolean; +} + +const LoadingButton = React.forwardRef( + ({ className, variant, size, asChild = false, loading, children, ...props }, ref) => { + if (asChild) { + return ( + + <> + {React.Children.map(children as React.ReactElement, (child: React.ReactElement) => { + return React.cloneElement(child, { + className: cn(buttonVariants({ variant, size }), className), + children: ( + <> + {loading && ( + + )} + {child.props.children} + + ), + }); + })} + + + ); + } + + return ( + + ); + }, +); +LoadingButton.displayName = 'LoadingButton'; + +export { LoadingButton, buttonVariants }; diff --git a/src/lib/api.ts b/src/lib/api.ts new file mode 100644 index 0000000..d9273d5 --- /dev/null +++ b/src/lib/api.ts @@ -0,0 +1,175 @@ +/** + * New API file for easier API access + * Could be used for a JavaScript library :eyes: + * @author DeveloLongScript + */ +// + +const connector = ( + endpoint: string, + options: { version: number; starting?: string } +) => + `${options.starting == undefined ? "/" : `${options.starting}/`}api/v${options.version}${endpoint}`; + +export async function getMOTDFromServer( + list: Array<{ server: string; motd: string }> +): Promise> { + const result = await fetch(connector("/motd", { version: 1 }), { + body: JSON.stringify({ motd: list }), + method: "POST", + headers: { + "Content-Type": "application/json", + }, + }); + + let json = await result.json(); + return json.result; +} + +export async function getCommunityServerFavorites( + server: string +): Promise { + const result = await fetch( + connector(`/favorites/${server}/community-favorites`, { version: 0 }), + { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + } + ); + + let json = await result.json(); + return json.result; +} + +/** requires authentication */ +export async function favoriteServer(server: string) { + try { + await fetch( + connector(`/favorites/${server}/favorite-server`, { version: 0 }), + { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + } + ); + } catch { + throw Error("Not authenticated with a user."); + } +} + +/** requires authentication */ +export async function isFavorited(server: string): Promise { + try { + const response = await fetch( + connector(`/favorites/${server}/favorited`, { version: 0 }), + { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + } + ); + + return (await response.json()).data; + } catch { + throw Error("Not authenticated with a user."); + } +} + +/** requires authentication */ +export async function getAccountFavorites(): Promise> { + try { + const response = await fetch( + connector(`/favorites/account-favorites`, { version: 0 }), + { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + } + ); + + return (await response.json()).result; + } catch { + throw Error("Not authenticated with a user."); + } +} + +/** + * currently not used in frontend yet + */ +export async function getHistoricalData( + server: string, + scopes: Array<"player_count" | "favorites" | "server" | "time"> +): Promise< + Array<{ + player_count?: number; + favorites?: number; + server?: string; + time?: number; + }> +> { + const response = await fetch( + connector(`/history/${server}/get-historical-data`, { version: 0 }), + { + method: "POST", + body: JSON.stringify({ scopes }), + headers: { + "Content-Type": "application/json", + }, + } + ); + + return (await response.json()).data; +} + +export async function getShortTermData( + server: string, + scopes: Array<"player_count" | "favorites" | "server" | "time"> +): Promise< + Array<{ + player_count?: number; + favorites?: number; + server?: string; + time?: number; + }> +> { + const response = await fetch( + connector(`/history/${server}/get-short-term-data`, { version: 0 }), + { + method: "POST", + body: JSON.stringify({ scopes }), + headers: { + "Content-Type": "application/json", + }, + } + ); + + return (await response.json()).data; +} + +export async function getMetaShortTerm( + scopes: Array<"total_players" | "total_servers" | "unix"> +): Promise< + Array<{ + total_players?: number; + total_servers?: number; + unix?: number; + }> +> { + const response = await fetch( + connector(`/history/meta-short-term-data`, { version: 0 }), + { + method: "POST", + body: JSON.stringify({ scopes }), + headers: { + "Content-Type": "application/json", + }, + } + ); + + return (await response.json()).data; +} diff --git a/src/lib/commandEvent.ts b/src/lib/commandEvent.ts new file mode 100644 index 0000000..98dccdc --- /dev/null +++ b/src/lib/commandEvent.ts @@ -0,0 +1,23 @@ +class CommandEvents { + eventTarget; + + constructor() { + this.eventTarget = new EventTarget(); + } + + // Method to emit events + emit(eventName: string) { + const event = new CustomEvent(eventName); + this.eventTarget.dispatchEvent(event); + } + + // Method to listen for events + on(eventName: string, callback: () => void) { + this.eventTarget.addEventListener(eventName, () => { + callback(); + }); + } +} + +const events = new CommandEvents(); +export default events; diff --git a/src/lib/list.ts b/src/lib/list.ts index deba664..b6bed56 100644 --- a/src/lib/list.ts +++ b/src/lib/list.ts @@ -1,5 +1,6 @@ -import { OnlineServer } from "@/components/ServerView"; +import { OnlineServer } from "./types/server"; import toast from "react-hot-toast"; +import { getMOTDFromServer } from "./api"; var numberOfItemsInView = 20; @@ -28,7 +29,7 @@ export default class ServersList { console.log( "%c[MHSF] STOP! There was an error while requesting Minehut's API! Heres the fetch object for debugging: ", "font-weight: bold", - b, + b ); toast.error(` Error while grabbing servers from API. @@ -82,7 +83,7 @@ export default class ServersList { console.log( "%c[MHSF] STOP! There was an error while requesting Minehut's API! Heres the error for debugging: ", "font-weight: bold", - b, + b ); bc(); }); @@ -92,14 +93,14 @@ export default class ServersList { moveListDown() { const slicedArray = this.servers.slice( this.it * numberOfItemsInView, - this.it * numberOfItemsInView + numberOfItemsInView, + this.it * numberOfItemsInView + numberOfItemsInView ); this.currentServers = this.currentServers.concat(slicedArray); this.it++; console.log( "%c[MHSF] Moved list down! Updated entries: ", "font-weight: bold", - slicedArray, + slicedArray ); if (slicedArray.length != numberOfItemsInView) { this.hasMore = false; @@ -114,16 +115,10 @@ export default class ServersList { this.hasMore = true; } - async getMOTDs(list: Array<{ server: string; motd: string }>) { - let response = await fetch("/api/getMOTD", { - body: JSON.stringify({ motd: list }), - method: "POST", - headers: { - "Content-Type": "application/json", - }, - }); - let json = await response.json(); - return json.result; + async getMOTDs( + list: Array<{ server: string; motd: string }> + ): Promise> { + return await getMOTDFromServer(list); } } diff --git a/src/lib/miniMessage2HTML.ts b/src/lib/motdEngine.ts similarity index 98% rename from src/lib/miniMessage2HTML.ts rename to src/lib/motdEngine.ts index 69a3930..b8295fd 100644 --- a/src/lib/miniMessage2HTML.ts +++ b/src/lib/motdEngine.ts @@ -1,4 +1,5 @@ -import { twi } from "tw-to-css"; +// rendering engine for MOTDs (aka Minehut) + const divList: any = { black: "000000", dark_blue: "002bff", @@ -147,7 +148,7 @@ function createHTML( tag: string, className: string, contents: string, - tw?: boolean, + tw?: boolean ) { if (className == undefined) className = ""; if (contents == undefined) contents = ""; diff --git a/src/lib/single.ts b/src/lib/single.ts index 9e35427..4095123 100644 --- a/src/lib/single.ts +++ b/src/lib/single.ts @@ -1,4 +1,4 @@ -import { OnlineServer, ServerResponse } from "@/components/ServerView"; +import { OnlineServer, ServerResponse } from "./types/server"; import toast from "react-hot-toast"; export default class ServerSingle { @@ -27,7 +27,7 @@ export default class ServerSingle { g(true); } }); - }), + }) ); } else g(true); }); @@ -35,7 +35,7 @@ export default class ServerSingle { console.log( "%c[MHSF] STOP! There was an error while requesting Minehut's API! Heres the fetch object for debugging: ", "font-weight: bold", - d, + d ); toast.error(` Error while grabbing servers from API. @@ -52,7 +52,7 @@ export default class ServerSingle { console.log( "%c[MHSF] STOP! There was an error while requesting Minehut's API! Heres the error for debugging: ", "font-weight: bold", - b, + b ); bc(); }); diff --git a/src/lib/top-loader.tsx b/src/lib/top-loader.tsx new file mode 100644 index 0000000..256f13a --- /dev/null +++ b/src/lib/top-loader.tsx @@ -0,0 +1,21 @@ +// NextTopLoader.tsx +'use client'; + +import Loader from 'nextjs-toploader'; +import { usePathname } from 'next/navigation'; +import {useEffect} from "react" +import * as NProgress from "nprogress"; +import { useTheme } from 'next-themes'; + +export default function NextTopLoader() { + const pathname = usePathname(); + const theme = useTheme() + + useEffect(() => { + NProgress.done(); + }, [pathname]); + + return ( + + ) +} \ No newline at end of file diff --git a/src/lib/types/server.ts b/src/lib/types/server.ts new file mode 100644 index 0000000..14e693b --- /dev/null +++ b/src/lib/types/server.ts @@ -0,0 +1,81 @@ +export interface ServerResponse { + __unix?: string; + deletion?: Deletion; + _id: string; + categories: string[]; + inheritedCategories: any[]; + purchased_icons: string[]; + backup_slots: number; + suspended: boolean; + server_version_type: string; + proxy: boolean; + connectedServers: any[]; + motd: string; + visibility: boolean; + server_plan: string; + storage_node: string; + default_banner_image: string; + default_banner_tint: string; + owner: string; + name: string; + name_lower: string; + creation: number; + platform: string; + credits_per_day: number; + in_game: boolean; + using_cosmetics: boolean; + __v: number; + port: number; + last_online: number; + joins: number; + active_icon: string; + expired: boolean; + icon: string; + online: boolean; + maxPlayers: number; + playerCount: number; + rawPlan: string; + activeServerPlan: string; +} + +export interface Deletion { + started: boolean; + started_at: number; + reason: string; + completed: boolean; + completed_at: number; + storage_completed: boolean; + storage_completed_at: number; +} + +export interface OnlineServer { + staticInfo: StaticInfo; + maxPlayers: number; + name: string; + motd: string; + icon: string; + playerData: PlayerData; + connectable: boolean; + visibility: boolean; + allCategories: string[]; + usingCosmetics: boolean; + author?: string; + authorRank: string; +} + +export interface StaticInfo { + _id: string; + serverPlan: string; + serviceStartDate: number; + platform: string; + planMaxPlayers: number; + planRam: number; + alwaysOnline: boolean; + rawPlan: string; + connectedServers: any[]; +} + +export interface PlayerData { + playerCount: number; + timeNoPlayers: number; +} diff --git a/src/lib/useRouter.tsx b/src/lib/useRouter.tsx new file mode 100644 index 0000000..a463fc3 --- /dev/null +++ b/src/lib/useRouter.tsx @@ -0,0 +1,32 @@ +// useRouter.ts +import { NavigateOptions } from 'next/dist/shared/lib/app-router-context.shared-runtime'; +import { useRouter as useNextRouter, usePathname } from 'next/navigation'; +import { useCallback } from 'react'; +import NProgress from 'nprogress'; + +export const useRouter = () => { + const router = useNextRouter(); + const pathname = usePathname(); + + const replace = useCallback( + (href: string, options?: NavigateOptions) => { + href !== pathname && NProgress.start(); + router.replace(href, options); + }, + [router, pathname], + ); + + const push = useCallback( + (href: string, options?: NavigateOptions) => { + href !== pathname && NProgress.start(); + router.push(href, options); + }, + [router, pathname], + ); + + return { + ...router, + replace, + push, + }; +}; \ No newline at end of file diff --git a/src/pages/api/inngest.ts b/src/pages/api/inngest.ts index 8f5b67c..5b92d11 100644 --- a/src/pages/api/inngest.ts +++ b/src/pages/api/inngest.ts @@ -2,7 +2,7 @@ // its fully automatic import Favorites from "@/app/account/favorites/page"; -import { OnlineServer } from "@/components/ServerView"; +import { OnlineServer } from "@/lib/types/server"; import { Inngest } from "inngest"; import { serve } from "inngest/next"; import { MongoClient } from "mongodb"; @@ -16,8 +16,8 @@ export default serve({ client: inngest, functions: [ inngest.createFunction( - { id: "every-60-min" }, - [{ cron: "*/30 * * * *" }], + { id: "every-30-min" }, + [{ cron: "*/30 * * * *" }, { event: "test/30-min" }], async ({ event, step }) => { const mongo = new MongoClient(process.env.MONGO_DB as string); try { @@ -79,7 +79,7 @@ export default serve({ mongo.close(); return { event, body: "Cloudflare.. aborting " + e }; } - }, + } ), inngest.createFunction( { id: "every-two-months" }, @@ -118,7 +118,7 @@ export default serve({ event, body: "Dropped database. ", }; - }, + } ), ], }); diff --git a/src/pages/api/isAuthenticating.ts b/src/pages/api/isAuthenticating.ts deleted file mode 100644 index e85ead5..0000000 --- a/src/pages/api/isAuthenticating.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { NextApiRequest, NextApiResponse } from "next"; - -export default async function handler( - req: NextApiRequest, - res: NextApiResponse, -) { - res.send({ message: process.env.IS_AUTH == "true" }); -} diff --git a/src/pages/api/favorites/getCommunityNum.ts b/src/pages/api/v0/favorites/[server]/community-favorites.ts similarity index 86% rename from src/pages/api/favorites/getCommunityNum.ts rename to src/pages/api/v0/favorites/[server]/community-favorites.ts index f466d58..c7e6f7b 100644 --- a/src/pages/api/favorites/getCommunityNum.ts +++ b/src/pages/api/v0/favorites/[server]/community-favorites.ts @@ -6,7 +6,7 @@ export default async function handler( req: NextApiRequest, res: NextApiResponse ) { - const server = checkForInfoOrLeave(res, req.body.server); + const { server } = req.query; const client = new MongoClient(process.env.MONGO_DB as string); await client.connect(); @@ -25,12 +25,6 @@ export default async function handler( client.close(); } -function checkForInfoOrLeave(res: NextApiResponse, info: any) { - if (info == undefined) - res.status(400).json({ message: "Information wasn't supplied" }); - return info; -} - export async function increaseNum(client: MongoClient, server: string) { const db = client.db("mhsf"); const collection = db.collection("meta"); diff --git a/src/pages/api/favorites/favoriteServer.ts b/src/pages/api/v0/favorites/[server]/favorite-server.ts similarity index 85% rename from src/pages/api/favorites/favoriteServer.ts rename to src/pages/api/v0/favorites/[server]/favorite-server.ts index 2eb8b47..2802352 100644 --- a/src/pages/api/favorites/favoriteServer.ts +++ b/src/pages/api/v0/favorites/[server]/favorite-server.ts @@ -1,7 +1,7 @@ import type { NextApiResponse, NextApiRequest } from "next"; import { MongoClient, ObjectId } from "mongodb"; import { getAuth } from "@clerk/nextjs/server"; -import { decreaseNum, increaseNum } from "./getCommunityNum"; +import { decreaseNum, increaseNum } from "./community-favorites"; export default async function handler( req: NextApiRequest, @@ -12,7 +12,7 @@ export default async function handler( if (!userId) { return res.status(401).json({ error: "Unauthorized" }); } - const server = checkForInfoOrLeave(res, req.body.server); + const server = req.query.server as string; const client = new MongoClient(process.env.MONGO_DB as string); await client.connect(); @@ -58,9 +58,3 @@ export default async function handler( } } } - -function checkForInfoOrLeave(res: NextApiResponse, info: any) { - if (info == undefined) - res.status(400).json({ message: "Information wasn't supplied" }); - return info; -} diff --git a/src/pages/api/favorites/isFavorited.ts b/src/pages/api/v0/favorites/[server]/favorited.ts similarity index 73% rename from src/pages/api/favorites/isFavorited.ts rename to src/pages/api/v0/favorites/[server]/favorited.ts index daa87dc..f5eac4a 100644 --- a/src/pages/api/favorites/isFavorited.ts +++ b/src/pages/api/v0/favorites/[server]/favorited.ts @@ -4,14 +4,14 @@ import { getAuth } from "@clerk/nextjs/server"; export default async function handler( req: NextApiRequest, - res: NextApiResponse, + res: NextApiResponse ) { const { userId } = getAuth(req); if (!userId) { return res.status(401).json({ error: "Unauthorized" }); } - const server = checkForInfoOrLeave(res, req.body.server); + const server = req.query.server as string; const client = new MongoClient(process.env.MONGO_DB as string); await client.connect(); @@ -24,9 +24,3 @@ export default async function handler( } client.close(); } - -function checkForInfoOrLeave(res: NextApiResponse, info: any) { - if (info == undefined) - res.status(400).json({ message: "Information wasn't supplied" }); - return info; -} diff --git a/src/pages/api/favorites/getAllFavorites.ts b/src/pages/api/v0/favorites/account-favorites.ts similarity index 78% rename from src/pages/api/favorites/getAllFavorites.ts rename to src/pages/api/v0/favorites/account-favorites.ts index 54800cc..c8abea2 100644 --- a/src/pages/api/favorites/getAllFavorites.ts +++ b/src/pages/api/v0/favorites/account-favorites.ts @@ -4,7 +4,7 @@ import { getAuth } from "@clerk/nextjs/server"; export default async function handler( req: NextApiRequest, - res: NextApiResponse, + res: NextApiResponse ) { const { userId } = getAuth(req); @@ -25,9 +25,3 @@ export default async function handler( } client.close(); } - -function checkForInfoOrLeave(res: NextApiResponse, info: any) { - if (info == undefined) - res.status(400).json({ message: "Information wasn't supplied" }); - return info; -} diff --git a/src/pages/api/history/getHistoricalData.ts b/src/pages/api/v0/history/[server]/get-historical-data.ts similarity index 90% rename from src/pages/api/history/getHistoricalData.ts rename to src/pages/api/v0/history/[server]/get-historical-data.ts index 710355f..426ead0 100644 --- a/src/pages/api/history/getHistoricalData.ts +++ b/src/pages/api/v0/history/[server]/get-historical-data.ts @@ -3,11 +3,11 @@ import { NextApiRequest, NextApiResponse } from "next"; export default async function handler( req: NextApiRequest, - res: NextApiResponse, + res: NextApiResponse ) { const client = new MongoClient(process.env.MONGO_DB as string); const db = client.db("mhsf").collection("historical"); - const server = checkForInfoOrLeave(res, req.body.server); + const server = req.query.server as string; const scopes: Array = checkForInfoOrLeave(res, req.body.scopes); const allData = await db.find({ server }).toArray(); diff --git a/src/pages/api/history/getShortTermData.ts b/src/pages/api/v0/history/[server]/get-short-term-data.ts similarity index 90% rename from src/pages/api/history/getShortTermData.ts rename to src/pages/api/v0/history/[server]/get-short-term-data.ts index b0af4d7..047cc1f 100644 --- a/src/pages/api/history/getShortTermData.ts +++ b/src/pages/api/v0/history/[server]/get-short-term-data.ts @@ -3,11 +3,11 @@ import { NextApiRequest, NextApiResponse } from "next"; export default async function handler( req: NextApiRequest, - res: NextApiResponse, + res: NextApiResponse ) { const client = new MongoClient(process.env.MONGO_DB as string); const db = client.db("mhsf").collection("history"); - const server = checkForInfoOrLeave(res, req.body.server); + const server = req.query.server as string; const scopes: Array = checkForInfoOrLeave(res, req.body.scopes); const allData = await db.find({ server }).toArray(); diff --git a/src/pages/api/history/getMetaShortTermData.ts b/src/pages/api/v0/history/meta-short-term-data.ts similarity index 100% rename from src/pages/api/history/getMetaShortTermData.ts rename to src/pages/api/v0/history/meta-short-term-data.ts diff --git a/src/pages/api/getMOTD.ts b/src/pages/api/v1/motd.ts similarity index 92% rename from src/pages/api/getMOTD.ts rename to src/pages/api/v1/motd.ts index e109478..18067d4 100644 --- a/src/pages/api/getMOTD.ts +++ b/src/pages/api/v1/motd.ts @@ -1,11 +1,11 @@ import { NextApiRequest, NextApiResponse } from "next"; -import parseToHTML from "@/lib/miniMessage2HTML"; +import parseToHTML from "@/lib/motdEngine"; let num = 0; export default async function handler( req: NextApiRequest, - res: NextApiResponse, + res: NextApiResponse ) { num++; var body: Array<{ server: string; motd: string }> = req.body.motd; diff --git a/src/pages/api/status.ts b/src/pages/api/v1/status.ts similarity index 100% rename from src/pages/api/status.ts rename to src/pages/api/v1/status.ts diff --git a/src/version.tsx b/src/version.tsx index 7dcf441..e37cb33 100644 --- a/src/version.tsx +++ b/src/version.tsx @@ -1,4 +1,4 @@ -export const version = "b-0.4.5"; +export const version = "b-0.6.0"; const User = ({ user }: { user: string }) => ( @@ -8,6 +8,18 @@ const User = ({ user }: { user: string }) => ( export const Changelog = () => ( <> +
+ + Version b-0.6.0 (August 3rd 2024) + +
    +
  • • Enhanced shortcuts
  • +
  • • Added gradient beam to player count
  • +
  • • Updated loading animations
  • +
  • • Lots of bugfixes
  • +
+
+
Version b-0.4.5 (July 26th 2024): diff --git a/tailwind.config.ts b/tailwind.config.ts index 26f5721..bfa29cc 100644 --- a/tailwind.config.ts +++ b/tailwind.config.ts @@ -59,6 +59,12 @@ const config = { sm: "calc(var(--radius) - 4px)", }, keyframes: { + "border-beam": { + "100%": { + "offset-distance": "100%", + }, + }, + "accordion-down": { from: { height: "0" }, to: { height: "var(--radix-accordion-content-height)" }, @@ -71,6 +77,8 @@ const config = { animation: { "accordion-down": "accordion-down 0.2s ease-out", "accordion-up": "accordion-up 0.2s ease-out", + + "border-beam": "border-beam calc(var(--duration)*1s) infinite linear", }, }, }, diff --git a/yarn.lock b/yarn.lock index ff23946..a769438 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1331,6 +1331,11 @@ dependencies: undici-types "~5.26.4" +"@types/nprogress@^0.2.3": + version "0.2.3" + resolved "https://registry.yarnpkg.com/@types/nprogress/-/nprogress-0.2.3.tgz#b2150b054a13622fabcba12cf6f0b54c48b14287" + integrity sha512-k7kRA033QNtC+gLc4VPlfnue58CM1iQLgn1IMAU8VPHGOj7oIHPp9UlhedEnD/Gl8evoCjwkZjlBORtZ3JByUA== + "@types/prop-types@*": version "15.7.12" resolved "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz" @@ -4695,6 +4700,14 @@ next@14.2.3: "@next/swc-win32-ia32-msvc" "14.2.3" "@next/swc-win32-x64-msvc" "14.2.3" +nextjs-toploader@^1.6.12: + version "1.6.12" + resolved "https://registry.yarnpkg.com/nextjs-toploader/-/nextjs-toploader-1.6.12.tgz#5b9f951e0de80450a23acd5101f4a311265c0d70" + integrity sha512-nbun5lvVjlKnxLQlahzZ55nELVEduqoEXT03KCHnsEYJnFpI/3BaIzpMyq/v8C7UGU2NfxQmjq6ldZ310rsDqA== + dependencies: + nprogress "^0.2.0" + prop-types "^15.8.1" + no-case@^3.0.4: version "3.0.4" resolved "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz" @@ -4739,6 +4752,11 @@ npm-run-path@^5.1.0: dependencies: path-key "^4.0.0" +nprogress@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/nprogress/-/nprogress-0.2.0.tgz#cb8f34c53213d895723fcbab907e9422adbcafb1" + integrity sha512-I19aIingLgR1fmhftnbWWO3dXc0hSxqHQHQb3H8m+K3TnEn/iSeTZZOyvKXWqQESMwuUVnatlCnZdLBZZt2VSA== + nypm@^0.3.8: version "0.3.9" resolved "https://registry.yarnpkg.com/nypm/-/nypm-0.3.9.tgz#ab74c55075737466847611aa33c3c67741c01d8f"