Navbar customization v2 (#18026)

Adds color support for navigation menu items.

---------

Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>
Co-authored-by: Devessier <baptiste@devessier.fr>
Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
Abdul Rahman
2026-02-28 16:18:28 +05:30
committed by GitHub
parent 63f17eec2c
commit 9fe2a07c55
94 changed files with 1204 additions and 474 deletions
@@ -1,4 +1,3 @@
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import { useLingui } from '@lingui/react/macro';
import { useIcons } from 'twenty-ui/display';
@@ -6,24 +5,22 @@ import { useIcons } from 'twenty-ui/display';
import { CommandMenuPageInfoLayout } from '@/command-menu/components/CommandMenuPageInfoLayout';
import { commandMenuPageInfoState } from '@/command-menu/states/commandMenuPageInfoState';
import { commandMenuShouldFocusTitleInputComponentState } from '@/command-menu/states/commandMenuShouldFocusTitleInputComponentState';
import { StyledNavigationMenuItemIconContainer } from '@/navigation-menu-item/components/NavigationMenuItemIconContainer';
import { NavigationMenuItemStyleIcon } from '@/navigation-menu-item/components/NavigationMenuItemStyleIcon';
import { FOLDER_ICON_DEFAULT } from '@/navigation-menu-item/constants/FolderIconDefault';
import { NavigationMenuItemType } from '@/navigation-menu-item/constants/NavigationMenuItemType';
import { useUpdateFolderInDraft } from '@/navigation-menu-item/hooks/useUpdateFolderInDraft';
import { useWorkspaceSectionItems } from '@/navigation-menu-item/hooks/useWorkspaceSectionItems';
import { selectedNavigationMenuItemInEditModeState } from '@/navigation-menu-item/states/selectedNavigationMenuItemInEditModeState';
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
import { getNavigationMenuItemIconColors } from '@/navigation-menu-item/utils/getNavigationMenuItemIconColors';
import { IconPicker } from '@/ui/input/components/IconPicker';
import { TitleInput } from '@/ui/input/components/TitleInput';
import { useAtomComponentState } from '@/ui/utilities/state/jotai/hooks/useAtomComponentState';
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
const StyledClickableIconWrapper = styled.div`
cursor: pointer;
`;
export const CommandMenuFolderInfo = () => {
const theme = useTheme();
const { t } = useLingui();
const { getIcon } = useIcons();
const commandMenuPageInfo = useAtomStateValue(commandMenuPageInfoState);
@@ -83,15 +80,10 @@ export const CommandMenuFolderInfo = () => {
}
clickableComponent={
<StyledClickableIconWrapper>
<StyledNavigationMenuItemIconContainer
$backgroundColor={getNavigationMenuItemIconColors(theme).folder}
>
<FolderIconComponent
size={theme.spacing(3.5)}
color={theme.grayScale.gray1}
stroke={theme.icon.stroke.md}
/>
</StyledNavigationMenuItemIconContainer>
<NavigationMenuItemStyleIcon
Icon={FolderIconComponent}
color={selectedItem.color}
/>
</StyledClickableIconWrapper>
}
/>
@@ -112,6 +104,7 @@ export const CommandMenuFolderInfo = () => {
onFocus={() => setCommandMenuShouldFocusTitleInput(false)}
/>
}
label={t`Folder`}
/>
);
};
@@ -67,7 +67,7 @@ export const CommandMenuItem = ({
})
: undefined
}
focused={isSelectedItemId}
focused={!disabled && isSelectedItemId}
RightComponent={RightComponent}
hasSubMenu={hasSubMenu}
isSubMenuOpened={isSubMenuOpened}
@@ -1,22 +1,19 @@
import { useTheme } from '@emotion/react';
import { useLingui } from '@lingui/react/macro';
import { IconLink } from 'twenty-ui/display';
import { CommandMenuPageInfoLayout } from '@/command-menu/components/CommandMenuPageInfoLayout';
import { commandMenuPageInfoState } from '@/command-menu/states/commandMenuPageInfoState';
import { commandMenuShouldFocusTitleInputComponentState } from '@/command-menu/states/commandMenuShouldFocusTitleInputComponentState';
import { NavigationMenuItemStyleIcon } from '@/navigation-menu-item/components/NavigationMenuItemStyleIcon';
import { NavigationMenuItemType } from '@/navigation-menu-item/constants/NavigationMenuItemType';
import { StyledNavigationMenuItemIconContainer } from '@/navigation-menu-item/components/NavigationMenuItemIconContainer';
import { useUpdateLinkInDraft } from '@/navigation-menu-item/hooks/useUpdateLinkInDraft';
import { useWorkspaceSectionItems } from '@/navigation-menu-item/hooks/useWorkspaceSectionItems';
import { selectedNavigationMenuItemInEditModeState } from '@/navigation-menu-item/states/selectedNavigationMenuItemInEditModeState';
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
import { getNavigationMenuItemIconColors } from '@/navigation-menu-item/utils/getNavigationMenuItemIconColors';
import { TitleInput } from '@/ui/input/components/TitleInput';
import { useAtomComponentState } from '@/ui/utilities/state/jotai/hooks/useAtomComponentState';
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
export const CommandMenuLinkInfo = () => {
const theme = useTheme();
const { t } = useLingui();
const commandMenuPageInfo = useAtomStateValue(commandMenuPageInfoState);
const [
@@ -64,15 +61,10 @@ export const CommandMenuLinkInfo = () => {
return (
<CommandMenuPageInfoLayout
icon={
<StyledNavigationMenuItemIconContainer
$backgroundColor={getNavigationMenuItemIconColors(theme).link}
>
<IconLink
size={theme.spacing(3.5)}
color={theme.grayScale.gray1}
stroke={theme.icon.stroke.md}
/>
</StyledNavigationMenuItemIconContainer>
<NavigationMenuItemStyleIcon
Icon={IconLink}
color={selectedItem.color}
/>
}
title={
<TitleInput
@@ -90,7 +82,7 @@ export const CommandMenuLinkInfo = () => {
onFocus={() => setCommandMenuShouldFocusTitleInput(false)}
/>
}
label={t`link`}
label={t`Link`}
/>
);
};
@@ -6,11 +6,15 @@ import { NavigationMenuItemIcon } from '@/navigation-menu-item/components/Naviga
import { NavigationMenuItemType } from '@/navigation-menu-item/constants/NavigationMenuItemType';
import { useSelectedNavigationMenuItemEditItem } from '@/navigation-menu-item/hooks/useSelectedNavigationMenuItemEditItem';
import { useSelectedNavigationMenuItemEditItemLabel } from '@/navigation-menu-item/hooks/useSelectedNavigationMenuItemEditItemLabel';
import { useSelectedNavigationMenuItemEditItemObjectMetadata } from '@/navigation-menu-item/hooks/useSelectedNavigationMenuItemEditItemObjectMetadata';
import { ViewKey } from '@/views/types/ViewKey';
export const CommandMenuObjectViewRecordInfo = () => {
const { t } = useLingui();
const { selectedItem } = useSelectedNavigationMenuItemEditItem();
const { selectedItemLabel } = useSelectedNavigationMenuItemEditItemLabel();
const { selectedItemObjectMetadata } =
useSelectedNavigationMenuItemEditItemObjectMetadata();
const processedItem =
selectedItem && selectedItem.itemType !== NavigationMenuItemType.FOLDER
@@ -30,11 +34,12 @@ export const CommandMenuObjectViewRecordInfo = () => {
return null;
}
const label = isViewOrRecord
? processedItem.itemType === NavigationMenuItemType.RECORD
? t`record`
: t`view`
: t`object`;
const label =
processedItem.itemType === NavigationMenuItemType.RECORD
? selectedItemObjectMetadata?.labelSingular
: processedItem.viewKey === ViewKey.Index
? t`Object`
: t`View`;
return (
<CommandMenuPageInfoLayout
@@ -1,12 +1,16 @@
import styled from '@emotion/styled';
import { isDefined } from 'twenty-shared/utils';
import { OverflowingTextWithTooltip } from 'twenty-ui/display';
import {
IconColumnInsertRight,
OverflowingTextWithTooltip,
} from 'twenty-ui/display';
import { CommandMenuAskAIInfo } from '@/command-menu/components/CommandMenuAskAIInfo';
import { CommandMenuFolderInfo } from '@/command-menu/components/CommandMenuFolderInfo';
import { CommandMenuLinkInfo } from '@/command-menu/components/CommandMenuLinkInfo';
import { CommandMenuMultipleRecordsInfo } from '@/command-menu/components/CommandMenuMultipleRecordsInfo';
import { CommandMenuObjectViewRecordInfo } from '@/command-menu/components/CommandMenuObjectViewRecordInfo';
import { CommandMenuPageInfoLayout } from '@/command-menu/components/CommandMenuPageInfoLayout';
import { CommandMenuPageLayoutInfo } from '@/command-menu/components/CommandMenuPageLayoutInfo';
import { CommandMenuRecordInfo } from '@/command-menu/components/CommandMenuRecordInfo';
import { CommandMenuWorkflowStepInfo } from '@/command-menu/components/CommandMenuWorkflowStepInfo';
@@ -16,6 +20,7 @@ import { selectedNavigationMenuItemInEditModeState } from '@/navigation-menu-ite
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
import { CommandMenuPages } from 'twenty-shared/types';
import { useTheme } from '@emotion/react';
import { type CommandMenuContextChipProps } from './CommandMenuContextChip';
const StyledPageTitle = styled.div`
@@ -29,6 +34,7 @@ type CommandMenuPageInfoProps = {
};
export const CommandMenuPageInfo = ({ pageChip }: CommandMenuPageInfoProps) => {
const theme = useTheme();
const selectedNavigationMenuItemInEditMode = useAtomStateValue(
selectedNavigationMenuItemInEditModeState,
);
@@ -121,6 +127,20 @@ export const CommandMenuPageInfo = ({ pageChip }: CommandMenuPageInfoProps) => {
return <CommandMenuAskAIInfo />;
}
if (pageChip.page?.page === CommandMenuPages.NavigationMenuAddItem) {
return (
<CommandMenuPageInfoLayout
icon={
<IconColumnInsertRight
size={theme.icon.size.md}
color={theme.font.color.tertiary}
/>
}
title={<OverflowingTextWithTooltip text={pageChip.text ?? ''} />}
/>
);
}
return (
<StyledPageTitle>
<OverflowingTextWithTooltip text={pageChip.text ?? ''} />
@@ -12,9 +12,12 @@ const StyledSubViewContainer = styled.div`
`;
const StyledSearchContainer = styled.div`
align-items: center;
border-bottom: 1px solid ${({ theme }) => theme.border.color.light};
display: flex;
height: ${({ theme }) => theme.spacing(10)};
min-width: 0;
padding: ${({ theme }) => theme.spacing(2, 3)};
padding-inline: ${({ theme }) => theme.spacing(3)};
`;
const StyledSearchInput = styled.input`
@@ -22,8 +25,7 @@ const StyledSearchInput = styled.input`
border: none;
border-radius: ${({ theme }) => theme.border.radius.sm};
box-sizing: border-box;
color: ${({ theme }) => theme.font.color.primary};
font-size: ${({ theme }) => theme.font.size.md};
padding: 0;
width: 100%;
outline: none;