- Created an new component state `isRecordEditableNameRenamingComponentState` - Updated `useCreateNewTableRecord` to open the ShowPage on workflow creation - Refactored `RecordEditableName` and its components to remove the useEffect (This was causing the recordName state to be updated after the focus on `NavigationDrawerInput`, but we want the text so be selected after the update). - Introduced a new component `EditableBreadcrumbItem` - Created an autosizing text input: This is done by a hack using a span inside a div and the input position is set to absolute and takes the size of the div. There are two problems that I didn't manage to fix: If the text is too long, the title overflows, and the letter spacing is different between the span and the input creating a small offset. https://github.com/user-attachments/assets/4aa1e177-7458-4691-b0c8-96567b482206 New text input component: https://github.com/user-attachments/assets/94565546-fe2b-457d-a1d8-907007e0e2ce
178 lines
4.9 KiB
TypeScript
178 lines
4.9 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;
|
|
|
|
@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)};
|
|
`;
|
|
|
|
const StyledTopBarIconStyledTitleContainer = styled.div`
|
|
align-items: center;
|
|
display: flex;
|
|
gap: ${({ theme }) => theme.spacing(1)};
|
|
flex-direction: row;
|
|
`;
|
|
|
|
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`
|
|
flex: 1 0 1;
|
|
display: flex;
|
|
flex-direction: row;
|
|
align-items: center;
|
|
`;
|
|
|
|
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>
|
|
);
|
|
};
|