diff --git a/.storybook/mockNextRouter.js b/.storybook/mockNextRouter.js index 5cdd186..040a979 100644 --- a/.storybook/mockNextRouter.js +++ b/.storybook/mockNextRouter.js @@ -1,7 +1,9 @@ import Router from 'next/router' Router.router = { - push: async () => {}, + push: async (route) => { + console.log('Pushing router to', route) + }, replace: async () => {}, prefetch: () => {}, route: '/mock-route', diff --git a/src/Box/Box.stories.tsx b/src/Box/Box.stories.tsx index 113bb86..8b453be 100644 --- a/src/Box/Box.stories.tsx +++ b/src/Box/Box.stories.tsx @@ -12,7 +12,7 @@ export default { } } as Meta -export const Basic = (args: any) => ( +export const Box = (args: any) => ( Test ) diff --git a/src/Box/BoxHeader.stories.tsx b/src/Box/BoxHeader.stories.tsx index 4934686..2f4db6b 100644 --- a/src/Box/BoxHeader.stories.tsx +++ b/src/Box/BoxHeader.stories.tsx @@ -12,7 +12,7 @@ export default { } } as Meta -export const Basic = (args: any) => ( +export const BoxHeader = (args: any) => ( ) diff --git a/src/Button/Button.module.styl b/src/Button/Button.module.styl index b1a61d9..b9f87ad 100644 --- a/src/Button/Button.module.styl +++ b/src/Button/Button.module.styl @@ -127,8 +127,9 @@ @media (prefers-color-scheme dark) border-color transparent transparent $darkGrayDark $darkGrayDark - -.textInner +svg + .textInner + margin-left 8px +.textInner + svg margin-left 8px /** diff --git a/src/Button/Button.stories.tsx b/src/Button/Button.stories.tsx index ddf0d11..b402b92 100644 --- a/src/Button/Button.stories.tsx +++ b/src/Button/Button.stories.tsx @@ -9,10 +9,11 @@ export default { component: Component } as Meta -export const Basic = (args: any) => Button -Basic.args = { +export const Button = (args: any) => Button +Button.args = { nomargintop: true, icon: Zap, + iconLeft: Zap, size: 'small', block: true } diff --git a/src/Button/index.tsx b/src/Button/index.tsx index b353182..dd53698 100644 --- a/src/Button/index.tsx +++ b/src/Button/index.tsx @@ -13,6 +13,7 @@ interface Props { color?: ColorType children?: React.ReactNode icon?: Icon | string + iconLeft?: Icon | string size?: 'large' | 'small' type?: 'outline' | 'ghost' block?: boolean @@ -29,18 +30,22 @@ export default class Button extends React.Component { let inner: any = this.props.children - if (this.props.icon) { - const Icon = this.props.icon + if (this.props.icon || this.props.iconLeft) { inner = ( <> - {typeof Icon === 'string' ? ( - + {this.props.icon && (typeof this.props.icon === 'string' ? ( + ) : ( - - )} + + ))} {this.props.children && ( {this.props.children} )} + {this.props.iconLeft && (typeof this.props.iconLeft === 'string' ? ( + + ) : ( + + ))} ) } diff --git a/src/Checkbox/Checkbox.stories.tsx b/src/Checkbox/Checkbox.stories.tsx index b070750..81c9ab2 100644 --- a/src/Checkbox/Checkbox.stories.tsx +++ b/src/Checkbox/Checkbox.stories.tsx @@ -7,4 +7,4 @@ export default { component: Checkbox } as Meta -export const Basic = (args: any) => +export const Checkbox = (args: any) => diff --git a/src/Code/Code.stories.tsx b/src/Code/Code.stories.tsx index 0394d96..affef51 100644 --- a/src/Code/Code.stories.tsx +++ b/src/Code/Code.stories.tsx @@ -10,7 +10,7 @@ export default { } } as Meta -export const Basic = (args: any) => { +export const Code = (args: any) => { const content = args.content delete args.content diff --git a/src/Container/Container.stories.tsx b/src/Container/Container.stories.tsx index aafd3be..2bf6b70 100644 --- a/src/Container/Container.stories.tsx +++ b/src/Container/Container.stories.tsx @@ -14,6 +14,6 @@ export default { } } as Meta -export const Basic = (args: any) => ( +export const Container = (args: any) => ( Test ) diff --git a/src/Link/Link.stories.tsx b/src/Link/Link.stories.tsx index 3a19a07..e1dd225 100644 --- a/src/Link/Link.stories.tsx +++ b/src/Link/Link.stories.tsx @@ -13,4 +13,4 @@ export default { } } as Meta -export const Basic = (args: any) => {args.text} +export const Link = (args: any) => {args.text} diff --git a/src/Loader/Loader.stories.tsx b/src/Loader/Loader.stories.tsx index 3d3d8a2..34fa574 100644 --- a/src/Loader/Loader.stories.tsx +++ b/src/Loader/Loader.stories.tsx @@ -11,9 +11,9 @@ export default { } } as Meta -export const Basic: Story = (args: any) => +export const Loader: Story = (args: any) => -let tmp = Basic.bind({}) +let tmp = Loader.bind({}) tmp.args = { auto: {interval : [10, 100], increment: [0, 5]} } diff --git a/src/Menu/Menu.stories.tsx b/src/Menu/Menu.stories.tsx index b772163..e8c4a94 100644 --- a/src/Menu/Menu.stories.tsx +++ b/src/Menu/Menu.stories.tsx @@ -21,6 +21,6 @@ const list: Component['props']['items'] = [ {value: 'Menu item 10', icon: XOctagon} ] -export const Basic = (args: any) => ( +export const Menu = (args: any) => ( list[index].selected = !list[index].selected} /> ) diff --git a/src/Menu/index.tsx b/src/Menu/index.tsx index 9d893f3..e35f624 100644 --- a/src/Menu/index.tsx +++ b/src/Menu/index.tsx @@ -1,4 +1,5 @@ import React from 'react' +import { Link } from '..' import Box from '../Box' import { Icon } from '../interfaces' import { buildClassName } from '../Util' @@ -6,7 +7,7 @@ import { buildClassName } from '../Util' import css from './Menu.module.styl' interface Props { - items: Array<{display?: string, value: any, selected?: boolean, icon?: Icon}> + items: Array<{display?: string, value: any, selected?: boolean, icon?: Icon, href?: string}> outline?: boolean onClick?: (value: any, key: number) => void className?: string @@ -17,14 +18,28 @@ export default class Menu extends React.Component { public render = () => (
    - {this.props.items.map((item, key) => ( -
  • this.props.onClick?.(item.value, key)}> - {item.icon && ( - - )} - {item.display ?? item.value} -
  • - ))} + {this.props.items.map((item, key) => { + const content = ( + <> + {item.icon && ( + + )} + {item.display ?? item.value} + + ) + if (item.href) { + return ( +
  • + {content} +
  • + ) + } + return ( +
  • this.props.onClick?.(item.value, key)}> + {content} +
  • + ) + })}
) diff --git a/src/Navbar/Navbar.module.styl b/src/Navbar/Navbar.module.styl index a871a84..0314eeb 100644 --- a/src/Navbar/Navbar.module.styl +++ b/src/Navbar/Navbar.module.styl @@ -1,228 +1,30 @@ @import '../config' -// $transition = 10s linear -// $transitionTime = 10s -// $transitionFunction = linear -.body-sidebar - margin-left 300px - transition margin-left $transition - &.short - margin-left 56px +$height = 76px .body-navbar - margin-top 70px + margin-top $height .navbar - background $foregroundLight - @media (prefers-color-scheme dark) - background $foregroundDark position fixed left 0 top 0 - height 70px + height $height width 100% z-index 100 display flex padding 16px - > ul, .userSpaceParent ul + > ul + .userSpaceParent ul display flex - li:first-child p - margin-left 0 - - > ul p, .userSpaceParent > ul p - padding 8px - - margin-left 16px - border-radius 4px - - &.active - background $mainGradient - color $textOnMain - - .userSpace - - height 100% - display flex - align-items center - cursor pointer - user-select none - svg - margin-left 16px - vertical-align top - - .userMenu - position fixed - top 70px - right 0 - border-bottom-left-radius 4px - transform translateX(100%) - background inherit - transition transform $transition - &.menuActive - transform translateX(0%) - - -.sidebar - background $foregroundLight - @media (prefers-color-scheme dark) - background $foregroundDark - position fixed - left 0 - top 0 - height 100vh - width 300px - z-index 100 - display flex - flex-direction column - - &.mobile - width 100% - z-index 101 - - & - transition width $transition - .header - .userSpace - .header .imgContainer - > ul span - // transition all $transition - transition-property width, padding, margin, max-width - transition-duration $transitionTime - transition-timing-function $transitionFunction - overflow hidden - > ul span - width calc(100% - 40px) - max-width 100% - .header p - cursor pointer - - .userSpaceParent - background $backgroundLight - @media (prefers-color-scheme dark) - background $backgroundDark - - > ul, .userSpaceParent ul - display flex - padding 16px - justify-content center - - li:first-child p - margin-left 0 - - > ul p, .userSpaceParent > ul p - padding 8px - - margin-left 16px - border-radius 4px - - &.active - background $mainGradient - color $textOnMain - - .userSpace - cursor pointer - user-select none - padding 16px - width 100% - max-width 100% - min-height 86px - p - overflow hidden - white-space nowrap - p:last-child:not(:first-child) - margin-top 8px - font-style italic - font-size rem(14) - - p:first-child - font-weight 500 - svg - vertical-align top - transition transform $transition - &.menuActive - transform rotateX(180deg) - - .userMenu - max-height 0px - transition all $transition - - &.menuActive - // TODO find better way to animate this shit - max-height 100% - - &.short - width 88px - .header > div - padding 0 - .header .imgContainer - .userSpace - > ul span - width 0 - padding-left 0 - padding-right 0 - margin 0 - max-width 0 - - - .header - min-height 70px - padding 0 - margin 0 - > div p > div - > div:first-child - padding 16px - > div:last-child - padding 0 - - hr - margin 0 - - > ul li - width 100% - p - padding 16px 0 - display flex - align-items center - z-index 111 - position relative - - // Temporary fix the transition for linear-gradient - &::before - transition opacity $transition - opacity 0 - width 100% - height 100% - content " " - position absolute - z-index -1 - background-image $mainGradient - &:hover - &.active - color $textOnMain - &::before - opacity 1 - svg - margin-left 16px - span - padding-left 16px - height inherit - .navbar -.sidebar ul list-style none margin 0 padding 0 -.userMenu - padding 8px 16px - a - display inline-block - padding-bottom 16px - - .mobileMenu opacity 0 transition opacity $transition @@ -230,7 +32,3 @@ &.shown opacity 1 pointer-events initial - -.mainGradient - //WIP - fill $mainGradient diff --git a/src/Navbar/Navbar.stories.tsx b/src/Navbar/Navbar.stories.tsx index c45dfc7..ac8b1e9 100644 --- a/src/Navbar/Navbar.stories.tsx +++ b/src/Navbar/Navbar.stories.tsx @@ -12,33 +12,34 @@ export default { } } as Meta -export const Basic: Story = (args: any) => -Basic.args = { - type: 'navbar', +export const Navbar: Story = (args: any) => +Navbar.args = { logo: {src: '/90-38.svg', width: 90, height: 38}, - loginUrl: '/login', - registerUrl: '/register', user: { name: 'Username', - description: 'User Description', - menu: { - links: [{ - path: '/logout', - name: 'Logout' - }, { - path: '/logout', - name: 'Logout' - }], - informations: (Testing :D) - } + menu: [{ + path: '/logout', + value: 'Logout' + }, { + path: '/logout', + value: 'Logout' + }] }, - items: [{ - path: '/dashboard', + menu: [{ name: 'Dasboard', icon: Zap + }, { + name: 'With Childs', + icon: Zap, + subMenu: [{ + name: 'Child 1' + }, { + name: 'Child with link', + path: '/dashboard' + }] }, { path: '/dashboard', - name: 'Dasboard', + name: 'Link', icon: ZapOff }], } diff --git a/src/Navbar/index.tsx b/src/Navbar/index.tsx index 2c4ca0e..a4070aa 100644 --- a/src/Navbar/index.tsx +++ b/src/Navbar/index.tsx @@ -2,8 +2,10 @@ import Router from 'next/router' import Image, { ImageProps } from 'next/image' import React from 'react' -import { ChevronDown, ChevronsRight, Menu, X } from 'lucide-react' +import { ChevronDown, ChevronsRight, Menu as LucideMenu, X } from 'lucide-react' import Text from '../Text' +import Menu from '../Menu' +import Sidebar from '../Sidebar' import Col from '../Col' import Row from '../Row' import Link from '../Link' @@ -11,14 +13,17 @@ import { buildClassName } from '../Util' import css from './Navbar.module.styl' import { Icon } from '../interfaces' +import { Button } from '..' +import { objectEqual } from '@dzeio/object-util' + +interface MenuItem { + path?: string + icon?: Icon + name: string + subMenu?: Array +} interface Props { - /** - * Type of Navbar - * _note: when in mobile it is not listened_ - */ - type: 'navbar' | 'sidebar' - /** * Logo to display */ @@ -39,39 +44,15 @@ interface Props { * Username */ name: string - /** - * User Short description - */ - description?: string /** * User Menu */ - menu?: { - /** - * Menu links - */ - links: Array<{ - path: string - name: string - }> - /** - * Custom informations shown next to the links - */ - informations?: JSX.Element - } + menu?: Array } /** * Links to display */ - items: Array<{ - path: string - icon?: Icon - name: string - }> - /** - * Internal Use don't use it ! - */ - mobileMenu?: () => void + menu: Array } interface State { @@ -79,10 +60,14 @@ interface State { short: boolean isMobile: boolean menuActive: boolean + subMenu?: { + x: number + menu: Menu['props']['items'] + } } /** - * Navbar/Sidebar Component + * Navbar Component * @version 1.0.3 */ export default class Navbar extends React.Component { @@ -96,7 +81,7 @@ export default class Navbar extends React.Component { public componentDidMount() { this.setState({ path: Router.asPath, - menuActive: !!this.props.mobileMenu + menuActive: false }) Router.events.on('routeChangeComplete', () => { this.setState({path: Router.asPath, menuActive: false}) @@ -104,10 +89,10 @@ export default class Navbar extends React.Component { Router.events.on('routeChangeError', () => { this.setState({path: Router.asPath, menuActive: false}) }) - if (!this.props.mobileMenu) { - window.addEventListener('resize', this.onResize) - this.onResize() - } + document.body.classList.add(css['body-navbar']) + document.body.addEventListener('click', this.onBodyClick) + window.addEventListener('resize', this.onResize) + this.onResize() } public onResize = () => { @@ -117,53 +102,20 @@ export default class Navbar extends React.Component { } } - public componentDidUpdate() { - if (!this.props.mobileMenu) { - if (this.state.short) { - document.body.classList.add(css.short) - } else { - document.body.classList.remove(css.short) - } - if (this.getType() === 'sidebar') { - document.body.classList.add(css['body-sidebar']) - document.body.classList.remove(css['body-navbar']) - } else { - document.body.classList.remove(css['body-sidebar']) - document.body.classList.add(css['body-navbar']) - } - } - - } - public componentWillUnmount() { - if (!this.props.mobileMenu) { - document.body.classList.remove(css.short, css[`body-${this.getType()}`]) - window.removeEventListener('resize', this.onResize) - } - } - - public onSidebarButton = () => { - if (!this.props.mobileMenu) { - this.setState({short: !this.state.short, menuActive: false}) - } else { - this.props.mobileMenu() - } + document.body.classList.remove(css['body-sidebar']) + document.body.removeEventListener('click', this.onBodyClick) + window.removeEventListener('resize', this.onResize) } public menuCloseCallback = () => { this.setState({menuActive: false}) - } - - public getType(): 'sidebar' | 'navbar' { - if (this.props.mobileMenu) { - return 'sidebar' - } - return this.state.isMobile ? 'navbar' : this.props.type + return true } public render = () => ( <> -