mirror of
https://github.com/DeveloLongScript/MHSF.git
synced 2026-05-07 18:44:59 -05:00
feat: new auto-link redirect
This commit is contained in:
parent
9b5d149b35
commit
2589552592
@ -40,7 +40,7 @@ export default function RootLayout({
|
|||||||
const pathname = usePathname();
|
const pathname = usePathname();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<span className="pt-[48px]">
|
<span className="pt-[48px] ">
|
||||||
<Sidebar curPage={pathname as string}>{children}</Sidebar>
|
<Sidebar curPage={pathname as string}>{children}</Sidebar>
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -85,7 +85,7 @@ export default function Settings() {
|
|||||||
<br />
|
<br />
|
||||||
<strong className="font-bold">Unlink Account</strong>
|
<strong className="font-bold">Unlink Account</strong>
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
<p>Unlink your Minecraft acconut if you have already linked one.</p>
|
<p>Unlink your Minecraft account if you have already linked one.</p>
|
||||||
|
|
||||||
{!linked && (
|
{!linked && (
|
||||||
<Button className="h-[30px] ml-2" disabled>
|
<Button className="h-[30px] ml-2" disabled>
|
||||||
|
|||||||
@ -43,6 +43,7 @@ import type { Metadata, Viewport } from "next";
|
|||||||
import { Inter as interFont } from "next/font/google";
|
import { Inter as interFont } from "next/font/google";
|
||||||
import LayoutPart from "@/components/feat/LayoutPart";
|
import LayoutPart from "@/components/feat/LayoutPart";
|
||||||
import AllBanners from "@/components/feat/AllBanners";
|
import AllBanners from "@/components/feat/AllBanners";
|
||||||
|
import Footer from "@/components/misc/Footer";
|
||||||
|
|
||||||
export const extraMetadata = {
|
export const extraMetadata = {
|
||||||
twitter: {
|
twitter: {
|
||||||
@ -84,6 +85,7 @@ export default async function RootLayout({
|
|||||||
<Analytics />
|
<Analytics />
|
||||||
<NewDomainDialog />
|
<NewDomainDialog />
|
||||||
<UnofficalDialog />
|
<UnofficalDialog />
|
||||||
|
<Footer />
|
||||||
</TooltipProvider>
|
</TooltipProvider>
|
||||||
</ThemeProvider>
|
</ThemeProvider>
|
||||||
</ClerkThemeProvider>
|
</ClerkThemeProvider>
|
||||||
|
|||||||
@ -132,16 +132,18 @@ export default function ServerPage({ params }: { params: { server: string } }) {
|
|||||||
<ColorProvider server={params.server}>
|
<ColorProvider server={params.server}>
|
||||||
<div className={"pt-[300px] xl:px-[100px]"}>
|
<div className={"pt-[300px] xl:px-[100px]"}>
|
||||||
<Banner server={params.server} />
|
<Banner server={params.server} />
|
||||||
<div className="pt-8 z-10 relative">
|
<div className="pt-8 z-8 relative">
|
||||||
<ServerView server={params.server} />
|
<ServerView server={params.server} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<StickyTopbar scrollElevation={100} className="pt-4">
|
<StickyTopbar scrollElevation={100} className="pt-4 z-10">
|
||||||
<TabServer server={params.server} tabDef="general" />
|
<TabServer server={params.server} tabDef="general" />
|
||||||
</StickyTopbar>
|
</StickyTopbar>
|
||||||
<br />
|
<br />
|
||||||
|
<div className="z-8 relative">
|
||||||
<AfterServerView server={params.server} />
|
<AfterServerView server={params.server} />
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</ColorProvider>
|
</ColorProvider>
|
||||||
</main>
|
</main>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -118,7 +118,7 @@ export default function AfterServerView({ server }: { server: string }) {
|
|||||||
<QRCodeGenerator server={server} />
|
<QRCodeGenerator server={server} />
|
||||||
</DrawerContent>
|
</DrawerContent>
|
||||||
</Drawer>
|
</Drawer>
|
||||||
<FadeIn className="relative z-10">
|
<FadeIn className="relative z-8">
|
||||||
<div className="grid sm:grid-cols-6 h-full pl-4 pr-4 ">
|
<div className="grid sm:grid-cols-6 h-full pl-4 pr-4 ">
|
||||||
<div className="ml-5 mb-2 flex items-center sm:hidden overflow-auto w-[calc(100vw-5rem)]">
|
<div className="ml-5 mb-2 flex items-center sm:hidden overflow-auto w-[calc(100vw-5rem)]">
|
||||||
{(description != "" || discord != "") && (
|
{(description != "" || discord != "") && (
|
||||||
|
|||||||
@ -29,28 +29,48 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { getCustomization } from "@/lib/api";
|
import { getCustomization } from "@/lib/api";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import "@/themes.css";
|
import "@/themes.css";
|
||||||
|
import { toast } from "sonner";
|
||||||
|
import { useRouter } from "@/lib/useRouter";
|
||||||
|
import { useEffectOnce } from "@/lib/useEffectOnce";
|
||||||
|
|
||||||
export default function ColorProvider({
|
export default function ColorProvider({
|
||||||
server,
|
server,
|
||||||
children,
|
children,
|
||||||
fetch,
|
fetchV,
|
||||||
}: {
|
}: {
|
||||||
server: string;
|
server: string;
|
||||||
children: any;
|
children: any;
|
||||||
fetch?: any;
|
fetchV?: any;
|
||||||
}) {
|
}) {
|
||||||
const [color, setColor] = useState("zinc");
|
const [color, setColor] = useState("zinc");
|
||||||
|
const nav = useRouter();
|
||||||
|
|
||||||
|
useEffectOnce(() => {
|
||||||
|
fetch("https://api.minehut.com/server/" + server + "?byName=true")
|
||||||
|
.then((c) => c.json())
|
||||||
|
.then((c: any) => {
|
||||||
|
console.log(c.server.name, server);
|
||||||
|
if (c.server.name !== server) {
|
||||||
|
toast.warning(
|
||||||
|
"The capitalization of this server was incorrect. If your using a permanent link resource, please change it to account for a new name. (" +
|
||||||
|
c.server.name +
|
||||||
|
") Redirecting now.",
|
||||||
|
{ duration: 15000 }
|
||||||
|
);
|
||||||
|
nav.replace("/server/" + c.server.name);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!fetch)
|
if (!fetchV)
|
||||||
getCustomization(server).then((v) =>
|
getCustomization(server).then((v) =>
|
||||||
setColor(v != null ? v.colorScheme : "zinc")
|
setColor(v != null ? v.colorScheme : "zinc")
|
||||||
);
|
);
|
||||||
else setColor(fetch.colorScheme);
|
else setColor(fetchV.colorScheme);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return <div className={`theme-${color}`}>{children}</div>;
|
return <div className={`theme-${color}`}>{children}</div>;
|
||||||
|
|||||||
@ -50,7 +50,7 @@ export function Sidebar({
|
|||||||
return (
|
return (
|
||||||
<ResizablePanelGroup
|
<ResizablePanelGroup
|
||||||
direction="horizontal"
|
direction="horizontal"
|
||||||
className="min-h-[calc(100vh-70px)] pt-[70px]"
|
className="min-h-[calc(100vh-70px)] pt-[70px] xl:px-[100px] "
|
||||||
>
|
>
|
||||||
<ResizablePanel className="max-md:hidden min-w-[285px] max-w-[285px] w-[285px]">
|
<ResizablePanel className="max-md:hidden min-w-[285px] max-w-[285px] w-[285px]">
|
||||||
<div className="w-[300px] ml-[10px]">
|
<div className="w-[300px] ml-[10px]">
|
||||||
|
|||||||
@ -49,7 +49,13 @@ import {
|
|||||||
} from "./ui/card";
|
} from "./ui/card";
|
||||||
import { TooltipContent, TooltipTrigger } from "./ui/tooltip";
|
import { TooltipContent, TooltipTrigger } from "./ui/tooltip";
|
||||||
|
|
||||||
export default function ServerCard({ b, motd, mini, favs }: any) {
|
export default function ServerCard({
|
||||||
|
b,
|
||||||
|
motd,
|
||||||
|
mini,
|
||||||
|
favs,
|
||||||
|
selectedProperties,
|
||||||
|
}: any) {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const clipboard = useClipboard();
|
const clipboard = useClipboard();
|
||||||
const [favoriteStar, setFavoriteStar] = useState(false);
|
const [favoriteStar, setFavoriteStar] = useState(false);
|
||||||
@ -165,17 +171,21 @@ export default function ServerCard({ b, motd, mini, favs }: any) {
|
|||||||
</DrawerFooter>
|
</DrawerFooter>
|
||||||
</DrawerContent>
|
</DrawerContent>
|
||||||
</Drawer>
|
</Drawer>
|
||||||
{b.author != undefined ? (
|
|
||||||
|
{selectedProperties.includes("Author") &&
|
||||||
|
b.author != undefined ? (
|
||||||
<div className="text-sm text-muted-foreground font-normal tracking-normal">
|
<div className="text-sm text-muted-foreground font-normal tracking-normal">
|
||||||
by {b.author}
|
by {b.author}
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<br />
|
<br />
|
||||||
)}
|
)}
|
||||||
<TagShower server={b} />
|
{selectedProperties.includes("Tags") && <TagShower server={b} />}
|
||||||
</CardTitle>
|
</CardTitle>
|
||||||
<CardDescription className="float-left inline ">
|
<CardDescription className="float-left inline ">
|
||||||
<span className="flex items-center">
|
<span className="flex items-center">
|
||||||
|
{selectedProperties.includes("Players Online") && (
|
||||||
|
<>
|
||||||
{b.playerData.playerCount == 0 ? (
|
{b.playerData.playerCount == 0 ? (
|
||||||
<div
|
<div
|
||||||
className="items-center border"
|
className="items-center border"
|
||||||
@ -196,14 +206,19 @@ export default function ServerCard({ b, motd, mini, favs }: any) {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{selectedProperties.includes("Players Online") && (
|
||||||
<span className="pl-1">
|
<span className="pl-1">
|
||||||
{b.playerData.playerCount}{" "}
|
{b.playerData.playerCount}{" "}
|
||||||
{b.playerData.playerCount == 1 ? "player" : "players"}{" "}
|
{b.playerData.playerCount == 1 ? "player" : "players"}{" "}
|
||||||
currently online {favs && <>• {favs} favorited</>}
|
currently online {favs && <>• {favs} favorited</>}
|
||||||
</span>
|
</span>
|
||||||
|
)}
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
|
{selectedProperties.includes("Actions") && (
|
||||||
<ContextMenu>
|
<ContextMenu>
|
||||||
<ContextMenuTrigger>
|
<ContextMenuTrigger>
|
||||||
<>
|
<>
|
||||||
@ -256,9 +271,10 @@ export default function ServerCard({ b, motd, mini, favs }: any) {
|
|||||||
</Link>
|
</Link>
|
||||||
</ContextMenuContent>
|
</ContextMenuContent>
|
||||||
</ContextMenu>
|
</ContextMenu>
|
||||||
|
)}
|
||||||
</CardDescription>
|
</CardDescription>
|
||||||
<CardContent>
|
<CardContent className="p-0">
|
||||||
{motd && (
|
{motd && selectedProperties.includes("MOTD") && (
|
||||||
<span
|
<span
|
||||||
dangerouslySetInnerHTML={{ __html: motd }}
|
dangerouslySetInnerHTML={{ __html: motd }}
|
||||||
className="w-[30px] text-center break-all overflow-hidden"
|
className="w-[30px] text-center break-all overflow-hidden"
|
||||||
|
|||||||
@ -44,34 +44,16 @@ import {
|
|||||||
AllCommunityModule,
|
AllCommunityModule,
|
||||||
ModuleRegistry,
|
ModuleRegistry,
|
||||||
colorSchemeDarkBlue,
|
colorSchemeDarkBlue,
|
||||||
colorSchemeDarkWarm,
|
|
||||||
colorSchemeLightCold,
|
|
||||||
colorSchemeLightWarm,
|
colorSchemeLightWarm,
|
||||||
themeQuartz,
|
themeQuartz,
|
||||||
} from "ag-grid-community";
|
} from "ag-grid-community";
|
||||||
import {
|
|
||||||
Menubar,
|
|
||||||
MenubarCheckboxItem,
|
|
||||||
MenubarContent,
|
|
||||||
MenubarItem,
|
|
||||||
MenubarMenu,
|
|
||||||
MenubarRadioGroup,
|
|
||||||
MenubarRadioItem,
|
|
||||||
MenubarSeparator,
|
|
||||||
MenubarShortcut,
|
|
||||||
MenubarSub,
|
|
||||||
MenubarSubContent,
|
|
||||||
MenubarSubTrigger,
|
|
||||||
MenubarTrigger,
|
|
||||||
} from "@/components/ui/menubar";
|
|
||||||
import { Separator } from "@/components/ui/separator";
|
import { Separator } from "@/components/ui/separator";
|
||||||
import {
|
import {
|
||||||
Tooltip,
|
Tooltip,
|
||||||
TooltipContent,
|
TooltipContent,
|
||||||
TooltipTrigger,
|
TooltipTrigger,
|
||||||
} from "@/components/ui/tooltip";
|
} from "@/components/ui/tooltip";
|
||||||
import { allCategories, allTags } from "@/config/tags";
|
import { allTags } from "@/config/tags";
|
||||||
import events from "@/lib/commandEvent";
|
|
||||||
import ServersList from "@/lib/list";
|
import ServersList from "@/lib/list";
|
||||||
import { OnlineServer } from "@/lib/types/mh-server";
|
import { OnlineServer } from "@/lib/types/mh-server";
|
||||||
import useClipboard from "@/lib/useClipboard";
|
import useClipboard from "@/lib/useClipboard";
|
||||||
@ -81,6 +63,7 @@ import { cn } from "@/lib/utils";
|
|||||||
import { SignedIn, SignedOut, useUser } from "@clerk/nextjs";
|
import { SignedIn, SignedOut, useUser } from "@clerk/nextjs";
|
||||||
import { ChatBubbleIcon, InputIcon } from "@radix-ui/react-icons";
|
import { ChatBubbleIcon, InputIcon } from "@radix-ui/react-icons";
|
||||||
import {
|
import {
|
||||||
|
ArrowDown,
|
||||||
ArrowDownZA,
|
ArrowDownZA,
|
||||||
Check,
|
Check,
|
||||||
CircleUser,
|
CircleUser,
|
||||||
@ -93,7 +76,6 @@ import {
|
|||||||
Sun,
|
Sun,
|
||||||
XIcon,
|
XIcon,
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
import { CommandIcon } from "lucide-react";
|
|
||||||
import { useTheme } from "next-themes";
|
import { useTheme } from "next-themes";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { useEffect, useRef, useState } from "react";
|
import { useEffect, useRef, useState } from "react";
|
||||||
@ -112,12 +94,13 @@ import { pageFind } from "./misc/Link";
|
|||||||
import { Badge } from "./ui/badge";
|
import { Badge } from "./ui/badge";
|
||||||
import { Popover, PopoverContent, PopoverTrigger } from "./ui/popover";
|
import { Popover, PopoverContent, PopoverTrigger } from "./ui/popover";
|
||||||
import { Skeleton } from "./ui/skeleton";
|
import { Skeleton } from "./ui/skeleton";
|
||||||
import { affiliates } from "@/config/affiliates";
|
|
||||||
import { LoadingSpinner } from "./ui/loading-spinner";
|
import { LoadingSpinner } from "./ui/loading-spinner";
|
||||||
import StickyTopbar from "./misc/StickyTopbar";
|
import StickyTopbar from "./misc/StickyTopbar";
|
||||||
import { HoverCard } from "@radix-ui/react-hover-card";
|
import { HoverCard } from "@radix-ui/react-hover-card";
|
||||||
import { HoverCardTrigger } from "./ui/hover-card";
|
import { HoverCardTrigger } from "./ui/hover-card";
|
||||||
import { ExampleChart } from "./charts/ExampleChart";
|
import { ExampleChart } from "./charts/ExampleChart";
|
||||||
|
import ServerListInterface from "./misc/ServerListInterface";
|
||||||
|
import NoItems from "./misc/NoItems";
|
||||||
|
|
||||||
// ag-grid
|
// ag-grid
|
||||||
ModuleRegistry.registerModules([AllCommunityModule]);
|
ModuleRegistry.registerModules([AllCommunityModule]);
|
||||||
@ -184,16 +167,23 @@ export default function ServerList() {
|
|||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { user, isSignedIn } = useUser();
|
const { user, isSignedIn } = useUser();
|
||||||
const [pOS, setpOS] = useState(false);
|
const [pOS, setpOS] = useState(false);
|
||||||
|
const [selectedProperties, setSelectedProperties] = useState<string[]>([
|
||||||
|
"Author",
|
||||||
|
"MOTD",
|
||||||
|
"Tags",
|
||||||
|
"Players Online",
|
||||||
|
"Actions",
|
||||||
|
]);
|
||||||
const [ipr, setIPR] = useState<string>("4");
|
const [ipr, setIPR] = useState<string>("4");
|
||||||
const [presentationMode, setPresentationMode] = useState<"table" | "grid">(
|
const [presentationMode, setPresentationMode] = useState<"table" | "grid">(
|
||||||
"grid",
|
"grid"
|
||||||
);
|
);
|
||||||
const [am, setAM] = useState(false);
|
const [am, setAM] = useState(false);
|
||||||
const [filters, setFilters] = useState<
|
const [filters, setFilters] = useState<
|
||||||
Array<(server: OnlineServer) => Promise<boolean>>
|
Array<(server: OnlineServer) => Promise<boolean>>
|
||||||
>([]);
|
>([]);
|
||||||
const [randomData, setRandomData] = useState<OnlineServer | undefined>(
|
const [randomData, setRandomData] = useState<OnlineServer | undefined>(
|
||||||
undefined,
|
undefined
|
||||||
);
|
);
|
||||||
const { resolvedTheme } = useTheme();
|
const { resolvedTheme } = useTheme();
|
||||||
const [color, setColor] = useState("#ffffff");
|
const [color, setColor] = useState("#ffffff");
|
||||||
@ -375,7 +365,7 @@ export default function ServerList() {
|
|||||||
className={cn(
|
className={cn(
|
||||||
"relative w-64 cursor-pointer overflow-hidden rounded-xl border no-underline " +
|
"relative w-64 cursor-pointer overflow-hidden rounded-xl border no-underline " +
|
||||||
"border-gray-950/[.1] bg-gray-950/[.01] hover:bg-gray-950/[.05] " +
|
"border-gray-950/[.1] bg-gray-950/[.01] hover:bg-gray-950/[.05] " +
|
||||||
"dark:border-gray-50/[.1] dark:bg-gray-50/[.10] dark:hover:bg-gray-50/[.15]",
|
"dark:border-gray-50/[.1] dark:bg-gray-50/[.10] dark:hover:bg-gray-50/[.15]"
|
||||||
)}
|
)}
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
router.push(pageFind(`Server:${server.name}`))
|
router.push(pageFind(`Server:${server.name}`))
|
||||||
@ -409,7 +399,7 @@ export default function ServerList() {
|
|||||||
className={cn(
|
className={cn(
|
||||||
"relative w-64 cursor-pointer overflow-hidden rounded-xl border no-underline " +
|
"relative w-64 cursor-pointer overflow-hidden rounded-xl border no-underline " +
|
||||||
"border-gray-950/[.1] bg-gray-950/[.01] hover:bg-gray-950/[.05] " +
|
"border-gray-950/[.1] bg-gray-950/[.01] hover:bg-gray-950/[.05] " +
|
||||||
"dark:border-gray-50/[.1] dark:bg-gray-50/[.10] dark:hover:bg-gray-50/[.15]",
|
"dark:border-gray-50/[.1] dark:bg-gray-50/[.10] dark:hover:bg-gray-50/[.15]"
|
||||||
)}
|
)}
|
||||||
onClick={() => router.push(`/server/${server.name}`)}
|
onClick={() => router.push(`/server/${server.name}`)}
|
||||||
>
|
>
|
||||||
@ -464,10 +454,15 @@ export default function ServerList() {
|
|||||||
Monitor your success
|
Monitor your success
|
||||||
</h1>
|
</h1>
|
||||||
<p className="animate-fade-in mb-12 -translate-y-4 text-balance text-lg tracking-tight text-gray-400 opacity-0 [--animation-delay:400ms] md:text-xl">
|
<p className="animate-fade-in mb-12 -translate-y-4 text-balance text-lg tracking-tight text-gray-400 opacity-0 [--animation-delay:400ms] md:text-xl">
|
||||||
Ever wondered how a server was doing? MHSF constantly monitors servers
|
Ever wondered how a server was doing? MHSF constantly monitors
|
||||||
and shows you statistics about how a server is doing at any point of time.
|
servers and shows you statistics about how a server is doing at
|
||||||
|
any point of time.
|
||||||
</p>
|
</p>
|
||||||
<ExampleChart />
|
<ExampleChart />
|
||||||
|
<br className="mb-8" />
|
||||||
|
<span className="text-sm flex items-center justify-center mt-32">
|
||||||
|
<ArrowDown className="mr-2" size={16} /> Check it out below!
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<br />
|
<br />
|
||||||
@ -555,30 +550,51 @@ export default function ServerList() {
|
|||||||
<Separator />
|
<Separator />
|
||||||
<ClientFadeIn delay={100}>
|
<ClientFadeIn delay={100}>
|
||||||
<StickyTopbar scrollElevation={250} className="p-2">
|
<StickyTopbar scrollElevation={250} className="p-2">
|
||||||
<Menubar className="mt-3 border rounded shadow">
|
<ServerListInterface
|
||||||
<MenubarMenu>
|
viewProps={{
|
||||||
<MenubarTrigger>Servers</MenubarTrigger>
|
setPresentationMode,
|
||||||
<MenubarContent>
|
presentationMode,
|
||||||
<MenubarItem
|
selectedProperties,
|
||||||
onSelect={() => events.emit("search-request-event")}
|
setSelectedProperties,
|
||||||
>
|
hero,
|
||||||
Search Servers
|
setHero,
|
||||||
<MenubarShortcut className="flex items-center ml-3">
|
padding,
|
||||||
<CommandIcon size={14} />
|
paddingChangerCallback: (v: any) => {
|
||||||
+Shift+K
|
if (am)
|
||||||
</MenubarShortcut>
|
toast.warning(
|
||||||
</MenubarItem>
|
"These settings will not change over reloads because you have account specific options enabled",
|
||||||
<MenubarItem
|
{
|
||||||
onSelect={() => {
|
action: {
|
||||||
|
label: "Check settings",
|
||||||
|
onClick: () =>
|
||||||
|
router.push("/account/settings/options"),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
setPadding(v);
|
||||||
|
},
|
||||||
|
am,
|
||||||
|
iprChangerCallback: (v: any) => {
|
||||||
|
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);
|
||||||
|
},
|
||||||
|
ipr,
|
||||||
|
}}
|
||||||
|
pickRandomServerCallback={() => {
|
||||||
setRandomData(serverList.getRandomServer());
|
setRandomData(serverList.getRandomServer());
|
||||||
setRandom(true);
|
setRandom(true);
|
||||||
}}
|
}}
|
||||||
>
|
refreshCallback={() => {
|
||||||
Pick Random Server
|
|
||||||
</MenubarItem>
|
|
||||||
<MenubarSeparator />
|
|
||||||
<MenubarItem
|
|
||||||
onSelect={() => {
|
|
||||||
toast.promise(
|
toast.promise(
|
||||||
new Promise((s, e) => {
|
new Promise((s, e) => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
@ -602,11 +618,9 @@ export default function ServerList() {
|
|||||||
|
|
||||||
serverList.getMOTDs(stringList).then((c) => {
|
serverList.getMOTDs(stringList).then((c) => {
|
||||||
var updatedSL = motdList;
|
var updatedSL = motdList;
|
||||||
c.forEach(
|
c.forEach((b: { server: string; motd: string }) => {
|
||||||
(b: { server: string; motd: string }) => {
|
|
||||||
updatedSL[b.server] = b.motd;
|
updatedSL[b.server] = b.motd;
|
||||||
},
|
});
|
||||||
);
|
|
||||||
setMotdList(updatedSL);
|
setMotdList(updatedSL);
|
||||||
setServers(serverList.currentServers);
|
setServers(serverList.currentServers);
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
@ -618,22 +632,107 @@ export default function ServerList() {
|
|||||||
});
|
});
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
success: "Succesfully refreshed servers",
|
success: "Succesfully reloaded servers",
|
||||||
loading: "Refreshing...",
|
loading: "Reloading...",
|
||||||
error: "Error while refreshing",
|
error: "Error while refreshing",
|
||||||
},
|
}
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
>
|
linksProps={{
|
||||||
Refresh
|
templateFilter,
|
||||||
</MenubarItem>
|
tagChangerValueCallback: (tag: any) => {
|
||||||
</MenubarContent>
|
return nameFilters["t-" + tag.docsName];
|
||||||
</MenubarMenu>
|
},
|
||||||
<MenubarMenu>
|
categoryChangerValueCallback: (categorie: any) => {
|
||||||
<MenubarTrigger>Filter</MenubarTrigger>
|
return nameFilters["c-" + categorie.name];
|
||||||
<MenubarContent className="max-h-[400px] overflow-auto">
|
},
|
||||||
<MenubarRadioGroup
|
categoryChangerCallback: (categorie: any) => async (b) => {
|
||||||
onValueChange={(v) => {
|
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 = {};
|
||||||
|
|
||||||
|
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);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
tagChangerCallback: (tag) => 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 = {};
|
||||||
|
|
||||||
|
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);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
serverSizeChangerValueCallback: () => {
|
||||||
|
if (nameFilters["smaller-tf"]) {
|
||||||
|
return "smaller";
|
||||||
|
}
|
||||||
|
if (nameFilters["bigger-tf"]) {
|
||||||
|
return "bigger";
|
||||||
|
}
|
||||||
|
return "none";
|
||||||
|
},
|
||||||
|
serverSizeChangerCallback: (v: any) => {
|
||||||
toast.promise(
|
toast.promise(
|
||||||
new Promise((g, b) => {
|
new Promise((g, b) => {
|
||||||
if (v == "smaller") {
|
if (v == "smaller") {
|
||||||
@ -668,11 +767,9 @@ export default function ServerList() {
|
|||||||
|
|
||||||
serverList.getMOTDs(stringList).then((c) => {
|
serverList.getMOTDs(stringList).then((c) => {
|
||||||
var updatedSL = motdList;
|
var updatedSL = motdList;
|
||||||
c.forEach(
|
c.forEach((b: { server: string; motd: string }) => {
|
||||||
(b: { server: string; motd: string }) => {
|
|
||||||
updatedSL[b.server] = b.motd;
|
updatedSL[b.server] = b.motd;
|
||||||
},
|
});
|
||||||
);
|
|
||||||
setMotdList(updatedSL);
|
setMotdList(updatedSL);
|
||||||
setServers(serverList.currentServers);
|
setServers(serverList.currentServers);
|
||||||
g(undefined);
|
g(undefined);
|
||||||
@ -710,11 +807,9 @@ export default function ServerList() {
|
|||||||
|
|
||||||
serverList.getMOTDs(stringList).then((c) => {
|
serverList.getMOTDs(stringList).then((c) => {
|
||||||
var updatedSL = motdList;
|
var updatedSL = motdList;
|
||||||
c.forEach(
|
c.forEach((b: { server: string; motd: string }) => {
|
||||||
(b: { server: string; motd: string }) => {
|
|
||||||
updatedSL[b.server] = b.motd;
|
updatedSL[b.server] = b.motd;
|
||||||
},
|
});
|
||||||
);
|
|
||||||
setMotdList(updatedSL);
|
setMotdList(updatedSL);
|
||||||
setServers(serverList.currentServers);
|
setServers(serverList.currentServers);
|
||||||
g(undefined);
|
g(undefined);
|
||||||
@ -752,11 +847,9 @@ export default function ServerList() {
|
|||||||
|
|
||||||
serverList.getMOTDs(stringList).then((c) => {
|
serverList.getMOTDs(stringList).then((c) => {
|
||||||
var updatedSL = motdList;
|
var updatedSL = motdList;
|
||||||
c.forEach(
|
c.forEach((b: { server: string; motd: string }) => {
|
||||||
(b: { server: string; motd: string }) => {
|
|
||||||
updatedSL[b.server] = b.motd;
|
updatedSL[b.server] = b.motd;
|
||||||
},
|
});
|
||||||
);
|
|
||||||
setMotdList(updatedSL);
|
setMotdList(updatedSL);
|
||||||
setServers(serverList.currentServers);
|
setServers(serverList.currentServers);
|
||||||
g(undefined);
|
g(undefined);
|
||||||
@ -768,283 +861,11 @@ export default function ServerList() {
|
|||||||
error: "Error while changing filters",
|
error: "Error while changing filters",
|
||||||
loading: "Changing filters...",
|
loading: "Changing filters...",
|
||||||
success: "Changed filters!",
|
success: "Changed filters!",
|
||||||
},
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
value={(() => {
|
|
||||||
if (nameFilters["smaller-tf"]) {
|
|
||||||
return "smaller";
|
|
||||||
} else if (nameFilters["bigger-tf"]) {
|
|
||||||
return "bigger";
|
|
||||||
} else {
|
|
||||||
return "none";
|
|
||||||
}
|
}
|
||||||
})()}
|
|
||||||
>
|
|
||||||
<MenubarRadioItem value="smaller">
|
|
||||||
<div className="block">
|
|
||||||
Only allow smaller servers
|
|
||||||
<br />
|
|
||||||
<span className="text-sm text-muted-foreground">
|
|
||||||
Only allow servers that have the player range 7-15,
|
|
||||||
and cannot <br />
|
|
||||||
be Always Online.
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</MenubarRadioItem>
|
|
||||||
<MenubarRadioItem value="bigger">
|
|
||||||
<div className="block">
|
|
||||||
Only allow bigger servers
|
|
||||||
<br />
|
|
||||||
<span className="text-sm text-muted-foreground">
|
|
||||||
Only allow servers with more than 15 players.
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</MenubarRadioItem>
|
|
||||||
<MenubarRadioItem value="none">
|
|
||||||
No/custom requirements
|
|
||||||
</MenubarRadioItem>
|
|
||||||
</MenubarRadioGroup>
|
|
||||||
<MenubarSeparator />
|
|
||||||
<MenubarSub>
|
|
||||||
<span className="text-sm text-muted-foreground ml-2">
|
|
||||||
Tags
|
|
||||||
</span>
|
|
||||||
</MenubarSub>
|
|
||||||
{allTags.map((tag) => (
|
|
||||||
<div key={tag.docsName}>
|
|
||||||
{tag.docsName && tag.__filter == undefined && (
|
|
||||||
<MenubarCheckboxItem
|
|
||||||
disabled={templateFilter && tag.__disab != undefined}
|
|
||||||
id={tag.docsName}
|
|
||||||
checked={(() => {
|
|
||||||
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 = {};
|
|
||||||
|
|
||||||
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);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Badge variant={tag.role} className="mr-1">
|
|
||||||
{tag.docsName}
|
|
||||||
</Badge>
|
|
||||||
</MenubarCheckboxItem>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
<MenubarSeparator />
|
|
||||||
<MenubarSub>
|
|
||||||
<span className="text-sm text-muted-foreground ml-2">
|
|
||||||
Categories
|
|
||||||
</span>
|
|
||||||
</MenubarSub>
|
|
||||||
{allCategories.map((categorie) => (
|
|
||||||
<MenubarCheckboxItem
|
|
||||||
id={categorie.name}
|
|
||||||
key={categorie.name}
|
|
||||||
onCheckedChange={async (b) => {
|
|
||||||
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 = {};
|
|
||||||
|
|
||||||
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];
|
|
||||||
})()}
|
|
||||||
>
|
|
||||||
<Badge variant={categorie.role} className="mr-1">
|
|
||||||
{categorie.name}
|
|
||||||
</Badge>
|
|
||||||
</MenubarCheckboxItem>
|
|
||||||
))}
|
|
||||||
</MenubarContent>
|
|
||||||
</MenubarMenu>
|
|
||||||
<MenubarMenu>
|
|
||||||
<MenubarTrigger>View</MenubarTrigger>
|
|
||||||
<MenubarContent>
|
|
||||||
<MenubarSub>
|
|
||||||
<MenubarSubTrigger>Mode</MenubarSubTrigger>
|
|
||||||
<MenubarSubContent>
|
|
||||||
<MenubarRadioGroup
|
|
||||||
value={presentationMode}
|
|
||||||
onValueChange={(v) =>
|
|
||||||
setPresentationMode(v as "grid" | "table")
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<MenubarRadioItem value="grid">Grid</MenubarRadioItem>
|
|
||||||
<MenubarRadioItem value="table">Table</MenubarRadioItem>
|
|
||||||
</MenubarRadioGroup>
|
|
||||||
</MenubarSubContent>
|
|
||||||
</MenubarSub>
|
|
||||||
<MenubarSub>
|
|
||||||
<MenubarSubTrigger disabled={presentationMode === "table"} className={presentationMode === "table" ? "text-muted-foreground" : ""}>
|
|
||||||
Grid
|
|
||||||
</MenubarSubTrigger>
|
|
||||||
<MenubarSubContent>
|
|
||||||
<MenubarRadioGroup
|
|
||||||
value={ipr}
|
|
||||||
onValueChange={(v) => {
|
|
||||||
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);
|
|
||||||
}}
|
}}
|
||||||
>
|
/>
|
||||||
<MenubarRadioItem value="4">
|
|
||||||
4 items per row
|
|
||||||
</MenubarRadioItem>
|
|
||||||
<MenubarRadioItem value="5">
|
|
||||||
5 items per row
|
|
||||||
</MenubarRadioItem>
|
|
||||||
<MenubarRadioItem value="6">
|
|
||||||
6 items per row
|
|
||||||
</MenubarRadioItem>
|
|
||||||
</MenubarRadioGroup>
|
|
||||||
</MenubarSubContent>
|
|
||||||
</MenubarSub>
|
|
||||||
<MenubarSub>
|
|
||||||
<MenubarSubTrigger>Padding</MenubarSubTrigger>
|
|
||||||
<MenubarSubContent>
|
|
||||||
<MenubarRadioGroup
|
|
||||||
value={padding.toString()}
|
|
||||||
onValueChange={(v) => {
|
|
||||||
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);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<MenubarRadioItem value="0">Default</MenubarRadioItem>
|
|
||||||
<MenubarSeparator />
|
|
||||||
<MenubarRadioItem value="15">15px</MenubarRadioItem>
|
|
||||||
<MenubarRadioItem value="30">30px</MenubarRadioItem>
|
|
||||||
<MenubarRadioItem value="40">40px</MenubarRadioItem>
|
|
||||||
<MenubarRadioItem value="60">60px</MenubarRadioItem>
|
|
||||||
<MenubarRadioItem value="100">100px</MenubarRadioItem>
|
|
||||||
<MenubarRadioItem value="200">200px</MenubarRadioItem>
|
|
||||||
</MenubarRadioGroup>
|
|
||||||
<MenubarSeparator />
|
|
||||||
<MenubarCheckboxItem
|
|
||||||
checked={pOS}
|
|
||||||
onCheckedChange={setpOS}
|
|
||||||
>
|
|
||||||
Only use padding on servers
|
|
||||||
</MenubarCheckboxItem>
|
|
||||||
</MenubarSubContent>
|
|
||||||
</MenubarSub>
|
|
||||||
<MenubarSeparator />
|
|
||||||
<SignedIn>
|
|
||||||
<MenubarCheckboxItem
|
|
||||||
checked={hero}
|
|
||||||
onCheckedChange={setHero}
|
|
||||||
>
|
|
||||||
Show Hero
|
|
||||||
</MenubarCheckboxItem>
|
|
||||||
</SignedIn>
|
|
||||||
<MenubarItem onClick={() => router.push("/docs")}>
|
|
||||||
View the docs
|
|
||||||
</MenubarItem>
|
|
||||||
{am && (
|
|
||||||
<MenubarItem
|
|
||||||
onClick={() => router.push("/account/settings")}
|
|
||||||
className="block"
|
|
||||||
>
|
|
||||||
Using saved settings in Preferences
|
|
||||||
<br />
|
|
||||||
<span className="text-muted-foreground text-xs">
|
|
||||||
Your using settings stored on your account, that are not
|
|
||||||
temporary.
|
|
||||||
</span>
|
|
||||||
</MenubarItem>
|
|
||||||
)}
|
|
||||||
</MenubarContent>
|
|
||||||
</MenubarMenu>
|
|
||||||
</Menubar>
|
|
||||||
</StickyTopbar>
|
</StickyTopbar>
|
||||||
</ClientFadeIn>
|
</ClientFadeIn>
|
||||||
|
|
||||||
@ -1107,7 +928,7 @@ export default function ServerList() {
|
|||||||
onClick={() => {
|
onClick={() => {
|
||||||
setTextCopied(true);
|
setTextCopied(true);
|
||||||
clipboard.writeText(
|
clipboard.writeText(
|
||||||
randomData.name + ".mshf.minehut.gg",
|
randomData.name + ".mshf.minehut.gg"
|
||||||
);
|
);
|
||||||
toast.success("Copied!");
|
toast.success("Copied!");
|
||||||
setTimeout(() => setTextCopied(false), 1000);
|
setTimeout(() => setTextCopied(false), 1000);
|
||||||
@ -1150,13 +971,9 @@ export default function ServerList() {
|
|||||||
}}
|
}}
|
||||||
loader={<LoadingSpinner className="flex items-center" />}
|
loader={<LoadingSpinner className="flex items-center" />}
|
||||||
endMessage={
|
endMessage={
|
||||||
<p
|
<p style={{ textAlign: "center" }}>
|
||||||
style={{ textAlign: "center" }}
|
<NoItems title="You've scrolled to the very bottom!" />
|
||||||
dangerouslySetInnerHTML={{
|
</p>
|
||||||
__html:
|
|
||||||
randomText + "<br /> <strong>You've seen it all</strong>",
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
}
|
}
|
||||||
style={{
|
style={{
|
||||||
overflow: "hidden !important",
|
overflow: "hidden !important",
|
||||||
@ -1219,7 +1036,11 @@ export default function ServerList() {
|
|||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
)} </> */}
|
)} </> */}
|
||||||
<ServerCard b={b} motd={motdList[b.name]} />
|
<ServerCard
|
||||||
|
b={b}
|
||||||
|
motd={motdList[b.name]}
|
||||||
|
selectedProperties={selectedProperties}
|
||||||
|
/>
|
||||||
</>
|
</>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
@ -1319,7 +1140,7 @@ export default function ServerList() {
|
|||||||
className="md:min-w-[128px] md:max-w-[328px] h-[32px] mt-1 ml-2"
|
className="md:min-w-[128px] md:max-w-[328px] h-[32px] mt-1 ml-2"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
clipboard.writeText(
|
clipboard.writeText(
|
||||||
c.data.name + ".mshf.minehut.gg",
|
c.data.name + ".mshf.minehut.gg"
|
||||||
);
|
);
|
||||||
toast.success("Copied IP to clipboard");
|
toast.success("Copied IP to clipboard");
|
||||||
}}
|
}}
|
||||||
|
|||||||
29
src/components/feat/LinkingSetup.tsx
Normal file
29
src/components/feat/LinkingSetup.tsx
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
200
src/components/misc/DisplaySettings.tsx
Normal file
200
src/components/misc/DisplaySettings.tsx
Normal file
@ -0,0 +1,200 @@
|
|||||||
|
"use client";
|
||||||
|
import { CircleAlert, LayoutGrid, List, Phone } from "lucide-react";
|
||||||
|
import { Tabs, TabsList, TabsTrigger, TabsContent } from "@/components/ui/tabs";
|
||||||
|
import { Switch } from "@/components/ui/switch";
|
||||||
|
import { Label } from "@/components/ui/label";
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
import { Separator } from "@/components/ui/separator";
|
||||||
|
import { Alert, AlertDescription, AlertTitle } from "../ui/alert";
|
||||||
|
import { Select } from "@radix-ui/react-select";
|
||||||
|
import {
|
||||||
|
SelectContent,
|
||||||
|
SelectGroup,
|
||||||
|
SelectItem,
|
||||||
|
SelectSeparator,
|
||||||
|
SelectTrigger,
|
||||||
|
SelectValue,
|
||||||
|
} from "../ui/select";
|
||||||
|
import { Tooltip, TooltipContent, TooltipTrigger } from "../ui/tooltip";
|
||||||
|
import { SignedIn } from "@clerk/nextjs";
|
||||||
|
|
||||||
|
export function DisplaySettings({
|
||||||
|
presentationMode,
|
||||||
|
setPresentationMode,
|
||||||
|
selectedProperties,
|
||||||
|
setSelectedProperties,
|
||||||
|
hero,
|
||||||
|
setHero,
|
||||||
|
ipr,
|
||||||
|
am,
|
||||||
|
iprChangerCallback,
|
||||||
|
padding,
|
||||||
|
paddingChangerCallback,
|
||||||
|
}: any) {
|
||||||
|
const toggleProperty = (property: string) => {
|
||||||
|
setSelectedProperties((prev: any) =>
|
||||||
|
prev.includes(property)
|
||||||
|
? prev.filter((p: any) => p !== property)
|
||||||
|
: [...prev, property]
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="w-full space-y-6 bg-background">
|
||||||
|
<Tabs
|
||||||
|
defaultValue="cards"
|
||||||
|
className="w-full"
|
||||||
|
onValueChange={setPresentationMode}
|
||||||
|
value={presentationMode}
|
||||||
|
>
|
||||||
|
<div className="border-b">
|
||||||
|
<TabsList className="grid w-full grid-cols-2 bg-background p-0">
|
||||||
|
<TabsTrigger
|
||||||
|
value="grid"
|
||||||
|
className="flex items-center gap-2 py-2.5 px-4 data-[state=active]:bg-background data-[state=active]:shadow-none rounded-none border-r"
|
||||||
|
>
|
||||||
|
<LayoutGrid className="h-4 w-4" />
|
||||||
|
Grid
|
||||||
|
</TabsTrigger>
|
||||||
|
<TabsTrigger
|
||||||
|
value="table"
|
||||||
|
className="flex items-center gap-2 py-2.5 px-4 data-[state=active]:bg-background data-[state=active]:shadow-none rounded-none"
|
||||||
|
>
|
||||||
|
<List className="h-4 w-4" />
|
||||||
|
Table
|
||||||
|
</TabsTrigger>
|
||||||
|
</TabsList>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<TabsContent value="grid" className="space-y-6 mt-0 ">
|
||||||
|
<SignedIn>
|
||||||
|
<div className="flex items-center justify-between pt-5 pb-1 p-4">
|
||||||
|
<Label htmlFor="set-hero" className="font-normal">
|
||||||
|
Show hero at the top of the page
|
||||||
|
</Label>
|
||||||
|
<Switch id="set-hero" value={hero} onCheckedChange={setHero} />
|
||||||
|
</div>
|
||||||
|
</SignedIn>
|
||||||
|
|
||||||
|
<Separator />
|
||||||
|
|
||||||
|
<div
|
||||||
|
className={
|
||||||
|
"flex items-center justify-between py-1 " +
|
||||||
|
(am ? "border border-orange-500 rounded px-2 mx-2" : "mx-4")
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Label
|
||||||
|
htmlFor="grid-columns"
|
||||||
|
className="font-normal flex items-center"
|
||||||
|
>
|
||||||
|
{am && (
|
||||||
|
<Tooltip>
|
||||||
|
<TooltipTrigger>
|
||||||
|
<CircleAlert size={16} className="mr-2 text-orange-500" />
|
||||||
|
</TooltipTrigger>
|
||||||
|
<TooltipContent>
|
||||||
|
If you change this setting, it will take priority over your{" "}
|
||||||
|
<br />
|
||||||
|
account settings. These settings will not save over reloads.
|
||||||
|
</TooltipContent>
|
||||||
|
</Tooltip>
|
||||||
|
)}
|
||||||
|
Grid items p/ row
|
||||||
|
</Label>
|
||||||
|
<Select value={ipr} onValueChange={iprChangerCallback}>
|
||||||
|
<SelectTrigger className="w-[125px]">
|
||||||
|
<SelectValue placeholder="" id="grid-columns" />
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent>
|
||||||
|
<SelectGroup>
|
||||||
|
<SelectItem value="4">4 items</SelectItem>
|
||||||
|
<SelectItem value="5">5 items</SelectItem>
|
||||||
|
<SelectItem value="6">6 items</SelectItem>
|
||||||
|
</SelectGroup>
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className={
|
||||||
|
"flex items-center justify-between py-1 " +
|
||||||
|
(am ? "border border-orange-500 rounded px-2 mx-2" : "mx-4")
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Label htmlFor="padding" className="font-normal flex items-center">
|
||||||
|
{am && (
|
||||||
|
<Tooltip>
|
||||||
|
<TooltipTrigger>
|
||||||
|
<CircleAlert size={16} className="mr-2 text-orange-500" />
|
||||||
|
</TooltipTrigger>
|
||||||
|
<TooltipContent>
|
||||||
|
If you change this setting, it will take priority over your{" "}
|
||||||
|
<br />
|
||||||
|
account settings. These settings will not save over reloads.
|
||||||
|
</TooltipContent>
|
||||||
|
</Tooltip>
|
||||||
|
)}
|
||||||
|
Padding
|
||||||
|
</Label>
|
||||||
|
<Select
|
||||||
|
value={padding.toString()}
|
||||||
|
onValueChange={paddingChangerCallback}
|
||||||
|
>
|
||||||
|
<SelectTrigger className="w-[125px]">
|
||||||
|
<SelectValue placeholder="" id="padding" />
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent>
|
||||||
|
<SelectGroup>
|
||||||
|
<SelectItem value="0">Default</SelectItem>
|
||||||
|
<SelectSeparator />
|
||||||
|
<SelectItem value="15">15px</SelectItem>
|
||||||
|
<SelectItem value="30">30px</SelectItem>
|
||||||
|
<SelectItem value="40">40px</SelectItem>
|
||||||
|
<SelectItem value="60">60px</SelectItem>
|
||||||
|
<SelectItem value="100">100px</SelectItem>
|
||||||
|
<SelectItem value="200">200px</SelectItem>
|
||||||
|
</SelectGroup>
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Separator />
|
||||||
|
|
||||||
|
<div className="space-y-4 pt-1 p-4">
|
||||||
|
<h3 className="text-xs uppercase text-gray-500">
|
||||||
|
Display Properties
|
||||||
|
</h3>
|
||||||
|
<div className="flex flex-wrap gap-2">
|
||||||
|
{["Author", "MOTD", "Tags", "Players Online", "Actions"].map(
|
||||||
|
(property) => (
|
||||||
|
<button
|
||||||
|
key={property}
|
||||||
|
onClick={() => toggleProperty(property)}
|
||||||
|
className={cn(
|
||||||
|
"px-3 py-1.5 text-sm rounded-md transition-colors",
|
||||||
|
selectedProperties.includes(property)
|
||||||
|
? "bg-secondary text-secondary-foreground border"
|
||||||
|
: "hover:bg-muted/80"
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{property}
|
||||||
|
</button>
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</TabsContent>
|
||||||
|
|
||||||
|
<TabsContent value="table" className="mt-0 px-4 my-4">
|
||||||
|
<Alert className="md:hidden">
|
||||||
|
<Phone className="h-4 w-4" />
|
||||||
|
<AlertTitle>Table mode isn't optimized for mobile</AlertTitle>
|
||||||
|
<AlertDescription>
|
||||||
|
At this time, we do not recommend using table mode on mobile.
|
||||||
|
</AlertDescription>
|
||||||
|
</Alert>
|
||||||
|
</TabsContent>
|
||||||
|
</Tabs>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
134
src/components/misc/FilterMenu.tsx
Normal file
134
src/components/misc/FilterMenu.tsx
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
/*
|
||||||
|
* 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 {
|
||||||
|
DropdownMenu,
|
||||||
|
DropdownMenuCheckboxItem,
|
||||||
|
DropdownMenuContent,
|
||||||
|
DropdownMenuRadioGroup,
|
||||||
|
DropdownMenuRadioItem,
|
||||||
|
DropdownMenuSeparator,
|
||||||
|
DropdownMenuSub,
|
||||||
|
DropdownMenuTrigger,
|
||||||
|
} from "@/components/ui/dropdown-menu";
|
||||||
|
import { Badge } from "../ui/badge";
|
||||||
|
import { allCategories, allTags } from "@/config/tags";
|
||||||
|
|
||||||
|
export function FilterMenu({
|
||||||
|
serverSizeChangerCallback,
|
||||||
|
serverSizeChangerValueCallback,
|
||||||
|
templateFilter,
|
||||||
|
tagChangerValueCallback,
|
||||||
|
tagChangerCallback,
|
||||||
|
categoryChangerCallback,
|
||||||
|
categoryChangerValueCallback,
|
||||||
|
children,
|
||||||
|
}: {
|
||||||
|
children: React.ReactNode;
|
||||||
|
serverSizeChangerCallback: any;
|
||||||
|
serverSizeChangerValueCallback: any;
|
||||||
|
templateFilter: any;
|
||||||
|
tagChangerValueCallback: any;
|
||||||
|
tagChangerCallback: any;
|
||||||
|
categoryChangerCallback: any;
|
||||||
|
categoryChangerValueCallback: any;
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<DropdownMenu>
|
||||||
|
<DropdownMenuTrigger asChild>{children}</DropdownMenuTrigger>
|
||||||
|
<DropdownMenuContent className="max-h-[400px] overflow-auto">
|
||||||
|
<DropdownMenuRadioGroup
|
||||||
|
onValueChange={serverSizeChangerCallback}
|
||||||
|
value={serverSizeChangerValueCallback()}
|
||||||
|
>
|
||||||
|
<DropdownMenuRadioItem value="smaller">
|
||||||
|
<div className="block">
|
||||||
|
Only allow smaller servers
|
||||||
|
<br />
|
||||||
|
<span className="text-sm text-muted-foreground">
|
||||||
|
Only allow servers that have the player range 7-15, and cannot{" "}
|
||||||
|
<br />
|
||||||
|
be Always Online.
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</DropdownMenuRadioItem>
|
||||||
|
<DropdownMenuRadioItem value="bigger">
|
||||||
|
<div className="block">
|
||||||
|
Only allow bigger servers
|
||||||
|
<br />
|
||||||
|
<span className="text-sm text-muted-foreground">
|
||||||
|
Only allow servers with more than 15 players.
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</DropdownMenuRadioItem>
|
||||||
|
<DropdownMenuRadioItem value="none">
|
||||||
|
No/custom requirements
|
||||||
|
</DropdownMenuRadioItem>
|
||||||
|
</DropdownMenuRadioGroup>
|
||||||
|
<DropdownMenuSeparator />
|
||||||
|
<DropdownMenuSub>
|
||||||
|
<span className="text-sm text-muted-foreground ml-2">Tags</span>
|
||||||
|
</DropdownMenuSub>
|
||||||
|
{allTags.map((tag) => (
|
||||||
|
<div key={tag.docsName}>
|
||||||
|
{tag.docsName && tag.__filter == undefined && (
|
||||||
|
<DropdownMenuCheckboxItem
|
||||||
|
disabled={templateFilter && tag.__disab != undefined}
|
||||||
|
id={tag.docsName}
|
||||||
|
checked={tagChangerValueCallback(tag)}
|
||||||
|
onCheckedChange={tagChangerCallback(tag)}
|
||||||
|
>
|
||||||
|
<Badge variant={tag.role} className="mr-1">
|
||||||
|
{tag.docsName}
|
||||||
|
</Badge>
|
||||||
|
</DropdownMenuCheckboxItem>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
<DropdownMenuSeparator />
|
||||||
|
<DropdownMenuSub>
|
||||||
|
<span className="text-sm text-muted-foreground ml-2">Categories</span>
|
||||||
|
</DropdownMenuSub>
|
||||||
|
{allCategories.map((categorie) => (
|
||||||
|
<DropdownMenuCheckboxItem
|
||||||
|
id={categorie.name}
|
||||||
|
key={categorie.name}
|
||||||
|
onCheckedChange={categoryChangerCallback(categorie)}
|
||||||
|
checked={categoryChangerValueCallback(categorie)}
|
||||||
|
>
|
||||||
|
<Badge variant={categorie.role} className="mr-1">
|
||||||
|
{categorie.name}
|
||||||
|
</Badge>
|
||||||
|
</DropdownMenuCheckboxItem>
|
||||||
|
))}
|
||||||
|
</DropdownMenuContent>
|
||||||
|
</DropdownMenu>
|
||||||
|
);
|
||||||
|
}
|
||||||
74
src/components/misc/Footer.tsx
Normal file
74
src/components/misc/Footer.tsx
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
* 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 { Book } from "lucide-react";
|
||||||
|
import { BrandingColorfulIcon } from "../Icon";
|
||||||
|
import { Button } from "../ui/button";
|
||||||
|
import Github from "../ui/github";
|
||||||
|
import { Separator } from "../ui/separator";
|
||||||
|
import Link from "next/link";
|
||||||
|
import { useTheme } from "next-themes";
|
||||||
|
|
||||||
|
export default function Footer() {
|
||||||
|
const { resolvedTheme } = useTheme();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<footer>
|
||||||
|
<Separator />
|
||||||
|
<p className="px-4 pt-8 pb-2">
|
||||||
|
<span className="text-xl font-bold text-muted-foreground pb-12 flex items-center">
|
||||||
|
<BrandingColorfulIcon className="w-12 h-12 mr-2" />
|
||||||
|
MHSF
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<p>© {new Date().getFullYear()} dvelo</p>
|
||||||
|
<strong className="text-sm">
|
||||||
|
MHSF is built on open-source technologies and is not endorsed by or
|
||||||
|
affiliated with GamerSafer or its subsidiaries.{" "}
|
||||||
|
</strong>
|
||||||
|
<br />
|
||||||
|
<span className="flex items-center">
|
||||||
|
<Link href="https://github.com/DeveloLongScript/MHSF">
|
||||||
|
<Button variant="ghost" size="icon">
|
||||||
|
<Github fill={resolvedTheme === "dark" ? "white" : "black"} />
|
||||||
|
</Button>
|
||||||
|
</Link>
|
||||||
|
<Link href="/docs">
|
||||||
|
<Button variant="ghost" size="icon">
|
||||||
|
<Book size={14} />
|
||||||
|
</Button>
|
||||||
|
</Link>
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
</footer>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -31,7 +31,7 @@
|
|||||||
|
|
||||||
import { DatabaseZap } from "lucide-react";
|
import { DatabaseZap } from "lucide-react";
|
||||||
|
|
||||||
export default function NoItems() {
|
export default function NoItems({ title }: { title?: string }) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="flex flex-col items-center justify-center p-4 pt-10">
|
<div className="flex flex-col items-center justify-center p-4 pt-10">
|
||||||
@ -40,7 +40,9 @@ export default function NoItems() {
|
|||||||
size={32}
|
size={32}
|
||||||
/>
|
/>
|
||||||
<p className="text-xl text-gray-600 mt-2">
|
<p className="text-xl text-gray-600 mt-2">
|
||||||
Huh, we tried to find something, but nothing was found.
|
{title
|
||||||
|
? title
|
||||||
|
: "Huh, we tried to find something, but nothing was found."}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
|
|||||||
158
src/components/misc/ServerListInterface.tsx
Normal file
158
src/components/misc/ServerListInterface.tsx
Normal file
@ -0,0 +1,158 @@
|
|||||||
|
/*
|
||||||
|
* 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 { Button } from "@/components/ui/button";
|
||||||
|
import { Input } from "@/components/ui/input";
|
||||||
|
import {
|
||||||
|
ChevronDown,
|
||||||
|
Dices,
|
||||||
|
ListRestart,
|
||||||
|
MoreVertical,
|
||||||
|
Search,
|
||||||
|
SquareTerminal,
|
||||||
|
} from "lucide-react";
|
||||||
|
import { FilterMenu } from "./FilterMenu";
|
||||||
|
import { DisplaySettings } from "./DisplaySettings";
|
||||||
|
import { Popover, PopoverContent, PopoverTrigger } from "../ui/popover";
|
||||||
|
import events from "@/lib/commandEvent";
|
||||||
|
import {
|
||||||
|
DropdownMenu,
|
||||||
|
DropdownMenuContent,
|
||||||
|
DropdownMenuItem,
|
||||||
|
DropdownMenuSeparator,
|
||||||
|
DropdownMenuTrigger,
|
||||||
|
} from "../ui/dropdown-menu";
|
||||||
|
|
||||||
|
export default function ServerListInterface({
|
||||||
|
linksProps,
|
||||||
|
viewProps,
|
||||||
|
refreshCallback,
|
||||||
|
pickRandomServerCallback,
|
||||||
|
}: {
|
||||||
|
linksProps: {
|
||||||
|
serverSizeChangerCallback: any;
|
||||||
|
serverSizeChangerValueCallback: any;
|
||||||
|
templateFilter: any;
|
||||||
|
tagChangerValueCallback: any;
|
||||||
|
tagChangerCallback: any;
|
||||||
|
categoryChangerCallback: any;
|
||||||
|
categoryChangerValueCallback: any;
|
||||||
|
};
|
||||||
|
viewProps: {
|
||||||
|
setPresentationMode: any;
|
||||||
|
presentationMode: any;
|
||||||
|
selectedProperties: any;
|
||||||
|
setSelectedProperties: any;
|
||||||
|
hero: any;
|
||||||
|
setHero: any;
|
||||||
|
iprChangerCallback: any;
|
||||||
|
ipr: any;
|
||||||
|
am: any;
|
||||||
|
padding: any;
|
||||||
|
paddingChangerCallback: any;
|
||||||
|
};
|
||||||
|
refreshCallback: any;
|
||||||
|
pickRandomServerCallback: any;
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<div className="w-full mt-6">
|
||||||
|
<div className="flex flex-col sm:flex-row items-stretch sm:items-center sm:justify-between gap-2 sm:gap-8">
|
||||||
|
<div className="grid grid-cols-2 sm:flex sm:flex-row items-stretch sm:items-center gap-2">
|
||||||
|
<FilterMenu {...linksProps}>
|
||||||
|
<Button variant="outline" className="w-full gap-2">
|
||||||
|
Filter
|
||||||
|
<ChevronDown className="h-4 w-4" />
|
||||||
|
</Button>
|
||||||
|
</FilterMenu>
|
||||||
|
|
||||||
|
<Popover>
|
||||||
|
<PopoverTrigger asChild>
|
||||||
|
<Button variant="outline" className="w-full gap-2">
|
||||||
|
Display
|
||||||
|
<ChevronDown className="h-4 w-4" />
|
||||||
|
</Button>
|
||||||
|
</PopoverTrigger>
|
||||||
|
<PopoverContent className="w-80 p-0">
|
||||||
|
<DisplaySettings {...viewProps} />
|
||||||
|
</PopoverContent>
|
||||||
|
</Popover>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex items-center gap-2 w-full sm:w-auto">
|
||||||
|
<div className="relative flex-1">
|
||||||
|
<Search className="absolute left-2.5 top-2.5 h-4 w-4 text-muted-foreground" />
|
||||||
|
<Input
|
||||||
|
type="search"
|
||||||
|
placeholder="Search..."
|
||||||
|
className="pl-8"
|
||||||
|
value=""
|
||||||
|
onClick={(c) => {
|
||||||
|
c.preventDefault();
|
||||||
|
events.emit("search-request-event");
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<DropdownMenu>
|
||||||
|
<DropdownMenuTrigger asChild>
|
||||||
|
<Button variant="ghost" size="icon" className="shrink-0">
|
||||||
|
<MoreVertical className="h-4 w-4" />
|
||||||
|
<span className="sr-only">More options</span>
|
||||||
|
</Button>
|
||||||
|
</DropdownMenuTrigger>
|
||||||
|
<DropdownMenuContent>
|
||||||
|
<DropdownMenuItem
|
||||||
|
className="dark:text-white py-2"
|
||||||
|
onSelect={refreshCallback}
|
||||||
|
>
|
||||||
|
<ListRestart />
|
||||||
|
Reload Servers
|
||||||
|
</DropdownMenuItem>
|
||||||
|
<DropdownMenuItem
|
||||||
|
className="dark:text-white py-2"
|
||||||
|
onSelect={pickRandomServerCallback}
|
||||||
|
>
|
||||||
|
<Dices />
|
||||||
|
Pick Random Server
|
||||||
|
</DropdownMenuItem>
|
||||||
|
<DropdownMenuSeparator />
|
||||||
|
<DropdownMenuItem
|
||||||
|
className="dark:text-white py-2"
|
||||||
|
onSelect={() => events.emit("cmd-event")}
|
||||||
|
>
|
||||||
|
<SquareTerminal />
|
||||||
|
Show Command Bar
|
||||||
|
</DropdownMenuItem>
|
||||||
|
</DropdownMenuContent>
|
||||||
|
</DropdownMenu>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -1,15 +1,20 @@
|
|||||||
|
import { useTheme } from "next-themes";
|
||||||
import type { SVGProps } from "react";
|
import type { SVGProps } from "react";
|
||||||
const Github = (props: SVGProps<SVGSVGElement>) => (
|
const Github = (props: SVGProps<SVGSVGElement>) => {
|
||||||
|
const { resolvedTheme } = useTheme();
|
||||||
|
|
||||||
|
return (
|
||||||
<svg
|
<svg
|
||||||
viewBox="0 0 256 250"
|
viewBox="0 0 256 250"
|
||||||
width="1em"
|
width="1em"
|
||||||
height="1em"
|
height="1em"
|
||||||
fill="#fff"
|
fill={resolvedTheme === "dark" ? "#fff" : "#24292f"}
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
preserveAspectRatio="xMidYMid"
|
preserveAspectRatio="xMidYMid"
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
<path d="M128.001 0C57.317 0 0 57.307 0 128.001c0 56.554 36.676 104.535 87.535 121.46 6.397 1.185 8.746-2.777 8.746-6.158 0-3.052-.12-13.135-.174-23.83-35.61 7.742-43.124-15.103-43.124-15.103-5.823-14.795-14.213-18.73-14.213-18.73-11.613-7.944.876-7.78.876-7.78 12.853.902 19.621 13.19 19.621 13.19 11.417 19.568 29.945 13.911 37.249 10.64 1.149-8.272 4.466-13.92 8.127-17.116-28.431-3.236-58.318-14.212-58.318-63.258 0-13.975 5-25.394 13.188-34.358-1.329-3.224-5.71-16.242 1.24-33.874 0 0 10.749-3.44 35.21 13.121 10.21-2.836 21.16-4.258 32.038-4.307 10.878.049 21.837 1.47 32.066 4.307 24.431-16.56 35.165-13.12 35.165-13.12 6.967 17.63 2.584 30.65 1.255 33.873 8.207 8.964 13.173 20.383 13.173 34.358 0 49.163-29.944 59.988-58.447 63.157 4.591 3.972 8.682 11.762 8.682 23.704 0 17.126-.148 30.91-.148 35.126 0 3.407 2.304 7.398 8.792 6.14C219.37 232.5 256 184.537 256 128.002 256 57.307 198.691 0 128.001 0Zm-80.06 182.34c-.282.636-1.283.827-2.194.39-.929-.417-1.45-1.284-1.15-1.922.276-.655 1.279-.838 2.205-.399.93.418 1.46 1.293 1.139 1.931Zm6.296 5.618c-.61.566-1.804.303-2.614-.591-.837-.892-.994-2.086-.375-2.66.63-.566 1.787-.301 2.626.591.838.903 1 2.088.363 2.66Zm4.32 7.188c-.785.545-2.067.034-2.86-1.104-.784-1.138-.784-2.503.017-3.05.795-.547 2.058-.055 2.861 1.075.782 1.157.782 2.522-.019 3.08Zm7.304 8.325c-.701.774-2.196.566-3.29-.49-1.119-1.032-1.43-2.496-.726-3.27.71-.776 2.213-.558 3.315.49 1.11 1.03 1.45 2.505.701 3.27Zm9.442 2.81c-.31 1.003-1.75 1.459-3.199 1.033-1.448-.439-2.395-1.613-2.103-2.626.301-1.01 1.747-1.484 3.207-1.028 1.446.436 2.396 1.602 2.095 2.622Zm10.744 1.193c.036 1.055-1.193 1.93-2.715 1.95-1.53.034-2.769-.82-2.786-1.86 0-1.065 1.202-1.932 2.733-1.958 1.522-.03 2.768.818 2.768 1.868Zm10.555-.405c.182 1.03-.875 2.088-2.387 2.37-1.485.271-2.861-.365-3.05-1.386-.184-1.056.893-2.114 2.376-2.387 1.514-.263 2.868.356 3.061 1.403Z" />
|
<path d="M128.001 0C57.317 0 0 57.307 0 128.001c0 56.554 36.676 104.535 87.535 121.46 6.397 1.185 8.746-2.777 8.746-6.158 0-3.052-.12-13.135-.174-23.83-35.61 7.742-43.124-15.103-43.124-15.103-5.823-14.795-14.213-18.73-14.213-18.73-11.613-7.944.876-7.78.876-7.78 12.853.902 19.621 13.19 19.621 13.19 11.417 19.568 29.945 13.911 37.249 10.64 1.149-8.272 4.466-13.92 8.127-17.116-28.431-3.236-58.318-14.212-58.318-63.258 0-13.975 5-25.394 13.188-34.358-1.329-3.224-5.71-16.242 1.24-33.874 0 0 10.749-3.44 35.21 13.121 10.21-2.836 21.16-4.258 32.038-4.307 10.878.049 21.837 1.47 32.066 4.307 24.431-16.56 35.165-13.12 35.165-13.12 6.967 17.63 2.584 30.65 1.255 33.873 8.207 8.964 13.173 20.383 13.173 34.358 0 49.163-29.944 59.988-58.447 63.157 4.591 3.972 8.682 11.762 8.682 23.704 0 17.126-.148 30.91-.148 35.126 0 3.407 2.304 7.398 8.792 6.14C219.37 232.5 256 184.537 256 128.002 256 57.307 198.691 0 128.001 0Zm-80.06 182.34c-.282.636-1.283.827-2.194.39-.929-.417-1.45-1.284-1.15-1.922.276-.655 1.279-.838 2.205-.399.93.418 1.46 1.293 1.139 1.931Zm6.296 5.618c-.61.566-1.804.303-2.614-.591-.837-.892-.994-2.086-.375-2.66.63-.566 1.787-.301 2.626.591.838.903 1 2.088.363 2.66Zm4.32 7.188c-.785.545-2.067.034-2.86-1.104-.784-1.138-.784-2.503.017-3.05.795-.547 2.058-.055 2.861 1.075.782 1.157.782 2.522-.019 3.08Zm7.304 8.325c-.701.774-2.196.566-3.29-.49-1.119-1.032-1.43-2.496-.726-3.27.71-.776 2.213-.558 3.315.49 1.11 1.03 1.45 2.505.701 3.27Zm9.442 2.81c-.31 1.003-1.75 1.459-3.199 1.033-1.448-.439-2.395-1.613-2.103-2.626.301-1.01 1.747-1.484 3.207-1.028 1.446.436 2.396 1.602 2.095 2.622Zm10.744 1.193c.036 1.055-1.193 1.93-2.715 1.95-1.53.034-2.769-.82-2.786-1.86 0-1.065 1.202-1.932 2.733-1.958 1.522-.03 2.768.818 2.768 1.868Zm10.555-.405c.182 1.03-.875 2.088-2.387 2.37-1.485.271-2.861-.365-3.05-1.386-.184-1.056.893-2.114 2.376-2.387 1.514-.263 2.868.356 3.061 1.403Z" />
|
||||||
</svg>
|
</svg>
|
||||||
);
|
);
|
||||||
|
};
|
||||||
export default Github;
|
export default Github;
|
||||||
|
|||||||
@ -294,7 +294,6 @@ async function requestServer(s: OnlineServer): Promise<ServerResponse> {
|
|||||||
const json = await re.json();
|
const json = await re.json();
|
||||||
serverCache[s.name] = json.server;
|
serverCache[s.name] = json.server;
|
||||||
return json.server;
|
return json.server;
|
||||||
} else {
|
|
||||||
return serverCache[s.name];
|
|
||||||
}
|
}
|
||||||
|
return serverCache[s.name];
|
||||||
}
|
}
|
||||||
|
|||||||
@ -30,6 +30,9 @@
|
|||||||
|
|
||||||
"use client";
|
"use client";
|
||||||
import A from "@/components/misc/Link";
|
import A from "@/components/misc/Link";
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
import Github from "@/components/ui/github";
|
||||||
|
import Link from "next/link";
|
||||||
import type { ReactNode } from "react";
|
import type { ReactNode } from "react";
|
||||||
|
|
||||||
const User = ({ user }: { user: string }) => (
|
const User = ({ user }: { user: string }) => (
|
||||||
@ -41,13 +44,22 @@ const User = ({ user }: { user: string }) => (
|
|||||||
const FeatureList = ({
|
const FeatureList = ({
|
||||||
features,
|
features,
|
||||||
title,
|
title,
|
||||||
|
github,
|
||||||
}: {
|
}: {
|
||||||
features: (string | ReactNode)[];
|
features: (string | ReactNode)[];
|
||||||
|
github?: string;
|
||||||
title: ReactNode;
|
title: ReactNode;
|
||||||
}) => {
|
}) => {
|
||||||
return (
|
return (
|
||||||
<ul>
|
<ul>
|
||||||
{title}
|
{title}
|
||||||
|
{github && (
|
||||||
|
<Link href={github}>
|
||||||
|
<Button variant="ghost" size="sm">
|
||||||
|
<Github className="mr-1" /> Release
|
||||||
|
</Button>
|
||||||
|
</Link>
|
||||||
|
)}
|
||||||
{features.map((feature, i) => (
|
{features.map((feature, i) => (
|
||||||
<li key={i}>• {feature}</li>
|
<li key={i}>• {feature}</li>
|
||||||
))}
|
))}
|
||||||
@ -55,13 +67,42 @@ const FeatureList = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const version = "1.6.50";
|
export const version = "1.7.0";
|
||||||
export const changelog: { name: string; id: string; changelog: ReactNode }[] = [
|
export const changelog: { name: string; id: string; changelog: ReactNode }[] = [
|
||||||
|
{
|
||||||
|
id: "38ufajf8efajwj3njdaisef",
|
||||||
|
name: "v1.7",
|
||||||
|
changelog: (
|
||||||
|
<FeatureList
|
||||||
|
github="https://github.com/DeveloLongScript/MHSF/releases/tag/1.7"
|
||||||
|
features={[
|
||||||
|
"Partnered with CoreBoxx!",
|
||||||
|
"You can now link your Minecraft account on CoreBoxx! (check out CB 3.0.15)",
|
||||||
|
"Revamped the server finding controls",
|
||||||
|
"Fixed various bugs",
|
||||||
|
"Made banners a different style",
|
||||||
|
"Made Discord embed not inside a card",
|
||||||
|
"Added incorrect server capitalization detection",
|
||||||
|
"Made the MOTD area slightly bigger",
|
||||||
|
"New footer",
|
||||||
|
"Added padding for settings page",
|
||||||
|
"Added new table mode",
|
||||||
|
"Added new button for GitHub release on changelog",
|
||||||
|
]}
|
||||||
|
title={
|
||||||
|
<strong className="flex items-center">
|
||||||
|
Version 1.7 (January 18th 2025)
|
||||||
|
</strong>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: "dut6hx3f2paswzjve4yg9r",
|
id: "dut6hx3f2paswzjve4yg9r",
|
||||||
name: "v1.6.5",
|
name: "v1.6.5",
|
||||||
changelog: (
|
changelog: (
|
||||||
<FeatureList
|
<FeatureList
|
||||||
|
github="https://github.com/DeveloLongScript/MHSF/releases/tag/1.6.5"
|
||||||
features={[
|
features={[
|
||||||
"New MOTD engine that is over 3,000% faster, runs client-side, and doesn't need any requests to run.",
|
"New MOTD engine that is over 3,000% faster, runs client-side, and doesn't need any requests to run.",
|
||||||
"Fixed issue where GitHub link was broken if you were signed-out",
|
"Fixed issue where GitHub link was broken if you were signed-out",
|
||||||
@ -80,6 +121,7 @@ export const changelog: { name: string; id: string; changelog: ReactNode }[] = [
|
|||||||
name: "v1.6.0",
|
name: "v1.6.0",
|
||||||
changelog: (
|
changelog: (
|
||||||
<FeatureList
|
<FeatureList
|
||||||
|
github="https://github.com/DeveloLongScript/MHSF/releases/tag/1.6"
|
||||||
features={[
|
features={[
|
||||||
"Completely redid top of server view",
|
"Completely redid top of server view",
|
||||||
"Favorite counts are now prominent on the server view",
|
"Favorite counts are now prominent on the server view",
|
||||||
@ -102,6 +144,7 @@ export const changelog: { name: string; id: string; changelog: ReactNode }[] = [
|
|||||||
name: "v1.5.0",
|
name: "v1.5.0",
|
||||||
changelog: (
|
changelog: (
|
||||||
<FeatureList
|
<FeatureList
|
||||||
|
github="https://github.com/DeveloLongScript/MHSF/releases/tag/1.5"
|
||||||
features={[
|
features={[
|
||||||
"New embeds",
|
"New embeds",
|
||||||
"More mobile friendly elements",
|
"More mobile friendly elements",
|
||||||
@ -121,6 +164,7 @@ export const changelog: { name: string; id: string; changelog: ReactNode }[] = [
|
|||||||
name: "v1.4.5",
|
name: "v1.4.5",
|
||||||
changelog: (
|
changelog: (
|
||||||
<FeatureList
|
<FeatureList
|
||||||
|
github="https://github.com/DeveloLongScript/MHSF/releases/tag/1.4.5"
|
||||||
features={["Add server icons"]}
|
features={["Add server icons"]}
|
||||||
title={
|
title={
|
||||||
<strong className="flex items-center">
|
<strong className="flex items-center">
|
||||||
@ -135,6 +179,7 @@ export const changelog: { name: string; id: string; changelog: ReactNode }[] = [
|
|||||||
name: "v1.4.0",
|
name: "v1.4.0",
|
||||||
changelog: (
|
changelog: (
|
||||||
<FeatureList
|
<FeatureList
|
||||||
|
github="https://github.com/DeveloLongScript/MHSF/releases/tag/1.4"
|
||||||
features={[
|
features={[
|
||||||
"Revamped documentation",
|
"Revamped documentation",
|
||||||
"Revamped changelog UI",
|
"Revamped changelog UI",
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user