Refactor Layout (#322)
* Refactor Layout * Fix storybook * Fixing tests by forcing msw version before regression
This commit is contained in:
@ -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>,
|
||||
),
|
||||
};
|
||||
|
||||
@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
@ -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>;
|
||||
}
|
||||
@ -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>
|
||||
</>
|
||||
|
||||
@ -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%;
|
||||
`;
|
||||
|
||||
|
||||
@ -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>
|
||||
);
|
||||
};
|
||||
53
front/src/modules/ui/layout/containers/ContentContainer.tsx
Normal file
53
front/src/modules/ui/layout/containers/ContentContainer.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
21
front/src/modules/ui/layout/containers/NoTopBarContainer.tsx
Normal file
21
front/src/modules/ui/layout/containers/NoTopBarContainer.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
@ -8,6 +8,7 @@ const StyledNavItemsContainer = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin-top: 40px;
|
||||
min-width: 220px;
|
||||
`;
|
||||
|
||||
function NavItemsContainer({ children }: OwnProps) {
|
||||
|
||||
@ -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>
|
||||
);
|
||||
|
||||
@ -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;
|
||||
@ -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>
|
||||
);
|
||||
}
|
||||
@ -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)};
|
||||
`;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user