feat: revamped documentation

This commit is contained in:
dvelo 2024-11-03 09:38:25 -06:00
parent dd9104f2f3
commit 3c1fd6cfc4
38 changed files with 3731 additions and 3237 deletions

@ -11,12 +11,12 @@ The command-bar has many mods and is a great tool for power-users to use as its
## Triggering the command-bar
There are two ways to trigger the command bar, using `Ctrl+K` and `Ctrl+Shift+K`. Both put you in a command-bar, however when using `Ctrl+K`, you go into a general page with other settings.
Using `Ctrl+Shift+K` opens a server viewer, and this may be faster then going through the general page.
There are two ways to trigger the command bar, using `Ctrl+K` and <kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>K</kbd>. Both put you in a command-bar, however when using `Ctrl+K`, you go into a general page with other settings.
Using <kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>K</kbd> opens a server viewer, and this may be faster then going through the general page.
## Functions using `Ctrl+K`
## Functions using Ctrl+K
- **Servers** opens a server list, same as `Ctrl+Shift+K`
- **Servers** opens a server list, same as <kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>K</kbd>
- **Sort Servers** allows you to go into a sorted server list quickly
- **Links** shows links useful for MHSF
- **Pick Random Server** picks a random server and shows the user what that server is, is similar to the one on [the server list](/)

@ -5,11 +5,11 @@ folder: "Guides"
# Owning a server
Owning a server is quite simple and allows you to [customize your server](/docs/guides/customization) your server and make it stand out from other servers. Before owning your server, make sure you agree to the [ECA](Docs:legal/external-content-agreement).
Owning a server is quite simple and allows you to [customize your server](/docs/guides/customization) and make it stand out from other servers. Before owning your server, make sure you agree to the [ECA](Docs:legal/external-content-agreement).
## Linking
Find the server you would like to own (either by looking for it, or using the keyboard shortcut `Ctrl`+`Shift`+`K` and searching for it), and make sure your account has [already been linked with your Minecraft account](Docs:guides/linking). Go to the server, and hit the Customization tab. If the owner of the server, and the user your linked to match, you will gain access to the server.
Find the server you would like to own (either by looking for it, or using the keyboard shortcut <kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>K</kbd> and searching for it), and make sure your account has [already been linked with your Minecraft account](Docs:guides/linking). Go to the server, and hit the Customization tab. If the owner of the server, and the user your linked to match, you will gain access to the server.
If they match, you should see a button named Click to own. Press that button, and you should automagically own the server. Congratulations!
## I can't link my server, because my server doesn't have a author

@ -19,6 +19,8 @@
"@emotion/is-prop-valid": "^1.3.0",
"@linear/sdk": "^31.0.0",
"@monaco-editor/react": "^4.6.0",
"@radix-ui/react-avatar": "^1.1.1",
"@radix-ui/react-collapsible": "^1.1.1",
"@radix-ui/react-hover-card": "^1.1.1",
"@radix-ui/react-icons": "^1.3.0",
"@radix-ui/react-menubar": "^1.1.1",
@ -35,7 +37,7 @@
"inngest": "^3.21.2",
"input-otp": "^1.2.4",
"json-beautify": "^1.1.1",
"lucide-react": "^0.416.0",
"lucide-react": "^0.454.0",
"minimessage-2-html": "1.6.0",
"mongodb": "^6.8.0",
"next": "14.2.10",
@ -63,17 +65,17 @@
"@hookform/resolvers": "^3.9.0",
"@radix-ui/react-checkbox": "^1.1.1",
"@radix-ui/react-context-menu": "^2.1.5",
"@radix-ui/react-dialog": "^1.1.1",
"@radix-ui/react-dropdown-menu": "^2.1.1",
"@radix-ui/react-dialog": "^1.1.2",
"@radix-ui/react-dropdown-menu": "^2.1.2",
"@radix-ui/react-label": "^2.1.0",
"@radix-ui/react-navigation-menu": "^1.1.4",
"@radix-ui/react-popover": "^1.0.7",
"@radix-ui/react-radio-group": "^1.2.0",
"@radix-ui/react-scroll-area": "^1.1.0",
"@radix-ui/react-separator": "^1.0.3",
"@radix-ui/react-separator": "^1.1.0",
"@radix-ui/react-slot": "^1.1.0",
"@radix-ui/react-tabs": "^1.1.0",
"@radix-ui/react-tooltip": "^1.0.7",
"@radix-ui/react-tooltip": "^1.1.3",
"@tailwindcss/typography": "^0.5.13",
"@types/canvas-confetti": "^1.6.4",
"@types/node": "^20",

@ -0,0 +1,129 @@
/*
* 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 TableOfContent from "@/components/docs/TOC";
import { ALegacy } from "@/components/misc/Link";
import { MDXElements } from "@/components/misc/MDXElements";
import { ScrollArea } from "@/components/ui/scroll-area";
import { Separator } from "@/components/ui/separator";
import { allDocs } from "contentlayer/generated";
import { useMDXComponent } from "next-contentlayer/hooks";
import NextLink from "next/link";
import { notFound } from "next/navigation";
export const generateStaticParams = async () =>
allDocs.map((post) => ({ slug: [post._raw.flattenedPath] }));
export const generateMetadata = ({
params,
}: {
params: { slug: string[] };
}) => {
const post = allDocs.find(
(post) => post._raw.flattenedPath === params.slug.join("/"),
);
if (!post) notFound();
return { title: post.title + " | MHSF Docs", themeColor: "#000000" };
};
const PostLayout = ({ params }: { params: { slug: string[] } }) => {
const doc = allDocs.find(
(post) => post._raw.flattenedPath === params.slug.join("/"),
);
if (!doc) notFound();
console.log(doc);
const MDXContent = useMDXComponent(doc.body.code);
return (
<main className="relative py-6 lg:gap-10 lg:py-8 xl:grid xl:grid-cols-[1fr_300px]">
<div className="mx-auto w-full min-w-0">
<div className="pb-12 pt-8 prose dark:prose-invert">
{doc.folder && <span>{doc.folder}</span>}{" "}
{doc.lastUpdated && <span> - last updated {doc.lastUpdated}</span>}{" "}
<MDXContent
components={{
Separator,
a: (props) => <ALegacy {...props} />,
...MDXElements,
}}
/>
</div>
</div>
{doc.toc && (
<div className="hidden text-sm xl:block">
<div className="sticky top-16 -mt-10 pt-4">
<ScrollArea className="pb-10">
<div className="sticky top-16 -mt-10 h-[calc(100vh-3.5rem)] py-12 space-y-2">
<p className="font-medium">On This Page</p>
{doc.toc.map(
(c: { level: number; text: string; slug: string }) => (
<TableOfContent toc={c} doc={doc} key={c.slug} />
),
)}
<br />
<div className="space-y-2">
<p className="font-medium">Contribute</p>
<ul className="m-0 list-none">
<li className="mt-0 pt-2">
<NextLink
href={
"https://github.com/DeveloLongScript/MHSF/edit/main/docs/" +
doc._raw.flattenedPath +
".mdx"
}
target="_blank"
rel="noopener noreferrer"
className="inline-flex items-center text-sm text-muted-foreground hover:text-foreground transition-colors no-underline"
>
<svg
viewBox="0 0 438.549 438.549"
fontSize={16}
className="mr-2 size-4"
>
<path
fill="currentColor"
d="M409.132 114.573c-19.608-33.596-46.205-60.194-79.798-79.8-33.598-19.607-70.277-29.408-110.063-29.408-39.781 0-76.472 9.804-110.063 29.408-33.596 19.605-60.192 46.204-79.8 79.8C9.803 148.168 0 184.854 0 224.63c0 47.78 13.94 90.745 41.827 128.906 27.884 38.164 63.906 64.572 108.063 79.227 5.14.954 8.945.283 11.419-1.996 2.475-2.282 3.711-5.14 3.711-8.562 0-.571-.049-5.708-.144-15.417a2549.81 2549.81 0 01-.144-25.406l-6.567 1.136c-4.187.767-9.469 1.092-15.846 1-6.374-.089-12.991-.757-19.842-1.999-6.854-1.231-13.229-4.086-19.13-8.559-5.898-4.473-10.085-10.328-12.56-17.556l-2.855-6.57c-1.903-4.374-4.899-9.233-8.992-14.559-4.093-5.331-8.232-8.945-12.419-10.848l-1.999-1.431c-1.332-.951-2.568-2.098-3.711-3.429-1.142-1.331-1.997-2.663-2.568-3.997-.572-1.335-.098-2.43 1.427-3.289 1.525-.859 4.281-1.276 8.28-1.276l5.708.853c3.807.763 8.516 3.042 14.133 6.851 5.614 3.806 10.229 8.754 13.846 14.842 4.38 7.806 9.657 13.754 15.846 17.847 6.184 4.093 12.419 6.136 18.699 6.136 6.28 0 11.704-.476 16.274-1.423 4.565-.952 8.848-2.383 12.847-4.285 1.713-12.758 6.377-22.559 13.988-29.41-10.848-1.14-20.601-2.857-29.264-5.14-8.658-2.286-17.605-5.996-26.835-11.14-9.235-5.137-16.896-11.516-22.985-19.126-6.09-7.614-11.088-17.61-14.987-29.979-3.901-12.374-5.852-26.648-5.852-42.826 0-23.035 7.52-42.637 22.557-58.817-7.044-17.318-6.379-36.732 1.997-58.24 5.52-1.715 13.706-.428 24.554 3.853 10.85 4.283 18.794 7.952 23.84 10.994 5.046 3.041 9.089 5.618 12.135 7.708 17.705-4.947 35.976-7.421 54.818-7.421s37.117 2.474 54.823 7.421l10.849-6.849c7.419-4.57 16.18-8.758 26.262-12.565 10.088-3.805 17.802-4.853 23.134-3.138 8.562 21.509 9.325 40.922 2.279 58.24 15.036 16.18 22.559 35.787 22.559 58.817 0 16.178-1.958 30.497-5.853 42.966-3.9 12.471-8.941 22.457-15.125 29.979-6.191 7.521-13.901 13.85-23.131 18.986-9.232 5.14-18.182 8.85-26.84 11.136-8.662 2.286-18.415 4.004-29.263 5.146 9.894 8.562 14.842 22.077 14.842 40.539v60.237c0 3.422 1.19 6.279 3.572 8.562 2.379 2.279 6.136 2.95 11.276 1.995 44.163-14.653 80.185-41.062 108.068-79.226 27.88-38.161 41.825-81.126 41.825-128.906-.01-39.771-9.818-76.454-29.414-110.049z"
/>
</svg>
Edit page on GitHub
</NextLink>
</li>
</ul>
</div>
</div>
</ScrollArea>
</div>
</div>
)}
</main>
);
};
export default PostLayout;

@ -28,47 +28,75 @@
* OTHER DEALINGS IN THE SOFTWARE.
*/
"use client";
import { Sidebar } from "@/components/docs/Sidebar";
import { Button } from "@/components/ui/button";
import { Drawer, DrawerContent, DrawerTrigger } from "@/components/ui/drawer";
import { ScrollArea } from "@/components/ui/scroll-area";
import {
SidebarInset,
SidebarProvider,
SidebarTrigger,
} from "@/components/ui/sidebar";
import { version } from "@/config/version";
import { HamburgerMenuIcon } from "@radix-ui/react-icons";
import { GeistMono } from "geist/font/mono";
import { GeistSans } from "geist/font/sans";
import "../globals.css";
import "../../themes.css";
import { ThemeProvider } from "@/components/ThemeProvider";
import { ClerkThemeProvider } from "@/components/clerk/ClerkThemeProvider";
import {
Breadcrumb,
BreadcrumbItem,
BreadcrumbLink,
BreadcrumbList,
BreadcrumbPage,
BreadcrumbSeparator,
} from "@/components/ui/breadcrumb";
import { Separator } from "@/components/ui/separator";
import NextTopLoader from "@/lib/top-loader";
import { useRouter } from "@/lib/useRouter";
import { allDocs } from "contentlayer/generated";
import { GetServerSideProps } from "next";
import { usePathname } from "next/navigation";
interface Props {
pathname: string;
}
export default async function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
const pathname = usePathname();
return (
<div className="border-b pt-[40px]">
<div className="container flex-1 items-start md:grid md:grid-cols-[220px_minmax(0,1fr)] md:gap-6 lg:grid-cols-[240px_minmax(0,1fr)] lg:gap-10">
<aside className="fixed top-14 z-30 hidden h-[calc(100vh-3.5rem)] w-full shrink-0 md:sticky md:block">
<ScrollArea className="h-full py-6 pr-6 lg:py-8">
<div className="bg-muted w-full rounded justify-center p-4 flex items-center">
MHSF Docs <small className="ml-2">Version {version}</small>
</div>
<br />
<ClerkThemeProvider className="">
<div className="theme-zinc">
<NextTopLoader />
<SidebarProvider>
<Sidebar />
</ScrollArea>
</aside>
<br className="md:hidden" />
<div className="bg-muted w-full rounded justify-center p-4 flex items-center md:hidden">
MHSF Docs <small className="ml-2">Version {version}</small>
<Drawer>
<DrawerTrigger>
<Button className="ml-2">
<HamburgerMenuIcon />
</Button>
</DrawerTrigger>
<DrawerContent className="p-4">
<Sidebar />
</DrawerContent>
</Drawer>
</div>
{children}
<SidebarInset>
<div className="fixed backdrop-blur w-full flex h-16 z-10 items-center gap-2 px-4 ">
<SidebarTrigger />
<Separator orientation="vertical" className="mr-2 h-4" />
{
allDocs.find(
(c) =>
c._raw.flattenedPath ===
pathname
?.split("/")
.splice(2, pathname?.split("/").length)
.join("/"),
)?.title
}
</div>
<div className="px-[100px] pt-[50px]">{children}</div>
</SidebarInset>
</SidebarProvider>
</div>
</ClerkThemeProvider>
);
}

