Design fixes (#665)
This commit is contained in:
@ -7,7 +7,7 @@ import { AppNavbar } from '~/AppNavbar';
|
||||
|
||||
import { MOBILE_VIEWPORT } from '../themes/themes';
|
||||
|
||||
import { NavbarContainer } from './navbar/NavbarContainer';
|
||||
import { NavbarAnimatedContainer } from './navbar/NavbarAnimatedContainer';
|
||||
import { isNavbarOpenedState } from './states/isNavbarOpenedState';
|
||||
|
||||
const StyledLayout = styled.div`
|
||||
@ -47,9 +47,9 @@ export function DefaultLayout({ children }: OwnProps) {
|
||||
{userIsAuthenticated ? (
|
||||
<>
|
||||
<CommandMenu />
|
||||
<NavbarContainer>
|
||||
<NavbarAnimatedContainer>
|
||||
<AppNavbar />
|
||||
</NavbarContainer>
|
||||
</NavbarAnimatedContainer>
|
||||
<MainContainer>{children}</MainContainer>
|
||||
</>
|
||||
) : (
|
||||
|
||||
@ -0,0 +1,6 @@
|
||||
import { useLocation } from 'react-router-dom';
|
||||
|
||||
export function useIsSubNavbarDisplayed() {
|
||||
const currentPath = useLocation().pathname;
|
||||
return currentPath.match(/\/settings\//g) !== null;
|
||||
}
|
||||
21
front/src/modules/ui/layout/navbar/MainNavbar.tsx
Normal file
21
front/src/modules/ui/layout/navbar/MainNavbar.tsx
Normal file
@ -0,0 +1,21 @@
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import NavItemsContainer from './NavItemsContainer';
|
||||
import NavWorkspaceButton from './NavWorkspaceButton';
|
||||
|
||||
type OwnProps = {
|
||||
children: JSX.Element;
|
||||
};
|
||||
|
||||
const StyledContainer = styled.div`
|
||||
width: 220px;
|
||||
`;
|
||||
|
||||
export default function MainNavbar({ children }: OwnProps) {
|
||||
return (
|
||||
<StyledContainer>
|
||||
<NavWorkspaceButton />
|
||||
<NavItemsContainer>{children}</NavItemsContainer>
|
||||
</StyledContainer>
|
||||
);
|
||||
}
|
||||
@ -8,7 +8,6 @@ const StyledNavItemsContainer = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin-top: 40px;
|
||||
min-width: 220px;
|
||||
`;
|
||||
|
||||
function NavItemsContainer({ children }: OwnProps) {
|
||||
|
||||
@ -0,0 +1,57 @@
|
||||
import { useTheme } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
import { motion } from 'framer-motion';
|
||||
import { useRecoilState, useRecoilValue } from 'recoil';
|
||||
|
||||
import { MOBILE_VIEWPORT } from '@/ui/themes/themes';
|
||||
|
||||
import { useIsSubNavbarDisplayed } from '../hooks/useIsSubNavbarDisplayed';
|
||||
import { isNavbarOpenedState } from '../states/isNavbarOpenedState';
|
||||
import { isNavbarSwitchingSizeState } from '../states/isNavbarSwitchingSizeState';
|
||||
|
||||
const StyledNavbarContainer = styled(motion.div)`
|
||||
align-items: end;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-shrink: 0;
|
||||
overflow: hidden;
|
||||
padding: ${({ theme }) => theme.spacing(2)};
|
||||
|
||||
@media (max-width: ${MOBILE_VIEWPORT}px) {
|
||||
width: ${(props) =>
|
||||
useRecoilValue(isNavbarOpenedState)
|
||||
? `calc(100% - ` + props.theme.spacing(4) + `)`
|
||||
: '0'};
|
||||
}
|
||||
`;
|
||||
|
||||
type NavbarProps = {
|
||||
children: React.ReactNode;
|
||||
layout?: string;
|
||||
};
|
||||
|
||||
export function NavbarAnimatedContainer({ children, layout }: NavbarProps) {
|
||||
const isMenuOpened = useRecoilValue(isNavbarOpenedState);
|
||||
const [, setIsNavbarSwitchingSize] = useRecoilState(
|
||||
isNavbarSwitchingSizeState,
|
||||
);
|
||||
const isSubNavbarDisplayed = useIsSubNavbarDisplayed();
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
<StyledNavbarContainer
|
||||
onAnimationComplete={() => {
|
||||
setIsNavbarSwitchingSize(false);
|
||||
}}
|
||||
animate={{
|
||||
width: isMenuOpened ? (isSubNavbarDisplayed ? '520px' : '220px') : '0',
|
||||
opacity: isMenuOpened ? 1 : 0,
|
||||
}}
|
||||
transition={{
|
||||
duration: theme.animation.duration.visible,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</StyledNavbarContainer>
|
||||
);
|
||||
}
|
||||
@ -1,38 +0,0 @@
|
||||
import styled from '@emotion/styled';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
|
||||
import { MOBILE_VIEWPORT } from '@/ui/themes/themes';
|
||||
|
||||
import { isNavbarOpenedState } from '../states/isNavbarOpenedState';
|
||||
|
||||
const StyledNavbarContainer = styled.div`
|
||||
flex-direction: column;
|
||||
flex-shrink: 0;
|
||||
overflow: hidden;
|
||||
padding: ${({ theme }) => theme.spacing(2)};
|
||||
width: ${(props) => (useRecoilValue(isNavbarOpenedState) ? 'auto' : '0')};
|
||||
|
||||
@media (max-width: ${MOBILE_VIEWPORT}px) {
|
||||
width: ${(props) =>
|
||||
useRecoilValue(isNavbarOpenedState)
|
||||
? `calc(100% - ` + props.theme.spacing(4) + `)`
|
||||
: '0'};
|
||||
}
|
||||
`;
|
||||
|
||||
const NavbarContent = styled.div`
|
||||
display: ${() => (useRecoilValue(isNavbarOpenedState) ? 'block' : 'none')};
|
||||
`;
|
||||
|
||||
type NavbarProps = {
|
||||
children: React.ReactNode;
|
||||
layout?: string;
|
||||
};
|
||||
|
||||
export function NavbarContainer({ children, layout }: NavbarProps) {
|
||||
return (
|
||||
<StyledNavbarContainer>
|
||||
<NavbarContent>{children}</NavbarContent>
|
||||
</StyledNavbarContainer>
|
||||
);
|
||||
}
|
||||
@ -1,8 +1,10 @@
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import styled from '@emotion/styled';
|
||||
import { useRecoilState } from 'recoil';
|
||||
|
||||
import { IconChevronLeft } from '@/ui/icons/index';
|
||||
|
||||
import { isNavbarSwitchingSizeState } from '../../states/isNavbarSwitchingSizeState';
|
||||
import NavCollapseButton from '../NavCollapseButton';
|
||||
|
||||
type OwnProps = {
|
||||
@ -32,12 +34,18 @@ const StyledContainer = styled.div`
|
||||
|
||||
export default function NavBackButton({ title }: OwnProps) {
|
||||
const navigate = useNavigate();
|
||||
const [, setIsNavbarSwitchingSize] = useRecoilState(
|
||||
isNavbarSwitchingSizeState,
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<StyledContainer>
|
||||
<IconAndButtonContainer
|
||||
onClick={() => navigate('/', { replace: true })}
|
||||
onClick={() => {
|
||||
setIsNavbarSwitchingSize(true);
|
||||
navigate('/', { replace: true });
|
||||
}}
|
||||
>
|
||||
<IconChevronLeft />
|
||||
<span>{title}</span>
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import NavItemsContainer from '../NavItemsContainer';
|
||||
|
||||
import NavBackButton from './NavBackButton';
|
||||
|
||||
type OwnProps = {
|
||||
@ -10,23 +12,15 @@ type OwnProps = {
|
||||
const StyledContainer = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding-left: 300px;
|
||||
padding-top: ${({ theme }) => theme.spacing(6)};
|
||||
width: 220px;
|
||||
`;
|
||||
|
||||
const StyledNavItemsContainer = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
`;
|
||||
|
||||
export default function SubNavbarContainer({
|
||||
children,
|
||||
backButtonTitle,
|
||||
}: OwnProps) {
|
||||
export default function SubNavbar({ children, backButtonTitle }: OwnProps) {
|
||||
return (
|
||||
<StyledContainer>
|
||||
<NavBackButton title={backButtonTitle} />
|
||||
<StyledNavItemsContainer>{children}</StyledNavItemsContainer>
|
||||
<NavItemsContainer>{children}</NavItemsContainer>
|
||||
</StyledContainer>
|
||||
);
|
||||
}
|
||||
@ -1,5 +1,7 @@
|
||||
import { useRef } from 'react';
|
||||
import { useTheme } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
import { motion } from 'framer-motion';
|
||||
import { useRecoilState } from 'recoil';
|
||||
|
||||
import {
|
||||
@ -13,16 +15,15 @@ import { rightDrawerPageState } from '../states/rightDrawerPageState';
|
||||
|
||||
import { RightDrawerRouter } from './RightDrawerRouter';
|
||||
|
||||
const StyledContainer = styled.div`
|
||||
const StyledContainer = styled(motion.div)`
|
||||
background: ${({ theme }) => theme.background.primary};
|
||||
box-shadow: ${({ theme }) => theme.boxShadow.strong};
|
||||
height: 100%;
|
||||
overflow-x: hidden;
|
||||
position: fixed;
|
||||
|
||||
right: 0;
|
||||
top: 0;
|
||||
transition: width 0.5s;
|
||||
width: ${({ theme }) => theme.rightDrawerWidth};
|
||||
z-index: 2;
|
||||
`;
|
||||
|
||||
@ -45,17 +46,23 @@ export function RightDrawer() {
|
||||
callback: () => setIsRightDrawerOpen(false),
|
||||
mode: OutsideClickAlerterMode.absolute,
|
||||
});
|
||||
if (!isRightDrawerOpen || !isDefined(rightDrawerPage)) {
|
||||
const theme = useTheme();
|
||||
if (!isDefined(rightDrawerPage)) {
|
||||
return <></>;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<StyledContainer>
|
||||
<StyledRightDrawer ref={rightDrawerRef}>
|
||||
<RightDrawerRouter />
|
||||
</StyledRightDrawer>
|
||||
</StyledContainer>
|
||||
</>
|
||||
<StyledContainer
|
||||
animate={{
|
||||
width: isRightDrawerOpen ? theme.rightDrawerWidth : '0',
|
||||
}}
|
||||
transition={{
|
||||
duration: theme.animation.duration.visible,
|
||||
}}
|
||||
>
|
||||
<StyledRightDrawer ref={rightDrawerRef}>
|
||||
<RightDrawerRouter />
|
||||
</StyledRightDrawer>
|
||||
</StyledContainer>
|
||||
);
|
||||
}
|
||||
|
||||
@ -0,0 +1,6 @@
|
||||
import { atom } from 'recoil';
|
||||
|
||||
export const isNavbarSwitchingSizeState = atom({
|
||||
key: 'ui/isNavbarSwitchingSizeState',
|
||||
default: true,
|
||||
});
|
||||
@ -1,6 +1,7 @@
|
||||
import { ReactNode } from 'react';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import { IconButton } from '@/ui/components/buttons/IconButton';
|
||||
import { IconPlus } from '@/ui/icons/index';
|
||||
|
||||
import NavCollapseButton from '../navbar/NavCollapseButton';
|
||||
@ -16,6 +17,7 @@ const TopBarContainer = styled.div`
|
||||
font-size: 14px;
|
||||
min-height: ${TOP_BAR_MIN_HEIGHT}px;
|
||||
padding: ${({ theme }) => theme.spacing(2)};
|
||||
padding-right: ${({ theme }) => theme.spacing(3)};
|
||||
`;
|
||||
|
||||
const TitleContainer = styled.div`
|
||||
@ -26,22 +28,6 @@ const TitleContainer = styled.div`
|
||||
width: 100%;
|
||||
`;
|
||||
|
||||
const AddButtonContainer = styled.div`
|
||||
align-items: center;
|
||||
border: 1px solid ${({ theme }) => theme.border.color.medium};
|
||||
border-radius: ${({ theme }) => theme.border.radius.sm};
|
||||
color: ${({ theme }) => theme.font.color.tertiary};
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
flex-shrink: 0;
|
||||
height: 28px;
|
||||
justify-content: center;
|
||||
justify-self: flex-end;
|
||||
margin-right: ${({ theme }) => theme.spacing(1)};
|
||||
user-select: none;
|
||||
width: 28px;
|
||||
`;
|
||||
|
||||
type OwnProps = {
|
||||
title: string;
|
||||
icon: ReactNode;
|
||||
@ -56,12 +42,13 @@ export function TopBar({ title, icon, onAddButtonClick }: OwnProps) {
|
||||
{icon}
|
||||
<TitleContainer data-testid="top-bar-title">{title}</TitleContainer>
|
||||
{onAddButtonClick && (
|
||||
<AddButtonContainer
|
||||
<IconButton
|
||||
icon={<IconPlus size={16} />}
|
||||
size="large"
|
||||
data-testid="add-button"
|
||||
onClick={onAddButtonClick}
|
||||
>
|
||||
<IconPlus size={16} />
|
||||
</AddButtonContainer>
|
||||
variant="border"
|
||||
/>
|
||||
)}
|
||||
</TopBarContainer>
|
||||
</>
|
||||
|
||||
Reference in New Issue
Block a user