From adb5047051330eb535e2b8eab0378122351b6075 Mon Sep 17 00:00:00 2001 From: Filip Witosz Date: Mon, 8 Feb 2021 09:29:52 +0100 Subject: [PATCH] Navbar --- __tests__/menu.test.tsx | 2 +- __tests__/navbar.test.tsx | 31 +++++ package.json | 2 +- src/components/Navbar/divider.tsx | 49 +++++++ src/components/Navbar/group.tsx | 49 +++++++ src/components/Navbar/index.tsx | 72 ++++++++++ src/components/Navbar/item.tsx | 59 +++++++++ src/components/Sidebar/index.tsx | 8 +- src/constants/theme.ts | 14 ++ src/index.tsx | 4 + src/stories/Navbar/Navbar.stories.tsx | 183 ++++++++++++++++++++++++++ 11 files changed, 464 insertions(+), 9 deletions(-) create mode 100644 __tests__/navbar.test.tsx create mode 100644 src/components/Navbar/divider.tsx create mode 100644 src/components/Navbar/group.tsx create mode 100644 src/components/Navbar/index.tsx create mode 100644 src/components/Navbar/item.tsx create mode 100644 src/stories/Navbar/Navbar.stories.tsx diff --git a/__tests__/menu.test.tsx b/__tests__/menu.test.tsx index 2fc1fcde..6cfbb8ed 100644 --- a/__tests__/menu.test.tsx +++ b/__tests__/menu.test.tsx @@ -7,7 +7,7 @@ import { ReqoreUIProvider, } from '../src/index'; -test('Renders Menu properly', async () => { +test('Renders Menu properly', () => { render( diff --git a/__tests__/navbar.test.tsx b/__tests__/navbar.test.tsx new file mode 100644 index 00000000..905660d1 --- /dev/null +++ b/__tests__/navbar.test.tsx @@ -0,0 +1,31 @@ +import { render } from '@testing-library/react'; +import React from 'react'; +import { + ReqoreHeader, + ReqoreNavbarDivider, + ReqoreNavbarGroup, + ReqoreNavbarItem, + ReqoreUIProvider, +} from '../src'; + +test('Renders Navbar properly', () => { + render( + + + + Logo + + + Item + + Item 2 + + + + ); + + expect(document.querySelectorAll('.reqore-navbar-header').length).toBe(1); + expect(document.querySelectorAll('.reqore-navbar-group').length).toBe(2); + expect(document.querySelectorAll('.reqore-navbar-divider').length).toBe(1); + expect(document.querySelectorAll('.reqore-navbar-item').length).toBe(3); +}); diff --git a/package.json b/package.json index efd133cf..5d025ad4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@qoretechnologies/reqore", - "version": "0.2.3", + "version": "0.2.4", "description": "ReQore is a UI library of components for Qorus connected apps", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/src/components/Navbar/divider.tsx b/src/components/Navbar/divider.tsx new file mode 100644 index 00000000..dbcd23ba --- /dev/null +++ b/src/components/Navbar/divider.tsx @@ -0,0 +1,49 @@ +import React, { forwardRef } from 'react'; +import styled from 'styled-components'; +import { IReqoreTheme } from '../../constants/theme'; +import { getReadableColor } from '../../helpers/colors'; + +export interface IReqoreNavbarDividerProps + extends React.HTMLAttributes { + type?: 'header' | 'footer'; +} + +const StyledNavbarDivider = styled.div<{ + theme: IReqoreTheme; + type?: 'header' | 'footer'; +}>` + position: relative; + width: 20px; + height: 100%; + background-color: inherit; + display: flex; + justify-content: center; + align-items: center; + + &:before { + content: ''; + display: block; + width: 1px; + height: 50%; + background-color: ${({ theme, type }) => + getReadableColor( + theme[type]?.background || theme[type]?.main || theme.main, + undefined, + undefined, + true + )}; + opacity: 0.2; + } +`; + +const ReqoreNavbarDivider = forwardRef( + ({ type, ...rest }: IReqoreNavbarDividerProps, ref: any) => ( + + ) +); + +export default ReqoreNavbarDivider; diff --git a/src/components/Navbar/group.tsx b/src/components/Navbar/group.tsx new file mode 100644 index 00000000..efbc92d2 --- /dev/null +++ b/src/components/Navbar/group.tsx @@ -0,0 +1,49 @@ +import React, { forwardRef } from 'react'; +import styled, { css } from 'styled-components'; +import { IReqoreTheme } from '../../constants/theme'; +import ReqoreThemeProvider from '../../containers/ThemeProvider'; + +export interface IReqoreNavbarGroupProps + extends React.HTMLAttributes { + position?: 'right' | 'left'; + type?: 'footer' | 'header'; + children?: any; +} + +export interface IReqoreNavbarGroupStyle extends IReqoreNavbarGroupProps { + theme: IReqoreTheme; +} + +const StyledNavbarGroup = styled.div` + ${({ position }: IReqoreNavbarGroupStyle) => css` + height: 100%; + float: ${position}; + color: inherit; + background-color: inherit; + display: flex; + justify-content: center; + align-items: center; + `} +`; + +const ReqoreNavbarGroup = forwardRef( + ( + { position = 'left', children, type, ...rest }: IReqoreNavbarGroupProps, + ref: any + ) => ( + + + {React.Children.map(children, (child) => + React.cloneElement(child, { type }) + )} + + + ) +); + +export default ReqoreNavbarGroup; diff --git a/src/components/Navbar/index.tsx b/src/components/Navbar/index.tsx new file mode 100644 index 00000000..2140c901 --- /dev/null +++ b/src/components/Navbar/index.tsx @@ -0,0 +1,72 @@ +import { darken } from 'polished'; +import React, { forwardRef } from 'react'; +import styled, { css } from 'styled-components'; +import { IReqoreTheme } from '../../constants/theme'; +import ReqoreThemeProvider from '../../containers/ThemeProvider'; +import { getMainColor, getReadableColor } from '../../helpers/colors'; + +export interface IReqoreNavbarProps + extends React.HTMLAttributes { + children?: any; + position?: 'top' | 'bottom'; + type?: 'header' | 'footer'; +} + +export interface IReqoreNavbarStyle extends IReqoreNavbarProps { + theme: IReqoreTheme; +} + +const StyledNavbar = styled.div` + ${({ theme, type }: IReqoreNavbarStyle) => css` + height: 50px; + width: 100%; + color: ${ + theme[type]?.color || + getReadableColor( + theme[type]?.background || theme[type]?.main || theme.main, + undefined, + undefined, + true + ) + }; + background-color: ${ + theme[type]?.background || theme[type]?.main || theme.main + }; + border-${type === 'header' ? 'bottom' : 'top'}: 1px solid ${ + theme[type]?.border || darken(0.1, getMainColor(theme, type)) + }; + `} +`; + +const ReqoreNavbar = forwardRef( + ( + { position = 'top', children, type, ...rest }: IReqoreNavbarProps, + ref: any + ) => ( + + + {React.Children.map(children, (child) => + React.cloneElement(child, { type }) + )} + + + ) +); + +export const ReqoreHeader = forwardRef( + (props: IReqoreNavbarProps, ref: any) => ( + + ) +); + +export const ReqoreFooter = forwardRef( + (props: IReqoreNavbarProps, ref: any) => ( + + ) +); diff --git a/src/components/Navbar/item.tsx b/src/components/Navbar/item.tsx new file mode 100644 index 00000000..da696cc9 --- /dev/null +++ b/src/components/Navbar/item.tsx @@ -0,0 +1,59 @@ +import React, { forwardRef } from 'react'; +import styled, { css } from 'styled-components'; +import { IReqoreTheme } from '../../constants/theme'; +import ReqoreThemeProvider from '../../containers/ThemeProvider'; +import { changeLightness, getMainColor } from '../../helpers/colors'; + +export interface IReqoreNavbarItemProps + extends React.HTMLAttributes { + children?: any; + interactive?: boolean; + type?: 'header' | 'footer'; +} + +export interface IReqoreNavbarItemStyle extends IReqoreNavbarItemProps { + theme?: IReqoreTheme; +} + +const StyledNavbarItem = styled.div` + height: 100%; + min-width: 50px; + display: flex; + justify-content: center; + align-items: center; + padding: 10px; + color: inherit; + background-color: inherit; + + ${({ interactive, theme, type }: IReqoreNavbarItemStyle) => + interactive && + css` + transition: background-color 0.1s linear; + cursor: pointer; + &:hover { + background-color: ${theme[type]?.hoverColor || + changeLightness(getMainColor(theme, type), 0.05)}; + } + `} +`; + +const ReqoreNavbarItem = forwardRef( + ( + { interactive, children, type, ...rest }: IReqoreNavbarItemProps, + ref: any + ) => ( + + + {children} + + + ) +); + +export default ReqoreNavbarItem; diff --git a/src/components/Sidebar/index.tsx b/src/components/Sidebar/index.tsx index 3792658c..fa4081f7 100644 --- a/src/components/Sidebar/index.tsx +++ b/src/components/Sidebar/index.tsx @@ -77,13 +77,6 @@ const StyledSidebar = styled.div<{ expanded?: boolean; theme: IReqoreTheme }>` flex: 1; } - #menuCollapse { - border-top: 1px solid - ${({ theme }) => - theme.sidebar?.item?.border || - darken(0.04, getMainColor(theme, 'sidebar'))}; - } - &.expanded { min-width: 180px !important; max-width: 180px !important; @@ -281,6 +274,7 @@ const StyledSidebar = styled.div<{ expanded?: boolean; theme: IReqoreTheme }>` .sidebarItem, .sidebarSubItem { + min-height: 50px; display: flex; align-items: center; cursor: pointer; diff --git a/src/constants/theme.ts b/src/constants/theme.ts index 85d54796..f358e894 100644 --- a/src/constants/theme.ts +++ b/src/constants/theme.ts @@ -41,6 +41,20 @@ export interface IReqoreTheme { popover?: { main: string; }; + header?: { + main?: string; + color?: string; + border?: string; + background?: string; + hoverColor?: string; + }; + footer?: { + main?: string; + color?: string; + border?: string; + background?: string; + hoverColor?: string; + }; } export interface IReqoreThemeNotification { diff --git a/src/index.tsx b/src/index.tsx index f5f955bb..a893c160 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -3,6 +3,10 @@ import '@blueprintjs/core/lib/css/blueprint.css'; export { default as ReqoreMenu } from './components/Menu'; export { default as ReqoreMenuDivider } from './components/Menu/divider'; export { default as ReqoreMenuItem } from './components/Menu/item'; +export { ReqoreFooter, ReqoreHeader } from './components/Navbar'; +export { default as ReqoreNavbarDivider } from './components/Navbar/divider'; +export { default as ReqoreNavbarGroup } from './components/Navbar/group'; +export { default as ReqoreNavbarItem } from './components/Navbar/item'; export { default as ReqoreNotificationsWrapper } from './components/Notifications'; export { default as ReqoreNotification } from './components/Notifications/notification'; export { default as ReqorePopover } from './components/Popover'; diff --git a/src/stories/Navbar/Navbar.stories.tsx b/src/stories/Navbar/Navbar.stories.tsx new file mode 100644 index 00000000..a67fc719 --- /dev/null +++ b/src/stories/Navbar/Navbar.stories.tsx @@ -0,0 +1,183 @@ +import { Icon } from '@blueprintjs/core'; +import { Meta, Story } from '@storybook/react/types-6-0'; +import { darken } from 'polished'; +import React from 'react'; +import styled, { css } from 'styled-components'; +import { IReqoreNavbarProps, ReqoreFooter } from '../../components/Navbar'; +import { IReqoreNavbarItemProps } from '../../components/Navbar/item'; +import ReqoreThemeProvider from '../../containers/ThemeProvider'; +import { IReqoreUIProviderProps } from '../../containers/UIProvider'; +import { changeLightness, getReadableColor } from '../../helpers/colors'; +import { + ReqoreHeader, + ReqoreMenu, + ReqoreMenuDivider, + ReqoreMenuItem, + ReqoreNavbarDivider, + ReqoreNavbarGroup, + ReqoreNavbarItem, + ReqorePopover, + ReqoreUIProvider, +} from '../../index'; + +export default { + title: 'ReQore/Navigation Bar', + args: { + theme: { + main: '#ffffff', + }, + }, +} as Meta; + +const StyledStoriesWrapper = styled.div` + width: 100%; + height: 800px; + display: flex; + flex-flow: row; +`; + +const StyledStoriesContent = styled.div` + ${({ theme }) => css` + padding: 15px; + display: flex; + width: 100%; + height: 100%; + flex: 1; + background-color: ${changeLightness(theme.main, 0.08)}; + + div { + width: 100%; + height: 100%; + flex: 1; + border-radius: 10px; + background-color: ${theme.main}; + color: ${getReadableColor(theme.main)}; + box-shadow: 0px 0px 3px 0px ${darken(0.2, theme.main)}; + } + `} +`; + +const StyledStoriesContentWrapper = styled.div` + width: 100%; + height: 100%; + display: flex; + flex-flow: column; +`; + +const Template: Story = ({ + theme, + ...args +}: IReqoreUIProviderProps & IReqoreNavbarProps) => { + return ( + + + + + + + +

I am a logo on the left

+
+
+ + + + + Profile + + + Alerts + + Log out +
+ } + handler='click' + componentProps={ + { interactive: true } as IReqoreNavbarItemProps + } + isReqoreComponent + > + + + + + + + + + + +
+ + + + +

I am a logo on the left

+
+
+ + + + + Profile + + + Alerts + + Log out + + } + handler='click' + componentProps={ + { interactive: true } as IReqoreNavbarItemProps + } + isReqoreComponent + > + + + + + + +
+ + + + + ); +}; + +export const Default = Template.bind({}); +export const Dark = Template.bind({}); +Dark.args = { + theme: { + main: '#333333', + }, +}; + +export const CustomColor = Template.bind({}); +CustomColor.args = { + theme: { + main: '#194d5d', + }, +};