prmbr-image-mksaas/src/components/layout/navbar.tsx

244 lines
11 KiB
TypeScript

'use client';
import { LoginWrapper } from '@/components/auth/login-wrapper';
import Container from '@/components/shared/container';
import { ModeSwitcher } from '@/components/layout/mode-switcher';
import { NavbarMobile } from '@/components/layout/navbar-mobile';
import { UserButton } from '@/components/layout/user-button';
import { Logo } from '@/components/shared/logo';
import { Button } from '@/components/ui/button';
import {
NavigationMenu,
NavigationMenuContent,
NavigationMenuItem,
NavigationMenuLink,
NavigationMenuList,
NavigationMenuTrigger,
navigationMenuTriggerStyle,
} from '@/components/ui/navigation-menu';
import { getMenuLinks } from '@/config';
import { useCurrentUser } from '@/hooks/use-current-user';
import { useScroll } from '@/hooks/use-scroll';
import { LocaleLink, useLocalePathname } from '@/i18n/navigation';
import { cn } from '@/lib/utils';
import { Routes } from '@/routes';
import { ArrowUpRightIcon } from 'lucide-react';
import { useTranslations } from 'next-intl';
import LocaleSwitcher from './locale-switcher';
interface NavBarProps {
scroll?: boolean;
}
const customNavigationMenuTriggerStyle = cn(
navigationMenuTriggerStyle(),
'relative bg-transparent text-muted-foreground cursor-pointer',
'hover:bg-accent hover:text-accent-foreground',
'focus:bg-accent focus:text-accent-foreground',
'data-active:font-semibold data-active:bg-transparent data-active:text-foreground',
'data-[state=open]:bg-transparent data-[state=open]:text-foreground'
);
export function Navbar({ scroll }: NavBarProps) {
const t = useTranslations();
const scrolled = useScroll(50);
const menuLinks = getMenuLinks();
const localePathname = useLocalePathname();
const currentUser = useCurrentUser();
// console.log(`Navbar, user:`, user);
return (
<section
className={cn(
'sticky inset-x-0 top-0 z-40 py-4 transition-all duration-300',
scroll
? scrolled
? 'bg-background/80 backdrop-blur-md border-b supports-backdrop-filter:bg-background/60'
: 'bg-background'
: 'border-b bg-background'
)}
>
<Container className="px-4">
{/* desktop navbar */}
<nav className="hidden lg:flex">
{/* logo and name */}
<div className="flex items-center">
<LocaleLink href="/" className="flex items-center space-x-2">
<Logo />
<span className="text-xl font-semibold">
{t('Metadata.name')}
</span>
</LocaleLink>
</div>
{/* menu links */}
<div className="flex-1 flex items-center justify-center space-x-2">
<NavigationMenu className="relative">
<NavigationMenuList className="flex items-center">
{menuLinks &&
menuLinks.map((item, index) =>
item.items ? (
<NavigationMenuItem key={index} className="relative">
<NavigationMenuTrigger
data-active={
item.items.some((subItem) =>
subItem.href
? localePathname.startsWith(subItem.href)
: false
)
? 'true'
: undefined
}
className={customNavigationMenuTriggerStyle}
>
{item.title}
</NavigationMenuTrigger>
<NavigationMenuContent>
<ul className="grid w-[400px] gap-4 p-4 md:w-[500px] md:grid-cols-2 lg:w-[600px]">
{item.items &&
item.items.map((subItem, subIndex) => {
const isSubItemActive =
subItem.href &&
localePathname.startsWith(subItem.href);
return (
<li key={subIndex}>
<NavigationMenuLink asChild>
<LocaleLink
href={subItem.href || '#'}
target={
subItem.external
? '_blank'
: undefined
}
rel={
subItem.external
? 'noopener noreferrer'
: undefined
}
className={cn(
'group flex select-none flex-row items-center gap-4 rounded-md',
'p-2 leading-none no-underline outline-hidden transition-colors',
'hover:bg-accent hover:text-accent-foreground',
'focus:bg-accent focus:text-accent-foreground',
isSubItemActive &&
'bg-accent text-accent-foreground'
)}
>
<div
className={cn(
'flex size-8 shrink-0 items-center justify-center transition-colors',
'bg-transparent text-muted-foreground',
'group-hover:bg-transparent group-hover:text-foreground',
'group-focus:bg-transparent group-focus:text-foreground',
isSubItemActive &&
'bg-transparent text-foreground'
)}
>
{subItem.icon ? subItem.icon : null}
</div>
<div className="flex-1">
<div
className={cn(
'text-sm font-medium text-muted-foreground',
'group-hover:bg-transparent group-hover:text-foreground',
'group-focus:bg-transparent group-focus:text-foreground',
isSubItemActive &&
'bg-transparent text-foreground'
)}
>
{subItem.title}
</div>
{subItem.description && (
<div
className={cn(
'text-sm text-muted-foreground',
'group-hover:bg-transparent group-hover:text-foreground/80',
'group-focus:bg-transparent group-focus:text-foreground/80',
isSubItemActive &&
'bg-transparent text-foreground/80'
)}
>
{subItem.description}
</div>
)}
</div>
{subItem.external && (
<ArrowUpRightIcon
className={cn(
'size-4 shrink-0 text-muted-foreground',
'group-hover:bg-transparent group-hover:text-foreground',
'group-focus:bg-transparent group-focus:text-foreground',
isSubItemActive &&
'bg-transparent text-foreground'
)}
/>
)}
</LocaleLink>
</NavigationMenuLink>
</li>
);
})}
</ul>
</NavigationMenuContent>
</NavigationMenuItem>
) : (
<NavigationMenuItem key={index}>
<NavigationMenuLink
asChild
active={
item.href
? localePathname.startsWith(item.href)
: false
}
className={customNavigationMenuTriggerStyle}
>
<LocaleLink
href={item.href || '#'}
target={item.external ? '_blank' : undefined}
rel={
item.external ? 'noopener noreferrer' : undefined
}
>
{item.title}
</LocaleLink>
</NavigationMenuLink>
</NavigationMenuItem>
)
)}
</NavigationMenuList>
</NavigationMenu>
</div>
{/* navbar right show sign in or user */}
<div className="flex items-center gap-x-4">
{currentUser ? (
<UserButton user={currentUser} />
) : (
<div className="flex items-center gap-x-4">
<LoginWrapper mode="modal" asChild>
<Button variant="outline" size="sm" className="cursor-pointer">
{t('Common.login')}
</Button>
</LoginWrapper>
<Button asChild size="sm" variant="default">
<LocaleLink href={Routes.Register}>
{t('Common.signUp')}
</LocaleLink>
</Button>
</div>
)}
<ModeSwitcher />
<LocaleSwitcher />
</div>
</nav>
{/* mobile navbar */}
<NavbarMobile className="lg:hidden" />
</Container>
</section>
);
}