mirror of
https://github.com/DeveloLongScript/MHSF.git
synced 2026-05-07 19:35:00 -05:00
chore: move dev branch commits -> main
chore: move dev branch commits -> main
This commit is contained in:
commit
cbdcc74ce8
@ -44,7 +44,7 @@
|
|||||||
"next": "14.2.10",
|
"next": "14.2.10",
|
||||||
"next-contentlayer": "^0.3.4",
|
"next-contentlayer": "^0.3.4",
|
||||||
"next-css-obfuscator": "^2.2.16",
|
"next-css-obfuscator": "^2.2.16",
|
||||||
"next-themes": "^0.3.0",
|
"next-themes": "^0.4.3",
|
||||||
"nextjs-toploader": "^1.6.12",
|
"nextjs-toploader": "^1.6.12",
|
||||||
"nprogress": "^0.2.0",
|
"nprogress": "^0.2.0",
|
||||||
"postcss-obfuscator": "^1.6.1",
|
"postcss-obfuscator": "^1.6.1",
|
||||||
@ -53,9 +53,11 @@
|
|||||||
"react-dom": "^18",
|
"react-dom": "^18",
|
||||||
"react-fade-in": "^2.0.1",
|
"react-fade-in": "^2.0.1",
|
||||||
"react-fast-marquee": "^1.6.5",
|
"react-fast-marquee": "^1.6.5",
|
||||||
|
"react-hot-toast": "^2.4.1",
|
||||||
"react-qr-code": "^2.0.15",
|
"react-qr-code": "^2.0.15",
|
||||||
"rehype-slug": "^6.0.0",
|
"rehype-slug": "^6.0.0",
|
||||||
"remark-gfm": "^4.0.0",
|
"remark-gfm": "^4.0.0",
|
||||||
|
"sonner": "^1.7.0",
|
||||||
"tailwind-merge": "^2.3.0",
|
"tailwind-merge": "^2.3.0",
|
||||||
"tailwindcss-animate": "^1.0.7",
|
"tailwindcss-animate": "^1.0.7",
|
||||||
"tailwindcss-patch": "^4.0.0",
|
"tailwindcss-patch": "^4.0.0",
|
||||||
@ -101,7 +103,6 @@
|
|||||||
"mangle-css-class-webpack-plugin": "^5.1.0",
|
"mangle-css-class-webpack-plugin": "^5.1.0",
|
||||||
"postcss": "^8",
|
"postcss": "^8",
|
||||||
"react-hook-form": "^7.52.2",
|
"react-hook-form": "^7.52.2",
|
||||||
"react-hot-toast": "^2.4.1",
|
|
||||||
"react-hotkeys-hook": "^4.5.0",
|
"react-hotkeys-hook": "^4.5.0",
|
||||||
"react-infinite-scroll-component": "^6.1.0",
|
"react-infinite-scroll-component": "^6.1.0",
|
||||||
"react-markdown": "^9.0.1",
|
"react-markdown": "^9.0.1",
|
||||||
|
|||||||
@ -31,7 +31,7 @@
|
|||||||
"use client";
|
"use client";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { useClerk, useUser } from "@clerk/nextjs";
|
import { useClerk, useUser } from "@clerk/nextjs";
|
||||||
import toast from "react-hot-toast";
|
import { toast } from "sonner";
|
||||||
import { unlinkMCAccount } from "@/lib/api";
|
import { unlinkMCAccount } from "@/lib/api";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { Dialog } from "@/components/ui/dialog";
|
import { Dialog } from "@/components/ui/dialog";
|
||||||
|
|||||||
@ -32,6 +32,7 @@ import AfterServerView from "@/components/AfterServerView";
|
|||||||
import Banner from "@/components/Banner";
|
import Banner from "@/components/Banner";
|
||||||
import ColorProvider from "@/components/ColorProvider";
|
import ColorProvider from "@/components/ColorProvider";
|
||||||
import ServerView from "@/components/ServerView";
|
import ServerView from "@/components/ServerView";
|
||||||
|
import StickyTopbar from "@/components/misc/StickyTopbar";
|
||||||
import TabServer from "@/components/misc/TabServer";
|
import TabServer from "@/components/misc/TabServer";
|
||||||
import { Separator } from "@/components/ui/separator";
|
import { Separator } from "@/components/ui/separator";
|
||||||
import type { Metadata, ResolvingMetadata } from "next";
|
import type { Metadata, ResolvingMetadata } from "next";
|
||||||
@ -132,7 +133,9 @@ export default function ServerPage({ params }: { params: { server: string } }) {
|
|||||||
<ColorProvider server={params.server}>
|
<ColorProvider server={params.server}>
|
||||||
<div className={"pt-16 xl:px-[100px]"}>
|
<div className={"pt-16 xl:px-[100px]"}>
|
||||||
<Banner server={params.server} />
|
<Banner server={params.server} />
|
||||||
<TabServer server={params.server} tabDef="general" />
|
<StickyTopbar scrollElevation={100} className="pt-4">
|
||||||
|
<TabServer server={params.server} tabDef="general" />
|
||||||
|
</StickyTopbar>
|
||||||
<div className="pt-8">
|
<div className="pt-8">
|
||||||
<ServerView server={params.server} />
|
<ServerView server={params.server} />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -41,7 +41,8 @@ import { Copy, Info, QrCode, Share2 } from "lucide-react";
|
|||||||
import { useTheme } from "next-themes";
|
import { useTheme } from "next-themes";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import FadeIn from "react-fade-in/lib/FadeIn";
|
import FadeIn from "react-fade-in/lib/FadeIn";
|
||||||
import toast, { CheckmarkIcon } from "react-hot-toast";
|
import { CheckmarkIcon } from "react-hot-toast";
|
||||||
|
import { toast } from "sonner";
|
||||||
import Markdown from "react-markdown";
|
import Markdown from "react-markdown";
|
||||||
import IconDisplay from "./IconDisplay";
|
import IconDisplay from "./IconDisplay";
|
||||||
import AchievementList from "./feat/AchievementList";
|
import AchievementList from "./feat/AchievementList";
|
||||||
|
|||||||
@ -68,7 +68,7 @@ import {
|
|||||||
} from "@/lib/api";
|
} from "@/lib/api";
|
||||||
import IconDisplay from "./IconDisplay";
|
import IconDisplay from "./IconDisplay";
|
||||||
import ServerSingle from "@/lib/single";
|
import ServerSingle from "@/lib/single";
|
||||||
import toast from "react-hot-toast";
|
import { toast } from "sonner";
|
||||||
import { ServerResponse, OnlineServer } from "@/lib/types/mh-server";
|
import { ServerResponse, OnlineServer } from "@/lib/types/mh-server";
|
||||||
import {
|
import {
|
||||||
Dialog,
|
Dialog,
|
||||||
@ -80,6 +80,7 @@ import {
|
|||||||
import { TagShower } from "./ServerList";
|
import { TagShower } from "./ServerList";
|
||||||
import { Button } from "./ui/button";
|
import { Button } from "./ui/button";
|
||||||
import { useTheme } from "next-themes";
|
import { useTheme } from "next-themes";
|
||||||
|
import { CheckmarkIcon } from "react-hot-toast";
|
||||||
|
|
||||||
export function SearchCommandBar() {
|
export function SearchCommandBar() {
|
||||||
const [serverList, setServerList] = useState<OnlineServer[]>([]);
|
const [serverList, setServerList] = useState<OnlineServer[]>([]);
|
||||||
@ -278,7 +279,7 @@ export function OfflineServerCB() {
|
|||||||
|
|
||||||
{customized && (
|
{customized && (
|
||||||
<h2 className="flex items-center text-muted-foreground">
|
<h2 className="flex items-center text-muted-foreground">
|
||||||
<CheckIcon />
|
<CheckmarkIcon />
|
||||||
<span className="pl-1.5 text-[16px]">
|
<span className="pl-1.5 text-[16px]">
|
||||||
Is customized by a MHSF User
|
Is customized by a MHSF User
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@ -30,13 +30,12 @@
|
|||||||
|
|
||||||
"use client";
|
"use client";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { Spinner } from "./ui/spinner";
|
|
||||||
import { Card, CardHeader, CardTitle } from "./ui/card";
|
import { Card, CardHeader, CardTitle } from "./ui/card";
|
||||||
import type { ServerResponse } from "@/lib/types/mh-server";
|
import type { ServerResponse } from "@/lib/types/mh-server";
|
||||||
import { useEffectOnce } from "@/lib/useEffectOnce";
|
import { useEffectOnce } from "@/lib/useEffectOnce";
|
||||||
import { Button } from "./ui/button";
|
import { Button } from "./ui/button";
|
||||||
import { Copy, Layers, XIcon } from "lucide-react";
|
import { Copy, Layers, XIcon } from "lucide-react";
|
||||||
import toast from "react-hot-toast";
|
import { toast } from "sonner";
|
||||||
import { Tooltip, TooltipContent, TooltipTrigger } from "./ui/tooltip";
|
import { Tooltip, TooltipContent, TooltipTrigger } from "./ui/tooltip";
|
||||||
import { getAccountFavorites } from "@/lib/api";
|
import { getAccountFavorites } from "@/lib/api";
|
||||||
import { useRouter } from "@/lib/useRouter";
|
import { useRouter } from "@/lib/useRouter";
|
||||||
|
|||||||
@ -41,62 +41,62 @@ import type { SVGProps } from "react";
|
|||||||
* @returns A JSX element representing the colorful branding icon.
|
* @returns A JSX element representing the colorful branding icon.
|
||||||
*/
|
*/
|
||||||
export function BrandingColorfulIcon(props: SVGProps<SVGSVGElement>) {
|
export function BrandingColorfulIcon(props: SVGProps<SVGSVGElement>) {
|
||||||
return (
|
return (
|
||||||
<svg
|
<svg
|
||||||
width="266"
|
width="266"
|
||||||
height="265"
|
height="265"
|
||||||
viewBox="0 0 266 265"
|
viewBox="0 0 266 265"
|
||||||
fill="none"
|
fill="none"
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
<rect
|
<rect
|
||||||
x="0.524048"
|
x="0.524048"
|
||||||
width="264.939"
|
width="264.939"
|
||||||
height="264.939"
|
height="264.939"
|
||||||
rx="66"
|
rx="66"
|
||||||
fill="url(#paint0_linear_1_19)"
|
fill="url(#paint0_linear_1_19)"
|
||||||
/>
|
/>
|
||||||
<path
|
<path
|
||||||
d="M104.513 123.27H94.8717C92.3148 123.27 89.8626 122.254 88.0546 120.446C86.2466 118.638 85.2309 116.186 85.2309 113.629V94.3476C85.2309 91.7907 86.2466 89.3385 88.0546 87.5305C89.8626 85.7225 92.3148 84.7068 94.8717 84.7068H171.998C174.555 84.7068 177.007 85.7225 178.815 87.5305C180.623 89.3385 181.639 91.7907 181.639 94.3476V113.629C181.639 116.186 180.623 118.638 178.815 120.446C177.007 122.254 174.555 123.27 171.998 123.27H162.357M104.513 142.552H94.8717C92.3148 142.552 89.8626 143.567 88.0546 145.376C86.2466 147.184 85.2309 149.636 85.2309 152.193V171.474C85.2309 174.031 86.2466 176.483 88.0546 178.291C89.8626 180.099 92.3148 181.115 94.8717 181.115H171.998C174.555 181.115 177.007 180.099 178.815 178.291C180.623 176.483 181.639 174.031 181.639 171.474V152.193C181.639 149.636 180.623 147.184 178.815 145.376C177.007 143.567 174.555 142.552 171.998 142.552H162.357M104.513 103.988H104.561M104.513 161.833H104.561M138.255 103.988L118.974 132.911H147.896L128.615 161.833"
|
d="M104.513 123.27H94.8717C92.3148 123.27 89.8626 122.254 88.0546 120.446C86.2466 118.638 85.2309 116.186 85.2309 113.629V94.3476C85.2309 91.7907 86.2466 89.3385 88.0546 87.5305C89.8626 85.7225 92.3148 84.7068 94.8717 84.7068H171.998C174.555 84.7068 177.007 85.7225 178.815 87.5305C180.623 89.3385 181.639 91.7907 181.639 94.3476V113.629C181.639 116.186 180.623 118.638 178.815 120.446C177.007 122.254 174.555 123.27 171.998 123.27H162.357M104.513 142.552H94.8717C92.3148 142.552 89.8626 143.567 88.0546 145.376C86.2466 147.184 85.2309 149.636 85.2309 152.193V171.474C85.2309 174.031 86.2466 176.483 88.0546 178.291C89.8626 180.099 92.3148 181.115 94.8717 181.115H171.998C174.555 181.115 177.007 180.099 178.815 178.291C180.623 176.483 181.639 174.031 181.639 171.474V152.193C181.639 149.636 180.623 147.184 178.815 145.376C177.007 143.567 174.555 142.552 171.998 142.552H162.357M104.513 103.988H104.561M104.513 161.833H104.561M138.255 103.988L118.974 132.911H147.896L128.615 161.833"
|
||||||
stroke="white"
|
stroke="white"
|
||||||
stroke-width="10"
|
stroke-width="10"
|
||||||
stroke-linecap="round"
|
stroke-linecap="round"
|
||||||
stroke-linejoin="round"
|
stroke-linejoin="round"
|
||||||
/>
|
/>
|
||||||
<circle
|
<circle
|
||||||
cx="132.993"
|
cx="132.993"
|
||||||
cy="132.469"
|
cy="132.469"
|
||||||
r="91.3779"
|
r="91.3779"
|
||||||
stroke="url(#paint1_linear_1_19)"
|
stroke="url(#paint1_linear_1_19)"
|
||||||
stroke-width="8"
|
stroke-width="8"
|
||||||
/>
|
/>
|
||||||
<defs>
|
<defs>
|
||||||
<linearGradient
|
<linearGradient
|
||||||
id="paint0_linear_1_19"
|
id="paint0_linear_1_19"
|
||||||
x1="107.824"
|
x1="107.824"
|
||||||
y1="54.754"
|
y1="54.754"
|
||||||
x2="230.579"
|
x2="230.579"
|
||||||
y2="225.198"
|
y2="225.198"
|
||||||
gradientUnits="userSpaceOnUse"
|
gradientUnits="userSpaceOnUse"
|
||||||
>
|
>
|
||||||
<stop stop-color="#007BFF" />
|
<stop stop-color="#007BFF" />
|
||||||
<stop offset="1" stop-color="#BF00FF" stop-opacity="0.5" />
|
<stop offset="1" stop-color="#BF00FF" stop-opacity="0.5" />
|
||||||
</linearGradient>
|
</linearGradient>
|
||||||
<linearGradient
|
<linearGradient
|
||||||
id="paint1_linear_1_19"
|
id="paint1_linear_1_19"
|
||||||
x1="132.993"
|
x1="132.993"
|
||||||
y1="37.0914"
|
y1="37.0914"
|
||||||
x2="132.993"
|
x2="132.993"
|
||||||
y2="227.847"
|
y2="227.847"
|
||||||
gradientUnits="userSpaceOnUse"
|
gradientUnits="userSpaceOnUse"
|
||||||
>
|
>
|
||||||
<stop stop-color="#EFEC32" />
|
<stop stop-color="#EFEC32" />
|
||||||
<stop offset="1" stop-color="#98FF60" />
|
<stop offset="1" stop-color="#98FF60" />
|
||||||
</linearGradient>
|
</linearGradient>
|
||||||
</defs>
|
</defs>
|
||||||
</svg>
|
</svg>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Returns the optional Pride icon
|
* Returns the optional Pride icon
|
||||||
@ -107,71 +107,71 @@ export function BrandingColorfulIcon(props: SVGProps<SVGSVGElement>) {
|
|||||||
* @returns A JSX element representing the branding icon.
|
* @returns A JSX element representing the branding icon.
|
||||||
*/
|
*/
|
||||||
export function BrandingPrideIcon(props: SVGProps<SVGSVGElement>) {
|
export function BrandingPrideIcon(props: SVGProps<SVGSVGElement>) {
|
||||||
return (
|
return (
|
||||||
<svg
|
<svg
|
||||||
width="265"
|
width="265"
|
||||||
height="265"
|
height="265"
|
||||||
viewBox="0 0 265 265"
|
viewBox="0 0 265 265"
|
||||||
fill="none"
|
fill="none"
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
<rect
|
<rect
|
||||||
width="264.939"
|
width="264.939"
|
||||||
height="264.939"
|
height="264.939"
|
||||||
rx="66"
|
rx="66"
|
||||||
fill="url(#paint0_linear_1_30)"
|
fill="url(#paint0_linear_1_30)"
|
||||||
/>
|
/>
|
||||||
<path
|
<path
|
||||||
d="M103.988 123.27H94.3476C91.7907 123.27 89.3385 122.254 87.5305 120.446C85.7225 118.638 84.7068 116.186 84.7068 113.629V94.3476C84.7068 91.7907 85.7225 89.3385 87.5305 87.5305C89.3385 85.7225 91.7907 84.7068 94.3476 84.7068H171.474C174.031 84.7068 176.483 85.7225 178.291 87.5305C180.099 89.3385 181.115 91.7907 181.115 94.3476V113.629C181.115 116.186 180.099 118.638 178.291 120.446C176.483 122.254 174.031 123.27 171.474 123.27H161.833M103.988 142.552H94.3476C91.7907 142.552 89.3385 143.567 87.5305 145.376C85.7225 147.184 84.7068 149.636 84.7068 152.193V171.474C84.7068 174.031 85.7225 176.483 87.5305 178.291C89.3385 180.099 91.7907 181.115 94.3476 181.115H171.474C174.031 181.115 176.483 180.099 178.291 178.291C180.099 176.483 181.115 174.031 181.115 171.474V152.193C181.115 149.636 180.099 147.184 178.291 145.376C176.483 143.567 174.031 142.552 171.474 142.552H161.833M103.988 103.988H104.037M103.988 161.833H104.037M137.731 103.988L118.45 132.911H147.372L128.091 161.833"
|
d="M103.988 123.27H94.3476C91.7907 123.27 89.3385 122.254 87.5305 120.446C85.7225 118.638 84.7068 116.186 84.7068 113.629V94.3476C84.7068 91.7907 85.7225 89.3385 87.5305 87.5305C89.3385 85.7225 91.7907 84.7068 94.3476 84.7068H171.474C174.031 84.7068 176.483 85.7225 178.291 87.5305C180.099 89.3385 181.115 91.7907 181.115 94.3476V113.629C181.115 116.186 180.099 118.638 178.291 120.446C176.483 122.254 174.031 123.27 171.474 123.27H161.833M103.988 142.552H94.3476C91.7907 142.552 89.3385 143.567 87.5305 145.376C85.7225 147.184 84.7068 149.636 84.7068 152.193V171.474C84.7068 174.031 85.7225 176.483 87.5305 178.291C89.3385 180.099 91.7907 181.115 94.3476 181.115H171.474C174.031 181.115 176.483 180.099 178.291 178.291C180.099 176.483 181.115 174.031 181.115 171.474V152.193C181.115 149.636 180.099 147.184 178.291 145.376C176.483 143.567 174.031 142.552 171.474 142.552H161.833M103.988 103.988H104.037M103.988 161.833H104.037M137.731 103.988L118.45 132.911H147.372L128.091 161.833"
|
||||||
stroke="white"
|
stroke="white"
|
||||||
stroke-width="10"
|
stroke-width="10"
|
||||||
stroke-linecap="round"
|
stroke-linecap="round"
|
||||||
stroke-linejoin="round"
|
stroke-linejoin="round"
|
||||||
/>
|
/>
|
||||||
<circle
|
<circle
|
||||||
cx="132.469"
|
cx="132.469"
|
||||||
cy="132.469"
|
cy="132.469"
|
||||||
r="91.3779"
|
r="91.3779"
|
||||||
stroke="url(#paint1_linear_1_30)"
|
stroke="url(#paint1_linear_1_30)"
|
||||||
stroke-width="8"
|
stroke-width="8"
|
||||||
/>
|
/>
|
||||||
<defs>
|
<defs>
|
||||||
<linearGradient
|
<linearGradient
|
||||||
id="paint0_linear_1_30"
|
id="paint0_linear_1_30"
|
||||||
x1="51.6631"
|
x1="51.6631"
|
||||||
y1="26.9354"
|
y1="26.9354"
|
||||||
x2="222.549"
|
x2="222.549"
|
||||||
y2="213.717"
|
y2="213.717"
|
||||||
gradientUnits="userSpaceOnUse"
|
gradientUnits="userSpaceOnUse"
|
||||||
>
|
>
|
||||||
<stop stop-color="#FF0000" />
|
<stop stop-color="#FF0000" />
|
||||||
<stop offset="0.110405" stop-color="#FF6200" />
|
<stop offset="0.110405" stop-color="#FF6200" />
|
||||||
<stop offset="0.225785" stop-color="#FFAE00" />
|
<stop offset="0.225785" stop-color="#FFAE00" />
|
||||||
<stop offset="0.326294" stop-color="#FFD500" />
|
<stop offset="0.326294" stop-color="#FFD500" />
|
||||||
<stop offset="0.422381" stop-color="#99EA00" />
|
<stop offset="0.422381" stop-color="#99EA00" />
|
||||||
<stop offset="0.498373" stop-color="#4DF457" />
|
<stop offset="0.498373" stop-color="#4DF457" />
|
||||||
<stop offset="0.593491" stop-color="#26D3AB" />
|
<stop offset="0.593491" stop-color="#26D3AB" />
|
||||||
<stop offset="0.699814" stop-color="#13A9D5" />
|
<stop offset="0.699814" stop-color="#13A9D5" />
|
||||||
<stop offset="0.805673" stop-color="#A200FF" />
|
<stop offset="0.805673" stop-color="#A200FF" />
|
||||||
<stop offset="0.884464" stop-color="#C62AEB" />
|
<stop offset="0.884464" stop-color="#C62AEB" />
|
||||||
<stop offset="0.957056" stop-color="white" />
|
<stop offset="0.957056" stop-color="white" />
|
||||||
<stop offset="0.997383" />
|
<stop offset="0.997383" />
|
||||||
</linearGradient>
|
</linearGradient>
|
||||||
<linearGradient
|
<linearGradient
|
||||||
id="paint1_linear_1_30"
|
id="paint1_linear_1_30"
|
||||||
x1="132.469"
|
x1="132.469"
|
||||||
y1="37.0914"
|
y1="37.0914"
|
||||||
x2="132.469"
|
x2="132.469"
|
||||||
y2="227.847"
|
y2="227.847"
|
||||||
gradientUnits="userSpaceOnUse"
|
gradientUnits="userSpaceOnUse"
|
||||||
>
|
>
|
||||||
<stop stop-color="#EFEC32" />
|
<stop stop-color="#EFEC32" />
|
||||||
<stop offset="1" stop-color="#98FF60" />
|
<stop offset="1" stop-color="#98FF60" />
|
||||||
</linearGradient>
|
</linearGradient>
|
||||||
</defs>
|
</defs>
|
||||||
</svg>
|
</svg>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -187,120 +187,136 @@ export function BrandingPrideIcon(props: SVGProps<SVGSVGElement>) {
|
|||||||
* @returns A JSX element representing the branding icon.
|
* @returns A JSX element representing the branding icon.
|
||||||
*/
|
*/
|
||||||
export function BrandingGenericIcon(props: SVGProps<SVGSVGElement>) {
|
export function BrandingGenericIcon(props: SVGProps<SVGSVGElement>) {
|
||||||
const { resolvedTheme } = useTheme();
|
const { resolvedTheme } = useTheme();
|
||||||
|
|
||||||
if (resolvedTheme == "dark") {
|
if (resolvedTheme == "dark") {
|
||||||
return (
|
return (
|
||||||
<svg
|
<svg
|
||||||
width="265"
|
width="265"
|
||||||
height="266"
|
height="266"
|
||||||
viewBox="0 0 265 266"
|
viewBox="0 0 265 266"
|
||||||
fill="none"
|
fill="none"
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
<rect
|
<rect
|
||||||
x="0.0612793"
|
x="0.0612793"
|
||||||
y="0.86145"
|
y="0.86145"
|
||||||
width="264.939"
|
width="264.939"
|
||||||
height="264.939"
|
height="264.939"
|
||||||
rx="66"
|
rx="66"
|
||||||
fill="url(#paint0_linear_1_20)"
|
fill="url(#paint0_linear_1_20)"
|
||||||
/>
|
/>
|
||||||
<path
|
<path
|
||||||
d="M104.05 124.132H94.4089C91.852 124.132 89.3998 123.116 87.5918 121.308C85.7838 119.5 84.7681 117.048 84.7681 114.491V95.2091C84.7681 92.6522 85.7838 90.2 87.5918 88.392C89.3998 86.584 91.852 85.5683 94.4089 85.5683H171.536C174.092 85.5683 176.545 86.584 178.353 88.392C180.161 90.2 181.176 92.6522 181.176 95.2091V114.491C181.176 117.048 180.161 119.5 178.353 121.308C176.545 123.116 174.092 124.132 171.536 124.132H161.895M104.05 143.413H94.4089C91.852 143.413 89.3998 144.429 87.5918 146.237C85.7838 148.045 84.7681 150.497 84.7681 153.054V172.336C84.7681 174.893 85.7838 177.345 87.5918 179.153C89.3998 180.961 91.852 181.977 94.4089 181.977H171.536C174.092 181.977 176.545 180.961 178.353 179.153C180.161 177.345 181.176 174.893 181.176 172.336V153.054C181.176 150.497 180.161 148.045 178.353 146.237C176.545 144.429 174.092 143.413 171.536 143.413H161.895M104.05 104.85H104.098M104.05 162.695H104.098M137.793 104.85L118.511 133.772H147.433L128.152 162.695"
|
d="M104.05 124.132H94.4089C91.852 124.132 89.3998 123.116 87.5918 121.308C85.7838 119.5 84.7681 117.048 84.7681 114.491V95.2091C84.7681 92.6522 85.7838 90.2 87.5918 88.392C89.3998 86.584 91.852 85.5683 94.4089 85.5683H171.536C174.092 85.5683 176.545 86.584 178.353 88.392C180.161 90.2 181.176 92.6522 181.176 95.2091V114.491C181.176 117.048 180.161 119.5 178.353 121.308C176.545 123.116 174.092 124.132 171.536 124.132H161.895M104.05 143.413H94.4089C91.852 143.413 89.3998 144.429 87.5918 146.237C85.7838 148.045 84.7681 150.497 84.7681 153.054V172.336C84.7681 174.893 85.7838 177.345 87.5918 179.153C89.3998 180.961 91.852 181.977 94.4089 181.977H171.536C174.092 181.977 176.545 180.961 178.353 179.153C180.161 177.345 181.176 174.893 181.176 172.336V153.054C181.176 150.497 180.161 148.045 178.353 146.237C176.545 144.429 174.092 143.413 171.536 143.413H161.895M104.05 104.85H104.098M104.05 162.695H104.098M137.793 104.85L118.511 133.772H147.433L128.152 162.695"
|
||||||
stroke="white"
|
stroke="white"
|
||||||
stroke-width="10"
|
stroke-width="10"
|
||||||
stroke-linecap="round"
|
stroke-linecap="round"
|
||||||
stroke-linejoin="round"
|
stroke-linejoin="round"
|
||||||
/>
|
/>
|
||||||
<circle
|
<circle
|
||||||
cx="132.531"
|
cx="132.531"
|
||||||
cy="133.331"
|
cy="133.331"
|
||||||
r="91.3779"
|
r="91.3779"
|
||||||
stroke="url(#paint1_linear_1_20)"
|
stroke="url(#paint1_linear_1_20)"
|
||||||
stroke-width="8"
|
stroke-width="8"
|
||||||
/>
|
/>
|
||||||
<defs>
|
<defs>
|
||||||
<linearGradient
|
<linearGradient
|
||||||
id="paint0_linear_1_20"
|
id="paint0_linear_1_20"
|
||||||
x1="107.361"
|
x1="107.361"
|
||||||
y1="55.6155"
|
y1="55.6155"
|
||||||
x2="230.116"
|
x2="230.116"
|
||||||
y2="226.059"
|
y2="226.059"
|
||||||
gradientUnits="userSpaceOnUse"
|
gradientUnits="userSpaceOnUse"
|
||||||
>
|
>
|
||||||
<stop />
|
<stop />
|
||||||
</linearGradient>
|
</linearGradient>
|
||||||
<linearGradient
|
<linearGradient
|
||||||
id="paint1_linear_1_20"
|
id="paint1_linear_1_20"
|
||||||
x1="132.531"
|
x1="132.531"
|
||||||
y1="37.9529"
|
y1="37.9529"
|
||||||
x2="132.531"
|
x2="132.531"
|
||||||
y2="228.709"
|
y2="228.709"
|
||||||
gradientUnits="userSpaceOnUse"
|
gradientUnits="userSpaceOnUse"
|
||||||
>
|
>
|
||||||
<stop stop-color="#EFEC32" />
|
<stop stop-color="#EFEC32" />
|
||||||
<stop offset="1" stop-color="#98FF60" />
|
<stop offset="1" stop-color="#98FF60" />
|
||||||
</linearGradient>
|
</linearGradient>
|
||||||
</defs>
|
</defs>
|
||||||
</svg>
|
</svg>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
<svg
|
<svg
|
||||||
width="265"
|
width="265"
|
||||||
height="265"
|
height="265"
|
||||||
viewBox="0 0 265 265"
|
viewBox="0 0 265 265"
|
||||||
fill="none"
|
fill="none"
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
<rect
|
<rect
|
||||||
x="0.0612793"
|
x="0.0612793"
|
||||||
width="264.939"
|
width="264.939"
|
||||||
height="264.939"
|
height="264.939"
|
||||||
rx="66"
|
rx="66"
|
||||||
fill="url(#paint0_linear_1_25)"
|
fill="url(#paint0_linear_1_25)"
|
||||||
/>
|
/>
|
||||||
<path
|
<path
|
||||||
d="M104.05 123.27H94.4089C91.852 123.27 89.3998 122.254 87.5918 120.446C85.7838 118.638 84.7681 116.186 84.7681 113.629V94.3476C84.7681 91.7907 85.7838 89.3385 87.5918 87.5305C89.3998 85.7225 91.852 84.7068 94.4089 84.7068H171.536C174.092 84.7068 176.545 85.7225 178.353 87.5305C180.161 89.3385 181.176 91.7907 181.176 94.3476V113.629C181.176 116.186 180.161 118.638 178.353 120.446C176.545 122.254 174.092 123.27 171.536 123.27H161.895M104.05 142.552H94.4089C91.852 142.552 89.3998 143.567 87.5918 145.376C85.7838 147.184 84.7681 149.636 84.7681 152.193V171.474C84.7681 174.031 85.7838 176.483 87.5918 178.291C89.3998 180.099 91.852 181.115 94.4089 181.115H171.536C174.092 181.115 176.545 180.099 178.353 178.291C180.161 176.483 181.176 174.031 181.176 171.474V152.193C181.176 149.636 180.161 147.184 178.353 145.376C176.545 143.567 174.092 142.552 171.536 142.552H161.895M104.05 103.988H104.098M104.05 161.833H104.098M137.793 103.988L118.511 132.911H147.433L128.152 161.833"
|
d="M104.05 123.27H94.4089C91.852 123.27 89.3998 122.254 87.5918 120.446C85.7838 118.638 84.7681 116.186 84.7681 113.629V94.3476C84.7681 91.7907 85.7838 89.3385 87.5918 87.5305C89.3998 85.7225 91.852 84.7068 94.4089 84.7068H171.536C174.092 84.7068 176.545 85.7225 178.353 87.5305C180.161 89.3385 181.176 91.7907 181.176 94.3476V113.629C181.176 116.186 180.161 118.638 178.353 120.446C176.545 122.254 174.092 123.27 171.536 123.27H161.895M104.05 142.552H94.4089C91.852 142.552 89.3998 143.567 87.5918 145.376C85.7838 147.184 84.7681 149.636 84.7681 152.193V171.474C84.7681 174.031 85.7838 176.483 87.5918 178.291C89.3998 180.099 91.852 181.115 94.4089 181.115H171.536C174.092 181.115 176.545 180.099 178.353 178.291C180.161 176.483 181.176 174.031 181.176 171.474V152.193C181.176 149.636 180.161 147.184 178.353 145.376C176.545 143.567 174.092 142.552 171.536 142.552H161.895M104.05 103.988H104.098M104.05 161.833H104.098M137.793 103.988L118.511 132.911H147.433L128.152 161.833"
|
||||||
stroke="black"
|
stroke="black"
|
||||||
stroke-width="10"
|
stroke-width="10"
|
||||||
stroke-linecap="round"
|
stroke-linecap="round"
|
||||||
stroke-linejoin="round"
|
stroke-linejoin="round"
|
||||||
/>
|
/>
|
||||||
<circle
|
<circle
|
||||||
cx="132.531"
|
cx="132.531"
|
||||||
cy="132.469"
|
cy="132.469"
|
||||||
r="91.3779"
|
r="91.3779"
|
||||||
stroke="url(#paint1_linear_1_25)"
|
stroke="url(#paint1_linear_1_25)"
|
||||||
stroke-width="8"
|
stroke-width="8"
|
||||||
/>
|
/>
|
||||||
<defs>
|
<defs>
|
||||||
<linearGradient
|
<linearGradient
|
||||||
id="paint0_linear_1_25"
|
id="paint0_linear_1_25"
|
||||||
x1="107.361"
|
x1="107.361"
|
||||||
y1="54.754"
|
y1="54.754"
|
||||||
x2="230.116"
|
x2="230.116"
|
||||||
y2="225.198"
|
y2="225.198"
|
||||||
gradientUnits="userSpaceOnUse"
|
gradientUnits="userSpaceOnUse"
|
||||||
>
|
>
|
||||||
<stop stop-color="white" />
|
<stop stop-color="white" />
|
||||||
</linearGradient>
|
</linearGradient>
|
||||||
<linearGradient
|
<linearGradient
|
||||||
id="paint1_linear_1_25"
|
id="paint1_linear_1_25"
|
||||||
x1="132.531"
|
x1="132.531"
|
||||||
y1="37.0914"
|
y1="37.0914"
|
||||||
x2="132.531"
|
x2="132.531"
|
||||||
y2="227.847"
|
y2="227.847"
|
||||||
gradientUnits="userSpaceOnUse"
|
gradientUnits="userSpaceOnUse"
|
||||||
>
|
>
|
||||||
<stop stop-color="#EFEC32" />
|
<stop stop-color="#EFEC32" />
|
||||||
<stop offset="1" stop-color="#98FF60" />
|
<stop offset="1" stop-color="#98FF60" />
|
||||||
</linearGradient>
|
</linearGradient>
|
||||||
</defs>
|
</defs>
|
||||||
</svg>
|
</svg>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export 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>
|
||||||
|
);
|
||||||
|
|||||||
@ -45,7 +45,7 @@ import { Checkbox } from "@/components/ui/checkbox";
|
|||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { Switch } from "./ui/switch";
|
import { Switch } from "./ui/switch";
|
||||||
import { setAccountSL } from "@/lib/api";
|
import { setAccountSL } from "@/lib/api";
|
||||||
import toast from "react-hot-toast";
|
import { toast } from "sonner";
|
||||||
import { useUser } from "@clerk/nextjs";
|
import { useUser } from "@clerk/nextjs";
|
||||||
|
|
||||||
export function SLCustomize() {
|
export function SLCustomize() {
|
||||||
|
|||||||
@ -1,54 +1,23 @@
|
|||||||
/*
|
|
||||||
* MHSF, Minehut Server List
|
|
||||||
* All external content is rather licensed under the ECA Agreement
|
|
||||||
* located here: https://list.mlnehut.com/docs/legal/external-content-agreement
|
|
||||||
*
|
|
||||||
* All code under MHSF is licensed under the MIT License
|
|
||||||
* by open source contributors
|
|
||||||
*
|
|
||||||
* Copyright (c) 2024 dvelo
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
* of this software and associated documentation files (the "Software"), to
|
|
||||||
* deal in the Software without restriction, including without limitation the
|
|
||||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
|
||||||
* sell copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in all
|
|
||||||
* copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
||||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|
||||||
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
||||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
||||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
||||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
||||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
||||||
* OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { NewChart } from "@/components/NewChart";
|
|
||||||
import { MiniJoinsChart } from "@/components/misc/MiniJoinsChart";
|
import { MiniJoinsChart } from "@/components/misc/MiniJoinsChart";
|
||||||
import {
|
import {
|
||||||
ContextMenu,
|
ContextMenu,
|
||||||
ContextMenuContent,
|
ContextMenuContent,
|
||||||
ContextMenuItem,
|
ContextMenuItem,
|
||||||
ContextMenuSeparator,
|
ContextMenuSeparator,
|
||||||
ContextMenuTrigger,
|
ContextMenuTrigger,
|
||||||
} from "@/components/ui/context-menu";
|
} from "@/components/ui/context-menu";
|
||||||
import {
|
import {
|
||||||
Drawer,
|
Drawer,
|
||||||
DrawerContent,
|
DrawerContent,
|
||||||
DrawerFooter,
|
DrawerFooter,
|
||||||
DrawerHeader,
|
DrawerHeader,
|
||||||
DrawerTitle,
|
DrawerTitle,
|
||||||
DrawerTrigger,
|
DrawerTrigger,
|
||||||
} from "@/components/ui/drawer";
|
} from "@/components/ui/drawer";
|
||||||
import {
|
import {
|
||||||
HoverCard,
|
HoverCard,
|
||||||
HoverCardContent,
|
HoverCardContent,
|
||||||
HoverCardTrigger,
|
HoverCardTrigger,
|
||||||
} from "@/components/ui/hover-card";
|
} from "@/components/ui/hover-card";
|
||||||
import { favoriteServer, isFavorited } from "@/lib/api";
|
import { favoriteServer, isFavorited } from "@/lib/api";
|
||||||
import useClipboard from "@/lib/useClipboard";
|
import useClipboard from "@/lib/useClipboard";
|
||||||
@ -56,300 +25,301 @@ import { useRouter } from "@/lib/useRouter";
|
|||||||
import { useUser } from "@clerk/nextjs";
|
import { useUser } from "@clerk/nextjs";
|
||||||
import { Tooltip } from "@radix-ui/react-tooltip";
|
import { Tooltip } from "@radix-ui/react-tooltip";
|
||||||
import {
|
import {
|
||||||
ArrowRight,
|
ArrowRight,
|
||||||
ChartArea,
|
ChartArea,
|
||||||
Copy,
|
Copy,
|
||||||
EllipsisVertical,
|
EllipsisVertical,
|
||||||
Layers,
|
Layers,
|
||||||
Star,
|
Star,
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
import { useTheme } from "next-themes";
|
import { useTheme } from "next-themes";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import toast, { LoaderIcon } from "react-hot-toast";
|
import { LoaderIcon } from "react-hot-toast";
|
||||||
|
import { toast } from "sonner";
|
||||||
import IconDisplay from "./IconDisplay";
|
import IconDisplay from "./IconDisplay";
|
||||||
import { TagShower } from "./ServerList";
|
import { TagShower } from "./ServerList";
|
||||||
import { Button } from "./ui/button";
|
import { Button } from "./ui/button";
|
||||||
import {
|
import {
|
||||||
Card,
|
Card,
|
||||||
CardContent,
|
CardContent,
|
||||||
CardDescription,
|
CardDescription,
|
||||||
CardHeader,
|
CardHeader,
|
||||||
CardTitle,
|
CardTitle,
|
||||||
} from "./ui/card";
|
} from "./ui/card";
|
||||||
import { TooltipContent, TooltipTrigger } from "./ui/tooltip";
|
import { TooltipContent, TooltipTrigger } from "./ui/tooltip";
|
||||||
|
|
||||||
export default function ServerCard({ b, motd, mini, favs }: any) {
|
export default function ServerCard({ b, motd, mini, favs }: any) {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const clipboard = useClipboard();
|
const clipboard = useClipboard();
|
||||||
const [favoriteStar, setFavoriteStar] = useState(false);
|
const [favoriteStar, setFavoriteStar] = useState(false);
|
||||||
const [favoriteLoading, setFavoriteLoading] = useState(true);
|
const [favoriteLoading, setFavoriteLoading] = useState(true);
|
||||||
const { isSignedIn } = useUser();
|
const { isSignedIn } = useUser();
|
||||||
const { resolvedTheme } = useTheme();
|
const { resolvedTheme } = useTheme();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ContextMenu
|
<ContextMenu
|
||||||
onOpenChange={(open) => {
|
onOpenChange={(open) => {
|
||||||
if (open && isSignedIn)
|
if (open && isSignedIn)
|
||||||
isFavorited(b.name).then((c) => {
|
isFavorited(b.name).then((c) => {
|
||||||
setFavoriteStar(c);
|
setFavoriteStar(c);
|
||||||
setFavoriteLoading(false);
|
setFavoriteLoading(false);
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<ContextMenuTrigger>
|
<ContextMenuTrigger>
|
||||||
<Card
|
<Card
|
||||||
key={b.name}
|
key={b.name}
|
||||||
className={
|
className={
|
||||||
(!mini ? "min-h-[450px] max-h-[450px]" : "") +
|
(!mini ? "min-h-[450px] max-h-[450px]" : "") +
|
||||||
" mb-4 flex items-start shadow-md"
|
" mb-4 flex items-start shadow-md"
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
<CardTitle className="m-0">
|
<CardTitle className="m-0">
|
||||||
<span>
|
<span>
|
||||||
<IconDisplay server={b} />
|
<IconDisplay server={b} />
|
||||||
<HoverCard>
|
<HoverCard>
|
||||||
<HoverCardTrigger asChild>
|
<HoverCardTrigger asChild>
|
||||||
<Link href={"/server/" + b.name}>
|
<Link href={"/server/" + b.name}>
|
||||||
<Button
|
<Button
|
||||||
variant={"link"}
|
variant={"link"}
|
||||||
className="text-2xl px-0 pl-1 font-semibold"
|
className="text-2xl px-0 pl-1 font-semibold"
|
||||||
>
|
>
|
||||||
{b.name}
|
{b.name}
|
||||||
</Button>
|
</Button>
|
||||||
</Link>
|
</Link>
|
||||||
</HoverCardTrigger>
|
</HoverCardTrigger>
|
||||||
<HoverCardContent className="w-80 font-normal tracking-normal">
|
<HoverCardContent className="w-80 font-normal tracking-normal">
|
||||||
<div className="flex justify-between space-x-4">
|
<div className="flex justify-between space-x-4">
|
||||||
<div className="space-y-1">
|
<div className="space-y-1">
|
||||||
<h4 className="text-sm font-semibold">{b.name}</h4>
|
<h4 className="text-sm font-semibold">{b.name}</h4>
|
||||||
<p className="text-sm">
|
<p className="text-sm">
|
||||||
{motd && (
|
{motd && (
|
||||||
<span
|
<span
|
||||||
dangerouslySetInnerHTML={{ __html: motd }}
|
dangerouslySetInnerHTML={{ __html: motd }}
|
||||||
className="w-[30px] text-center break-all overflow-hidden"
|
className="w-[30px] text-center break-all overflow-hidden"
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</p>
|
</p>
|
||||||
<br />
|
<br />
|
||||||
<br />
|
<br />
|
||||||
<strong className="text-sm font-semibold text-center">
|
<strong className="text-sm font-semibold text-center">
|
||||||
Joins Chart
|
Joins Chart
|
||||||
</strong>
|
</strong>
|
||||||
<MiniJoinsChart server={b.name} />
|
<MiniJoinsChart server={b.name} />
|
||||||
|
|
||||||
<div className="flex items-center pt-2">
|
<div className="flex items-center pt-2">
|
||||||
<span className="text-xs text-muted-foreground flex items-center">
|
<span className="text-xs text-muted-foreground flex items-center">
|
||||||
<ArrowRight size={16} className="mr-2" />
|
<ArrowRight size={16} className="mr-2" />
|
||||||
Open Server Page
|
Open Server Page
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center pt-2">
|
<div className="flex items-center pt-2">
|
||||||
<span className="text-xs text-muted-foreground flex items-center">
|
<span className="text-xs text-muted-foreground flex items-center">
|
||||||
<ChartArea size={16} className="mr-2" />
|
<ChartArea size={16} className="mr-2" />
|
||||||
Running on{" "}
|
Running on{" "}
|
||||||
{b.staticInfo.serverPlan == undefined
|
{b.staticInfo.serverPlan == undefined
|
||||||
? "Free Plan"
|
? "Free Plan"
|
||||||
: b.staticInfo.serverPlan}
|
: b.staticInfo.serverPlan}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</HoverCardContent>
|
</HoverCardContent>
|
||||||
</HoverCard>
|
</HoverCard>
|
||||||
</span>
|
</span>
|
||||||
<Drawer>
|
<Drawer>
|
||||||
<DrawerTrigger>
|
<DrawerTrigger>
|
||||||
<Button
|
<Button
|
||||||
size="icon"
|
size="icon"
|
||||||
className="w-[24px] h-[24px] ml-2 md:hidden"
|
className="w-[24px] h-[24px] ml-2 md:hidden"
|
||||||
variant="secondary"
|
variant="secondary"
|
||||||
>
|
>
|
||||||
<EllipsisVertical size={16} />
|
<EllipsisVertical size={16} />
|
||||||
</Button>
|
</Button>
|
||||||
</DrawerTrigger>
|
</DrawerTrigger>
|
||||||
<DrawerContent>
|
<DrawerContent>
|
||||||
<DrawerHeader>
|
<DrawerHeader>
|
||||||
<DrawerTitle>Actions</DrawerTitle>
|
<DrawerTitle>Actions</DrawerTitle>
|
||||||
</DrawerHeader>
|
</DrawerHeader>
|
||||||
<DrawerFooter>
|
<DrawerFooter>
|
||||||
<Button
|
<Button
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
clipboard.writeText(b.name + ".mshf.minehut.gg");
|
clipboard.writeText(b.name + ".mshf.minehut.gg");
|
||||||
toast.success("Copied IP to clipboard");
|
toast.success("Copied IP to clipboard");
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Copy server IP
|
Copy server IP
|
||||||
<Copy size={18} className="ml-4" />
|
<Copy size={18} className="ml-4" />
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
router.push("/server/" + b.name);
|
router.push("/server/" + b.name);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Open server page
|
Open server page
|
||||||
</Button>
|
</Button>
|
||||||
</DrawerFooter>
|
</DrawerFooter>
|
||||||
</DrawerContent>
|
</DrawerContent>
|
||||||
</Drawer>
|
</Drawer>
|
||||||
{b.author != undefined ? (
|
{b.author != undefined ? (
|
||||||
<div className="text-sm text-muted-foreground font-normal tracking-normal">
|
<div className="text-sm text-muted-foreground font-normal tracking-normal">
|
||||||
by {b.author}
|
by {b.author}
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<br />
|
<br />
|
||||||
)}
|
)}
|
||||||
<TagShower server={b} />
|
<TagShower server={b} />
|
||||||
</CardTitle>
|
</CardTitle>
|
||||||
<CardDescription className="float-left inline ">
|
<CardDescription className="float-left inline ">
|
||||||
<span className="flex items-center">
|
<span className="flex items-center">
|
||||||
{b.playerData.playerCount == 0 ? (
|
{b.playerData.playerCount == 0 ? (
|
||||||
<div
|
<div
|
||||||
className="items-center border"
|
className="items-center border"
|
||||||
style={{
|
style={{
|
||||||
width: ".5rem",
|
width: ".5rem",
|
||||||
height: ".5rem",
|
height: ".5rem",
|
||||||
borderRadius: "9999px",
|
borderRadius: "9999px",
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<div
|
<div
|
||||||
className="items-center"
|
className="items-center"
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: "#0cce6b",
|
backgroundColor: "#0cce6b",
|
||||||
width: ".5rem",
|
width: ".5rem",
|
||||||
height: ".5rem",
|
height: ".5rem",
|
||||||
borderRadius: "9999px",
|
borderRadius: "9999px",
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<span className="pl-1">
|
<span className="pl-1">
|
||||||
{b.playerData.playerCount}{" "}
|
{b.playerData.playerCount}{" "}
|
||||||
{b.playerData.playerCount == 1 ? "player" : "players"}{" "}
|
{b.playerData.playerCount == 1 ? "player" : "players"}{" "}
|
||||||
currently online {favs && <>• {favs} favorited</>}
|
currently online {favs && <>• {favs} favorited</>}
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<ContextMenu>
|
<ContextMenu>
|
||||||
<ContextMenuTrigger>
|
<ContextMenuTrigger>
|
||||||
<>
|
<>
|
||||||
<Button
|
<Button
|
||||||
size="icon"
|
size="icon"
|
||||||
variant="secondary"
|
variant="secondary"
|
||||||
className="min-w-[128px] max-w-[328px] h-[32px] mt-2 ml-2 max-md:hidden"
|
className="min-w-[128px] max-w-[328px] h-[32px] mt-2 ml-2 max-md:hidden"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
clipboard.writeText(b.name + ".mshf.minehut.gg");
|
clipboard.writeText(b.name + ".mshf.minehut.gg");
|
||||||
toast.success("Copied IP to clipboard");
|
toast.success("Copied IP to clipboard");
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Copy size={18} />
|
<Copy size={18} />
|
||||||
<code className="ml-2">{b.name}</code>
|
<code className="ml-2">{b.name}</code>
|
||||||
</Button>
|
</Button>
|
||||||
<Tooltip>
|
<Tooltip>
|
||||||
<TooltipTrigger>
|
<TooltipTrigger>
|
||||||
<Link href={"/server/" + b.name}>
|
<Link href={"/server/" + b.name}>
|
||||||
<Button
|
<Button
|
||||||
size="icon"
|
size="icon"
|
||||||
variant="secondary"
|
variant="secondary"
|
||||||
className="w-[32px] h-[32px] mt-2 ml-2 max-md:hidden"
|
className="w-[32px] h-[32px] mt-2 ml-2 max-md:hidden"
|
||||||
>
|
>
|
||||||
<Layers size={18} />
|
<Layers size={18} />
|
||||||
</Button>
|
</Button>
|
||||||
</Link>
|
</Link>
|
||||||
</TooltipTrigger>
|
</TooltipTrigger>
|
||||||
<TooltipContent>
|
<TooltipContent>
|
||||||
Open up the server page to see more information about
|
Open up the server page to see more information about
|
||||||
the server
|
the server
|
||||||
</TooltipContent>
|
</TooltipContent>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</>
|
</>
|
||||||
</ContextMenuTrigger>
|
</ContextMenuTrigger>
|
||||||
<ContextMenuContent>
|
<ContextMenuContent>
|
||||||
<ContextMenuItem
|
<ContextMenuItem
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
clipboard.writeText(b.name + ".mshf.minehut.gg");
|
clipboard.writeText(b.name + ".mshf.minehut.gg");
|
||||||
toast.success("Copied IP to clipboard");
|
toast.success("Copied IP to clipboard");
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Copy server IP
|
Copy server IP
|
||||||
<div className="RightSlot">
|
<div className="RightSlot">
|
||||||
<Copy size={18} />
|
<Copy size={18} />
|
||||||
</div>
|
</div>
|
||||||
</ContextMenuItem>
|
</ContextMenuItem>
|
||||||
<ContextMenuSeparator />
|
<ContextMenuSeparator />
|
||||||
<Link href={"/src/app/(main)/server/" + b.name}>
|
<Link href={"/src/app/(main)/server/" + b.name}>
|
||||||
<ContextMenuItem>Open server page</ContextMenuItem>
|
<ContextMenuItem>Open server page</ContextMenuItem>
|
||||||
</Link>
|
</Link>
|
||||||
</ContextMenuContent>
|
</ContextMenuContent>
|
||||||
</ContextMenu>
|
</ContextMenu>
|
||||||
</CardDescription>
|
</CardDescription>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
{motd && (
|
{motd && (
|
||||||
<span
|
<span
|
||||||
dangerouslySetInnerHTML={{ __html: motd }}
|
dangerouslySetInnerHTML={{ __html: motd }}
|
||||||
className="w-[30px] text-center break-all overflow-hidden"
|
className="w-[30px] text-center break-all overflow-hidden"
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
</Card>
|
</Card>
|
||||||
</ContextMenuTrigger>
|
</ContextMenuTrigger>
|
||||||
<ContextMenuContent>
|
<ContextMenuContent>
|
||||||
<ContextMenuItem
|
<ContextMenuItem
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
clipboard.writeText(b.name + ".mshf.minehut.gg");
|
clipboard.writeText(b.name + ".mshf.minehut.gg");
|
||||||
toast.success("Copied IP to clipboard");
|
toast.success("Copied IP to clipboard");
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Copy server IP
|
Copy server IP
|
||||||
</ContextMenuItem>
|
</ContextMenuItem>
|
||||||
<ContextMenuSeparator />
|
<ContextMenuSeparator />
|
||||||
<ContextMenuItem
|
<ContextMenuItem
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
router.push("/server/" + b.name);
|
router.push("/server/" + b.name);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Open server page
|
Open server page
|
||||||
</ContextMenuItem>
|
</ContextMenuItem>
|
||||||
<ContextMenuItem
|
<ContextMenuItem
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
router.push("/server/" + b.name + "/statistics");
|
router.push("/server/" + b.name + "/statistics");
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Open statistics page
|
Open statistics page
|
||||||
</ContextMenuItem>
|
</ContextMenuItem>
|
||||||
<ContextMenuSeparator />
|
<ContextMenuSeparator />
|
||||||
<ContextMenuItem
|
<ContextMenuItem
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setFavoriteLoading(true);
|
setFavoriteLoading(true);
|
||||||
favoriteServer(b.name).then(() => {
|
favoriteServer(b.name).then(() => {
|
||||||
setFavoriteLoading(false);
|
setFavoriteLoading(false);
|
||||||
setFavoriteStar(!favoriteStar);
|
setFavoriteStar(!favoriteStar);
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
disabled={!isSignedIn || favoriteLoading}
|
disabled={!isSignedIn || favoriteLoading}
|
||||||
>
|
>
|
||||||
{!favoriteLoading && (
|
{!favoriteLoading && (
|
||||||
<Star
|
<Star
|
||||||
size={16}
|
size={16}
|
||||||
className="mr-2 text-white"
|
className="mr-2 text-white"
|
||||||
fill={
|
fill={
|
||||||
favoriteStar
|
favoriteStar
|
||||||
? resolvedTheme == "dark"
|
? resolvedTheme == "dark"
|
||||||
? "white"
|
? "white"
|
||||||
: "black"
|
: "black"
|
||||||
: "transparent"
|
: "transparent"
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
)}{" "}
|
)}{" "}
|
||||||
{favoriteLoading && <LoaderIcon className="mr-2" />}
|
{favoriteLoading && <LoaderIcon className="mr-2" />}
|
||||||
{favoriteStar && isSignedIn ? "Unf" : "F"}avorite Server
|
{favoriteStar && isSignedIn ? "Unf" : "F"}avorite Server
|
||||||
</ContextMenuItem>
|
</ContextMenuItem>
|
||||||
</ContextMenuContent>
|
</ContextMenuContent>
|
||||||
</ContextMenu>
|
</ContextMenu>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -30,13 +30,13 @@
|
|||||||
|
|
||||||
"use client";
|
"use client";
|
||||||
import {
|
import {
|
||||||
getCustomization,
|
getCustomization,
|
||||||
ownServer,
|
ownServer,
|
||||||
reportServer,
|
reportServer,
|
||||||
serverOwned as sOFunc,
|
serverOwned as sOFunc,
|
||||||
setCustomization,
|
setCustomization,
|
||||||
unownServer,
|
unownServer,
|
||||||
userOwnedServer,
|
userOwnedServer,
|
||||||
} from "@/lib/api";
|
} from "@/lib/api";
|
||||||
import { OnlineServer } from "@/lib/types/mh-server";
|
import { OnlineServer } from "@/lib/types/mh-server";
|
||||||
import { SignedIn, SignedOut, useUser } from "@clerk/nextjs";
|
import { SignedIn, SignedOut, useUser } from "@clerk/nextjs";
|
||||||
@ -45,17 +45,17 @@ import { CheckIcon, X } from "lucide-react";
|
|||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { Dispatch, SetStateAction, useEffect, useState } from "react";
|
import { Dispatch, SetStateAction, useEffect, useState } from "react";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import toast from "react-hot-toast";
|
import { toast } from "sonner";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { Button } from "./ui/button";
|
import { Button } from "./ui/button";
|
||||||
import {
|
import {
|
||||||
Form,
|
Form,
|
||||||
FormControl,
|
FormControl,
|
||||||
FormDescription,
|
FormDescription,
|
||||||
FormField,
|
FormField,
|
||||||
FormItem,
|
FormItem,
|
||||||
FormLabel,
|
FormLabel,
|
||||||
FormMessage,
|
FormMessage,
|
||||||
} from "./ui/form";
|
} from "./ui/form";
|
||||||
import Setting from "./ui/setting";
|
import Setting from "./ui/setting";
|
||||||
import { Textarea } from "./ui/textarea";
|
import { Textarea } from "./ui/textarea";
|
||||||
@ -66,456 +66,456 @@ import { useTheme } from "next-themes";
|
|||||||
import { BannerPopover } from "./misc/BannerPopover";
|
import { BannerPopover } from "./misc/BannerPopover";
|
||||||
import { DiscordPopover } from "./misc/DiscordPopover";
|
import { DiscordPopover } from "./misc/DiscordPopover";
|
||||||
import {
|
import {
|
||||||
Card,
|
Card,
|
||||||
CardContent,
|
CardContent,
|
||||||
CardDescription,
|
CardDescription,
|
||||||
CardFooter,
|
CardFooter,
|
||||||
CardHeader,
|
CardHeader,
|
||||||
CardTitle,
|
CardTitle,
|
||||||
} from "./ui/card";
|
} from "./ui/card";
|
||||||
import {
|
import {
|
||||||
Dialog,
|
Dialog,
|
||||||
DialogContent,
|
DialogContent,
|
||||||
DialogDescription,
|
DialogDescription,
|
||||||
DialogHeader,
|
DialogHeader,
|
||||||
DialogTitle,
|
DialogTitle,
|
||||||
DialogTrigger,
|
DialogTrigger,
|
||||||
} from "./ui/dialog";
|
} from "./ui/dialog";
|
||||||
import { Popover, PopoverContent, PopoverTrigger } from "./ui/popover";
|
import { Popover, PopoverContent, PopoverTrigger } from "./ui/popover";
|
||||||
import { Spinner } from "./ui/spinner";
|
import { LoadingSpinner } from "./ui/loading-spinner";
|
||||||
|
|
||||||
const formSchema = z.object({
|
const formSchema = z.object({
|
||||||
description: z
|
description: z
|
||||||
.string()
|
.string()
|
||||||
.min(2, {
|
.min(2, {
|
||||||
message: "Description must be at least 2 characters.",
|
message: "Description must be at least 2 characters.",
|
||||||
})
|
})
|
||||||
.max(1250, {
|
.max(1250, {
|
||||||
message: "Description cannot be longer than 1250 characters.",
|
message: "Description cannot be longer than 1250 characters.",
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default function ServerCustomize({
|
export default function ServerCustomize({
|
||||||
server,
|
server,
|
||||||
cs,
|
cs,
|
||||||
setCS,
|
setCS,
|
||||||
}: {
|
}: {
|
||||||
server: string;
|
server: string;
|
||||||
cs: string;
|
cs: string;
|
||||||
setCS: Dispatch<SetStateAction<string>>;
|
setCS: Dispatch<SetStateAction<string>>;
|
||||||
}) {
|
}) {
|
||||||
const [serverOwned, setServerOwned] = useState(false);
|
const [serverOwned, setServerOwned] = useState(false);
|
||||||
const [userOwned, setUserOwned] = useState(false);
|
const [userOwned, setUserOwned] = useState(false);
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
const [reason, setReason] = useState("");
|
const [reason, setReason] = useState("");
|
||||||
const [description, setDescription] = useState("");
|
const [description, setDescription] = useState("");
|
||||||
const [get, setGet] = useState<any>({});
|
const [get, setGet] = useState<any>({});
|
||||||
const [author, setAuthor] = useState<string | undefined>("");
|
const [author, setAuthor] = useState<string | undefined>("");
|
||||||
const [minehutOwned, setMinehutOwned] = useState(false);
|
const [minehutOwned, setMinehutOwned] = useState(false);
|
||||||
const { resolvedTheme: mode } = useTheme();
|
const { resolvedTheme: mode } = useTheme();
|
||||||
const { user, isSignedIn } = useUser();
|
const { user, isSignedIn } = useUser();
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
sOFunc(server).then((c) => {
|
sOFunc(server).then((c) => {
|
||||||
setServerOwned(c);
|
setServerOwned(c);
|
||||||
getCustomization(server).then((b) => {
|
getCustomization(server).then((b) => {
|
||||||
setGet(b);
|
setGet(b);
|
||||||
setDescription(b != null ? b.description : "");
|
setDescription(b != null ? b.description : "");
|
||||||
form.reset({ description: b != null ? b.description : "" });
|
form.reset({ description: b != null ? b.description : "" });
|
||||||
setCS(b != null ? b.colorScheme : "zinc");
|
setCS(b != null ? b.colorScheme : "zinc");
|
||||||
userOwnedServer(server).then((c) => {
|
userOwnedServer(server).then((c) => {
|
||||||
setUserOwned(c);
|
setUserOwned(c);
|
||||||
fetch("https://api.minehut.com/servers").then((c) => {
|
fetch("https://api.minehut.com/servers").then((c) => {
|
||||||
c.json().then((c: { servers: Array<OnlineServer> }) => {
|
c.json().then((c: { servers: Array<OnlineServer> }) => {
|
||||||
c.servers.forEach((v) => {
|
c.servers.forEach((v) => {
|
||||||
setAuthor(v.author);
|
setAuthor(v.author);
|
||||||
if (v.name == server && isSignedIn) {
|
if (v.name == server && isSignedIn) {
|
||||||
if (user?.publicMetadata.player === v.author) {
|
if (user?.publicMetadata.player === v.author) {
|
||||||
setMinehutOwned(true);
|
setMinehutOwned(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}, [isSignedIn]);
|
}, [isSignedIn]);
|
||||||
const form = useForm<z.infer<typeof formSchema>>({
|
const form = useForm<z.infer<typeof formSchema>>({
|
||||||
resolver: zodResolver(formSchema),
|
resolver: zodResolver(formSchema),
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
description,
|
description,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Spinner className="flex items-center" />
|
<LoadingSpinner className="flex items-center" />
|
||||||
<br />
|
<br />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<SignedOut>
|
<SignedOut>
|
||||||
{!serverOwned && (
|
{!serverOwned && (
|
||||||
<div>
|
<div>
|
||||||
<div className="font-bold">Do you own this server? </div>
|
<div className="font-bold">Do you own this server? </div>
|
||||||
Create an account and link it to the owner of the server to
|
Create an account and link it to the owner of the server to
|
||||||
customize it.
|
customize it.
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</SignedOut>
|
</SignedOut>
|
||||||
<SignedIn>
|
<SignedIn>
|
||||||
{!serverOwned && user?.publicMetadata.player == null && (
|
{!serverOwned && user?.publicMetadata.player == null && (
|
||||||
<div>
|
<div>
|
||||||
<div className="font-bold">Do you own this server? </div>
|
<div className="font-bold">Do you own this server? </div>
|
||||||
Create an account and link it to the owner of the server to
|
Create an account and link it to the owner of the server to
|
||||||
customize it.
|
customize it.
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{serverOwned && !userOwned && (
|
{serverOwned && !userOwned && (
|
||||||
<div>
|
<div>
|
||||||
<div className="font-bold">
|
<div className="font-bold">
|
||||||
Is this server in violation of the ECA?
|
Is this server in violation of the ECA?
|
||||||
</div>
|
</div>
|
||||||
Is this server in violation of the{" "}
|
Is this server in violation of the{" "}
|
||||||
<Link href="/docs/legal/external-content-agreement">
|
<Link href="/docs/legal/external-content-agreement">
|
||||||
External Content Agreement (aka ECA)
|
External Content Agreement (aka ECA)
|
||||||
</Link>
|
</Link>
|
||||||
? You can report the server to remove the customizations from the
|
? You can report the server to remove the customizations from the
|
||||||
server.
|
server.
|
||||||
<Dialog>
|
<Dialog>
|
||||||
<DialogTrigger>
|
<DialogTrigger>
|
||||||
<Button className="h-[30px] ml-2">Report</Button>
|
<Button className="h-[30px] ml-2">Report</Button>
|
||||||
</DialogTrigger>
|
</DialogTrigger>
|
||||||
<DialogContent>
|
<DialogContent>
|
||||||
<DialogHeader>
|
<DialogHeader>
|
||||||
<DialogTitle>Report Server</DialogTitle>
|
<DialogTitle>Report Server</DialogTitle>
|
||||||
<DialogDescription>
|
<DialogDescription>
|
||||||
This will send a notification to MHSF maintainers. This
|
This will send a notification to MHSF maintainers. This
|
||||||
server must be in violation of the{" "}
|
server must be in violation of the{" "}
|
||||||
<Link href="/docs/legal/external-content-agreement">
|
<Link href="/docs/legal/external-content-agreement">
|
||||||
ECA
|
ECA
|
||||||
</Link>{" "}
|
</Link>{" "}
|
||||||
to be a valid report. Typical response times include 1 hour
|
to be a valid report. Typical response times include 1 hour
|
||||||
to 1 day, and you will not be notified if your report is
|
to 1 day, and you will not be notified if your report is
|
||||||
successful or not.{" "}
|
successful or not.{" "}
|
||||||
<b>
|
<b>
|
||||||
Please do not spam this form with mindless reports. If you
|
Please do not spam this form with mindless reports. If you
|
||||||
do, your account will be banned. We are not Minehut
|
do, your account will be banned. We are not Minehut
|
||||||
support, we cannot help you with a problem within the
|
support, we cannot help you with a problem within the
|
||||||
Minehut platform or within the server, we can only
|
Minehut platform or within the server, we can only
|
||||||
moderate the customization of the server.
|
moderate the customization of the server.
|
||||||
</b>{" "}
|
</b>{" "}
|
||||||
(if the problem is within the server,{" "}
|
(if the problem is within the server,{" "}
|
||||||
<Link href="https://support.minehut.com/hc/en-us/requests/new?tf_subject=Reporting%20Server&tf_27062997154195=reports_appeals&tf_27063229498259=report_server">
|
<Link href="https://support.minehut.com/hc/en-us/requests/new?tf_subject=Reporting%20Server&tf_27062997154195=reports_appeals&tf_27063229498259=report_server">
|
||||||
report it on Minehut
|
report it on Minehut
|
||||||
</Link>
|
</Link>
|
||||||
)<br />
|
)<br />
|
||||||
<br />
|
<br />
|
||||||
<b>Reason:</b>
|
<b>Reason:</b>
|
||||||
</DialogDescription>
|
</DialogDescription>
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
<Textarea
|
<Textarea
|
||||||
value={reason}
|
value={reason}
|
||||||
onChange={(e) => setReason(e.target.value)}
|
onChange={(e) => setReason(e.target.value)}
|
||||||
/>
|
/>
|
||||||
<div className="grid grid-flow-row gap-2">
|
<div className="grid grid-flow-row gap-2">
|
||||||
<Button
|
<Button
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
await toast.promise(
|
await toast.promise(
|
||||||
new Promise(async (g, b) => {
|
new Promise(async (g, b) => {
|
||||||
(await reportServer(server, reason)) ? g("") : b();
|
(await reportServer(server, reason)) ? g("") : b();
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
success: "Report sent!",
|
success: "Report sent!",
|
||||||
loading: "Sending report...",
|
loading: "Sending report...",
|
||||||
error: "Error while sending report",
|
error: "Error while sending report",
|
||||||
},
|
}
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Report Server
|
Report Server
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
<br />
|
<br />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</SignedIn>
|
</SignedIn>
|
||||||
|
|
||||||
{!serverOwned && minehutOwned && (
|
{!serverOwned && minehutOwned && (
|
||||||
<div className="font-bold">
|
<div className="font-bold">
|
||||||
Do you own this server?{" "}
|
Do you own this server?{" "}
|
||||||
<Button
|
<Button
|
||||||
className="h-[30px] ml-2"
|
className="h-[30px] ml-2"
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
await toast.promise(
|
await toast.promise(
|
||||||
new Promise(async (g, b) => {
|
new Promise(async (g, b) => {
|
||||||
(await ownServer(server)) ? g("") : b();
|
(await ownServer(server)) ? g("") : b();
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
success: "Owned server!",
|
success: "Owned server!",
|
||||||
loading: "Owning server...",
|
loading: "Owning server...",
|
||||||
error: "Error while owning server",
|
error: "Error while owning server",
|
||||||
},
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
setMinehutOwned(true);
|
setMinehutOwned(true);
|
||||||
setUserOwned(true);
|
setUserOwned(true);
|
||||||
setServerOwned(true);
|
setServerOwned(true);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Click to own this server
|
Click to own this server
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<br />
|
<br />
|
||||||
{!userOwned && (
|
{!userOwned && (
|
||||||
<>
|
<>
|
||||||
<strong>
|
<strong>
|
||||||
{" "}
|
{" "}
|
||||||
<X size={24} />
|
<X size={24} />
|
||||||
Whoops.. something went wrong
|
Whoops.. something went wrong
|
||||||
</strong>
|
</strong>
|
||||||
<div> You don't have permission to customize this server. </div>
|
<div> You don't have permission to customize this server. </div>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{serverOwned && userOwned && (
|
{serverOwned && userOwned && (
|
||||||
<div className="max-w-[800px]">
|
<div className="max-w-[800px]">
|
||||||
<Card>
|
<Card>
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
<CardTitle>Description</CardTitle>
|
<CardTitle>Description</CardTitle>
|
||||||
<CardDescription>
|
<CardDescription>
|
||||||
Edit the description of the server.
|
Edit the description of the server.
|
||||||
</CardDescription>
|
</CardDescription>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<Form {...form}>
|
<Form {...form}>
|
||||||
<form
|
<form
|
||||||
onSubmit={form.handleSubmit((c) => {
|
onSubmit={form.handleSubmit((c) => {
|
||||||
toast.promise(setCustomization(server, c), {
|
toast.promise(setCustomization(server, c), {
|
||||||
success: "Successfully set description",
|
success: "Successfully set description",
|
||||||
loading: "Setting description..",
|
loading: "Setting description..",
|
||||||
error: "Error while setting descript",
|
error: "Error while setting descript",
|
||||||
});
|
});
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
name="description"
|
name="description"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem>
|
<FormItem>
|
||||||
<FormLabel>Description</FormLabel>
|
<FormLabel>Description</FormLabel>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<Editor
|
<Editor
|
||||||
height="90vh"
|
height="90vh"
|
||||||
className="rounded"
|
className="rounded"
|
||||||
defaultLanguage="markdown"
|
defaultLanguage="markdown"
|
||||||
defaultValue=""
|
defaultValue=""
|
||||||
theme={mode == "dark" ? "vs-dark" : "light"}
|
theme={mode == "dark" ? "vs-dark" : "light"}
|
||||||
{...field}
|
{...field}
|
||||||
/>
|
/>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
<FormDescription>
|
<FormDescription>
|
||||||
Set the description for your server page. <br />
|
Set the description for your server page. <br />
|
||||||
<small>
|
<small>
|
||||||
By adding a description, all text is subject to{" "}
|
By adding a description, all text is subject to{" "}
|
||||||
<Link href="https://minehut.wiki.gg/wiki/Rules">
|
<Link href="https://minehut.wiki.gg/wiki/Rules">
|
||||||
Minehuts Terms of Service
|
Minehuts Terms of Service
|
||||||
</Link>{" "}
|
</Link>{" "}
|
||||||
& the{" "}
|
& the{" "}
|
||||||
<Link href="/docs/legal/external-content-agreement">
|
<Link href="/docs/legal/external-content-agreement">
|
||||||
External Content Agreement
|
External Content Agreement
|
||||||
</Link>
|
</Link>
|
||||||
.
|
.
|
||||||
</small>
|
</small>
|
||||||
</FormDescription>
|
</FormDescription>
|
||||||
<FormMessage />
|
<FormMessage />
|
||||||
</FormItem>
|
</FormItem>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
<CardFooter className="border-t px-6 py-4">
|
<CardFooter className="border-t px-6 py-4">
|
||||||
<Button type="submit" className="h-[30px]">
|
<Button type="submit" className="h-[30px]">
|
||||||
Edit Description
|
Edit Description
|
||||||
</Button>
|
</Button>
|
||||||
</CardFooter>
|
</CardFooter>
|
||||||
</form>
|
</form>
|
||||||
</Form>
|
</Form>
|
||||||
</Card>
|
</Card>
|
||||||
<br />
|
<br />
|
||||||
<br />
|
<br />
|
||||||
<Setting
|
<Setting
|
||||||
name="Color Scheme"
|
name="Color Scheme"
|
||||||
description={
|
description={
|
||||||
<>
|
<>
|
||||||
Pick any color scheme for the components on your server page to
|
Pick any color scheme for the components on your server page to
|
||||||
use.
|
use.
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
button={
|
button={
|
||||||
<Popover>
|
<Popover>
|
||||||
<PopoverTrigger>
|
<PopoverTrigger>
|
||||||
<Button type="submit" className="h-[30px]">
|
<Button type="submit" className="h-[30px]">
|
||||||
Edit Color Schemes
|
Edit Color Schemes
|
||||||
</Button>
|
</Button>
|
||||||
</PopoverTrigger>
|
</PopoverTrigger>
|
||||||
<PopoverContent className="grid grid-cols-3 gap-1.5 w-[400px]">
|
<PopoverContent className="grid grid-cols-3 gap-1.5 w-[400px]">
|
||||||
{themes.map((colorObj) => {
|
{themes.map((colorObj) => {
|
||||||
const color = colorObj.name;
|
const color = colorObj.name;
|
||||||
const theme = themes.find((theme) => theme.name === color);
|
const theme = themes.find((theme) => theme.name === color);
|
||||||
const isActive = cs === color;
|
const isActive = cs === color;
|
||||||
|
|
||||||
if (!theme) {
|
if (!theme) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
variant={"outline"}
|
variant={"outline"}
|
||||||
size="sm"
|
size="sm"
|
||||||
key={theme.name}
|
key={theme.name}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setCS(theme.name);
|
setCS(theme.name);
|
||||||
setCustomization(server, { colorScheme: theme.name });
|
setCustomization(server, { colorScheme: theme.name });
|
||||||
}}
|
}}
|
||||||
className={
|
className={
|
||||||
"justify-start " +
|
"justify-start " +
|
||||||
(isActive && "border-2 border-primary")
|
(isActive && "border-2 border-primary")
|
||||||
}
|
}
|
||||||
style={
|
style={
|
||||||
{
|
{
|
||||||
"--theme-primary": `hsl(${
|
"--theme-primary": `hsl(${
|
||||||
theme?.activeColor[
|
theme?.activeColor[
|
||||||
mode === "dark" ? "dark" : "light"
|
mode === "dark" ? "dark" : "light"
|
||||||
]
|
]
|
||||||
})`,
|
})`,
|
||||||
} as React.CSSProperties
|
} as React.CSSProperties
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
className={
|
className={
|
||||||
"mr-1 flex h-5 w-5 shrink-0 -translate-x-1 items-center justify-center rounded-full bg-[--theme-primary]"
|
"mr-1 flex h-5 w-5 shrink-0 -translate-x-1 items-center justify-center rounded-full bg-[--theme-primary]"
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{isActive && (
|
{isActive && (
|
||||||
<CheckIcon className="h-4 w-4 text-white" />
|
<CheckIcon className="h-4 w-4 text-white" />
|
||||||
)}
|
)}
|
||||||
</span>
|
</span>
|
||||||
{theme.label}
|
{theme.label}
|
||||||
</Button>
|
</Button>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</PopoverContent>
|
</PopoverContent>
|
||||||
</Popover>
|
</Popover>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<br />
|
<br />
|
||||||
<br />
|
<br />
|
||||||
<Setting
|
<Setting
|
||||||
name="Banner"
|
name="Banner"
|
||||||
description={
|
description={
|
||||||
<>
|
<>
|
||||||
Banners appear on both the server list, and the server page.{" "}
|
Banners appear on both the server list, and the server page.{" "}
|
||||||
<i>
|
<i>
|
||||||
You will have to provide your own Imgur image for your image.
|
You will have to provide your own Imgur image for your image.
|
||||||
</i>
|
</i>
|
||||||
<br />
|
<br />
|
||||||
<small>
|
<small>
|
||||||
By adding a banner, all images are subject to{" "}
|
By adding a banner, all images are subject to{" "}
|
||||||
<Link href="https://minehut.wiki.gg/wiki/Rules">
|
<Link href="https://minehut.wiki.gg/wiki/Rules">
|
||||||
Minehuts Terms of Service
|
Minehuts Terms of Service
|
||||||
</Link>
|
</Link>
|
||||||
,{" "}
|
,{" "}
|
||||||
<Link href="https://imgur.com/tos">
|
<Link href="https://imgur.com/tos">
|
||||||
Imgurs Terms of Service
|
Imgurs Terms of Service
|
||||||
</Link>{" "}
|
</Link>{" "}
|
||||||
& the{" "}
|
& the{" "}
|
||||||
<Link href="/docs/legal/external-content-agreement">
|
<Link href="/docs/legal/external-content-agreement">
|
||||||
External Content Agreement
|
External Content Agreement
|
||||||
</Link>
|
</Link>
|
||||||
.
|
.
|
||||||
</small>
|
</small>
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
button={
|
button={
|
||||||
<Popover>
|
<Popover>
|
||||||
<PopoverTrigger>
|
<PopoverTrigger>
|
||||||
<Button className="h-[30px]">Change Banner</Button>
|
<Button className="h-[30px]">Change Banner</Button>
|
||||||
</PopoverTrigger>
|
</PopoverTrigger>
|
||||||
<PopoverContent>
|
<PopoverContent>
|
||||||
<BannerPopover server={server} get={get} />
|
<BannerPopover server={server} get={get} />
|
||||||
</PopoverContent>
|
</PopoverContent>
|
||||||
</Popover>
|
</Popover>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<br />
|
<br />
|
||||||
<br />
|
<br />
|
||||||
<Setting
|
<Setting
|
||||||
name="Discord Server"
|
name="Discord Server"
|
||||||
description={
|
description={
|
||||||
<>
|
<>
|
||||||
Associate a Discord server embed in your server page.
|
Associate a Discord server embed in your server page.
|
||||||
<br />
|
<br />
|
||||||
<small>
|
<small>
|
||||||
By adding a Discord Server, all servers are subject to{" "}
|
By adding a Discord Server, all servers are subject to{" "}
|
||||||
<Link href="https://discord.com/terms/">
|
<Link href="https://discord.com/terms/">
|
||||||
Discords Terms of Service
|
Discords Terms of Service
|
||||||
</Link>{" "}
|
</Link>{" "}
|
||||||
& the{" "}
|
& the{" "}
|
||||||
<Link href="/docs/legal/external-content-agreement">
|
<Link href="/docs/legal/external-content-agreement">
|
||||||
External Content Agreement
|
External Content Agreement
|
||||||
</Link>
|
</Link>
|
||||||
.
|
.
|
||||||
</small>
|
</small>
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
button={
|
button={
|
||||||
<Popover>
|
<Popover>
|
||||||
<PopoverTrigger>
|
<PopoverTrigger>
|
||||||
<Button className="h-[30px]">Change Discord</Button>
|
<Button className="h-[30px]">Change Discord</Button>
|
||||||
</PopoverTrigger>
|
</PopoverTrigger>
|
||||||
<PopoverContent>
|
<PopoverContent>
|
||||||
<DiscordPopover server={server} get={get} />
|
<DiscordPopover server={server} get={get} />
|
||||||
</PopoverContent>
|
</PopoverContent>
|
||||||
</Popover>
|
</Popover>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<br />
|
<br />
|
||||||
<br />
|
<br />
|
||||||
<Setting
|
<Setting
|
||||||
name="Un-own server"
|
name="Un-own server"
|
||||||
description={
|
description={
|
||||||
<>
|
<>
|
||||||
By unowning the server, you will revert all customizations on
|
By unowning the server, you will revert all customizations on
|
||||||
the server and not be associated with the server.
|
the server and not be associated with the server.
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
button={
|
button={
|
||||||
<Button
|
<Button
|
||||||
className="h-[30px]"
|
className="h-[30px]"
|
||||||
variant="destructive"
|
variant="destructive"
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
toast.promise(unownServer(server), {
|
toast.promise(unownServer(server), {
|
||||||
success: "Un-owned server!",
|
success: "Un-owned server!",
|
||||||
loading: "Un-owning server...",
|
loading: "Un-owning server...",
|
||||||
error: "Error while un-owning server.",
|
error: "Error while un-owning server.",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
Un-own Server
|
Un-own Server
|
||||||
</Button>
|
</Button>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<br />
|
<br />
|
||||||
<br />
|
<br />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -59,6 +59,7 @@ import { useClerk, useUser } from "@clerk/nextjs";
|
|||||||
import { LoaderIcon } from "react-hot-toast";
|
import { LoaderIcon } from "react-hot-toast";
|
||||||
import { Separator } from "./ui/separator";
|
import { Separator } from "./ui/separator";
|
||||||
import { convert } from "@/components/NewChart";
|
import { convert } from "@/components/NewChart";
|
||||||
|
import { LoadingSpinner } from "./ui/loading-spinner";
|
||||||
|
|
||||||
export default function ServerView(props: { server: string }) {
|
export default function ServerView(props: { server: string }) {
|
||||||
const [single, setSingle] = useState(new ServerSingle(props.server));
|
const [single, setSingle] = useState(new ServerSingle(props.server));
|
||||||
@ -210,7 +211,9 @@ export default function ServerView(props: { server: string }) {
|
|||||||
}}
|
}}
|
||||||
disabled={loadingFavorite}
|
disabled={loadingFavorite}
|
||||||
>
|
>
|
||||||
{loadingFavorite && <LoaderIcon className="mr-2" />}
|
{loadingFavorite && (
|
||||||
|
<LoadingSpinner className="mr-2 h-4 w-4" />
|
||||||
|
)}
|
||||||
{!favorited && !loadingFavorite && (
|
{!favorited && !loadingFavorite && (
|
||||||
<motion.div
|
<motion.div
|
||||||
animate={{ opacity: 1, scale: 1 }}
|
animate={{ opacity: 1, scale: 1 }}
|
||||||
|
|||||||
@ -31,7 +31,6 @@
|
|||||||
"use client";
|
"use client";
|
||||||
import IconDisplay from "@/components/IconDisplay";
|
import IconDisplay from "@/components/IconDisplay";
|
||||||
import { Badge } from "@/components/ui/badge";
|
import { Badge } from "@/components/ui/badge";
|
||||||
import { Spinner } from "@/components/ui/spinner";
|
|
||||||
import type { ServerResponse } from "@/lib/types/mh-server";
|
import type { ServerResponse } from "@/lib/types/mh-server";
|
||||||
import { Copy, ExternalLink, ServerCrash } from "lucide-react";
|
import { Copy, ExternalLink, ServerCrash } from "lucide-react";
|
||||||
import { notFound, useSearchParams } from "next/navigation";
|
import { notFound, useSearchParams } from "next/navigation";
|
||||||
@ -40,6 +39,7 @@ import { Button } from "../ui/button";
|
|||||||
import { CheckmarkIcon } from "react-hot-toast";
|
import { CheckmarkIcon } from "react-hot-toast";
|
||||||
import useClipboard from "@/lib/useClipboard";
|
import useClipboard from "@/lib/useClipboard";
|
||||||
import { Tooltip, TooltipTrigger, TooltipContent } from "../ui/tooltip";
|
import { Tooltip, TooltipTrigger, TooltipContent } from "../ui/tooltip";
|
||||||
|
import { LoadingSpinner } from "../ui/loading-spinner";
|
||||||
|
|
||||||
export default function Embed({ params }: { params: { server: string } }) {
|
export default function Embed({ params }: { params: { server: string } }) {
|
||||||
const [serverFound, setServerFound] = useState(true);
|
const [serverFound, setServerFound] = useState(true);
|
||||||
@ -65,7 +65,7 @@ export default function Embed({ params }: { params: { server: string } }) {
|
|||||||
}, [params]);
|
}, [params]);
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return <Spinner />;
|
return <LoadingSpinner />;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!serverFound) {
|
if (!serverFound) {
|
||||||
|
|||||||
@ -39,7 +39,7 @@ import { codeToHtml } from "shiki";
|
|||||||
import { useTheme } from "next-themes";
|
import { useTheme } from "next-themes";
|
||||||
import { Asterisk, Copy } from "lucide-react";
|
import { Asterisk, Copy } from "lucide-react";
|
||||||
import useClipboard from "@/lib/useClipboard";
|
import useClipboard from "@/lib/useClipboard";
|
||||||
import toast from "react-hot-toast";
|
import { toast } from "sonner";
|
||||||
import { Checkbox } from "../ui/checkbox";
|
import { Checkbox } from "../ui/checkbox";
|
||||||
import {
|
import {
|
||||||
Select,
|
Select,
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
"use client";
|
"use client";;
|
||||||
|
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
@ -15,8 +14,7 @@ import {
|
|||||||
} from "@/components/ui/form";
|
} from "@/components/ui/form";
|
||||||
import { Input } from "@/components/ui/input";
|
import { Input } from "@/components/ui/input";
|
||||||
import { setCustomization } from "@/lib/api";
|
import { setCustomization } from "@/lib/api";
|
||||||
import { useEffect } from "react";
|
import { toast } from "sonner";
|
||||||
import toast from "react-hot-toast";
|
|
||||||
import ColorProvider from "../ColorProvider";
|
import ColorProvider from "../ColorProvider";
|
||||||
|
|
||||||
const FormSchema = z.object({
|
const FormSchema = z.object({
|
||||||
|
|||||||
@ -47,7 +47,7 @@ import { Input } from "@/components/ui/input";
|
|||||||
import { setCustomization } from "@/lib/api";
|
import { setCustomization } from "@/lib/api";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import ColorProvider from "../ColorProvider";
|
import ColorProvider from "../ColorProvider";
|
||||||
import toast from "react-hot-toast";
|
import { toast } from "sonner";
|
||||||
|
|
||||||
const FormSchema = z.object({
|
const FormSchema = z.object({
|
||||||
id: z.string().min(2, {
|
id: z.string().min(2, {
|
||||||
|
|||||||
@ -49,7 +49,7 @@ import {
|
|||||||
InputOTPSlot,
|
InputOTPSlot,
|
||||||
} from "@/components/ui/input-otp";
|
} from "@/components/ui/input-otp";
|
||||||
import { linkMCAccount } from "@/lib/api";
|
import { linkMCAccount } from "@/lib/api";
|
||||||
import toast from "react-hot-toast";
|
import { toast } from "sonner";
|
||||||
import {
|
import {
|
||||||
Dialog,
|
Dialog,
|
||||||
DialogContent,
|
DialogContent,
|
||||||
|
|||||||
68
src/components/misc/StickyTopbar.tsx
Normal file
68
src/components/misc/StickyTopbar.tsx
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
/*
|
||||||
|
* MHSF, Minehut Server List
|
||||||
|
* All external content is rather licensed under the ECA Agreement
|
||||||
|
* located here: https://mhsf.app/docs/legal/external-content-agreement
|
||||||
|
*
|
||||||
|
* All code under MHSF is licensed under the MIT License
|
||||||
|
* by open source contributors
|
||||||
|
*
|
||||||
|
* Copyright (c) 2024 dvelo
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to
|
||||||
|
* deal in the Software without restriction, including without limitation the
|
||||||
|
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
* sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||||
|
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||||
|
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||||
|
* OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
"use client";
|
||||||
|
|
||||||
|
import { useEffect, useState, ReactNode } from "react";
|
||||||
|
|
||||||
|
export default function StickyTopbar({
|
||||||
|
children,
|
||||||
|
scrollElevation,
|
||||||
|
className,
|
||||||
|
}: {
|
||||||
|
children: ReactNode;
|
||||||
|
scrollElevation: number;
|
||||||
|
className?: string;
|
||||||
|
}) {
|
||||||
|
const [isSticky, setIsSticky] = useState(false);
|
||||||
|
|
||||||
|
const handleScroll = () => {
|
||||||
|
if (window.scrollY > scrollElevation) {
|
||||||
|
setIsSticky(true);
|
||||||
|
} else {
|
||||||
|
setIsSticky(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
window.addEventListener("scroll", handleScroll);
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener("scroll", handleScroll);
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={`transition-all duration-300 ${isSticky ? "fixed top-[70px] left-0 w-full backdrop-blur shadow-lg " + className : "block w-full bg-transparent"}`}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -31,7 +31,7 @@
|
|||||||
"use client";
|
"use client";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { Button } from "../ui/button";
|
import { Button } from "../ui/button";
|
||||||
import toast from "react-hot-toast";
|
import { toast } from "sonner";
|
||||||
import { Check } from "lucide-react";
|
import { Check } from "lucide-react";
|
||||||
import useClipboard from "@/lib/useClipboard";
|
import useClipboard from "@/lib/useClipboard";
|
||||||
|
|
||||||
|
|||||||
@ -31,20 +31,10 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useTheme } from "next-themes";
|
import { useTheme } from "next-themes";
|
||||||
import { Toaster } from "react-hot-toast";
|
import { Toaster } from "../ui/sonner";
|
||||||
|
|
||||||
export default function ThemedToaster() {
|
export default function ThemedToaster() {
|
||||||
const { resolvedTheme } = useTheme();
|
const { resolvedTheme } = useTheme();
|
||||||
|
|
||||||
return (
|
return <Toaster position="bottom-center" richColors />;
|
||||||
<Toaster
|
|
||||||
position="bottom-center"
|
|
||||||
reverseOrder={false}
|
|
||||||
toastOptions={
|
|
||||||
resolvedTheme == "dark"
|
|
||||||
? { style: { background: "#333", color: "#fff" } }
|
|
||||||
: undefined
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|||||||
64
src/components/ui/loading-spinner.tsx
Normal file
64
src/components/ui/loading-spinner.tsx
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* MHSF, Minehut Server List
|
||||||
|
* All external content is rather licensed under the ECA Agreement
|
||||||
|
* located here: https://mhsf.app/docs/legal/external-content-agreement
|
||||||
|
*
|
||||||
|
* All code under MHSF is licensed under the MIT License
|
||||||
|
* by open source contributors
|
||||||
|
*
|
||||||
|
* Copyright (c) 2024 dvelo
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to
|
||||||
|
* deal in the Software without restriction, including without limitation the
|
||||||
|
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
* sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||||
|
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||||
|
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||||
|
* OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
|
export function LoadingSpinner({ className }: { className?: string }) {
|
||||||
|
return (
|
||||||
|
<div className={cn("h-5 w-5", className)}>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
position: "relative",
|
||||||
|
top: "50%",
|
||||||
|
left: "50%",
|
||||||
|
}}
|
||||||
|
className={cn("loading-spinner", "h-5 w-5", className)}
|
||||||
|
>
|
||||||
|
{[...Array(12)].map((_, i) => (
|
||||||
|
<div
|
||||||
|
key={i}
|
||||||
|
style={{
|
||||||
|
animationDelay: `${-1.2 + 0.1 * i}s`,
|
||||||
|
background: "gray",
|
||||||
|
position: "absolute",
|
||||||
|
borderRadius: "1rem",
|
||||||
|
width: "30%",
|
||||||
|
height: "8%",
|
||||||
|
left: "-10%",
|
||||||
|
top: "-4%",
|
||||||
|
transform: `rotate(${30 * i}deg) translate(120%)`,
|
||||||
|
}}
|
||||||
|
className="animate-spinner"
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
31
src/components/ui/sonner.tsx
Normal file
31
src/components/ui/sonner.tsx
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
"use client"
|
||||||
|
|
||||||
|
import { useTheme } from "next-themes"
|
||||||
|
import { Toaster as Sonner } from "sonner"
|
||||||
|
|
||||||
|
type ToasterProps = React.ComponentProps<typeof Sonner>
|
||||||
|
|
||||||
|
const Toaster = ({ ...props }: ToasterProps) => {
|
||||||
|
const { theme = "system" } = useTheme()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Sonner
|
||||||
|
theme={theme as ToasterProps["theme"]}
|
||||||
|
className="toaster group"
|
||||||
|
toastOptions={{
|
||||||
|
classNames: {
|
||||||
|
toast:
|
||||||
|
"group toast group-[.toaster]:bg-background group-[.toaster]:text-foreground group-[.toaster]:border-border group-[.toaster]:shadow-lg",
|
||||||
|
description: "group-[.toast]:text-muted-foreground",
|
||||||
|
actionButton:
|
||||||
|
"group-[.toast]:bg-primary group-[.toast]:text-primary-foreground",
|
||||||
|
cancelButton:
|
||||||
|
"group-[.toast]:bg-muted group-[.toast]:text-muted-foreground",
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export { Toaster }
|
||||||
@ -59,7 +59,7 @@ const TabsTrigger = React.forwardRef<
|
|||||||
<TabsPrimitive.Trigger
|
<TabsPrimitive.Trigger
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
"inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm",
|
"inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:text-foreground data-[state=active]:shadow-sm",
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
|
|||||||
42
src/config/affiliates.ts
Normal file
42
src/config/affiliates.ts
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* MHSF, Minehut Server List
|
||||||
|
* All external content is rather licensed under the ECA Agreement
|
||||||
|
* located here: https://mhsf.app/docs/legal/external-content-agreement
|
||||||
|
*
|
||||||
|
* All code under MHSF is licensed under the MIT License
|
||||||
|
* by open source contributors
|
||||||
|
*
|
||||||
|
* Copyright (c) 2024 dvelo
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to
|
||||||
|
* deal in the Software without restriction, including without limitation the
|
||||||
|
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
* sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||||
|
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||||
|
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||||
|
* OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { SVGProps } from "react";
|
||||||
|
|
||||||
|
export const affiliates: {
|
||||||
|
name: string;
|
||||||
|
shop: string;
|
||||||
|
line: string;
|
||||||
|
mode: string[];
|
||||||
|
otherLinks: {
|
||||||
|
name: string;
|
||||||
|
icon: (props: SVGProps<SVGSVGElement>) => JSX.Element;
|
||||||
|
}[];
|
||||||
|
}[] = [];
|
||||||
@ -29,7 +29,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { OnlineServer } from "./types/mh-server";
|
import { OnlineServer } from "./types/mh-server";
|
||||||
import toast from "react-hot-toast";
|
import { toast } from "sonner";
|
||||||
import { getMOTDFromServer } from "./api";
|
import { getMOTDFromServer } from "./api";
|
||||||
|
|
||||||
var numberOfItemsInView = 20;
|
var numberOfItemsInView = 20;
|
||||||
|
|||||||
@ -30,7 +30,7 @@
|
|||||||
|
|
||||||
import { serverOwned } from "./api";
|
import { serverOwned } from "./api";
|
||||||
import { OnlineServer, ServerResponse } from "./types/mh-server";
|
import { OnlineServer, ServerResponse } from "./types/mh-server";
|
||||||
import toast from "react-hot-toast";
|
import { toast } from "sonner";
|
||||||
|
|
||||||
export default class ServerSingle {
|
export default class ServerSingle {
|
||||||
private name = "";
|
private name = "";
|
||||||
|
|||||||
@ -28,7 +28,7 @@
|
|||||||
* OTHER DEALINGS IN THE SOFTWARE.
|
* OTHER DEALINGS IN THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import toast from "react-hot-toast"
|
import { toast } from "sonner";
|
||||||
|
|
||||||
/** A hook to properly write text to the clipboard without triggering a client-side error
|
/** A hook to properly write text to the clipboard without triggering a client-side error
|
||||||
* @version 1.0
|
* @version 1.0
|
||||||
|
|||||||
@ -31,177 +31,186 @@
|
|||||||
import type { Config } from "tailwindcss";
|
import type { Config } from "tailwindcss";
|
||||||
|
|
||||||
const config = {
|
const config = {
|
||||||
darkMode: ["class"],
|
darkMode: ["class"],
|
||||||
content: [
|
content: [
|
||||||
"./pages/**/*.{ts,tsx}",
|
"./pages/**/*.{ts,tsx}",
|
||||||
"./components/**/*.{ts,tsx}",
|
"./components/**/*.{ts,tsx}",
|
||||||
"./app/**/*.{ts,tsx}",
|
"./app/**/*.{ts,tsx}",
|
||||||
"./src/**/*.{ts,tsx,json}",
|
"./src/**/*.{ts,tsx,json}",
|
||||||
],
|
],
|
||||||
prefix: "",
|
prefix: "",
|
||||||
theme: {
|
theme: {
|
||||||
container: {
|
container: {
|
||||||
center: true,
|
center: true,
|
||||||
padding: "2rem",
|
padding: "2rem",
|
||||||
screens: {
|
screens: {
|
||||||
"2xl": "1400px",
|
"2xl": "1400px",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
extend: {
|
extend: {
|
||||||
colors: {
|
colors: {
|
||||||
border: "hsl(var(--border))",
|
border: "hsl(var(--border))",
|
||||||
input: "hsl(var(--input))",
|
input: "hsl(var(--input))",
|
||||||
ring: "hsl(var(--ring))",
|
ring: "hsl(var(--ring))",
|
||||||
background: "hsl(var(--background))",
|
background: "hsl(var(--background))",
|
||||||
foreground: "hsl(var(--foreground))",
|
foreground: "hsl(var(--foreground))",
|
||||||
primary: {
|
primary: {
|
||||||
DEFAULT: "hsl(var(--primary))",
|
DEFAULT: "hsl(var(--primary))",
|
||||||
foreground: "hsl(var(--primary-foreground))",
|
foreground: "hsl(var(--primary-foreground))",
|
||||||
},
|
},
|
||||||
secondary: {
|
secondary: {
|
||||||
DEFAULT: "hsl(var(--secondary))",
|
DEFAULT: "hsl(var(--secondary))",
|
||||||
foreground: "hsl(var(--secondary-foreground))",
|
foreground: "hsl(var(--secondary-foreground))",
|
||||||
},
|
},
|
||||||
destructive: {
|
destructive: {
|
||||||
DEFAULT: "hsl(var(--destructive))",
|
DEFAULT: "hsl(var(--destructive))",
|
||||||
foreground: "hsl(var(--destructive-foreground))",
|
foreground: "hsl(var(--destructive-foreground))",
|
||||||
},
|
},
|
||||||
muted: {
|
muted: {
|
||||||
DEFAULT: "hsl(var(--muted))",
|
DEFAULT: "hsl(var(--muted))",
|
||||||
foreground: "hsl(var(--muted-foreground))",
|
foreground: "hsl(var(--muted-foreground))",
|
||||||
},
|
},
|
||||||
accent: {
|
accent: {
|
||||||
DEFAULT: "hsl(var(--accent))",
|
DEFAULT: "hsl(var(--accent))",
|
||||||
foreground: "hsl(var(--accent-foreground))",
|
foreground: "hsl(var(--accent-foreground))",
|
||||||
},
|
},
|
||||||
popover: {
|
popover: {
|
||||||
DEFAULT: "hsl(var(--popover))",
|
DEFAULT: "hsl(var(--popover))",
|
||||||
foreground: "hsl(var(--popover-foreground))",
|
foreground: "hsl(var(--popover-foreground))",
|
||||||
},
|
},
|
||||||
card: {
|
card: {
|
||||||
DEFAULT: "hsl(var(--card))",
|
DEFAULT: "hsl(var(--card))",
|
||||||
foreground: "hsl(var(--card-foreground))",
|
foreground: "hsl(var(--card-foreground))",
|
||||||
},
|
},
|
||||||
sidebar: {
|
sidebar: {
|
||||||
DEFAULT: "hsl(var(--sidebar-background))",
|
DEFAULT: "hsl(var(--sidebar-background))",
|
||||||
foreground: "hsl(var(--sidebar-foreground))",
|
foreground: "hsl(var(--sidebar-foreground))",
|
||||||
primary: "hsl(var(--sidebar-primary))",
|
primary: "hsl(var(--sidebar-primary))",
|
||||||
"primary-foreground": "hsl(var(--sidebar-primary-foreground))",
|
"primary-foreground": "hsl(var(--sidebar-primary-foreground))",
|
||||||
accent: "hsl(var(--sidebar-accent))",
|
accent: "hsl(var(--sidebar-accent))",
|
||||||
"accent-foreground": "hsl(var(--sidebar-accent-foreground))",
|
"accent-foreground": "hsl(var(--sidebar-accent-foreground))",
|
||||||
border: "hsl(var(--sidebar-border))",
|
border: "hsl(var(--sidebar-border))",
|
||||||
ring: "hsl(var(--sidebar-ring))",
|
ring: "hsl(var(--sidebar-ring))",
|
||||||
mhsf: "hsl(var(--sidebar-mhsf))",
|
mhsf: "hsl(var(--sidebar-mhsf))",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
borderRadius: {
|
borderRadius: {
|
||||||
lg: "var(--radius)",
|
lg: "var(--radius)",
|
||||||
md: "calc(var(--radius) - 2px)",
|
md: "calc(var(--radius) - 2px)",
|
||||||
sm: "calc(var(--radius) - 4px)",
|
sm: "calc(var(--radius) - 4px)",
|
||||||
},
|
},
|
||||||
keyframes: {
|
keyframes: {
|
||||||
"image-glow": {
|
"image-glow": {
|
||||||
"0%": {
|
"0%": {
|
||||||
opacity: "0",
|
opacity: "0",
|
||||||
"animation-timing-function": "cubic-bezier(0.74, 0.25, 0.76, 1)",
|
"animation-timing-function": "cubic-bezier(0.74, 0.25, 0.76, 1)",
|
||||||
},
|
},
|
||||||
"10%": {
|
"10%": {
|
||||||
opacity: "0.7",
|
opacity: "0.7",
|
||||||
"animation-timing-function": "cubic-bezier(0.12, 0.01, 0.08, 0.99)",
|
"animation-timing-function": "cubic-bezier(0.12, 0.01, 0.08, 0.99)",
|
||||||
},
|
},
|
||||||
"100%": {
|
"100%": {
|
||||||
opacity: "0.4",
|
opacity: "0.4",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"border-beam": {
|
"border-beam": {
|
||||||
"100%": {
|
"100%": {
|
||||||
"offset-distance": "100%",
|
"offset-distance": "100%",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"caret-blink": {
|
"caret-blink": {
|
||||||
"0%,70%,100%": {
|
"0%,70%,100%": {
|
||||||
opacity: "1",
|
opacity: "1",
|
||||||
},
|
},
|
||||||
"20%,50%": {
|
"20%,50%": {
|
||||||
opacity: "0",
|
opacity: "0",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"accordion-down": {
|
"accordion-down": {
|
||||||
from: {
|
from: {
|
||||||
height: "0",
|
height: "0",
|
||||||
},
|
},
|
||||||
to: {
|
to: {
|
||||||
height: "var(--radix-accordion-content-height)",
|
height: "var(--radix-accordion-content-height)",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"accordion-up": {
|
"accordion-up": {
|
||||||
from: {
|
from: {
|
||||||
height: "var(--radix-accordion-content-height)",
|
height: "var(--radix-accordion-content-height)",
|
||||||
},
|
},
|
||||||
to: {
|
to: {
|
||||||
height: "0",
|
height: "0",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"fade-in": {
|
"fade-in": {
|
||||||
from: {
|
from: {
|
||||||
opacity: "0",
|
opacity: "0",
|
||||||
transform: "translateY(-10px)",
|
transform: "translateY(-10px)",
|
||||||
},
|
},
|
||||||
to: {
|
to: {
|
||||||
opacity: "1",
|
opacity: "1",
|
||||||
transform: "none",
|
transform: "none",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
marquee: {
|
marquee: {
|
||||||
from: {
|
from: {
|
||||||
transform: "translateX(0)",
|
transform: "translateX(0)",
|
||||||
},
|
},
|
||||||
to: {
|
to: {
|
||||||
transform: "translateX(calc(-100% - var(--gap)))",
|
transform: "translateX(calc(-100% - var(--gap)))",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"marquee-vertical": {
|
"marquee-vertical": {
|
||||||
from: {
|
from: {
|
||||||
transform: "translateY(0)",
|
transform: "translateY(0)",
|
||||||
},
|
},
|
||||||
to: {
|
to: {
|
||||||
transform: "translateY(calc(-100% - var(--gap)))",
|
transform: "translateY(calc(-100% - var(--gap)))",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"fade-up": {
|
"fade-up": {
|
||||||
from: {
|
from: {
|
||||||
opacity: "0",
|
opacity: "0",
|
||||||
transform: "translateY(20px)",
|
transform: "translateY(20px)",
|
||||||
},
|
},
|
||||||
to: {
|
to: {
|
||||||
opacity: "1",
|
opacity: "1",
|
||||||
transform: "none",
|
transform: "none",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
shimmer: {
|
spinner: {
|
||||||
"0%, 90%, 100%": {
|
"0%": {
|
||||||
"background-position": "calc(-100% - var(--shimmer-width)) 0",
|
opacity: "1",
|
||||||
},
|
},
|
||||||
"30%, 60%": {
|
"100%": {
|
||||||
"background-position": "calc(100% + var(--shimmer-width)) 0",
|
opacity: "0",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
shimmer: {
|
||||||
animation: {
|
"0%, 90%, 100%": {
|
||||||
marquee: "marquee var(--duration) linear infinite",
|
"background-position": "calc(-100% - var(--shimmer-width)) 0",
|
||||||
"marquee-vertical": "marquee-vertical var(--duration) linear infinite",
|
},
|
||||||
"accordion-down": "accordion-down 0.2s ease-out",
|
"30%, 60%": {
|
||||||
"accordion-up": "accordion-up 0.2s ease-out",
|
"background-position": "calc(100% + var(--shimmer-width)) 0",
|
||||||
"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",
|
animation: {
|
||||||
"border-beam": "border-beam calc(var(--duration)*1s) infinite linear",
|
marquee: "marquee var(--duration) linear infinite",
|
||||||
"fade-up": "fade-up 1000ms var(--animation-delay, 0ms) ease forwards",
|
"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",
|
||||||
plugins: [require("tailwindcss-animate"), require("@tailwindcss/typography")],
|
shimmer: "shimmer 8s infinite",
|
||||||
|
spinner: "spinner 1.2s linear infinite",
|
||||||
|
"fade-in": "fade-in 1000ms var(--animation-delay, 0ms) ease forwards",
|
||||||
|
"caret-blink": "caret-blink 1.25s ease-out infinite",
|
||||||
|
"border-beam": "border-beam calc(var(--duration)*1s) infinite linear",
|
||||||
|
"fade-up": "fade-up 1000ms var(--animation-delay, 0ms) ease forwards",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
plugins: [require("tailwindcss-animate"), require("@tailwindcss/typography")],
|
||||||
} satisfies Config;
|
} satisfies Config;
|
||||||
|
|
||||||
export default config;
|
export default config;
|
||||||
|
|||||||
21
yarn.lock
21
yarn.lock
@ -4322,9 +4322,9 @@ globby@^11.1.0:
|
|||||||
slash "^3.0.0"
|
slash "^3.0.0"
|
||||||
|
|
||||||
goober@^2.1.10:
|
goober@^2.1.10:
|
||||||
version "2.1.14"
|
version "2.1.16"
|
||||||
resolved "https://registry.npmjs.org/goober/-/goober-2.1.14.tgz"
|
resolved "https://registry.yarnpkg.com/goober/-/goober-2.1.16.tgz#7d548eb9b83ff0988d102be71f271ca8f9c82a95"
|
||||||
integrity sha512-4UpC0NdGyAFqLNPnhCT2iHpza2q+RAY3GV85a/mRPdzyPQMsj0KmMMuetdIkzWRbJ+Hgau1EZztq8ImmiMGhsg==
|
integrity sha512-erjk19y1U33+XAMe1VTvIONHYoSqE4iS7BYUZfHaqeohLmnC0FdxEh7rQU+6MZ4OajItzjZFSRtVANrQwNq6/g==
|
||||||
|
|
||||||
gopd@^1.0.1:
|
gopd@^1.0.1:
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
@ -6344,10 +6344,10 @@ next-css-obfuscator@^2.2.16:
|
|||||||
recoverable-random "^1.0.5"
|
recoverable-random "^1.0.5"
|
||||||
yargs "^17.7.2"
|
yargs "^17.7.2"
|
||||||
|
|
||||||
next-themes@^0.3.0:
|
next-themes@^0.4.3:
|
||||||
version "0.3.0"
|
version "0.4.3"
|
||||||
resolved "https://registry.npmjs.org/next-themes/-/next-themes-0.3.0.tgz"
|
resolved "https://registry.yarnpkg.com/next-themes/-/next-themes-0.4.3.tgz#ea54552d5986936d177eed393ea50b658ae44800"
|
||||||
integrity sha512-/QHIrsYpd6Kfk7xakK4svpDI5mmXP0gfvCoJdGpZQ2TOrQZmsW0QxjaiLn8wbIKjtm4BTSqLoix4lxYYOnLJ/w==
|
integrity sha512-nG84VPkTdUHR2YeD89YchvV4I9RbiMAql3GiLEQlPvq1ioaqPaIReK+yMRdg/zgiXws620qS1rU30TiWmmG9lA==
|
||||||
|
|
||||||
next@14.2.10:
|
next@14.2.10:
|
||||||
version "14.2.10"
|
version "14.2.10"
|
||||||
@ -6890,7 +6890,7 @@ react-hook-form@^7.52.2:
|
|||||||
|
|
||||||
react-hot-toast@^2.4.1:
|
react-hot-toast@^2.4.1:
|
||||||
version "2.4.1"
|
version "2.4.1"
|
||||||
resolved "https://registry.npmjs.org/react-hot-toast/-/react-hot-toast-2.4.1.tgz"
|
resolved "https://registry.yarnpkg.com/react-hot-toast/-/react-hot-toast-2.4.1.tgz#df04295eda8a7b12c4f968e54a61c8d36f4c0994"
|
||||||
integrity sha512-j8z+cQbWIM5LY37pR6uZR6D4LfseplqnuAO4co4u8917hBUvXlEqyP1ZzqVLcqoyUesZZv/ImreoCeHVDpE5pQ==
|
integrity sha512-j8z+cQbWIM5LY37pR6uZR6D4LfseplqnuAO4co4u8917hBUvXlEqyP1ZzqVLcqoyUesZZv/ImreoCeHVDpE5pQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
goober "^2.1.10"
|
goober "^2.1.10"
|
||||||
@ -7422,6 +7422,11 @@ snakecase-keys@5.4.4:
|
|||||||
snake-case "^3.0.4"
|
snake-case "^3.0.4"
|
||||||
type-fest "^2.5.2"
|
type-fest "^2.5.2"
|
||||||
|
|
||||||
|
sonner@^1.7.0:
|
||||||
|
version "1.7.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/sonner/-/sonner-1.7.0.tgz#f59a2a70e049a179b6fbd1bb1bf2619d5ced07c0"
|
||||||
|
integrity sha512-W6dH7m5MujEPyug3lpI2l3TC3Pp1+LTgK0Efg+IHDrBbtEjyCmCHHo6yfNBOsf1tFZ6zf+jceWwB38baC8yO9g==
|
||||||
|
|
||||||
source-map-js@^1.0.1, source-map-js@^1.0.2, source-map-js@^1.2.0:
|
source-map-js@^1.0.1, source-map-js@^1.0.2, source-map-js@^1.2.0:
|
||||||
version "1.2.0"
|
version "1.2.0"
|
||||||
resolved "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz"
|
resolved "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz"
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user