feat(twenty-front): generalize the page primary/secondary bars (flat redesign) (#21308)
Replaces #21279 and #21282 with one clean PR from `main`. Generalizes the settings primary-bar / secondary-bar card chrome to the record index, record show and standalone pages via a shared `PageCardLayout` + `PageCardHeader` (the side panel sits as a sibling of the content card), and applies the new flat design direction: square corners on the card, side panel and loading skeletons. Iterating toward the new design (Figma node 102282-221623); the confirmed direction and the explicit "remove rounded corners" change are in, remaining designer specifics to follow.
This commit is contained in:
@@ -1,51 +1,24 @@
|
||||
import { SKELETON_LOADER_HEIGHT_SIZES } from '@/activities/components/SkeletonLoader';
|
||||
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
|
||||
import { SettingsSectionSkeletonLoader } from '@/settings/components/SettingsSectionSkeletonLoader';
|
||||
import { SettingsPageHeader } from '@/settings/components/layout/SettingsPageHeader';
|
||||
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
|
||||
import { styled } from '@linaria/react';
|
||||
import { PageCardHeader } from '@/ui/layout/page/components/PageCardHeader';
|
||||
import { PageCardLayout } from '@/ui/layout/page/components/PageCardLayout';
|
||||
import { useContext } from 'react';
|
||||
import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
|
||||
import {
|
||||
ThemeContext,
|
||||
themeCssVariables,
|
||||
} from 'twenty-ui-deprecated/theme-constants';
|
||||
|
||||
const StyledRoot = styled.div<{ isMobile: boolean }>`
|
||||
display: flex;
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
min-width: 0;
|
||||
padding: ${({ isMobile }) =>
|
||||
isMobile ? themeCssVariables.spacing[1] : themeCssVariables.spacing[2]};
|
||||
`;
|
||||
|
||||
const StyledCard = styled.div`
|
||||
background: ${themeCssVariables.background.primary};
|
||||
border: 1px solid ${themeCssVariables.border.color.medium};
|
||||
border-radius: ${themeCssVariables.border.radius.md};
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
min-height: 0;
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
`;
|
||||
import { ThemeContext } from 'twenty-ui-deprecated/theme-constants';
|
||||
|
||||
export const SettingsSkeletonLoader = () => {
|
||||
const isMobile = useIsMobile();
|
||||
const { theme } = useContext(ThemeContext);
|
||||
|
||||
return (
|
||||
<StyledRoot isMobile={isMobile}>
|
||||
<StyledCard>
|
||||
<SkeletonTheme
|
||||
baseColor={theme.background.tertiary}
|
||||
highlightColor={theme.background.transparent.lighter}
|
||||
borderRadius={4}
|
||||
>
|
||||
<SettingsPageHeader
|
||||
<SkeletonTheme
|
||||
baseColor={theme.background.tertiary}
|
||||
highlightColor={theme.background.transparent.lighter}
|
||||
borderRadius={4}
|
||||
>
|
||||
<PageCardLayout
|
||||
header={
|
||||
<PageCardHeader
|
||||
links={[
|
||||
{
|
||||
children: (
|
||||
@@ -63,11 +36,13 @@ export const SettingsSkeletonLoader = () => {
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<SettingsPageContainer>
|
||||
<SettingsSectionSkeletonLoader />
|
||||
</SettingsPageContainer>
|
||||
</SkeletonTheme>
|
||||
</StyledCard>
|
||||
</StyledRoot>
|
||||
}
|
||||
showInformationBanner={false}
|
||||
>
|
||||
<SettingsPageContainer>
|
||||
<SettingsSectionSkeletonLoader />
|
||||
</SettingsPageContainer>
|
||||
</PageCardLayout>
|
||||
</SkeletonTheme>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,87 +0,0 @@
|
||||
import { useNavigationDrawerExpanded } from '@/navigation/hooks/useNavigationDrawerExpanded';
|
||||
import { SIDE_PANEL_TOP_BAR_HEIGHT } from '@/side-panel/constants/SidePanelTopBarHeight';
|
||||
import {
|
||||
Breadcrumb,
|
||||
type BreadcrumbProps,
|
||||
} from '@/ui/navigation/bread-crumb/components/Breadcrumb';
|
||||
import { NavigationDrawerCollapseButton } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerCollapseButton';
|
||||
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
|
||||
import { styled } from '@linaria/react';
|
||||
import { type ReactNode } from 'react';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { themeCssVariables } from 'twenty-ui-deprecated/theme-constants';
|
||||
|
||||
type SettingsPageHeaderProps = {
|
||||
links: BreadcrumbProps['links'];
|
||||
title?: ReactNode;
|
||||
tag?: ReactNode;
|
||||
actionButton?: ReactNode;
|
||||
};
|
||||
|
||||
// minmax(0, 1fr) side tracks (not 1fr) let a long breadcrumb truncate instead of
|
||||
// pushing the centered title off its shared axis with the tabs and body.
|
||||
const StyledHeader = styled.div`
|
||||
align-items: center;
|
||||
background-color: ${themeCssVariables.background.secondary};
|
||||
border-bottom: 1px solid ${themeCssVariables.border.color.medium};
|
||||
box-sizing: border-box;
|
||||
display: grid;
|
||||
gap: ${themeCssVariables.spacing[2]};
|
||||
grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
|
||||
min-height: ${SIDE_PANEL_TOP_BAR_HEIGHT}px;
|
||||
padding: 0 ${themeCssVariables.spacing[3]};
|
||||
width: 100%;
|
||||
`;
|
||||
|
||||
const StyledLeft = styled.div`
|
||||
align-items: center;
|
||||
display: flex;
|
||||
gap: ${themeCssVariables.spacing[1]};
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
`;
|
||||
|
||||
const StyledTitle = styled.div`
|
||||
align-items: center;
|
||||
color: ${themeCssVariables.font.color.primary};
|
||||
display: flex;
|
||||
font-size: ${themeCssVariables.font.size.md};
|
||||
font-weight: ${themeCssVariables.font.weight.semiBold};
|
||||
gap: ${themeCssVariables.spacing[2]};
|
||||
min-width: 0;
|
||||
text-align: center;
|
||||
`;
|
||||
|
||||
const StyledRight = styled.div`
|
||||
align-items: center;
|
||||
display: flex;
|
||||
gap: ${themeCssVariables.spacing[2]};
|
||||
justify-content: flex-end;
|
||||
min-width: 0;
|
||||
`;
|
||||
|
||||
export const SettingsPageHeader = ({
|
||||
links,
|
||||
title,
|
||||
tag,
|
||||
actionButton,
|
||||
}: SettingsPageHeaderProps) => {
|
||||
const isMobile = useIsMobile();
|
||||
const isNavigationDrawerExpanded = useNavigationDrawerExpanded();
|
||||
|
||||
return (
|
||||
<StyledHeader>
|
||||
<StyledLeft>
|
||||
{!isNavigationDrawerExpanded && (
|
||||
<NavigationDrawerCollapseButton direction="right" />
|
||||
)}
|
||||
<Breadcrumb links={links} />
|
||||
</StyledLeft>
|
||||
<StyledTitle>
|
||||
{!isMobile && isDefined(title) && title}
|
||||
{!isMobile && tag}
|
||||
</StyledTitle>
|
||||
<StyledRight>{actionButton}</StyledRight>
|
||||
</StyledHeader>
|
||||
);
|
||||
};
|
||||
+21
-74
@@ -1,15 +1,9 @@
|
||||
import { CommandMenuForMobile } from '@/command-menu/components/CommandMenuForMobile';
|
||||
import { useCommandMenuHotKeys } from '@/command-menu/hooks/useCommandMenuHotKeys';
|
||||
import { InformationBannerWrapper } from '@/information-banner/components/InformationBannerWrapper';
|
||||
import { SettingsPageHeader } from '@/settings/components/layout/SettingsPageHeader';
|
||||
import { SettingsSecondaryBar } from '@/settings/components/layout/SettingsSecondaryBar';
|
||||
import { SidePanelForDesktop } from '@/side-panel/components/SidePanelForDesktop';
|
||||
import { PageCardHeader } from '@/ui/layout/page/components/PageCardHeader';
|
||||
import { PageCardLayout } from '@/ui/layout/page/components/PageCardLayout';
|
||||
import { type BreadcrumbProps } from '@/ui/navigation/bread-crumb/components/Breadcrumb';
|
||||
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
|
||||
import { styled } from '@linaria/react';
|
||||
import { type JSX, type ReactNode } from 'react';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { themeCssVariables } from 'twenty-ui-deprecated/theme-constants';
|
||||
|
||||
type SettingsPageLayoutProps = {
|
||||
links: BreadcrumbProps['links'];
|
||||
@@ -20,44 +14,6 @@ type SettingsPageLayoutProps = {
|
||||
tag?: JSX.Element;
|
||||
};
|
||||
|
||||
const StyledRoot = styled.div<{ isMobile: boolean }>`
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: row;
|
||||
min-height: 0;
|
||||
min-width: 0;
|
||||
padding: ${({ isMobile }) =>
|
||||
isMobile ? themeCssVariables.spacing[1] : themeCssVariables.spacing[2]};
|
||||
`;
|
||||
|
||||
const StyledMainCardWrapper = styled.div`
|
||||
display: flex;
|
||||
flex: 1 1 0;
|
||||
min-width: 0;
|
||||
width: 0;
|
||||
`;
|
||||
|
||||
const StyledCard = styled.div`
|
||||
background: ${themeCssVariables.background.primary};
|
||||
border: 1px solid ${themeCssVariables.border.color.medium};
|
||||
border-radius: ${themeCssVariables.border.radius.md};
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
min-height: 0;
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
`;
|
||||
|
||||
const StyledBodyContent = styled.div`
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
min-height: 0;
|
||||
width: 100%;
|
||||
`;
|
||||
|
||||
export const SettingsPageLayout = ({
|
||||
links,
|
||||
title,
|
||||
@@ -65,31 +21,22 @@ export const SettingsPageLayout = ({
|
||||
secondaryBar,
|
||||
children,
|
||||
tag,
|
||||
}: SettingsPageLayoutProps) => {
|
||||
const isMobile = useIsMobile();
|
||||
|
||||
useCommandMenuHotKeys();
|
||||
|
||||
return (
|
||||
<StyledRoot isMobile={isMobile}>
|
||||
<StyledMainCardWrapper>
|
||||
<StyledCard>
|
||||
<SettingsPageHeader
|
||||
links={links}
|
||||
title={title}
|
||||
tag={tag}
|
||||
actionButton={actionButton}
|
||||
/>
|
||||
{isDefined(secondaryBar) && (
|
||||
<SettingsSecondaryBar>{secondaryBar}</SettingsSecondaryBar>
|
||||
)}
|
||||
<StyledBodyContent>
|
||||
<InformationBannerWrapper />
|
||||
{children}
|
||||
</StyledBodyContent>
|
||||
</StyledCard>
|
||||
</StyledMainCardWrapper>
|
||||
{isMobile ? <CommandMenuForMobile /> : <SidePanelForDesktop />}
|
||||
</StyledRoot>
|
||||
);
|
||||
};
|
||||
}: SettingsPageLayoutProps) => (
|
||||
<PageCardLayout
|
||||
header={
|
||||
<PageCardHeader
|
||||
links={links}
|
||||
title={title}
|
||||
tag={tag}
|
||||
actionButton={actionButton}
|
||||
/>
|
||||
}
|
||||
secondaryBar={
|
||||
isDefined(secondaryBar) ? (
|
||||
<SettingsSecondaryBar>{secondaryBar}</SettingsSecondaryBar>
|
||||
) : undefined
|
||||
}
|
||||
>
|
||||
{children}
|
||||
</PageCardLayout>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user