Fix Sidenav

This commit is contained in:
Théo 2023-02-06 21:41:35 +01:00
parent 16252ee5a2
commit 18d1d82659
4 changed files with 107 additions and 133 deletions

View file

@ -1,6 +1,16 @@
import Wrapper from '@/ui/dashboard/Wrapper';
import { type ReactNode } from 'react';
import Sidenav from '@/ui/dashboard/Sidenav';
export default function Layout({ children }: { children: ReactNode }) {
return <Wrapper>{children}</Wrapper>;
return (
<div className="flex h-screen flex-col">
<div className="flex flex-1 flex-col overflow-hidden sm:flex-row">
<Sidenav />
<div className="mx-4 flex flex-1 transform flex-col pt-4 pb-8 duration-300 ease-in-out sm:mx-auto sm:py-8 md:max-w-6xl">
{children}
</div>
</div>
</div>
);
}

BIN
public/logo.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

View file

@ -1,77 +1,111 @@
'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 { useState } from 'react';
import Logo from '../../public/logo.webp';
import AppLink from '../AppLink';
import Icon from '../Icon';
export default function Sidenav({
onClick,
width,
isOpen
}: {
onClick: () => void;
width: number;
isOpen: boolean;
}) {
export default function Sidenav() {
const [isOpen, setIsOpen] = useState(false);
function toggleSidenav() {
setIsOpen(!isOpen);
}
return (
(width >= 640 && (
<aside
className={cn(
'hidden fixed top-0 left-0 z-10 h-full space-y-4 bg-dark shadow-md transition-all duration-300 ease-in-out sm:block',
isOpen ? 'w-60' : 'w-24 '
'relative flex h-24 flex-row justify-between bg-dark shadow-md transition-all duration-300 ease-in-out sm:h-screen sm:flex-col',
{
'sm:w-60': isOpen,
'w-full sm:w-28': !isOpen
}
)}
>
<div className="px-8 pt-4">
<div className="mx-auto items-center">
<button onClick={onClick} className="flex h-10 w-full items-center space-x-2">
<div className="flex flex-row sm:flex-col">
<div className="flex px-4 pt-0 sm:block sm:items-center sm:pt-4">
<div className="flex items-center justify-between">
<AppLink href="/" className="hidden sm:block">
<Image src={Logo} alt="Peer-at Code Logo" className=" h-10 w-10" />
</AppLink>
<button
className="flex items-center justify-center rounded bg-light-dark p-1"
onClick={toggleSidenav}
>
<Icon
className={cn(
'text-xl transition-transform duration-300 ease-in-out',
isOpen ? 'rotate-180' : 'rotate-0'
)}
name="arrow-right-s-line"
name="arrow-left-line"
className={cn('transition duration-300', {
'rotate-0': isOpen,
'rotate-180': !isOpen
})}
/>
<span
className={cn(
'text-xl font-semibold transition',
isOpen ? 'duration-400 opacity-100 delay-150' : 'opacity-0'
)}
>
Peer-at-Code
</span>
</button>
</div>
</div>
<hr className="mx-auto w-1/2 pb-4" />
<ul
className={cn(
'relative flex flex-col space-y-4 transition-all duration-300 ease-in-out',
isOpen ? ' px-8' : 'px-4'
)}
>
<div className="hidden px-4 pt-4 sm:block">
<hr className="border-light-dark" />
</div>
<div className="hidden px-4 pt-4 sm:block">
<ul className="space-y-4">
{navItems.map((item) => (
<li className="relative" key={item.slug}>
<li key={item.slug}>
<NavItem item={item} isOpen={isOpen} />
</li>
))}
</ul>
<div
className={cn(
'absolute bottom-5 flex w-full items-center text-center',
isOpen ? 'px-8' : 'px-4'
)}
>
<button
className={cn(
'mx-auto w-full truncate rounded-md bg-light-dark py-3 transition-all duration-300 ease-in-out hover:bg-light-dark/60'
)}
>
<span className="text-sm font-semibold">Session ici</span>
</div>
</div>
<div className="flex flex-row sm:flex-col">
<div className="px-4 py-4">
<button className="flex w-full items-center space-x-2 truncate rounded bg-light-dark p-3">
<Icon className="text-2xl" name="user-line" />
<span className="truncate">Hacktiviste</span>
</button>
</div>
</div>
</aside>
)) || (
<aside
);
}
function NavItem({ item, isOpen }: { item: NavItem; isOpen: boolean }) {
const segment = useSelectedLayoutSegment();
const isActive = segment?.split('/').pop() === item.slug || (item.slug === '' && !segment);
return (
<AppLink
href={item.disabled ? '/dashboard' : `/dashboard/${item.slug}`}
className={cn('flex rounded-md px-3 py-3 text-sm font-medium', {
'bg-light-dark text-gray-400 hover:bg-light-dark/60 hover:text-white': !isActive,
'bg-blue-500 text-white': isActive,
'text-gray-600 hover:text-gray-600': item.disabled,
'justify-start': isOpen,
'justify-center': !isOpen
})}
passHref
>
<div
className={cn('flex items-center', {
'space-x-2': isOpen
})}
>
<Icon className="text-2xl" name={item.icon} />
<span
className={cn({
hidden: !isOpen
})}
>
{item.name}
</span>
</div>
</AppLink>
);
}
{
/* <aside
className={cn(
'fixed top-0 z-10 w-full bg-dark shadow-md transition-all duration-300 ease-in-out sm:block md:hidden'
)}
@ -108,32 +142,5 @@ export default function Sidenav({
))}
</ul>
</div>
</aside>
)
);
}
function NavItem({ item, isOpen }: { item: NavItem; isOpen: boolean }) {
const segment = useSelectedLayoutSegment();
const isActive = segment?.split('/').pop() === item.slug || (item.slug === '' && !segment);
return (
<AppLink
href={item.disabled ? '/dashboard' : `/dashboard/${item.slug}`}
className={cn(
'flex rounded-md px-3 py-3 text-sm font-medium transition duration-300 ease-in-out',
{
'bg-light-dark text-gray-400 hover:bg-light-dark/60': !isActive,
'bg-blue-500 text-white': isActive,
'text-gray-600 hover:text-gray-600': item.disabled,
'justify-center': !isOpen
}
)}
passHref
>
<div className={cn('flex items-center', isOpen && 'space-x-4')}>
<Icon className="text-2xl" name={item.icon} />
<span className={cn(isOpen ? 'block' : 'hidden')}>{item.name}</span>
</div>
</AppLink>
);
</aside> */
}

View file

@ -1,43 +0,0 @@
'use client';
import { cn } from '@/lib/utils';
import { useCallback, useEffect, useState, type ReactNode } from 'react';
import Sidenav from './Sidenav';
export default function Wrapper({ children }: { children: ReactNode }) {
const [isOpen, setIsOpen] = useState(false);
const [width, setWidth] = useState(0);
function toggleSidenav() {
setIsOpen(!isOpen);
}
function useWidth() {
const handleResize = useCallback(() => setWidth(window.innerWidth), []);
useEffect(() => {
handleResize();
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
}, [handleResize]);
return width;
}
return (
<div
className={cn(
'relative min-h-screen transition-all duration-300 ease-in-out',
isOpen ? 'sm:pl-60' : 'sm:pl-24'
)}
>
<Sidenav onClick={toggleSidenav} width={useWidth()} isOpen={isOpen} />
<div
className={cn(
'mx-auto h-screen w-full transform px-2 pt-24 pb-8 duration-300 ease-in-out sm:px-0 sm:py-8',
isOpen ? 'md:max-w-6xl' : 'md:max-w-7xl'
)}
>
{children}
</div>
</div>
);
}