124 lines
3.7 KiB
TypeScript
124 lines
3.7 KiB
TypeScript
'use client';
|
|
|
|
import { NavItem, navItems } from '@/lib/nav-items';
|
|
import { cn } from '@/lib/utils';
|
|
import Image from 'next/image';
|
|
import { useSelectedLayoutSegment } from 'next/navigation';
|
|
import AppLink from '../AppLink';
|
|
import Icon from '../Icon';
|
|
|
|
export default function Sidenav({ isOpen, toggle }: { isOpen: boolean; toggle: () => void }) {
|
|
return (
|
|
<aside
|
|
className={cn(
|
|
'absolute z-10 h-screen w-28 border-r border-highlight-primary bg-gradient-to-b from-primary-800 to-primary-900 shadow-md transition-all duration-300 ease-in-out sm:relative sm:flex sm:flex-col lg:w-60',
|
|
{
|
|
'bottom-0 -translate-x-full sm:translate-x-0': !isOpen,
|
|
'bottom-0 w-full sm:w-28': isOpen
|
|
}
|
|
)}
|
|
>
|
|
<div className="flex h-full flex-col">
|
|
<div className="flex w-full justify-center p-[9px]">
|
|
<AppLink href="/">
|
|
<Image
|
|
title="Logo"
|
|
src="/assets/brand/peerat.png"
|
|
alt="Peer-at"
|
|
width={50}
|
|
height={50}
|
|
loading="eager"
|
|
priority
|
|
/>
|
|
</AppLink>
|
|
</div>
|
|
<div className="px-4">
|
|
<hr className="border-highlight-primary" />
|
|
</div>
|
|
<div className="px-4 pt-4">
|
|
<ul className="space-y-4">
|
|
{navItems.map((item) => (
|
|
<li key={item.slug}>
|
|
<NavItem item={item} isOpen={isOpen} onClick={toggle} />
|
|
</li>
|
|
))}
|
|
</ul>
|
|
</div>
|
|
<div className="px-4 pt-4">
|
|
<hr className="border-highlight-primary" />
|
|
</div>
|
|
<div className="px-4 pt-4">
|
|
<ul className="space-y-4">
|
|
<li>
|
|
<NavItem
|
|
item={{
|
|
name: 'Discord',
|
|
slug: 'https://discord.gg/72vuHcwUkE',
|
|
icon: 'discord-fill',
|
|
disabled: false
|
|
}}
|
|
isOpen={isOpen}
|
|
onClick={toggle}
|
|
/>
|
|
</li>
|
|
<li>
|
|
<NavItem
|
|
item={{
|
|
name: 'Git',
|
|
slug: 'https://git.peerat.dev/Peer-at-Code',
|
|
icon: 'git-repository-line',
|
|
disabled: false
|
|
}}
|
|
isOpen={isOpen}
|
|
onClick={toggle}
|
|
/>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</aside>
|
|
);
|
|
}
|
|
|
|
function NavItem({
|
|
item,
|
|
isOpen,
|
|
onClick
|
|
}: {
|
|
item: NavItem;
|
|
isOpen: boolean;
|
|
onClick?: () => void;
|
|
}) {
|
|
const segment = useSelectedLayoutSegment();
|
|
const pathname = segment?.split('/').pop() || '';
|
|
const isHttp = item.slug.includes('http');
|
|
const isActive = pathname === item.slug || (item.slug === '' && !segment);
|
|
return (
|
|
<AppLink
|
|
aria-disabled={item.disabled}
|
|
href={isHttp ? item.slug : `dashboard/${item.slug}`}
|
|
target={isHttp ? '_blank' : undefined}
|
|
rel={isHttp ? 'noopener noreferrer' : undefined}
|
|
className={cn('flex justify-center rounded-md px-3 py-3 text-sm lg:justify-start', {
|
|
'text-muted hover:text-secondary': !isActive,
|
|
'bg-highlight-primary text-secondary': isActive,
|
|
'cursor-not-allowed text-gray-600 hover:text-gray-600': item.disabled,
|
|
'justify-center lg:justify-start': isOpen,
|
|
'justify-start sm:justify-center': !isOpen
|
|
})}
|
|
onClick={onClick}
|
|
>
|
|
<div className="flex items-center space-x-2">
|
|
<Icon className="text-2xl" name={item.icon} />
|
|
<span
|
|
className={cn('hidden lg:block', {
|
|
'block sm:hidden': isOpen,
|
|
hidden: !isOpen
|
|
})}
|
|
>
|
|
{item.name}
|
|
</span>
|
|
</div>
|
|
</AppLink>
|
|
);
|
|
}
|