Refactor Layout (#322)

* Refactor Layout

* Fix storybook

* Fixing tests by forcing msw version before regression
This commit is contained in:
Charles Bochet
2023-06-17 21:24:15 +02:00
committed by GitHub
parent 5ae5f28dcb
commit 49462c69a2
38 changed files with 325 additions and 451 deletions

View File

@ -1,6 +1,7 @@
import { MemoryRouter } from 'react-router-dom';
import type { Meta, StoryObj } from '@storybook/react';
import { getRenderWrapperForPage } from '~/testing/renderWrappers';
import { getRenderWrapperForComponent } from '~/testing/renderWrappers';
import { CommandMenu } from '../CommandMenu';
@ -13,5 +14,9 @@ export default meta;
type Story = StoryObj<typeof CommandMenu>;
export const Default: Story = {
render: getRenderWrapperForPage(<CommandMenu initiallyOpen={true} />),
render: getRenderWrapperForComponent(
<MemoryRouter>
<CommandMenu initiallyOpen={true} />
</MemoryRouter>,
),
};

View File

@ -8,16 +8,15 @@ import {
IconSettings,
IconUser,
} from '@/ui/icons/index';
import NavBackButton from '@/ui/layout/navbar//NavBackButton';
import NavItem from '@/ui/layout/navbar/NavItem';
import NavItemsContainer from '@/ui/layout/navbar/NavItemsContainer';
import NavTitle from '@/ui/layout/navbar/NavTitle';
import SubNavbarContainer from '@/ui/layout/navbar/sub-navbar/SubNavBarContainer';
export function SettingsNavbar() {
const theme = useTheme();
return (
<>
<NavBackButton title="Settings" />
<SubNavbarContainer backButtonTitle="Settings">
<NavItemsContainer>
<NavTitle label="User" />
<NavItem
@ -64,6 +63,6 @@ export function SettingsNavbar() {
danger={true}
/>
</NavItemsContainer>
</>
</SubNavbarContainer>
);
}

View File

@ -1,11 +0,0 @@
import { SecondaryLayout } from '@/ui/layout/SecondaryLayout';
import { SettingsNavbar } from './SettingsNavbar';
type OwnProps = {
children: JSX.Element;
};
export function SettingsPage({ children }: OwnProps) {
return <SecondaryLayout Navbar={SettingsNavbar}>{children}</SecondaryLayout>;
}

View File

@ -3,6 +3,7 @@ import { useRecoilState, useRecoilValue } from 'recoil';
import { currentUserState } from '@/auth/states/currentUserState';
import { CommandMenu } from '@/search/components/CommandMenu';
import { AppNavbar } from '~/AppNavbar';
import { NavbarContainer } from './navbar/NavbarContainer';
import { isNavbarOpenedState } from './states/isNavbarOpenedState';
@ -25,9 +26,8 @@ const MainContainer = styled.div`
overflow: hidden;
width: ${() =>
useRecoilValue(isNavbarOpenedState)
? `(calc(100% - ${NAVBAR_WIDTH})`
? `calc(100% - ${NAVBAR_WIDTH})`
: '100%'};
@media (max-width: ${MOBILE_VIEWPORT}px) {
width: ${() => (useRecoilValue(isNavbarOpenedState) ? '0' : '100%')};
}
@ -35,10 +35,9 @@ const MainContainer = styled.div`
type OwnProps = {
children: JSX.Element;
Navbar: () => JSX.Element;
};
export function DefaultLayout({ children, Navbar }: OwnProps) {
export function DefaultLayout({ children }: OwnProps) {
const currentUser = useRecoilState(currentUserState);
const userIsAuthenticated = !!currentUser;
@ -48,7 +47,7 @@ export function DefaultLayout({ children, Navbar }: OwnProps) {
<>
<CommandMenu />
<NavbarContainer>
<Navbar />
<AppNavbar />
</NavbarContainer>
<MainContainer>{children}</MainContainer>
</>

View File

@ -6,6 +6,7 @@ const StyledPanel = styled.div`
border: 1px solid ${(props) => props.theme.primaryBorder};
border-radius: 8px;
display: flex;
flex-direction: row;
width: 100%;
`;

View File

@ -1,68 +0,0 @@
import styled from '@emotion/styled';
import { NavbarContainer } from './navbar/NavbarContainer';
import { MOBILE_VIEWPORT } from './styles/themes';
type OwnProps = {
children: JSX.Element;
Navbar: () => JSX.Element;
};
const StyledLayout = styled.div`
background: ${(props) => props.theme.noisyBackground};
display: flex;
flex-direction: row;
height: 100vh;
position: relative;
width: 100vw;
`;
const MainContainer = styled.div`
display: flex;
flex-direction: row;
overflow: hidden;
width: 100%;
`;
const SubContainer = styled.div`
background: ${(props) => props.theme.primaryBackground};
border: 1px solid ${(props) => props.theme.primaryBorder};
border-radius: ${(props) => props.theme.spacing(2)};
display: flex;
flex-direction: column;
margin: ${(props) => props.theme.spacing(4)};
max-width: calc(100vw - 500px);
padding: ${(props) => props.theme.spacing(8)};
width: 100%;
@media (max-width: ${MOBILE_VIEWPORT}px) {
width: 100%;
max-width: none;
}
`;
const SubSubContainer = styled.div`
color: ${(props) => props.theme.text100};
display: flex;
flex-direction: column;
gap: 32px;
width: 350px;
@media (max-width: ${MOBILE_VIEWPORT}px) {
width: 100%;
}
`;
export const SecondaryLayout = ({ children, Navbar }: OwnProps) => {
return (
<StyledLayout>
<NavbarContainer layout="secondary">
<Navbar />
</NavbarContainer>
<MainContainer>
<SubContainer>
<SubSubContainer>{children}</SubSubContainer>
</SubContainer>
</MainContainer>
</StyledLayout>
);
};

View File

@ -0,0 +1,53 @@
import styled from '@emotion/styled';
import { useRecoilState } from 'recoil';
import { Panel } from '../Panel';
import { RightDrawer } from '../right-drawer/components/RightDrawer';
import { isRightDrawerOpenState } from '../right-drawer/states/isRightDrawerOpenState';
type OwnProps = {
children: JSX.Element;
topMargin?: number;
};
const MainContainer = styled.div<{ topMargin: number }>`
background: ${(props) => props.theme.noisyBackground};
display: flex;
flex-direction: row;
gap: ${(props) => props.theme.spacing(2)};
height: calc(100% - ${(props) => props.topMargin}px);
padding-bottom: ${(props) => props.theme.spacing(3)};
padding-right: ${(props) => props.theme.spacing(3)};
width: calc(100% - ${(props) => props.theme.spacing(3)});
`;
type LeftContainerProps = {
isRightDrawerOpen?: boolean;
};
const LeftContainer = styled.div<LeftContainerProps>`
display: flex;
position: relative;
width: calc(
100% -
${(props) =>
props.isRightDrawerOpen
? `${props.theme.rightDrawerWidth} - ${props.theme.spacing(2)}`
: '0px'}
);
`;
export function ContentContainer({ children, topMargin }: OwnProps) {
const [isRightDrawerOpen] = useRecoilState(isRightDrawerOpenState);
return (
<MainContainer topMargin={topMargin ?? 0}>
<LeftContainer isRightDrawerOpen={isRightDrawerOpen}>
<Panel>{children}</Panel>
</LeftContainer>
<RightDrawer />
</MainContainer>
);
}

View File

@ -0,0 +1,21 @@
import styled from '@emotion/styled';
import { ContentContainer } from './ContentContainer';
type OwnProps = {
children: JSX.Element;
};
const StyledContainer = styled.div`
display: flex;
padding-top: ${(props) => props.theme.spacing(4)};
width: 100%;
`;
export function NoTopBarContainer({ children }: OwnProps) {
return (
<StyledContainer>
<ContentContainer topMargin={16}>{children}</ContentContainer>
</StyledContainer>
);
}

View File

@ -1,12 +1,10 @@
import { ReactNode } from 'react';
import styled from '@emotion/styled';
import { useRecoilState } from 'recoil';
import { Panel } from '../Panel';
import { RightDrawer } from '../right-drawer/components/RightDrawer';
import { isRightDrawerOpenState } from '../right-drawer/states/isRightDrawerOpenState';
import { TOP_BAR_MIN_HEIGHT, TopBar } from '../top-bar/TopBar';
import { ContentContainer } from './ContentContainer';
type OwnProps = {
children: JSX.Element;
title: string;
@ -20,53 +18,18 @@ const StyledContainer = styled.div`
width: 100%;
`;
const MainContainer = styled.div`
background: ${(props) => props.theme.noisyBackground};
display: flex;
flex-direction: row;
gap: ${(props) => props.theme.spacing(2)};
height: calc(
100% - ${TOP_BAR_MIN_HEIGHT} - ${(props) => props.theme.spacing(2)} -
${(props) => props.theme.spacing(5)}
);
padding-bottom: ${(props) => props.theme.spacing(3)};
padding-right: ${(props) => props.theme.spacing(3)};
width: calc(100% - ${(props) => props.theme.spacing(3)});
`;
type LeftContainerProps = {
isRightDrawerOpen?: boolean;
};
const LeftContainer = styled.div<LeftContainerProps>`
display: flex;
position: relative;
width: calc(
100% -
${(props) =>
props.isRightDrawerOpen
? `${props.theme.rightDrawerWidth} - ${props.theme.spacing(2)}`
: '0px'}
);
`;
export function WithTopBarContainer({
children,
title,
icon,
onAddButtonClick,
}: OwnProps) {
const [isRightDrawerOpen] = useRecoilState(isRightDrawerOpenState);
return (
<StyledContainer>
<TopBar title={title} icon={icon} onAddButtonClick={onAddButtonClick} />
<MainContainer>
<LeftContainer isRightDrawerOpen={isRightDrawerOpen}>
<Panel>{children}</Panel>
</LeftContainer>
<RightDrawer />
</MainContainer>
<ContentContainer topMargin={TOP_BAR_MIN_HEIGHT}>
{children}
</ContentContainer>
</StyledContainer>
);
}

View File

@ -8,6 +8,7 @@ const StyledNavItemsContainer = styled.div`
display: flex;
flex-direction: column;
margin-top: 40px;
min-width: 220px;
`;
function NavItemsContainer({ children }: OwnProps) {

View File

@ -4,10 +4,9 @@ import { useRecoilValue } from 'recoil';
import { isNavbarOpenedState } from '../states/isNavbarOpenedState';
import { MOBILE_VIEWPORT } from '../styles/themes';
const StyledNavbarContainer = styled.div<{ width: string }>`
const StyledNavbarContainer = styled.div`
flex-direction: column;
width: ${(props) =>
useRecoilValue(isNavbarOpenedState) ? props.width : '0'};
width: ${(props) => (useRecoilValue(isNavbarOpenedState) ? 'auto' : '0')};
padding: ${(props) => props.theme.spacing(2)};
flex-shrink: 0;
overflow: hidden;
@ -19,18 +18,6 @@ const StyledNavbarContainer = styled.div<{ width: string }>`
: '0'};
`;
const NavbarSubContainer = styled.div`
display: flex;
flex-direction: column;
margin-left: auto;
margin-top: 41px;
width: 160px;
@media (max-width: ${MOBILE_VIEWPORT}px) {
width: 100%;
}
`;
const NavbarContent = styled.div`
display: ${() => (useRecoilValue(isNavbarOpenedState) ? 'block' : 'none')};
`;
@ -44,18 +31,8 @@ export const NavbarContainer: React.FC<NavbarProps> = ({
children,
layout,
}) => {
if (layout === 'secondary') {
return (
<StyledNavbarContainer width="500px">
<NavbarSubContainer>
<NavbarContent>{children}</NavbarContent>
</NavbarSubContainer>
</StyledNavbarContainer>
);
}
return (
<StyledNavbarContainer width="220px">
<StyledNavbarContainer>
<NavbarContent>{children}</NavbarContent>
</StyledNavbarContainer>
);

View File

@ -3,7 +3,7 @@ import styled from '@emotion/styled';
import { IconChevronLeft } from '@/ui/icons/index';
import NavCollapseButton from './NavCollapseButton';
import NavCollapseButton from '../NavCollapseButton';
type OwnProps = {
title: string;

View File

@ -0,0 +1,32 @@
import styled from '@emotion/styled';
import NavBackButton from './NavBackButton';
type OwnProps = {
children: JSX.Element;
backButtonTitle: string;
};
const StyledContainer = styled.div`
display: flex;
flex-direction: column;
padding-left: 300px;
padding-top: ${(props) => props.theme.spacing(6)};
`;
const StyledNavItemsContainer = styled.div`
display: flex;
flex-direction: column;
`;
export default function SubNavbarContainer({
children,
backButtonTitle,
}: OwnProps) {
return (
<StyledContainer>
<NavBackButton title={backButtonTitle} />
<StyledNavItemsContainer>{children}</StyledNavItemsContainer>
</StyledContainer>
);
}

View File

@ -5,7 +5,7 @@ import { IconPlus } from '@/ui/icons/index';
import NavCollapseButton from '../navbar/NavCollapseButton';
export const TOP_BAR_MIN_HEIGHT = '40px';
export const TOP_BAR_MIN_HEIGHT = 40;
const TopBarContainer = styled.div`
align-items: center;
@ -14,7 +14,7 @@ const TopBarContainer = styled.div`
display: flex;
flex-direction: row;
font-size: 14px;
min-height: ${TOP_BAR_MIN_HEIGHT};
min-height: ${TOP_BAR_MIN_HEIGHT}px;
padding: ${(props) => props.theme.spacing(2)};
`;