diff --git a/packages/twenty-front/src/modules/command-menu/components/CommandMenuContextChip.tsx b/packages/twenty-front/src/modules/command-menu/components/CommandMenuContextChip.tsx index 480c77db7..e95b16928 100644 --- a/packages/twenty-front/src/modules/command-menu/components/CommandMenuContextChip.tsx +++ b/packages/twenty-front/src/modules/command-menu/components/CommandMenuContextChip.tsx @@ -43,12 +43,17 @@ const StyledIconsContainer = styled.div` display: flex; `; +const StyledEmptyText = styled.div` + color: ${({ theme }) => theme.font.color.tertiary}; +`; + export type CommandMenuContextChipProps = { Icons: React.ReactNode[]; text?: string; onClick?: () => void; testId?: string; maxWidth?: string; + forceEmptyText?: boolean; }; export const CommandMenuContextChip = ({ @@ -57,6 +62,7 @@ export const CommandMenuContextChip = ({ onClick, testId, maxWidth, + forceEmptyText = false, }: CommandMenuContextChipProps) => { return ( {Icon} ))} - {text && } + {text?.trim() ? ( + + ) : !forceEmptyText ? ( + Untitled + ) : ( + '' + )} ); }; diff --git a/packages/twenty-front/src/modules/command-menu/components/CommandMenuTopBar.tsx b/packages/twenty-front/src/modules/command-menu/components/CommandMenuTopBar.tsx index a6cce40c7..b0138e315 100644 --- a/packages/twenty-front/src/modules/command-menu/components/CommandMenuTopBar.tsx +++ b/packages/twenty-front/src/modules/command-menu/components/CommandMenuTopBar.tsx @@ -21,8 +21,8 @@ import { useRef } from 'react'; import { useLocation } from 'react-router-dom'; import { useRecoilState, useRecoilValue } from 'recoil'; import { isDefined } from 'twenty-shared/utils'; -import { Button } from 'twenty-ui/input'; import { IconChevronLeft, IconX } from 'twenty-ui/display'; +import { Button } from 'twenty-ui/input'; import { getOsControlSymbol, useIsMobile } from 'twenty-ui/utilities'; const StyledInputContainer = styled.div` @@ -126,6 +126,7 @@ export const CommandMenuTopBar = () => { Icons={[]} onClick={goBackFromCommandMenu} testId="command-menu-go-back-button" + forceEmptyText={true} /> )} diff --git a/packages/twenty-front/src/modules/object-record/record-title-cell/components/RecordTitleCellTextFieldDisplay.tsx b/packages/twenty-front/src/modules/object-record/record-title-cell/components/RecordTitleCellTextFieldDisplay.tsx index d7ff5ebdc..32a08594e 100644 --- a/packages/twenty-front/src/modules/object-record/record-title-cell/components/RecordTitleCellTextFieldDisplay.tsx +++ b/packages/twenty-front/src/modules/object-record/record-title-cell/components/RecordTitleCellTextFieldDisplay.tsx @@ -4,6 +4,7 @@ import { useInlineCell } from '@/object-record/record-inline-cell/hooks/useInlin import { useRecordValue } from '@/object-record/record-store/contexts/RecordFieldValueSelectorContext'; import { TitleInputHotkeyScope } from '@/ui/input/types/TitleInputHotkeyScope'; import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope'; +import { Theme, withTheme } from '@emotion/react'; import styled from '@emotion/styled'; import { useContext } from 'react'; import { OverflowingTextWithTooltip } from 'twenty-ui/display'; @@ -26,10 +27,16 @@ const StyledDiv = styled.div` } `; +const StyledEmptyText = withTheme(styled.div<{ theme: Theme }>` + color: ${({ theme }) => theme.font.color.tertiary}; +`); + export const RecordTitleCellSingleTextDisplayMode = () => { const { recordId, fieldDefinition } = useContext(FieldContext); const recordValue = useRecordValue(recordId); + const isEmpty = + recordValue?.[fieldDefinition.metadata.fieldName].trim() === ''; const { openInlineCell } = useInlineCell(); @@ -46,12 +53,16 @@ export const RecordTitleCellSingleTextDisplayMode = () => { openInlineCell(); }} > - + {isEmpty ? ( + Untitled + ) : ( + + )} ); }; diff --git a/packages/twenty-front/src/modules/object-record/record-title-cell/components/RecordTitleFullNameFieldDisplay.tsx b/packages/twenty-front/src/modules/object-record/record-title-cell/components/RecordTitleFullNameFieldDisplay.tsx index ca538b83d..538de0e18 100644 --- a/packages/twenty-front/src/modules/object-record/record-title-cell/components/RecordTitleFullNameFieldDisplay.tsx +++ b/packages/twenty-front/src/modules/object-record/record-title-cell/components/RecordTitleFullNameFieldDisplay.tsx @@ -1,6 +1,7 @@ import { FieldContext } from '@/object-record/record-field/contexts/FieldContext'; import { useFullNameFieldDisplay } from '@/object-record/record-field/meta-types/hooks/useFullNameFieldDisplay'; import { useInlineCell } from '@/object-record/record-inline-cell/hooks/useInlineCell'; +import { Theme, withTheme } from '@emotion/react'; import styled from '@emotion/styled'; import { isNonEmptyString } from '@sniptt/guards'; import { useContext } from 'react'; @@ -25,6 +26,10 @@ const StyledDiv = styled.div` } `; +const StyledEmptyText = withTheme(styled.div<{ theme: Theme }>` + color: ${({ theme }) => theme.font.color.tertiary}; +`); + export const RecordTitleFullNameFieldDisplay = () => { const { fieldDefinition } = useContext(FieldContext); @@ -39,9 +44,13 @@ export const RecordTitleFullNameFieldDisplay = () => { return ( openInlineCell()}> - + {!content ? ( + Untitled + ) : ( + + )} ); }; diff --git a/packages/twenty-ui/src/components/chip/Chip.tsx b/packages/twenty-ui/src/components/chip/Chip.tsx index 4b65715eb..fc967b691 100644 --- a/packages/twenty-ui/src/components/chip/Chip.tsx +++ b/packages/twenty-ui/src/components/chip/Chip.tsx @@ -35,6 +35,10 @@ export type ChipProps = { className?: string; }; +const StyledDiv = withTheme(styled.div<{ theme: Theme }>` + color: ${({ theme }) => theme.font.color.tertiary}; +`); + const StyledContainer = withTheme(styled.div< Pick< ChipProps, @@ -147,8 +151,10 @@ export const Chip = ({ maxWidth={maxWidth} > {leftComponent} - {!isLabelHidden && ( + {!isLabelHidden && label.trim() ? ( + ) : ( + Untitled )} {rightComponent?.()} diff --git a/packages/twenty-ui/src/components/chip/__stories__/EntityChip.stories.tsx b/packages/twenty-ui/src/components/chip/__stories__/EntityChip.stories.tsx index 73b1bd29f..c7f4ce9c9 100644 --- a/packages/twenty-ui/src/components/chip/__stories__/EntityChip.stories.tsx +++ b/packages/twenty-ui/src/components/chip/__stories__/EntityChip.stories.tsx @@ -21,3 +21,9 @@ export default meta; type Story = StoryObj; export const Default: Story = {}; + +export const Empty: Story = { + args: { + name: '', + }, +}; diff --git a/packages/twenty-ui/src/display/avatar/components/Avatar.tsx b/packages/twenty-ui/src/display/avatar/components/Avatar.tsx index 92cb2963b..5adc94db1 100644 --- a/packages/twenty-ui/src/display/avatar/components/Avatar.tsx +++ b/packages/twenty-ui/src/display/avatar/components/Avatar.tsx @@ -90,7 +90,10 @@ export const Avatar = ({ }) : null; - const placeholderChar = placeholder?.[0]?.toLocaleUpperCase(); + const placeholderFirstChar = placeholder?.trim()?.charAt(0); + const isPlaceholderFirstCharEmpty = + !placeholderFirstChar || placeholderFirstChar === ''; + const placeholderChar = placeholderFirstChar?.toUpperCase() || '-'; const showPlaceholder = isNull(avatarImageURI) || invalidAvatarUrls.includes(avatarImageURI); @@ -101,10 +104,12 @@ export const Avatar = ({ } }; - const fixedColor = - color ?? stringToHslColor(placeholderColorSeed ?? '', 75, 25); - const fixedBackgroundColor = - backgroundColor ?? stringToHslColor(placeholderColorSeed ?? '', 75, 85); + const fixedColor = isPlaceholderFirstCharEmpty + ? theme.font.color.tertiary + : (color ?? stringToHslColor(placeholderColorSeed ?? '', 75, 25)); + const fixedBackgroundColor = isPlaceholderFirstCharEmpty + ? theme.background.transparent.light + : (backgroundColor ?? stringToHslColor(placeholderColorSeed ?? '', 75, 85)); const showBackgroundColor = showPlaceholder;