add mobile menu and v1 of DexNet
Build KX3DEX.radio / Build and Deploy (push) Successful in 31m18s Details

master
Dex 2024-04-10 22:40:31 -04:00
parent e0ed17bd66
commit 1af01fa8a7
38 changed files with 774 additions and 171 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,40 +0,0 @@
"use client"
import * as React from "react"
import { MoonIcon, SunIcon } from "@radix-ui/react-icons"
import { useTheme } from "next-themes"
import { Button } from "@/components/ui/button"
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu"
export function ModeToggle() {
const { setTheme } = useTheme()
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="outline" size="icon">
<SunIcon className="h-[1.2rem] w-[1.2rem] rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" />
<MoonIcon 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>
)
}

View File

@ -19,7 +19,7 @@ export default function DexNetPage() {
/>
</div>
<h2 className="text-xl font-black text-center mt-10">
<Link href="#">Download Here - LINK COMING SOON</Link>
<Link href="KX3DEX_DexNet_v1.pdf">Download Version 1</Link>
</h2>
</div>
)

View File

@ -2,69 +2,54 @@
@tailwind components;
@tailwind utilities;
@layer base {
:root {
--background: 0 0% 100%;
--foreground: 222.2 84% 4.9%;
--foreground: 240 10% 3.9%;
--card: 0 0% 100%;
--card-foreground: 222.2 84% 4.9%;
--card-foreground: 240 10% 3.9%;
--popover: 0 0% 100%;
--popover-foreground: 222.2 84% 4.9%;
--primary: 222.2 47.4% 11.2%;
--primary-foreground: 210 40% 98%;
--secondary: 210 40% 96.1%;
--secondary-foreground: 222.2 47.4% 11.2%;
--muted: 210 40% 96.1%;
--muted-foreground: 215.4 16.3% 46.9%;
--accent: 210 40% 96.1%;
--accent-foreground: 222.2 47.4% 11.2%;
--popover-foreground: 240 10% 3.9%;
--primary: 240 5.9% 10%;
--primary-foreground: 0 0% 98%;
--secondary: 240 4.8% 95.9%;
--secondary-foreground: 240 5.9% 10%;
--muted: 240 4.8% 95.9%;
--muted-foreground: 240 3.8% 46.1%;
--accent: 240 4.8% 95.9%;
--accent-foreground: 240 5.9% 10%;
--destructive: 0 84.2% 60.2%;
--destructive-foreground: 210 40% 98%;
--border: 214.3 31.8% 91.4%;
--input: 214.3 31.8% 91.4%;
--ring: 222.2 84% 4.9%;
--destructive-foreground: 0 0% 98%;
--border: 240 5.9% 90%;
--input: 240 5.9% 90%;
--ring: 240 5.9% 10%;
--radius: 0.5rem;
}
.dark {
--background: 222.2 84% 4.9%;
--foreground: 210 40% 98%;
--card: 222.2 84% 4.9%;
--card-foreground: 210 40% 98%;
--popover: 222.2 84% 4.9%;
--popover-foreground: 210 40% 98%;
--primary: 210 40% 98%;
--primary-foreground: 222.2 47.4% 11.2%;
--secondary: 217.2 32.6% 17.5%;
--secondary-foreground: 210 40% 98%;
--muted: 217.2 32.6% 17.5%;
--muted-foreground: 215 20.2% 65.1%;
--accent: 217.2 32.6% 17.5%;
--accent-foreground: 210 40% 98%;
--background: 240 10% 3.9%;
--foreground: 0 0% 98%;
--card: 240 10% 3.9%;
--card-foreground: 0 0% 98%;
--popover: 240 10% 3.9%;
--popover-foreground: 0 0% 98%;
--primary: 0 0% 98%;
--primary-foreground: 240 5.9% 10%;
--secondary: 240 3.7% 15.9%;
--secondary-foreground: 0 0% 98%;
--muted: 240 3.7% 15.9%;
--muted-foreground: 240 5% 64.9%;
--accent: 240 3.7% 15.9%;
--accent-foreground: 0 0% 98%;
--destructive: 0 62.8% 30.6%;
--destructive-foreground: 210 40% 98%;
--destructive-foreground: 0 0% 98%;
--border: 240 3.7% 15.9%;
--input: 240 3.7% 15.9%;
--ring: 240 4.9% 83.9%;
}
}
--border: 217.2 32.6% 17.5%;
--input: 217.2 32.6% 17.5%;
--ring: 212.7 26.8% 83.9%;
}
}
@layer base {
* {

View File

@ -1,11 +1,14 @@
import "./globals.css";
import type { Metadata } from "next";
import Image from 'next/image'
import React from 'react';
import { Inter } from "next/font/google";
import "./globals.css";
import { ThemeProvider } from "./components/theme-provider";
import Header from "@/components/ui/header";
import Footer from "@/components/ui/footer";
import Header from '@/components/header'
import HeaderMobile from '@/components/header-mobile'
import Footer from "@/components/footer";
import MarginWidthWrapper from '@/components/margin-width-wrapper';
import PageWrapper from '@/components/page-wrapper';
const inter = Inter({ subsets: ["latin"] });
@ -36,9 +39,12 @@ export default function RootLayout({
fill
style={{ position: 'absolute' }}
/>
<main className="max-w-5xl mx-auto px-4 z-10">
<Header />
<main className="max-w-5xl mx-auto px-4 z-10">{children}</main>
<HeaderMobile />
{children}
<Footer />
</main>
</div>
</ThemeProvider>
</body>

View File

@ -1,5 +1,3 @@
import { Button } from "@/components/ui/button";
export default async function Home() {
return (

118
components/drawer.tsx Normal file
View File

@ -0,0 +1,118 @@
"use client"
import * as React from "react"
import { Drawer as DrawerPrimitive } from "vaul"
import { cn } from "@/lib/utils"
const Drawer = ({
shouldScaleBackground = true,
...props
}: React.ComponentProps<typeof DrawerPrimitive.Root>) => (
<DrawerPrimitive.Root
shouldScaleBackground={shouldScaleBackground}
{...props}
/>
)
Drawer.displayName = "Drawer"
const DrawerTrigger = DrawerPrimitive.Trigger
const DrawerPortal = DrawerPrimitive.Portal
const DrawerClose = DrawerPrimitive.Close
const DrawerOverlay = React.forwardRef<
React.ElementRef<typeof DrawerPrimitive.Overlay>,
React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Overlay>
>(({ className, ...props }, ref) => (
<DrawerPrimitive.Overlay
ref={ref}
className={cn("fixed inset-0 z-50 bg-black/80", className)}
{...props}
/>
))
DrawerOverlay.displayName = DrawerPrimitive.Overlay.displayName
const DrawerContent = React.forwardRef<
React.ElementRef<typeof DrawerPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Content>
>(({ className, children, ...props }, ref) => (
<DrawerPortal>
<DrawerOverlay />
<DrawerPrimitive.Content
ref={ref}
className={cn(
"fixed inset-x-0 bottom-0 z-50 mt-24 flex h-auto flex-col rounded-t-[10px] border bg-background",
className
)}
{...props}
>
<div className="mx-auto mt-4 h-2 w-[100px] rounded-full bg-muted" />
{children}
</DrawerPrimitive.Content>
</DrawerPortal>
))
DrawerContent.displayName = "DrawerContent"
const DrawerHeader = ({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn("grid gap-1.5 p-4 text-center sm:text-left", className)}
{...props}
/>
)
DrawerHeader.displayName = "DrawerHeader"
const DrawerFooter = ({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn("mt-auto flex flex-col gap-2 p-4", className)}
{...props}
/>
)
DrawerFooter.displayName = "DrawerFooter"
const DrawerTitle = React.forwardRef<
React.ElementRef<typeof DrawerPrimitive.Title>,
React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Title>
>(({ className, ...props }, ref) => (
<DrawerPrimitive.Title
ref={ref}
className={cn(
"text-lg font-semibold leading-none tracking-tight",
className
)}
{...props}
/>
))
DrawerTitle.displayName = DrawerPrimitive.Title.displayName
const DrawerDescription = React.forwardRef<
React.ElementRef<typeof DrawerPrimitive.Description>,
React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Description>
>(({ className, ...props }, ref) => (
<DrawerPrimitive.Description
ref={ref}
className={cn("text-sm text-muted-foreground", className)}
{...props}
/>
))
DrawerDescription.displayName = DrawerPrimitive.Description.displayName
export {
Drawer,
DrawerPortal,
DrawerOverlay,
DrawerTrigger,
DrawerClose,
DrawerContent,
DrawerHeader,
DrawerFooter,
DrawerTitle,
DrawerDescription,
}

View File

@ -0,0 +1,240 @@
'use client';
import React, { ReactNode, useEffect, useRef, useState } from 'react';
import Link from 'next/link';
import { usePathname } from 'next/navigation';
import { NAV_ITEMS } from '@/components/nav';
import { NavItem } from '@/components/types';
import { Icon } from '@iconify/react';
import { motion, useCycle } from 'framer-motion';
type MenuItemWithSubMenuProps = {
item: NavItem;
toggleOpen: () => void;
};
const sidebar = {
open: (height = 1000) => ({
clipPath: `circle(${height * 2 + 200}px at 100% 0)`,
transition: {
type: 'spring',
stiffness: 20,
restDelta: 2,
},
}),
closed: {
clipPath: 'circle(0px at 100% 0)',
transition: {
type: 'spring',
stiffness: 400,
damping: 40,
},
},
};
const HeaderMobile = () => {
const pathname = usePathname();
const containerRef = useRef(null);
const { height } = useDimensions(containerRef);
const [isOpen, toggleOpen] = useCycle(false, true);
return (
<motion.nav
initial={false}
animate={isOpen ? 'open' : 'closed'}
custom={height}
className={`fixed inset-0 z-50 w-full md:hidden ${
isOpen ? '' : 'pointer-events-none'
}`}
ref={containerRef}
>
<motion.div
className="absolute inset-0 right-0 w-full bg-black"
variants={sidebar}
/>
<motion.ul
variants={variants}
className="absolute grid w-full gap-3 px-10 py-16 max-h-screen overflow-y-auto"
>
{NAV_ITEMS.map((item, idx) => {
const isLastItem = idx === NAV_ITEMS.length - 1; // Check if it's the last item
return (
<div key={idx}>
{item.submenu ? (
<MenuItemWithSubMenu item={item} toggleOpen={toggleOpen} />
) : (
<MenuItem>
<Link
href={item.path}
onClick={() => toggleOpen()}
className={`flex w-full text-2xl ${
item.path === pathname ? 'font-bold' : ''
}`}
>
{item.title}
</Link>
</MenuItem>
)}
{!isLastItem && (
<MenuItem className="my-3 h-px w-full bg-gray-300" />
)}
</div>
);
})}
</motion.ul>
<MenuToggle toggle={toggleOpen} />
</motion.nav>
);
};
export default HeaderMobile;
const MenuToggle = ({ toggle }: { toggle: any }) => (
<button
onClick={toggle}
className="pointer-events-auto absolute right-4 top-[14px] z-30 p-7"
>
<svg width="60" height="60" viewBox="0 0 23 23">
<Path
variants={{
closed: { d: 'M 2 2.5 L 20 2.5' },
open: { d: 'M 3 16.5 L 17 2.5' },
}}
/>
<Path
d="M 2 9.423 L 20 9.423"
variants={{
closed: { opacity: 1 },
open: { opacity: 0 },
}}
transition={{ duration: 0.1 }}
/>
<Path
variants={{
closed: { d: 'M 2 16.346 L 20 16.346' },
open: { d: 'M 3 2.5 L 17 16.346' },
}}
/>
</svg>
</button>
);
const Path = (props: any) => (
<motion.path
fill="transparent"
strokeWidth="2"
stroke="hsl(0, 0%, 100%)"
strokeLinecap="round"
{...props}
/>
);
const MenuItem = ({
className,
children,
}: {
className?: string;
children?: ReactNode;
}) => {
return (
<motion.li variants={MenuItemVariants} className={className}>
{children}
</motion.li>
);
};
const MenuItemWithSubMenu: React.FC<MenuItemWithSubMenuProps> = ({
item,
toggleOpen,
}) => {
const pathname = usePathname();
const [subMenuOpen, setSubMenuOpen] = useState(false);
return (
<>
<MenuItem>
<button
className="flex w-full text-2xl"
onClick={() => setSubMenuOpen(!subMenuOpen)}
>
<div className="flex flex-row justify-between w-full items-center">
<span
className={`${pathname.includes(item.path) ? 'font-bold' : ''}`}
>
{item.title}
</span>
<div className={`${subMenuOpen && 'rotate-180'}`}>
<Icon icon="lucide:chevron-down" width="24" height="24" />
</div>
</div>
</button>
</MenuItem>
<div className="mt-2 ml-2 flex flex-col space-y-2">
{subMenuOpen && (
<>
{item.subMenuItems?.map((subItem, subIdx) => {
return (
<MenuItem key={subIdx}>
<Link
href={subItem.path}
onClick={() => toggleOpen()}
className={` ${
subItem.path === pathname ? 'font-bold' : ''
}`}
>
{subItem.title}
</Link>
</MenuItem>
);
})}
</>
)}
</div>
</>
);
};
const MenuItemVariants = {
open: {
y: 0,
opacity: 1,
transition: {
y: { stiffness: 1000, velocity: -100 },
},
},
closed: {
y: 50,
opacity: 0,
transition: {
y: { stiffness: 1000 },
duration: 0.02,
},
},
};
const variants = {
open: {
transition: { staggerChildren: 0.02, delayChildren: 0.15 },
},
closed: {
transition: { staggerChildren: 0.01, staggerDirection: -1 },
},
};
const useDimensions = (ref: any) => {
const dimensions = useRef({ width: 0, height: 0 });
useEffect(() => {
if (ref.current) {
dimensions.current.width = ref.current.offsetWidth;
dimensions.current.height = ref.current.offsetHeight;
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [ref]);
return dimensions.current;
};

65
components/header.tsx Normal file
View File

@ -0,0 +1,65 @@
'use client';
import React from 'react';
import Image from 'next/image';
import { useSelectedLayoutSegment } from 'next/navigation';
import logo from '@/public/images/kx3dex_radio_logo.png'
import useScroll from '@/hooks/use-scroll';
import { cn } from '@/lib/utils';
import {
NavigationMenu,
NavigationMenuContent,
NavigationMenuItem,
NavigationMenuLink,
NavigationMenuList,
NavigationMenuTrigger,
} from "@/components/navigation-menu"
const Header = () => {
const scrolled = useScroll(5);
const selectedLayout = useSelectedLayoutSegment();
return (
<div
className={cn(
`sticky inset-x-0 top-0 z-30 w-full transition-all border-b border-gray-200`,
{
'border-b border-gray-200 backdrop-blur-lg': scrolled,
'border-b border-gray-200 mb-5': selectedLayout,
},
)}
>
<div className="flex items-center justify-between p-4">
<div className="flex items-center space-x-4">
<Image
src={logo}
width={100}
height={100}
alt="Logo Image"
priority
className="rounded-lg border"
/>
</div>
<div className="hidden md:block">
<NavigationMenu>
<NavigationMenuLink href="/" className="font-bold text-3xl pr-5">Home</NavigationMenuLink>
<NavigationMenuLink href="/dexnet" className="font-bold text-3xl pr-5">DexNet</NavigationMenuLink>
<NavigationMenuList>
<NavigationMenuItem>
<NavigationMenuTrigger className="font-bold text-3xl pr-5">Go Kits</NavigationMenuTrigger>
<NavigationMenuContent className="flex flex-col min-w-[300px] p-2 absolute right-0">
<NavigationMenuLink href="/projects/go-kit-command-center" className="font-bold">Go Kit (Command Center)</NavigationMenuLink>
</NavigationMenuContent>
</NavigationMenuItem>
</NavigationMenuList>
</NavigationMenu>
</div>
</div>
</div>
);
};
export default Header;

View File

@ -0,0 +1,13 @@
import { ReactNode } from 'react';
export default function MarginWidthWrapper({
children,
}: {
children: ReactNode;
}) {
return (
<div className="flex flex-col md:ml-60 sm:border-r sm:border-zinc-700 min-h-screen">
{children}
</div>
);
}

22
components/nav.tsx Normal file
View File

@ -0,0 +1,22 @@
import { Icon } from '@iconify/react';
import { NavItem } from '@/components/types';
export const NAV_ITEMS: NavItem[] = [
{
title: 'Home',
path: '/',
},
{
title: 'DexNet',
path: '/dexnet',
},
{
title: 'Go Kits',
path: '',
submenu: true,
subMenuItems: [
{ title: 'Go Kit Command Center', path: '/projects/go-kit-command-center' },
],
}
];

View File

@ -41,7 +41,7 @@ NavigationMenuList.displayName = NavigationMenuPrimitive.List.displayName
const NavigationMenuItem = NavigationMenuPrimitive.Item
const navigationMenuTriggerStyle = cva(
"group inline-flex h-10 w-max items-center justify-center rounded-md bg-background px-4 py-2 text-sm font-medium transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground focus:outline-none disabled:pointer-events-none disabled:opacity-50 data-[active]:bg-accent/50 data-[state=open]:bg-accent/50"
"group inline-flex h-10 w-max items-center justify-center rounded-md yarnpy-2 text-sm font-medium transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground focus:outline-none disabled:pointer-events-none disabled:opacity-50 data-[active]:bg-accent/50 data-[state=open]:bg-accent/50"
)
const NavigationMenuTrigger = React.forwardRef<
@ -83,10 +83,10 @@ const NavigationMenuViewport = React.forwardRef<
React.ElementRef<typeof NavigationMenuPrimitive.Viewport>,
React.ComponentPropsWithoutRef<typeof NavigationMenuPrimitive.Viewport>
>(({ className, ...props }, ref) => (
<div className={cn("absolute left-0 top-full flex justify-center")}>
<div className={cn("absolute right-0 top-full flex ")}>
<NavigationMenuPrimitive.Viewport
className={cn(
"origin-top-center relative mt-1.5 h-[var(--radix-navigation-menu-viewport-height)] w-full overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-90 md:w-[var(--radix-navigation-menu-viewport-width)]",
"origin-top-left relative mt-1.5 h-[var(--radix-navigation-menu-viewport-height)] w-full overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-90 md:w-[var(--radix-navigation-menu-viewport-width)]",
className
)}
ref={ref}

View File

@ -0,0 +1,9 @@
import { ReactNode } from 'react';
export default function PageWrapper({ children }: { children: ReactNode }) {
return (
<div className="flex flex-col pt-2 px-4 space-y-2 bg-zinc-100 flex-grow pb-4">
{children}
</div>
);
}

7
components/types.tsx Normal file
View File

@ -0,0 +1,7 @@
export type NavItem = {
title: string;
path: string;
icon?: JSX.Element;
submenu?: boolean;
subMenuItems?: NavItem[];
};

View File

@ -1,47 +0,0 @@
'use client'
import Link from 'next/link'
import Image from 'next/image'
import logo from '@/public/images/kx3dex_radio_logo.png'
import {
NavigationMenu,
NavigationMenuContent,
NavigationMenuItem,
NavigationMenuLink,
NavigationMenuList,
NavigationMenuTrigger,
} from "@/components/ui/navigation-menu"
export default function Header() {
return (
<nav className="w-full relative flex items-center max-w-5xl mx-auto px-4 py-5">
<Image
src={logo}
width={100}
height={100}
alt="Logo Image"
priority
className="rounded-lg border"
/>
<Link href="/" className="font-bold text-3xl pl-10 pr-5">
Home
</Link>
<Link href="/dexnet" className="font-bold text-3xl ">
DexNet
</Link>
<NavigationMenu>
<NavigationMenuList>
<NavigationMenuItem>
<NavigationMenuTrigger className="font-bold text-3xl pr-5">Go Kits</NavigationMenuTrigger>
<NavigationMenuContent className="flex flex-col min-w-[300px] p-2">
<NavigationMenuLink href="/projects/go-kit-command-center" className="font-bold">Go Kit (Command Center)</NavigationMenuLink>
</NavigationMenuContent>
</NavigationMenuItem>
</NavigationMenuList>
</NavigationMenu>
</nav>
)
}

21
hooks/use-scroll.tsx Normal file
View File

@ -0,0 +1,21 @@
import { useCallback, useEffect, useState } from 'react';
export default function useScroll(threshold: number) {
const [scrolled, setScrolled] = useState(false);
const onScroll = useCallback(() => {
setScrolled(window.scrollY > threshold);
}, [threshold]);
useEffect(() => {
window.addEventListener('scroll', onScroll);
return () => window.removeEventListener('scroll', onScroll);
}, [onScroll]);
// also check on first load
useEffect(() => {
onScroll();
}, [onScroll]);
return scrolled;
}

106
package-lock.json generated
View File

@ -8,20 +8,25 @@
"name": "kx3dex_radio",
"version": "1.0.0",
"dependencies": {
"@iconify/react": "^4.1.1",
"@radix-ui/react-dialog": "^1.0.5",
"@radix-ui/react-dropdown-menu": "^2.0.6",
"@radix-ui/react-icons": "^1.3.0",
"@radix-ui/react-navigation-menu": "^1.1.4",
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.0",
"framer-motion": "^11.0.27",
"lucide-react": "^0.363.0",
"next": "14.1.4",
"next-themes": "^0.3.0",
"react": "^18",
"react-dom": "^18",
"react-icons": "^5.0.1",
"sharp": "^0.33.3",
"swiper": "^11.1.0",
"tailwind-merge": "^2.2.2",
"tailwindcss-animate": "^1.0.7"
"tailwindcss-animate": "^1.0.7",
"vaul": "^0.9.0"
},
"devDependencies": {
"@types/node": "^20",
@ -198,6 +203,25 @@
"integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==",
"dev": true
},
"node_modules/@iconify/react": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/@iconify/react/-/react-4.1.1.tgz",
"integrity": "sha512-jed14EjvKjee8mc0eoscGxlg7mSQRkwQG3iX3cPBCO7UlOjz0DtlvTqxqEcHUJGh+z1VJ31Yhu5B9PxfO0zbdg==",
"dependencies": {
"@iconify/types": "^2.0.0"
},
"funding": {
"url": "https://github.com/sponsors/cyberalien"
},
"peerDependencies": {
"react": ">=16"
}
},
"node_modules/@iconify/types": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/@iconify/types/-/types-2.0.0.tgz",
"integrity": "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg=="
},
"node_modules/@img/sharp-darwin-arm64": {
"version": "0.33.3",
"resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.3.tgz",
@ -994,6 +1018,42 @@
}
}
},
"node_modules/@radix-ui/react-dialog": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.0.5.tgz",
"integrity": "sha512-GjWJX/AUpB703eEBanuBnIWdIXg6NvJFCXcNlSZk4xdszCdhrJgBoUd1cGk67vFO+WdA2pfI/plOpqz/5GUP6Q==",
"dependencies": {
"@babel/runtime": "^7.13.10",
"@radix-ui/primitive": "1.0.1",
"@radix-ui/react-compose-refs": "1.0.1",
"@radix-ui/react-context": "1.0.1",
"@radix-ui/react-dismissable-layer": "1.0.5",
"@radix-ui/react-focus-guards": "1.0.1",
"@radix-ui/react-focus-scope": "1.0.4",
"@radix-ui/react-id": "1.0.1",
"@radix-ui/react-portal": "1.0.4",
"@radix-ui/react-presence": "1.0.1",
"@radix-ui/react-primitive": "1.0.3",
"@radix-ui/react-slot": "1.0.2",
"@radix-ui/react-use-controllable-state": "1.0.1",
"aria-hidden": "^1.1.1",
"react-remove-scroll": "2.5.5"
},
"peerDependencies": {
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0",
"react-dom": "^16.8 || ^17.0 || ^18.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-direction": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.0.1.tgz",
@ -3290,6 +3350,30 @@
"url": "https://github.com/sponsors/rawify"
}
},
"node_modules/framer-motion": {
"version": "11.0.27",
"resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-11.0.27.tgz",
"integrity": "sha512-OmY1hnBXxUfvQTuoPqumAiXYPEt8jY31Fqbmihf/NR29XUL9BkRPHrqVqtJS7TLKriwRt+0pbwiO9tnziZTJzA==",
"dependencies": {
"tslib": "^2.4.0"
},
"peerDependencies": {
"@emotion/is-prop-valid": "*",
"react": "^18.0.0",
"react-dom": "^18.0.0"
},
"peerDependenciesMeta": {
"@emotion/is-prop-valid": {
"optional": true
},
"react": {
"optional": true
},
"react-dom": {
"optional": true
}
}
},
"node_modules/fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
@ -4957,6 +5041,14 @@
"react": "^18.2.0"
}
},
"node_modules/react-icons": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.0.1.tgz",
"integrity": "sha512-WqLZJ4bLzlhmsvme6iFdgO8gfZP17rfjYEJ2m9RsZjZ+cc4k1hTzknEz63YS1MeT50kVzoa1Nz36f4BEx+Wigw==",
"peerDependencies": {
"react": "*"
}
},
"node_modules/react-is": {
"version": "16.13.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
@ -6027,6 +6119,18 @@
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
},
"node_modules/vaul": {
"version": "0.9.0",
"resolved": "https://registry.npmjs.org/vaul/-/vaul-0.9.0.tgz",
"integrity": "sha512-bZSySGbAHiTXmZychprnX/dE0EsSige88xtyyL3/MCRbrFotRPQZo7UdydGXZWw+CKbNOw5Ow8gwAo93/nB/Cg==",
"dependencies": {
"@radix-ui/react-dialog": "^1.0.4"
},
"peerDependencies": {
"react": "^16.8 || ^17.0 || ^18.0",
"react-dom": "^16.8 || ^17.0 || ^18.0"
}
},
"node_modules/which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",

View File

@ -9,20 +9,25 @@
"lint": "next lint"
},
"dependencies": {
"@iconify/react": "^4.1.1",
"@radix-ui/react-dialog": "^1.0.5",
"@radix-ui/react-dropdown-menu": "^2.0.6",
"@radix-ui/react-icons": "^1.3.0",
"@radix-ui/react-navigation-menu": "^1.1.4",
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.0",
"framer-motion": "^11.0.27",
"lucide-react": "^0.363.0",
"next": "14.1.4",
"next-themes": "^0.3.0",
"react": "^18",
"react-dom": "^18",
"react-icons": "^5.0.1",
"sharp": "^0.33.3",
"swiper": "^11.1.0",
"tailwind-merge": "^2.2.2",
"tailwindcss-animate": "^1.0.7"
"tailwindcss-animate": "^1.0.7",
"vaul": "^0.9.0"
},
"devDependencies": {
"@types/node": "^20",

BIN
public/KX3DEX_DexNet_v1.pdf Normal file

Binary file not shown.

135
yarn.lock
View File

@ -29,11 +29,11 @@ __metadata:
linkType: hard
"@emnapi/runtime@npm:^1.1.0":
version: 1.1.0
resolution: "@emnapi/runtime@npm:1.1.0"
version: 1.1.1
resolution: "@emnapi/runtime@npm:1.1.1"
dependencies:
tslib: ^2.4.0
checksum: a29917ac2ab20276c416244a0866b4628e50cb7bb9219a1bd51f48c5328d3565a78f5aa97cc81fa8fad8d06356b5274c551744da94184b2495be6b081da829c3
checksum: db5ec075a8fa71d7dbbba8592c8edfed073dfe5181a87bde56f92693985c548be5be3a66c6bd656e41b7f23d0af20d59e55684a81aecc5d2977f74ed24cbe3fe
languageName: node
linkType: hard
@ -142,6 +142,24 @@ __metadata:
languageName: node
linkType: hard
"@iconify/react@npm:^4.1.1":
version: 4.1.1
resolution: "@iconify/react@npm:4.1.1"
dependencies:
"@iconify/types": ^2.0.0
peerDependencies:
react: ">=16"
checksum: 43b71a0eb4312cf0fa7412b568369e75b8a327b8b7d9fc3dce42b2d047326e39dd17541a8d915fb80b87b20a56eba1a9b52304410624b5814fdf3ad17da9196a
languageName: node
linkType: hard
"@iconify/types@npm:^2.0.0":
version: 2.0.0
resolution: "@iconify/types@npm:2.0.0"
checksum: 029f58542c160e9d4a746869cf2e475b603424d3adf3994c5cc8d0406c47e6e04a3b898b2707840c1c5b9bd5563a1660a34b110d89fce43923baca5222f4e597
languageName: node
linkType: hard
"@img/sharp-darwin-arm64@npm:0.33.3":
version: 0.33.3
resolution: "@img/sharp-darwin-arm64@npm:0.33.3"
@ -480,15 +498,15 @@ __metadata:
linkType: hard
"@npmcli/agent@npm:^2.0.0":
version: 2.2.1
resolution: "@npmcli/agent@npm:2.2.1"
version: 2.2.2
resolution: "@npmcli/agent@npm:2.2.2"
dependencies:
agent-base: ^7.1.0
http-proxy-agent: ^7.0.0
https-proxy-agent: ^7.0.1
lru-cache: ^10.0.1
socks-proxy-agent: ^8.0.1
checksum: c69aca42dbba393f517bc5777ee872d38dc98ea0e5e93c1f6d62b82b8fecdc177a57ea045f07dda1a770c592384b2dd92a5e79e21e2a7cf51c9159466a8f9c9b
socks-proxy-agent: ^8.0.3
checksum: 67de7b88cc627a79743c88bab35e023e23daf13831a8aa4e15f998b92f5507b644d8ffc3788afc8e64423c612e0785a6a92b74782ce368f49a6746084b50d874
languageName: node
linkType: hard
@ -590,6 +608,39 @@ __metadata:
languageName: node
linkType: hard
"@radix-ui/react-dialog@npm:^1.0.4, @radix-ui/react-dialog@npm:^1.0.5":
version: 1.0.5
resolution: "@radix-ui/react-dialog@npm:1.0.5"
dependencies:
"@babel/runtime": ^7.13.10
"@radix-ui/primitive": 1.0.1
"@radix-ui/react-compose-refs": 1.0.1
"@radix-ui/react-context": 1.0.1
"@radix-ui/react-dismissable-layer": 1.0.5
"@radix-ui/react-focus-guards": 1.0.1
"@radix-ui/react-focus-scope": 1.0.4
"@radix-ui/react-id": 1.0.1
"@radix-ui/react-portal": 1.0.4
"@radix-ui/react-presence": 1.0.1
"@radix-ui/react-primitive": 1.0.3
"@radix-ui/react-slot": 1.0.2
"@radix-ui/react-use-controllable-state": 1.0.1
aria-hidden: ^1.1.1
react-remove-scroll: 2.5.5
peerDependencies:
"@types/react": "*"
"@types/react-dom": "*"
react: ^16.8 || ^17.0 || ^18.0
react-dom: ^16.8 || ^17.0 || ^18.0
peerDependenciesMeta:
"@types/react":
optional: true
"@types/react-dom":
optional: true
checksum: 3d11ca31afb794a6dd286005ab7894cb0ce7bc2de5481de98900470b11d495256401306763de030f5e35aa545ff90d34632ffd54a1b29bf55afba813be4bb84a
languageName: node
linkType: hard
"@radix-ui/react-direction@npm:1.0.1":
version: 1.0.1
resolution: "@radix-ui/react-direction@npm:1.0.1"
@ -1213,12 +1264,12 @@ __metadata:
languageName: node
linkType: hard
"agent-base@npm:^7.0.2, agent-base@npm:^7.1.0":
version: 7.1.0
resolution: "agent-base@npm:7.1.0"
"agent-base@npm:^7.0.2, agent-base@npm:^7.1.0, agent-base@npm:^7.1.1":
version: 7.1.1
resolution: "agent-base@npm:7.1.1"
dependencies:
debug: ^4.3.4
checksum: f7828f991470a0cc22cb579c86a18cbae83d8a3cbed39992ab34fc7217c4d126017f1c74d0ab66be87f71455318a8ea3e757d6a37881b8d0f2a2c6aa55e5418f
checksum: 51c158769c5c051482f9ca2e6e1ec085ac72b5a418a9b31b4e82fe6c0a6699adb94c1c42d246699a587b3335215037091c79e0de512c516f73b6ea844202f037
languageName: node
linkType: hard
@ -2509,6 +2560,26 @@ __metadata:
languageName: node
linkType: hard
"framer-motion@npm:^11.0.27":
version: 11.0.27
resolution: "framer-motion@npm:11.0.27"
dependencies:
tslib: ^2.4.0
peerDependencies:
"@emotion/is-prop-valid": "*"
react: ^18.0.0
react-dom: ^18.0.0
peerDependenciesMeta:
"@emotion/is-prop-valid":
optional: true
react:
optional: true
react-dom:
optional: true
checksum: 07809e386288350547bd9193143d9e33e6ab2d1357152b4d90acf50a445437b59ddb1653dcedde75579d3af8c7904c158fdfa6ad97d65786855eb002634bb38b
languageName: node
linkType: hard
"fs-minipass@npm:^2.0.0":
version: 2.1.0
resolution: "fs-minipass@npm:2.1.0"
@ -3295,6 +3366,8 @@ __metadata:
version: 0.0.0-use.local
resolution: "kx3dex_radio@workspace:."
dependencies:
"@iconify/react": ^4.1.1
"@radix-ui/react-dialog": ^1.0.5
"@radix-ui/react-dropdown-menu": ^2.0.6
"@radix-ui/react-icons": ^1.3.0
"@radix-ui/react-navigation-menu": ^1.1.4
@ -3306,18 +3379,21 @@ __metadata:
clsx: ^2.1.0
eslint: ^8
eslint-config-next: 14.1.4
framer-motion: ^11.0.27
lucide-react: ^0.363.0
next: 14.1.4
next-themes: ^0.3.0
postcss: ^8
react: ^18
react-dom: ^18
react-icons: ^5.0.1
sharp: ^0.33.3
swiper: ^11.1.0
tailwind-merge: ^2.2.2
tailwindcss: ^3.4.1
tailwindcss-animate: ^1.0.7
typescript: ^5
vaul: ^0.9.0
languageName: unknown
linkType: soft
@ -4120,6 +4196,15 @@ __metadata:
languageName: node
linkType: hard
"react-icons@npm:^5.0.1":
version: 5.0.1
resolution: "react-icons@npm:5.0.1"
peerDependencies:
react: "*"
checksum: e5df9c5e3bcdb8d68bd4c5e41650c26d2a3ceda61ded0e2abf7caa0e54c9fb712badcd06f0c240cfc645a5dd15a5dc1eb5dd55f60123d86860f516b1fc456474
languageName: node
linkType: hard
"react-is@npm:^16.13.1":
version: 16.13.1
resolution: "react-is@npm:16.13.1"
@ -4552,24 +4637,24 @@ __metadata:
languageName: node
linkType: hard
"socks-proxy-agent@npm:^8.0.1":
version: 8.0.2
resolution: "socks-proxy-agent@npm:8.0.2"
"socks-proxy-agent@npm:^8.0.3":
version: 8.0.3
resolution: "socks-proxy-agent@npm:8.0.3"
dependencies:
agent-base: ^7.0.2
agent-base: ^7.1.1
debug: ^4.3.4
socks: ^2.7.1
checksum: 4fb165df08f1f380881dcd887b3cdfdc1aba3797c76c1e9f51d29048be6e494c5b06d68e7aea2e23df4572428f27a3ec22b3d7c75c570c5346507433899a4b6d
checksum: 8fab38821c327c190c28f1658087bc520eb065d55bc07b4a0fdf8d1e0e7ad5d115abbb22a95f94f944723ea969dd771ad6416b1e3cde9060c4c71f705c8b85c5
languageName: node
linkType: hard
"socks@npm:^2.7.1":
version: 2.8.1
resolution: "socks@npm:2.8.1"
version: 2.8.3
resolution: "socks@npm:2.8.3"
dependencies:
ip-address: ^9.0.5
smart-buffer: ^4.2.0
checksum: 29586d42e9c36c5016632b2bcb6595e3adfbcb694b3a652c51bc8741b079c5ec37bdd5675a1a89a1620078c8137208294991fabb50786f92d47759a725b2b62e
checksum: 7a6b7f6eedf7482b9e4597d9a20e09505824208006ea8f2c49b71657427f3c137ca2ae662089baa73e1971c62322d535d9d0cf1c9235cf6f55e315c18203eadd
languageName: node
linkType: hard
@ -5095,6 +5180,18 @@ __metadata:
languageName: node
linkType: hard
"vaul@npm:^0.9.0":
version: 0.9.0
resolution: "vaul@npm:0.9.0"
dependencies:
"@radix-ui/react-dialog": ^1.0.4
peerDependencies:
react: ^16.8 || ^17.0 || ^18.0
react-dom: ^16.8 || ^17.0 || ^18.0
checksum: 12c4ced1a91400abe8d20c0c2108f2ffe7d81172eb08c3d7a24e9f813a034e00a9ddb43bb30a7ec312e71292d7b15b13d0fd9e866646b35e13b6d8bc61974198
languageName: node
linkType: hard
"which-boxed-primitive@npm:^1.0.2":
version: 1.0.2
resolution: "which-boxed-primitive@npm:1.0.2"