import React, { MouseEvent } from 'react' import Router from 'next/router' import { ChevronDown, MoreHorizontal, Plus } from 'lucide-react' import Text from '../Text' import Col from '../Col' import Row from '../Row' import Link from '../Link' import Image from '../Image' import { buildClassName } from '../Util' import css from './Sidebar.module.styl' import { Icon } from '../interfaces' import { Menu } from '..' interface MenuItem { path?: string icon?: Icon name: string } interface Props { /** * Logo to display */ logo?: Image['props']['imageProps'] & {height: number, width: number} /** * User Informations if loggedin */ user?: { picture?: string /** * Username */ name: string /** * User Menu */ menu?: Array } /** * Links to display */ menu: Array}> onClose?: () => boolean fullWidth?: boolean } interface State { path?: string /** * Define if the menu is open or closed * * in mobile it will be hidden when closed */ open: boolean activeMenu?: string isMobile: boolean userMenu?: boolean subMenu?: { y: number menu: Menu['props']['items'] } } /** * Sidebar Component * @version 1.0.0 */ export default class Sidebar extends React.Component { public state: State = { open: true, isMobile: false } public componentDidMount() { this.onRouteChange(Router.asPath) Router.events.on('routeChangeComplete', () => { this.onRouteChange(Router.asPath) }) Router.events.on('routeChangeError', () => { this.onRouteChange(Router.asPath) }) if (!this.props.fullWidth) { document.body.classList.add(css.sidebarBody) } document.body.addEventListener('click', this.onBodyClick) } private onRouteChange(newRoute: string) { let activeMenu = undefined for (const menu of this.props.menu) { if (newRoute === menu.path || menu.subMenu?.find((it) => newRoute === it.path)) { activeMenu = menu.name + (menu.path ?? '') } } this.setState({path: newRoute, subMenu: undefined, userMenu: false, activeMenu}) } public componentDidUpdate() { //console.log(this.state.path) if (this.state.open) { document.body.classList.remove(css.short) } else { document.body.classList.add(css.short) } } public componentWillUnmount() { document.body.classList.remove(css.short, css.sidebarBody) document.body.removeEventListener('click', this.onBodyClick) } private onBodyClick = () => { this.setState({subMenu: undefined, userMenu: false}) } public onClick = (id: string, subMenu?: Array) => (ev: MouseEvent) => { ev.stopPropagation() if (!this.state.open && subMenu) { //console.log(ev) this.setState({ subMenu: { y: (ev.currentTarget as HTMLElement).offsetTop, menu: subMenu.map((v) => ({ display: v.name, value: v.path, href: v.path, selected: this.state.path === v.path })) } }) } else { this.setState({activeMenu: this.state.activeMenu === id ? undefined : id, subMenu: undefined}) } } public render = () => ( <> {this.props.user?.menu && this.state.userMenu && (
({ display: v.name, value: v.path, href: v.path, selected: this.state.path === v.path }))} />
)} {this.state.subMenu && (
)} ) private onCloseOpenClick = () => { let willBeOpen = !this.state.open if (this.props.onClose && !willBeOpen) { willBeOpen = this.props.onClose() } this.setState(!willBeOpen ? {open: false, activeMenu: undefined} : {open: true}) } private onMenuClick = (value?: string) => { this.setState({userMenu: false, subMenu: undefined}) if (value) { Router.push(value) } } private makeMenuItem(obj: MenuItem & {subMenu?: Array}, isSub = false) { const id = obj.name + (obj.path ?? '') const content = ( <> {obj.icon && ( )} {obj.name} {obj.subMenu && ( )} ) const isActive = this.state.path === obj.path || obj.subMenu?.find((it) => this.state.path === it.path) return
  • {obj.path ? ( {content} ) : content}
    {obj.subMenu && (
      {obj.subMenu.map((it) => this.makeMenuItem(it, true))}
    )}
  • } }