Feat/add right drawer (#159)
* Added right drawer component and logic * Refactored layout to accept right drawer
This commit is contained in:
@ -1,4 +1,4 @@
|
||||
import Navbar from './navbar/Navbar';
|
||||
import { Navbar } from './navbar/Navbar';
|
||||
import styled from '@emotion/styled';
|
||||
import { ThemeProvider } from '@emotion/react';
|
||||
import { User } from '../interfaces/entities/user.interface';
|
||||
@ -9,13 +9,15 @@ const StyledLayout = styled.div`
|
||||
flex-direction: row;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
background: ${(props) => props.theme.noisyBackground};
|
||||
overflow: hidden;
|
||||
`;
|
||||
|
||||
const StyledRightContainer = styled.div`
|
||||
const MainContainer = styled.div`
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
widht: calc(100% - 220px);
|
||||
`;
|
||||
|
||||
type OwnProps = {
|
||||
@ -28,7 +30,7 @@ function AppLayout({ children, user }: OwnProps) {
|
||||
<ThemeProvider theme={lightTheme}>
|
||||
<StyledLayout>
|
||||
<Navbar user={user} workspace={user?.workspaceMember?.workspace} />
|
||||
<StyledRightContainer>{children}</StyledRightContainer>
|
||||
<MainContainer>{children}</MainContainer>
|
||||
</StyledLayout>
|
||||
</ThemeProvider>
|
||||
);
|
||||
|
||||
14
front/src/layout/Panel.tsx
Normal file
14
front/src/layout/Panel.tsx
Normal file
@ -0,0 +1,14 @@
|
||||
import styled from '@emotion/styled';
|
||||
import React from 'react';
|
||||
|
||||
const StyledPanel = styled.div`
|
||||
display: flex;
|
||||
background: ${(props) => props.theme.primaryBackground};
|
||||
border-radius: 8px;
|
||||
border: 1px solid ${(props) => props.theme.primaryBorder};
|
||||
width: 100%;
|
||||
`;
|
||||
|
||||
export function Panel({ children }: { children: React.ReactNode }) {
|
||||
return <StyledPanel>{children}</StyledPanel>;
|
||||
}
|
||||
12
front/src/layout/containers/MainContainer.tsx
Normal file
12
front/src/layout/containers/MainContainer.tsx
Normal file
@ -0,0 +1,12 @@
|
||||
import styled from '@emotion/styled';
|
||||
import React from 'react';
|
||||
|
||||
const StyledMainContainer = styled.div`
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
overflow: hidden;
|
||||
`;
|
||||
|
||||
export function MainContainer({ children }: { children: React.ReactNode }) {
|
||||
return <StyledMainContainer>{children}</StyledMainContainer>;
|
||||
}
|
||||
@ -1,6 +1,10 @@
|
||||
import styled from '@emotion/styled';
|
||||
import TopBar from '../top-bar/TopBar';
|
||||
import { ReactNode } from 'react';
|
||||
import { RightDrawer } from '../right-drawer/RightDrawer';
|
||||
import { Panel } from '../Panel';
|
||||
import { isRightDrawerOpenState } from '../../modules/ui/layout/right-drawer/states/isRightDrawerOpenState';
|
||||
import { useRecoilState } from 'recoil';
|
||||
|
||||
type OwnProps = {
|
||||
children: JSX.Element;
|
||||
@ -11,30 +15,32 @@ type OwnProps = {
|
||||
|
||||
const StyledContainer = styled.div`
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
`;
|
||||
|
||||
const ContentContainer = styled.div`
|
||||
const MainContainer = styled.div`
|
||||
display: flex;
|
||||
position: relative;
|
||||
flex-direction: column;
|
||||
background: ${(props) => props.theme.noisyBackground};
|
||||
flex: 1;
|
||||
padding-right: ${(props) => props.theme.spacing(3)};
|
||||
padding-bottom: ${(props) => props.theme.spacing(3)};
|
||||
width: calc(100% - ${(props) => props.theme.spacing(3)});
|
||||
height: calc(100% - 54px);
|
||||
`;
|
||||
|
||||
const ContentSubContainer = styled.div`
|
||||
display: flex;
|
||||
background: ${(props) => props.theme.primaryBackground};
|
||||
border-radius: 8px;
|
||||
flex-direction: row;
|
||||
height: 100%;
|
||||
flex: 1;
|
||||
border: 1px solid ${(props) => props.theme.primaryBorder};
|
||||
width: calc(100% - 16px);
|
||||
margin-right: 8px;
|
||||
margin-bottom: 8px;
|
||||
gap: 8px;
|
||||
padding: 4px;
|
||||
`;
|
||||
|
||||
const RIGHT_DRAWER_WIDTH = '300px';
|
||||
|
||||
type LeftContainerProps = {
|
||||
isRightDrawerOpen?: boolean;
|
||||
};
|
||||
|
||||
const LeftContainer = styled.div<LeftContainerProps>`
|
||||
display: flex;
|
||||
width: calc(
|
||||
100% - ${(props) => (props.isRightDrawerOpen ? RIGHT_DRAWER_WIDTH : '0px')}
|
||||
);
|
||||
`;
|
||||
|
||||
function FullWidthContainer({
|
||||
@ -43,12 +49,17 @@ function FullWidthContainer({
|
||||
icon,
|
||||
onAddButtonClick,
|
||||
}: OwnProps) {
|
||||
const [isRightDrawerOpen] = useRecoilState(isRightDrawerOpenState);
|
||||
|
||||
return (
|
||||
<StyledContainer>
|
||||
<TopBar title={title} icon={icon} onAddButtonClick={onAddButtonClick} />
|
||||
<ContentContainer>
|
||||
<ContentSubContainer>{children}</ContentSubContainer>
|
||||
</ContentContainer>
|
||||
<MainContainer>
|
||||
<LeftContainer isRightDrawerOpen={isRightDrawerOpen}>
|
||||
<Panel>{children}</Panel>
|
||||
</LeftContainer>
|
||||
<RightDrawer />
|
||||
</MainContainer>
|
||||
</StyledContainer>
|
||||
);
|
||||
}
|
||||
|
||||
@ -10,9 +10,9 @@ import { TbBuilding, TbUser } from 'react-icons/tb';
|
||||
const NavbarContainer = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: ${(props) => props.theme.noisyBackground};
|
||||
min-width: 220px;
|
||||
width: 220px;
|
||||
padding: ${(props) => props.theme.spacing(2)};
|
||||
flex-shrink: 0;
|
||||
`;
|
||||
|
||||
const NavItemsContainer = styled.div`
|
||||
@ -26,7 +26,7 @@ type OwnProps = {
|
||||
workspace?: Workspace;
|
||||
};
|
||||
|
||||
function Navbar({ workspace }: OwnProps) {
|
||||
export function Navbar({ workspace }: OwnProps) {
|
||||
return (
|
||||
<>
|
||||
<NavbarContainer>
|
||||
@ -60,5 +60,3 @@ function Navbar({ workspace }: OwnProps) {
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default Navbar;
|
||||
|
||||
30
front/src/layout/right-drawer/RightDrawer.tsx
Normal file
30
front/src/layout/right-drawer/RightDrawer.tsx
Normal file
@ -0,0 +1,30 @@
|
||||
import styled from '@emotion/styled';
|
||||
import { useRecoilState } from 'recoil';
|
||||
import { isRightDrawerOpenState } from '../../modules/ui/layout/right-drawer/states/isRightDrawerOpenState';
|
||||
import { RightDrawerRouter } from './RightDrawerRouter';
|
||||
import { rightDrawerPageState } from '../../modules/ui/layout/right-drawer/states/rightDrawerPageState';
|
||||
import { isDefined } from '../../modules/utils/type-guards/isDefined';
|
||||
import { Panel } from '../Panel';
|
||||
|
||||
const StyledRightDrawer = styled.div`
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
width: 300px;
|
||||
`;
|
||||
|
||||
export function RightDrawer() {
|
||||
const [isRightDrawerOpen] = useRecoilState(isRightDrawerOpenState);
|
||||
const [rightDrawerPage] = useRecoilState(rightDrawerPageState);
|
||||
|
||||
if (!isRightDrawerOpen || !isDefined(rightDrawerPage)) {
|
||||
return <></>;
|
||||
}
|
||||
|
||||
return (
|
||||
<StyledRightDrawer>
|
||||
<Panel>
|
||||
<RightDrawerRouter />
|
||||
</Panel>
|
||||
</StyledRightDrawer>
|
||||
);
|
||||
}
|
||||
14
front/src/layout/right-drawer/RightDrawerRouter.tsx
Normal file
14
front/src/layout/right-drawer/RightDrawerRouter.tsx
Normal file
@ -0,0 +1,14 @@
|
||||
import { useRecoilState } from 'recoil';
|
||||
import { rightDrawerPageState } from '../../modules/ui/layout/right-drawer/states/rightDrawerPageState';
|
||||
import { isDefined } from '../../modules/utils/type-guards/isDefined';
|
||||
import { RightDrawerComments } from '../../components/comments/RightDrawerComments';
|
||||
|
||||
export function RightDrawerRouter() {
|
||||
const [rightDrawerPage] = useRecoilState(rightDrawerPageState);
|
||||
|
||||
if (!isDefined(rightDrawerPage)) {
|
||||
return <></>;
|
||||
}
|
||||
|
||||
return rightDrawerPage === 'comments' ? <RightDrawerComments /> : <></>;
|
||||
}
|
||||
34
front/src/layout/right-drawer/RightDrawerTopBar.tsx
Normal file
34
front/src/layout/right-drawer/RightDrawerTopBar.tsx
Normal file
@ -0,0 +1,34 @@
|
||||
import styled from '@emotion/styled';
|
||||
import { RightDrawerTopBarCloseButton } from './RightDrawerTopBarCloseButton';
|
||||
|
||||
const StyledRightDrawerTopBar = styled.div`
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
height: 40px;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding-left: 8px;
|
||||
padding-right: 8px;
|
||||
font-size: 13px;
|
||||
color: ${(props) => props.theme.text60};
|
||||
border-bottom: 1px solid ${(props) => props.theme.lightBorder};
|
||||
width: 100%;
|
||||
`;
|
||||
|
||||
const StyledTopBarTitle = styled.div`
|
||||
align-items: center;
|
||||
font-weight: 500;
|
||||
`;
|
||||
|
||||
export function RightDrawerTopBar({
|
||||
title,
|
||||
}: {
|
||||
title: string | null | undefined;
|
||||
}) {
|
||||
return (
|
||||
<StyledRightDrawerTopBar>
|
||||
<StyledTopBarTitle>{title}</StyledTopBarTitle>
|
||||
<RightDrawerTopBarCloseButton />
|
||||
</StyledRightDrawerTopBar>
|
||||
);
|
||||
}
|
||||
@ -0,0 +1,37 @@
|
||||
import styled from '@emotion/styled';
|
||||
import { FaTimes } from 'react-icons/fa';
|
||||
import { useRecoilState } from 'recoil';
|
||||
import { isRightDrawerOpenState } from '../../modules/ui/layout/right-drawer/states/isRightDrawerOpenState';
|
||||
|
||||
const StyledButton = styled.button`
|
||||
height: 24px;
|
||||
width: 24px;
|
||||
border: 1px solid ${(props) => props.theme.lightBorder};
|
||||
background: none;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
padding: 8px;
|
||||
|
||||
border-radius: 4px;
|
||||
|
||||
transition: ${(props) => props.theme.clickableElementBackgroundTransition};
|
||||
&:hover {
|
||||
background: ${(props) => props.theme.clickableElementBackgroundHover};
|
||||
}
|
||||
`;
|
||||
|
||||
export function RightDrawerTopBarCloseButton() {
|
||||
const [, setIsRightDrawerOpen] = useRecoilState(isRightDrawerOpenState);
|
||||
|
||||
function handleButtonClick() {
|
||||
setIsRightDrawerOpen(false);
|
||||
}
|
||||
|
||||
return (
|
||||
<StyledButton onClick={handleButtonClick}>
|
||||
<FaTimes />
|
||||
</StyledButton>
|
||||
);
|
||||
}
|
||||
@ -30,6 +30,10 @@ const lightThemeSpecific = {
|
||||
secondaryBackgroundSmallTransparency: 'rgba(252, 252, 252, 0.97)',
|
||||
|
||||
primaryBorder: 'rgba(0, 0, 0, 0.08)',
|
||||
lightBorder: '#f5f5f5',
|
||||
|
||||
clickableElementBackgroundHover: 'rgba(0, 0, 0, 0.04)',
|
||||
clickableElementBackgroundTransition: 'background 0.1s ease',
|
||||
|
||||
text100: '#000',
|
||||
text80: '#333333',
|
||||
@ -62,7 +66,11 @@ const darkThemeSpecific: typeof lightThemeSpecific = {
|
||||
|
||||
secondaryBackgroundSmallTransparency: 'rgba(23, 23, 23, 0.97)',
|
||||
|
||||
clickableElementBackgroundHover: 'rgba(0, 0, 0, 0.04)',
|
||||
clickableElementBackgroundTransition: 'background 0.1s ease',
|
||||
|
||||
primaryBorder: 'rgba(255, 255, 255, 0.08)',
|
||||
lightBorder: '#222222',
|
||||
|
||||
text100: '#ffffff',
|
||||
text80: '#cccccc',
|
||||
|
||||
@ -11,7 +11,6 @@ const TopBarContainer = styled.div`
|
||||
padding: 8px;
|
||||
font-size: 14px;
|
||||
color: ${(props) => props.theme.text80};
|
||||
flex-shrink: 0;
|
||||
`;
|
||||
|
||||
const TitleContainer = styled.div`
|
||||
|
||||
Reference in New Issue
Block a user