TopMenu.tsx (7200B)
1 import * as React from "react" 2 import Link from "next/link" 3 import { cn } from "@/lib/utils" 4 import * as NavigationMenu from '@radix-ui/react-navigation-menu'; 5 import { Menu, X, Zap } from "lucide-react" 6 import { Button } from "../ui/Button"; 7 import { DAMUS_APP_STORE_URL, DAMUS_MERCH_STORE_URL } from "@/lib/constants"; 8 import { useIntl } from "react-intl"; 9 import { AnimatePresence, motion, useScroll, useTransform } from "framer-motion"; 10 11 let regularNavItems: { nameIntlId: string, href: string, target?: string }[] = [ 12 { nameIntlId: "topbar.purple", href: "/purple" }, 13 { nameIntlId: "topbar.notedeck", href: "/notedeck" }, 14 { nameIntlId: "topbar.store", href: DAMUS_MERCH_STORE_URL, target: "_blank" }, 15 { nameIntlId: "topbar.events", href: "/#events" }, 16 { nameIntlId: "topbar.team", href: "/#team" }, 17 { nameIntlId: "topbar.contribute", href: "/#contribute" }, 18 ] 19 20 const ENABLE_FULL_MENU = true 21 22 export interface TopMenuProps { 23 className?: string 24 customCTA?: React.ReactNode 25 hideLogoOnTop?: boolean 26 } 27 28 export function TopMenu({ className, customCTA, hideLogoOnTop: hideLogoOnTop = false }: TopMenuProps) { 29 let navItemDefaultStyles = "hover:opacity-80 transition-opacity duration-200 ease-in-out" 30 const [showMobileMenu, setShowMobileMenu] = React.useState<boolean>(false) 31 const ref = React.useRef(null) 32 const { scrollYProgress } = useScroll({ 33 target: ref, 34 offset: ["start start", "end start"] 35 }) 36 const logoOpacity = useTransform(scrollYProgress, [0.1, 0.5], [hideLogoOnTop ? 0.0 : 1.0, 1.0]); 37 const menuBgColor = useTransform(scrollYProgress, [0.1, 0.5], ["rgba(0,0,0,0)", "rgba(0,0,0,0.5)"]); 38 const intl = useIntl() 39 40 // This is needed to allow intl commands to extract the strings 41 const topbarItemNameIntl: Record<string, string> = { 42 "topbar.purple": intl.formatMessage({ id: "topbar.purple", defaultMessage: "Purple" }), 43 "topbar.notedeck": intl.formatMessage({ id: "topbar.notedeck", defaultMessage: "Notedeck" }), 44 "topbar.store": intl.formatMessage({ id: "topbar.store", defaultMessage: "Store" }), 45 "topbar.events": intl.formatMessage({ id: "topbar.events", defaultMessage: "Events" }), 46 "topbar.team": intl.formatMessage({ id: "topbar.team", defaultMessage: "Our Team" }), 47 "topbar.contribute": intl.formatMessage({ id: "topbar.contribute", defaultMessage: "Contribute" }), 48 } 49 50 return (<> 51 <div ref={ref} className="absolute top-0 h-screen bg-transparent pointer-events-none w-4 left-0" /> 52 <motion.div 53 style={{ 54 opacity: 0, 55 backgroundColor: showMobileMenu ? "rgba(0,0,0,0.5)" : menuBgColor, 56 borderColor: showMobileMenu ? "rgba(0,0,0,0.5)" : menuBgColor, 57 }} 58 animate={{ opacity: 1, transition: { delay: 1.5, duration: 1 } }} 59 className="w-full border-b z-50 backdrop-blur-sm fixed" 60 > 61 <NavigationMenu.Root className={cn("flex flex-col items-center z-50", className)}> 62 <div className="container justify-between items-center flex p-6"> 63 <motion.div 64 style={{ opacity: logoOpacity }} 65 > 66 <NavigationMenu.Link className={cn(navItemDefaultStyles, "text-white")} href="/"> 67 <img src="/logo_icon_2.png" className="h-12" alt={ intl.formatMessage({ id: "topbar.logo_alt_text", defaultMessage: "Damus logo" }) }/> 68 </NavigationMenu.Link> 69 </motion.div> 70 <div className="hidden lg:block"> 71 <NavigationMenu.List className={cn("inline-flex space-x-6 items-center justify-self-center")}> 72 {ENABLE_FULL_MENU && (<> 73 {regularNavItems.map((item, index) => ( 74 <NavigationMenu.Item key={index}> 75 <NavigationMenu.Link className={cn(navItemDefaultStyles, "text-white")} href={item.href} target={item.target}> 76 {topbarItemNameIntl[item.nameIntlId]} 77 </NavigationMenu.Link> 78 </NavigationMenu.Item> 79 ))} 80 <NavigationMenu.Item> 81 <NavigationMenu.Link className={cn("text-yellow-500 flex items-center")} href="lightning:lnurl1dp68gurn8ghj7um9dej8xct5wvhxcmmv9uh8wetvdskkkmn0wahz7mrww4excup0v3sk6atnjmrn5a" target="_blank"> 82 <Zap className="h-4"/> 83 { intl.formatMessage({ id: "topbar.zap_us", defaultMessage: "Zap Us" }) } 84 </NavigationMenu.Link> 85 </NavigationMenu.Item> 86 </>)} 87 </NavigationMenu.List> 88 </div> 89 <div className="hidden lg:block"> 90 {customCTA ? customCTA : <> 91 <Link href={DAMUS_APP_STORE_URL} target="_blank" className="hidden lg:block"> 92 <Button variant="accent"> 93 {intl.formatMessage({ id: "topbar.download", defaultMessage: "Download" })} 94 </Button> 95 </Link> 96 </>} 97 </div> 98 <button className="lg:hidden" onClick={() => setShowMobileMenu(!showMobileMenu)}> 99 {showMobileMenu ? <X className="h-8 text-white"/> : <Menu className="h-8 text-white"/>} 100 </button> 101 </div> 102 <AnimatePresence> 103 {showMobileMenu && ( 104 <motion.div className="lg:hidden container flex justify-end mb-6" key="mobile-menu"> 105 <NavigationMenu.List className={cn("flex flex-col gap-6 justify-start items-end text-3xl font-bold p-6")}> 106 {ENABLE_FULL_MENU && (<> 107 {regularNavItems.map((item, index) => ( 108 <NavigationMenu.Item key={index}> 109 <NavigationMenu.Link className={cn(navItemDefaultStyles, "text-white")} href={item.href} target={item.target}> 110 {topbarItemNameIntl[item.nameIntlId]} 111 </NavigationMenu.Link> 112 </NavigationMenu.Item> 113 ))} 114 <NavigationMenu.Item> 115 <NavigationMenu.Link className={cn("text-yellow-500 flex items-center")} href="lightning:lnurl1dp68gurn8ghj7um9dej8xct5wvhxcmmv9uh8wetvdskkkmn0wahz7mrww4excup0v3sk6atnjmrn5a" target="_blank"> 116 <Zap className="h-4"/> 117 { intl.formatMessage({ id: "topbar.zap_us", defaultMessage: "Zap Us" }) } 118 </NavigationMenu.Link> 119 </NavigationMenu.Item> 120 </>)} 121 </NavigationMenu.List> 122 </motion.div> 123 )} 124 </AnimatePresence> 125 </NavigationMenu.Root> 126 </motion.div> 127 </>) 128 }