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..7a973e5 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, @@ -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/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}

-

- {motd && ( - - )} -

-
-
- - Joins Chart - - + return ( + { + if (open && isSignedIn) + isFavorited(b.name).then((c) => { + setFavoriteStar(c); + setFavoriteLoading(false); + }); + }} + > + + + + + + + + + + + + + +
+
+

{b.name}

+

+ {motd && ( + + )} +

+
+
+ + Joins Chart + + -
- - - Open Server Page - -
-
- - - Running on{" "} - {b.staticInfo.serverPlan == undefined - ? "Free Plan" - : b.staticInfo.serverPlan} - -
-
-
-
-
-
- - - - - - - Actions - - - - - - - - {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 + + + + + + + + {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} + + - - - <> - - - - - - - - - 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 - - - - ); + + + <> + + + + + + + + + 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 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: -
-
-