Compare commits

..

No commits in common. "5478276fd783a6a167b4e54db89a4e9d2584448e" and "335ac6d31cf7eae4f9d7e9f4fb5234c3d3468b76" have entirely different histories.

11 changed files with 175 additions and 431 deletions

@ -24,7 +24,6 @@
"@radix-ui/react-aspect-ratio": "1.1.1", "@radix-ui/react-aspect-ratio": "1.1.1",
"@radix-ui/react-avatar": "1.1.1", "@radix-ui/react-avatar": "1.1.1",
"@radix-ui/react-collapsible": "1.1.1", "@radix-ui/react-collapsible": "1.1.1",
"@radix-ui/react-context-menu": "^2.2.6",
"@radix-ui/react-hover-card": "1.1.1", "@radix-ui/react-hover-card": "1.1.1",
"@radix-ui/react-icons": "1.3.0", "@radix-ui/react-icons": "1.3.0",
"@radix-ui/react-menubar": "1.1.1", "@radix-ui/react-menubar": "1.1.1",

@ -40,7 +40,6 @@ import { ClerkProvider } from "@clerk/nextjs";
import Link from "next/link"; import Link from "next/link";
import { NavBar } from "@/components/feat/navbar/navbar"; import { NavBar } from "@/components/feat/navbar/navbar";
import { TooltipProvider } from "@/components/ui/tooltip"; import { TooltipProvider } from "@/components/ui/tooltip";
import { ThemeProvider } from "@/components/util/theme-provider";
const inter = Inter({ subsets: ["latin"] }); const inter = Inter({ subsets: ["latin"] });
@ -71,15 +70,8 @@ export default function RootLayout({
</main> </main>
</noscript> </noscript>
<IsScript> <IsScript>
<ThemeProvider <NavBar />
attribute="class" <div className="pt-16">{children}</div>
defaultTheme="system"
enableSystem
disableTransitionOnChange
>
<NavBar />
<div className="pt-16">{children}</div>
</ThemeProvider>
</IsScript> </IsScript>
</TooltipProvider> </TooltipProvider>
</body> </body>

@ -1,19 +1,8 @@
"use client"; "use client";
import { BrandingGenericIcon } from "@/components/feat/icons/branding-icons"; import { BrandingGenericIcon } from "@/components/feat/icons/branding-icons";
import {
ContextMenu,
ContextMenuContent,
ContextMenuItem,
ContextMenuSeparator,
ContextMenuTrigger,
} from "@/components/ui/context-menu";
import Github from "@/components/ui/github";
import { ALegacy } from "@/components/util/link";
import { ModeToggle } from "@/components/util/mode-toggle";
import { version } from "@/config/version"; import { version } from "@/config/version";
import { useScroll } from "@/lib/hooks/use-scroll"; import { useScroll } from "@/lib/hooks/use-scroll";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
import { ServerCrash } from "lucide-react";
import Link from "next/link"; import Link from "next/link";
export function NavBar() { export function NavBar() {
@ -23,45 +12,19 @@ export function NavBar() {
<div <div
className={cn( className={cn(
"w-screen h-[3rem] grid-cols-3 fixed backdrop-blur-xl z-10 flex", "w-screen h-[3rem] grid-cols-3 fixed backdrop-blur-xl z-10 flex",
"items-center justify-self-start me-auto pl-4 flex-1 transition-all justify-between", "items-center justify-self-start me-auto pl-4 flex-1 transition-all",
showBorder ? "border-b" : "" showBorder ? "border-b" : ""
)} )}
> >
<span> <Link className="gap-5 flex items-center " href="/">
<ContextMenu> <BrandingGenericIcon className="max-w-[32px] max-h-[32px] mt-0.5" />
<ContextMenuTrigger> <span className="gap-2 flex group hover:text-blue-500 hover:underline transition-all">
<Link className="gap-5 flex items-center " href="/"> <strong className="">MHSF</strong>
<BrandingGenericIcon className="max-w-[32px] max-h-[32px] mt-0.5" /> <span className="text-muted-foreground group-hover:text-blue-500 transition-all">
<span className="gap-2 flex group hover:text-blue-500 hover:underline transition-all"> v{version}
<strong className="">MHSF</strong> </span>
<span className="text-muted-foreground group-hover:text-blue-500 transition-all"> </span>
v{version} </Link>
</span>
</span>
</Link>
</ContextMenuTrigger>
<ContextMenuContent className="overflow-hidden min-w-[300px]">
<ALegacy href="Special:Root">
<ContextMenuItem>
<span className="pl-2 flex gap-2 items-center">
<ServerCrash size={16} /> Go home
</span>
</ContextMenuItem>
</ALegacy>
<ContextMenuSeparator />
<ALegacy href="Special:GitHub">
<ContextMenuItem>
<span className="pl-2 flex gap-2 items-center">
<Github /> Open GitHub
</span>
</ContextMenuItem>
</ALegacy>
</ContextMenuContent>
</ContextMenu>
</span>
<span className="mr-3">
<ModeToggle />
</span>
</div> </div>
); );
} }

@ -6,10 +6,9 @@ import {
TooltipTrigger, TooltipTrigger,
} from "@/components/ui/tooltip"; } from "@/components/ui/tooltip";
import type { OnlineServer } from "@/lib/types/mh-server"; import type { OnlineServer } from "@/lib/types/mh-server";
import { ChartArea, HardDriveUpload, InfoIcon, Users } from "lucide-react"; import { InfoIcon } from "lucide-react";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { motion, AnimatePresence } from "framer-motion"; import { motion, AnimatePresence } from "framer-motion";
import IconDisplay from "../icons/minecraft-icon-display";
export function Statistics({ export function Statistics({
totalPlayers, totalPlayers,
@ -50,32 +49,29 @@ export function Statistics({
return ( return (
<div className="grid grid-cols-3 gap-2"> <div className="grid grid-cols-3 gap-2">
<Material className="gap-3"> <Material className="gap-2">
<strong className="justify-between flex items-center"> <strong className="flex items-center gap-1">
<span className="flex items-center gap-1"> Total Players
Total Players <Tooltip>
<Tooltip> <TooltipTrigger>
<TooltipTrigger> <InfoIcon size={14} />
<InfoIcon size={14} /> </TooltipTrigger>
</TooltipTrigger> <TooltipContent>
<TooltipContent> For players, the first number represents the current amount of
For players, the first number represents the current amount of <br />
<br /> players, while the second one represents the average of the last
players, while the second one represents the average of the last <br />
<br /> 100 entries of players.
100 entries of players. </TooltipContent>
</TooltipContent> </Tooltip>
</Tooltip>
</span>
<Users size={16} className="text-muted-foreground" />
</strong> </strong>
<span className="text-lg flex items-center gap-1"> <span className="text-lg flex items-center gap-1">
<span <span
className={ className={
!averagesLoading && !error !averagesLoading && !error
? (averages?.totalPlayerAverage as number) > totalPlayers ? (averages?.totalPlayerAverage as number) > totalPlayers
? "text-rose-400" ? "text-red-400"
: "text-lime-400" : "text-green-400"
: "" : ""
} }
> >
@ -96,40 +92,29 @@ export function Statistics({
{averagesLoading && <FormSpinner />} {averagesLoading && <FormSpinner />}
</span> </span>
</Material> </Material>
<Material className="gap-3"> <Material className="gap-2">
<strong className="justify-between flex items-center"> <strong className="flex items-center gap-1">
<span className="flex items-center gap-1"> Total Servers
Total Servers <Tooltip>
<Tooltip> <TooltipTrigger>
<TooltipTrigger> <InfoIcon size={14} />
<InfoIcon size={14} /> </TooltipTrigger>
</TooltipTrigger> <TooltipContent>
<TooltipContent className="max-w-[390px] break-words"> For servers, the first number represents the current amount of
<p> <br />
For servers, the first number represents the current amount of servers, while the second one represents the average of the last
servers, while the second one represents the average of the <br />
last 100 entries of servers. 100 entries of servers.
</p> </TooltipContent>
<p className="mt-1"> </Tooltip>
Minehut automatically puts new servers in a queue once the
queue for the server plan (1,800 paid & 1,380 free = 3,180
total) is hit for efficiency & economical reasons. This
usually happens during high demand times, most likely during
the American summer, in the afternoon.
</p>
</TooltipContent>
</Tooltip>
</span>
<HardDriveUpload size={16} className="text-muted-foreground" />
</strong> </strong>
<span className="text-lg flex items-center gap-1"> <span className="text-lg flex items-center gap-1">
<span <span
className={ className={
!averagesLoading && !error !averagesLoading && !error
? (averages?.totalServerAverage as number) > totalServers ? (averages?.totalServerAverage as number) > totalServers
? "text-rose-400" ? "text-red-400"
: "text-lime-400" : "text-green-400"
: "" : ""
} }
> >
@ -150,14 +135,9 @@ export function Statistics({
{averagesLoading && <FormSpinner />} {averagesLoading && <FormSpinner />}
</span> </span>
</Material> </Material>
<Material className="gap-3"> <Material className="gap-2">
<strong className="justify-between flex items-center"> <strong>Top Server</strong> <br />
Top Server <ChartArea size={16} className="text-muted-foreground" /> <span className="text-lg"> {topServer.name}</span>
</strong>{" "}
<span className="text-lg gap-2 flex items-center">
{topServer.name}
<IconDisplay server={topServer} />
</span>
</Material> </Material>
</div> </div>
); );

@ -1,215 +0,0 @@
"use client";
import * as React from "react";
import * as ContextMenuPrimitive from "@radix-ui/react-context-menu";
import { Check, ChevronRight, Circle } from "lucide-react";
import { cn } from "@/lib/utils";
import { Material } from "./material";
const ContextMenu = ContextMenuPrimitive.Root;
const ContextMenuTrigger = ContextMenuPrimitive.Trigger;
const ContextMenuGroup = ContextMenuPrimitive.Group;
const ContextMenuPortal = ContextMenuPrimitive.Portal;
const ContextMenuSub = ContextMenuPrimitive.Sub;
const ContextMenuRadioGroup = ContextMenuPrimitive.RadioGroup;
const ContextMenuSubTrigger = React.forwardRef<
React.ElementRef<typeof ContextMenuPrimitive.SubTrigger>,
React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.SubTrigger> & {
inset?: boolean;
}
>(({ className, inset, children, ...props }, ref) => (
<ContextMenuPrimitive.SubTrigger
ref={ref}
className={cn(
"flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground",
inset && "pl-8",
className
)}
{...props}
>
{children}
<ChevronRight className="ml-auto h-4 w-4" />
</ContextMenuPrimitive.SubTrigger>
));
ContextMenuSubTrigger.displayName = ContextMenuPrimitive.SubTrigger.displayName;
const ContextMenuSubContent = React.forwardRef<
React.ElementRef<typeof ContextMenuPrimitive.SubContent>,
React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.SubContent>
>(({ className, ...props }, ref) => (
<ContextMenuPrimitive.SubContent
ref={ref}
className={cn(
"z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
className
)}
{...props}
/>
));
ContextMenuSubContent.displayName = ContextMenuPrimitive.SubContent.displayName;
const ContextMenuContent = React.forwardRef<
React.ElementRef<typeof ContextMenuPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Content>
>(({ className, ...props }, ref) => (
<ContextMenuPrimitive.Portal>
<ContextMenuPrimitive.Content
ref={ref}
className={cn(
"backdrop-blur-xl w-max max-w-[280px] z-[100] origin-top-left max-h-[32rem] overflow-auto list-none shadow-xl rounded-xl",
className
)}
data-align="end"
data-side="left"
{...props}
>
<div className="animate-scale-in">
<Material
className="flex flex-col py-2 list-none bg-white/80 dark:bg-zinc-900/80 px-2"
color="distinct"
padding="none"
rounding="xl"
>
{props.children}
</Material>
</div>
</ContextMenuPrimitive.Content>
</ContextMenuPrimitive.Portal>
));
ContextMenuContent.displayName = ContextMenuPrimitive.Content.displayName;
const ContextMenuItem = React.forwardRef<
React.ElementRef<typeof ContextMenuPrimitive.Item>,
React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Item> & {
inset?: boolean;
}
>(({ className, inset, ...props }, ref) => (
<ContextMenuPrimitive.Item
ref={ref}
className={cn(
"w-full px-2 rounded-lg z-[100] min-h-[36px] font-normal flex items-center cursor-pointer hover:dark:bg-zinc-800/70",
props.disabled ? "opacity-70 pointer-events-none cursor-not-allowed" : "",
"duration-100 border border-transparent bg-transparent hover:bg-slate-100 dark:text-zinc-200",
className
)}
{...props}
/>
));
ContextMenuItem.displayName = ContextMenuPrimitive.Item.displayName;
const ContextMenuCheckboxItem = React.forwardRef<
React.ElementRef<typeof ContextMenuPrimitive.CheckboxItem>,
React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.CheckboxItem>
>(({ className, children, checked, ...props }, ref) => (
<ContextMenuPrimitive.CheckboxItem
ref={ref}
className={cn(
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
className
)}
checked={checked}
{...props}
>
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
<ContextMenuPrimitive.ItemIndicator>
<Check className="h-4 w-4" />
</ContextMenuPrimitive.ItemIndicator>
</span>
{children}
</ContextMenuPrimitive.CheckboxItem>
));
ContextMenuCheckboxItem.displayName =
ContextMenuPrimitive.CheckboxItem.displayName;
const ContextMenuRadioItem = React.forwardRef<
React.ElementRef<typeof ContextMenuPrimitive.RadioItem>,
React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.RadioItem>
>(({ className, children, ...props }, ref) => (
<ContextMenuPrimitive.RadioItem
ref={ref}
className={cn(
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
className
)}
{...props}
>
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
<ContextMenuPrimitive.ItemIndicator>
<Circle className="h-4 w-4 fill-current" />
</ContextMenuPrimitive.ItemIndicator>
</span>
{children}
</ContextMenuPrimitive.RadioItem>
));
ContextMenuRadioItem.displayName = ContextMenuPrimitive.RadioItem.displayName;
const ContextMenuLabel = React.forwardRef<
React.ElementRef<typeof ContextMenuPrimitive.Label>,
React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Label> & {
inset?: boolean;
}
>(({ className, inset, ...props }, ref) => (
<ContextMenuPrimitive.Label
ref={ref}
className={cn(
"px-2 py-1.5 text-sm font-semibold text-foreground",
inset && "pl-8",
className
)}
{...props}
/>
));
ContextMenuLabel.displayName = ContextMenuPrimitive.Label.displayName;
const ContextMenuSeparator = React.forwardRef<
React.ElementRef<typeof ContextMenuPrimitive.Separator>,
React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Separator>
>(({ className, ...props }, ref) => (
<ContextMenuPrimitive.Separator
ref={ref}
className={cn("-mx-1 my-1 h-px ", className)}
{...props}
/>
));
ContextMenuSeparator.displayName = ContextMenuPrimitive.Separator.displayName;
const ContextMenuShortcut = ({
className,
...props
}: React.HTMLAttributes<HTMLSpanElement>) => {
return (
<span
className={cn(
"ml-auto text-xs tracking-widest text-muted-foreground",
className
)}
{...props}
/>
);
};
ContextMenuShortcut.displayName = "ContextMenuShortcut";
export {
ContextMenu,
ContextMenuTrigger,
ContextMenuContent,
ContextMenuItem,
ContextMenuCheckboxItem,
ContextMenuRadioItem,
ContextMenuLabel,
ContextMenuSeparator,
ContextMenuShortcut,
ContextMenuGroup,
ContextMenuPortal,
ContextMenuSub,
ContextMenuSubContent,
ContextMenuSubTrigger,
ContextMenuRadioGroup,
};

@ -1,28 +1,27 @@
"use client"; "use client"
import * as React from "react"; import * as React from "react"
import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu"; import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu"
import { Check, ChevronRight, Circle } from "lucide-react"; import { Check, ChevronRight, Circle } from "lucide-react"
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils"
import { Material } from "./material";
const DropdownMenu = DropdownMenuPrimitive.Root; const DropdownMenu = DropdownMenuPrimitive.Root
const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger; const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger
const DropdownMenuGroup = DropdownMenuPrimitive.Group; const DropdownMenuGroup = DropdownMenuPrimitive.Group
const DropdownMenuPortal = DropdownMenuPrimitive.Portal; const DropdownMenuPortal = DropdownMenuPrimitive.Portal
const DropdownMenuSub = DropdownMenuPrimitive.Sub; const DropdownMenuSub = DropdownMenuPrimitive.Sub
const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup; const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup
const DropdownMenuSubTrigger = React.forwardRef< const DropdownMenuSubTrigger = React.forwardRef<
React.ElementRef<typeof DropdownMenuPrimitive.SubTrigger>, React.ElementRef<typeof DropdownMenuPrimitive.SubTrigger>,
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubTrigger> & { React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubTrigger> & {
inset?: boolean; inset?: boolean
} }
>(({ className, inset, children, ...props }, ref) => ( >(({ className, inset, children, ...props }, ref) => (
<DropdownMenuPrimitive.SubTrigger <DropdownMenuPrimitive.SubTrigger
@ -37,9 +36,9 @@ const DropdownMenuSubTrigger = React.forwardRef<
{children} {children}
<ChevronRight className="ml-auto" /> <ChevronRight className="ml-auto" />
</DropdownMenuPrimitive.SubTrigger> </DropdownMenuPrimitive.SubTrigger>
)); ))
DropdownMenuSubTrigger.displayName = DropdownMenuSubTrigger.displayName =
DropdownMenuPrimitive.SubTrigger.displayName; DropdownMenuPrimitive.SubTrigger.displayName
const DropdownMenuSubContent = React.forwardRef< const DropdownMenuSubContent = React.forwardRef<
React.ElementRef<typeof DropdownMenuPrimitive.SubContent>, React.ElementRef<typeof DropdownMenuPrimitive.SubContent>,
@ -53,9 +52,9 @@ const DropdownMenuSubContent = React.forwardRef<
)} )}
{...props} {...props}
/> />
)); ))
DropdownMenuSubContent.displayName = DropdownMenuSubContent.displayName =
DropdownMenuPrimitive.SubContent.displayName; DropdownMenuPrimitive.SubContent.displayName
const DropdownMenuContent = React.forwardRef< const DropdownMenuContent = React.forwardRef<
React.ElementRef<typeof DropdownMenuPrimitive.Content>, React.ElementRef<typeof DropdownMenuPrimitive.Content>,
@ -64,47 +63,35 @@ const DropdownMenuContent = React.forwardRef<
<DropdownMenuPrimitive.Portal> <DropdownMenuPrimitive.Portal>
<DropdownMenuPrimitive.Content <DropdownMenuPrimitive.Content
ref={ref} ref={ref}
sideOffset={sideOffset}
className={cn( className={cn(
"backdrop-blur-xl w-max z-[100] max-w-[280px] origin-top-left max-h-[32rem] overflow-auto list-none shadow-xl rounded-xl", "z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md",
"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
className className
)} )}
{...props} {...props}
> />
<div className="animate-scale-in">
<Material
className="flex flex-col py-2 list-none bg-white/80 dark:bg-zinc-900/80 px-2"
color="distinct"
padding="none"
rounding="xl"
>
<div className="overflow-y-auto max-h-[calc(32rem-1rem)]">
{props.children}
</div>
</Material>
</div>
</DropdownMenuPrimitive.Content>
</DropdownMenuPrimitive.Portal> </DropdownMenuPrimitive.Portal>
)); ))
DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName; DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName
const DropdownMenuItem = React.forwardRef< const DropdownMenuItem = React.forwardRef<
React.ElementRef<typeof DropdownMenuPrimitive.Item>, React.ElementRef<typeof DropdownMenuPrimitive.Item>,
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & { React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & {
inset?: boolean; inset?: boolean
} }
>(({ className, inset, ...props }, ref) => ( >(({ className, inset, ...props }, ref) => (
<DropdownMenuPrimitive.Item <DropdownMenuPrimitive.Item
ref={ref} ref={ref}
className={cn( className={cn(
"w-full px-2 rounded-lg z-[100] min-h-[36px] font-normal flex items-center cursor-pointer hover:dark:bg-zinc-800/70", "relative flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&>svg]:size-4 [&>svg]:shrink-0",
props.disabled ? "opacity-70 pointer-events-none cursor-not-allowed" : "", inset && "pl-8",
"duration-100 border border-transparent bg-transparent hover:bg-slate-100 dark:text-zinc-200",
className className
)} )}
{...props} {...props}
/> />
)); ))
DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName; DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName
const DropdownMenuCheckboxItem = React.forwardRef< const DropdownMenuCheckboxItem = React.forwardRef<
React.ElementRef<typeof DropdownMenuPrimitive.CheckboxItem>, React.ElementRef<typeof DropdownMenuPrimitive.CheckboxItem>,
@ -126,9 +113,9 @@ const DropdownMenuCheckboxItem = React.forwardRef<
</span> </span>
{children} {children}
</DropdownMenuPrimitive.CheckboxItem> </DropdownMenuPrimitive.CheckboxItem>
)); ))
DropdownMenuCheckboxItem.displayName = DropdownMenuCheckboxItem.displayName =
DropdownMenuPrimitive.CheckboxItem.displayName; DropdownMenuPrimitive.CheckboxItem.displayName
const DropdownMenuRadioItem = React.forwardRef< const DropdownMenuRadioItem = React.forwardRef<
React.ElementRef<typeof DropdownMenuPrimitive.RadioItem>, React.ElementRef<typeof DropdownMenuPrimitive.RadioItem>,
@ -149,13 +136,13 @@ const DropdownMenuRadioItem = React.forwardRef<
</span> </span>
{children} {children}
</DropdownMenuPrimitive.RadioItem> </DropdownMenuPrimitive.RadioItem>
)); ))
DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName; DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName
const DropdownMenuLabel = React.forwardRef< const DropdownMenuLabel = React.forwardRef<
React.ElementRef<typeof DropdownMenuPrimitive.Label>, React.ElementRef<typeof DropdownMenuPrimitive.Label>,
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label> & { React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label> & {
inset?: boolean; inset?: boolean
} }
>(({ className, inset, ...props }, ref) => ( >(({ className, inset, ...props }, ref) => (
<DropdownMenuPrimitive.Label <DropdownMenuPrimitive.Label
@ -167,8 +154,8 @@ const DropdownMenuLabel = React.forwardRef<
)} )}
{...props} {...props}
/> />
)); ))
DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName; DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName
const DropdownMenuSeparator = React.forwardRef< const DropdownMenuSeparator = React.forwardRef<
React.ElementRef<typeof DropdownMenuPrimitive.Separator>, React.ElementRef<typeof DropdownMenuPrimitive.Separator>,
@ -179,8 +166,8 @@ const DropdownMenuSeparator = React.forwardRef<
className={cn("-mx-1 my-1 h-px bg-muted", className)} className={cn("-mx-1 my-1 h-px bg-muted", className)}
{...props} {...props}
/> />
)); ))
DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName; DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName
const DropdownMenuShortcut = ({ const DropdownMenuShortcut = ({
className, className,
@ -191,9 +178,9 @@ const DropdownMenuShortcut = ({
className={cn("ml-auto text-xs tracking-widest opacity-60", className)} className={cn("ml-auto text-xs tracking-widest opacity-60", className)}
{...props} {...props}
/> />
); )
}; }
DropdownMenuShortcut.displayName = "DropdownMenuShortcut"; DropdownMenuShortcut.displayName = "DropdownMenuShortcut"
export { export {
DropdownMenu, DropdownMenu,
@ -211,4 +198,4 @@ export {
DropdownMenuSubContent, DropdownMenuSubContent,
DropdownMenuSubTrigger, DropdownMenuSubTrigger,
DropdownMenuRadioGroup, DropdownMenuRadioGroup,
}; }

@ -0,0 +1,81 @@
import { cn } from "@/lib/utils";
import * as PopoverPrimitive from "@radix-ui/react-popover";
import * as React from "react";
import { Material } from "./material";
import { Button, type ButtonProps } from "./button";
const MenuContent = React.forwardRef<
React.ElementRef<typeof PopoverPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content>
>(
(
{ className, align = "start", side = "bottom", sideOffset = 4, ...props },
ref
) => (
<PopoverPrimitive.Portal>
<PopoverPrimitive.Content
ref={ref}
align={align}
sideOffset={sideOffset}
side={side}
className={cn(
"backdrop-blur-xl w-max max-w-[280px] origin-top-left max-h-[32rem] overflow-auto list-none shadow-xl rounded-xl",
className
)}
{...props}
>
<div className="animate-scale-in">
<Material
className="flex flex-col py-2 list-none bg-white/80 dark:bg-zinc-900/80 px-2"
color="distinct"
padding="none"
rounding="xl"
>
<div className="overflow-y-auto max-h-[calc(32rem-1rem)]">
{props.children}
</div>
</Material>
</div>
</PopoverPrimitive.Content>
</PopoverPrimitive.Portal>
)
);
MenuContent.displayName = PopoverPrimitive.Content.displayName;
function MenuButton(props: ButtonProps) {
const variant = props.variant ?? "tertiary";
const alignment = props.alignment ?? "left";
return (
<Button
rounding="none"
className={cn(
"w-full px-2 rounded-lg min-h-[36px] font-normal flex items-center",
props.disabled
? "opacity-70 pointer-events-none cursor-not-allowed"
: "",
variant === "tertiary" ? "hover:dark:bg-zinc-800/70" : "",
"duration-100",
props.className
)}
variant={variant}
alignment={alignment}
{...props}
/>
);
}
function MenuButtonPrefix({ children }: { children: React.ReactNode }) {
return <span className="contents flex-shrink-0">{children}</span>;
}
function MenuSeparator({ children }: { children?: React.ReactNode }) {
return (
<span className="text-slate-800 dark:text-zinc-200 text-xs font-medium py-2 px-2 block">
{children}
</span>
);
}
export { MenuContent, MenuButton, MenuButtonPrefix, MenuSeparator };

@ -18,7 +18,7 @@ const Separator = React.forwardRef<
decorative={decorative} decorative={decorative}
orientation={orientation} orientation={orientation}
className={cn( className={cn(
"shrink-0 dark:bg-border bg-slate-200 ", "shrink-0 bg-slate-200",
orientation === "horizontal" ? "h-[1px] w-full" : "h-full w-[1px]", orientation === "horizontal" ? "h-[1px] w-full" : "h-full w-[1px]",
className className
)} )}

@ -69,7 +69,7 @@ export function ALegacy({
return ( return (
<NextLink <NextLink
href={pageFind(href || "") || "#"} href={pageFind(href || "") || "#"}
className="no-underline transition duration-300 " className="no-underline transition duration-300 hover:underline "
title={href} title={href}
> >
{(href || "").startsWith("Docs:") && ( {(href || "").startsWith("Docs:") && (
@ -95,8 +95,7 @@ export const pageFind = (text: string) => {
if (text === "Special:AccountOptions") return "/account/settings/options"; if (text === "Special:AccountOptions") return "/account/settings/options";
if (text.startsWith("Server:") && text.endsWith("/Customization")) if (text.startsWith("Server:") && text.endsWith("/Customization"))
return "/server/" + text.substring(7, text.length - 14) + "/customization"; return "/server/" + text.substring(7, text.length - 14) + "/customization";
if (text === "Special:ClerkConvertionPage") if (text === "Special:ClerkConvertionPage") return process.env.NEXT_PUBLIC_CLERK_SWITCH_DOMAIN;
return process.env.NEXT_PUBLIC_CLERK_SWITCH_DOMAIN;
if (text.startsWith("Server:")) return "/server/" + text.substring(7); if (text.startsWith("Server:")) return "/server/" + text.substring(7);
if (text.startsWith("Wiki:")) if (text.startsWith("Wiki:"))
return "https://minehut.wiki.gg/wiki/" + text.substring(5); return "https://minehut.wiki.gg/wiki/" + text.substring(5);

@ -1,42 +0,0 @@
"use client";
import { Moon, Sun } from "lucide-react";
import { useTheme } from "next-themes";
import { Button } from "@/components/ui/button";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "../ui/dropdown-menu";
export function ModeToggle() {
const { setTheme } = useTheme();
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button
variant="tertiary"
className="flex items-center"
size="square-lg"
>
<Sun className="h-[1.2rem] w-[1.2rem] rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" />
<Moon className="absolute h-[1.2rem] w-[1.2rem] rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" />
<span className="sr-only">Toggle theme</span>
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuItem onClick={() => setTheme("light")}>
Light
</DropdownMenuItem>
<DropdownMenuItem onClick={() => setTheme("dark")}>
Dark
</DropdownMenuItem>
<DropdownMenuItem onClick={() => setTheme("system")}>
System
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
);
}

@ -1639,7 +1639,7 @@
resolved "https://registry.yarnpkg.com/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.1.tgz#6f766faa975f8738269ebb8a23bad4f5a8d2faec" resolved "https://registry.yarnpkg.com/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.1.tgz#6f766faa975f8738269ebb8a23bad4f5a8d2faec"
integrity sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw== integrity sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw==
"@radix-ui/react-context-menu@^2.1.5", "@radix-ui/react-context-menu@^2.2.6": "@radix-ui/react-context-menu@^2.1.5":
version "2.2.6" version "2.2.6"
resolved "https://registry.yarnpkg.com/@radix-ui/react-context-menu/-/react-context-menu-2.2.6.tgz#752fd1d91f92bba287ef2b558770f4ca7d74523e" resolved "https://registry.yarnpkg.com/@radix-ui/react-context-menu/-/react-context-menu-2.2.6.tgz#752fd1d91f92bba287ef2b558770f4ca7d74523e"
integrity sha512-aUP99QZ3VU84NPsHeaFt4cQUNgJqFsLLOt/RbbWXszZ6MP0DpDyjkFZORr4RpAEx3sUBk+Kc8h13yGtC5Qw8dg== integrity sha512-aUP99QZ3VU84NPsHeaFt4cQUNgJqFsLLOt/RbbWXszZ6MP0DpDyjkFZORr4RpAEx3sUBk+Kc8h13yGtC5Qw8dg==