Migrate right drawer record page to the command menu (#9459)

Closes #9423



https://github.com/user-attachments/assets/0d93f170-8c4f-43ff-a0ca-3d2874d44820
This commit is contained in:
Raphaël Bosi
2025-01-09 09:58:14 +01:00
committed by GitHub
parent e0e436a51d
commit a2f2f4148a
37 changed files with 400 additions and 232 deletions

View File

@ -1,23 +1,19 @@
import { CommandGroup } from '@/command-menu/components/CommandGroup';
import { CommandMenuDefaultSelectionEffect } from '@/command-menu/components/CommandMenuDefaultSelectionEffect';
import { CommandMenuItem } from '@/command-menu/components/CommandMenuItem';
import { CommandMenuTopBar } from '@/command-menu/components/CommandMenuTopBar';
import { COMMAND_MENU_SEARCH_BAR_HEIGHT } from '@/command-menu/constants/CommandMenuSearchBarHeight';
import { COMMAND_MENU_SEARCH_BAR_PADDING } from '@/command-menu/constants/CommandMenuSearchBarPadding';
import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu';
import { useCommandMenuHotKeys } from '@/command-menu/hooks/useCommandMenuHotKeys';
import { useCommandMenuOnItemClick } from '@/command-menu/hooks/useCommandMenuOnItemClick';
import { useMatchingCommandMenuCommands } from '@/command-menu/hooks/useMatchingCommandMenuCommands';
import { commandMenuSearchState } from '@/command-menu/states/commandMenuSearchState';
import { Command } from '@/command-menu/types/Command';
import { SelectableItem } from '@/ui/layout/selectable-list/components/SelectableItem';
import { SelectableList } from '@/ui/layout/selectable-list/components/SelectableList';
import { AppHotkeyScope } from '@/ui/utilities/hotkey/types/AppHotkeyScope';
import { useListenClickOutside } from '@/ui/utilities/pointer-event/hooks/useListenClickOutside';
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
import { ScrollWrapper } from '@/ui/utilities/scroll/components/ScrollWrapper';
import styled from '@emotion/styled';
import { useRef } from 'react';
import { useRecoilState } from 'recoil';
import { useRecoilValue } from 'recoil';
import { isDefined } from 'twenty-ui';
const MOBILE_NAVIGATION_BAR_HEIGHT = 64;
@ -27,21 +23,6 @@ type CommandGroupConfig = {
items?: Command[];
};
const StyledCommandMenu = styled.div`
background: ${({ theme }) => theme.background.secondary};
border-left: 1px solid ${({ theme }) => theme.border.color.medium};
box-shadow: ${({ theme }) => theme.boxShadow.strong};
font-family: ${({ theme }) => theme.font.family};
height: 100%;
overflow: hidden;
padding: 0;
position: fixed;
right: 0%;
top: 0%;
width: ${() => (useIsMobile() ? '100%' : '500px')};
z-index: 1000;
`;
const StyledList = styled.div`
background: ${({ theme }) => theme.background.secondary};
overscroll-behavior: contain;
@ -75,24 +56,12 @@ const StyledEmpty = styled.div`
`;
export const CommandMenu = () => {
const { onItemClick, closeCommandMenu } = useCommandMenu();
const commandMenuRef = useRef<HTMLDivElement>(null);
const { onItemClick } = useCommandMenuOnItemClick();
const [commandMenuSearch, setCommandMenuSearch] = useRecoilState(
commandMenuSearchState,
);
const commandMenuSearch = useRecoilValue(commandMenuSearchState);
const isMobile = useIsMobile();
useCommandMenuHotKeys();
useListenClickOutside({
refs: [commandMenuRef],
callback: closeCommandMenu,
listenerId: 'COMMAND_MENU_LISTENER_ID',
hotkeyScope: AppHotkeyScope.CommandMenuOpen,
});
const {
isNoResults,
isLoading,
@ -184,74 +153,66 @@ export const CommandMenu = () => {
<CommandMenuDefaultSelectionEffect
selectableItemIds={selectableItemIds}
/>
<StyledCommandMenu ref={commandMenuRef} className="command-menu">
<CommandMenuTopBar
commandMenuSearch={commandMenuSearch}
setCommandMenuSearch={setCommandMenuSearch}
/>
<StyledList>
<ScrollWrapper
contextProviderName="commandMenu"
componentInstanceId={`scroll-wrapper-command-menu`}
>
<StyledInnerList isMobile={isMobile}>
<SelectableList
selectableListId="command-menu-list"
selectableItemIdArray={selectableItemIds}
hotkeyScope={AppHotkeyScope.CommandMenu}
onEnter={(itemId) => {
const command = selectableItems.find(
(item) => item.id === itemId,
);
if (isDefined(command)) {
const {
to,
onCommandClick,
shouldCloseCommandMenuOnClick,
} = command;
<StyledList>
<ScrollWrapper
contextProviderName="commandMenu"
componentInstanceId={`scroll-wrapper-command-menu`}
>
<StyledInnerList isMobile={isMobile}>
<SelectableList
selectableListId="command-menu-list"
selectableItemIdArray={selectableItemIds}
hotkeyScope={AppHotkeyScope.CommandMenu}
onEnter={(itemId) => {
const command = selectableItems.find(
(item) => item.id === itemId,
);
onItemClick({
shouldCloseCommandMenuOnClick,
onClick: onCommandClick,
to,
});
}
}}
>
{isNoResults && !isLoading && (
<StyledEmpty>No results found</StyledEmpty>
)}
{commandGroups.map(({ heading, items }) =>
items?.length ? (
<CommandGroup heading={heading} key={heading}>
{items.map((item) => {
return (
<SelectableItem itemId={item.id} key={item.id}>
<CommandMenuItem
key={item.id}
id={item.id}
Icon={item.Icon}
label={item.label}
to={item.to}
onClick={item.onCommandClick}
firstHotKey={item.firstHotKey}
secondHotKey={item.secondHotKey}
shouldCloseCommandMenuOnClick={
item.shouldCloseCommandMenuOnClick
}
/>
</SelectableItem>
);
})}
</CommandGroup>
) : null,
)}
</SelectableList>
</StyledInnerList>
</ScrollWrapper>
</StyledList>
</StyledCommandMenu>
if (isDefined(command)) {
const { to, onCommandClick, shouldCloseCommandMenuOnClick } =
command;
onItemClick({
shouldCloseCommandMenuOnClick,
onClick: onCommandClick,
to,
});
}
}}
>
{isNoResults && !isLoading && (
<StyledEmpty>No results found</StyledEmpty>
)}
{commandGroups.map(({ heading, items }) =>
items?.length ? (
<CommandGroup heading={heading} key={heading}>
{items.map((item) => {
return (
<SelectableItem itemId={item.id} key={item.id}>
<CommandMenuItem
key={item.id}
id={item.id}
Icon={item.Icon}
label={item.label}
to={item.to}
onClick={item.onCommandClick}
firstHotKey={item.firstHotKey}
secondHotKey={item.secondHotKey}
shouldCloseCommandMenuOnClick={
item.shouldCloseCommandMenuOnClick
}
/>
</SelectableItem>
);
})}
</CommandGroup>
) : null,
)}
</SelectableList>
</StyledInnerList>
</ScrollWrapper>
</StyledList>
</>
);
};