The weeb for the next gen discord boat - Wamellow wamellow.com
bot discord
3
fork

Configure Feed

Select the types of activity you want to include in your feed.

new user pop-out

Luna e063b526 6bb6f8ea

+311 -216
+4
bun.lock
··· 14 14 "@radix-ui/react-checkbox": "^1.3.3", 15 15 "@radix-ui/react-compose-refs": "1.1.2", 16 16 "@radix-ui/react-dialog": "^1.1.15", 17 + "@radix-ui/react-dropdown-menu": "^2.1.16", 17 18 "@radix-ui/react-popover": "^1.1.15", 18 19 "@radix-ui/react-primitive": "2.1.3", 19 20 "@radix-ui/react-separator": "^1.1.7", ··· 363 364 364 365 "@radix-ui/react-dismissable-layer": ["@radix-ui/react-dismissable-layer@1.1.11", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-escape-keydown": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg=="], 365 366 367 + "@radix-ui/react-dropdown-menu": ["@radix-ui/react-dropdown-menu@2.1.16", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-menu": "2.1.16", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-1PLGQEynI/3OX/ftV54COn+3Sud/Mn8vALg2rWnBLnRaGtJDduNW/22XjlGgPdpcIbiQxjKtb7BkcjP00nqfJw=="], 368 + 366 369 "@radix-ui/react-focus-guards": ["@radix-ui/react-focus-guards@1.1.3", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw=="], 367 370 368 371 "@radix-ui/react-focus-scope": ["@radix-ui/react-focus-scope@1.1.7", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw=="], 369 372 370 373 "@radix-ui/react-id": ["@radix-ui/react-id@1.1.1", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg=="], 371 374 375 + "@radix-ui/react-menu": ["@radix-ui/react-menu@2.1.16", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-focus-guards": "1.1.3", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-popper": "1.2.8", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-callback-ref": "1.1.1", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-72F2T+PLlphrqLcAotYPp0uJMr5SjP5SL01wfEspJbru5Zs5vQaSHb4VB3ZMJPimgHHCHG7gMOeOB9H3Hdmtxg=="], 372 376 373 377 "@radix-ui/react-popover": ["@radix-ui/react-popover@1.1.15", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-focus-guards": "1.1.3", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-popper": "1.2.8", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-controllable-state": "1.2.2", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-kr0X2+6Yy/vJzLYJUPCZEc8SfQcf+1COFoAqauJm74umQhta9M7lNJHP7QQS3vkvcGLQUbWpMzwrXYwrYztHKA=="], 374 378
+106 -215
components/header.tsx
··· 1 1 "use client"; 2 2 3 + import type { User } from "@/common/user"; 3 4 import { userStore } from "@/common/user"; 4 5 import { webStore } from "@/common/webstore"; 5 6 import { LoginButton } from "@/components/login-button"; 7 + import { Avatar, AvatarImage } from "@/components/ui/avatar"; 8 + import { 9 + DropdownMenu, 10 + DropdownMenuContent, 11 + DropdownMenuGroup, 12 + DropdownMenuItem, 13 + DropdownMenuLabel, 14 + DropdownMenuSeparator, 15 + DropdownMenuTrigger 16 + } from "@/components/ui/dropdown-menu"; 6 17 import { authorize } from "@/utils/authorize-user"; 7 - import { cn } from "@/utils/cn"; 8 - import { AnimatePresence, motion, MotionConfig } from "framer-motion"; 9 18 import Link from "next/link"; 10 - import { useRouter } from "next/navigation"; 11 - import { useCookies } from "next-client-cookies"; 12 - import { useCallback, useEffect, useMemo, useState } from "react"; 13 - import { HiAdjustments, HiBeaker, HiChartPie, HiChevronDown, HiEyeOff, HiFire, HiIdentification, HiLogout, HiTrendingUp, HiViewGridAdd } from "react-icons/hi"; 19 + import { useEffect, useState } from "react"; 20 + import { HiBookOpen, HiChevronDown, HiIdentification, HiLogout, HiSparkles, HiSupport, HiTerminal, HiViewGridAdd } from "react-icons/hi"; 14 21 15 - import ImageReduceMotion from "./image-reduce-motion"; 16 - import { Button } from "./ui/button"; 17 22 import { Skeleton } from "./ui/skeleton"; 18 - import { Switch } from "./ui/switch"; 19 23 20 24 enum State { 21 25 Idle = 0, ··· 23 27 Failure = 2 24 28 } 25 29 26 - const split = { type: "split" } as const; 27 - 28 30 export function Header() { 29 - const cookies = useCookies(); 30 - const devTools = cookies.get("devTools") === "true"; 31 - const reduceMotions = cookies.get("reduceMotions") === "true"; 32 - 33 - const [menu, setMenu] = useState(false); 34 31 const [state, setState] = useState<State>(State.Loading); 35 - 36 32 const user = userStore((s) => s); 37 - const router = useRouter(); 38 33 39 34 useEffect(() => { 40 35 authorize({ setState }) ··· 50 45 }); 51 46 }, []); 52 47 53 - const buttons = useMemo(() => [ 54 - split, 55 - { 56 - name: "Dashboard", 57 - icon: <HiViewGridAdd />, 58 - url: "/dashboard" 59 - }, 60 - { 61 - name: "Profile", 62 - icon: <HiIdentification />, 63 - url: "/profile" 64 - }, 65 - { 66 - name: "Reduce Motion", 67 - icon: <HiEyeOff />, 68 - value: reduceMotions, 69 - onChange: () => { 70 - if (reduceMotions) { 71 - cookies.remove("reduceMotions"); 72 - } else { 73 - cookies.set("reduceMotions", "true", { expires: 365 }); 74 - } 75 - router.refresh(); 76 - } 77 - }, 78 - ...(user?.HELLO_AND_WELCOME_TO_THE_DEV_TOOLS__PLEASE_GO_AWAY ? 79 - [ 80 - split, 81 - { 82 - name: "Analytics", 83 - icon: <HiChartPie />, 84 - url: "/profile/analytics" 85 - }, 86 - { 87 - name: "Debug", 88 - icon: <HiAdjustments />, 89 - url: "/debug" 90 - }, 91 - { 92 - name: "Issues", 93 - icon: <HiFire />, 94 - url: "https://redirect.wamellow.com/issues" 95 - }, 96 - { 97 - name: "Metrics", 98 - icon: <HiTrendingUp />, 99 - url: "https://redirect.wamellow.com/metrics" 100 - }, 101 - { 102 - name: "Lunar Tools", 103 - icon: <HiBeaker />, 104 - value: devTools, 105 - onChange: () => { 106 - if (devTools) { 107 - cookies.remove("devTools"); 108 - } else { 109 - cookies.set("devTools", "true", { expires: 365 }); 110 - } 111 - router.refresh(); 112 - } 113 - } 114 - ] 115 - : 116 - [] 117 - ) 118 - ], [user, reduceMotions, devTools]); 48 + if (state === State.Failure) { 49 + return <LoginButton state={state} className="ml-auto" />; 50 + } 119 51 120 - const UserButton = useCallback(() => ( 121 - <button 122 - className={cn( 123 - "ml-auto truncate flex hover:bg-wamellow py-2 px-4 rounded-lg duration-200 items-center", 124 - menu && "bg-wamellow" 125 - )} 126 - onClick={() => setMenu(!menu)} 127 - > 128 - {user?.id ? 129 - <> 130 - <ImageReduceMotion 131 - alt="your avatar" 132 - className="rounded-full mr-2 size-[30px] shrink-0" 133 - url={`https://cdn.discordapp.com/avatars/${user?.id}/${user?.avatar}`} 134 - size={96} 135 - /> 52 + if (state === State.Loading || !user) { 53 + return ( 54 + <div className="ml-auto flex items-center py-2 px-4"> 55 + <Skeleton className="rounded-full mr-2 size-[30px]" /> 56 + <Skeleton className="rounded-xl w-20 h-5" /> 57 + </div> 58 + ); 59 + } 136 60 137 - <p className="mr-1 relative bottom-px truncate block text-primary-foreground font-medium tracking-tight">{user.globalName || user.username}</p> 138 - <HiChevronDown /> 139 - </> 140 - : 141 - <> 142 - <Skeleton className="rounded-full mr-2 size-[30p]" /> 143 - <Skeleton className="rounded-xl w-20 h-4" /> 144 - </> 145 - } 146 - </button> 147 - ), [user, menu]); 61 + return <Dropdown user={user} />; 62 + } 148 63 149 - const UserDropdown = useCallback(() => ( 150 - <motion.div 151 - initial="closed" 152 - animate={menu ? "open" : "closed"} 153 - exit="closed" 154 - variants={{ 155 - closed: { 156 - y: "var(--y-closed, 0)", 157 - opacity: "var(--opacity-closed)", 158 - scale: "var(--scale-closed, 1)" 159 - }, 160 - open: { 161 - y: "var(--y-open, 0)", 162 - opacity: "var(--opacity-open)", 163 - scale: "var(--scale-open, 1)" 164 - } 165 - }} 166 - className=" 167 - ml-auto w-full sm:w-72 bg-black/40 rounded-xl backdrop-blur-2xl backdrop-brightness-75 shadow-xl 168 - flex flex-col py-2 sm:py-1 p-2 sm:p-0 169 - [--y-closed:-16px] [--opacity-closed:0%] sm:[--scale-closed:90%] 170 - [--y-open:0px] [--opacity-open:100%] sm:[--scale-open:100%] 171 - " 172 - > 173 - <div className="flex items-center space-x-3 px-4 py-2"> 174 - <ImageReduceMotion 175 - alt="your avatar" 176 - className="rounded-full size-14 sm:size-10 shrink-0" 177 - url={`https://cdn.discordapp.com/avatars/${user?.id}/${user?.avatar}`} 178 - size={128} 179 - /> 180 - <div className="w-full"> 181 - <div className="text-neutral-200 max-w-40 truncate font-medium text-xl sm:text-base"> 182 - {user?.globalName || user?.username} 183 - </div> 184 - <div className="text-neutral-400 max-w-40 truncate -mt-1 text-medium sm:text-sm"> 185 - @{user?.username} 186 - </div> 187 - </div> 64 + function Dropdown({ user }: { user: User; }) { 65 + return ( 66 + <DropdownMenu> 67 + <DropdownMenuTrigger asChild> 188 68 <button 189 - className="ml-auto text-red-500 m-4" 190 - onClick={() => { 191 - window.location.href = "/login?logout=true"; 192 - userStore.setState({ __fetched: true }); 193 - setMenu(false); 194 - }} 69 + className="ml-auto truncate flex hover:bg-wamellow py-2 px-4 rounded-lg duration-200 items-center data-[state=open]:bg-wamellow outline-none" 195 70 > 196 - <HiLogout className="size-5" /> 197 - </button> 198 - </div> 199 - 200 - {buttons.map((button, i) => { 201 - if ("type" in button && button.type === "split") return ( 202 - <hr key={"headerButton-" + button.type + i} className="my-1 mx-2 dark:border-wamellow border-wamellow-100" /> 203 - ); 71 + <Avatar className="size-[30px] mr-2"> 72 + <AvatarImage 73 + alt={user.username} 74 + src={user.avatar ? `https://cdn.discordapp.com/avatars/${user.id}/${user.avatar}?size=96` : "/discord.webp"} 75 + /> 76 + </Avatar> 204 77 205 - if ("url" in button) return ( 206 - <Button 207 - key={"headerButton-" + button.name + button.url} 78 + <p className="mr-1 relative bottom-px truncate block text-primary-foreground font-medium tracking-tight">{user.globalName || user.username}</p> 79 + <HiChevronDown /> 80 + </button> 81 + </DropdownMenuTrigger> 82 + <DropdownMenuContent className='w-56 scale-120 relative top-7 right-5' align="end"> 83 + <DropdownMenuLabel className='flex items-center gap-3'> 84 + <Avatar> 85 + <AvatarImage 86 + alt={user.username} 87 + src={user.avatar ? `https://cdn.discordapp.com/avatars/${user.id}/${user.avatar}?size=96` : "/discord.webp"} 88 + /> 89 + </Avatar> 90 + <div className='flex flex-col pb-0.5 truncate'> 91 + <span className='text-popover-foreground truncate'>{user.globalName || user.username}</span> 92 + <span className='text-muted-foreground text-xs truncate'>{user.email}</span> 93 + </div> 94 + </DropdownMenuLabel> 95 + <DropdownMenuSeparator /> 96 + <DropdownMenuGroup> 97 + <DropdownMenuItem asChild> 98 + <Link href="/profile"> 99 + <HiViewGridAdd /> 100 + Dashboard 101 + </Link> 102 + </DropdownMenuItem> 103 + <DropdownMenuItem asChild> 104 + <Link href="/profile"> 105 + <HiIdentification /> 106 + Profile 107 + </Link> 108 + </DropdownMenuItem> 109 + <DropdownMenuItem asChild> 110 + <Link href={user.premium ? "/profile/billing" : "/premium"}> 111 + <HiSparkles /> 112 + {user.premium ? "Billing" : "Premium"} 113 + </Link> 114 + </DropdownMenuItem> 115 + </DropdownMenuGroup> 116 + <DropdownMenuSeparator /> 117 + <DropdownMenuGroup> 118 + <DropdownMenuItem asChild> 119 + <Link href="/support"> 120 + <HiSupport /> 121 + Support 122 + </Link> 123 + </DropdownMenuItem> 124 + <DropdownMenuItem asChild> 125 + <Link href="/docs/index"> 126 + <HiBookOpen /> 127 + Documentation 128 + </Link> 129 + </DropdownMenuItem> 130 + <DropdownMenuItem disabled> 131 + <HiTerminal /> 132 + Developer API 133 + </DropdownMenuItem> 134 + </DropdownMenuGroup> 135 + <DropdownMenuSeparator /> 136 + <DropdownMenuGroup> 137 + <DropdownMenuItem 208 138 asChild 209 - className="w-full font-medium justify-start text-xl my-1 sm:my-0 sm:text-medium bg-transparent hover:bg-wamellow rounded-xs" 210 - onClick={() => setMenu(false)} 139 + className="text-red-400" 211 140 > 212 - <Link href={button.url!}> 213 - {button.icon} 214 - {button.name} 141 + <Link href="/login?logout=true" prefetch={false}> 142 + <HiLogout /> 143 + Logout 215 144 </Link> 216 - </Button> 217 - ); 218 - 219 - if ("onChange" in button) return ( 220 - <div 221 - key={"headerButton-" + button.name} 222 - className="flex items-center px-4 pt-2 pb-3" 223 - > 224 - {button.icon} 225 - <span className="ml-[9px] text-xl my-1 sm:text-medium sm:my-0">{button.name}</span> 226 - <Switch 227 - key={"headerButton-" + button.name} 228 - className="ml-auto" 229 - checked={button.value} 230 - onChange={button.onChange} 231 - /> 232 - </div> 233 - ); 234 - })} 235 - </motion.div> 236 - ), [user, menu, reduceMotions, devTools]); 237 - 238 - return (<> 239 - {state === State.Failure 240 - ? <LoginButton state={state} className="ml-auto" /> 241 - : <UserButton /> 242 - } 243 - 244 - <MotionConfig 245 - transition={reduceMotions 246 - ? { duration: 0 } 247 - : { type: "spring", bounce: 0.4, duration: menu ? 0.7 : 0.4 } 248 - } 249 - > 250 - <AnimatePresence initial={false}> 251 - {user?.id && menu && 252 - <div className="absolute top-[72px] right-3.5 z-50 w-[calc(100%-1.6rem)]"> 253 - <UserDropdown /> 254 - </div> 255 - } 256 - </AnimatePresence> 257 - </MotionConfig> 258 - </>); 145 + </DropdownMenuItem> 146 + </DropdownMenuGroup> 147 + </DropdownMenuContent> 148 + </DropdownMenu> 149 + ); 259 150 }
+1 -1
components/markdown/index.tsx
··· 122 122 )} 123 123 > 124 124 {/* eslint-disable-next-line @next/next/no-img-element */} 125 - <img alt={alt} className={cn("rounded-md", alt === "emoji") && "inline"} loading="lazy" {...props} /> 125 + <img alt={alt} className={cn("rounded-lg", alt === "emoji" && "inline")} loading="lazy" {...props} /> 126 126 {alt && alt !== "emoji" && <span aria-hidden="true" className="text-neutral-500 font-medium text-sm text-center">{alt}</span>} 127 127 </span> 128 128 );
+199
components/ui/dropdown-menu.tsx
··· 1 + "use client"; 2 + 3 + import { cn } from "@/utils/cn"; 4 + import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu"; 5 + import { Check, ChevronRight, Circle } from "lucide-react"; 6 + import * as React from "react"; 7 + 8 + const DropdownMenu = DropdownMenuPrimitive.Root; 9 + 10 + const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger; 11 + 12 + const DropdownMenuGroup = DropdownMenuPrimitive.Group; 13 + 14 + const DropdownMenuPortal = DropdownMenuPrimitive.Portal; 15 + 16 + const DropdownMenuSub = DropdownMenuPrimitive.Sub; 17 + 18 + const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup; 19 + 20 + const DropdownMenuSubTrigger = React.forwardRef< 21 + React.ElementRef<typeof DropdownMenuPrimitive.SubTrigger>, 22 + React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubTrigger> & { 23 + inset?: boolean; 24 + } 25 + >(({ className, inset, children, ...props }, ref) => ( 26 + <DropdownMenuPrimitive.SubTrigger 27 + ref={ref} 28 + className={cn( 29 + "flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent data-[state=open]:bg-accent [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0", 30 + inset && "pl-8", 31 + className 32 + )} 33 + {...props} 34 + > 35 + {children} 36 + <ChevronRight className="ml-auto" /> 37 + </DropdownMenuPrimitive.SubTrigger> 38 + )); 39 + DropdownMenuSubTrigger.displayName = 40 + DropdownMenuPrimitive.SubTrigger.displayName; 41 + 42 + const DropdownMenuSubContent = React.forwardRef< 43 + React.ElementRef<typeof DropdownMenuPrimitive.SubContent>, 44 + React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubContent> 45 + >(({ className, ...props }, ref) => ( 46 + <DropdownMenuPrimitive.SubContent 47 + ref={ref} 48 + className={cn( 49 + "z-50 min-w-[8rem] overflow-hidden rounded-lg bg-wamellow 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 origin-[--radix-dropdown-menu-content-transform-origin]", 50 + className 51 + )} 52 + {...props} 53 + /> 54 + )); 55 + DropdownMenuSubContent.displayName = 56 + DropdownMenuPrimitive.SubContent.displayName; 57 + 58 + const DropdownMenuContent = React.forwardRef< 59 + React.ElementRef<typeof DropdownMenuPrimitive.Content>, 60 + React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content> 61 + >(({ className, sideOffset = 4, ...props }, ref) => ( 62 + <DropdownMenuPrimitive.Portal> 63 + <DropdownMenuPrimitive.Content 64 + ref={ref} 65 + sideOffset={sideOffset} 66 + className={cn( 67 + "z-50 max-h-[var(--radix-dropdown-menu-content-available-height)] min-w-[8rem] overflow-y-auto overflow-x-hidden rounded-lg bg-wamellow backdrop-brightness-50 backdrop-blur-xl p-1 text-primary-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 origin-[--radix-dropdown-menu-content-transform-origin]", 68 + className 69 + )} 70 + {...props} 71 + /> 72 + </DropdownMenuPrimitive.Portal> 73 + )); 74 + DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName; 75 + 76 + const DropdownMenuItem = React.forwardRef< 77 + React.ElementRef<typeof DropdownMenuPrimitive.Item>, 78 + React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & { 79 + inset?: boolean; 80 + } 81 + >(({ className, inset, ...props }, ref) => ( 82 + <DropdownMenuPrimitive.Item 83 + ref={ref} 84 + className={cn( 85 + "relative flex select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-wamellow focus:text-primary-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0", 86 + inset && "pl-8", 87 + className 88 + )} 89 + {...props} 90 + /> 91 + )); 92 + DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName; 93 + 94 + const DropdownMenuCheckboxItem = React.forwardRef< 95 + React.ElementRef<typeof DropdownMenuPrimitive.CheckboxItem>, 96 + React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.CheckboxItem> 97 + >(({ className, children, checked, ...props }, ref) => ( 98 + <DropdownMenuPrimitive.CheckboxItem 99 + ref={ref} 100 + className={cn( 101 + "relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50", 102 + className 103 + )} 104 + checked={checked} 105 + {...props} 106 + > 107 + <span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center"> 108 + <DropdownMenuPrimitive.ItemIndicator> 109 + <Check className="h-4 w-4" /> 110 + </DropdownMenuPrimitive.ItemIndicator> 111 + </span> 112 + {children} 113 + </DropdownMenuPrimitive.CheckboxItem> 114 + )); 115 + DropdownMenuCheckboxItem.displayName = 116 + DropdownMenuPrimitive.CheckboxItem.displayName; 117 + 118 + const DropdownMenuRadioItem = React.forwardRef< 119 + React.ElementRef<typeof DropdownMenuPrimitive.RadioItem>, 120 + React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.RadioItem> 121 + >(({ className, children, ...props }, ref) => ( 122 + <DropdownMenuPrimitive.RadioItem 123 + ref={ref} 124 + className={cn( 125 + "relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50", 126 + className 127 + )} 128 + {...props} 129 + > 130 + <span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center"> 131 + <DropdownMenuPrimitive.ItemIndicator> 132 + <Circle className="h-2 w-2 fill-current" /> 133 + </DropdownMenuPrimitive.ItemIndicator> 134 + </span> 135 + {children} 136 + </DropdownMenuPrimitive.RadioItem> 137 + )); 138 + DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName; 139 + 140 + const DropdownMenuLabel = React.forwardRef< 141 + React.ElementRef<typeof DropdownMenuPrimitive.Label>, 142 + React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label> & { 143 + inset?: boolean; 144 + } 145 + >(({ className, inset, ...props }, ref) => ( 146 + <DropdownMenuPrimitive.Label 147 + ref={ref} 148 + className={cn( 149 + "px-2 py-1.5 text-sm font-semibold", 150 + inset && "pl-8", 151 + className 152 + )} 153 + {...props} 154 + /> 155 + )); 156 + DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName; 157 + 158 + const DropdownMenuSeparator = React.forwardRef< 159 + React.ElementRef<typeof DropdownMenuPrimitive.Separator>, 160 + React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Separator> 161 + >(({ className, ...props }, ref) => ( 162 + <DropdownMenuPrimitive.Separator 163 + ref={ref} 164 + className={cn("-mx-1 my-1 h-px bg-muted", className)} 165 + {...props} 166 + /> 167 + )); 168 + DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName; 169 + 170 + const DropdownMenuShortcut = ({ 171 + className, 172 + ...props 173 + }: React.HTMLAttributes<HTMLSpanElement>) => { 174 + return ( 175 + <span 176 + className={cn("ml-auto text-xs tracking-widest opacity-60", className)} 177 + {...props} 178 + /> 179 + ); 180 + }; 181 + DropdownMenuShortcut.displayName = "DropdownMenuShortcut"; 182 + 183 + export { 184 + DropdownMenu, 185 + DropdownMenuCheckboxItem, 186 + DropdownMenuContent, 187 + DropdownMenuGroup, 188 + DropdownMenuItem, 189 + DropdownMenuLabel, 190 + DropdownMenuPortal, 191 + DropdownMenuRadioGroup, 192 + DropdownMenuRadioItem, 193 + DropdownMenuSeparator, 194 + DropdownMenuShortcut, 195 + DropdownMenuSub, 196 + DropdownMenuSubContent, 197 + DropdownMenuSubTrigger, 198 + DropdownMenuTrigger 199 + };
+1
package.json
··· 23 23 "@radix-ui/react-checkbox": "^1.3.3", 24 24 "@radix-ui/react-compose-refs": "1.1.2", 25 25 "@radix-ui/react-dialog": "^1.1.15", 26 + "@radix-ui/react-dropdown-menu": "^2.1.16", 26 27 "@radix-ui/react-popover": "^1.1.15", 27 28 "@radix-ui/react-primitive": "2.1.3", 28 29 "@radix-ui/react-separator": "^1.1.7",