80c55b4462
Created a new component `RecordTitleCell` with an API close to `RecordInlineCell`. This new component is an autogrowing input. It consumes the `FieldContext`. It uses some hooks and states from `RecordInlineCell` because I didn't want to duplicate all the logic, but this logic could be duplicated. Two issues that I didn't solve in this PR: - There is a flashing glitch inside the input when typing - The input of a workflow isn't focused when creating a new one. This is because of an issue with the `useHotkeyScopeOnMount` hook which is deprecated but still used in some components. Upon redirection on the workflow showpage, the hokey scope of the input is overridden by the hokey scopes of the components which use `useHotkeyScopeOnMount`. I decided not to open the input for now. ## Command menu record show page ### Single input https://github.com/user-attachments/assets/50dc235c-8f34-4445-8b04-586125606bd5 ### Double input https://github.com/user-attachments/assets/bdcfd6eb-d25e-4006-a87f-6e615e8a6e7e ## Workflow breadcrumb https://github.com/user-attachments/assets/ded38dd6-5794-4779-a4ae-b3948567595a ## Record show page ### Single input https://github.com/user-attachments/assets/8ad7a606-556a-416b-8788-93415f7989e1 ### Double input https://github.com/user-attachments/assets/55aae40b-36ae-40f1-8171-06f1a5db3532
181 lines
5.0 KiB
TypeScript
181 lines
5.0 KiB
TypeScript
import { useTheme } from '@emotion/react';
|
|
import styled from '@emotion/styled';
|
|
import { ReactNode } from 'react';
|
|
import { useRecoilValue } from 'recoil';
|
|
import {
|
|
IconButton,
|
|
IconChevronDown,
|
|
IconChevronUp,
|
|
IconComponent,
|
|
IconX,
|
|
LightIconButton,
|
|
MOBILE_VIEWPORT,
|
|
OverflowingTextWithTooltip,
|
|
} from 'twenty-ui';
|
|
|
|
import { NavigationDrawerCollapseButton } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerCollapseButton';
|
|
|
|
import { isNavigationDrawerExpandedState } from '@/ui/navigation/states/isNavigationDrawerExpanded';
|
|
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
|
|
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
|
import { FeatureFlagKey } from '~/generated/graphql';
|
|
|
|
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)};
|
|
gap: ${({ theme }) => theme.spacing(2)};
|
|
|
|
@media (max-width: ${MOBILE_VIEWPORT}px) {
|
|
box-sizing: border-box;
|
|
padding: ${({ 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(1)};
|
|
overflow-x: hidden;
|
|
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};
|
|
font-weight: ${({ theme }) => theme.font.weight.medium};
|
|
margin-left: ${({ theme }) => theme.spacing(1)};
|
|
width: 100%;
|
|
overflow: hidden;
|
|
`;
|
|
|
|
const StyledTopBarIconStyledTitleContainer = styled.div`
|
|
align-items: center;
|
|
display: flex;
|
|
gap: ${({ theme }) => theme.spacing(1)};
|
|
flex-direction: row;
|
|
width: 100%;
|
|
overflow: hidden;
|
|
`;
|
|
|
|
const StyledPageActionContainer = styled.div`
|
|
display: inline-flex;
|
|
gap: ${({ theme }) => theme.spacing(2)};
|
|
flex: 1 0 1;
|
|
`;
|
|
|
|
const StyledTopBarButtonContainer = styled.div`
|
|
margin-left: ${({ theme }) => theme.spacing(1)};
|
|
margin-right: ${({ theme }) => theme.spacing(1)};
|
|
`;
|
|
|
|
const StyledIconContainer = styled.div`
|
|
align-items: center;
|
|
display: flex;
|
|
flex-direction: row;
|
|
`;
|
|
|
|
type PageHeaderProps = {
|
|
title?: ReactNode;
|
|
hasClosePageButton?: boolean;
|
|
onClosePage?: () => void;
|
|
hasPaginationButtons?: boolean;
|
|
hasPreviousRecord?: boolean;
|
|
hasNextRecord?: boolean;
|
|
navigateToPreviousRecord?: () => void;
|
|
navigateToNextRecord?: () => void;
|
|
Icon?: IconComponent;
|
|
children?: ReactNode;
|
|
};
|
|
|
|
export const PageHeader = ({
|
|
title,
|
|
hasClosePageButton,
|
|
onClosePage,
|
|
hasPaginationButtons,
|
|
navigateToPreviousRecord,
|
|
navigateToNextRecord,
|
|
Icon,
|
|
children,
|
|
}: PageHeaderProps) => {
|
|
const isMobile = useIsMobile();
|
|
const theme = useTheme();
|
|
const isNavigationDrawerExpanded = useRecoilValue(
|
|
isNavigationDrawerExpandedState,
|
|
);
|
|
|
|
const isCommandMenuV2Enabled = useIsFeatureEnabled(
|
|
FeatureFlagKey.IsCommandMenuV2Enabled,
|
|
);
|
|
|
|
return (
|
|
<StyledTopBarContainer>
|
|
<StyledLeftContainer>
|
|
{!isMobile && !isNavigationDrawerExpanded && (
|
|
<StyledTopBarButtonContainer>
|
|
<NavigationDrawerCollapseButton direction="right" />
|
|
</StyledTopBarButtonContainer>
|
|
)}
|
|
{hasClosePageButton && (
|
|
<LightIconButton
|
|
Icon={IconX}
|
|
size="small"
|
|
accent="tertiary"
|
|
onClick={() => onClosePage?.()}
|
|
/>
|
|
)}
|
|
|
|
<StyledTopBarIconStyledTitleContainer>
|
|
{!isCommandMenuV2Enabled && hasPaginationButtons && (
|
|
<>
|
|
<IconButton
|
|
Icon={IconChevronUp}
|
|
size="small"
|
|
variant="secondary"
|
|
onClick={() => navigateToPreviousRecord?.()}
|
|
/>
|
|
<IconButton
|
|
Icon={IconChevronDown}
|
|
size="small"
|
|
variant="secondary"
|
|
onClick={() => navigateToNextRecord?.()}
|
|
/>
|
|
</>
|
|
)}
|
|
<StyledIconContainer>
|
|
{Icon && <Icon size={theme.icon.size.md} />}
|
|
</StyledIconContainer>
|
|
{title && (
|
|
<StyledTitleContainer data-testid="top-bar-title">
|
|
{typeof title === 'string' ? (
|
|
<OverflowingTextWithTooltip text={title} />
|
|
) : (
|
|
title
|
|
)}
|
|
</StyledTitleContainer>
|
|
)}
|
|
</StyledTopBarIconStyledTitleContainer>
|
|
</StyledLeftContainer>
|
|
|
|
<StyledPageActionContainer className="page-action-container">
|
|
{children}
|
|
</StyledPageActionContainer>
|
|
</StyledTopBarContainer>
|
|
);
|
|
};
|