Hey is a decentralized and permissionless social media app built with Lens Protocol 馃尶
at main 131 lines 3.7 kB view raw
1import { 2 BellIcon, 3 GlobeAltIcon as GlobeOutline, 4 HomeIcon, 5 MagnifyingGlassIcon 6} from "@heroicons/react/24/outline"; 7import { 8 BellIcon as BellIconSolid, 9 GlobeAltIcon as GlobeSolid, 10 HomeIcon as HomeIconSolid 11} from "@heroicons/react/24/solid"; 12import getAvatar from "@hey/helpers/getAvatar"; 13import type { MouseEvent, ReactNode } from "react"; 14import { Link, useLocation } from "react-router"; 15import { Image } from "@/components/Shared/UI"; 16import useHasNewNotifications from "@/hooks/useHasNewNotifications"; 17import { useMobileDrawerModalStore } from "@/store/non-persisted/modal/useMobileDrawerModalStore"; 18import { useAccountStore } from "@/store/persisted/useAccountStore"; 19import MobileDrawerMenu from "./MobileDrawerMenu"; 20 21interface NavigationItemProps { 22 path: string; 23 label: string; 24 outline: ReactNode; 25 solid: ReactNode; 26 isActive: boolean; 27 onClick?: (e: MouseEvent) => void; 28 showIndicator?: boolean; 29} 30 31const NavigationItem = ({ 32 path, 33 label, 34 outline, 35 solid, 36 isActive, 37 onClick, 38 showIndicator 39}: NavigationItemProps) => ( 40 <Link 41 aria-label={label} 42 className="relative mx-auto my-3" 43 onClick={onClick} 44 to={path} 45 > 46 {isActive ? solid : outline} 47 {showIndicator && ( 48 <span className="-right-1 -top-1 absolute size-2 rounded-full bg-red-500" /> 49 )} 50 </Link> 51); 52 53const BottomNavigation = () => { 54 const { pathname } = useLocation(); 55 const { currentAccount } = useAccountStore(); 56 const { show: showMobileDrawer, setShow: setShowMobileDrawer } = 57 useMobileDrawerModalStore(); 58 const hasNewNotifications = useHasNewNotifications(); 59 60 const handleAccountClick = () => setShowMobileDrawer(true); 61 62 const handleHomClick = (path: string, e: MouseEvent) => { 63 if (path === "/" && pathname === "/") { 64 e.preventDefault(); 65 window.scrollTo(0, 0); 66 } 67 }; 68 69 const navigationItems = [ 70 { 71 label: "Home", 72 outline: <HomeIcon className="size-6" />, 73 path: "/", 74 solid: <HomeIconSolid className="size-6" /> 75 }, 76 { 77 label: "Search", 78 outline: <MagnifyingGlassIcon className="size-6" />, 79 path: "/search", 80 solid: <MagnifyingGlassIcon className="size-6" /> 81 }, 82 { 83 label: "Explore", 84 outline: <GlobeOutline className="size-6" />, 85 path: "/explore", 86 solid: <GlobeSolid className="size-6" /> 87 }, 88 { 89 label: "Notifications", 90 outline: <BellIcon className="size-6" />, 91 path: "/notifications", 92 solid: <BellIconSolid className="size-6" /> 93 } 94 ]; 95 96 return ( 97 <nav className="fixed inset-x-0 bottom-0 z-[5] border-gray-200 border-t bg-white pb-safe md:hidden dark:border-gray-800 dark:bg-black"> 98 {showMobileDrawer && <MobileDrawerMenu />} 99 <div className="flex justify-between"> 100 {navigationItems.map(({ path, label, outline, solid }) => ( 101 <NavigationItem 102 isActive={pathname === path} 103 key={path} 104 label={label} 105 onClick={(e) => handleHomClick(path, e)} 106 outline={outline} 107 path={path} 108 showIndicator={hasNewNotifications && path === "/notifications"} 109 solid={solid} 110 /> 111 ))} 112 {currentAccount && ( 113 <button 114 aria-label="Your account" 115 className="m-auto h-fit" 116 onClick={handleAccountClick} 117 type="button" 118 > 119 <Image 120 alt={currentAccount.address} 121 className="m-0.5 size-6 rounded-full border border-gray-200 dark:border-gray-700" 122 src={getAvatar(currentAccount)} 123 /> 124 </button> 125 )} 126 </div> 127 </nav> 128 ); 129}; 130 131export default BottomNavigation;