277 lines
8.7 KiB
TypeScript
277 lines
8.7 KiB
TypeScript
'use client';
|
|
import { useState, useContext } from 'react';
|
|
import { usePathname } from 'next/navigation';
|
|
import Image from 'next/image';
|
|
import {
|
|
Navbar,
|
|
NavbarContent,
|
|
NavbarMenu,
|
|
NavbarMenuToggle,
|
|
NavbarBrand,
|
|
NavbarItem,
|
|
Link as NextUiLink,
|
|
ListboxItem,
|
|
Listbox,
|
|
} from '@heroui/react';
|
|
import { ArrowRightFromLine, ArrowRightToLine, File, Globe, MoveUpRight, PenTool, Settings } from 'lucide-react';
|
|
import DropdownAccount from './DropdownAccount';
|
|
import DropdownLanguage from './DropdownLanguage';
|
|
import { ThemeSwitch } from '@/components/ThemeSwitch';
|
|
import { GithubIcon } from '@/components/icons';
|
|
import { locales } from '@/config/selection';
|
|
import { Link, useRouter } from '@/src/i18n/routing';
|
|
import { TokenContext } from '@/utils/TokenProvider';
|
|
import UserAvatar from '@/components/UserAvatar';
|
|
import { LocaleCodeType } from '@/types/locale';
|
|
import Config from '@/config/config';
|
|
|
|
type NabbarMenuMessages = {
|
|
projects: string;
|
|
admin: string;
|
|
docs: string;
|
|
roadmap: string;
|
|
account: string;
|
|
profileSettings: string;
|
|
signUp: string;
|
|
signIn: string;
|
|
signOut: string;
|
|
links: string;
|
|
languages: string;
|
|
};
|
|
|
|
type Props = {
|
|
messages: NabbarMenuMessages;
|
|
locale: LocaleCodeType;
|
|
};
|
|
|
|
export default function HeaderNavbarMenu({ messages, locale }: Props) {
|
|
const [isMenuOpen, setIsMenuOpen] = useState(false);
|
|
const context = useContext(TokenContext);
|
|
|
|
const commonLinks = [
|
|
{
|
|
uid: 'projects',
|
|
href: '/projects',
|
|
label: messages.projects,
|
|
isExternal: false,
|
|
},
|
|
];
|
|
|
|
if (Config.isDemoSite) {
|
|
commonLinks.push(
|
|
{
|
|
uid: 'docs',
|
|
href: 'https://kimatata.github.io/unittcms/docs/getstarted/selfhost',
|
|
label: messages.docs,
|
|
isExternal: true,
|
|
},
|
|
{
|
|
uid: 'roadmap',
|
|
href: 'https://kimatata.github.io/unittcms/docs/roadmap/',
|
|
label: messages.roadmap,
|
|
isExternal: true,
|
|
}
|
|
);
|
|
}
|
|
|
|
const router = useRouter();
|
|
const pathname = usePathname();
|
|
async function changeLocale(nextLocale: string) {
|
|
let newPathname;
|
|
if (pathname.length < 4) {
|
|
// when root path
|
|
router.push('/', { locale: nextLocale });
|
|
} else {
|
|
// when not root path, trim first "/en" from pathname = "/en/projects"
|
|
newPathname = pathname.slice(locale.length + 1);
|
|
router.push(newPathname, { locale: nextLocale });
|
|
}
|
|
}
|
|
|
|
return (
|
|
<Navbar isMenuOpen={isMenuOpen} maxWidth="full" position="sticky" className="bg-inherit">
|
|
<NavbarContent className="basis-1/5 sm:basis-full" justify="start">
|
|
<NavbarBrand as="li" className="gap-3 max-w-fit">
|
|
<Link className="flex justify-start items-center gap-1" href="/" locale={locale}>
|
|
<Image src="/favicon/icon-192.png" width={32} height={32} alt="Logo" />
|
|
<p className="font-bold text-inherit ms-1">UnitTCMS</p>
|
|
</Link>
|
|
</NavbarBrand>
|
|
{commonLinks.map((link) =>
|
|
link.isExternal ? (
|
|
<NavbarItem key={link.uid} className="hidden md:block">
|
|
<NextUiLink isExternal href={link.href} showAnchorIcon>
|
|
{link.label}
|
|
</NextUiLink>
|
|
</NavbarItem>
|
|
) : (
|
|
<NavbarItem key={link.uid} className="hidden md:block">
|
|
<Link
|
|
className="data-[active=true]:text-primary data-[active=true]:font-medium"
|
|
href={link.href}
|
|
locale={locale}
|
|
>
|
|
{link.label}
|
|
</Link>
|
|
</NavbarItem>
|
|
)
|
|
)}
|
|
{context.isAdmin() && (
|
|
<NavbarItem key="admin" className="hidden md:block">
|
|
<Link
|
|
className="data-[active=true]:text-primary data-[active=true]:font-medium"
|
|
href="/admin"
|
|
locale={locale}
|
|
>
|
|
{messages.admin}
|
|
</Link>
|
|
</NavbarItem>
|
|
)}
|
|
</NavbarContent>
|
|
|
|
<NavbarContent className="basis-1 pl-4" justify="end">
|
|
<NextUiLink isExternal href="https://github.com/kimatata/unittcms" aria-label="Github">
|
|
<GithubIcon className="text-default-500" />
|
|
</NextUiLink>
|
|
<ThemeSwitch />
|
|
<div className="hidden md:block">
|
|
<DropdownAccount messages={messages} locale={locale} onItemPress={() => {}} />
|
|
<DropdownLanguage locale={locale} onChangeLocale={changeLocale} />
|
|
</div>
|
|
<NavbarMenuToggle className="md:hidden" onChange={() => setIsMenuOpen(!isMenuOpen)} />
|
|
</NavbarContent>
|
|
|
|
<NavbarMenu>
|
|
<div className="mx-4 mt-2 flex flex-col gap-2">
|
|
<p className="font-bold">{messages.links}</p>
|
|
<Listbox
|
|
aria-label="Links"
|
|
itemClasses={{
|
|
base: 'h-10 text-large',
|
|
}}
|
|
>
|
|
{commonLinks.map((link) =>
|
|
link.isExternal ? (
|
|
<ListboxItem
|
|
key={link.uid}
|
|
title={link.label}
|
|
startContent={<MoveUpRight size={12} />}
|
|
onPress={() => {
|
|
window.open(link.href, '_blank');
|
|
setIsMenuOpen(false);
|
|
}}
|
|
/>
|
|
) : (
|
|
<ListboxItem
|
|
key={link.uid}
|
|
title={link.label}
|
|
startContent={<File size={12} />}
|
|
onPress={() => {
|
|
router.push(link.href, { locale: locale });
|
|
setIsMenuOpen(false);
|
|
}}
|
|
/>
|
|
)
|
|
)}
|
|
</Listbox>
|
|
|
|
<p className="font-bold">{messages.account}</p>
|
|
{context.isSignedIn() ? (
|
|
<Listbox
|
|
aria-label="Account links"
|
|
itemClasses={{
|
|
base: 'h-10 text-large',
|
|
}}
|
|
>
|
|
<ListboxItem
|
|
key="account"
|
|
title={messages.account}
|
|
startContent={
|
|
<UserAvatar
|
|
size={16}
|
|
username={context.token?.user?.username}
|
|
avatarPath={context.token?.user?.avatarPath}
|
|
/>
|
|
}
|
|
onPress={() => {
|
|
router.push('/account', { locale: locale });
|
|
setIsMenuOpen(false);
|
|
}}
|
|
/>
|
|
<ListboxItem
|
|
key="profile"
|
|
title={messages.profileSettings}
|
|
startContent={<Settings size={16} />}
|
|
onPress={() => {
|
|
router.push('/account/settings', { locale: locale });
|
|
setIsMenuOpen(false);
|
|
}}
|
|
/>
|
|
<ListboxItem
|
|
key="signout"
|
|
title={messages.signOut}
|
|
startContent={<ArrowRightFromLine size={16} />}
|
|
onPress={() => {
|
|
context.setToken({
|
|
access_token: '',
|
|
expires_at: 0,
|
|
user: null,
|
|
});
|
|
context.removeTokenFromLocalStorage();
|
|
router.push(`/account/signin`, { locale: locale });
|
|
setIsMenuOpen(false);
|
|
}}
|
|
/>
|
|
</Listbox>
|
|
) : (
|
|
<Listbox
|
|
aria-label="Account links"
|
|
itemClasses={{
|
|
base: 'h-10 text-large',
|
|
}}
|
|
>
|
|
<ListboxItem
|
|
key="signin"
|
|
startContent={<ArrowRightToLine size={16} />}
|
|
title={messages.signIn}
|
|
onPress={() => {
|
|
router.push('/account/signin', { locale: locale });
|
|
setIsMenuOpen(false);
|
|
}}
|
|
/>
|
|
<ListboxItem
|
|
key="signup"
|
|
title={messages.signUp}
|
|
startContent={<PenTool size={16} />}
|
|
onPress={() => {
|
|
router.push('/account/signup', { locale: locale });
|
|
setIsMenuOpen(false);
|
|
}}
|
|
/>
|
|
</Listbox>
|
|
)}
|
|
<p className="font-bold">{messages.languages}</p>
|
|
<Listbox
|
|
aria-label="Language links"
|
|
itemClasses={{
|
|
base: 'h-10 text-large',
|
|
}}
|
|
>
|
|
{locales.map((entry) => (
|
|
<ListboxItem
|
|
key={entry.code}
|
|
startContent={<Globe size={16} />}
|
|
title={entry.name}
|
|
onPress={() => {
|
|
changeLocale(entry.code);
|
|
setIsMenuOpen(false);
|
|
}}
|
|
/>
|
|
))}
|
|
</Listbox>
|
|
</div>
|
|
</NavbarMenu>
|
|
</Navbar>
|
|
);
|
|
}
|