mirror of
https://github.com/DeveloLongScript/MHSF.git
synced 2026-05-08 02:04:59 -05:00
push changes to main
push changes to main
This commit is contained in:
commit
7cc8671448
1
.tool-versions
Normal file
1
.tool-versions
Normal file
@ -0,0 +1 @@
|
||||
nodejs 23.3.0
|
||||
@ -20,6 +20,7 @@
|
||||
"@emotion/is-prop-valid": "^1.3.0",
|
||||
"@linear/sdk": "^31.0.0",
|
||||
"@monaco-editor/react": "^4.6.0",
|
||||
"@radix-ui/react-aspect-ratio": "^1.1.1",
|
||||
"@radix-ui/react-avatar": "^1.1.1",
|
||||
"@radix-ui/react-collapsible": "^1.1.1",
|
||||
"@radix-ui/react-hover-card": "^1.1.1",
|
||||
|
||||
@ -32,27 +32,17 @@ import { Analytics } from "@vercel/analytics/react";
|
||||
import { SpeedInsights } from "@vercel/speed-insights/next";
|
||||
import { GeistSans } from "geist/font/sans";
|
||||
import "../globals.css";
|
||||
import ClientFadeIn from "@/components/ClientFadeIn";
|
||||
import { CommandBarer } from "@/components/CommandBar";
|
||||
import { BrandingGenericIcon } from "@/components/Icon";
|
||||
import TextFromPathname from "@/components/TextFromPathname";
|
||||
import { ThemeProvider } from "@/components/ThemeProvider";
|
||||
import { ClerkThemeProvider } from "@/components/clerk/ClerkThemeProvider";
|
||||
import TopBar from "@/components/clerk/Topbar";
|
||||
import NewDomainDialog from "@/components/misc/NewDomainDialog";
|
||||
import ThemedToaster from "@/components/misc/ThemedToaster";
|
||||
import UnofficalDialog from "@/components/misc/UnofficalDialog";
|
||||
import {
|
||||
Breadcrumb,
|
||||
BreadcrumbList,
|
||||
BreadcrumbPage,
|
||||
} from "@/components/ui/breadcrumb";
|
||||
import { TooltipProvider } from "@/components/ui/tooltip";
|
||||
import { banner } from "@/config/banner";
|
||||
import NextTopLoader from "@/lib/top-loader";
|
||||
import type { Metadata, Viewport } from "next";
|
||||
import { Inter as interFont } from "next/font/google";
|
||||
import Link from "next/link";
|
||||
import LayoutPart from "@/components/feat/LayoutPart";
|
||||
import AllBanners from "@/components/feat/AllBanners";
|
||||
|
||||
export const extraMetadata = {
|
||||
twitter: {
|
||||
@ -86,35 +76,8 @@ export default async function RootLayout({
|
||||
<ClerkThemeProvider className={GeistSans.className}>
|
||||
<ThemeProvider attribute="class" defaultTheme="system" enableSystem>
|
||||
<TooltipProvider>
|
||||
{banner.isBanner && (
|
||||
<div className="bg-orange-600 z-10 w-screen h-8 border-b fixed text-black flex items-center text-center font-medium pl-2">
|
||||
{banner.bannerText}
|
||||
</div>
|
||||
)}
|
||||
<div
|
||||
className={
|
||||
"w-screen h-[3rem] border-b fixed backdrop-blur flex z-10 " +
|
||||
(banner.isBanner == true ? "mt-8" : "")
|
||||
}
|
||||
>
|
||||
<div className="items-center me-auto mt-2 pl-7 max-sm:mt-3">
|
||||
<Breadcrumb>
|
||||
<BreadcrumbList>
|
||||
<Link href="/">
|
||||
<BreadcrumbPage className="max-sm:hidden">
|
||||
<BrandingGenericIcon className="max-w-[32px] max-h-[32px] " />
|
||||
</BreadcrumbPage>
|
||||
</Link>
|
||||
<TextFromPathname />
|
||||
</BreadcrumbList>
|
||||
</Breadcrumb>
|
||||
</div>
|
||||
<TopBar inter={inter.className} />
|
||||
</div>
|
||||
<div className={banner.isBanner ? "pt-8" : undefined}>
|
||||
<NextTopLoader />
|
||||
<ClientFadeIn>{children}</ClientFadeIn>
|
||||
</div>{" "}
|
||||
<AllBanners />
|
||||
<LayoutPart>{children}</LayoutPart>
|
||||
<ThemedToaster />
|
||||
<CommandBarer />
|
||||
<SpeedInsights />
|
||||
|
||||
@ -34,7 +34,6 @@ import ColorProvider from "@/components/ColorProvider";
|
||||
import ServerView from "@/components/ServerView";
|
||||
import StickyTopbar from "@/components/misc/StickyTopbar";
|
||||
import TabServer from "@/components/misc/TabServer";
|
||||
import { Separator } from "@/components/ui/separator";
|
||||
import type { Metadata, ResolvingMetadata } from "next";
|
||||
|
||||
type Props = {
|
||||
@ -129,17 +128,17 @@ export async function generateMetadata(
|
||||
|
||||
export default function ServerPage({ params }: { params: { server: string } }) {
|
||||
return (
|
||||
<main>
|
||||
<main style={{ "color-scheme": "dark" } as React.CSSProperties}>
|
||||
<ColorProvider server={params.server}>
|
||||
<div className={"pt-16 xl:px-[100px]"}>
|
||||
<div className={"pt-[300px] xl:px-[100px]"}>
|
||||
<Banner server={params.server} />
|
||||
<div className="pt-8 z-10 relative">
|
||||
<ServerView server={params.server} />
|
||||
</div>
|
||||
|
||||
<StickyTopbar scrollElevation={100} className="pt-4">
|
||||
<TabServer server={params.server} tabDef="general" />
|
||||
</StickyTopbar>
|
||||
<div className="pt-8">
|
||||
<ServerView server={params.server} />
|
||||
</div>
|
||||
<Separator />
|
||||
<br />
|
||||
<AfterServerView server={params.server} />
|
||||
</div>
|
||||
|
||||
@ -35,6 +35,7 @@ import ServerView from "@/components/ServerView";
|
||||
import TabServer from "@/components/misc/TabServer";
|
||||
import { Separator } from "@/components/ui/separator";
|
||||
import type { Metadata, ResolvingMetadata } from "next";
|
||||
import StickyTopbar from "@/components/misc/StickyTopbar";
|
||||
|
||||
type Props = {
|
||||
params: { server: string };
|
||||
@ -96,18 +97,21 @@ export async function generateMetadata(
|
||||
|
||||
export default function ServerPage({ params }: { params: { server: string } }) {
|
||||
return (
|
||||
<main>
|
||||
<main style={{ "color-scheme": "dark" } as React.CSSProperties}>
|
||||
<ColorProvider server={params.server}>
|
||||
<div className={"pt-16 xl:px-[100px]"}>
|
||||
<div className={"pt-[300px] xl:px-[100px]"}>
|
||||
<Banner server={params.server} />
|
||||
<TabServer server={params.server} tabDef="statistics" />
|
||||
<div className="pt-8">
|
||||
<div className="pt-8 z-10 relative">
|
||||
<ServerView server={params.server} />
|
||||
<Separator />
|
||||
<br />
|
||||
<div className="p-4 gap-4">
|
||||
<NewChart server={params.server} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<StickyTopbar scrollElevation={100} className="pt-4">
|
||||
<TabServer server={params.server} tabDef="statistics" />
|
||||
</StickyTopbar>
|
||||
<Separator />
|
||||
<br />
|
||||
<div className="p-4 gap-4">
|
||||
<NewChart server={params.server} />
|
||||
</div>
|
||||
</div>
|
||||
</ColorProvider>
|
||||
|
||||
@ -117,7 +117,7 @@ export default function AfterServerView({ server }: { server: string }) {
|
||||
<QRCodeGenerator server={server} />
|
||||
</DrawerContent>
|
||||
</Drawer>
|
||||
<FadeIn>
|
||||
<FadeIn className="relative z-10">
|
||||
<div className="grid sm:grid-cols-6 h-full pl-4 pr-4 ">
|
||||
<div className="ml-5 mb-2 flex items-center sm:hidden overflow-auto w-[calc(100vw-5rem)]">
|
||||
{(description != "" || discord != "") && (
|
||||
|
||||
@ -31,44 +31,54 @@
|
||||
"use client";
|
||||
import { getCustomization } from "@/lib/api";
|
||||
import { useEffect, useState } from "react";
|
||||
import useTotalBannerSize from "@/lib/hooks/use-total-banner-size";
|
||||
|
||||
export default function Banner({ server }: { server: string }) {
|
||||
const [bannerURL, setBannerURL] = useState("");
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [bannerURL, setBannerURL] = useState("");
|
||||
const [loading, setLoading] = useState(true);
|
||||
const { bannerSize } = useTotalBannerSize();
|
||||
|
||||
useEffect(() => {
|
||||
getCustomization(server).then((c) => {
|
||||
if (c != null) {
|
||||
setLoading(false);
|
||||
setBannerURL(c.banner == undefined ? "" : c.banner);
|
||||
} else {
|
||||
setLoading(false);
|
||||
}
|
||||
});
|
||||
}, [server]);
|
||||
useEffect(() => {
|
||||
getCustomization(server).then((c) => {
|
||||
if (c != null) {
|
||||
setLoading(false);
|
||||
setBannerURL(c.banner == undefined ? "" : c.banner);
|
||||
} else {
|
||||
setLoading(false);
|
||||
}
|
||||
});
|
||||
}, [server]);
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<>
|
||||
<br />
|
||||
</>
|
||||
);
|
||||
}
|
||||
if (loading) {
|
||||
return (
|
||||
<>
|
||||
<br />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{bannerURL != "" && (
|
||||
<img
|
||||
src={
|
||||
bannerURL.startsWith("https://i.imgur.com")
|
||||
? bannerURL
|
||||
: "wsrv.nl/?url=" + encodeURIComponent(bannerURL) + "?n=-1"
|
||||
}
|
||||
className="rounded align-middle block ml-auto mr-auto w-[50%] max-h-[150px]"
|
||||
alt="User-provided banner for this server."
|
||||
/>
|
||||
)}
|
||||
<br />
|
||||
</>
|
||||
);
|
||||
return (
|
||||
<>
|
||||
{bannerURL != "" && (
|
||||
<img
|
||||
src={
|
||||
bannerURL.startsWith("https://i.imgur.com")
|
||||
? bannerURL
|
||||
: "wsrv.nl/?url=" + encodeURIComponent(bannerURL) + "?n=-1"
|
||||
}
|
||||
className="rounded align-middle block ml-auto mr-auto absolute left-0 z-0 w-full object-fill"
|
||||
alt="User-provided banner for this server."
|
||||
style={
|
||||
{
|
||||
"-webkit-mask-image":
|
||||
"linear-gradient(to top, transparent, black)",
|
||||
maskImage: "linear-gradient(to top, transparent, black)",
|
||||
top: `${bannerSize * 32 + 36}px`,
|
||||
} as React.CSSProperties
|
||||
}
|
||||
/>
|
||||
)}
|
||||
<br />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@ -30,7 +30,6 @@
|
||||
|
||||
"use client";
|
||||
import { useState } from "react";
|
||||
import Banner from "./Banner";
|
||||
import ServerCustomize from "./ServerCustomize";
|
||||
import TabServer from "./misc/TabServer";
|
||||
|
||||
@ -42,7 +41,6 @@ export default function CustomizeRoot({
|
||||
const [color, setColor] = useState("");
|
||||
return (
|
||||
<div className={"pt-16 xl:px-[100px] theme-" + color}>
|
||||
<Banner server={params.server} />
|
||||
<TabServer server={params.server} tabDef="customize" />
|
||||
<br />
|
||||
<div className="pl-[40px] pr-[40px]">
|
||||
|
||||
@ -33,6 +33,7 @@
|
||||
import * as React from "react";
|
||||
import { ThemeProvider as NextThemesProvider, useTheme } from "next-themes";
|
||||
import { type ThemeProviderProps } from "next-themes";
|
||||
import { usePathname } from "next/navigation";
|
||||
|
||||
declare global {
|
||||
interface Document {
|
||||
@ -48,6 +49,7 @@ declare global {
|
||||
|
||||
export function ThemeProvider({ children, ...props }: ThemeProviderProps) {
|
||||
const [mounted, setMounted] = React.useState(false);
|
||||
const pathname = usePathname();
|
||||
|
||||
React.useEffect(() => {
|
||||
setMounted(true);
|
||||
@ -55,7 +57,14 @@ export function ThemeProvider({ children, ...props }: ThemeProviderProps) {
|
||||
|
||||
if (!mounted) return null;
|
||||
|
||||
return <NextThemesProvider {...props}>{children}</NextThemesProvider>;
|
||||
return (
|
||||
<NextThemesProvider
|
||||
forcedTheme={pathname?.startsWith("/server") ? "dark" : undefined}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
</NextThemesProvider>
|
||||
);
|
||||
}
|
||||
|
||||
interface UseThemeTransitionResult {
|
||||
|
||||
@ -39,9 +39,11 @@ import {
|
||||
DropdownMenuTrigger,
|
||||
} from "@/components/ui/dropdown-menu";
|
||||
import { useThemeTransition } from "./ThemeProvider";
|
||||
import { usePathname } from "next/navigation";
|
||||
|
||||
export function ModeToggle() {
|
||||
const { changeTheme } = useThemeTransition();
|
||||
const pathname = usePathname();
|
||||
|
||||
return (
|
||||
<DropdownMenu>
|
||||
@ -53,13 +55,28 @@ export function ModeToggle() {
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end">
|
||||
<DropdownMenuItem onClick={() => changeTheme("light")}>
|
||||
{pathname?.startsWith("/server") && (
|
||||
<div className="text-sm p-4">
|
||||
For compatibility reasons, <br /> server pages are forced to dark
|
||||
mode
|
||||
</div>
|
||||
)}
|
||||
<DropdownMenuItem
|
||||
onClick={() => changeTheme("light")}
|
||||
disabled={pathname?.startsWith("/server")}
|
||||
>
|
||||
Light
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onClick={() => changeTheme("dark")}>
|
||||
<DropdownMenuItem
|
||||
onClick={() => changeTheme("dark")}
|
||||
disabled={pathname?.startsWith("/server")}
|
||||
>
|
||||
Dark
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onClick={() => changeTheme("system")}>
|
||||
<DropdownMenuItem
|
||||
onClick={() => changeTheme("system")}
|
||||
disabled={pathname?.startsWith("/server")}
|
||||
>
|
||||
System
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
|
||||
73
src/components/effects/gradient-banner.tsx
Normal file
73
src/components/effects/gradient-banner.tsx
Normal file
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* 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 React, { useEffect, useState } from "react";
|
||||
import { Gradient } from "stripe-gradient";
|
||||
|
||||
export default function GradientBanner({
|
||||
children,
|
||||
}: {
|
||||
children?: React.ReactNode;
|
||||
}) {
|
||||
const [gradientId, setGradientId] = useState("gradient-banner");
|
||||
|
||||
useEffect(() => {
|
||||
setGradientId("gradient-banner");
|
||||
const gradient = new Gradient();
|
||||
gradient.initGradient("#" + gradientId);
|
||||
}, [gradientId]);
|
||||
|
||||
return (
|
||||
<div className="fixed top-0 left-0 backdrop-blur">
|
||||
<canvas
|
||||
id={gradientId}
|
||||
data-js-darken-top
|
||||
className="w-screen blur-sm h-[4rem] border-b z-1"
|
||||
style={
|
||||
{
|
||||
"--gradient-color-1": "#6ec3f4",
|
||||
"--gradient-color-2": "#3a3aff",
|
||||
"--gradient-color-3": "#ff61ab",
|
||||
"--gradient-color-4": "#E63946",
|
||||
webKitMaskImage: "linear-gradient(to top, transparent, black)",
|
||||
maskImage: "linear-gradient(to top, transparent, black)",
|
||||
} as React.CSSProperties
|
||||
}
|
||||
height="64"
|
||||
width={window.screen.width}
|
||||
/>{" "}
|
||||
<div className="fixed top-0 left-0 z-2 p-2 text-left text-black dark:text-white">
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* 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
|
||||
* located here: https://mhsf.app/docs/legal/external-content-agreement
|
||||
*
|
||||
* All code under MHSF is licensed under the MIT License
|
||||
* by open source contributors
|
||||
@ -28,26 +28,16 @@
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import { Button } from "@/components/ui/button";
|
||||
import Link from "next/link";
|
||||
"use client";
|
||||
|
||||
/** used when there is a outage */
|
||||
export const banner = {
|
||||
isBanner:
|
||||
process.env.NEXT_PUBLIC_VERCEL_ENV !== "production"
|
||||
? true
|
||||
: /** Set this to true when outage --->*/ false,
|
||||
bannerText:
|
||||
process.env.NEXT_PUBLIC_VERCEL_ENV !== "production" ? (
|
||||
<>
|
||||
Your not in production!{" "}
|
||||
<Link href="https://list.mlnehut.com">
|
||||
<Button variant="link" className="dark:text-black">
|
||||
Go to production
|
||||
</Button>
|
||||
</Link>
|
||||
</>
|
||||
) : (
|
||||
<>{/** Set this to an explanation! */}</>
|
||||
),
|
||||
};
|
||||
import { useBanners } from "@/lib/hooks/use-banners";
|
||||
|
||||
export default function AllBanners() {
|
||||
const { banners } = useBanners();
|
||||
|
||||
return (
|
||||
<div className="fixed grid grid-cols-1 z-10">
|
||||
{banners.map((banner) => banner.bannerContent)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
51
src/components/feat/BannerContainer.tsx
Normal file
51
src/components/feat/BannerContainer.tsx
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* 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 useTotalBannerSize from "@/lib/hooks/use-total-banner-size";
|
||||
|
||||
export default function BannerContainer({
|
||||
children,
|
||||
className,
|
||||
style,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
className?: string;
|
||||
style: (size: number) => React.CSSProperties;
|
||||
}) {
|
||||
const { bannerSize } = useTotalBannerSize();
|
||||
|
||||
return (
|
||||
<div className={className} style={style(bannerSize)}>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
55
src/components/feat/LayoutPart.tsx
Normal file
55
src/components/feat/LayoutPart.tsx
Normal file
@ -0,0 +1,55 @@
|
||||
"use client";
|
||||
|
||||
import ClientFadeIn from "@/components/ClientFadeIn";
|
||||
import { BrandingGenericIcon } from "@/components/Icon";
|
||||
import TextFromPathname from "@/components/TextFromPathname";
|
||||
import TopBar from "@/components/clerk/Topbar";
|
||||
import {
|
||||
Breadcrumb,
|
||||
BreadcrumbList,
|
||||
BreadcrumbPage,
|
||||
} from "@/components/ui/breadcrumb";
|
||||
import NextTopLoader from "@/lib/top-loader";
|
||||
import Link from "next/link";
|
||||
import BannerContainer from "@/components/feat/BannerContainer";
|
||||
import { Inter } from "next/font/google";
|
||||
|
||||
const inter = Inter({ variable: "--font-inter", subsets: ["latin"] });
|
||||
export default function LayoutPart({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
}) {
|
||||
return (
|
||||
<>
|
||||
<BannerContainer
|
||||
className={"w-screen h-[3rem] border-b fixed backdrop-blur flex z-10"}
|
||||
style={(size: number) => ({
|
||||
marginTop: `${2 * size}rem`,
|
||||
})}
|
||||
>
|
||||
<div className="items-center me-auto mt-2 pl-7 max-sm:mt-3">
|
||||
<Breadcrumb>
|
||||
<BreadcrumbList>
|
||||
<Link href="/">
|
||||
<BreadcrumbPage className="max-sm:hidden">
|
||||
<BrandingGenericIcon className="max-w-[32px] max-h-[32px] " />
|
||||
</BreadcrumbPage>
|
||||
</Link>
|
||||
<TextFromPathname />
|
||||
</BreadcrumbList>
|
||||
</Breadcrumb>
|
||||
</div>
|
||||
<TopBar inter={inter.className} />
|
||||
</BannerContainer>
|
||||
<BannerContainer
|
||||
style={(size: number) => ({
|
||||
paddingTop: `${2 * size}rem`,
|
||||
})}
|
||||
>
|
||||
<NextTopLoader />
|
||||
<ClientFadeIn>{children}</ClientFadeIn>
|
||||
</BannerContainer>
|
||||
</>
|
||||
);
|
||||
}
|
||||
50
src/components/feat/MainBanner.tsx
Normal file
50
src/components/feat/MainBanner.tsx
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export default function MainBanner({
|
||||
className,
|
||||
size = 1,
|
||||
children,
|
||||
}: {
|
||||
className?: string;
|
||||
size?: number;
|
||||
children?: React.ReactNode;
|
||||
}) {
|
||||
return (
|
||||
<div
|
||||
className={`w-screen border-b text-black flex items-center text-center font-medium pl-2 ${className}`}
|
||||
style={{
|
||||
height: `${size * 2}rem`,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
29
src/components/misc/AffilatePopup.tsx
Normal file
29
src/components/misc/AffilatePopup.tsx
Normal file
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* MHSF, Minehut Server List
|
||||
* All external content is rather licensed under the ECA Agreement
|
||||
* located here: https://mhsf.app/docs/legal/external-content-agreement
|
||||
*
|
||||
* All code under MHSF is licensed under the MIT License
|
||||
* by open source contributors
|
||||
*
|
||||
* Copyright (c) 2024 dvelo
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
@ -29,8 +29,7 @@
|
||||
*/
|
||||
|
||||
"use client";
|
||||
|
||||
import { banner } from "@/config/banner";
|
||||
import useTotalBannerSize from "@/lib/hooks/use-total-banner-size";
|
||||
import { useEffect, useState, ReactNode } from "react";
|
||||
|
||||
export default function StickyTopbar({
|
||||
@ -43,6 +42,7 @@ export default function StickyTopbar({
|
||||
className?: string;
|
||||
}) {
|
||||
const [isSticky, setIsSticky] = useState(false);
|
||||
const { bannerSize } = useTotalBannerSize();
|
||||
|
||||
const handleScroll = () => {
|
||||
if (window.scrollY > scrollElevation) {
|
||||
@ -61,7 +61,10 @@ export default function StickyTopbar({
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`transition-all duration-300 ${isSticky ? "fixed left-0 w-full backdrop-blur shadow-lg " + (banner.isBanner == true ? "top-[70px] " : "top-[38px] ") + className : "block w-full bg-transparent"}`}
|
||||
className={`transition-all duration-300 ${isSticky ? "fixed left-0 w-full backdrop-blur shadow-lg " + className : "block w-full bg-transparent"}`}
|
||||
style={{
|
||||
top: isSticky ? `${bannerSize * 32 + 38}px` : undefined,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
|
||||
7
src/components/ui/aspect-ratio.tsx
Normal file
7
src/components/ui/aspect-ratio.tsx
Normal file
@ -0,0 +1,7 @@
|
||||
"use client"
|
||||
|
||||
import * as AspectRatioPrimitive from "@radix-ui/react-aspect-ratio"
|
||||
|
||||
const AspectRatio = AspectRatioPrimitive.Root
|
||||
|
||||
export { AspectRatio }
|
||||
17
src/components/ui/discord.tsx
Normal file
17
src/components/ui/discord.tsx
Normal file
@ -0,0 +1,17 @@
|
||||
import type { SVGProps } from "react";
|
||||
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>
|
||||
);
|
||||
export default Discord;
|
||||
15
src/components/ui/github.tsx
Normal file
15
src/components/ui/github.tsx
Normal file
@ -0,0 +1,15 @@
|
||||
import type { SVGProps } from "react";
|
||||
const Github = (props: SVGProps<SVGSVGElement>) => (
|
||||
<svg
|
||||
viewBox="0 0 256 250"
|
||||
width="1em"
|
||||
height="1em"
|
||||
fill="#fff"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
preserveAspectRatio="xMidYMid"
|
||||
{...props}
|
||||
>
|
||||
<path d="M128.001 0C57.317 0 0 57.307 0 128.001c0 56.554 36.676 104.535 87.535 121.46 6.397 1.185 8.746-2.777 8.746-6.158 0-3.052-.12-13.135-.174-23.83-35.61 7.742-43.124-15.103-43.124-15.103-5.823-14.795-14.213-18.73-14.213-18.73-11.613-7.944.876-7.78.876-7.78 12.853.902 19.621 13.19 19.621 13.19 11.417 19.568 29.945 13.911 37.249 10.64 1.149-8.272 4.466-13.92 8.127-17.116-28.431-3.236-58.318-14.212-58.318-63.258 0-13.975 5-25.394 13.188-34.358-1.329-3.224-5.71-16.242 1.24-33.874 0 0 10.749-3.44 35.21 13.121 10.21-2.836 21.16-4.258 32.038-4.307 10.878.049 21.837 1.47 32.066 4.307 24.431-16.56 35.165-13.12 35.165-13.12 6.967 17.63 2.584 30.65 1.255 33.873 8.207 8.964 13.173 20.383 13.173 34.358 0 49.163-29.944 59.988-58.447 63.157 4.591 3.972 8.682 11.762 8.682 23.704 0 17.126-.148 30.91-.148 35.126 0 3.407 2.304 7.398 8.792 6.14C219.37 232.5 256 184.537 256 128.002 256 57.307 198.691 0 128.001 0Zm-80.06 182.34c-.282.636-1.283.827-2.194.39-.929-.417-1.45-1.284-1.15-1.922.276-.655 1.279-.838 2.205-.399.93.418 1.46 1.293 1.139 1.931Zm6.296 5.618c-.61.566-1.804.303-2.614-.591-.837-.892-.994-2.086-.375-2.66.63-.566 1.787-.301 2.626.591.838.903 1 2.088.363 2.66Zm4.32 7.188c-.785.545-2.067.034-2.86-1.104-.784-1.138-.784-2.503.017-3.05.795-.547 2.058-.055 2.861 1.075.782 1.157.782 2.522-.019 3.08Zm7.304 8.325c-.701.774-2.196.566-3.29-.49-1.119-1.032-1.43-2.496-.726-3.27.71-.776 2.213-.558 3.315.49 1.11 1.03 1.45 2.505.701 3.27Zm9.442 2.81c-.31 1.003-1.75 1.459-3.199 1.033-1.448-.439-2.395-1.613-2.103-2.626.301-1.01 1.747-1.484 3.207-1.028 1.446.436 2.396 1.602 2.095 2.622Zm10.744 1.193c.036 1.055-1.193 1.93-2.715 1.95-1.53.034-2.769-.82-2.786-1.86 0-1.065 1.202-1.932 2.733-1.958 1.522-.03 2.768.818 2.768 1.868Zm10.555-.405c.182 1.03-.875 2.088-2.387 2.37-1.485.271-2.861-.365-3.05-1.386-.184-1.056.893-2.114 2.376-2.387 1.514-.263 2.868.356 3.061 1.403Z" />
|
||||
</svg>
|
||||
);
|
||||
export default Github;
|
||||
41
src/config/banners.tsx
Normal file
41
src/config/banners.tsx
Normal file
@ -0,0 +1,41 @@
|
||||
export const defaultBanners: {
|
||||
bannerSpace: number;
|
||||
bannerContent: React.ReactNode;
|
||||
}[] = [
|
||||
// The sponsor banner ALWAYS has to be first.
|
||||
// {
|
||||
// bannerSpace: 2,
|
||||
// bannerContent: (
|
||||
// <MainBanner size={2} className="max-h-[4rem] border-0">
|
||||
// {" "}
|
||||
// <GradientBanner>
|
||||
// <strong>???</strong> — <i>an official affiliate of MHSF</i>{" "}
|
||||
// <br />
|
||||
// Lorem ipsum odor amet, consectetuer adipiscing elit. — check it out
|
||||
// </GradientBanner>
|
||||
// </MainBanner>
|
||||
// ),
|
||||
// },
|
||||
];
|
||||
|
||||
export const bannerHooks: (() =>
|
||||
| { bannerSpace: number; bannerContent: React.ReactNode }
|
||||
| undefined)[] = [
|
||||
() => {
|
||||
// if (process.env.NEXT_PUBLIC_VERCEL_ENV !== "production")
|
||||
// return {
|
||||
// bannerSpace: 1,
|
||||
// bannerContent: (
|
||||
// <MainBanner className="bg-orange-600">
|
||||
// Your not in production!{" "}
|
||||
// <Link href="https://mhsf.app">
|
||||
// <Button variant="link" className="dark:text-black">
|
||||
// Go to production
|
||||
// </Button>
|
||||
// </Link>
|
||||
// </MainBanner>
|
||||
// ),
|
||||
// };
|
||||
return undefined;
|
||||
},
|
||||
];
|
||||
@ -29,61 +29,60 @@
|
||||
*/
|
||||
|
||||
export const allFolders: DocsFolder[] = [
|
||||
{
|
||||
name: "General",
|
||||
docs: [
|
||||
{
|
||||
title: "Getting Started",
|
||||
url: "/docs/getting-started",
|
||||
},
|
||||
{
|
||||
title: "Reading",
|
||||
url: "/docs/reading",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Guides",
|
||||
docs: [
|
||||
{
|
||||
title: "Linking",
|
||||
url: "/docs/guides/linking",
|
||||
},
|
||||
{
|
||||
title: "Owning a Server",
|
||||
url: "/docs/guides/owning-a-server",
|
||||
},
|
||||
{
|
||||
title: "Server Customization",
|
||||
url: "/docs/guides/customization",
|
||||
},
|
||||
{ title: "Reporting a server", url: "/docs/guides/reporting-server" },
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Advanced",
|
||||
docs: [
|
||||
{ title: "Tech Stack", url: "/docs/advanced/tech-stack" },
|
||||
{ title: "Using the Command-bar", url: "/docs/advanced/command-bar" },
|
||||
{ title: "Tips with external servers", url: "/docs/advanced/external" },
|
||||
{ title: "Achievements", url: "/docs/advanced/achievements" },
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Legal",
|
||||
docs: [
|
||||
{ title: "ECA Agreement", url: "/docs/legal/external-content-agreement" },
|
||||
{ title: "Email List", url: "/docs/legal/email-list" },
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "General",
|
||||
docs: [
|
||||
{
|
||||
title: "Getting Started",
|
||||
url: "/docs/getting-started",
|
||||
},
|
||||
{
|
||||
title: "Reading",
|
||||
url: "/docs/reading",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Guides",
|
||||
docs: [
|
||||
{
|
||||
title: "Linking",
|
||||
url: "/docs/guides/linking",
|
||||
},
|
||||
{
|
||||
title: "Owning a Server",
|
||||
url: "/docs/guides/owning-a-server",
|
||||
},
|
||||
{
|
||||
title: "Server Customization",
|
||||
url: "/docs/guides/customization",
|
||||
},
|
||||
{ title: "Reporting a server", url: "/docs/guides/reporting-server" },
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Advanced",
|
||||
docs: [
|
||||
{ title: "Tech Stack", url: "/docs/advanced/tech-stack" },
|
||||
{ title: "Using the Command-bar", url: "/docs/advanced/command-bar" },
|
||||
{ title: "Tips with external servers", url: "/docs/advanced/external" },
|
||||
{ title: "Achievements", url: "/docs/advanced/achievements" },
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Legal",
|
||||
docs: [
|
||||
{ title: "ECA Agreement", url: "/docs/legal/external-content-agreement" },
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
export type Docs = {
|
||||
title: string;
|
||||
url: string;
|
||||
title: string;
|
||||
url: string;
|
||||
};
|
||||
|
||||
export type DocsFolder = {
|
||||
name: string;
|
||||
docs: Array<Docs>;
|
||||
name: string;
|
||||
docs: Array<Docs>;
|
||||
};
|
||||
|
||||
@ -65,7 +65,7 @@ export const changelog: { name: string; id: string; changelog: ReactNode }[] = [
|
||||
features={[
|
||||
"New MOTD engine that is over 3,000% faster, runs client-side, and doesn't need any requests to run.",
|
||||
"Fixed issue where GitHub link was broken if you were signed-out",
|
||||
"",
|
||||
"Adding snowfall finally (better late then ever)",
|
||||
]}
|
||||
title={
|
||||
<strong className="flex items-center">
|
||||
|
||||
@ -62,13 +62,17 @@ async function apiConstructor<K>(
|
||||
export async function getMOTDFromServer(
|
||||
list: Array<{ server: string; motd: string }>,
|
||||
): Promise<Array<{ server: string; motd: string }>> {
|
||||
const result = await fetch(connector("/motd", { version: 1 }), {
|
||||
body: JSON.stringify({ motd: list }),
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
const result = await fetch(
|
||||
process.env.NEXT_PUBLIC_ALTERNATE_MOTD_ENDPOINT ??
|
||||
connector("/motd", { version: 1 }),
|
||||
{
|
||||
body: JSON.stringify({ motd: list }),
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
},
|
||||
});
|
||||
);
|
||||
|
||||
let json = await result.json();
|
||||
return json.result;
|
||||
|
||||
57
src/lib/hooks/use-banners.tsx
Normal file
57
src/lib/hooks/use-banners.tsx
Normal file
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* 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 { bannerHooks, defaultBanners } from "@/config/banners";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useIsMobile } from "./use-mobile";
|
||||
|
||||
export function useBanners() {
|
||||
const [banners, setBanners] = useState<
|
||||
{
|
||||
bannerSpace: number;
|
||||
bannerContent: React.ReactNode;
|
||||
}[]
|
||||
>(defaultBanners);
|
||||
const isOnMobile = useIsMobile();
|
||||
|
||||
useEffect(() => {
|
||||
if (isOnMobile) {
|
||||
setBanners([]);
|
||||
return;
|
||||
}
|
||||
setBanners(defaultBanners);
|
||||
bannerHooks.forEach((hook) => {
|
||||
const run = hook();
|
||||
if (run !== undefined) setBanners((oldBanners) => [...oldBanners, run]);
|
||||
});
|
||||
}, [isOnMobile]);
|
||||
|
||||
return { banners };
|
||||
}
|
||||
61
src/lib/hooks/use-total-banner-size.tsx
Normal file
61
src/lib/hooks/use-total-banner-size.tsx
Normal file
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* 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 { bannerHooks, defaultBanners } from "@/config/banners";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useIsMobile } from "./use-mobile";
|
||||
|
||||
export default function useTotalBannerSize() {
|
||||
const [bannerSize, setBannerSize] = useState(0);
|
||||
const isOnMobile = useIsMobile();
|
||||
|
||||
useEffect(() => {
|
||||
setBannerSize(0);
|
||||
if (isOnMobile) return;
|
||||
const allBanners = [];
|
||||
|
||||
// First push the default banners
|
||||
allBanners.push(...defaultBanners);
|
||||
|
||||
// Then push the banner hooks
|
||||
bannerHooks.forEach((hook) => {
|
||||
allBanners.push(hook());
|
||||
});
|
||||
|
||||
setBannerSize(
|
||||
allBanners.reduce(
|
||||
(acc, banner) => acc + (banner ?? { bannerSpace: 0 }).bannerSpace,
|
||||
0
|
||||
) ?? 0
|
||||
);
|
||||
}, [isOnMobile]);
|
||||
|
||||
return { bannerSize };
|
||||
}
|
||||
5
src/lib/types/stripe-gradient.d.ts
vendored
Normal file
5
src/lib/types/stripe-gradient.d.ts
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
declare module "stripe-gradient" {
|
||||
declare class Gradient {
|
||||
initGradient(id: string): void;
|
||||
};
|
||||
}
|
||||
@ -1178,6 +1178,13 @@
|
||||
dependencies:
|
||||
"@radix-ui/react-primitive" "2.0.0"
|
||||
|
||||
"@radix-ui/react-aspect-ratio@^1.1.1":
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-aspect-ratio/-/react-aspect-ratio-1.1.1.tgz#95d7692e61bab5eb7fec91f241ea993899593313"
|
||||
integrity sha512-kNU4FIpcFMBLkOUcgeIteH06/8JLBcYY6Le1iKenDGCYNYFX3TQqCZjzkOsz37h7r94/99GTb7YhEr98ZBJibw==
|
||||
dependencies:
|
||||
"@radix-ui/react-primitive" "2.0.1"
|
||||
|
||||
"@radix-ui/react-avatar@^1.1.1":
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-avatar/-/react-avatar-1.1.1.tgz#5848d2ed5f34d18b36fc7e2d227c41fca8600ea1"
|
||||
|
||||
Loading…
Reference in New Issue
Block a user