@ -28,36 +28,36 @@
* OTHER DEALINGS IN THE SOFTWARE.
*/
import { GeistSans } from "geist/font/sans";
import { SpeedInsights } from "@vercel/speed-insights/next";
import { Analytics } from "@vercel/analytics/react";
import "./globals.css";
import { TooltipProvider } from "@/components/ui/tooltip";
import { SpeedInsights } from "@vercel/speed-insights/next";
import { GeistSans } from "geist/font/sans";
import "../globals.css";
import ClientFadeIn from "@/components/ClientFadeIn";
import { CommandBarer } from "@/components/CommandBar";
import { BrandingGenericIcon } from "@/components/Icon";
import TextFromPathname from "@/components/TextFromPathname";
import { ThemeProvider } from "@/components/ThemeProvider";
import { ClerkThemeProvider } from "@/components/clerk/ClerkThemeProvider";
import NextTopLoader from "@/lib/top-loader";
import { banner } from "@/config/banner";
import TopBar from "@/components/clerk/Topbar";
import ThemedToaster from "@/components/misc/ThemedToaster";
import UnofficalDialog from "@/components/misc/UnofficalDialog";
import {
Breadcrumb,
BreadcrumbList,
BreadcrumbPage,
} from "@/components/ui/breadcrumb";
import Link from "next/link";
import TopBar from "@/components/clerk/Topbar";
import TextFromPathname from "@/components/TextFromPathname";
import { Inter as interFont } from "next/font/google";
import { CommandBarer } from "@/components/CommandBar";
import ThemedToaster from "@/components/misc/ThemedToaster";
import UnofficalDialog from "@/components/misc/UnofficalDialog";
import ClientFadeIn from "@/components/ClientFadeIn";
import { BrandingGenericIcon } from "@/components/Icon";
import { TooltipProvider } from "@/components/ui/tooltip";
import { banner } from "@/config/banner";
import NextTopLoader from "@/lib/top-loader";
import type { Metadata, Viewport } from "next";
import { Inter as interFont } from "next/font/google";
import Link from "next/link";
export const extraMetadata = {
twitter: {
images: [
{
url: "/public/imgs/icon-cf.png",
url: "/imgs/icon-cf.png",
},
],
},
@ -65,7 +65,7 @@ export const extraMetadata = {
openGraph: {
images: [
{
url: "/public/imgs/icon-cf.png",
url: "/imgs/icon-cf.png",
},
],
},

@ -38,7 +38,7 @@ export default function NotFound() {
<br />
<p>
We couldn't find the page you were looking for.{" "}
<Link href="/">Go home</Link>
<Link href="/public">Go home</Link>
</p>
</div>
</main>

@ -40,7 +40,7 @@ export const metadata: Metadata = {
twitter: {
images: [
{
url: "/public/imgs/icon-cf.png",
url: "/imgs/icon-cf.png",
},
],
},
@ -48,7 +48,7 @@ export const metadata: Metadata = {
openGraph: {
images: [
{
url: "/public/imgs/icon-cf.png",
url: "/imgs/icon-cf.png",
},
],
},

@ -0,0 +1,155 @@
/*
* 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 AfterServerView from "@/components/AfterServerView";
import Banner from "@/components/Banner";
import ColorProvider from "@/components/ColorProvider";
import ServerView from "@/components/ServerView";
import TabServer from "@/components/misc/TabServer";
import { Button } from "@/components/ui/button";
import { Separator } from "@/components/ui/separator";
import { CornerDownLeft } from "lucide-react";
import type { Metadata, ResolvingMetadata } from "next";
import Link from "next/link";
type Props = {
params: { server: string };
};
export async function generateMetadata(
{ params }: Props,
parent: ResolvingMetadata,
): Promise<Metadata> {
// read route params
const { server } = params;
const json = await (
await fetch("https://api.minehut.com/server/" + server + "?byName=true")
).json();
return {
themeColor: "#000000",
title:
json.server == null
? "Server doesn't exist | MHSF"
: json.server.name +
", " +
(json.server.online
? json.server.playerCount +
(json.server.maxPlayers != 10
? "/" + json.server.maxPlayers
: "") +
" online"
: "Offline") +
" | MHSF",
description:
json.server == null
? `The server ${server} doesn't exist.`
: `View ${server} on Minehut Server Finder!`,
authors: json.server == null ? undefined : { name: json.server.owner },
applicationName: "MHSF (Minehut Server Finder)",
icons:
json.server == null
? undefined
: "https://minehut-server-icons-live.s3.us-west-2.amazonaws.com/" +
(json.server.icon == undefined ? "OAK_SIGN" : json.server.icon) +
".png",
twitter: {
title:
json.server == null
? "Server doesn't exist | MHSF"
: json.server.name +
", " +
(json.server.online
? json.server.playerCount +
(json.server.maxPlayers != 10
? "/" + json.server.maxPlayers
: "") +
" online"
: "Offline") +
" | MHSF",
description:
json.server == null
? `The server ${server} doesn't exist.`
: `View ${server} on Minehut Server Finder!`,
images: [
{
url:
"https://minehut-server-icons-live.s3.us-west-2.amazonaws.com/" +
json.server.icon +
".png",
},
{
url: "/public/imgs/icon-cf.png",
},
],
},
openGraph: {
type: "profile",
siteName: "MHSF (Minehut Server Finder)",
images: [
{
url:
"https://minehut-server-icons-live.s3.us-west-2.amazonaws.com/" +
json.server.icon +
".png",
},
{
url: "/public/imgs/icon-cf.png",
},
],
},
};
}
export default function ServerPage({ params }: { params: { server: string } }) {
return (
<main>
<ColorProvider server={params.server}>
<div className={"pt-16"}>
<Banner server={params.server} />
<Link href="/">
<Button variant="link" className="text-muted-foreground text-sm">
<CornerDownLeft size={16} className="mr-2" /> Go back to the
server list
</Button>
</Link>
<TabServer server={params.server} tabDef="general" />
<div className="pt-8">
<ServerView server={params.server} />
</div>
<Separator />
<br />
<AfterServerView server={params.server} />
</div>
</ColorProvider>
</main>
);
}

@ -0,0 +1,116 @@
/*
* 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 Banner from "@/components/Banner";
import ColorProvider from "@/components/ColorProvider";
import { NewChart } from "@/components/NewChart";
import ServerView from "@/components/ServerView";
import TabServer from "@/components/misc/TabServer";
import { Separator } from "@/components/ui/separator";
import type { Metadata, ResolvingMetadata } from "next";
type Props = {
params: { server: string };
};
export async function generateMetadata(
{ params }: Props,
parent: ResolvingMetadata,
): Promise<Metadata> {
// read route params
const { server } = params;
const json = await (
await fetch("https://api.minehut.com/server/" + server + "?byName=true")
).json();
return {
title:
json.server == null
? "Server doesn't exist | MHSF"
: json.server.name +
", " +
(json.server.online
? json.server.playerCount +
(json.server.maxPlayers != 10
? "/" + json.server.maxPlayers
: "") +
" online"
: "Offline") +
" | MHSF",
description:
json.server == null
? `The server ${server} doesn't exist.`
: `View ${server} on Minehut Server Finder!`,
authors: json.server == null ? undefined : { name: json.server.owner },
applicationName: "MHSF (Minehut Server Finder)",
icons:
json.server == null
? undefined
: "https://mcapi.marveldc.me/item/" +
(json.server.icon == undefined ? "OAK_SIGN" : json.server.icon) +
"?width=64&height=64",
openGraph: {
type: "profile",
siteName: "MHSF (Minehut Server Finder)",
images: [
{
url:
"https://mcapi.marveldc.me/item/" +
json.server.icon +
"?width=64&height=64",
},
{
url: "/favicon.ico",
},
],
},
};
}
export default function ServerPage({ params }: { params: { server: string } }) {
return (
<main>
<ColorProvider server={params.server}>
<div className={"pt-16"}>
<Banner server={params.server} />
<TabServer server={params.server} tabDef="statistics" />
<div className="pt-8">
<ServerView server={params.server} />
<Separator />
<br />
<div className="p-4 gap-4">
<NewChart server={params.server} />
</div>
</div>
</div>
</ColorProvider>
</main>
);
}

@ -1,129 +0,0 @@
/*
* 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 TableOfContent from "@/components/docs/TOC";
import { ScrollArea } from "@/components/ui/scroll-area";
import { allDocs } from "contentlayer/generated";
import { useMDXComponent } from "next-contentlayer/hooks";
import NextLink from "next/link";
import { notFound } from "next/navigation";
import { Separator } from "@/components/ui/separator";
import { ALegacy } from "@/components/misc/Link";
import { MDXElements } from "@/components/misc/MDXElements";
export const generateStaticParams = async () =>
allDocs.map((post) => ({ slug: [post._raw.flattenedPath] }));
export const generateMetadata = ({
params,
}: {
params: { slug: string[] };
}) => {
const post = allDocs.find(
(post) => post._raw.flattenedPath === params.slug.join("/")
);
if (!post) notFound();
return { title: post.title + " | MHSF Docs", themeColor: "#000000" };
};
const PostLayout = ({ params }: { params: { slug: string[] } }) => {
const doc = allDocs.find(
(post) => post._raw.flattenedPath === params.slug.join("/")
);
if (!doc) notFound();
console.log(doc);
const MDXContent = useMDXComponent(doc.body.code);
return (
<main className="relative py-6 lg:gap-10 lg:py-8 xl:grid xl:grid-cols-[1fr_300px]">
<div className="mx-auto w-full min-w-0">
<div className="pb-12 pt-8 prose dark:prose-invert">
{doc.folder && <span>{doc.folder}</span>}{" "}
{doc.lastUpdated && <span> - last updated {doc.lastUpdated}</span>}{" "}
<MDXContent
components={{
Separator,
a: (props) => <ALegacy {...props} />,
...MDXElements,
}}
/>
</div>
</div>
{doc.toc && (
<div className="hidden text-sm xl:block">
<div className="sticky top-16 -mt-10 pt-4">
<ScrollArea className="pb-10">
<div className="sticky top-16 -mt-10 h-[calc(100vh-3.5rem)] py-12 space-y-2">
<p className="font-medium">On This Page</p>
{doc.toc.map(
(c: { level: number; text: string; slug: string }) => (
<TableOfContent toc={c} doc={doc} key={c.slug} />
)
)}
<br />
<div className="space-y-2">
<p className="font-medium">Contribute</p>
<ul className="m-0 list-none">
<li className="mt-0 pt-2">
<NextLink
href={
"https://github.com/DeveloLongScript/MHSF/edit/main/docs/" +
doc._raw.flattenedPath +
".mdx"
}
target="_blank"
rel="noopener noreferrer"
className="inline-flex items-center text-sm text-muted-foreground hover:text-foreground transition-colors no-underline"
>
<svg
viewBox="0 0 438.549 438.549"
fontSize={16}
className="mr-2 size-4"
>
<path
fill="currentColor"
d="M409.132 114.573c-19.608-33.596-46.205-60.194-79.798-79.8-33.598-19.607-70.277-29.408-110.063-29.408-39.781 0-76.472 9.804-110.063 29.408-33.596 19.605-60.192 46.204-79.8 79.8C9.803 148.168 0 184.854 0 224.63c0 47.78 13.94 90.745 41.827 128.906 27.884 38.164 63.906 64.572 108.063 79.227 5.14.954 8.945.283 11.419-1.996 2.475-2.282 3.711-5.14 3.711-8.562 0-.571-.049-5.708-.144-15.417a2549.81 2549.81 0 01-.144-25.406l-6.567 1.136c-4.187.767-9.469 1.092-15.846 1-6.374-.089-12.991-.757-19.842-1.999-6.854-1.231-13.229-4.086-19.13-8.559-5.898-4.473-10.085-10.328-12.56-17.556l-2.855-6.57c-1.903-4.374-4.899-9.233-8.992-14.559-4.093-5.331-8.232-8.945-12.419-10.848l-1.999-1.431c-1.332-.951-2.568-2.098-3.711-3.429-1.142-1.331-1.997-2.663-2.568-3.997-.572-1.335-.098-2.43 1.427-3.289 1.525-.859 4.281-1.276 8.28-1.276l5.708.853c3.807.763 8.516 3.042 14.133 6.851 5.614 3.806 10.229 8.754 13.846 14.842 4.38 7.806 9.657 13.754 15.846 17.847 6.184 4.093 12.419 6.136 18.699 6.136 6.28 0 11.704-.476 16.274-1.423 4.565-.952 8.848-2.383 12.847-4.285 1.713-12.758 6.377-22.559 13.988-29.41-10.848-1.14-20.601-2.857-29.264-5.14-8.658-2.286-17.605-5.996-26.835-11.14-9.235-5.137-16.896-11.516-22.985-19.126-6.09-7.614-11.088-17.61-14.987-29.979-3.901-12.374-5.852-26.648-5.852-42.826 0-23.035 7.52-42.637 22.557-58.817-7.044-17.318-6.379-36.732 1.997-58.24 5.52-1.715 13.706-.428 24.554 3.853 10.85 4.283 18.794 7.952 23.84 10.994 5.046 3.041 9.089 5.618 12.135 7.708 17.705-4.947 35.976-7.421 54.818-7.421s37.117 2.474 54.823 7.421l10.849-6.849c7.419-4.57 16.18-8.758 26.262-12.565 10.088-3.805 17.802-4.853 23.134-3.138 8.562 21.509 9.325 40.922 2.279 58.24 15.036 16.18 22.559 35.787 22.559 58.817 0 16.178-1.958 30.497-5.853 42.966-3.9 12.471-8.941 22.457-15.125 29.979-6.191 7.521-13.901 13.85-23.131 18.986-9.232 5.14-18.182 8.85-26.84 11.136-8.662 2.286-18.415 4.004-29.263 5.146 9.894 8.562 14.842 22.077 14.842 40.539v60.237c0 3.422 1.19 6.279 3.572 8.562 2.379 2.279 6.136 2.95 11.276 1.995 44.163-14.653 80.185-41.062 108.068-79.226 27.88-38.161 41.825-81.126 41.825-128.906-.01-39.771-9.818-76.454-29.414-110.049z"
/>
</svg>
Edit page on GitHub
</NextLink>
</li>
</ul>
</div>
</div>
</ScrollArea>
</div>
</div>
)}
</main>
);
};
export default PostLayout;

@ -73,6 +73,15 @@
--color-one: #37ecba;
--color-two: #72afd3;
--color-three: #ff2e63;
--sidebar-background: 0 0% 98%;
--sidebar-foreground: 240 5.3% 26.1%;
--sidebar-primary: 240 5.9% 10%;
--sidebar-primary-foreground: 0 0% 98%;
--sidebar-mhsf: 240 1% 92%;
--sidebar-accent: 240 4.8% 95.9%;
--sidebar-accent-foreground: 240 5.9% 10%;
--sidebar-border: 220 13% 91%;
--sidebar-ring: 217.2 91.2% 59.8%;
}
.dark {
@ -112,6 +121,15 @@
--chart-3: 216 92% 60%;
--chart-4: 210 98% 78%;
--chart-5: 212 97% 87%;
--sidebar-background: 240 5.9% 10%;
--sidebar-foreground: 240 4.8% 95.9%;
--sidebar-primary: 224.3 76.3% 48%;
--sidebar-primary-foreground: 0 0% 100%;
--sidebar-mhsf: 240 0% 13%;
--sidebar-accent: 240 3.7% 15.9%;
--sidebar-accent-foreground: 240 4.8% 95.9%;
--sidebar-border: 240 3.7% 15.9%;
--sidebar-ring: 217.2 91.2% 59.8%;
}
}
@ -123,11 +141,11 @@
@apply bg-background text-foreground;
}
}
@layer base {
a {
@apply underline text-blue-400;
}
}
/*@layer base {*/
/* a {*/
/* @apply underline text-blue-400;*/
/* }*/
/*}*/
.backdrop-blur {
-webkit-backdrop-filter: blur(8px) !important;

@ -1,152 +0,0 @@
/*
* 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 ServerView from "@/components/ServerView";
import type { Metadata, ResolvingMetadata } from "next";
import TabServer from "@/components/misc/TabServer";
import ColorProvider from "@/components/ColorProvider";
import AfterServerView from "@/components/AfterServerView";
import Banner from "@/components/Banner";
import { Button } from "@/components/ui/button";
import { CornerDownLeft } from "lucide-react";
import Link from "next/link";
type Props = {
params: { server: string };
};
export async function generateMetadata(
{ params }: Props,
parent: ResolvingMetadata
): Promise<Metadata> {
// read route params
const { server } = params;
const json = await (
await fetch("https://api.minehut.com/server/" + server + "?byName=true")
).json();
return {
themeColor: "#000000",
title:
json.server == null
? "Server doesn't exist | MHSF"
: json.server.name +
", " +
(json.server.online
? json.server.playerCount +
(json.server.maxPlayers != 10
? "/" + json.server.maxPlayers
: "") +
" online"
: "Offline") +
" | MHSF",
description:
json.server == null
? `The server ${server} doesn't exist.`
: `View ${server} on Minehut Server Finder!`,
authors: json.server == null ? undefined : { name: json.server.owner },
applicationName: "MHSF (Minehut Server Finder)",
icons:
json.server == null
? undefined
: "https://minehut-server-icons-live.s3.us-west-2.amazonaws.com/" +
(json.server.icon == undefined ? "OAK_SIGN" : json.server.icon) +
".png",
twitter: {
title:
json.server == null
? "Server doesn't exist | MHSF"
: json.server.name +
", " +
(json.server.online
? json.server.playerCount +
(json.server.maxPlayers != 10
? "/" + json.server.maxPlayers
: "") +
" online"
: "Offline") +
" | MHSF",
description:
json.server == null
? `The server ${server} doesn't exist.`
: `View ${server} on Minehut Server Finder!`,
images: [
{
url:
"https://minehut-server-icons-live.s3.us-west-2.amazonaws.com/" +
json.server.icon +
".png",
},
{
url: "/public/imgs/icon-cf.png",
},
],
},
openGraph: {
type: "profile",
siteName: "MHSF (Minehut Server Finder)",
images: [
{
url:
"https://minehut-server-icons-live.s3.us-west-2.amazonaws.com/" +
json.server.icon +
".png",
},
{
url: "/public/imgs/icon-cf.png",
},
],
},
};
}
export default function ServerPage({ params }: { params: { server: string } }) {
return (
<main>
<ColorProvider server={params.server}>
<div className={"pt-16"}>
<Banner server={params.server} />
<Link href="/">
<Button variant="link" className="text-muted-foreground text-sm">
<CornerDownLeft size={16} className="mr-2" /> Go back to the
server list
</Button>
</Link>
<TabServer server={params.server} tabDef="general" />
<div className="pt-8">
<ServerView server={params.server} />
</div>
<AfterServerView server={params.server} />
</div>
</ColorProvider>
</main>
);
}

@ -1,113 +0,0 @@
/*
* 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 ServerView from "@/components/ServerView";
import type { Metadata, ResolvingMetadata } from "next";
import TabServer from "@/components/misc/TabServer";
import { NewChart } from "@/components/NewChart";
import ColorProvider from "@/components/ColorProvider";
import Banner from "@/components/Banner";
type Props = {
params: { server: string };
};
export async function generateMetadata(
{ params }: Props,
parent: ResolvingMetadata
): Promise<Metadata> {
// read route params
const { server } = params;
const json = await (
await fetch("https://api.minehut.com/server/" + server + "?byName=true")
).json();
return {
title:
json.server == null
? "Server doesn't exist | MHSF"
: json.server.name +
", " +
(json.server.online
? json.server.playerCount +
(json.server.maxPlayers != 10
? "/" + json.server.maxPlayers
: "") +
" online"
: "Offline") +
" | MHSF",
description:
json.server == null
? `The server ${server} doesn't exist.`
: `View ${server} on Minehut Server Finder!`,
authors: json.server == null ? undefined : { name: json.server.owner },
applicationName: "MHSF (Minehut Server Finder)",
icons:
json.server == null
? undefined
: "https://mcapi.marveldc.me/item/" +
(json.server.icon == undefined ? "OAK_SIGN" : json.server.icon) +
"?width=64&height=64",
openGraph: {
type: "profile",
siteName: "MHSF (Minehut Server Finder)",
images: [
{
url:
"https://mcapi.marveldc.me/item/" +
json.server.icon +
"?width=64&height=64",
},
{
url: "/favicon.ico",
},
],
},
};
}
export default function ServerPage({ params }: { params: { server: string } }) {
return (
<main>
<ColorProvider server={params.server}>
<div className={"pt-16"}>
<Banner server={params.server} />
<TabServer server={params.server} tabDef="statistics" />
<div className="pt-8">
<ServerView server={params.server} />
<div className="p-4 gap-4">
<NewChart server={params.server} />
</div>
</div>
</div>
</ColorProvider>
</main>
);
}

@ -30,7 +30,17 @@
"use client";
import { getCommunityServerFavorites, getCustomization } from "@/lib/api";
import { MHSF } from "@/lib/mhsf";
import { ServerResponse } from "@/lib/types/mh-server";
import { MinehutIcon, getMinehutIcons } from "@/lib/types/server-icon";
import { Copy, Info } 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 Markdown from "react-markdown";
import AchievementList from "./feat/AchievementList";
import { Button } from "./ui/button";
import {
Card,
CardContent,
@ -38,28 +48,20 @@ import {
CardHeader,
CardTitle,
} from "./ui/card";
import Markdown from "react-markdown";
import { useTheme } from "next-themes";
import FadeIn from "react-fade-in/lib/FadeIn";
import { Button } from "./ui/button";
import { ServerResponse } from "@/lib/types/mh-server";
import { Copy, Info } from "lucide-react";
import toast, { CheckmarkIcon } from "react-hot-toast";
import { MHSF } from "@/lib/mhsf";
import { Tooltip, TooltipContent, TooltipTrigger } from "./ui/tooltip";
import AchievementList from "./feat/AchievementList";
export default function AfterServerView({ server }: { server: string }) {
const [description, setDescription] = useState("");
const [discord, setDiscord] = useState("");
const [mhsf, setMHSF] = useState(new MHSF());
const [icons, setIcons] = useState<MinehutIcon[]>();
const { resolvedTheme } = useTheme();
const [loading, setLoading] = useState(true);
const [view, setView] = useState(
description !== "" || discord !== "" ? "desc" : "extra"
description !== "" || discord !== "" ? "desc" : "extra",
);
const [serverObject, setServerObject] = useState<ServerResponse | undefined>(
undefined
undefined,
);
const [copied, setCopied] = useState(false);
@ -72,9 +74,12 @@ export default function AfterServerView({ server }: { server: string }) {
getCommunityServerFavorites(server).then((c) => {
mhsf.setFavorites(c);
});
getMinehutIcons().then((i) => {
setIcons(i);
});
}
fetch("https://api.minehut.com/server/" + server + "?byName=true").then(
(c) => c.json().then((n) => setServerObject(n.server))
(c) => c.json().then((n) => setServerObject(n.server)),
);
setLoading(false);
});
@ -108,6 +113,12 @@ export default function AfterServerView({ server }: { server: string }) {
>
Achievements
</Button>
<Button
variant={view == "icons" ? undefined : "ghost"}
onClick={() => setView("icons")}
>
Purchased Icons
</Button>
</div>
<div className="max-sm:hidden">
<div className="grid">
@ -131,6 +142,12 @@ export default function AfterServerView({ server }: { server: string }) {
>
Achievements
</Button>
<Button
variant={view == "icons" ? undefined : "ghost"}
onClick={() => setView("icons")}
>
Purchased Icons
</Button>
</div>
</div>
@ -317,11 +334,11 @@ export default function AfterServerView({ server }: { server: string }) {
JSON.stringify({
minehut: serverObject,
mhsf: mhsf.getMHSF(),
})
}),
);
} catch {
toast.error(
"Clipboard is inaccessible. Cannot copy"
"Clipboard is inaccessible. Cannot copy",
);
}
toast.success(
@ -334,7 +351,7 @@ export default function AfterServerView({ server }: { server: string }) {
}).substring(0, 36)}
...
</code>
</div>
</div>,
);
setTimeout(() => setCopied(false), 1000);
}}
@ -393,6 +410,20 @@ export default function AfterServerView({ server }: { server: string }) {
</Card>
</div>
)}
{view == "icons" && (
<div>
<p>
Purchased Icons are icons that are under the server's
ownership, they may or may not available at that certain
moment either.
</p>
{serverObject?.purchased_icons.map((icon) => (
<div key={icon}>
{icons?.find((c) => c._id === icon)?.icon_name}
</div>
))}
</div>
)}
</div>
</div>
<br />

@ -29,10 +29,11 @@
*/
"use client";
import { Separator } from "@/components/ui/separator";
import { useState } from "react";
import TabServer from "./misc/TabServer";
import ServerCustomize from "./ServerCustomize";
import Banner from "./Banner";
import ServerCustomize from "./ServerCustomize";
import TabServer from "./misc/TabServer";
export default function CustomizeRoot({
params,
@ -44,6 +45,7 @@ export default function CustomizeRoot({
<div className={"pt-16 theme-" + color}>
<Banner server={params.server} />
<TabServer server={params.server} tabDef="customize" />
<Separator />
<br />
<div className="pl-[40px] pr-[40px]">
<ServerCustomize server={params.server} cs={color} setCS={setColor} />

@ -28,15 +28,15 @@
* OTHER DEALINGS IN THE SOFTWARE.
*/
import { useClerk } from "@clerk/nextjs";
import { Cog, ExternalLink, KeyRound, Link, UserPen } from "lucide-react";
import NextLink from "next/link";
import { Button } from "./ui/button";
import {
ResizableHandle,
ResizablePanel,
ResizablePanelGroup,
} from "./ui/resizable";
import NextLink from "next/link";
import { useClerk } from "@clerk/nextjs";
export function Sidebar({
children,
@ -54,7 +54,10 @@ export function Sidebar({
>
<ResizablePanel className="max-md:hidden min-w-[285px] max-w-[285px] w-[285px]">
<div className="w-[300px] ml-[10px]">
<NextLink href="/account/settings" className="text-inherit">
<NextLink
href="/src/app/(main)/account/settings"
className="text-inherit"
>
<Button
className="mb-[2px] w-[250px]"
variant={curPage !== "/account/settings" ? "ghost" : "default"}
@ -62,7 +65,10 @@ export function Sidebar({
<Link size={16} className="mr-2" /> Linking
</Button>
</NextLink>
<NextLink href="/account/settings/options" className="text-inherit">
<NextLink
href="/src/app/(main)/account/settings/options"
className="text-inherit"
>
<Button
className="mb-[2px] w-[250px] "
variant={
@ -93,7 +99,10 @@ export function Sidebar({
<ResizableHandle className="max-md:hidden" />
<ResizablePanel>
<div className="md:hidden ml-2">
<NextLink href="/account/settings" className="text-inherit">
<NextLink
href="/src/app/(main)/account/settings"
className="text-inherit"
>
<Button
className="mr-[2px]"
variant={curPage !== "/account/settings" ? "ghost" : "default"}
@ -101,7 +110,10 @@ export function Sidebar({
<Link size={16} className="mr-2" /> Linking
</Button>
</NextLink>
<NextLink href="/account/settings/options" className="text-inherit">
<NextLink
href="/src/app/(main)/account/settings/options"
className="text-inherit"
>
<Button
className="mr-[2px]"
variant={

@ -28,32 +28,15 @@
* OTHER DEALINGS IN THE SOFTWARE.
*/
import { NewChart } from "@/components/NewChart";
import { MiniJoinsChart } from "@/components/misc/MiniJoinsChart";
import {
ContextMenu,
ContextMenuTrigger,
ContextMenuItem,
ContextMenuContent,
ContextMenuItem,
ContextMenuSeparator,
ContextMenuTrigger,
} from "@/components/ui/context-menu";
import toast, { LoaderIcon } from "react-hot-toast";
import {
CardHeader,
CardTitle,
CardDescription,
Card,
CardContent,
} from "./ui/card";
import IconDisplay from "./IconDisplay";
import { TagShower } from "./ServerList";
import {
ArrowRight,
ChartArea,
Copy,
EllipsisVertical,
Layers,
Star,
} from "lucide-react";
import { Button } from "./ui/button";
import {
Drawer,
DrawerContent,
@ -62,20 +45,39 @@ import {
DrawerTitle,
DrawerTrigger,
} from "@/components/ui/drawer";
import { Tooltip } from "@radix-ui/react-tooltip";
import { TooltipContent, TooltipTrigger } from "./ui/tooltip";
import { useRouter } from "@/lib/useRouter";
import Link from "next/link";
import { useState } from "react";
import { favoriteServer, isFavorited } from "@/lib/api";
import { useUser } from "@clerk/nextjs";
import { useTheme } from "next-themes";
import {
HoverCard,
HoverCardContent,
HoverCardTrigger,
} from "@/components/ui/hover-card";
import { favoriteServer, isFavorited } from "@/lib/api";
import useClipboard from "@/lib/useClipboard";
import { useRouter } from "@/lib/useRouter";
import { useUser } from "@clerk/nextjs";
import { Tooltip } from "@radix-ui/react-tooltip";
import {
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 IconDisplay from "./IconDisplay";
import { TagShower } from "./ServerList";
import { Button } from "./ui/button";
import {
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();
@ -130,6 +132,13 @@ export default function ServerCard({ b, motd, mini, favs }: any) {
/>
)}
</p>
<br />
<br />
<strong className="text-sm font-semibold text-center">
Joins Chart
</strong>
<MiniJoinsChart server={b.name} />
<div className="flex items-center pt-2">
<span className="text-xs text-muted-foreground flex items-center">
<ArrowRight size={16} className="mr-2" />
@ -272,7 +281,7 @@ export default function ServerCard({ b, motd, mini, favs }: any) {
</div>
</ContextMenuItem>
<ContextMenuSeparator />
<Link href={"/server/" + b.name}>
<Link href={"/src/app/(main)/server/" + b.name}>
<ContextMenuItem>Open server page</ContextMenuItem>
</Link>
</ContextMenuContent>

@ -181,7 +181,7 @@ export default function ServerCustomize({
Is this server in violation of the ECA?
</div>
Is this server in violation of the{" "}
<Link href="/docs/legal/external-content-agreement">
<Link href="/src/app/(main)/docs/legal/external-content-agreement">
External Content Agreement (aka ECA)
</Link>
? You can report the server to remove the customizations from the
@ -196,7 +196,7 @@ export default function ServerCustomize({
<DialogDescription>
This will send a notification to MHSF maintainers. This
server must be in violation of the{" "}
<Link href="/docs/legal/external-content-agreement">
<Link href="/src/app/(main)/docs/legal/external-content-agreement">
ECA
</Link>{" "}
to be a valid report. Typical response times include 1 hour
@ -329,7 +329,7 @@ export default function ServerCustomize({
Minehuts Terms of Service
</Link>{" "}
& the{" "}
<Link href="/docs/legal/external-content-agreement">
<Link href="/src/app/(main)/docs/legal/external-content-agreement">
External Content Agreement
</Link>
.
@ -436,7 +436,7 @@ export default function ServerCustomize({
Imgurs Terms of Service
</Link>{" "}
& the{" "}
<Link href="/docs/legal/external-content-agreement">
<Link href="/src/app/(main)/docs/legal/external-content-agreement">
External Content Agreement
</Link>
.
@ -468,7 +468,7 @@ export default function ServerCustomize({
Discords Terms of Service
</Link>{" "}
& the{" "}
<Link href="/docs/legal/external-content-agreement">
<Link href="/src/app/(main)/docs/legal/external-content-agreement">
External Content Agreement
</Link>
.

@ -29,23 +29,8 @@
*/
"use client";
import { useEffect, useRef, useState } from "react";
import { Separator } from "@/components/ui/separator";
import { BorderBeam } from "@/components/effects/border-beam";
import { Button } from "@/components/ui/button";
import { Badge } from "./ui/badge";
import ServersList from "@/lib/list";
import {
CircleUser,
Network,
Sun,
Check,
XIcon,
Info,
ArrowDownZA,
LogIn,
ImageIcon,
} from "lucide-react";
import Stat from "./Stat";
import {
Dialog,
DialogContent,
@ -54,23 +39,6 @@ import {
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog";
import {
Tooltip,
TooltipContent,
TooltipTrigger,
} from "@/components/ui/tooltip";
import toast from "react-hot-toast";
import { allTags, allCategories } from "@/config/tags";
import IconDisplay from "./IconDisplay";
import InfiniteScroll from "react-infinite-scroll-component";
import { Spinner } from "./ui/spinner";
import { CommandIcon } from "lucide-react";
import { OnlineServer } from "@/lib/types/mh-server";
import { useEffectOnce } from "@/lib/useEffectOnce";
import ServerCard from "./ServerCard";
import events from "@/lib/commandEvent";
import { BorderBeam } from "@/components/effects/border-beam";
import { useRouter } from "@/lib/useRouter";
import {
Menubar,
MenubarCheckboxItem,
@ -86,21 +54,53 @@ import {
MenubarSubTrigger,
MenubarTrigger,
} from "@/components/ui/menubar";
import ClientFadeIn from "./ClientFadeIn";
import { Skeleton } from "./ui/skeleton";
import { Separator } from "@/components/ui/separator";
import {
Tooltip,
TooltipContent,
TooltipTrigger,
} from "@/components/ui/tooltip";
import { allCategories, allTags } from "@/config/tags";
import events from "@/lib/commandEvent";
import ServersList from "@/lib/list";
import { OnlineServer } from "@/lib/types/mh-server";
import useClipboard from "@/lib/useClipboard";
import { SignedIn, SignedOut, useUser } from "@clerk/nextjs";
import Link from "next/link";
import SparklesText from "./effects/sparkles-text";
import Particles from "./effects/particles";
import { useTheme } from "next-themes";
import { ChatBubbleIcon, InputIcon } from "@radix-ui/react-icons";
import Marquee from "./effects/marquee";
import { useEffectOnce } from "@/lib/useEffectOnce";
import { useRouter } from "@/lib/useRouter";
import { cn } from "@/lib/utils";
import { Popover, PopoverContent, PopoverTrigger } from "./ui/popover";
import { SignedIn, SignedOut, useUser } from "@clerk/nextjs";
import { ChatBubbleIcon, InputIcon } from "@radix-ui/react-icons";
import {
ArrowDownZA,
Check,
CircleUser,
ImageIcon,
Info,
LogIn,
Network,
Sun,
XIcon,
} from "lucide-react";
import { CommandIcon } from "lucide-react";
import { useTheme } from "next-themes";
import Link from "next/link";
import { useEffect, useRef, useState } from "react";
import toast from "react-hot-toast";
import InfiniteScroll from "react-infinite-scroll-component";
import ClientFadeIn from "./ClientFadeIn";
import IconDisplay from "./IconDisplay";
import ServerCard from "./ServerCard";
import Stat from "./Stat";
import { SignInPopover } from "./clerk/SignInPopoverButton";
import { BentoCard, BentoGrid } from "./effects/bento-grid";
import Marquee from "./effects/marquee";
import Particles from "./effects/particles";
import SparklesText from "./effects/sparkles-text";
import { pageFind } from "./misc/Link";
import { Badge } from "./ui/badge";
import { Popover, PopoverContent, PopoverTrigger } from "./ui/popover";
import { Skeleton } from "./ui/skeleton";
import { Spinner } from "./ui/spinner";
const features = [
{
@ -167,7 +167,7 @@ export default function ServerList() {
Array<(server: OnlineServer) => Promise<boolean>>
>([]);
const [randomData, setRandomData] = useState<OnlineServer | undefined>(
undefined
undefined,
);
const { resolvedTheme } = useTheme();
const [color, setColor] = useState("#ffffff");
@ -258,7 +258,7 @@ export default function ServerList() {
<div className="p-0 branding-hero">
<>
{(!isSignedIn || hero) && (
<div className=" pb-[300px] relative mx-auto mt-20 max-w-7xl px-6 text-center md:px-8 ">
<div className="pb-[300px] max-lg:pb-[1000px] max-md:pb-[1000px] relative mx-auto mt-20 max-w-7xl text-center md:px-8 ">
<Particles
className="absolute inset-0 -z-10 block"
quantity={100}
@ -349,7 +349,7 @@ export default function ServerList() {
className={cn(
"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] " +
"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(pageFind(`Server:${server.name}`))
@ -383,7 +383,7 @@ export default function ServerList() {
className={cn(
"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] " +
"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}`)}
>
@ -566,7 +566,7 @@ export default function ServerList() {
c.forEach(
(b: { server: string; motd: string }) => {
updatedSL[b.server] = b.motd;
}
},
);
setMotdList(updatedSL);
setServers(serverList.currentServers);
@ -582,7 +582,7 @@ export default function ServerList() {
success: "Succesfully refreshed servers",
loading: "Refreshing...",
error: "Error while refreshing",
}
},
);
}}
>
@ -629,7 +629,7 @@ export default function ServerList() {
c.forEach(
(b: { server: string; motd: string }) => {
updatedSL[b.server] = b.motd;
}
},
);
setMotdList(updatedSL);
setServers(serverList.currentServers);
@ -668,7 +668,7 @@ export default function ServerList() {
c.forEach(
(b: { server: string; motd: string }) => {
updatedSL[b.server] = b.motd;
}
},
);
setMotdList(updatedSL);
setServers(serverList.currentServers);
@ -707,7 +707,7 @@ export default function ServerList() {
c.forEach(
(b: { server: string; motd: string }) => {
updatedSL[b.server] = b.motd;
}
},
);
setMotdList(updatedSL);
setServers(serverList.currentServers);
@ -720,7 +720,7 @@ export default function ServerList() {
error: "Error while changing filters",
loading: "Changing filters...",
success: "Changed filters!",
}
},
);
}}
value={(() => {
@ -804,7 +804,7 @@ export default function ServerList() {
c.forEach(
(b: { server: string; motd: string }) => {
updatedSL[b.server] = b.motd;
}
},
);
setMotdList(updatedSL);
setServers(serverList.currentServers);
@ -901,7 +901,7 @@ export default function ServerList() {
Change your preferences
</Button>
</span>,
{ icon: "⚠️" }
{ icon: "!" },
);
setIPR(v);
}}
@ -939,7 +939,7 @@ export default function ServerList() {
Change your preferences
</Button>
</span>,
{ icon: "⚠️" }
{ icon: "!" },
);
setPadding(v);
}}
@ -1063,7 +1063,7 @@ export default function ServerList() {
onClick={() => {
setTextCopied(true);
clipboard.writeText(
randomData.name + ".mshf.minehut.gg"
randomData.name + ".mshf.minehut.gg",
);
toast.success("Copied!");
setTimeout(() => setTextCopied(false), 1000);

@ -30,17 +30,17 @@
"use client";
import { ClerkProvider } from "@clerk/nextjs";
import { useTheme } from "next-themes";
import { dark } from "@clerk/themes";
import { useTheme } from "next-themes";
import { type ReactNode, useEffect, useState } from "react";
import { ThemeProvider } from "../ThemeProvider";
import { useEffect, useState } from "react";
export function ClerkThemeProvider({
children,
className,
}: {
children: JSX.Element;
className: string;
children: ReactNode | ReactNode[];
className: string | undefined;
}) {
const [theme, setTheme] = useState<string | undefined>("");

@ -0,0 +1,199 @@
/*
* 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.
*/
"use client";
import {
BadgeCheck,
Bell,
ChevronsUpDown,
Computer,
CreditCard,
LogIn,
LogOut,
Moon,
SettingsIcon,
Sparkles,
Sun,
} from "lucide-react";
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import {
DropdownMenu,
DropdownMenuCheckboxItem,
DropdownMenuContent,
DropdownMenuGroup,
DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuPortal,
DropdownMenuRadioGroup,
DropdownMenuRadioItem,
DropdownMenuSeparator,
DropdownMenuSub,
DropdownMenuSubContent,
DropdownMenuSubTrigger,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import {
SidebarMenu,
SidebarMenuButton,
SidebarMenuItem,
useSidebar,
} from "@/components/ui/sidebar";
import { useClerk, useUser } from "@clerk/nextjs";
import { useTheme } from "next-themes";
export function NavUser() {
const { isMobile } = useSidebar();
const { user, isSignedIn } = useUser();
const clerk = useClerk();
const { setTheme, theme } = useTheme();
return (
<SidebarMenu>
<SidebarMenuItem>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<SidebarMenuButton
size="lg"
className="data-[state=open]:bg-sidebar-accent data-[state=open]:text-sidebar-accent-foreground"
>
{isSignedIn && (
<Avatar className="h-8 w-8 rounded-lg">
<AvatarImage
src={
user?.imageUrl == undefined
? "https://img.clerk.com/preview.png?size=144&seed=seed&initials=AD&isSquare=true&bgType=marble&bgColor=6c47ff&fgType=silhouette&fgColor=FFFFFF&type=user&w=48&q=75"
: user?.imageUrl
}
alt={user?.username || "?"}
/>
<AvatarFallback className="rounded-lg">?</AvatarFallback>
</Avatar>
)}
<div className="grid flex-1 text-left text-sm leading-tight">
<span className="truncate font-semibold">
{isSignedIn ? user?.username : "Not logged in"}
</span>
<span className="truncate text-xs">
{user?.primaryEmailAddress?.emailAddress}
</span>
</div>
<ChevronsUpDown className="ml-auto size-4" />
</SidebarMenuButton>
</DropdownMenuTrigger>
<DropdownMenuContent
className="w-[--radix-dropdown-menu-trigger-width] min-w-56 rounded-lg"
side={isMobile ? "bottom" : "right"}
align="end"
sideOffset={4}
>
{isSignedIn && (
<>
<DropdownMenuLabel className="p-0 font-normal">
<div className="flex items-center gap-2 px-1 py-1.5 text-left text-sm">
<Avatar className="h-8 w-8 rounded-lg">
<AvatarImage
src={
user?.imageUrl == undefined
? "https://img.clerk.com/preview.png?size=144&seed=seed&initials=AD&isSquare=true&bgType=marble&bgColor=6c47ff&fgType=silhouette&fgColor=FFFFFF&type=user&w=48&q=75"
: user?.imageUrl
}
alt={user?.username || "?"}
/>
<AvatarFallback className="rounded-lg">?</AvatarFallback>
</Avatar>
<div className="grid flex-1 text-left text-sm leading-tight">
<span className="truncate font-semibold">
{user?.username}
</span>
<span className="truncate text-xs">
{user?.primaryEmailAddress?.emailAddress}
</span>
</div>
</div>
</DropdownMenuLabel>
<DropdownMenuSeparator />
</>
)}
<DropdownMenuGroup>
<DropdownMenuRadioGroup
onValueChange={(c) => setTheme(c)}
value={theme}
>
<DropdownMenuRadioItem value="dark">
<Moon /> Dark
</DropdownMenuRadioItem>
<DropdownMenuRadioItem value="light">
<Sun /> Light
</DropdownMenuRadioItem>
<DropdownMenuRadioItem value="system">
<Computer /> System
</DropdownMenuRadioItem>
</DropdownMenuRadioGroup>
</DropdownMenuGroup>
{isSignedIn && (
<>
<DropdownMenuSeparator />
<DropdownMenuGroup>
<DropdownMenuItem onSelect={() => clerk.openUserProfile()}>
<SettingsIcon />
Account Settings
</DropdownMenuItem>
<DropdownMenuItem
className="text-red-500"
onSelect={() => clerk.signOut()}
>
<LogOut />
Log out
</DropdownMenuItem>
</DropdownMenuGroup>
</>
)}
{!isSignedIn && (
<>
<DropdownMenuSeparator />
<DropdownMenuGroup>
<DropdownMenuItem onSelect={() => clerk.openSignIn()}>
<LogIn />
Sign in
</DropdownMenuItem>
</DropdownMenuGroup>
</>
)}
</DropdownMenuContent>
</DropdownMenu>
</SidebarMenuItem>
</SidebarMenu>
);
}

@ -1,134 +1,51 @@
/*
* 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 * as React from "react";
"use client";
import { allFolders, Docs, DocsFolder } from "@/config/docs";
import { usePathname } from "next/navigation";
import { Button } from "../ui/button";
import { useState } from "react";
import { ChevronRight } from "lucide-react";
import { useRouter } from "@/lib/useRouter";
import { AnimatePresence, motion } from "framer-motion";
import { NavUser } from "@/components/docs/NavUser";
import { VersionSwitcher } from "@/components/docs/VersionSwitcher";
import {
Sidebar as ShadSidebar,
SidebarContent,
SidebarFooter,
SidebarGroup,
SidebarGroupContent,
SidebarGroupLabel,
SidebarHeader,
SidebarMenu,
SidebarMenuButton,
SidebarMenuItem,
SidebarRail,
} from "@/components/ui/sidebar";
import { allFolders } from "@/config/docs";
export function Sidebar() {
return (
<>
{allFolders.map((docs) => (
<Folder docs={docs} key={"url" in docs ? docs.title : docs.name} />
<ShadSidebar>
<SidebarHeader>
<VersionSwitcher />
</SidebarHeader>
<SidebarContent>
{/* We create a SidebarGroup for each parent. */}
{allFolders.map((item) => (
<SidebarGroup key={item.name}>
<SidebarGroupLabel>{item.name}</SidebarGroupLabel>
<SidebarGroupContent>
<SidebarMenu>
{item.docs.map((item) => (
<SidebarMenuItem key={item.title}>
<SidebarMenuButton asChild>
<a href={item.url}>{item.title}</a>
</SidebarMenuButton>
</SidebarMenuItem>
))}
</>
);
}
function Folder({ docs }: { docs: any }) {
const [folderOpen, setOpen] = useState(false);
const router = useRouter();
const pathname = usePathname();
return (
<div key={"url" in docs ? docs.title : docs.name}>
<Button
size="sm"
className="w-full font-normal tracking-normal mt-1"
noJustify
variant={
"url" in docs
? pathname === docs.url
? "default"
: "ghost"
: "ghost"
}
onClick={() => {
if ("docs" in docs) {
setOpen(!folderOpen);
} else {
router.push(docs.url);
}
}}
>
{"url" in docs ? docs.title : docs.name}
<div className="flex items-center ml-auto text-muted-foreground">
<AnimatePresence>
{"docs" in docs && folderOpen && (
<motion.div initial={{ rotate: 90 }} animate={{ rotate: 0 }}>
<ChevronRight size={18} />
</motion.div>
)}
{"docs" in docs && !folderOpen && (
<motion.div initial={{ rotate: 0 }} animate={{ rotate: 90 }}>
<ChevronRight size={18} />
</motion.div>
)}
</AnimatePresence>
</div>
</Button>
<div className="ml-2">
{folderOpen && <Subdocs docs={"docs" in docs ? docs.docs : []} />}
</div>
</div>
);
}
function Subdocs({ docs }: { docs: (Docs | DocsFolder)[] }) {
const pathname = usePathname();
const router = useRouter();
return (
<>
{docs.map((doc) => {
if ("docs" in doc) {
return <Subdocs docs={doc.docs} key={doc.name} />;
}
return (
<>
<Button
size="sm"
className="w-full font-normal tracking-normal mt-1"
noJustify
onClick={() => {
router.push(doc.url);
}}
key={doc.title}
variant={
"url" in doc
? pathname == doc.url
? "default"
: "ghost"
: "ghost"
}
>
{doc.title}
</Button>
<br key={doc.url} />
</>
);
})}
</>
</SidebarMenu>
</SidebarGroupContent>
</SidebarGroup>
))}
</SidebarContent>
<SidebarFooter>
<NavUser />
</SidebarFooter>
<SidebarRail />
</ShadSidebar>
);
}

@ -28,17 +28,17 @@
* OTHER DEALINGS IN THE SOFTWARE.
*/
import { Button } from "../ui/button";
import { Book, Calendar, Star, TerminalIcon } from "lucide-react";
import { Dialog, DialogContent, DialogHeader, DialogTitle } from "../ui/dialog";
import { useState } from "react";
import { Changelog, version } from "@/config/version";
import { Changelog } from "@/components/changelog";
import { changelog, version } from "@/config/version";
import events from "@/lib/commandEvent";
import { ScrollArea } from "../ui/scroll-area";
import { useRouter } from "@/lib/useRouter";
import { Book, Calendar, Star, TerminalIcon } from "lucide-react";
import { useState } from "react";
import { Button } from "../ui/button";
import { Dialog, DialogContent, DialogHeader, DialogTitle } from "../ui/dialog";
import { ScrollArea } from "../ui/scroll-area";
export default function InfoPopover() {
const [changeLog, setChangelog] = useState(false);
const router = useRouter();
return (
@ -51,19 +51,11 @@ export default function InfoPopover() {
<small>* Licensed under the MIT License</small>
</small>
<Button variant={"ghost"} onClick={() => setChangelog(true)}>
<Changelog items={changelog}>
<Button variant={"ghost"}>
<Calendar size={18} className="mr-2" /> Changelog
</Button>
<Dialog open={changeLog} onOpenChange={setChangelog}>
<DialogContent>
<ScrollArea className="max-h-[500px]">
<DialogHeader>
<DialogTitle>Changelog</DialogTitle>
<Changelog />
</DialogHeader>
</ScrollArea>
</DialogContent>
</Dialog>
</Changelog>
<Button
variant={"ghost"}

@ -0,0 +1,111 @@
/*
* 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 {
type ChartConfig,
ChartContainer,
ChartTooltip,
ChartTooltipContent,
} from "@/components/ui/chart";
import { getShortTermData } from "@/lib/api";
import { useEffectOnce } from "@/lib/useEffectOnce";
import * as React from "react";
import { CartesianGrid, Line, LineChart, XAxis, YAxis } from "recharts";
const chartConfig = {
player_count: {
label: "Joins",
color: "hsl(var(--chart-1))",
},
} satisfies ChartConfig;
export function MiniJoinsChart({ server }: { server: string }) {
const [chartData, setChartData] = React.useState<any>([]);
const [loading, setLoading] = React.useState(true);
useEffectOnce(() => {
getShortTermData(server, ["player_count", "date"]).then((result) => {
setChartData(result.slice(-20));
setLoading(false);
});
});
return (
<div className="max-h-[160px] w-full">
<ChartContainer config={chartConfig}>
<LineChart accessibilityLayer data={chartData}>
<CartesianGrid vertical={false} />
<YAxis
dataKey={"player_count"}
tickLine={false}
axisLine={false}
tickFormatter={(value) => {
return value;
}}
/>
<XAxis
dataKey="date"
className="hidden"
tickLine={false}
axisLine={false}
tickMargin={8}
minTickGap={32}
tickFormatter={(value) => {
return new Date(value).toLocaleTimeString("en-US", {
timeStyle: "short",
});
}}
/>
<ChartTooltip
content={
<ChartTooltipContent
className="w-[150px]"
nameKey={"player_count"}
indicator="line"
labelFormatter={(value) => {
return new Date(value).toLocaleTimeString("en-US", {
timeStyle: "short",
});
}}
/>
}
/>
<Line
dataKey={"player_count"}
type="monotone"
stroke={"var(--color-player_count)"}
strokeWidth={2}
dot={false}
/>
</LineChart>
</ChartContainer>
</div>
);
}

@ -28,30 +28,30 @@
* OTHER DEALINGS IN THE SOFTWARE.
*/
"use client"
"use client";
import * as React from "react"
import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu"
import { Check, ChevronRight, Circle } from "lucide-react"
import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
import { Check, ChevronRight, Circle } from "lucide-react";
import * as React from "react";
import { cn } from "@/lib/utils"
import { cn } from "@/lib/utils";
const DropdownMenu = DropdownMenuPrimitive.Root
const DropdownMenu = DropdownMenuPrimitive.Root;
const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger
const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;
const DropdownMenuGroup = DropdownMenuPrimitive.Group
const DropdownMenuGroup = DropdownMenuPrimitive.Group;
const DropdownMenuPortal = DropdownMenuPrimitive.Portal
const DropdownMenuPortal = DropdownMenuPrimitive.Portal;
const DropdownMenuSub = DropdownMenuPrimitive.Sub
const DropdownMenuSub = DropdownMenuPrimitive.Sub;
const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup
const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup;
const DropdownMenuSubTrigger = React.forwardRef<
React.ElementRef<typeof DropdownMenuPrimitive.SubTrigger>,
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubTrigger> & {
inset?: boolean
inset?: boolean;
}
>(({ className, inset, children, ...props }, ref) => (
<DropdownMenuPrimitive.SubTrigger
@ -59,16 +59,16 @@ const DropdownMenuSubTrigger = React.forwardRef<
className={cn(
"flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent data-[state=open]:bg-accent",
inset && "pl-8",
className
className,
)}
{...props}
>
{children}
<ChevronRight className="ml-auto h-4 w-4" />
</DropdownMenuPrimitive.SubTrigger>
))
));
DropdownMenuSubTrigger.displayName =
DropdownMenuPrimitive.SubTrigger.displayName
DropdownMenuPrimitive.SubTrigger.displayName;
const DropdownMenuSubContent = React.forwardRef<
React.ElementRef<typeof DropdownMenuPrimitive.SubContent>,
@ -78,13 +78,13 @@ const DropdownMenuSubContent = React.forwardRef<
ref={ref}
className={cn(
"z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
className
className,
)}
{...props}
/>
))
));
DropdownMenuSubContent.displayName =
DropdownMenuPrimitive.SubContent.displayName
DropdownMenuPrimitive.SubContent.displayName;
const DropdownMenuContent = React.forwardRef<
React.ElementRef<typeof DropdownMenuPrimitive.Content>,
@ -96,31 +96,31 @@ const DropdownMenuContent = React.forwardRef<
sideOffset={sideOffset}
className={cn(
"z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
className
className,
)}
{...props}
/>
</DropdownMenuPrimitive.Portal>
))
DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName
));
DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName;
const DropdownMenuItem = React.forwardRef<
React.ElementRef<typeof DropdownMenuPrimitive.Item>,
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & {
inset?: boolean
inset?: boolean;
}
>(({ className, inset, ...props }, ref) => (
<DropdownMenuPrimitive.Item
ref={ref}
className={cn(
"relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
"relative flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&>svg]:size-4 [&>svg]:shrink-0",
inset && "pl-8",
className
className,
)}
{...props}
/>
))
DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName
));
DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName;
const DropdownMenuCheckboxItem = React.forwardRef<
React.ElementRef<typeof DropdownMenuPrimitive.CheckboxItem>,
@ -130,7 +130,7 @@ const DropdownMenuCheckboxItem = React.forwardRef<
ref={ref}
className={cn(
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
className
className,
)}
checked={checked}
{...props}
@ -142,9 +142,9 @@ const DropdownMenuCheckboxItem = React.forwardRef<
</span>
{children}
</DropdownMenuPrimitive.CheckboxItem>
))
));
DropdownMenuCheckboxItem.displayName =
DropdownMenuPrimitive.CheckboxItem.displayName
DropdownMenuPrimitive.CheckboxItem.displayName;
const DropdownMenuRadioItem = React.forwardRef<
React.ElementRef<typeof DropdownMenuPrimitive.RadioItem>,
@ -153,8 +153,8 @@ const DropdownMenuRadioItem = React.forwardRef<
<DropdownMenuPrimitive.RadioItem
ref={ref}
className={cn(
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
className
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&>svg]:size-4 [&>svg]:shrink-0 gap-3",
className,
)}
{...props}
>
@ -165,13 +165,13 @@ const DropdownMenuRadioItem = React.forwardRef<
</span>
{children}
</DropdownMenuPrimitive.RadioItem>
))
DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName
));
DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName;
const DropdownMenuLabel = React.forwardRef<
React.ElementRef<typeof DropdownMenuPrimitive.Label>,
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label> & {
inset?: boolean
inset?: boolean;
}
>(({ className, inset, ...props }, ref) => (
<DropdownMenuPrimitive.Label
@ -179,12 +179,12 @@ const DropdownMenuLabel = React.forwardRef<
className={cn(
"px-2 py-1.5 text-sm font-semibold",
inset && "pl-8",
className
className,
)}
{...props}
/>
))
DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName
));
DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName;
const DropdownMenuSeparator = React.forwardRef<
React.ElementRef<typeof DropdownMenuPrimitive.Separator>,
@ -195,8 +195,8 @@ const DropdownMenuSeparator = React.forwardRef<
className={cn("-mx-1 my-1 h-px bg-muted", className)}
{...props}
/>
))
DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName
));
DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName;
const DropdownMenuShortcut = ({
className,
@ -207,9 +207,9 @@ const DropdownMenuShortcut = ({
className={cn("ml-auto text-xs tracking-widest opacity-60", className)}
{...props}
/>
)
}
DropdownMenuShortcut.displayName = "DropdownMenuShortcut"
);
};
DropdownMenuShortcut.displayName = "DropdownMenuShortcut";
export {
DropdownMenu,
@ -227,4 +227,4 @@ export {
DropdownMenuSubContent,
DropdownMenuSubTrigger,
DropdownMenuRadioGroup,
}
};

@ -28,19 +28,20 @@
* OTHER DEALINGS IN THE SOFTWARE.
*/
export const allFolders: (DocsFolder | Docs)[] = [
export const allFolders: DocsFolder[] = [
{
name: "General",
docs: [
{
title: "Getting Started",
url: "/docs/getting-started",
},
{
title: "Server List",
url: "/",
},
{
title: "Reading",
url: "/docs/reading",
},
],
},
{
name: "Guides",
docs: [

@ -278,7 +278,7 @@ export const allCategories: Array<{
];
async function requestServer(s: OnlineServer): Promise<ServerResponse> {
if (serverCache[s.name] == undefined) {
if (serverCache[s.name] === undefined) {
const re = await fetch(
"https://api.minehut.com/server/" + s.name + "?byName=true",
);

@ -29,149 +29,73 @@
*/
"use client";
import Image from "next/image";
import Link from "next/link";
import { Separator } from "../components/ui/separator";
import { Button } from "../components/ui/button";
import confetti from "canvas-confetti";
export const version = "1.3.2";
import A from "@/components/misc/Link";
import type { ReactNode } from "react";
const User = ({ user }: { user: string }) => (
<span className="cursor-pointer bg-[rgba(255,165,0,0.25);] rounded p-[2.5px]">
{user}
</span>
);
const handleClick = () => {
const duration = 5 * 1000;
const animationEnd = Date.now() + duration;
const defaults = { startVelocity: 30, spread: 360, ticks: 60, zIndex: 0 };
const randomInRange = (min: number, max: number) =>
Math.random() * (max - min) + min;
const interval = window.setInterval(() => {
const timeLeft = animationEnd - Date.now();
if (timeLeft <= 0) {
return clearInterval(interval);
}
const particleCount = 50 * (timeLeft / duration);
confetti({
...defaults,
particleCount,
zIndex: 60,
origin: { x: randomInRange(0.1, 0.3), y: Math.random() - 0.2 },
});
confetti({
...defaults,
particleCount,
zIndex: 60,
origin: { x: randomInRange(0.7, 0.9), y: Math.random() - 0.2 },
});
}, 250);
};
export const Changelog = () => {
const router = useRouter();
const FeatureList = ({
features,
title,
}: { features: (string | ReactNode)[]; title: ReactNode }) => {
return (
<>
<div>
Running on commit{" "}
<code>
<a
href={`https://github.com/DeveloLongScript/mhsf/commit/${process.env.NEXT_PUBLIC_VERCEL_GIT_COMMIT_SHA}`}
>
{(
process.env.NEXT_PUBLIC_VERCEL_GIT_COMMIT_SHA || "unknown"
).substring(0, 7)}
</a>{" "}
{process.env.NEXT_PUBLIC_VERCEL_GIT_PULL_REQUEST_ID != undefined &&
process.env.NEXT_PUBLIC_VERCEL_GIT_PULL_REQUEST_ID != "" && (
<>
{" "}
| on PR{" "}
<a
href={`https://github.com/DeveloLongScript/MHSF/pull/${process.env.NEXT_PUBLIC_VERCEL_GIT_PULL_REQUEST_ID}`}
>
{process.env.NEXT_PUBLIC_VERCEL_GIT_PULL_REQUEST_ID}
</a>{" "}
by{" "}
<a
href={`https://github.com/${process.env.NEXT_PUBLIC_VERCEL_GIT_COMMIT_AUTHOR_NAME}`}
>
{process.env.NEXT_PUBLIC_VERCEL_GIT_COMMIT_AUTHOR_NAME}
</a>
</>
)}{" "}
{process.env.NEXT_PUBLIC_VERCEL_GIT_COMMIT_MESSAGE != undefined &&
`| ${process.env.NEXT_PUBLIC_VERCEL_GIT_COMMIT_MESSAGE.substring(0, 24)}`}
</code>
</div>
<div className="md:grid md:grid-cols-3 gap-1.5">
<Button
className="text-sm hover:h-[60px] animate-all group block max-md:w-full max-md:mt-2"
onClick={() =>
window.open("https://discord.com/invite/cCyEeUs", "_blank")
<ul>
{title}
{features.map((feature, i) => (
<li key={i}> {feature}</li>
))}
</ul>
);
};
export const version = "1.4.0";
export const changelog: { name: string; id: string; changelog: ReactNode }[] = [
{
id: "amq4suhgcfwrb7y5j6",
name: "v1.4.0",
changelog: (
<FeatureList
features={[
"Revamped documentation",
"Revamped changelog UI",
"New hover joins chart",
]}
title={
<strong className="flex items-center">
Version 1.4.0 (November 3rd 2024)
</strong>
}
>
<span className="group-hover:underline flex items-center">
<Discord className="mr-2"/> Discord
</span>
<Marquee
className="hidden group-hover:flex font-normal"
style={{"--duration": "15s"}}
>
Join the offical Minehut Discord server! Talk to people that like
MHSF too!
</Marquee>
</Button>
<Button
className="text-sm max-md:w-full max-md:mt-2 hover:h-[60px] animate-all group block "
onClick={() =>
window.open("https://github.com/DeveloLongScript/MHSF", "_blank")
}
>
<span className="group-hover:underline flex items-center">
<Github className="mr-2" fill={useDepTheme()}/> Star on GitHub
</span>
<Marquee
className="hidden group-hover:flex font-normal"
style={{"--duration": "10s"}}
>
Support the development of MHSF by starring it on GitHub!
</Marquee>
</Button>
<Button
className="text-sm max-md:w-full max-md:mt-2 hover:h-[60px] animate-all group block "
onClick={() => window.open("/docs", "_blank")}
>
<span className="group-hover:underline flex items-center">
<BookIcon className="mr-2" size={16}/> See the docs
</span>
<Marquee
className="hidden group-hover:flex font-normal"
style={{"--duration": "10s"}}
>
See more information about MHSF and how to use it
</Marquee>
</Button>
</div>
<br/>
/>
),
},
{
id: "jeh48p7w9bx2k3ad6f",
name: "v1.3.2",
changelog: (
<div>
<strong className="flex items-center">
Version 1.3.2 (October 4th 2024)
</strong>
<ul>
<li> Minor backend changes</li>
<li>
Minor backend changes
</li>
<li>
<A alt="Please check on GitHub for statuses about this project.">Special:GitHub/releases/tag/1.3.2</A>
{" "}
<A alt="Please check on GitHub for statuses about this project.">
Special:GitHub/releases/tag/1.3.2
</A>
</li>
</ul>
</div>
<br/>
),
},
{
id: "wvg9x5dbpj76sn4yrz",
name: "v1.3.0",
changelog: (
<div>
<strong className="flex items-center">
Version 1.3.0 (September 9th 2024)
@ -188,7 +112,11 @@ export const Changelog = () => {
<li> Overhauled account preferences</li>
</ul>
</div>
<br/>
),
},
{
name: "v1.2.0",
changelog: (
<div>
<strong className="flex items-center">
Version 1.2.0 (September 3rd 2024)
@ -200,7 +128,12 @@ export const Changelog = () => {
<li> and alot more!</li>
</ul>
</div>
<br/>
),
id: "e482y9k5hvjt73urfx",
},
{
name: "v1.1.0",
changelog: (
<div>
<strong className="flex items-center">
Version 1.1.0 (August 24rd 2024)
@ -211,27 +144,29 @@ export const Changelog = () => {
<li> New help guide</li>
</ul>
</div>
<br/>
),
id: "hfn9p243765x8bwurj",
},
{
name: "v1.0.0",
changelog: (
<div>
<strong className="flex items-center">
Version 1.0.0 (August 22nd 2024)
</strong>
<ul>
<li>
1.0!{" "}
<Button className="h-[25px] w-[50px] ml-2" onClick={handleClick}>
woah!
</Button>
</li>
<li> 1.0!</li>
<li> New hover card on server title hover</li>
<li> Moving to self-hosted cron jobs</li>
<li> Fixing some mobile issues</li>
</ul>
</div>
<br/>
<Separator/>
<br/>
),
id: "a8w4xvjbg3s7ynehu6",
},
{
name: "v0.10.7",
changelog: (
<div>
<strong className="flex items-center">
Version b-0.10.7 (August 18th 2024)
@ -240,7 +175,12 @@ export const Changelog = () => {
<li> New server information tab on server pages</li>
</ul>
</div>
<br/>
),
id: "asbt64h9fdyu8neqmp",
},
{
name: "v0.10.2",
changelog: (
<div>
<strong className="flex items-center">
Version b-0.10.2 (August 18th 2024)
@ -250,7 +190,12 @@ export const Changelog = () => {
<li> Instead of using spinners, now we are using Skeletons</li>
</ul>
</div>
<br/>
),
id: "kct29adbp6zug5r3q8",
},
{
name: "v0.10.0",
changelog: (
<div>
<strong className="flex items-center">
Version b-0.10.0 (August 17th 2024)
@ -271,8 +216,12 @@ export const Changelog = () => {
<span className="grid-cols-5" />
<span className="grid-cols-4" />
</div>
<br/>
<br/>
),
id: "ah6t7c8sfzyrkp3u52",
},
{
name: "v0.9.0",
changelog: (
<div>
<strong className="flex items-center">
Version b-0.9.0 (August 15th 2024)
@ -291,7 +240,12 @@ export const Changelog = () => {
</i>
<br />
</div>
<br/>
),
id: "kjxnrfazc7hp9q4e82",
},
{
name: "v0.8.0",
changelog: (
<div>
<strong className="flex items-center">
Version b-0.8.0 (August 11th 2024)
@ -301,7 +255,12 @@ export const Changelog = () => {
<li> Renaming "Short Term" to "Statistics"</li>
</ul>
</div>
<br/>
),
id: "f8rmhwzuxk3qyds542",
},
{
name: "v0.7.2",
changelog: (
<div>
<strong className="flex items-center">
Version b-0.7.2 (August 7th 2024)
@ -312,7 +271,12 @@ export const Changelog = () => {
<li> Moved from Inngest to Vercel Cron</li>
</ul>
</div>
<br/>
),
id: "g2rhxfj6bu8wqk43n7",
},
{
name: "v0.7.0",
changelog: (
<div>
<strong className="flex items-center">
Version b-0.7.0 (August 7th 2024)
@ -323,7 +287,12 @@ export const Changelog = () => {
<li> Lots of bugfixes</li>
</ul>
</div>
<br/>
),
id: "a5xb97jv3surwmqn62",
},
{
name: "v0.6.0",
changelog: (
<div>
<strong className="flex items-center">
Version b-0.6.0 (August 3rd 2024)
@ -335,7 +304,12 @@ export const Changelog = () => {
<li> Lots of bugfixes</li>
</ul>
</div>
<br/>
),
id: "u83r5mkea9x4p2fjnb",
},
{
name: "v0.4.5",
changelog: (
<div>
<strong className="flex items-center">
Version b-0.4.5 (July 26th 2024):
@ -345,7 +319,12 @@ export const Changelog = () => {
<li> Sorted API endpoints</li>
</ul>
</div>
<br/>
),
id: "vu3k2daqj4y68bnwsp",
},
{
name: "v0.4.0",
changelog: (
<div>
<strong className="flex items-center">
Version b-0.4 (July 25th 2024):
@ -359,7 +338,12 @@ export const Changelog = () => {
</li>
</ul>
</div>
<br/>
),
id: "psr9tx5jah74d32vq6",
},
{
name: "v0.3.0",
changelog: (
<div>
<strong className="flex items-center">
Version b-0.3 (July 23th 2024):
@ -370,7 +354,12 @@ export const Changelog = () => {
</li>
</ul>
</div>
<br/>
),
id: "m2ngpd6fwtv7xh5zrk",
},
{
name: "v0.2.0",
changelog: (
<div>
<strong className="flex items-center">
Version b-0.2 (July 23th 2024):
@ -379,57 +368,7 @@ export const Changelog = () => {
<li> Inital release!</li>
</ul>
</div>
<br/>
<div>
<strong>All developers that helped out:</strong>
<Link href="https://dvelo.vercel.app">
<Image
src="/imgs/badge1.gif"
alt="cool badge"
width={88}
height={31}
className="w-[88px] h-[31px]"
/>
</Link>
</div>
</>
);
};
const Github = (props: SVGProps<SVGSVGElement>) => (
<svg
viewBox="0 0 256 250"
width="1em"
height="1em"
fill="#24292f"
xmlns="http://www.w3.org/2000/svg"
preserveAspectRatio="xMidYMid"
{...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" />
</svg>
);
import type { SVGProps } from "react";
import Marquee from "@/components/effects/marquee";
import { useRouter } from "@/lib/useRouter";
import { BookIcon } from "lucide-react";
import A from "@/components/misc/Link";
import { useDepTheme } from "@/lib/getDependentTheming";
const Discord = (props: SVGProps<SVGSVGElement>) => (
<svg
viewBox="0 0 256 199"
width="1em"
height="1em"
xmlns="http://www.w3.org/2000/svg"
preserveAspectRatio="xMidYMid"
{...props}
>
<path
d="M216.856 16.597A208.502 208.502 0 0 0 164.042 0c-2.275 4.113-4.933 9.645-6.766 14.046-19.692-2.961-39.203-2.961-58.533 0-1.832-4.4-4.55-9.933-6.846-14.046a207.809 207.809 0 0 0-52.855 16.638C5.618 67.147-3.443 116.4 1.087 164.956c22.169 16.555 43.653 26.612 64.775 33.193A161.094 161.094 0 0 0 79.735 175.3a136.413 136.413 0 0 1-21.846-10.632 108.636 108.636 0 0 0 5.356-4.237c42.122 19.702 87.89 19.702 129.51 0a131.66 131.66 0 0 0 5.355 4.237 136.07 136.07 0 0 1-21.886 10.653c4.006 8.02 8.638 15.67 13.873 22.848 21.142-6.58 42.646-16.637 64.815-33.213 5.316-56.288-9.08-105.09-38.056-148.36ZM85.474 135.095c-12.645 0-23.015-11.805-23.015-26.18s10.149-26.2 23.015-26.2c12.867 0 23.236 11.804 23.015 26.2.02 14.375-10.148 26.18-23.015 26.18Zm85.051 0c-12.645 0-23.014-11.805-23.014-26.18s10.148-26.2 23.014-26.2c12.867 0 23.236 11.804 23.015 26.2 0 14.375-10.148 26.18-23.015 26.18Z"
fill="#5865F2"
/>
</svg>
);
),
id: "xsfw2rcnv7m3kuhpbq",
},
];

@ -30,10 +30,14 @@
import { LinearClient, LinearFetch, User } from "@linear/sdk";
export async function createReportIssue(server: string, reportDescription: string, userId: string) {
export async function createReportIssue(
server: string,
reportDescription: string,
userId: string,
) {
const linearClient = new LinearClient({
apiKey: process.env.LINEAR
})
apiKey: process.env.LINEAR,
});
const allTeams = await linearClient.teams();
// Always grabs the first issue category.
@ -41,7 +45,12 @@ export async function createReportIssue(server: string, reportDescription: strin
// Ensure there *actually* is a team there
if (team.id) {
await linearClient.createIssue({teamId: team.id, title: `Issue against server \`${server}\``, description: desc(userId, server, reportDescription), assigneeId: (await team.members()).nodes[0].id })
await linearClient.createIssue({
teamId: team.id,
title: `Issue against server \`${server}\``,
description: desc(userId, server, reportDescription),
assigneeId: (await team.members()).nodes[0].id,
});
}
}
@ -56,4 +65,4 @@ ${reason}
*This was an automatically added issue by the report bot. Add the canceled status to remove the issue from the active issues, along with the labels Not Controllable & Spam for their respective values.*
`
`;

@ -0,0 +1,58 @@
/*
* 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.
*/
export async function getMinehutIcons(): Promise<MinehutIcon[] | undefined> {
const icons = await fetch("https://api.minehut.com/servers/icons");
console.log(icons);
if (!icons.ok) return undefined;
return await icons.json();
}
export type MinehutIcon = {
_id: string;
display_name: string;
icon_name: string;
price: number;
rank: string;
available: boolean;
disabled: boolean;
created: number;
last_updated: number;
__v: number;
salePrice: any;
};
export const rarityIndex = {
common: { bg: "#40464d", text: "#b7bfc5" },
uncommon: { bg: "#184f02", text: "#61bf01" },
rare: { bg: "#15448a", text: "#41afff" },
epic: { bg: "#4c1a7b", text: "#ce59ff" },
legendary: { bg: "#de6e0d", text: "#fce8cf" },
};

@ -41,126 +41,165 @@ const config = {
prefix: "",
theme: {
container: {
center: true,
padding: "2rem",
center: 'true',
padding: '2rem',
screens: {
"2xl": "1400px",
},
'2xl': '1400px'
}
},
extend: {
colors: {
border: "hsl(var(--border))",
input: "hsl(var(--input))",
ring: "hsl(var(--ring))",
background: "hsl(var(--background))",
foreground: "hsl(var(--foreground))",
border: 'hsl(var(--border))',
input: 'hsl(var(--input))',
ring: 'hsl(var(--ring))',
background: 'hsl(var(--background))',
foreground: 'hsl(var(--foreground))',
primary: {
DEFAULT: "hsl(var(--primary))",
foreground: "hsl(var(--primary-foreground))",
DEFAULT: 'hsl(var(--primary))',
foreground: 'hsl(var(--primary-foreground))'
},
secondary: {
DEFAULT: "hsl(var(--secondary))",
foreground: "hsl(var(--secondary-foreground))",
DEFAULT: 'hsl(var(--secondary))',
foreground: 'hsl(var(--secondary-foreground))'
},
destructive: {
DEFAULT: "hsl(var(--destructive))",
foreground: "hsl(var(--destructive-foreground))",
DEFAULT: 'hsl(var(--destructive))',
foreground: 'hsl(var(--destructive-foreground))'
},
muted: {
DEFAULT: "hsl(var(--muted))",
foreground: "hsl(var(--muted-foreground))",
DEFAULT: 'hsl(var(--muted))',
foreground: 'hsl(var(--muted-foreground))'
},
accent: {
DEFAULT: "hsl(var(--accent))",
foreground: "hsl(var(--accent-foreground))",
DEFAULT: 'hsl(var(--accent))',
foreground: 'hsl(var(--accent-foreground))'
},
popover: {
DEFAULT: "hsl(var(--popover))",
foreground: "hsl(var(--popover-foreground))",
DEFAULT: 'hsl(var(--popover))',
foreground: 'hsl(var(--popover-foreground))'
},
card: {
DEFAULT: "hsl(var(--card))",
foreground: "hsl(var(--card-foreground))",
DEFAULT: 'hsl(var(--card))',
foreground: 'hsl(var(--card-foreground))'
},
sidebar: {
DEFAULT: 'hsl(var(--sidebar-background))',
foreground: 'hsl(var(--sidebar-foreground))',
primary: 'hsl(var(--sidebar-primary))',
'primary-foreground': 'hsl(var(--sidebar-primary-foreground))',
accent: 'hsl(var(--sidebar-accent))',
'accent-foreground': 'hsl(var(--sidebar-accent-foreground))',
border: 'hsl(var(--sidebar-border))',
ring: 'hsl(var(--sidebar-ring))',
mhsf: 'hsl(var(--sidebar-mhsf))'
}
},
borderRadius: {
lg: "var(--radius)",
md: "calc(var(--radius) - 2px)",
sm: "calc(var(--radius) - 4px)",
lg: 'var(--radius)',
md: 'calc(var(--radius) - 2px)',
sm: 'calc(var(--radius) - 4px)'
},
keyframes: {
'image-glow': {
'0%': {
'opacity': '0',
'animation-timing-function': 'cubic-bezier(0.74, 0.25, 0.76, 1)',
opacity: '0',
'animation-timing-function': 'cubic-bezier(0.74, 0.25, 0.76, 1)'
},
'10%': {
'opacity': '0.7',
'animation-timing-function': 'cubic-bezier(0.12, 0.01, 0.08, 0.99)',
opacity: '0.7',
'animation-timing-function': 'cubic-bezier(0.12, 0.01, 0.08, 0.99)'
},
'100%': {
opacity: '0.4',
opacity: '0.4'
}
},
'border-beam': {
'100%': {
'offset-distance': '100%'
}
},
"border-beam": {
"100%": {
"offset-distance": "100%",
'caret-blink': {
'0%,70%,100%': {
opacity: '1'
},
'20%,50%': {
opacity: '0'
}
},
"caret-blink": {
"0%,70%,100%": { opacity: "1" },
"20%,50%": { opacity: "0" },
'accordion-down': {
from: {
height: '0'
},
"accordion-down": {
from: { height: "0" },
to: { height: "var(--radix-accordion-content-height)" },
to: {
height: 'var(--radix-accordion-content-height)'
}
},
"accordion-up": {
from: { height: "var(--radix-accordion-content-height)" },
to: { height: "0" },
'accordion-up': {
from: {
height: 'var(--radix-accordion-content-height)'
},
"fade-in": {
from: { opacity: "0", transform: "translateY(-10px)" },
to: { opacity: "1", transform: "none" },
to: {
height: '0'
}
},
'fade-in': {
from: {
opacity: '0',
transform: 'translateY(-10px)'
},
to: {
opacity: '1',
transform: 'none'
}
},
marquee: {
from: { transform: "translateX(0)" },
to: { transform: "translateX(calc(-100% - var(--gap)))" },
from: {
transform: 'translateX(0)'
},
"marquee-vertical": {
from: { transform: "translateY(0)" },
to: { transform: "translateY(calc(-100% - var(--gap)))" },
to: {
transform: 'translateX(calc(-100% - var(--gap)))'
}
},
"fade-up": {
from: { opacity: "0", transform: "translateY(20px)" },
to: { opacity: "1", transform: "none" },
'marquee-vertical': {
from: {
transform: 'translateY(0)'
},
'shimmer': {
to: {
transform: 'translateY(calc(-100% - var(--gap)))'
}
},
'fade-up': {
from: {
opacity: '0',
transform: 'translateY(20px)'
},
to: {
opacity: '1',
transform: 'none'
}
},
shimmer: {
'0%, 90%, 100%': {
'background-position': 'calc(-100% - var(--shimmer-width)) 0',
'background-position': 'calc(-100% - var(--shimmer-width)) 0'
},
'30%, 60%': {
'background-position': 'calc(100% + var(--shimmer-width)) 0',
},
},
'background-position': 'calc(100% + var(--shimmer-width)) 0'
}
}
},
animation: {
marquee: "marquee var(--duration) linear infinite",
"marquee-vertical": "marquee-vertical var(--duration) linear infinite",
"accordion-down": "accordion-down 0.2s ease-out",
"accordion-up": "accordion-up 0.2s ease-out",
marquee: 'marquee var(--duration) linear infinite',
'marquee-vertical': 'marquee-vertical var(--duration) linear infinite',
'accordion-down': 'accordion-down 0.2s ease-out',
'accordion-up': 'accordion-up 0.2s ease-out',
'image-glow': 'image-glow 4100ms 600ms ease-out forwards',
'shimmer': 'shimmer 8s infinite',
"fade-in": "fade-in 1000ms var(--animation-delay, 0ms) ease forwards",
"caret-blink": "caret-blink 1.25s ease-out infinite",
"border-beam": "border-beam calc(var(--duration)*1s) infinite linear",
"fade-up": "fade-up 1000ms var(--animation-delay, 0ms) ease forwards",
},
},
shimmer: 'shimmer 8s infinite',
'fade-in': 'fade-in 1000ms var(--animation-delay, 0ms) ease forwards',
'caret-blink': 'caret-blink 1.25s ease-out infinite',
'border-beam': 'border-beam calc(var(--duration)*1s) infinite linear',
'fade-up': 'fade-up 1000ms var(--animation-delay, 0ms) ease forwards'
}
}
},
plugins: [require("tailwindcss-animate"), require("@tailwindcss/typography")],
} satisfies Config;

193
yarn.lock

@ -1157,6 +1157,16 @@
dependencies:
"@radix-ui/react-primitive" "2.0.0"
"@radix-ui/react-avatar@^1.1.1":
version "1.1.1"
resolved "https://registry.yarnpkg.com/@radix-ui/react-avatar/-/react-avatar-1.1.1.tgz#5848d2ed5f34d18b36fc7e2d227c41fca8600ea1"
integrity sha512-eoOtThOmxeoizxpX6RiEsQZ2wj5r4+zoeqAwO0cBaFQGjJwIH3dIX0OCxNrCyrrdxG+vBweMETh3VziQG7c1kw==
dependencies:
"@radix-ui/react-context" "1.1.1"
"@radix-ui/react-primitive" "2.0.0"
"@radix-ui/react-use-callback-ref" "1.1.0"
"@radix-ui/react-use-layout-effect" "1.1.0"
"@radix-ui/react-checkbox@^1.1.1":
version "1.1.1"
resolved "https://registry.yarnpkg.com/@radix-ui/react-checkbox/-/react-checkbox-1.1.1.tgz#a559c4303957d797acee99914480b755aa1f27d6"
@ -1171,6 +1181,20 @@
"@radix-ui/react-use-previous" "1.1.0"
"@radix-ui/react-use-size" "1.1.0"
"@radix-ui/react-collapsible@^1.1.1":
version "1.1.1"
resolved "https://registry.yarnpkg.com/@radix-ui/react-collapsible/-/react-collapsible-1.1.1.tgz#1382cc9ec48f8b473c14f3779d317f0cdf6da5e9"
integrity sha512-1///SnrfQHJEofLokyczERxQbWfCGQlQ2XsCZMucVs6it+lq9iw4vXy+uDn1edlb58cOZOWSldnfPAYcT4O/Yg==
dependencies:
"@radix-ui/primitive" "1.1.0"
"@radix-ui/react-compose-refs" "1.1.0"
"@radix-ui/react-context" "1.1.1"
"@radix-ui/react-id" "1.1.0"
"@radix-ui/react-presence" "1.1.1"
"@radix-ui/react-primitive" "2.0.0"
"@radix-ui/react-use-controllable-state" "1.1.0"
"@radix-ui/react-use-layout-effect" "1.1.0"
"@radix-ui/react-collection@1.0.3":
version "1.0.3"
resolved "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.0.3.tgz"
@ -1229,6 +1253,11 @@
resolved "https://registry.yarnpkg.com/@radix-ui/react-context/-/react-context-1.1.0.tgz#6df8d983546cfd1999c8512f3a8ad85a6e7fcee8"
integrity sha512-OKrckBy+sMEgYM/sMmqmErVn0kZqrHPJze+Ql3DzYsDDp0hl0L62nx/2122/Bvps1qz645jlcu2tD9lrRSdf8A==
"@radix-ui/react-context@1.1.1":
version "1.1.1"
resolved "https://registry.yarnpkg.com/@radix-ui/react-context/-/react-context-1.1.1.tgz#82074aa83a472353bb22e86f11bcbd1c61c4c71a"
integrity sha512-UASk9zi+crv9WteK/NU4PLvOoL3OuE6BWVKNF6hPRBtYBDXQ2u5iu3O59zUlJiTVvkyuycnqrztsHVJwcK9K+Q==
"@radix-ui/react-dialog@1.0.5":
version "1.0.5"
resolved "https://registry.yarnpkg.com/@radix-ui/react-dialog/-/react-dialog-1.0.5.tgz#71657b1b116de6c7a0b03242d7d43e01062c7300"
@ -1250,7 +1279,7 @@
aria-hidden "^1.1.1"
react-remove-scroll "2.5.5"
"@radix-ui/react-dialog@^1.0.4", "@radix-ui/react-dialog@^1.1.1":
"@radix-ui/react-dialog@^1.0.4":
version "1.1.1"
resolved "https://registry.yarnpkg.com/@radix-ui/react-dialog/-/react-dialog-1.1.1.tgz#4906507f7b4ad31e22d7dad69d9330c87c431d44"
integrity sha512-zysS+iU4YP3STKNS6USvFVqI4qqx8EpiwmT5TuCApVEBca+eRCbONi4EgzfNSuVnOXvC5UPHHMjs8RXO6DH9Bg==
@ -1270,6 +1299,26 @@
aria-hidden "^1.1.1"
react-remove-scroll "2.5.7"
"@radix-ui/react-dialog@^1.1.2":
version "1.1.2"
resolved "https://registry.yarnpkg.com/@radix-ui/react-dialog/-/react-dialog-1.1.2.tgz#d9345575211d6f2d13e209e84aec9a8584b54d6c"
integrity sha512-Yj4dZtqa2o+kG61fzB0H2qUvmwBA2oyQroGLyNtBj1beo1khoQ3q1a2AO8rrQYjd8256CO9+N8L9tvsS+bnIyA==
dependencies:
"@radix-ui/primitive" "1.1.0"
"@radix-ui/react-compose-refs" "1.1.0"
"@radix-ui/react-context" "1.1.1"
"@radix-ui/react-dismissable-layer" "1.1.1"
"@radix-ui/react-focus-guards" "1.1.1"
"@radix-ui/react-focus-scope" "1.1.0"
"@radix-ui/react-id" "1.1.0"
"@radix-ui/react-portal" "1.1.2"
"@radix-ui/react-presence" "1.1.1"
"@radix-ui/react-primitive" "2.0.0"
"@radix-ui/react-slot" "1.1.0"
"@radix-ui/react-use-controllable-state" "1.1.0"
aria-hidden "^1.1.1"
react-remove-scroll "2.6.0"
"@radix-ui/react-direction@1.0.1":
version "1.0.1"
resolved "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.0.1.tgz"
@ -1305,16 +1354,27 @@
"@radix-ui/react-use-callback-ref" "1.1.0"
"@radix-ui/react-use-escape-keydown" "1.1.0"
"@radix-ui/react-dropdown-menu@^2.1.1":
version "2.1.1"
resolved "https://registry.yarnpkg.com/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.1.1.tgz#3dc578488688250dbbe109d9ff2ca28a9bca27ec"
integrity sha512-y8E+x9fBq9qvteD2Zwa4397pUVhYsh9iq44b5RD5qu1GMJWBCBuVg1hMyItbc6+zH00TxGRqd9Iot4wzf3OoBQ==
"@radix-ui/react-dismissable-layer@1.1.1":
version "1.1.1"
resolved "https://registry.yarnpkg.com/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.1.tgz#cbdcb739c5403382bdde5f9243042ba643883396"
integrity sha512-QSxg29lfr/xcev6kSz7MAlmDnzbP1eI/Dwn3Tp1ip0KT5CUELsxkekFEMVBEoykI3oV39hKT4TKZzBNMbcTZYQ==
dependencies:
"@radix-ui/primitive" "1.1.0"
"@radix-ui/react-compose-refs" "1.1.0"
"@radix-ui/react-context" "1.1.0"
"@radix-ui/react-primitive" "2.0.0"
"@radix-ui/react-use-callback-ref" "1.1.0"
"@radix-ui/react-use-escape-keydown" "1.1.0"
"@radix-ui/react-dropdown-menu@^2.1.2":
version "2.1.2"
resolved "https://registry.yarnpkg.com/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.1.2.tgz#acc49577130e3c875ef0133bd1e271ea3392d924"
integrity sha512-GVZMR+eqK8/Kes0a36Qrv+i20bAPXSn8rCBTHx30w+3ECnR5o3xixAlqcVaYvLeyKUsm0aqyhWfmUcqufM8nYA==
dependencies:
"@radix-ui/primitive" "1.1.0"
"@radix-ui/react-compose-refs" "1.1.0"
"@radix-ui/react-context" "1.1.1"
"@radix-ui/react-id" "1.1.0"
"@radix-ui/react-menu" "2.1.1"
"@radix-ui/react-menu" "2.1.2"
"@radix-ui/react-primitive" "2.0.0"
"@radix-ui/react-use-controllable-state" "1.1.0"
@ -1330,6 +1390,11 @@
resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.0.tgz#8e9abb472a9a394f59a1b45f3dd26cfe3fc6da13"
integrity sha512-w6XZNUPVv6xCpZUqb/yN9DL6auvpGX3C/ee6Hdi16v2UUy25HV2Q5bcflsiDyT/g5RwbPQ/GIT1vLkeRb+ITBw==
"@radix-ui/react-focus-guards@1.1.1":
version "1.1.1"
resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.1.tgz#8635edd346304f8b42cae86b05912b61aef27afe"
integrity sha512-pSIwfrT1a6sIoDASCSpFwOasEwKTZWDw/iBdtnqKO7v6FeOzYJ7U53cPzYFVR3geGGXgVHaH+CdngrrAzqUGxg==
"@radix-ui/react-focus-scope@1.0.4":
version "1.0.4"
resolved "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.0.4.tgz"
@ -1440,6 +1505,30 @@
aria-hidden "^1.1.1"
react-remove-scroll "2.5.7"
"@radix-ui/react-menu@2.1.2":
version "2.1.2"
resolved "https://registry.yarnpkg.com/@radix-ui/react-menu/-/react-menu-2.1.2.tgz#91f6815845a4298dde775563ed2d80b7ad667899"
integrity sha512-lZ0R4qR2Al6fZ4yCCZzu/ReTFrylHFxIqy7OezIpWF4bL0o9biKo0pFIvkaew3TyZ9Fy5gYVrR5zCGZBVbO1zg==
dependencies:
"@radix-ui/primitive" "1.1.0"
"@radix-ui/react-collection" "1.1.0"
"@radix-ui/react-compose-refs" "1.1.0"
"@radix-ui/react-context" "1.1.1"
"@radix-ui/react-direction" "1.1.0"
"@radix-ui/react-dismissable-layer" "1.1.1"
"@radix-ui/react-focus-guards" "1.1.1"
"@radix-ui/react-focus-scope" "1.1.0"
"@radix-ui/react-id" "1.1.0"
"@radix-ui/react-popper" "1.2.0"
"@radix-ui/react-portal" "1.1.2"
"@radix-ui/react-presence" "1.1.1"
"@radix-ui/react-primitive" "2.0.0"
"@radix-ui/react-roving-focus" "1.1.0"
"@radix-ui/react-slot" "1.1.0"
"@radix-ui/react-use-callback-ref" "1.1.0"
aria-hidden "^1.1.1"
react-remove-scroll "2.6.0"
"@radix-ui/react-menubar@^1.1.1":
version "1.1.1"
resolved "https://registry.yarnpkg.com/@radix-ui/react-menubar/-/react-menubar-1.1.1.tgz#e126514cb1c46e0a4f9fba7d016e578cc4e41f22"
@ -1548,6 +1637,14 @@
"@radix-ui/react-primitive" "2.0.0"
"@radix-ui/react-use-layout-effect" "1.1.0"
"@radix-ui/react-portal@1.1.2":
version "1.1.2"
resolved "https://registry.yarnpkg.com/@radix-ui/react-portal/-/react-portal-1.1.2.tgz#51eb46dae7505074b306ebcb985bf65cc547d74e"
integrity sha512-WeDYLGPxJb/5EGBoedyJbT0MpoULmwnIPMJMSldkuiMsBAv7N1cRdsTWZWht9vpPOiN3qyiGAtbK2is47/uMFg==
dependencies:
"@radix-ui/react-primitive" "2.0.0"
"@radix-ui/react-use-layout-effect" "1.1.0"
"@radix-ui/react-presence@1.0.1":
version "1.0.1"
resolved "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.0.1.tgz"
@ -1565,6 +1662,14 @@
"@radix-ui/react-compose-refs" "1.1.0"
"@radix-ui/react-use-layout-effect" "1.1.0"
"@radix-ui/react-presence@1.1.1":
version "1.1.1"
resolved "https://registry.yarnpkg.com/@radix-ui/react-presence/-/react-presence-1.1.1.tgz#98aba423dba5e0c687a782c0669dcd99de17f9b1"
integrity sha512-IeFXVi4YS1K0wVZzXNrbaaUvIJ3qdY+/Ih4eHFhWA9SwGR9UDX7Ck8abvL57C4cv3wwMvUE0OG69Qc3NCcTe/A==
dependencies:
"@radix-ui/react-compose-refs" "1.1.0"
"@radix-ui/react-use-layout-effect" "1.1.0"
"@radix-ui/react-primitive@1.0.3":
version "1.0.3"
resolved "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-1.0.3.tgz"
@ -1642,13 +1747,12 @@
"@radix-ui/react-use-callback-ref" "1.1.0"
"@radix-ui/react-use-layout-effect" "1.1.0"
"@radix-ui/react-separator@^1.0.3":
version "1.0.3"
resolved "https://registry.npmjs.org/@radix-ui/react-separator/-/react-separator-1.0.3.tgz"
integrity sha512-itYmTy/kokS21aiV5+Z56MZB54KrhPgn6eHDKkFeOLR34HMN2s8PaN47qZZAGnvupcjxHaFZnW4pQEh0BvvVuw==
"@radix-ui/react-separator@^1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@radix-ui/react-separator/-/react-separator-1.1.0.tgz#ee0f4d86003b0e3ea7bc6ccab01ea0adee32663e"
integrity sha512-3uBAs+egzvJBDZAzvb/n4NxxOYpnspmWxO2u5NbZ8Y6FM/NdrGSF9bop3Cf6F6C71z1rTSn8KV0Fo2ZVd79lGA==
dependencies:
"@babel/runtime" "^7.13.10"
"@radix-ui/react-primitive" "1.0.3"
"@radix-ui/react-primitive" "2.0.0"
"@radix-ui/react-slot@1.0.2":
version "1.0.2"
@ -1692,24 +1796,23 @@
"@radix-ui/react-roving-focus" "1.1.0"
"@radix-ui/react-use-controllable-state" "1.1.0"
"@radix-ui/react-tooltip@^1.0.7":
version "1.0.7"
resolved "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.0.7.tgz"
integrity sha512-lPh5iKNFVQ/jav/j6ZrWq3blfDJ0OH9R6FlNUHPMqdLuQ9vwDgFsRxvl8b7Asuy5c8xmoojHUxKHQSOAvMHxyw==
"@radix-ui/react-tooltip@^1.1.3":
version "1.1.3"
resolved "https://registry.yarnpkg.com/@radix-ui/react-tooltip/-/react-tooltip-1.1.3.tgz#4250b14723f2d8477e7a3d0526c169f91d1f2f74"
integrity sha512-Z4w1FIS0BqVFI2c1jZvb/uDVJijJjJ2ZMuPV81oVgTZ7g3BZxobplnMVvXtFWgtozdvYJ+MFWtwkM5S2HnAong==
dependencies:
"@babel/runtime" "^7.13.10"
"@radix-ui/primitive" "1.0.1"
"@radix-ui/react-compose-refs" "1.0.1"
"@radix-ui/react-context" "1.0.1"
"@radix-ui/react-dismissable-layer" "1.0.5"
"@radix-ui/react-id" "1.0.1"
"@radix-ui/react-popper" "1.1.3"
"@radix-ui/react-portal" "1.0.4"
"@radix-ui/react-presence" "1.0.1"
"@radix-ui/react-primitive" "1.0.3"
"@radix-ui/react-slot" "1.0.2"
"@radix-ui/react-use-controllable-state" "1.0.1"
"@radix-ui/react-visually-hidden" "1.0.3"
"@radix-ui/primitive" "1.1.0"
"@radix-ui/react-compose-refs" "1.1.0"
"@radix-ui/react-context" "1.1.1"
"@radix-ui/react-dismissable-layer" "1.1.1"
"@radix-ui/react-id" "1.1.0"
"@radix-ui/react-popper" "1.2.0"
"@radix-ui/react-portal" "1.1.2"
"@radix-ui/react-presence" "1.1.1"
"@radix-ui/react-primitive" "2.0.0"
"@radix-ui/react-slot" "1.1.0"
"@radix-ui/react-use-controllable-state" "1.1.0"
"@radix-ui/react-visually-hidden" "1.1.0"
"@radix-ui/react-use-callback-ref@1.0.1":
version "1.0.1"
@ -1815,6 +1918,13 @@
"@babel/runtime" "^7.13.10"
"@radix-ui/react-primitive" "1.0.3"
"@radix-ui/react-visually-hidden@1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.1.0.tgz#ad47a8572580f7034b3807c8e6740cd41038a5a2"
integrity sha512-N8MDZqtgCgG5S3aV60INAB475osJousYpZ4cTJ2cFbMpdHS5Y6loLTH8LPtkj2QN0x93J30HT/M3qJXM0+lyeQ==
dependencies:
"@radix-ui/react-primitive" "2.0.0"
"@radix-ui/rect@1.0.1":
version "1.0.1"
resolved "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.0.1.tgz"
@ -2809,7 +2919,7 @@ citty@^0.1.6:
class-variance-authority@^0.7.0:
version "0.7.0"
resolved "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.7.0.tgz"
resolved "https://registry.yarnpkg.com/class-variance-authority/-/class-variance-authority-0.7.0.tgz#1c3134d634d80271b1837452b06d821915954522"
integrity sha512-jFI8IQw4hczaL4ALINxqLEXQbWcNjoSkloa4IaufXCJr6QawJyw7tuRysRsrE8w2p/4gGaxKIt/hX3qz/IbD1A==
dependencies:
clsx "2.0.0"
@ -5010,10 +5120,10 @@ lru-cache@^10.2.0:
resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.2.tgz"
integrity sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==
lucide-react@^0.416.0:
version "0.416.0"
resolved "https://registry.yarnpkg.com/lucide-react/-/lucide-react-0.416.0.tgz#657da248f9b862703d7d80aafb912e79ad886313"
integrity sha512-wPWxTzdss1CTz2aqcNWNlbh4YSnH9neJWP3RaeXepxpLCTW+pmu7WcT/wxJe+Q7Y7DqGOxAqakJv0pIK3431Ag==
lucide-react@^0.454.0:
version "0.454.0"
resolved "https://registry.yarnpkg.com/lucide-react/-/lucide-react-0.454.0.tgz#a81b9c482018720f07ead0503ae502d94d528444"
integrity sha512-hw7zMDwykCLnEzgncEEjHeA6+45aeEzRYuKHuyRSOPkhko+J3ySGjGIzu+mmMfDFG1vazHepMaYFYHbTFAZAAQ==
luxon@~3.4.0:
version "3.4.4"
@ -6708,7 +6818,7 @@ react-markdown@^9.0.1:
unist-util-visit "^5.0.0"
vfile "^6.0.0"
react-remove-scroll-bar@^2.3.3, react-remove-scroll-bar@^2.3.4:
react-remove-scroll-bar@^2.3.3, react-remove-scroll-bar@^2.3.4, react-remove-scroll-bar@^2.3.6:
version "2.3.6"
resolved "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.6.tgz"
integrity sha512-DtSYaao4mBmX+HDo5YWYdBWQwYIQQshUV/dVxFxK+KM26Wjwp1gZ6rv6OC3oujI6Bfu6Xyg3TwK533AQutsn/g==
@ -6738,6 +6848,17 @@ react-remove-scroll@2.5.7:
use-callback-ref "^1.3.0"
use-sidecar "^1.1.2"
react-remove-scroll@2.6.0:
version "2.6.0"
resolved "https://registry.yarnpkg.com/react-remove-scroll/-/react-remove-scroll-2.6.0.tgz#fb03a0845d7768a4f1519a99fdb84983b793dc07"
integrity sha512-I2U4JVEsQenxDAKaVa3VZ/JeJZe0/2DxPWL8Tj8yLKctQJQiZM52pn/GWFpSp8dftjM3pSAHVJZscAnC/y+ySQ==
dependencies:
react-remove-scroll-bar "^2.3.6"
react-style-singleton "^2.2.1"
tslib "^2.1.0"
use-callback-ref "^1.3.0"
use-sidecar "^1.1.2"
react-resizable-panels@^2.0.23:
version "2.0.23"
resolved "https://registry.yarnpkg.com/react-resizable-panels/-/react-resizable-panels-2.0.23.tgz#7a4296f23028c32ffcbe8086aa918cd934e7e87f"