Migrate to a monorepo structure (#2909)

This commit is contained in:
Charles Bochet
2023-12-10 18:10:54 +01:00
committed by GitHub
parent a70a9281eb
commit 5bdca9de6c
2304 changed files with 37152 additions and 25869 deletions

View File

@ -0,0 +1,91 @@
import { ReactNode } from 'react';
import styled from '@emotion/styled';
import { AnimatePresence, LayoutGroup } from 'framer-motion';
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 { AppErrorBoundary } from '@/error-handler/components/AppErrorBoundary';
import { KeyboardShortcutMenu } from '@/keyboard-shortcut-menu/components/KeyboardShortcutMenu';
import { AppNavigationDrawer } from '@/navigation/components/AppNavigationDrawer';
import { MobileNavigationBar } from '@/navigation/components/MobileNavigationBar';
import { SignInBackgroundMockPage } from '@/sign-in-background-mock/components/SignInBackgroundMockPage';
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
const StyledLayout = styled.div`
background: ${({ theme }) => theme.background.noisy};
display: flex;
flex-direction: column;
height: 100vh;
position: relative;
scrollbar-color: ${({ theme }) => theme.border.color.medium};
scrollbar-width: 4px;
width: 100%;
*::-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 StyledPageContainer = styled.div`
display: flex;
flex: 1 1 auto;
flex-direction: row;
min-height: 0;
`;
const StyledAppNavigationDrawer = styled(AppNavigationDrawer)`
flex-shrink: 0;
`;
const StyledMainContainer = styled.div`
display: flex;
flex: 0 1 100%;
overflow: hidden;
`;
type DefaultLayoutProps = {
children: ReactNode;
};
export const DefaultLayout = ({ children }: DefaultLayoutProps) => {
const onboardingStatus = useOnboardingStatus();
const isMobile = useIsMobile();
return (
<StyledLayout>
<CommandMenu />
<KeyboardShortcutMenu />
<StyledPageContainer>
<StyledAppNavigationDrawer />
<StyledMainContainer>
{onboardingStatus &&
onboardingStatus !== OnboardingStatus.Completed ? (
<>
<SignInBackgroundMockPage />
<AnimatePresence mode="wait">
<LayoutGroup>
<AuthModal>{children}</AuthModal>
</LayoutGroup>
</AnimatePresence>
</>
) : (
<AppErrorBoundary>{children}</AppErrorBoundary>
)}
</StyledMainContainer>
</StyledPageContainer>
{isMobile && <MobileNavigationBar />}
</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 @@
export { RightDrawerContainer as PageBody } from './RightDrawerContainer';

View File

@ -0,0 +1,9 @@
import styled from '@emotion/styled';
const StyledContainer = styled.div`
display: flex;
flex-direction: column;
width: 100%;
`;
export { StyledContainer as PageContainer };

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,122 @@
import { ComponentProps, ReactNode } 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 } from '@/ui/input/button/components/IconButton';
import { NavigationDrawerCollapseButton } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerCollapseButton';
import { isNavigationDrawerOpenState } from '@/ui/navigation/states/isNavigationDrawerOpenState';
import { MOBILE_VIEWPORT } from '@/ui/theme/constants/theme';
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
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;
@media (max-width: ${MOBILE_VIEWPORT}px) {
padding-left: ${({ theme }) => theme.spacing(3)};
}
`;
const StyledLeftContainer = styled.div`
align-items: center;
display: flex;
flex-direction: row;
gap: ${({ theme }) => theme.spacing(1)};
padding-left: ${({ theme }) => theme.spacing(2)};
width: 100%;
@media (max-width: ${MOBILE_VIEWPORT}px) {
padding-left: ${({ theme }) => theme.spacing(1)};
}
`;
const StyledTitleContainer = styled.div`
display: flex;
font-size: ${({ theme }) => theme.font.size.md};
margin-left: ${({ theme }) => theme.spacing(1)};
max-width: 50%;
`;
const StyledBackIconButton = styled(IconButton)`
margin-right: ${({ theme }) => theme.spacing(1)};
`;
const StyledTopBarIconStyledTitleContainer = styled.div`
align-items: center;
display: flex;
flex: 1 0 100%;
flex-direction: row;
`;
const StyledPageActionContainer = styled.div`
display: inline-flex;
gap: ${({ theme }) => theme.spacing(2)};
`;
const StyledTopBarButtonContainer = styled.div`
margin-left: ${({ theme }) => theme.spacing(1)};
margin-right: ${({ theme }) => theme.spacing(1)};
`;
type PageHeaderProps = ComponentProps<'div'> & {
title: string;
hasBackButton?: boolean;
Icon: IconComponent;
children?: ReactNode;
};
export const PageHeader = ({
title,
hasBackButton,
Icon,
children,
}: PageHeaderProps) => {
const isMobile = useIsMobile();
const navigate = useNavigate();
const theme = useTheme();
const isNavigationDrawerOpen = useRecoilValue(isNavigationDrawerOpenState);
return (
<StyledTopBarContainer>
<StyledLeftContainer>
{!isMobile && !isNavigationDrawerOpen && (
<StyledTopBarButtonContainer>
<NavigationDrawerCollapseButton direction="right" />
</StyledTopBarButtonContainer>
)}
{hasBackButton && (
<StyledBackIconButton
Icon={IconChevronLeft}
size={isMobile ? 'small' : 'medium'}
onClick={() => navigate(-1)}
variant="tertiary"
/>
)}
<StyledTopBarIconStyledTitleContainer>
{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 '@/object-record/record-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,15 @@
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};
height: 100%;
overflow: auto;
width: 100%;
`;
export const PagePanel = ({ children }: { children: React.ReactNode }) => (
<StyledPanel>{children}</StyledPanel>
);

View File

@ -0,0 +1,50 @@
import { ReactNode } from 'react';
import styled from '@emotion/styled';
import { RightDrawer } from '@/ui/layout/right-drawer/components/RightDrawer';
import { MOBILE_VIEWPORT } from '@/ui/theme/constants/theme';
import { PagePanel } from './PagePanel';
type RightDrawerContainerProps = {
children: ReactNode;
};
const StyledMainContainer = styled.div`
background: ${({ theme }) => theme.background.noisy};
box-sizing: border-box;
display: flex;
flex: 1 1 auto;
flex-direction: row;
gap: ${({ theme }) => theme.spacing(2)};
min-height: 0;
padding: ${({ theme }) => theme.spacing(0, 3)};
width: 100%;
@media (max-width: ${MOBILE_VIEWPORT}px) {
padding-left: ${({ theme }) => theme.spacing(3)};
padding-bottom: 0;
}
`;
type LeftContainerProps = {
isRightDrawerOpen?: boolean;
};
const StyledLeftContainer = styled.div<LeftContainerProps>`
display: flex;
flex-direction: column;
position: relative;
width: 100%;
`;
export const RightDrawerContainer = ({
children,
}: RightDrawerContainerProps) => (
<StyledMainContainer>
<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%' : '100%')};
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(3) : 0)};
width: 100%;
`;
export const SubMenuTopBarContainer = ({
children,
title,
Icon,
}: SubMenuTopBarContainerProps) => {
const isMobile = useIsMobile();
return (
<StyledContainer isMobile={isMobile}>
{isMobile && <PageHeader title={title} Icon={Icon} />}
<RightDrawerContainer>{children}</RightDrawerContainer>
</StyledContainer>
);
};