Refactor UI folder (#2016)

* Added Overview page

* Revised Getting Started page

* Minor revision

* Edited readme, minor modifications to docs

* Removed sweep.yaml, .devcontainer, .ergomake

* Moved security.md to .github, added contributing.md

* changes as per code review

* updated contributing.md

* fixed broken links & added missing links in doc, improved structure

* fixed link in wsl setup

* fixed server link, added https cloning in yarn-setup

* removed package-lock.json

* added doc card, admonitions

* removed underline from nav buttons

* refactoring modules/ui

* refactoring modules/ui

* Change folder case

* Fix theme location

* Fix case 2

* Fix storybook

---------

Co-authored-by: Nimra Ahmed <nimra1408@gmail.com>
Co-authored-by: Nimra Ahmed <50912134+nimraahmed@users.noreply.github.com>
This commit is contained in:
Charles Bochet
2023-10-14 00:04:29 +02:00
committed by GitHub
parent a35ea5e8f9
commit 258685467b
732 changed files with 1106 additions and 1010 deletions

View File

@ -0,0 +1,86 @@
import styled from '@emotion/styled';
import { AnimatePresence, LayoutGroup } from 'framer-motion';
import { useRecoilValue } from 'recoil';
import { AuthModal } from '@/auth/components/Modal';
import { useOnboardingStatus } from '@/auth/hooks/useOnboardingStatus';
import { OnboardingStatus } from '@/auth/utils/getOnboardingStatus';
import { CommandMenu } from '@/command-menu/components/CommandMenu';
import { NavbarAnimatedContainer } from '@/ui/navigation/navbar/components/NavbarAnimatedContainer';
import { MOBILE_VIEWPORT } from '@/ui/theme/constants/theme';
import { AppNavbar } from '~/AppNavbar';
import { CompaniesMockMode } from '~/pages/companies/CompaniesMockMode';
import { isNavbarOpenedState } from '../states/isNavbarOpenedState';
const StyledLayout = styled.div`
background: ${({ theme }) => theme.background.noisy};
display: flex;
flex-direction: row;
height: 100vh;
position: relative;
scrollbar-color: ${({ theme }) => theme.border.color.medium};
scrollbar-width: 4px;
width: 100vw;
*::-webkit-scrollbar {
height: 4px;
width: 4px;
}
*::-webkit-scrollbar-corner {
background-color: transparent;
}
*::-webkit-scrollbar-thumb {
background-color: transparent;
border-radius: ${({ theme }) => theme.border.radius.sm};
}
`;
const NAVBAR_WIDTH = '236px';
const StyledMainContainer = styled.div`
display: flex;
flex-direction: row;
overflow: hidden;
width: ${() =>
useRecoilValue(isNavbarOpenedState)
? `calc(100% - ${NAVBAR_WIDTH})`
: '100%'};
@media (max-width: ${MOBILE_VIEWPORT}px) {
width: ${() => (useRecoilValue(isNavbarOpenedState) ? '0' : '100%')};
}
`;
type DefaultLayoutProps = {
children: React.ReactNode;
};
export const DefaultLayout = ({ children }: DefaultLayoutProps) => {
const onboardingStatus = useOnboardingStatus();
return (
<StyledLayout>
<CommandMenu />
<NavbarAnimatedContainer>
<AppNavbar />
</NavbarAnimatedContainer>
<StyledMainContainer>
{onboardingStatus && onboardingStatus !== OnboardingStatus.Completed ? (
<>
<CompaniesMockMode />
<AnimatePresence mode="wait">
<LayoutGroup>
<AuthModal>{children}</AuthModal>
</LayoutGroup>
</AnimatePresence>
</>
) : (
<>{children}</>
)}
</StyledMainContainer>
</StyledLayout>
);
};

View File

@ -0,0 +1,18 @@
import { IconPlus } from '@/ui/display/icon';
import { IconButton } from '@/ui/input/button/components/IconButton';
type PageAddButtonProps = {
onClick: () => void;
};
export const PageAddButton = ({ onClick }: PageAddButtonProps) => (
<IconButton
Icon={IconPlus}
dataTestId="add-button"
size="medium"
variant="secondary"
accent="default"
onClick={onClick}
ariaLabel="Add"
/>
);

View File

@ -0,0 +1,12 @@
import { PAGE_BAR_MIN_HEIGHT } from './PageHeader';
import { RightDrawerContainer } from './RightDrawerContainer';
type PageBodyProps = {
children: JSX.Element | JSX.Element[];
};
export const PageBody = ({ children }: PageBodyProps) => (
<RightDrawerContainer topMargin={PAGE_BAR_MIN_HEIGHT + 16 + 16}>
{children}
</RightDrawerContainer>
);

View File

@ -0,0 +1,15 @@
import styled from '@emotion/styled';
type PageContainerProps = {
children: JSX.Element | JSX.Element[];
};
const StyledContainer = styled.div`
display: flex;
flex-direction: column;
width: 100%;
`;
export const PageContainer = ({ children }: PageContainerProps) => (
<StyledContainer>{children}</StyledContainer>
);

View File

@ -0,0 +1,21 @@
import { IconHeart } from '@/ui/display/icon';
import { IconButton } from '@/ui/input/button/components/IconButton';
type PageFavoriteButtonProps = {
isFavorite: boolean;
onClick: () => void;
};
export const PageFavoriteButton = ({
isFavorite,
onClick,
}: PageFavoriteButtonProps) => (
<IconButton
Icon={IconHeart}
size="medium"
variant="secondary"
data-testid="add-button"
accent={isFavorite ? 'danger' : 'default'}
onClick={onClick}
/>
);

View File

@ -0,0 +1,124 @@
import { ComponentProps, useCallback } from 'react';
import { useNavigate } from 'react-router-dom';
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import { useRecoilValue } from 'recoil';
import { IconChevronLeft } from '@/ui/display/icon/index';
import { IconComponent } from '@/ui/display/icon/types/IconComponent';
import { OverflowingTextWithTooltip } from '@/ui/display/tooltip/OverflowingTextWithTooltip';
import {
IconButton,
IconButtonSize,
} from '@/ui/input/button/components/IconButton';
import NavCollapseButton from '@/ui/navigation/navbar/components/NavCollapseButton';
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
import { isNavbarOpenedState } from '../states/isNavbarOpenedState';
export const PAGE_BAR_MIN_HEIGHT = 40;
const StyledTopBarContainer = styled.div`
align-items: center;
background: ${({ theme }) => theme.background.noisy};
color: ${({ theme }) => theme.font.color.primary};
display: flex;
flex-direction: row;
font-size: ${({ theme }) => theme.font.size.lg};
justify-content: space-between;
min-height: ${PAGE_BAR_MIN_HEIGHT}px;
padding: ${({ theme }) => theme.spacing(2)};
padding-left: 0;
padding-right: ${({ theme }) => theme.spacing(3)};
z-index: 20;
`;
const StyledLeftContainer = styled.div`
align-items: center;
display: flex;
flex-direction: row;
width: 100%;
`;
const StyledTitleContainer = styled.div`
display: flex;
font-size: ${({ theme }) => theme.font.size.md};
margin-left: ${({ theme }) => theme.spacing(1)};
max-width: 50%;
`;
const StyledTopBarButtonContainer = styled.div`
margin-left: ${({ theme }) => theme.spacing(1)};
margin-right: ${({ theme }) => theme.spacing(1)};
`;
const StyledBackIconButton = styled(IconButton)`
margin-right: ${({ theme }) => theme.spacing(1)};
`;
const StyledTopBarIconStyledTitleContainer = styled.div<{
hideLeftPadding?: boolean;
}>`
align-items: center;
display: flex;
flex-direction: row;
padding-left: ${({ theme, hideLeftPadding }) =>
hideLeftPadding ? theme.spacing(2) : undefined};
width: 100%;
`;
const StyledPageActionContainer = styled.div`
display: inline-flex;
gap: ${({ theme }) => theme.spacing(2)};
`;
type PageHeaderProps = ComponentProps<'div'> & {
title: string;
hasBackButton?: boolean;
Icon: IconComponent;
children?: JSX.Element | JSX.Element[];
};
export const PageHeader = ({
title,
hasBackButton,
Icon,
children,
}: PageHeaderProps) => {
const navigate = useNavigate();
const navigateBack = useCallback(() => navigate(-1), [navigate]);
const isNavbarOpened = useRecoilValue(isNavbarOpenedState);
const iconSize: IconButtonSize = useIsMobile() ? 'small' : 'medium';
const theme = useTheme();
return (
<StyledTopBarContainer>
<StyledLeftContainer>
{!isNavbarOpened && (
<StyledTopBarButtonContainer>
<NavCollapseButton direction="right" />
</StyledTopBarButtonContainer>
)}
{hasBackButton && (
<StyledTopBarButtonContainer>
<StyledBackIconButton
Icon={IconChevronLeft}
size={iconSize}
onClick={navigateBack}
variant="tertiary"
/>
</StyledTopBarButtonContainer>
)}
<StyledTopBarIconStyledTitleContainer hideLeftPadding={!hasBackButton}>
{Icon && <Icon size={theme.icon.size.md} />}
<StyledTitleContainer data-testid="top-bar-title">
<OverflowingTextWithTooltip text={title} />
</StyledTitleContainer>
</StyledTopBarIconStyledTitleContainer>
</StyledLeftContainer>
<StyledPageActionContainer>{children}</StyledPageActionContainer>
</StyledTopBarContainer>
);
};

View File

@ -0,0 +1,16 @@
import { TableHotkeyScope } from '@/ui/data/data-table/types/TableHotkeyScope';
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
type PageHotkeysEffectProps = {
onAddButtonClick?: () => void;
};
export const PageHotkeysEffect = ({
onAddButtonClick,
}: PageHotkeysEffectProps) => {
useScopedHotkeys('c', () => onAddButtonClick?.(), TableHotkeyScope.Table, [
onAddButtonClick,
]);
return <></>;
};

View File

@ -0,0 +1,17 @@
import React from 'react';
import styled from '@emotion/styled';
const StyledPanel = styled.div`
background: ${({ theme }) => theme.background.primary};
border: 1px solid ${({ theme }) => theme.border.color.medium};
border-radius: ${({ theme }) => theme.border.radius.md};
display: flex;
flex-direction: row;
height: 100%;
overflow: auto;
width: 100%;
`;
export const PagePanel = ({ children }: { children: React.ReactNode }) => (
<StyledPanel>{children}</StyledPanel>
);

View File

@ -0,0 +1,46 @@
import styled from '@emotion/styled';
import { RightDrawer } from '@/ui/layout/right-drawer/components/RightDrawer';
import { PagePanel } from './PagePanel';
type RightDrawerContainerProps = {
children: JSX.Element | JSX.Element[];
topMargin?: number;
};
const StyledMainContainer = styled.div<{ topMargin: number }>`
background: ${({ theme }) => theme.background.noisy};
display: flex;
flex-direction: row;
gap: ${({ theme }) => theme.spacing(2)};
height: calc(100% - ${(props) => props.topMargin}px);
padding-bottom: ${({ theme }) => theme.spacing(3)};
padding-right: ${({ theme }) => theme.spacing(3)};
width: calc(100% - ${({ theme }) => theme.spacing(3)});
`;
type LeftContainerProps = {
isRightDrawerOpen?: boolean;
};
const StyledLeftContainer = styled.div<LeftContainerProps>`
display: flex;
flex-direction: column;
position: relative;
width: 100%;
`;
export const RightDrawerContainer = ({
children,
topMargin,
}: RightDrawerContainerProps) => (
<StyledMainContainer topMargin={topMargin ?? 0}>
<StyledLeftContainer>
<PagePanel>{children}</PagePanel>
</StyledLeftContainer>
<RightDrawer />
</StyledMainContainer>
);

View File

@ -0,0 +1,44 @@
import { ReactElement } from 'react';
import styled from '@emotion/styled';
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
import { ScrollWrapper } from '@/ui/utilities/scroll/components/ScrollWrapper';
const StyledOuterContainer = styled.div`
display: flex;
gap: ${({ theme }) => (useIsMobile() ? theme.spacing(3) : '0')};
height: ${() => (useIsMobile() ? '100%' : 'auto')};
overflow-x: ${() => (useIsMobile() ? 'hidden' : 'auto')};
width: 100%;
`;
const StyledInnerContainer = styled.div`
display: flex;
flex-direction: ${() => (useIsMobile() ? 'column' : 'row')};
width: 100%;
`;
const StyledScrollWrapper = styled(ScrollWrapper)`
background-color: ${({ theme }) => theme.background.secondary};
border-radius: ${({ theme }) => theme.border.radius.md};
`;
export type ShowPageContainerProps = {
children: ReactElement[];
};
export const ShowPageContainer = ({ children }: ShowPageContainerProps) => {
const isMobile = useIsMobile();
return isMobile ? (
<StyledOuterContainer>
<StyledScrollWrapper>
<StyledInnerContainer>{children}</StyledInnerContainer>
</StyledScrollWrapper>
</StyledOuterContainer>
) : (
<StyledOuterContainer>
<StyledInnerContainer>{children}</StyledInnerContainer>
</StyledOuterContainer>
);
};

View File

@ -0,0 +1,36 @@
import { JSX } from 'react';
import styled from '@emotion/styled';
import { IconComponent } from '@/ui/display/icon/types/IconComponent';
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
import { PageHeader } from './PageHeader';
import { RightDrawerContainer } from './RightDrawerContainer';
type SubMenuTopBarContainerProps = {
children: JSX.Element | JSX.Element[];
title: string;
Icon: IconComponent;
};
const StyledContainer = styled.div<{ isMobile: boolean }>`
display: flex;
flex-direction: column;
padding-top: ${({ theme, isMobile }) => (!isMobile ? theme.spacing(4) : 0)};
width: 100%;
`;
export const SubMenuTopBarContainer = ({
children,
title,
Icon,
}: SubMenuTopBarContainerProps) => {
const isMobile = useIsMobile();
return (
<StyledContainer isMobile={isMobile}>
{isMobile && <PageHeader title={title} Icon={Icon} />}
<RightDrawerContainer topMargin={16}>{children}</RightDrawerContainer>
</StyledContainer>
);
};