From 2bd8d17b75f2d5849c304ddc2bbf4780983d67d4 Mon Sep 17 00:00:00 2001
From: dvelo <52332868+DeveloLongScript@users.noreply.github.com>
Date: Sat, 23 Nov 2024 17:54:15 -0600
Subject: [PATCH 1/3] feat: revamp loading spinner
---
src/components/ui/loading-spinner.tsx | 64 +++++++++++++++++++++++++++
1 file changed, 64 insertions(+)
create mode 100644 src/components/ui/loading-spinner.tsx
diff --git a/src/components/ui/loading-spinner.tsx b/src/components/ui/loading-spinner.tsx
new file mode 100644
index 0000000..00d4ba4
--- /dev/null
+++ b/src/components/ui/loading-spinner.tsx
@@ -0,0 +1,64 @@
+/*
+ * MHSF, Minehut Server List
+ * All external content is rather licensed under the ECA Agreement
+ * located here: https://mhsf.app/docs/legal/external-content-agreement
+ *
+ * All code under MHSF is licensed under the MIT License
+ * by open source contributors
+ *
+ * Copyright (c) 2024 dvelo
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+import { cn } from "@/lib/utils";
+
+export function LoadingSpinner({ className }: { className?: string }) {
+ return (
+
+
+ {[...Array(12)].map((_, i) => (
+
+ ))}
+
+
+ );
+}
From b073f719bedb2b3f0bbedb369cd879e9058c7161 Mon Sep 17 00:00:00 2001
From: dvelo <52332868+DeveloLongScript@users.noreply.github.com>
Date: Sat, 23 Nov 2024 17:54:51 -0600
Subject: [PATCH 2/3] feat: cosmetic changes for toasts and tabs
---
package.json | 5 +-
src/app/(main)/account/settings/page.tsx | 2 +-
src/app/(main)/server/[server]/page.tsx | 5 +-
src/components/AfterServerView.tsx | 3 +-
src/components/CommandBar.tsx | 4 +-
src/components/FavoritesView.tsx | 3 +-
src/components/Icon.tsx | 488 ++---
src/components/SLCustomizePage.tsx | 2 +-
src/components/ServerCard.tsx | 620 +++---
src/components/ServerCustomize.tsx | 900 ++++-----
src/components/ServerList.tsx | 2309 +++++++++++-----------
src/components/ServerView.tsx | 5 +-
src/components/feat/Embed.tsx | 4 +-
src/components/feat/EmbedSelector.tsx | 2 +-
src/components/misc/BannerPopover.tsx | 6 +-
src/components/misc/DiscordPopover.tsx | 2 +-
src/components/misc/LinkDialog.tsx | 2 +-
src/components/misc/StickyTopbar.tsx | 68 +
src/components/misc/TextCopyComp.tsx | 2 +-
src/components/misc/ThemedToaster.tsx | 14 +-
src/components/ui/sonner.tsx | 31 +
src/components/ui/tabs.tsx | 2 +-
src/config/affiliates.ts | 42 +
src/lib/list.ts | 2 +-
src/lib/single.ts | 2 +-
src/lib/useClipboard.ts | 2 +-
tailwind.config.ts | 351 ++--
yarn.lock | 21 +-
28 files changed, 2541 insertions(+), 2358 deletions(-)
create mode 100644 src/components/misc/StickyTopbar.tsx
create mode 100644 src/components/ui/sonner.tsx
create mode 100644 src/config/affiliates.ts
diff --git a/package.json b/package.json
index 1086e63..c7e8f70 100644
--- a/package.json
+++ b/package.json
@@ -44,7 +44,7 @@
"next": "14.2.10",
"next-contentlayer": "^0.3.4",
"next-css-obfuscator": "^2.2.16",
- "next-themes": "^0.3.0",
+ "next-themes": "^0.4.3",
"nextjs-toploader": "^1.6.12",
"nprogress": "^0.2.0",
"postcss-obfuscator": "^1.6.1",
@@ -53,9 +53,11 @@
"react-dom": "^18",
"react-fade-in": "^2.0.1",
"react-fast-marquee": "^1.6.5",
+ "react-hot-toast": "^2.4.1",
"react-qr-code": "^2.0.15",
"rehype-slug": "^6.0.0",
"remark-gfm": "^4.0.0",
+ "sonner": "^1.7.0",
"tailwind-merge": "^2.3.0",
"tailwindcss-animate": "^1.0.7",
"tailwindcss-patch": "^4.0.0",
@@ -101,7 +103,6 @@
"mangle-css-class-webpack-plugin": "^5.1.0",
"postcss": "^8",
"react-hook-form": "^7.52.2",
- "react-hot-toast": "^2.4.1",
"react-hotkeys-hook": "^4.5.0",
"react-infinite-scroll-component": "^6.1.0",
"react-markdown": "^9.0.1",
diff --git a/src/app/(main)/account/settings/page.tsx b/src/app/(main)/account/settings/page.tsx
index a724687..16402ae 100644
--- a/src/app/(main)/account/settings/page.tsx
+++ b/src/app/(main)/account/settings/page.tsx
@@ -31,7 +31,7 @@
"use client";
import { Button } from "@/components/ui/button";
import { useClerk, useUser } from "@clerk/nextjs";
-import toast from "react-hot-toast";
+import { toast } from "sonner";
import { unlinkMCAccount } from "@/lib/api";
import { useEffect, useState } from "react";
import { Dialog } from "@/components/ui/dialog";
diff --git a/src/app/(main)/server/[server]/page.tsx b/src/app/(main)/server/[server]/page.tsx
index b79e3e2..8d7b44d 100644
--- a/src/app/(main)/server/[server]/page.tsx
+++ b/src/app/(main)/server/[server]/page.tsx
@@ -32,6 +32,7 @@ import AfterServerView from "@/components/AfterServerView";
import Banner from "@/components/Banner";
import ColorProvider from "@/components/ColorProvider";
import ServerView from "@/components/ServerView";
+import StickyTopbar from "@/components/misc/StickyTopbar";
import TabServer from "@/components/misc/TabServer";
import { Separator } from "@/components/ui/separator";
import type { Metadata, ResolvingMetadata } from "next";
@@ -132,7 +133,9 @@ export default function ServerPage({ params }: { params: { server: string } }) {
-
+
+
+
diff --git a/src/components/AfterServerView.tsx b/src/components/AfterServerView.tsx
index 940a608..f45cfdc 100644
--- a/src/components/AfterServerView.tsx
+++ b/src/components/AfterServerView.tsx
@@ -41,7 +41,8 @@ import { Copy, Info, QrCode, Share2 } from "lucide-react";
import { useTheme } from "next-themes";
import { useEffect, useState } from "react";
import FadeIn from "react-fade-in/lib/FadeIn";
-import toast, { CheckmarkIcon } from "react-hot-toast";
+import { CheckmarkIcon } from "react-hot-toast";
+import { toast } from "sonner";
import Markdown from "react-markdown";
import IconDisplay from "./IconDisplay";
import AchievementList from "./feat/AchievementList";
diff --git a/src/components/CommandBar.tsx b/src/components/CommandBar.tsx
index 00d43f0..272f5e9 100644
--- a/src/components/CommandBar.tsx
+++ b/src/components/CommandBar.tsx
@@ -68,7 +68,7 @@ import {
} from "@/lib/api";
import IconDisplay from "./IconDisplay";
import ServerSingle from "@/lib/single";
-import toast from "react-hot-toast";
+import { toast } from "sonner";
import { ServerResponse, OnlineServer } from "@/lib/types/mh-server";
import {
Dialog,
@@ -278,7 +278,7 @@ export function OfflineServerCB() {
{customized && (
-
+
Is customized by a MHSF User
diff --git a/src/components/FavoritesView.tsx b/src/components/FavoritesView.tsx
index 0e41ce1..8221fe5 100644
--- a/src/components/FavoritesView.tsx
+++ b/src/components/FavoritesView.tsx
@@ -30,13 +30,12 @@
"use client";
import { useState } from "react";
-import { Spinner } from "./ui/spinner";
import { Card, CardHeader, CardTitle } from "./ui/card";
import type { ServerResponse } from "@/lib/types/mh-server";
import { useEffectOnce } from "@/lib/useEffectOnce";
import { Button } from "./ui/button";
import { Copy, Layers, XIcon } from "lucide-react";
-import toast from "react-hot-toast";
+import { toast } from "sonner";
import { Tooltip, TooltipContent, TooltipTrigger } from "./ui/tooltip";
import { getAccountFavorites } from "@/lib/api";
import { useRouter } from "@/lib/useRouter";
diff --git a/src/components/Icon.tsx b/src/components/Icon.tsx
index 9128c7a..f1114fc 100644
--- a/src/components/Icon.tsx
+++ b/src/components/Icon.tsx
@@ -41,62 +41,62 @@ import type { SVGProps } from "react";
* @returns A JSX element representing the colorful branding icon.
*/
export function BrandingColorfulIcon(props: SVGProps) {
- return (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- );
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
}
/**
* Returns the optional Pride icon
@@ -107,71 +107,71 @@ export function BrandingColorfulIcon(props: SVGProps) {
* @returns A JSX element representing the branding icon.
*/
export function BrandingPrideIcon(props: SVGProps) {
- return (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- );
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
}
/**
@@ -187,120 +187,136 @@ export function BrandingPrideIcon(props: SVGProps) {
* @returns A JSX element representing the branding icon.
*/
export function BrandingGenericIcon(props: SVGProps) {
- const { resolvedTheme } = useTheme();
+ const { resolvedTheme } = useTheme();
- if (resolvedTheme == "dark") {
- return (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- );
- } else {
- return (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- );
- }
+ if (resolvedTheme == "dark") {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+ } else {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+ }
}
+
+export const Discord = (props: SVGProps) => (
+
+
+
+);
diff --git a/src/components/SLCustomizePage.tsx b/src/components/SLCustomizePage.tsx
index 96195a7..a4faf87 100644
--- a/src/components/SLCustomizePage.tsx
+++ b/src/components/SLCustomizePage.tsx
@@ -45,7 +45,7 @@ import { Checkbox } from "@/components/ui/checkbox";
import { Button } from "@/components/ui/button";
import { Switch } from "./ui/switch";
import { setAccountSL } from "@/lib/api";
-import toast from "react-hot-toast";
+import { toast } from "sonner";
import { useUser } from "@clerk/nextjs";
export function SLCustomize() {
diff --git a/src/components/ServerCard.tsx b/src/components/ServerCard.tsx
index 2847edf..4b211b7 100644
--- a/src/components/ServerCard.tsx
+++ b/src/components/ServerCard.tsx
@@ -1,54 +1,23 @@
-/*
- * MHSF, Minehut Server List
- * All external content is rather licensed under the ECA Agreement
- * located here: https://list.mlnehut.com/docs/legal/external-content-agreement
- *
- * All code under MHSF is licensed under the MIT License
- * by open source contributors
- *
- * Copyright (c) 2024 dvelo
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- */
-
-import { NewChart } from "@/components/NewChart";
import { MiniJoinsChart } from "@/components/misc/MiniJoinsChart";
import {
- ContextMenu,
- ContextMenuContent,
- ContextMenuItem,
- ContextMenuSeparator,
- ContextMenuTrigger,
+ ContextMenu,
+ ContextMenuContent,
+ ContextMenuItem,
+ ContextMenuSeparator,
+ ContextMenuTrigger,
} from "@/components/ui/context-menu";
import {
- Drawer,
- DrawerContent,
- DrawerFooter,
- DrawerHeader,
- DrawerTitle,
- DrawerTrigger,
+ Drawer,
+ DrawerContent,
+ DrawerFooter,
+ DrawerHeader,
+ DrawerTitle,
+ DrawerTrigger,
} from "@/components/ui/drawer";
import {
- HoverCard,
- HoverCardContent,
- HoverCardTrigger,
+ HoverCard,
+ HoverCardContent,
+ HoverCardTrigger,
} from "@/components/ui/hover-card";
import { favoriteServer, isFavorited } from "@/lib/api";
import useClipboard from "@/lib/useClipboard";
@@ -56,300 +25,301 @@ import { useRouter } from "@/lib/useRouter";
import { useUser } from "@clerk/nextjs";
import { Tooltip } from "@radix-ui/react-tooltip";
import {
- ArrowRight,
- ChartArea,
- Copy,
- EllipsisVertical,
- Layers,
- Star,
+ ArrowRight,
+ ChartArea,
+ Copy,
+ EllipsisVertical,
+ Layers,
+ Star,
} from "lucide-react";
import { useTheme } from "next-themes";
import Link from "next/link";
import { useState } from "react";
-import toast, { LoaderIcon } from "react-hot-toast";
+import { LoaderIcon } from "react-hot-toast";
+import { toast } from "sonner";
import IconDisplay from "./IconDisplay";
import { TagShower } from "./ServerList";
import { Button } from "./ui/button";
import {
- Card,
- CardContent,
- CardDescription,
- CardHeader,
- CardTitle,
+ Card,
+ CardContent,
+ CardDescription,
+ CardHeader,
+ CardTitle,
} from "./ui/card";
import { TooltipContent, TooltipTrigger } from "./ui/tooltip";
export default function ServerCard({ b, motd, mini, favs }: any) {
- const router = useRouter();
- const clipboard = useClipboard();
- const [favoriteStar, setFavoriteStar] = useState(false);
- const [favoriteLoading, setFavoriteLoading] = useState(true);
- const { isSignedIn } = useUser();
- const { resolvedTheme } = useTheme();
+ const router = useRouter();
+ const clipboard = useClipboard();
+ const [favoriteStar, setFavoriteStar] = useState(false);
+ const [favoriteLoading, setFavoriteLoading] = useState(true);
+ const { isSignedIn } = useUser();
+ const { resolvedTheme } = useTheme();
- return (
- {
- if (open && isSignedIn)
- isFavorited(b.name).then((c) => {
- setFavoriteStar(c);
- setFavoriteLoading(false);
- });
- }}
- >
-
-
-
-
-
-
-
-
-
-
- {b.name}
-
-
-
-
-
-
-
{b.name}
-
- {motd && (
-
- )}
-
-
-
-
- Joins Chart
-
-
+ return (
+
{
+ if (open && isSignedIn)
+ isFavorited(b.name).then((c) => {
+ setFavoriteStar(c);
+ setFavoriteLoading(false);
+ });
+ }}
+ >
+
+
+
+
+
+
+
+
+
+
+ {b.name}
+
+
+
+
+
+
+
{b.name}
+
+ {motd && (
+
+ )}
+
+
+
+
+ Joins Chart
+
+
-
-
-
- Open Server Page
-
-
-
-
-
- Running on{" "}
- {b.staticInfo.serverPlan == undefined
- ? "Free Plan"
- : b.staticInfo.serverPlan}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Actions
-
-
- {
- clipboard.writeText(b.name + ".mshf.minehut.gg");
- toast.success("Copied IP to clipboard");
- }}
- >
- Copy server IP
-
-
- {
- router.push("/server/" + b.name);
- }}
- >
- Open server page
-
-
-
-
- {b.author != undefined ? (
-
- by {b.author}
-
- ) : (
-
- )}
-
-
-
-
- {b.playerData.playerCount == 0 ? (
-
- ) : (
-
- )}
+
+
+
+ Open Server Page
+
+
+
+
+
+ Running on{" "}
+ {b.staticInfo.serverPlan == undefined
+ ? "Free Plan"
+ : b.staticInfo.serverPlan}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Actions
+
+
+ {
+ clipboard.writeText(b.name + ".mshf.minehut.gg");
+ toast.success("Copied IP to clipboard");
+ }}
+ >
+ Copy server IP
+
+
+ {
+ router.push("/server/" + b.name);
+ }}
+ >
+ Open server page
+
+
+
+
+ {b.author != undefined ? (
+
+ by {b.author}
+
+ ) : (
+
+ )}
+
+
+
+
+ {b.playerData.playerCount == 0 ? (
+
+ ) : (
+
+ )}
-
- {b.playerData.playerCount}{" "}
- {b.playerData.playerCount == 1 ? "player" : "players"}{" "}
- currently online {favs && <>• {favs} favorited>}
-
-
+
+ {b.playerData.playerCount}{" "}
+ {b.playerData.playerCount == 1 ? "player" : "players"}{" "}
+ currently online {favs && <>• {favs} favorited>}
+
+
-
-
- <>
- {
- clipboard.writeText(b.name + ".mshf.minehut.gg");
- toast.success("Copied IP to clipboard");
- }}
- >
-
- {b.name}
-
-
-
-
-
-
-
-
-
-
- Open up the server page to see more information about
- the server
-
-
- >
-
-
- {
- clipboard.writeText(b.name + ".mshf.minehut.gg");
- toast.success("Copied IP to clipboard");
- }}
- >
- Copy server IP
-
-
-
-
-
-
- Open server page
-
-
-
-
-
- {motd && (
-
- )}
-
-
-
-
-
- {
- clipboard.writeText(b.name + ".mshf.minehut.gg");
- toast.success("Copied IP to clipboard");
- }}
- >
- Copy server IP
-
-
- {
- router.push("/server/" + b.name);
- }}
- >
- Open server page
-
- {
- router.push("/server/" + b.name + "/statistics");
- }}
- >
- Open statistics page
-
-
- {
- setFavoriteLoading(true);
- favoriteServer(b.name).then(() => {
- setFavoriteLoading(false);
- setFavoriteStar(!favoriteStar);
- });
- }}
- disabled={!isSignedIn || favoriteLoading}
- >
- {!favoriteLoading && (
-
- )}{" "}
- {favoriteLoading && }
- {favoriteStar && isSignedIn ? "Unf" : "F"}avorite Server
-
-
-
- );
+
+
+ <>
+ {
+ clipboard.writeText(b.name + ".mshf.minehut.gg");
+ toast.success("Copied IP to clipboard");
+ }}
+ >
+
+ {b.name}
+
+
+
+
+
+
+
+
+
+
+ Open up the server page to see more information about
+ the server
+
+
+ >
+
+
+ {
+ clipboard.writeText(b.name + ".mshf.minehut.gg");
+ toast.success("Copied IP to clipboard");
+ }}
+ >
+ Copy server IP
+
+
+
+
+
+
+ Open server page
+
+
+
+
+
+ {motd && (
+
+ )}
+
+
+
+
+
+ {
+ clipboard.writeText(b.name + ".mshf.minehut.gg");
+ toast.success("Copied IP to clipboard");
+ }}
+ >
+ Copy server IP
+
+
+ {
+ router.push("/server/" + b.name);
+ }}
+ >
+ Open server page
+
+ {
+ router.push("/server/" + b.name + "/statistics");
+ }}
+ >
+ Open statistics page
+
+
+ {
+ setFavoriteLoading(true);
+ favoriteServer(b.name).then(() => {
+ setFavoriteLoading(false);
+ setFavoriteStar(!favoriteStar);
+ });
+ }}
+ disabled={!isSignedIn || favoriteLoading}
+ >
+ {!favoriteLoading && (
+
+ )}{" "}
+ {favoriteLoading && }
+ {favoriteStar && isSignedIn ? "Unf" : "F"}avorite Server
+
+
+
+ );
}
diff --git a/src/components/ServerCustomize.tsx b/src/components/ServerCustomize.tsx
index cabc43c..8027a87 100644
--- a/src/components/ServerCustomize.tsx
+++ b/src/components/ServerCustomize.tsx
@@ -30,13 +30,13 @@
"use client";
import {
- getCustomization,
- ownServer,
- reportServer,
- serverOwned as sOFunc,
- setCustomization,
- unownServer,
- userOwnedServer,
+ getCustomization,
+ ownServer,
+ reportServer,
+ serverOwned as sOFunc,
+ setCustomization,
+ unownServer,
+ userOwnedServer,
} from "@/lib/api";
import { OnlineServer } from "@/lib/types/mh-server";
import { SignedIn, SignedOut, useUser } from "@clerk/nextjs";
@@ -45,17 +45,17 @@ import { CheckIcon, X } from "lucide-react";
import Link from "next/link";
import { Dispatch, SetStateAction, useEffect, useState } from "react";
import { useForm } from "react-hook-form";
-import toast from "react-hot-toast";
+import { toast } from "sonner";
import { z } from "zod";
import { Button } from "./ui/button";
import {
- Form,
- FormControl,
- FormDescription,
- FormField,
- FormItem,
- FormLabel,
- FormMessage,
+ Form,
+ FormControl,
+ FormDescription,
+ FormField,
+ FormItem,
+ FormLabel,
+ FormMessage,
} from "./ui/form";
import Setting from "./ui/setting";
import { Textarea } from "./ui/textarea";
@@ -66,456 +66,456 @@ import { useTheme } from "next-themes";
import { BannerPopover } from "./misc/BannerPopover";
import { DiscordPopover } from "./misc/DiscordPopover";
import {
- Card,
- CardContent,
- CardDescription,
- CardFooter,
- CardHeader,
- CardTitle,
+ Card,
+ CardContent,
+ CardDescription,
+ CardFooter,
+ CardHeader,
+ CardTitle,
} from "./ui/card";
import {
- Dialog,
- DialogContent,
- DialogDescription,
- DialogHeader,
- DialogTitle,
- DialogTrigger,
+ Dialog,
+ DialogContent,
+ DialogDescription,
+ DialogHeader,
+ DialogTitle,
+ DialogTrigger,
} from "./ui/dialog";
import { Popover, PopoverContent, PopoverTrigger } from "./ui/popover";
-import { Spinner } from "./ui/spinner";
+import { LoadingSpinner } from "./ui/loading-spinner";
const formSchema = z.object({
- description: z
- .string()
- .min(2, {
- message: "Description must be at least 2 characters.",
- })
- .max(1250, {
- message: "Description cannot be longer than 1250 characters.",
- }),
+ description: z
+ .string()
+ .min(2, {
+ message: "Description must be at least 2 characters.",
+ })
+ .max(1250, {
+ message: "Description cannot be longer than 1250 characters.",
+ }),
});
export default function ServerCustomize({
- server,
- cs,
- setCS,
+ server,
+ cs,
+ setCS,
}: {
- server: string;
- cs: string;
- setCS: Dispatch>;
+ server: string;
+ cs: string;
+ setCS: Dispatch>;
}) {
- const [serverOwned, setServerOwned] = useState(false);
- const [userOwned, setUserOwned] = useState(false);
- const [loading, setLoading] = useState(true);
- const [reason, setReason] = useState("");
- const [description, setDescription] = useState("");
- const [get, setGet] = useState({});
- const [author, setAuthor] = useState("");
- const [minehutOwned, setMinehutOwned] = useState(false);
- const { resolvedTheme: mode } = useTheme();
- const { user, isSignedIn } = useUser();
- useEffect(() => {
- sOFunc(server).then((c) => {
- setServerOwned(c);
- getCustomization(server).then((b) => {
- setGet(b);
- setDescription(b != null ? b.description : "");
- form.reset({ description: b != null ? b.description : "" });
- setCS(b != null ? b.colorScheme : "zinc");
- userOwnedServer(server).then((c) => {
- setUserOwned(c);
- fetch("https://api.minehut.com/servers").then((c) => {
- c.json().then((c: { servers: Array }) => {
- c.servers.forEach((v) => {
- setAuthor(v.author);
- if (v.name == server && isSignedIn) {
- if (user?.publicMetadata.player === v.author) {
- setMinehutOwned(true);
- }
- }
- setLoading(false);
- });
- });
- });
- });
- });
- });
- }, [isSignedIn]);
- const form = useForm>({
- resolver: zodResolver(formSchema),
- defaultValues: {
- description,
- },
- });
- if (loading) {
- return (
- <>
-
-
- >
- );
- }
+ const [serverOwned, setServerOwned] = useState(false);
+ const [userOwned, setUserOwned] = useState(false);
+ const [loading, setLoading] = useState(true);
+ const [reason, setReason] = useState("");
+ const [description, setDescription] = useState("");
+ const [get, setGet] = useState({});
+ const [author, setAuthor] = useState("");
+ const [minehutOwned, setMinehutOwned] = useState(false);
+ const { resolvedTheme: mode } = useTheme();
+ const { user, isSignedIn } = useUser();
+ useEffect(() => {
+ sOFunc(server).then((c) => {
+ setServerOwned(c);
+ getCustomization(server).then((b) => {
+ setGet(b);
+ setDescription(b != null ? b.description : "");
+ form.reset({ description: b != null ? b.description : "" });
+ setCS(b != null ? b.colorScheme : "zinc");
+ userOwnedServer(server).then((c) => {
+ setUserOwned(c);
+ fetch("https://api.minehut.com/servers").then((c) => {
+ c.json().then((c: { servers: Array }) => {
+ c.servers.forEach((v) => {
+ setAuthor(v.author);
+ if (v.name == server && isSignedIn) {
+ if (user?.publicMetadata.player === v.author) {
+ setMinehutOwned(true);
+ }
+ }
+ setLoading(false);
+ });
+ });
+ });
+ });
+ });
+ });
+ }, [isSignedIn]);
+ const form = useForm>({
+ resolver: zodResolver(formSchema),
+ defaultValues: {
+ description,
+ },
+ });
+ if (loading) {
+ return (
+ <>
+
+
+ >
+ );
+ }
- return (
- <>
-
- {!serverOwned && (
-
-
Do you own this server?
- Create an account and link it to the owner of the server to
- customize it.
-
- )}
-
-
- {!serverOwned && user?.publicMetadata.player == null && (
-
-
Do you own this server?
- Create an account and link it to the owner of the server to
- customize it.
-
- )}
- {serverOwned && !userOwned && (
-
-
- Is this server in violation of the ECA?
-
- Is this server in violation of the{" "}
-
- External Content Agreement (aka ECA)
-
- ? You can report the server to remove the customizations from the
- server.
-
-
- Report
-
-
-
- Report Server
-
- This will send a notification to MHSF maintainers. This
- server must be in violation of the{" "}
-
- ECA
- {" "}
- to be a valid report. Typical response times include 1 hour
- to 1 day, and you will not be notified if your report is
- successful or not.{" "}
-
- Please do not spam this form with mindless reports. If you
- do, your account will be banned. We are not Minehut
- support, we cannot help you with a problem within the
- Minehut platform or within the server, we can only
- moderate the customization of the server.
- {" "}
- (if the problem is within the server,{" "}
-
- report it on Minehut
-
- )
-
- Reason:
-
-
-
-
-
-
- )}
-
+ return (
+ <>
+
+ {!serverOwned && (
+
+
Do you own this server?
+ Create an account and link it to the owner of the server to
+ customize it.
+
+ )}
+
+
+ {!serverOwned && user?.publicMetadata.player == null && (
+
+
Do you own this server?
+ Create an account and link it to the owner of the server to
+ customize it.
+
+ )}
+ {serverOwned && !userOwned && (
+
+
+ Is this server in violation of the ECA?
+
+ Is this server in violation of the{" "}
+
+ External Content Agreement (aka ECA)
+
+ ? You can report the server to remove the customizations from the
+ server.
+
+
+ Report
+
+
+
+ Report Server
+
+ This will send a notification to MHSF maintainers. This
+ server must be in violation of the{" "}
+
+ ECA
+ {" "}
+ to be a valid report. Typical response times include 1 hour
+ to 1 day, and you will not be notified if your report is
+ successful or not.{" "}
+
+ Please do not spam this form with mindless reports. If you
+ do, your account will be banned. We are not Minehut
+ support, we cannot help you with a problem within the
+ Minehut platform or within the server, we can only
+ moderate the customization of the server.
+ {" "}
+ (if the problem is within the server,{" "}
+
+ report it on Minehut
+
+ )
+
+ Reason:
+
+
+
+
+
+
+ )}
+
- {!serverOwned && minehutOwned && (
-
- Do you own this server?{" "}
-
{
- await toast.promise(
- new Promise(async (g, b) => {
- (await ownServer(server)) ? g("") : b();
- }),
- {
- success: "Owned server!",
- loading: "Owning server...",
- error: "Error while owning server",
- },
- );
+ {!serverOwned && minehutOwned && (
+
+ Do you own this server?{" "}
+ {
+ await toast.promise(
+ new Promise(async (g, b) => {
+ (await ownServer(server)) ? g("") : b();
+ }),
+ {
+ success: "Owned server!",
+ loading: "Owning server...",
+ error: "Error while owning server",
+ }
+ );
- setMinehutOwned(true);
- setUserOwned(true);
- setServerOwned(true);
- }}
- >
- Click to own this server
-
-
- )}
-
- {!userOwned && (
- <>
-
- {" "}
-
- Whoops.. something went wrong
-
- You don't have permission to customize this server.
- >
- )}
+ setMinehutOwned(true);
+ setUserOwned(true);
+ setServerOwned(true);
+ }}
+ >
+ Click to own this server
+
+
+ )}
+
+ {!userOwned && (
+ <>
+
+ {" "}
+
+ Whoops.. something went wrong
+
+ You don't have permission to customize this server.
+ >
+ )}
- {serverOwned && userOwned && (
-
-
-
- Description
-
- Edit the description of the server.
-
-
-
-
-
-
-
-
- Pick any color scheme for the components on your server page to
- use.
- >
- }
- button={
-
-
-
- Edit Color Schemes
-
-
-
- {themes.map((colorObj) => {
- const color = colorObj.name;
- const theme = themes.find((theme) => theme.name === color);
- const isActive = cs === color;
+ {serverOwned && userOwned && (
+
+
+
+ Description
+
+ Edit the description of the server.
+
+
+
+
+
+
+
+
+ Pick any color scheme for the components on your server page to
+ use.
+ >
+ }
+ button={
+
+
+
+ Edit Color Schemes
+
+
+
+ {themes.map((colorObj) => {
+ const color = colorObj.name;
+ const theme = themes.find((theme) => theme.name === color);
+ const isActive = cs === color;
- if (!theme) {
- return null;
- }
+ if (!theme) {
+ return null;
+ }
- return (
- {
- setCS(theme.name);
- setCustomization(server, { colorScheme: theme.name });
- }}
- className={
- "justify-start " +
- (isActive && "border-2 border-primary")
- }
- style={
- {
- "--theme-primary": `hsl(${
- theme?.activeColor[
- mode === "dark" ? "dark" : "light"
- ]
- })`,
- } as React.CSSProperties
- }
- >
-
- {isActive && (
-
- )}
-
- {theme.label}
-
- );
- })}
-
-
- }
- />
-
-
-
- Banners appear on both the server list, and the server page.{" "}
-
- You will have to provide your own Imgur image for your image.
-
-
-
- By adding a banner, all images are subject to{" "}
-
- Minehuts Terms of Service
-
- ,{" "}
-
- Imgurs Terms of Service
- {" "}
- & the{" "}
-
- External Content Agreement
-
- .
-
- >
- }
- button={
-
-
- Change Banner
-
-
-
-
-
- }
- />
-
-
-
- Associate a Discord server embed in your server page.
-
-
- By adding a Discord Server, all servers are subject to{" "}
-
- Discords Terms of Service
- {" "}
- & the{" "}
-
- External Content Agreement
-
- .
-
- >
- }
- button={
-
-
- Change Discord
-
-
-
-
-
- }
- />
-
-
-
- By unowning the server, you will revert all customizations on
- the server and not be associated with the server.
- >
- }
- button={
-
- toast.promise(unownServer(server), {
- success: "Un-owned server!",
- loading: "Un-owning server...",
- error: "Error while un-owning server.",
- })
- }
- >
- Un-own Server
-
- }
- />
-
-
-
- )}
- >
- );
+ return (
+ {
+ setCS(theme.name);
+ setCustomization(server, { colorScheme: theme.name });
+ }}
+ className={
+ "justify-start " +
+ (isActive && "border-2 border-primary")
+ }
+ style={
+ {
+ "--theme-primary": `hsl(${
+ theme?.activeColor[
+ mode === "dark" ? "dark" : "light"
+ ]
+ })`,
+ } as React.CSSProperties
+ }
+ >
+
+ {isActive && (
+
+ )}
+
+ {theme.label}
+
+ );
+ })}
+
+
+ }
+ />
+
+
+
+ Banners appear on both the server list, and the server page.{" "}
+
+ You will have to provide your own Imgur image for your image.
+
+
+
+ By adding a banner, all images are subject to{" "}
+
+ Minehuts Terms of Service
+
+ ,{" "}
+
+ Imgurs Terms of Service
+ {" "}
+ & the{" "}
+
+ External Content Agreement
+
+ .
+
+ >
+ }
+ button={
+
+
+ Change Banner
+
+
+
+
+
+ }
+ />
+
+
+
+ Associate a Discord server embed in your server page.
+
+
+ By adding a Discord Server, all servers are subject to{" "}
+
+ Discords Terms of Service
+ {" "}
+ & the{" "}
+
+ External Content Agreement
+
+ .
+
+ >
+ }
+ button={
+
+
+ Change Discord
+
+
+
+
+
+ }
+ />
+
+
+
+ By unowning the server, you will revert all customizations on
+ the server and not be associated with the server.
+ >
+ }
+ button={
+
+ toast.promise(unownServer(server), {
+ success: "Un-owned server!",
+ loading: "Un-owning server...",
+ error: "Error while un-owning server.",
+ })
+ }
+ >
+ Un-own Server
+
+ }
+ />
+
+
+
+ )}
+ >
+ );
}
diff --git a/src/components/ServerList.tsx b/src/components/ServerList.tsx
index 30a344e..658974b 100644
--- a/src/components/ServerList.tsx
+++ b/src/components/ServerList.tsx
@@ -32,33 +32,33 @@
import { BorderBeam } from "@/components/effects/border-beam";
import { Button } from "@/components/ui/button";
import {
- Dialog,
- DialogContent,
- DialogDescription,
- DialogHeader,
- DialogTitle,
- DialogTrigger,
+ Dialog,
+ DialogContent,
+ DialogDescription,
+ DialogHeader,
+ DialogTitle,
+ DialogTrigger,
} from "@/components/ui/dialog";
import {
- Menubar,
- MenubarCheckboxItem,
- MenubarContent,
- MenubarItem,
- MenubarMenu,
- MenubarRadioGroup,
- MenubarRadioItem,
- MenubarSeparator,
- MenubarShortcut,
- MenubarSub,
- MenubarSubContent,
- MenubarSubTrigger,
- MenubarTrigger,
+ Menubar,
+ MenubarCheckboxItem,
+ MenubarContent,
+ MenubarItem,
+ MenubarMenu,
+ MenubarRadioGroup,
+ MenubarRadioItem,
+ MenubarSeparator,
+ MenubarShortcut,
+ MenubarSub,
+ MenubarSubContent,
+ MenubarSubTrigger,
+ MenubarTrigger,
} from "@/components/ui/menubar";
import { Separator } from "@/components/ui/separator";
import {
- Tooltip,
- TooltipContent,
- TooltipTrigger,
+ Tooltip,
+ TooltipContent,
+ TooltipTrigger,
} from "@/components/ui/tooltip";
import { allCategories, allTags } from "@/config/tags";
import events from "@/lib/commandEvent";
@@ -71,21 +71,21 @@ import { cn } from "@/lib/utils";
import { SignedIn, SignedOut, useUser } from "@clerk/nextjs";
import { ChatBubbleIcon, InputIcon } from "@radix-ui/react-icons";
import {
- ArrowDownZA,
- Check,
- CircleUser,
- ImageIcon,
- Info,
- LogIn,
- Network,
- Sun,
- XIcon,
+ ArrowDownZA,
+ Check,
+ CircleUser,
+ ImageIcon,
+ Info,
+ LogIn,
+ Network,
+ Sun,
+ XIcon,
} from "lucide-react";
import { CommandIcon } from "lucide-react";
import { useTheme } from "next-themes";
import Link from "next/link";
import { useEffect, useRef, useState } from "react";
-import toast from "react-hot-toast";
+import { toast } from "sonner";
import InfiniteScroll from "react-infinite-scroll-component";
import ClientFadeIn from "./ClientFadeIn";
import IconDisplay from "./IconDisplay";
@@ -100,1156 +100,1203 @@ import { pageFind } from "./misc/Link";
import { Badge } from "./ui/badge";
import { Popover, PopoverContent, PopoverTrigger } from "./ui/popover";
import { Skeleton } from "./ui/skeleton";
-import { Spinner } from "./ui/spinner";
+import { affiliates } from "@/config/affiliates";
+import { LoadingSpinner } from "./ui/loading-spinner";
+import StickyTopbar from "./misc/StickyTopbar";
const features = [
- {
- Icon: ChatBubbleIcon,
- name: "Add a Discord widget",
- description:
- "Show where your players talk to each-other, including an online users count.",
- href: "/docs/guides/customization",
- cta: "Learn more",
- background: ,
- className: "lg:row-start-1 lg:row-end-2 lg:col-start-2 lg:col-end-3",
- },
- {
- Icon: InputIcon,
- name: "Descriptions",
- href: "/docs/guides/customization",
- cta: "Learn more",
- description:
- "Format your descriptions using Markdown to show what your server has to offer.",
- background: ,
- className: "lg:col-start-1 lg:col-end-2 lg:row-start-1 lg:row-end-2",
- },
- {
- Icon: ImageIcon,
- name: "Banners",
- href: "/docs/guides/customization",
- cta: "Learn more",
- description:
- "Show a banner with can contain images that show on your server page.",
- background: ,
- className: "lg:col-start-3 lg:col-end-4 lg:row-start-1 lg:row-end-2",
- },
+ {
+ Icon: ChatBubbleIcon,
+ name: "Add a Discord widget",
+ description:
+ "Show where your players talk to each-other, including an online users count.",
+ href: "/docs/guides/customization",
+ cta: "Learn more",
+ background: ,
+ className: "lg:row-start-1 lg:row-end-2 lg:col-start-2 lg:col-end-3",
+ },
+ {
+ Icon: InputIcon,
+ name: "Descriptions",
+ href: "/docs/guides/customization",
+ cta: "Learn more",
+ description:
+ "Format your descriptions using Markdown to show what your server has to offer.",
+ background: ,
+ className: "lg:col-start-1 lg:col-end-2 lg:row-start-1 lg:row-end-2",
+ },
+ {
+ Icon: ImageIcon,
+ name: "Banners",
+ href: "/docs/guides/customization",
+ cta: "Learn more",
+ description:
+ "Show a banner with can contain images that show on your server page.",
+ background: ,
+ className: "lg:col-start-3 lg:col-end-4 lg:row-start-1 lg:row-end-2",
+ },
];
export default function ServerList() {
- const [loading, setLoading]: any = useState(true);
- const [randomText, setRandomText] = useState("");
- const [motdList, setMotdList] = useState({});
- const allText = [""];
- const getRandomText = () => {
- return allText[Math.floor(Math.random() * allText.length)];
- };
- const [templateFilter, setTemplateFilter] = useState(false);
- const [random, setRandom] = useState(false);
- const [serverList, setServerList] = useState(new ServersList([]));
- const [textCopied, setTextCopied] = useState(false);
- const [padding, setPadding] = useState("0");
- const bigger = async (server: OnlineServer) =>
- server.playerData.playerCount > 15;
- const smaller = async (server: OnlineServer) =>
- !server.staticInfo.alwaysOnline &&
- server.playerData.playerCount < 15 &&
- server.playerData.playerCount > 7;
- const [nameFilters, setNameFilters] = useState({});
- const [inErrState, setErrState] = useState(false);
- const [servers, setServers] = useState>([]);
- const clipboard = useClipboard();
- const router = useRouter();
- const { user, isSignedIn } = useUser();
- const [pOS, setpOS] = useState(false);
- const [ipr, setIPR] = useState("4");
- const [am, setAM] = useState(false);
- const [filters, setFilters] = useState<
- Array<(server: OnlineServer) => Promise>
- >([]);
- const [randomData, setRandomData] = useState(
- undefined,
- );
- const { resolvedTheme } = useTheme();
- const [color, setColor] = useState("#ffffff");
+ const [loading, setLoading]: any = useState(true);
+ const [randomText, setRandomText] = useState("");
+ const [motdList, setMotdList] = useState({});
+ const allText = [""];
+ const getRandomText = () => {
+ return allText[Math.floor(Math.random() * allText.length)];
+ };
+ const [templateFilter, setTemplateFilter] = useState(false);
+ const [random, setRandom] = useState(false);
+ const [serverList, setServerList] = useState(new ServersList([]));
+ const [textCopied, setTextCopied] = useState(false);
+ const [padding, setPadding] = useState("0");
+ const bigger = async (server: OnlineServer) =>
+ server.playerData.playerCount > 15;
+ const smaller = async (server: OnlineServer) =>
+ !server.staticInfo.alwaysOnline &&
+ server.playerData.playerCount < 15 &&
+ server.playerData.playerCount > 7;
+ const [nameFilters, setNameFilters] = useState({});
+ const [inErrState, setErrState] = useState(false);
+ const [servers, setServers] = useState>([]);
+ const clipboard = useClipboard();
+ const router = useRouter();
+ const { user, isSignedIn } = useUser();
+ const [pOS, setpOS] = useState(false);
+ const [ipr, setIPR] = useState("4");
+ const [am, setAM] = useState(false);
+ const [filters, setFilters] = useState<
+ Array<(server: OnlineServer) => Promise>
+ >([]);
+ const [randomData, setRandomData] = useState(
+ undefined
+ );
+ const { resolvedTheme } = useTheme();
+ const [color, setColor] = useState("#ffffff");
- useEffect(() => {
- setColor(resolvedTheme === "dark" ? "#ffffff" : "#000000");
- }, [resolvedTheme]);
+ useEffect(() => {
+ setColor(resolvedTheme === "dark" ? "#ffffff" : "#000000");
+ }, [resolvedTheme]);
- useEffect(() => {
- if (isSignedIn) {
- setAM(true);
- console.log(user.publicMetadata);
+ useEffect(() => {
+ if (isSignedIn) {
+ setAM(true);
+ console.log(user.publicMetadata);
- setIPR((user.publicMetadata.ipr as string | undefined) || "4");
- setPadding((user.publicMetadata.pad as string | undefined) || "0");
- setpOS((user.publicMetadata.srv as boolean | undefined) || false);
- }
- }, [isSignedIn, user]);
+ setIPR((user.publicMetadata.ipr as string | undefined) || "4");
+ setPadding((user.publicMetadata.pad as string | undefined) || "0");
+ setpOS((user.publicMetadata.srv as boolean | undefined) || false);
+ }
+ }, [isSignedIn, user]);
- useEffectOnce(() => {
- setRandomText(getRandomText());
- serverList
- .fetchDataAndFilter()
- .then(() => {
- serverList.moveListDown();
- let stringList: Array<{ server: string; motd: string }> = [];
- let obj: any = {};
+ useEffectOnce(() => {
+ setRandomText(getRandomText());
+ serverList
+ .fetchDataAndFilter()
+ .then(() => {
+ serverList.moveListDown();
+ let stringList: Array<{ server: string; motd: string }> = [];
+ let obj: any = {};
- serverList.currentServers.forEach((b) => {
- stringList.push({ motd: b.motd, server: b.name });
- });
+ serverList.currentServers.forEach((b) => {
+ stringList.push({ motd: b.motd, server: b.name });
+ });
- serverList.getMOTDs(stringList).then((c) => {
- var updatedSL = motdList;
- c.forEach((b: { server: string; motd: string }) => {
- updatedSL[b.server] = b.motd;
- });
- setMotdList(updatedSL);
- setServers(serverList.currentServers);
- setLoading(false);
- });
- })
- .catch(() => setErrState(true));
- });
+ serverList.getMOTDs(stringList).then((c) => {
+ var updatedSL = motdList;
+ c.forEach((b: { server: string; motd: string }) => {
+ updatedSL[b.server] = b.motd;
+ });
+ setMotdList(updatedSL);
+ setServers(serverList.currentServers);
+ setLoading(false);
+ });
+ })
+ .catch(() => setErrState(true));
+ });
- const ref = useRef(null);
- const [clickedPage, setClickedPage] = useState("banners");
- const [hero, setHero] = useState(false);
- if (inErrState) {
- return (
- <>
-
-
-
-
-
- Hmm. Something is wrong. Reload the page.
-
- >
- );
- }
+ const ref = useRef(null);
+ const [clickedPage, setClickedPage] = useState("banners");
+ const [hero, setHero] = useState(false);
+ if (inErrState) {
+ return (
+ <>
+
+
+
+
+
+ Hmm. Something is wrong. Reload the page.
+
+ >
+ );
+ }
- if (loading) {
- return (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- );
- }
+ if (loading) {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+ }
- return (
-
-
- <>
- {(!isSignedIn || hero) && (
-
-
-
- <>
- Meet MHSF, the modern
- server finder
- >
-
-
- MHSF is the next generation server list for Minehut, with
- interactive filters, {" "}
- intuitive keyboard shortcuts, and everything between.
-
+ return (
+
+
+ <>
+ {(!isSignedIn || hero) && (
+
+
+
+ <>
+ Meet MHSF, the modern
+ server finder
+ >
+
+
+ MHSF is the next generation server list for Minehut, with
+ interactive filters, {" "}
+ intuitive keyboard shortcuts, and everything between.
+
-
-
- Look and see
-
-
-
-
-
-
- Login
-
-
-
-
-
-
-
-
-
-
+
+
+ Look and see
+
+
+
+
+
+
+ Login
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
- For players
-
-
-
-
- Find what you want now, not later
-
-
- Use interactive filters and customization modes to find the
- server of your choice
- in less than 10 minutes.
-
-
-
- {serverList.currentServers.slice(0, 20).map((server) => (
-
- router.push(pageFind(`Server:${server.name}`))
- }
- >
-
-
-
-
- {server.name}
-
- {server.author && (
-
- by {server.author}
-
- )}
-
-
-
- ))}
-
-
- {serverList.currentServers.slice(0, 20).map((server) => (
- router.push(`/server/${server.name}`)}
- >
-
-
-
-
- {server.name}
-
- {server.author && (
-
- by {server.author}
-
- )}
-
-
-
- ))}
-
-
+
+
+
+
+
+
+
+ For players
+
+
+
+
+ Find what you want now, not later
+
+
+ Use interactive filters and customization modes to find the
+ server of your choice
+ in less than 10 minutes.
+
+
+
+ {serverList.currentServers.slice(0, 20).map((server) => (
+
+ router.push(pageFind(`Server:${server.name}`))
+ }
+ >
+
+
+
+
+ {server.name}
+
+ {server.author && (
+
+ by {server.author}
+
+ )}
+
+
+
+ ))}
+
+
+ {serverList.currentServers.slice(0, 20).map((server) => (
+ router.push(`/server/${server.name}`)}
+ >
+
+
+
+
+ {server.name}
+
+ {server.author && (
+
+ by {server.author}
+
+ )}
+
+
+
+ ))}
+
+
-
-
-
-
- For server owners
-
-
-
-
- Make your server stand out
-
-
- Servers can have custom banners, Discord widgets, color schemes,
- and descriptions, making your server stand out with information
- that can be shown to players.
-
-
- {features.map((feature, idx) => (
-
- ))}
-
+
+
+
+
+ For server owners
+
+
+
+
+ Make your server stand out
+
+
+ Servers can have custom banners, Discord widgets, color schemes,
+ and descriptions, making your server stand out with information
+ that can be shown to players.
+
+
+ {features.map((feature, idx) => (
+
+ ))}
+
-
-
- )}
-
- >
-
-
-
-
-
- = 3200
- ? "bg-clip-text text-transparent bg-gradient-to-r from-cyan-500 to-blue-500"
- : ""
- }
- >
- Servers online{" "}
-
- }
- className="relative z-0"
- desc={
-
-
= 3200
- ? "bg-clip-text text-transparent bg-gradient-to-r from-cyan-500 to-blue-500 "
- : ""
- }
- >
- {serverList.getExtraData().total_servers.toString()}
-
- {serverList.getExtraData().total_servers >= 3200 && (
-
-
-
-
-
- The server amount is over 3.2k, meaning that new servers
- have to go into a queue before being able to be online.{" "}
-
- (the server count isn't entirely accurate, so sometimes
- you might not go into a queue even when the server count
- is at 3.2k)
-
-
- )}
-
- }
- icon={Network}
- >
- {serverList.getExtraData().total_servers >= 3200 && (
-
- )}
-
-
- {serverList.currentServers[0] != undefined
- ? serverList.currentServers[0].name
- : "None"}{" "}
- {serverList.currentServers[0] != undefined && (
-
- )}
- >
- }
- icon={Sun}
- />
-
-
-
-
-
-
-
- Servers
-
- events.emit("search-request-event")}
- >
- Search Servers
-
-
- +Shift+K
-
-
- {
- setRandomData(serverList.getRandomServer());
- setRandom(true);
- }}
- >
- Pick Random Server
-
-
- {
- toast.promise(
- new Promise((s, e) => {
- setLoading(true);
- serverList
- .fetchDataAndFilter()
- .then(() => {
- serverList.moveListDown();
+
+
+ )}
+
+ >
+
+
+
+
+
+ = 3200
+ ? "bg-clip-text text-transparent bg-gradient-to-r from-cyan-500 to-blue-500"
+ : ""
+ }
+ >
+ Servers online{" "}
+
+ }
+ className="relative z-0"
+ desc={
+
+
= 3200
+ ? "bg-clip-text text-transparent bg-gradient-to-r from-cyan-500 to-blue-500 "
+ : ""
+ }
+ >
+ {serverList.getExtraData().total_servers.toString()}
+
+ {serverList.getExtraData().total_servers >= 3200 && (
+
+
+
+
+
+ The server amount is over 3.2k, meaning that new servers
+ have to go into a queue before being able to be online.{" "}
+
+ (the server count isn't entirely accurate, so sometimes
+ you might not go into a queue even when the server count
+ is at 3.2k)
+
+
+ )}
+
+ }
+ icon={Network}
+ >
+ {serverList.getExtraData().total_servers >= 3200 && (
+
+ )}
+
+
+ {serverList.currentServers[0] != undefined
+ ? serverList.currentServers[0].name
+ : "None"}{" "}
+ {serverList.currentServers[0] != undefined && (
+
+ )}
+ >
+ }
+ icon={Sun}
+ />
+
+
+
+
+
+
+
+
+ Servers
+
+ events.emit("search-request-event")}
+ >
+ Search Servers
+
+
+ +Shift+K
+
+
+ {
+ setRandomData(serverList.getRandomServer());
+ setRandom(true);
+ }}
+ >
+ Pick Random Server
+
+
+ {
+ toast.promise(
+ new Promise((s, e) => {
+ setLoading(true);
+ serverList
+ .fetchDataAndFilter()
+ .then(() => {
+ serverList.moveListDown();
- let stringList: Array<{
- server: string;
- motd: string;
- }> = [];
- let obj: any = {};
+ let stringList: Array<{
+ server: string;
+ motd: string;
+ }> = [];
+ let obj: any = {};
- serverList.currentServers.forEach((b) => {
- stringList.push({ motd: b.motd, server: b.name });
- });
+ serverList.currentServers.forEach((b) => {
+ stringList.push({
+ motd: b.motd,
+ server: b.name,
+ });
+ });
- serverList.getMOTDs(stringList).then((c) => {
- var updatedSL = motdList;
- c.forEach(
- (b: { server: string; motd: string }) => {
- updatedSL[b.server] = b.motd;
- },
- );
- setMotdList(updatedSL);
- setServers(serverList.currentServers);
- setLoading(false);
- s(false);
- });
- })
- .catch(() => {
- e();
- });
- }),
- {
- success: "Succesfully refreshed servers",
- loading: "Refreshing...",
- error: "Error while refreshing",
- },
- );
- }}
- >
- Refresh
-
-
-
-
- Filter
-
- {
- toast.promise(
- new Promise((g, b) => {
- if (v == "smaller") {
- setTemplateFilter(true);
- var filt = nameFilters;
- filt["smaller-tf"] = true;
- filt["bigger-tf"] = false;
- setNameFilters(filt);
+ serverList.getMOTDs(stringList).then((c) => {
+ var updatedSL = motdList;
+ c.forEach(
+ (b: { server: string; motd: string }) => {
+ updatedSL[b.server] = b.motd;
+ }
+ );
+ setMotdList(updatedSL);
+ setServers(serverList.currentServers);
+ setLoading(false);
+ s(false);
+ });
+ })
+ .catch(() => {
+ e();
+ });
+ }),
+ {
+ success: "Succesfully refreshed servers",
+ loading: "Refreshing...",
+ error: "Error while refreshing",
+ }
+ );
+ }}
+ >
+ Refresh
+
+
+
+
+ Filter
+
+ {
+ toast.promise(
+ new Promise((g, b) => {
+ if (v == "smaller") {
+ setTemplateFilter(true);
+ var filt = nameFilters;
+ filt["smaller-tf"] = true;
+ filt["bigger-tf"] = false;
+ setNameFilters(filt);
- var filt2 = filters;
- filt2.push(smaller);
- if (filt2.includes(bigger)) {
- filt2.splice(filt2.indexOf(bigger), 1);
- }
- setFilters(filt2);
- serverList.editFilters(filters);
- serverList.fetchDataAndFilter().then(() => {
- serverList.moveListDown();
+ var filt2 = filters;
+ filt2.push(smaller);
+ if (filt2.includes(bigger)) {
+ filt2.splice(filt2.indexOf(bigger), 1);
+ }
+ setFilters(filt2);
+ serverList.editFilters(filters);
+ serverList.fetchDataAndFilter().then(() => {
+ serverList.moveListDown();
- let stringList: Array<{
- server: string;
- motd: string;
- }> = [];
- let obj: any = {};
+ let stringList: Array<{
+ server: string;
+ motd: string;
+ }> = [];
+ let obj: any = {};
- serverList.currentServers.forEach((b) => {
- stringList.push({ motd: b.motd, server: b.name });
- });
+ serverList.currentServers.forEach((b) => {
+ stringList.push({
+ motd: b.motd,
+ server: b.name,
+ });
+ });
- serverList.getMOTDs(stringList).then((c) => {
- var updatedSL = motdList;
- c.forEach(
- (b: { server: string; motd: string }) => {
- updatedSL[b.server] = b.motd;
- },
- );
- setMotdList(updatedSL);
- setServers(serverList.currentServers);
- g(undefined);
- });
- });
- } else if (v == "bigger") {
- setTemplateFilter(true);
- var filt = nameFilters;
- filt["smaller-tf"] = false;
- filt["bigger-tf"] = true;
- setNameFilters(filt);
- var filt2 = filters;
- filt2.push(bigger);
+ serverList.getMOTDs(stringList).then((c) => {
+ var updatedSL = motdList;
+ c.forEach(
+ (b: { server: string; motd: string }) => {
+ updatedSL[b.server] = b.motd;
+ }
+ );
+ setMotdList(updatedSL);
+ setServers(serverList.currentServers);
+ g(undefined);
+ });
+ });
+ } else if (v == "bigger") {
+ setTemplateFilter(true);
+ var filt = nameFilters;
+ filt["smaller-tf"] = false;
+ filt["bigger-tf"] = true;
+ setNameFilters(filt);
+ var filt2 = filters;
+ filt2.push(bigger);
- filt2.splice(filt2.indexOf(smaller), 1);
+ filt2.splice(filt2.indexOf(smaller), 1);
- setFilters(filt2);
- serverList.editFilters(filters);
+ setFilters(filt2);
+ serverList.editFilters(filters);
- serverList.fetchDataAndFilter().then(() => {
- serverList.moveListDown();
+ serverList.fetchDataAndFilter().then(() => {
+ serverList.moveListDown();
- let stringList: Array<{
- server: string;
- motd: string;
- }> = [];
- let obj: any = {};
+ let stringList: Array<{
+ server: string;
+ motd: string;
+ }> = [];
+ let obj: any = {};
- serverList.currentServers.forEach((b) => {
- stringList.push({ motd: b.motd, server: b.name });
- });
+ serverList.currentServers.forEach((b) => {
+ stringList.push({
+ motd: b.motd,
+ server: b.name,
+ });
+ });
- serverList.getMOTDs(stringList).then((c) => {
- var updatedSL = motdList;
- c.forEach(
- (b: { server: string; motd: string }) => {
- updatedSL[b.server] = b.motd;
- },
- );
- setMotdList(updatedSL);
- setServers(serverList.currentServers);
- g(undefined);
- });
- });
- } else {
- var filt = nameFilters;
- filt["smaller-tf"] = false;
- filt["bigger-tf"] = false;
- setNameFilters(filt);
- setTemplateFilter(false);
+ serverList.getMOTDs(stringList).then((c) => {
+ var updatedSL = motdList;
+ c.forEach(
+ (b: { server: string; motd: string }) => {
+ updatedSL[b.server] = b.motd;
+ }
+ );
+ setMotdList(updatedSL);
+ setServers(serverList.currentServers);
+ g(undefined);
+ });
+ });
+ } else {
+ var filt = nameFilters;
+ filt["smaller-tf"] = false;
+ filt["bigger-tf"] = false;
+ setNameFilters(filt);
+ setTemplateFilter(false);
- var filt2 = filters;
- filt2.splice(filt2.indexOf(smaller), 1);
- filt2.splice(filt2.indexOf(bigger), 1);
- setFilters(filt2);
- console.log(filters, filters.includes(smaller));
- serverList.editFilters(filters);
+ var filt2 = filters;
+ filt2.splice(filt2.indexOf(smaller), 1);
+ filt2.splice(filt2.indexOf(bigger), 1);
+ setFilters(filt2);
+ console.log(filters, filters.includes(smaller));
+ serverList.editFilters(filters);
- serverList.fetchDataAndFilter().then(() => {
- serverList.moveListDown();
+ serverList.fetchDataAndFilter().then(() => {
+ serverList.moveListDown();
- let stringList: Array<{
- server: string;
- motd: string;
- }> = [];
- let obj: any = {};
+ let stringList: Array<{
+ server: string;
+ motd: string;
+ }> = [];
+ let obj: any = {};
- serverList.currentServers.forEach((b) => {
- stringList.push({ motd: b.motd, server: b.name });
- });
+ serverList.currentServers.forEach((b) => {
+ stringList.push({
+ motd: b.motd,
+ server: b.name,
+ });
+ });
- serverList.getMOTDs(stringList).then((c) => {
- var updatedSL = motdList;
- c.forEach(
- (b: { server: string; motd: string }) => {
- updatedSL[b.server] = b.motd;
- },
- );
- setMotdList(updatedSL);
- setServers(serverList.currentServers);
- g(undefined);
- });
- });
- }
- }),
- {
- error: "Error while changing filters",
- loading: "Changing filters...",
- success: "Changed filters!",
- },
- );
- }}
- value={(() => {
- if (nameFilters["smaller-tf"]) {
- return "smaller";
- } else if (nameFilters["bigger-tf"]) {
- return "bigger";
- } else {
- return "none";
- }
- })()}
- >
-
-
- Only allow smaller servers
-
-
- Only allow servers that have the player range 7-15, and
- cannot
- be Always Online.
-
-
-
-
-
- Only allow bigger servers
-
-
- Only allow servers with more than 15 players.
-
-
-
-
- No/custom requirements
-
-
-
-
-
- Tags
-
-
- {allTags.map((tag) => (
-
- {tag.docsName && tag.__filter == undefined && (
-
{
- return nameFilters["t-" + tag.docsName];
- })()}
- onCheckedChange={async (b) => {
- var filt = nameFilters;
- filt["t-" + tag.docsName] = b;
- setNameFilters(filt);
- if (b) {
- var filt2 = filters;
- filt2.push(tag.condition);
- setFilters(filt2);
- } else {
- var filt2 = filters;
- filt2.splice(filt2.indexOf(tag.condition), 1);
- setFilters(filt2);
- }
- serverList.editFilters(filters);
- serverList.fetchDataAndFilter().then(() => {
- serverList.moveListDown();
+ serverList.getMOTDs(stringList).then((c) => {
+ var updatedSL = motdList;
+ c.forEach(
+ (b: { server: string; motd: string }) => {
+ updatedSL[b.server] = b.motd;
+ }
+ );
+ setMotdList(updatedSL);
+ setServers(serverList.currentServers);
+ g(undefined);
+ });
+ });
+ }
+ }),
+ {
+ error: "Error while changing filters",
+ loading: "Changing filters...",
+ success: "Changed filters!",
+ }
+ );
+ }}
+ value={(() => {
+ if (nameFilters["smaller-tf"]) {
+ return "smaller";
+ } else if (nameFilters["bigger-tf"]) {
+ return "bigger";
+ } else {
+ return "none";
+ }
+ })()}
+ >
+
+
+ Only allow smaller servers
+
+
+ Only allow servers that have the player range 7-15,
+ and cannot
+ be Always Online.
+
+
+
+
+
+ Only allow bigger servers
+
+
+ Only allow servers with more than 15 players.
+
+
+
+
+ No/custom requirements
+
+
+
+
+
+ Tags
+
+
+ {allTags.map((tag) => (
+
+ {tag.docsName && tag.__filter == undefined && (
+ {
+ return nameFilters["t-" + tag.docsName];
+ })()}
+ onCheckedChange={async (b) => {
+ var filt = nameFilters;
+ filt["t-" + tag.docsName] = b;
+ setNameFilters(filt);
+ if (b) {
+ var filt2 = filters;
+ filt2.push(tag.condition);
+ setFilters(filt2);
+ } else {
+ var filt2 = filters;
+ filt2.splice(filt2.indexOf(tag.condition), 1);
+ setFilters(filt2);
+ }
+ serverList.editFilters(filters);
+ serverList.fetchDataAndFilter().then(() => {
+ serverList.moveListDown();
- let stringList: Array<{
- server: string;
- motd: string;
- }> = [];
- let obj: any = {};
+ let stringList: Array<{
+ server: string;
+ motd: string;
+ }> = [];
+ let obj: any = {};
- serverList.currentServers.forEach((b) => {
- stringList.push({ motd: b.motd, server: b.name });
- });
+ serverList.currentServers.forEach((b) => {
+ stringList.push({
+ motd: b.motd,
+ server: b.name,
+ });
+ });
- serverList.getMOTDs(stringList).then((c) => {
- var updatedSL = motdList;
- c.forEach(
- (b: { server: string; motd: string }) => {
- updatedSL[b.server] = b.motd;
- },
- );
- setMotdList(updatedSL);
- setServers(serverList.currentServers);
- });
- });
- }}
- >
-
- {tag.docsName}
-
-
- )}
-
- ))}
-
-
-
- Categories
-
-
- {allCategories.map((categorie) => (
- {
- var filt = nameFilters;
- filt["c-" + categorie.name] = b;
- setNameFilters(filt);
- if (b) {
- var filt2 = filters;
- filt2.push(categorie.condition);
- setFilters(filt2);
- } else {
- var filt2 = filters;
- filt2.splice(filt2.indexOf(categorie.condition), 1);
- setFilters(filt2);
- }
- serverList.editFilters(filters);
- serverList.fetchDataAndFilter().then(() => {
- serverList.moveListDown();
+ serverList.getMOTDs(stringList).then((c) => {
+ var updatedSL = motdList;
+ c.forEach(
+ (b: { server: string; motd: string }) => {
+ updatedSL[b.server] = b.motd;
+ }
+ );
+ setMotdList(updatedSL);
+ setServers(serverList.currentServers);
+ });
+ });
+ }}
+ >
+
+ {tag.docsName}
+
+
+ )}
+
+ ))}
+
+
+
+ Categories
+
+
+ {allCategories.map((categorie) => (
+ {
+ var filt = nameFilters;
+ filt["c-" + categorie.name] = b;
+ setNameFilters(filt);
+ if (b) {
+ var filt2 = filters;
+ filt2.push(categorie.condition);
+ setFilters(filt2);
+ } else {
+ var filt2 = filters;
+ filt2.splice(filt2.indexOf(categorie.condition), 1);
+ setFilters(filt2);
+ }
+ serverList.editFilters(filters);
+ serverList.fetchDataAndFilter().then(() => {
+ serverList.moveListDown();
- let stringList: Array<{
- server: string;
- motd: string;
- }> = [];
- let obj: any = {};
+ let stringList: Array<{
+ server: string;
+ motd: string;
+ }> = [];
+ let obj: any = {};
- serverList.currentServers.forEach((b) => {
- stringList.push({ motd: b.motd, server: b.name });
- });
+ serverList.currentServers.forEach((b) => {
+ stringList.push({ motd: b.motd, server: b.name });
+ });
- serverList.getMOTDs(stringList).then((c) => {
- var updatedSL = motdList;
- c.forEach((b: { server: string; motd: string }) => {
- updatedSL[b.server] = b.motd;
- });
- setMotdList(updatedSL);
- setServers(serverList.currentServers);
- });
- });
- }}
- checked={(() => {
- return nameFilters["c-" + categorie.name];
- })()}
- >
-
- {categorie.name}
-
-
- ))}
-
-
-
- View
-
-
- Grid
-
- {
- if (am)
- toast(
-
- These settings will not change over reloads
- because you have account specific options enabled
-
- router.push("/account/settings/options")
- }
- >
- Change your preferences
-
- ,
- { icon: "!" },
- );
- setIPR(v);
- }}
- >
-
- 4 items per row
-
-
- 5 items per row
-
-
- 6 items per row
-
-
-
-
-
- Padding
-
- {
- if (am)
- toast(
-
- These settings will not change over reloads
- because you have account specific options enabled
-
- router.push("/account/settings/options")
- }
- >
- Change your preferences
-
- ,
- { icon: "!" },
- );
- setPadding(v);
- }}
- >
- Default
-
- 15px
- 30px
- 40px
- 60px
- 100px
- 200px
-
-
-
- Only use padding on servers
-
-
-
-
- Sort
-
- {
- if (c === "favorites") router.push("/sort/favorites");
- }}
- >
-
- Players Online
-
-
- Favorites
-
-
-
-
-
-
-
- Show Hero
-
-
- router.push("/docs")}>
- View the docs
-
- {am && (
- router.push("/account/settings")}
- className="block"
- >
- Using saved settings in Preferences
-
-
- Your using settings stored on your account, that are not
- temporary.
-
-
- )}
-
-
-
-
+ serverList.getMOTDs(stringList).then((c) => {
+ var updatedSL = motdList;
+ c.forEach((b: { server: string; motd: string }) => {
+ updatedSL[b.server] = b.motd;
+ });
+ setMotdList(updatedSL);
+ setServers(serverList.currentServers);
+ });
+ });
+ }}
+ checked={(() => {
+ return nameFilters["c-" + categorie.name];
+ })()}
+ >
+
+ {categorie.name}
+
+
+ ))}
+
+
+
+ View
+
+
+ Grid
+
+ {
+ if (am)
+ toast.warning(
+ "These settings will not change over reloads because you have account specific options enabled",
+ {
+ action: {
+ label: "Check settings",
+ onClick: () =>
+ router.push("/account/settings/options"),
+ },
+ }
+ );
+ setIPR(v);
+ }}
+ >
+
+ 4 items per row
+
+
+ 5 items per row
+
+
+ 6 items per row
+
+
+
+
+
+ Padding
+
+ {
+ if (am)
+ toast.warning(
+ "These settings will not change over reloads because you have account specific options enabled",
+ {
+ action: {
+ label: "Check settings",
+ onClick: () =>
+ router.push("/account/settings/options"),
+ },
+ }
+ );
+ setPadding(v);
+ }}
+ >
+ Default
+
+ 15px
+ 30px
+ 40px
+ 60px
+ 100px
+ 200px
+
+
+
+ Only use padding on servers
+
+
+
+
+ Sort
+
+ {
+ if (c === "favorites") router.push("/sort/favorites");
+ }}
+ >
+
+ Players Online
+
+
+ Favorites
+
+
+
+
+
+
+
+ Show Hero
+
+
+ router.push("/docs")}>
+ View the docs
+
+ {am && (
+ router.push("/account/settings")}
+ className="block"
+ >
+ Using saved settings in Preferences
+
+
+ Your using settings stored on your account, that are not
+ temporary.
+
+
+ )}
+
+
+
+
+
-
-
- {randomData == undefined && <>No data to randomize>}
- {randomData != undefined && (
-
-
- {randomData.name}
- {randomData.author != undefined ? (
-
- by {randomData.author}
-
- ) : (
-
- )}
-
-
-
-
- {randomData.playerData.playerCount == 0 ? (
-
- ) : (
-
- )}
+
+
+ {randomData == undefined && <>No data to randomize>}
+ {randomData != undefined && (
+
+
+ {randomData.name}
+ {randomData.author != undefined ? (
+
+ by {randomData.author}
+
+ ) : (
+
+ )}
+
+
+
+
+ {randomData.playerData.playerCount == 0 ? (
+
+ ) : (
+
+ )}
-
- {randomData.playerData.playerCount}{" "}
- {randomData.playerData.playerCount == 1
- ? "player"
- : "players"}{" "}
- currently online
-
-
-
- Server IP
-
-
-
- {randomData.name}.minehut.gg{" "}
- {
- setTextCopied(true);
- clipboard.writeText(
- randomData.name + ".mshf.minehut.gg",
- );
- toast.success("Copied!");
- setTimeout(() => setTextCopied(false), 1000);
- }}
- >
- {textCopied ? (
-
- ) : (
- Copy
- )}
-
-
-
-
- )}
-
-
+
+ {randomData.playerData.playerCount}{" "}
+ {randomData.playerData.playerCount == 1
+ ? "player"
+ : "players"}{" "}
+ currently online
+
+
+
+ Server IP
+
+
+
+ {randomData.name}.minehut.gg{" "}
+ {
+ setTextCopied(true);
+ clipboard.writeText(
+ randomData.name + ".mshf.minehut.gg"
+ );
+ toast.success("Copied!");
+ setTimeout(() => setTextCopied(false), 1000);
+ }}
+ >
+ {textCopied ? (
+
+ ) : (
+ Copy
+ )}
+
+
+
+
+ )}
+
+
-
-
{
- serverList.moveListDown();
- let stringList: Array<{ server: string; motd: string }> = [];
- serverList.currentServers.forEach((b) => {
- stringList.push({ motd: b.motd, server: b.name });
- });
+
+ {
+ serverList.moveListDown();
+ let stringList: Array<{ server: string; motd: string }> = [];
+ serverList.currentServers.forEach((b) => {
+ stringList.push({ motd: b.motd, server: b.name });
+ });
- serverList.getMOTDs(stringList).then((c) => {
- var updatedSL = motdList;
- c.forEach((b: { server: string; motd: string }) => {
- updatedSL[b.server] = b.motd;
- });
- setMotdList(updatedSL);
- setServers(serverList.currentServers);
- setLoading(false);
- });
- }}
- loader={ }
- endMessage={
-
You've seen it all ",
- }}
- />
- }
- style={{
- overflow: "hidden !important",
- paddingLeft: pOS ? `${padding}px` : 6,
- paddingRight: pOS ? `${padding}px` : 6,
- }}
- >
-
- {/** This looks stupid, but its the only way that works */}
-
- {servers.map((b: any) => (
- <>
-
- >
- ))}
-
-
-
-
-
- );
+ serverList.getMOTDs(stringList).then((c) => {
+ var updatedSL = motdList;
+ c.forEach((b: { server: string; motd: string }) => {
+ updatedSL[b.server] = b.motd;
+ });
+ setMotdList(updatedSL);
+ setServers(serverList.currentServers);
+ setLoading(false);
+ });
+ }}
+ loader={ }
+ endMessage={
+
You've seen it all ",
+ }}
+ />
+ }
+ style={{
+ overflow: "hidden !important",
+ paddingLeft: pOS ? `${padding}px` : 6,
+ paddingRight: pOS ? `${padding}px` : 6,
+ }}
+ >
+
+ {/** This looks stupid, but its the only way that works */}
+
+ {servers.map((b: any, i: number) => (
+ <>
+ {i === Number(ipr) && affiliates.length != 0 && (
+
+
+
+ Affiliates
+
+
+ We have been able to partner with some servers that we
+ think are high-effort servers that need to be
+ recognized.
+
+
+ Please take some interest in a server you find
+ interesting and give them some much needed support.
+
+
+ These servers have absolutely no financial affiliation
+ with MHSF.
+
+
+ {affiliates
+ .filter((a) => a.mode.includes("server-list"))
+ .map((a) => (
+
+ {a.name}
+
+ ))}
+
+ )}
+
+ >
+ ))}
+
+
+
+
+
+ );
}
export function TagShower(props: {
- server: OnlineServer;
- className?: string;
- unclickable?: boolean;
+ server: OnlineServer;
+ className?: string;
+ unclickable?: boolean;
}) {
- const [loading, setLoading] = useState(true);
- const [compatiableTags, setCompatiableTags] = useState<
- Array<{
- name: string;
- docsName?: string;
- tooltip: string;
- htmlDocs: string;
- role:
- | "default"
- | "destructive"
- | "outline"
- | "secondary"
- | "red"
- | "orange"
- | "yellow"
- | "green"
- | "lime"
- | "blue"
- | "teal"
- | "cyan"
- | "violet"
- | "indigo"
- | "purple"
- | "fuchsia"
- | "pink";
- }>
- >([]);
+ const [loading, setLoading] = useState(true);
+ const [compatiableTags, setCompatiableTags] = useState<
+ Array<{
+ name: string;
+ docsName?: string;
+ tooltip: string;
+ htmlDocs: string;
+ role:
+ | "default"
+ | "destructive"
+ | "outline"
+ | "secondary"
+ | "red"
+ | "orange"
+ | "yellow"
+ | "green"
+ | "lime"
+ | "blue"
+ | "teal"
+ | "cyan"
+ | "violet"
+ | "indigo"
+ | "purple"
+ | "fuchsia"
+ | "pink";
+ }>
+ >([]);
- useEffectOnce(() => {
- if (loading) {
- allTags.forEach((tag) => {
- tag.condition(props.server).then((b) => {
- if (b && tag.primary) {
- tag.name(props.server).then((n) => {
- compatiableTags.push({
- name: n,
- docsName: tag.docsName,
- tooltip: tag.tooltipDesc,
- htmlDocs: tag.htmlDocs,
- role: tag.role == undefined ? "secondary" : tag.role,
- });
- setLoading(false);
- });
- }
- });
- });
- }
- });
+ useEffectOnce(() => {
+ if (loading) {
+ allTags.forEach((tag) => {
+ tag.condition(props.server).then((b) => {
+ if (b && tag.primary) {
+ tag.name(props.server).then((n) => {
+ compatiableTags.push({
+ name: n,
+ docsName: tag.docsName,
+ tooltip: tag.tooltipDesc,
+ htmlDocs: tag.htmlDocs,
+ role: tag.role == undefined ? "secondary" : tag.role,
+ });
+ setLoading(false);
+ });
+ }
+ });
+ });
+ }
+ });
- if (loading) {
- return <>>;
- }
+ if (loading) {
+ return <>>;
+ }
- return (
-
- {compatiableTags.map((t) => (
- <>
- {props.unclickable && (
-
- {t.name}
-
- )}
- {!props.unclickable && (
-
-
-
-
-
- {t.name}
-
-
-
-
- {t.tooltip}
-
- Click the tag to learn more about it.
-
-
-
-
-
-
-
- {'"'}
- {t.docsName == undefined ? t.name : t.docsName}
- {'"'} documentation
-
-
-
-
-
- )}
- >
- ))}
-
- );
+ return (
+
+ {compatiableTags.map((t) => (
+ <>
+ {props.unclickable && (
+
+ {t.name}
+
+ )}
+ {!props.unclickable && (
+
+
+
+
+
+ {t.name}
+
+
+
+
+ {t.tooltip}
+
+ Click the tag to learn more about it.
+
+
+
+
+
+
+
+ {'"'}
+ {t.docsName == undefined ? t.name : t.docsName}
+ {'"'} documentation
+
+
+
+
+
+ )}
+ >
+ ))}
+
+ );
}
diff --git a/src/components/ServerView.tsx b/src/components/ServerView.tsx
index 7a96c23..f78fa0a 100644
--- a/src/components/ServerView.tsx
+++ b/src/components/ServerView.tsx
@@ -59,6 +59,7 @@ import { useClerk, useUser } from "@clerk/nextjs";
import { LoaderIcon } from "react-hot-toast";
import { Separator } from "./ui/separator";
import { convert } from "@/components/NewChart";
+import { LoadingSpinner } from "./ui/loading-spinner";
export default function ServerView(props: { server: string }) {
const [single, setSingle] = useState(new ServerSingle(props.server));
@@ -210,7 +211,9 @@ export default function ServerView(props: { server: string }) {
}}
disabled={loadingFavorite}
>
- {loadingFavorite && }
+ {loadingFavorite && (
+
+ )}
{!favorited && !loadingFavorite && (
;
+ return ;
}
if (!serverFound) {
diff --git a/src/components/feat/EmbedSelector.tsx b/src/components/feat/EmbedSelector.tsx
index 98ee335..c9882ca 100644
--- a/src/components/feat/EmbedSelector.tsx
+++ b/src/components/feat/EmbedSelector.tsx
@@ -39,7 +39,7 @@ import { codeToHtml } from "shiki";
import { useTheme } from "next-themes";
import { Asterisk, Copy } from "lucide-react";
import useClipboard from "@/lib/useClipboard";
-import toast from "react-hot-toast";
+import { toast } from "sonner";
import { Checkbox } from "../ui/checkbox";
import {
Select,
diff --git a/src/components/misc/BannerPopover.tsx b/src/components/misc/BannerPopover.tsx
index a657191..b621ce4 100644
--- a/src/components/misc/BannerPopover.tsx
+++ b/src/components/misc/BannerPopover.tsx
@@ -1,5 +1,4 @@
-"use client";
-
+"use client";;
import { zodResolver } from "@hookform/resolvers/zod";
import { useForm } from "react-hook-form";
import { z } from "zod";
@@ -15,8 +14,7 @@ import {
} from "@/components/ui/form";
import { Input } from "@/components/ui/input";
import { setCustomization } from "@/lib/api";
-import { useEffect } from "react";
-import toast from "react-hot-toast";
+import { toast } from "sonner";
import ColorProvider from "../ColorProvider";
const FormSchema = z.object({
diff --git a/src/components/misc/DiscordPopover.tsx b/src/components/misc/DiscordPopover.tsx
index 195bce1..814d885 100644
--- a/src/components/misc/DiscordPopover.tsx
+++ b/src/components/misc/DiscordPopover.tsx
@@ -47,7 +47,7 @@ import { Input } from "@/components/ui/input";
import { setCustomization } from "@/lib/api";
import { useEffect, useState } from "react";
import ColorProvider from "../ColorProvider";
-import toast from "react-hot-toast";
+import { toast } from "sonner";
const FormSchema = z.object({
id: z.string().min(2, {
diff --git a/src/components/misc/LinkDialog.tsx b/src/components/misc/LinkDialog.tsx
index 745605d..36a3892 100644
--- a/src/components/misc/LinkDialog.tsx
+++ b/src/components/misc/LinkDialog.tsx
@@ -49,7 +49,7 @@ import {
InputOTPSlot,
} from "@/components/ui/input-otp";
import { linkMCAccount } from "@/lib/api";
-import toast from "react-hot-toast";
+import { toast } from "sonner";
import {
Dialog,
DialogContent,
diff --git a/src/components/misc/StickyTopbar.tsx b/src/components/misc/StickyTopbar.tsx
new file mode 100644
index 0000000..84558fe
--- /dev/null
+++ b/src/components/misc/StickyTopbar.tsx
@@ -0,0 +1,68 @@
+/*
+ * MHSF, Minehut Server List
+ * All external content is rather licensed under the ECA Agreement
+ * located here: https://mhsf.app/docs/legal/external-content-agreement
+ *
+ * All code under MHSF is licensed under the MIT License
+ * by open source contributors
+ *
+ * Copyright (c) 2024 dvelo
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+"use client";
+
+import { useEffect, useState, ReactNode } from "react";
+
+export default function StickyTopbar({
+ children,
+ scrollElevation,
+ className,
+}: {
+ children: ReactNode;
+ scrollElevation: number;
+ className?: string;
+}) {
+ const [isSticky, setIsSticky] = useState(false);
+
+ const handleScroll = () => {
+ if (window.scrollY > scrollElevation) {
+ setIsSticky(true);
+ } else {
+ setIsSticky(false);
+ }
+ };
+
+ useEffect(() => {
+ window.addEventListener("scroll", handleScroll);
+ return () => {
+ window.removeEventListener("scroll", handleScroll);
+ };
+ }, []);
+
+ return (
+
+ {children}
+
+ );
+}
diff --git a/src/components/misc/TextCopyComp.tsx b/src/components/misc/TextCopyComp.tsx
index b004d2c..dc2d85f 100644
--- a/src/components/misc/TextCopyComp.tsx
+++ b/src/components/misc/TextCopyComp.tsx
@@ -31,7 +31,7 @@
"use client";
import { useState } from "react";
import { Button } from "../ui/button";
-import toast from "react-hot-toast";
+import { toast } from "sonner";
import { Check } from "lucide-react";
import useClipboard from "@/lib/useClipboard";
diff --git a/src/components/misc/ThemedToaster.tsx b/src/components/misc/ThemedToaster.tsx
index be18dc4..9771f60 100644
--- a/src/components/misc/ThemedToaster.tsx
+++ b/src/components/misc/ThemedToaster.tsx
@@ -31,20 +31,10 @@
"use client";
import { useTheme } from "next-themes";
-import { Toaster } from "react-hot-toast";
+import { Toaster } from "../ui/sonner";
export default function ThemedToaster() {
const { resolvedTheme } = useTheme();
- return (
-
- );
+ return ;
}
diff --git a/src/components/ui/sonner.tsx b/src/components/ui/sonner.tsx
new file mode 100644
index 0000000..452f4d9
--- /dev/null
+++ b/src/components/ui/sonner.tsx
@@ -0,0 +1,31 @@
+"use client"
+
+import { useTheme } from "next-themes"
+import { Toaster as Sonner } from "sonner"
+
+type ToasterProps = React.ComponentProps
+
+const Toaster = ({ ...props }: ToasterProps) => {
+ const { theme = "system" } = useTheme()
+
+ return (
+
+ )
+}
+
+export { Toaster }
diff --git a/src/components/ui/tabs.tsx b/src/components/ui/tabs.tsx
index aca78dc..3c703eb 100644
--- a/src/components/ui/tabs.tsx
+++ b/src/components/ui/tabs.tsx
@@ -59,7 +59,7 @@ const TabsTrigger = React.forwardRef<
) => JSX.Element;
+ }[];
+}[] = [];
diff --git a/src/lib/list.ts b/src/lib/list.ts
index 8f443ca..c72eaab 100644
--- a/src/lib/list.ts
+++ b/src/lib/list.ts
@@ -29,7 +29,7 @@
*/
import { OnlineServer } from "./types/mh-server";
-import toast from "react-hot-toast";
+import { toast } from "sonner";
import { getMOTDFromServer } from "./api";
var numberOfItemsInView = 20;
diff --git a/src/lib/single.ts b/src/lib/single.ts
index 2390297..2158e9e 100644
--- a/src/lib/single.ts
+++ b/src/lib/single.ts
@@ -30,7 +30,7 @@
import { serverOwned } from "./api";
import { OnlineServer, ServerResponse } from "./types/mh-server";
-import toast from "react-hot-toast";
+import { toast } from "sonner";
export default class ServerSingle {
private name = "";
diff --git a/src/lib/useClipboard.ts b/src/lib/useClipboard.ts
index 9585f86..63d8a63 100644
--- a/src/lib/useClipboard.ts
+++ b/src/lib/useClipboard.ts
@@ -28,7 +28,7 @@
* OTHER DEALINGS IN THE SOFTWARE.
*/
-import toast from "react-hot-toast"
+import { toast } from "sonner";
/** A hook to properly write text to the clipboard without triggering a client-side error
* @version 1.0
diff --git a/tailwind.config.ts b/tailwind.config.ts
index ba88528..6cb7b00 100644
--- a/tailwind.config.ts
+++ b/tailwind.config.ts
@@ -31,177 +31,186 @@
import type { Config } from "tailwindcss";
const config = {
- darkMode: ["class"],
- content: [
- "./pages/**/*.{ts,tsx}",
- "./components/**/*.{ts,tsx}",
- "./app/**/*.{ts,tsx}",
- "./src/**/*.{ts,tsx,json}",
- ],
- prefix: "",
- theme: {
- container: {
- center: true,
- padding: "2rem",
- screens: {
- "2xl": "1400px",
- },
- },
- extend: {
- colors: {
- border: "hsl(var(--border))",
- input: "hsl(var(--input))",
- ring: "hsl(var(--ring))",
- background: "hsl(var(--background))",
- foreground: "hsl(var(--foreground))",
- primary: {
- DEFAULT: "hsl(var(--primary))",
- foreground: "hsl(var(--primary-foreground))",
- },
- secondary: {
- DEFAULT: "hsl(var(--secondary))",
- foreground: "hsl(var(--secondary-foreground))",
- },
- destructive: {
- DEFAULT: "hsl(var(--destructive))",
- foreground: "hsl(var(--destructive-foreground))",
- },
- muted: {
- DEFAULT: "hsl(var(--muted))",
- foreground: "hsl(var(--muted-foreground))",
- },
- accent: {
- DEFAULT: "hsl(var(--accent))",
- foreground: "hsl(var(--accent-foreground))",
- },
- popover: {
- DEFAULT: "hsl(var(--popover))",
- foreground: "hsl(var(--popover-foreground))",
- },
- card: {
- DEFAULT: "hsl(var(--card))",
- foreground: "hsl(var(--card-foreground))",
- },
- sidebar: {
- DEFAULT: "hsl(var(--sidebar-background))",
- foreground: "hsl(var(--sidebar-foreground))",
- primary: "hsl(var(--sidebar-primary))",
- "primary-foreground": "hsl(var(--sidebar-primary-foreground))",
- accent: "hsl(var(--sidebar-accent))",
- "accent-foreground": "hsl(var(--sidebar-accent-foreground))",
- border: "hsl(var(--sidebar-border))",
- ring: "hsl(var(--sidebar-ring))",
- mhsf: "hsl(var(--sidebar-mhsf))",
- },
- },
- borderRadius: {
- lg: "var(--radius)",
- md: "calc(var(--radius) - 2px)",
- sm: "calc(var(--radius) - 4px)",
- },
- keyframes: {
- "image-glow": {
- "0%": {
- opacity: "0",
- "animation-timing-function": "cubic-bezier(0.74, 0.25, 0.76, 1)",
- },
- "10%": {
- opacity: "0.7",
- "animation-timing-function": "cubic-bezier(0.12, 0.01, 0.08, 0.99)",
- },
- "100%": {
- opacity: "0.4",
- },
- },
- "border-beam": {
- "100%": {
- "offset-distance": "100%",
- },
- },
- "caret-blink": {
- "0%,70%,100%": {
- opacity: "1",
- },
- "20%,50%": {
- opacity: "0",
- },
- },
- "accordion-down": {
- from: {
- height: "0",
- },
- to: {
- height: "var(--radix-accordion-content-height)",
- },
- },
- "accordion-up": {
- from: {
- height: "var(--radix-accordion-content-height)",
- },
- to: {
- height: "0",
- },
- },
- "fade-in": {
- from: {
- opacity: "0",
- transform: "translateY(-10px)",
- },
- to: {
- opacity: "1",
- transform: "none",
- },
- },
- marquee: {
- from: {
- transform: "translateX(0)",
- },
- to: {
- transform: "translateX(calc(-100% - var(--gap)))",
- },
- },
- "marquee-vertical": {
- from: {
- transform: "translateY(0)",
- },
- to: {
- transform: "translateY(calc(-100% - var(--gap)))",
- },
- },
- "fade-up": {
- from: {
- opacity: "0",
- transform: "translateY(20px)",
- },
- to: {
- opacity: "1",
- transform: "none",
- },
- },
- shimmer: {
- "0%, 90%, 100%": {
- "background-position": "calc(-100% - var(--shimmer-width)) 0",
- },
- "30%, 60%": {
- "background-position": "calc(100% + var(--shimmer-width)) 0",
- },
- },
- },
- animation: {
- marquee: "marquee var(--duration) linear infinite",
- "marquee-vertical": "marquee-vertical var(--duration) linear infinite",
- "accordion-down": "accordion-down 0.2s ease-out",
- "accordion-up": "accordion-up 0.2s ease-out",
- "image-glow": "image-glow 4100ms 600ms ease-out forwards",
- shimmer: "shimmer 8s infinite",
- "fade-in": "fade-in 1000ms var(--animation-delay, 0ms) ease forwards",
- "caret-blink": "caret-blink 1.25s ease-out infinite",
- "border-beam": "border-beam calc(var(--duration)*1s) infinite linear",
- "fade-up": "fade-up 1000ms var(--animation-delay, 0ms) ease forwards",
- },
- },
- },
- plugins: [require("tailwindcss-animate"), require("@tailwindcss/typography")],
+ darkMode: ["class"],
+ content: [
+ "./pages/**/*.{ts,tsx}",
+ "./components/**/*.{ts,tsx}",
+ "./app/**/*.{ts,tsx}",
+ "./src/**/*.{ts,tsx,json}",
+ ],
+ prefix: "",
+ theme: {
+ container: {
+ center: true,
+ padding: "2rem",
+ screens: {
+ "2xl": "1400px",
+ },
+ },
+ extend: {
+ colors: {
+ border: "hsl(var(--border))",
+ input: "hsl(var(--input))",
+ ring: "hsl(var(--ring))",
+ background: "hsl(var(--background))",
+ foreground: "hsl(var(--foreground))",
+ primary: {
+ DEFAULT: "hsl(var(--primary))",
+ foreground: "hsl(var(--primary-foreground))",
+ },
+ secondary: {
+ DEFAULT: "hsl(var(--secondary))",
+ foreground: "hsl(var(--secondary-foreground))",
+ },
+ destructive: {
+ DEFAULT: "hsl(var(--destructive))",
+ foreground: "hsl(var(--destructive-foreground))",
+ },
+ muted: {
+ DEFAULT: "hsl(var(--muted))",
+ foreground: "hsl(var(--muted-foreground))",
+ },
+ accent: {
+ DEFAULT: "hsl(var(--accent))",
+ foreground: "hsl(var(--accent-foreground))",
+ },
+ popover: {
+ DEFAULT: "hsl(var(--popover))",
+ foreground: "hsl(var(--popover-foreground))",
+ },
+ card: {
+ DEFAULT: "hsl(var(--card))",
+ foreground: "hsl(var(--card-foreground))",
+ },
+ sidebar: {
+ DEFAULT: "hsl(var(--sidebar-background))",
+ foreground: "hsl(var(--sidebar-foreground))",
+ primary: "hsl(var(--sidebar-primary))",
+ "primary-foreground": "hsl(var(--sidebar-primary-foreground))",
+ accent: "hsl(var(--sidebar-accent))",
+ "accent-foreground": "hsl(var(--sidebar-accent-foreground))",
+ border: "hsl(var(--sidebar-border))",
+ ring: "hsl(var(--sidebar-ring))",
+ mhsf: "hsl(var(--sidebar-mhsf))",
+ },
+ },
+ borderRadius: {
+ lg: "var(--radius)",
+ md: "calc(var(--radius) - 2px)",
+ sm: "calc(var(--radius) - 4px)",
+ },
+ keyframes: {
+ "image-glow": {
+ "0%": {
+ opacity: "0",
+ "animation-timing-function": "cubic-bezier(0.74, 0.25, 0.76, 1)",
+ },
+ "10%": {
+ opacity: "0.7",
+ "animation-timing-function": "cubic-bezier(0.12, 0.01, 0.08, 0.99)",
+ },
+ "100%": {
+ opacity: "0.4",
+ },
+ },
+ "border-beam": {
+ "100%": {
+ "offset-distance": "100%",
+ },
+ },
+ "caret-blink": {
+ "0%,70%,100%": {
+ opacity: "1",
+ },
+ "20%,50%": {
+ opacity: "0",
+ },
+ },
+ "accordion-down": {
+ from: {
+ height: "0",
+ },
+ to: {
+ height: "var(--radix-accordion-content-height)",
+ },
+ },
+ "accordion-up": {
+ from: {
+ height: "var(--radix-accordion-content-height)",
+ },
+ to: {
+ height: "0",
+ },
+ },
+ "fade-in": {
+ from: {
+ opacity: "0",
+ transform: "translateY(-10px)",
+ },
+ to: {
+ opacity: "1",
+ transform: "none",
+ },
+ },
+ marquee: {
+ from: {
+ transform: "translateX(0)",
+ },
+ to: {
+ transform: "translateX(calc(-100% - var(--gap)))",
+ },
+ },
+ "marquee-vertical": {
+ from: {
+ transform: "translateY(0)",
+ },
+ to: {
+ transform: "translateY(calc(-100% - var(--gap)))",
+ },
+ },
+ "fade-up": {
+ from: {
+ opacity: "0",
+ transform: "translateY(20px)",
+ },
+ to: {
+ opacity: "1",
+ transform: "none",
+ },
+ },
+ spinner: {
+ "0%": {
+ opacity: "1",
+ },
+ "100%": {
+ opacity: "0",
+ },
+ },
+ shimmer: {
+ "0%, 90%, 100%": {
+ "background-position": "calc(-100% - var(--shimmer-width)) 0",
+ },
+ "30%, 60%": {
+ "background-position": "calc(100% + var(--shimmer-width)) 0",
+ },
+ },
+ },
+ animation: {
+ marquee: "marquee var(--duration) linear infinite",
+ "marquee-vertical": "marquee-vertical var(--duration) linear infinite",
+ "accordion-down": "accordion-down 0.2s ease-out",
+ "accordion-up": "accordion-up 0.2s ease-out",
+ "image-glow": "image-glow 4100ms 600ms ease-out forwards",
+ shimmer: "shimmer 8s infinite",
+ spinner: "spinner 1.2s linear infinite",
+ "fade-in": "fade-in 1000ms var(--animation-delay, 0ms) ease forwards",
+ "caret-blink": "caret-blink 1.25s ease-out infinite",
+ "border-beam": "border-beam calc(var(--duration)*1s) infinite linear",
+ "fade-up": "fade-up 1000ms var(--animation-delay, 0ms) ease forwards",
+ },
+ },
+ },
+ plugins: [require("tailwindcss-animate"), require("@tailwindcss/typography")],
} satisfies Config;
export default config;
diff --git a/yarn.lock b/yarn.lock
index db00a94..6048c79 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -4322,9 +4322,9 @@ globby@^11.1.0:
slash "^3.0.0"
goober@^2.1.10:
- version "2.1.14"
- resolved "https://registry.npmjs.org/goober/-/goober-2.1.14.tgz"
- integrity sha512-4UpC0NdGyAFqLNPnhCT2iHpza2q+RAY3GV85a/mRPdzyPQMsj0KmMMuetdIkzWRbJ+Hgau1EZztq8ImmiMGhsg==
+ version "2.1.16"
+ resolved "https://registry.yarnpkg.com/goober/-/goober-2.1.16.tgz#7d548eb9b83ff0988d102be71f271ca8f9c82a95"
+ integrity sha512-erjk19y1U33+XAMe1VTvIONHYoSqE4iS7BYUZfHaqeohLmnC0FdxEh7rQU+6MZ4OajItzjZFSRtVANrQwNq6/g==
gopd@^1.0.1:
version "1.0.1"
@@ -6344,10 +6344,10 @@ next-css-obfuscator@^2.2.16:
recoverable-random "^1.0.5"
yargs "^17.7.2"
-next-themes@^0.3.0:
- version "0.3.0"
- resolved "https://registry.npmjs.org/next-themes/-/next-themes-0.3.0.tgz"
- integrity sha512-/QHIrsYpd6Kfk7xakK4svpDI5mmXP0gfvCoJdGpZQ2TOrQZmsW0QxjaiLn8wbIKjtm4BTSqLoix4lxYYOnLJ/w==
+next-themes@^0.4.3:
+ version "0.4.3"
+ resolved "https://registry.yarnpkg.com/next-themes/-/next-themes-0.4.3.tgz#ea54552d5986936d177eed393ea50b658ae44800"
+ integrity sha512-nG84VPkTdUHR2YeD89YchvV4I9RbiMAql3GiLEQlPvq1ioaqPaIReK+yMRdg/zgiXws620qS1rU30TiWmmG9lA==
next@14.2.10:
version "14.2.10"
@@ -6890,7 +6890,7 @@ react-hook-form@^7.52.2:
react-hot-toast@^2.4.1:
version "2.4.1"
- resolved "https://registry.npmjs.org/react-hot-toast/-/react-hot-toast-2.4.1.tgz"
+ resolved "https://registry.yarnpkg.com/react-hot-toast/-/react-hot-toast-2.4.1.tgz#df04295eda8a7b12c4f968e54a61c8d36f4c0994"
integrity sha512-j8z+cQbWIM5LY37pR6uZR6D4LfseplqnuAO4co4u8917hBUvXlEqyP1ZzqVLcqoyUesZZv/ImreoCeHVDpE5pQ==
dependencies:
goober "^2.1.10"
@@ -7422,6 +7422,11 @@ snakecase-keys@5.4.4:
snake-case "^3.0.4"
type-fest "^2.5.2"
+sonner@^1.7.0:
+ version "1.7.0"
+ resolved "https://registry.yarnpkg.com/sonner/-/sonner-1.7.0.tgz#f59a2a70e049a179b6fbd1bb1bf2619d5ced07c0"
+ integrity sha512-W6dH7m5MujEPyug3lpI2l3TC3Pp1+LTgK0Efg+IHDrBbtEjyCmCHHo6yfNBOsf1tFZ6zf+jceWwB38baC8yO9g==
+
source-map-js@^1.0.1, source-map-js@^1.0.2, source-map-js@^1.2.0:
version "1.2.0"
resolved "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz"
From e45d8f0a705637a3e377b837dcdc255e3d51cb90 Mon Sep 17 00:00:00 2001
From: dvelo <52332868+DeveloLongScript@users.noreply.github.com>
Date: Sat, 23 Nov 2024 17:59:09 -0600
Subject: [PATCH 3/3] fix: react-related issues
---
src/components/CommandBar.tsx | 3 ++-
src/components/ServerList.tsx | 5 ++++-
2 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/src/components/CommandBar.tsx b/src/components/CommandBar.tsx
index 272f5e9..7a973e5 100644
--- a/src/components/CommandBar.tsx
+++ b/src/components/CommandBar.tsx
@@ -80,6 +80,7 @@ import {
import { TagShower } from "./ServerList";
import { Button } from "./ui/button";
import { useTheme } from "next-themes";
+import { CheckmarkIcon } from "react-hot-toast";
export function SearchCommandBar() {
const [serverList, setServerList] = useState([]);
@@ -278,7 +279,7 @@ export function OfflineServerCB() {
{customized && (
-
+
Is customized by a MHSF User
diff --git a/src/components/ServerList.tsx b/src/components/ServerList.tsx
index 658974b..7be0585 100644
--- a/src/components/ServerList.tsx
+++ b/src/components/ServerList.tsx
@@ -1177,7 +1177,10 @@ export default function ServerList() {
{affiliates
.filter((a) => a.mode.includes("server-list"))
.map((a) => (
-