refactor!: rename Command Menu page/navigation layer to Side Panel (#18393)

This commit is contained in:
nitin
2026-03-05 20:16:31 +05:30
committed by GitHub
parent 38ad0820c0
commit 5853891b02
675 changed files with 4894 additions and 4964 deletions
@@ -13,8 +13,8 @@
* TODO: add the other remaining components that can appear in the root stacking context
*/
export enum RootStackingContextZIndices {
CommandMenu = 21,
CommandMenuButton = 22,
SidePanel = 21,
SidePanelButton = 22,
DropdownPortalBelowModal = 38,
RootModalBackDrop = 39,
RootModal = 40,
@@ -10,7 +10,7 @@ export type LayoutRenderingContextType = {
layoutType: PageLayoutType;
isInRightDrawer: boolean;
isInSidePanel: boolean;
};
export const [LayoutRenderingProvider, useLayoutRenderingContext] =
@@ -1,4 +1,4 @@
import { SIDE_PANEL_FOCUS_ID } from '@/command-menu/constants/SidePanelFocusId';
import { SIDE_PANEL_FOCUS_ID } from '@/side-panel/constants/SidePanelFocusId';
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
@@ -1,9 +1,9 @@
import { COMMAND_MENU_SEARCH_BAR_HEIGHT_MOBILE } from '@/command-menu/constants/CommandMenuSearchBarHeightMobile';
import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu';
import { isCommandMenuOpenedState } from '@/command-menu/states/isCommandMenuOpenedState';
import { SIDE_PANEL_TOP_BAR_HEIGHT_MOBILE } from '@/side-panel/constants/SidePanelTopBarHeightMobile';
import { useSidePanelMenu } from '@/side-panel/hooks/useSidePanelMenu';
import { isSidePanelOpenedState } from '@/side-panel/states/isSidePanelOpenedState';
import { isNavigationMenuInEditModeState } from '@/navigation-menu-item/states/isNavigationMenuInEditModeState';
import { RootStackingContextZIndices } from '@/ui/layout/constants/RootStackingContextZIndices';
import { PAGE_HEADER_COMMAND_MENU_BUTTON_CLICK_OUTSIDE_ID } from '@/ui/layout/page-header/constants/PageHeaderCommandMenuButtonClickOutsideId';
import { PAGE_HEADER_SIDE_PANEL_BUTTON_CLICK_OUTSIDE_ID } from '@/ui/layout/page-header/constants/PageHeaderSidePanelButtonClickOutsideId';
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
import { styled } from '@linaria/react';
import { i18n } from '@lingui/core';
@@ -18,12 +18,12 @@ const StyledButtonWrapper = styled.div<{ alignToTop: boolean }>`
align-items: ${({ alignToTop }) => (alignToTop ? 'center' : 'initial')};
display: ${({ alignToTop }) => (alignToTop ? 'flex' : 'block')};
height: ${({ alignToTop }) =>
alignToTop ? `${COMMAND_MENU_SEARCH_BAR_HEIGHT_MOBILE}px` : 'auto'};
alignToTop ? `${SIDE_PANEL_TOP_BAR_HEIGHT_MOBILE}px` : 'auto'};
position: ${({ alignToTop }) => (alignToTop ? 'fixed' : 'static')};
right: ${({ alignToTop }) =>
alignToTop ? themeCssVariables.spacing[3] : 'auto'};
top: ${({ alignToTop }) => (alignToTop ? '0' : 'auto')};
z-index: ${RootStackingContextZIndices.CommandMenuButton};
z-index: ${RootStackingContextZIndices.SidePanelButton};
`;
const StyledTooltipWrapper = styled.div`
@@ -38,9 +38,9 @@ const xPaths = {
};
const AnimatedIcon = ({
isCommandMenuOpened,
isSidePanelOpened,
}: {
isCommandMenuOpened: boolean;
isSidePanelOpened: boolean;
}) => {
const { theme } = useContext(ThemeContext);
@@ -64,8 +64,8 @@ const AnimatedIcon = ({
r="1"
initial={{ opacity: 0 }}
animate={{
scale: isCommandMenuOpened ? 0 : 1,
opacity: isCommandMenuOpened ? 0 : 1,
scale: isSidePanelOpened ? 0 : 1,
opacity: isSidePanelOpened ? 0 : 1,
}}
transition={{
duration: theme.animation.duration.fast,
@@ -79,13 +79,13 @@ const AnimatedIcon = ({
d={path}
initial={{ pathLength: 0, opacity: 0 }}
animate={{
pathLength: isCommandMenuOpened ? 1 : 0,
opacity: isCommandMenuOpened ? 1 : 0,
pathLength: isSidePanelOpened ? 1 : 0,
opacity: isSidePanelOpened ? 1 : 0,
}}
transition={{
duration: theme.animation.duration.fast,
ease: 'easeInOut',
delay: isCommandMenuOpened ? 0.1 : 0,
delay: isSidePanelOpened ? 0.1 : 0,
}}
/>
))}
@@ -97,8 +97,8 @@ const AnimatedIcon = ({
r="1"
initial={{ opacity: 0 }}
animate={{
scale: isCommandMenuOpened ? 0 : 1,
opacity: isCommandMenuOpened ? 0 : 1,
scale: isSidePanelOpened ? 0 : 1,
opacity: isSidePanelOpened ? 0 : 1,
}}
transition={{
duration: theme.animation.duration.fast,
@@ -112,8 +112,8 @@ const AnimatedIcon = ({
r="1"
initial={{ opacity: 0 }}
animate={{
scale: isCommandMenuOpened ? 0 : 1,
opacity: isCommandMenuOpened ? 0 : 1,
scale: isSidePanelOpened ? 0 : 1,
opacity: isSidePanelOpened ? 0 : 1,
}}
transition={{
duration: theme.animation.duration.fast,
@@ -123,39 +123,38 @@ const AnimatedIcon = ({
);
};
export const PageHeaderToggleCommandMenuButton = () => {
const { theme } = useContext(ThemeContext);
const { toggleCommandMenu } = useCommandMenu();
const isCommandMenuOpened = useAtomStateValue(isCommandMenuOpenedState);
export const PageHeaderToggleSidePanelButton = () => {
const { toggleSidePanelMenu } = useSidePanelMenu();
const isSidePanelOpened = useAtomStateValue(isSidePanelOpenedState);
const isNavigationMenuInEditMode = useAtomStateValue(
isNavigationMenuInEditModeState,
);
const isMobile = useIsMobile();
const alignWithCommandMenuTopBar =
isMobile && isNavigationMenuInEditMode && isCommandMenuOpened;
const alignWithSidePanelTopBar =
isMobile && isNavigationMenuInEditMode && isSidePanelOpened;
const ariaLabel = isCommandMenuOpened
? t`Close command menu`
: t`Open command menu`;
const ariaLabel = isSidePanelOpened
? t`Close side panel`
: t`Open side panel`;
const { theme } = useContext(ThemeContext);
return (
<StyledButtonWrapper alignToTop={alignWithCommandMenuTopBar}>
<div id="toggle-command-menu-button">
<StyledButtonWrapper alignToTop={alignWithSidePanelTopBar}>
<div id="toggle-side-panel-button">
<AnimatedButton
animatedSvg={
<AnimatedIcon isCommandMenuOpened={isCommandMenuOpened} />
}
dataClickOutsideId={PAGE_HEADER_COMMAND_MENU_BUTTON_CLICK_OUTSIDE_ID}
dataTestId="page-header-command-menu-button"
animatedSvg={<AnimatedIcon isSidePanelOpened={isSidePanelOpened} />}
dataClickOutsideId={PAGE_HEADER_SIDE_PANEL_BUTTON_CLICK_OUTSIDE_ID}
dataTestId="page-header-side-panel-button"
size={isMobile ? 'medium' : 'small'}
variant="secondary"
accent="default"
hotkeys={[getOsControlSymbol(), 'K']}
ariaLabel={ariaLabel}
onClick={toggleCommandMenu}
onClick={toggleSidePanelMenu}
animate={{
rotate: isCommandMenuOpened ? 90 : 0,
rotate: isSidePanelOpened ? 90 : 0,
}}
transition={{
duration: theme.animation.duration.normal,
@@ -166,7 +165,7 @@ export const PageHeaderToggleCommandMenuButton = () => {
<StyledTooltipWrapper>
<AppTooltip
anchorSelect="#toggle-command-menu-button"
anchorSelect="#toggle-side-panel-button"
content={i18n._(ariaLabel)}
delay={TooltipDelay.longDelay}
place={TooltipPosition.Bottom}
@@ -1,2 +0,0 @@
export const PAGE_HEADER_COMMAND_MENU_BUTTON_CLICK_OUTSIDE_ID =
'page-header-command-menu-button';
@@ -0,0 +1,2 @@
export const PAGE_HEADER_SIDE_PANEL_BUTTON_CLICK_OUTSIDE_ID =
'page-header-side-panel-button';
@@ -24,7 +24,7 @@ const StyledMainContainer = styled.div`
`;
type LeftContainerProps = {
isRightDrawerOpen?: boolean;
isSidePanelOpen?: boolean;
};
const StyledLeftContainer = styled.div<LeftContainerProps>`
@@ -1,7 +0,0 @@
import { type ResizablePanelConstraints } from '@/ui/layout/resizable-panel/types/ResizablePanelConstraints';
export const COMMAND_MENU_CONSTRAINTS: ResizablePanelConstraints = {
min: 320,
max: 600,
default: 400,
};
@@ -1,8 +0,0 @@
import { createRequiredContext } from '~/utils/createRequiredContext';
type RightDrawerContextType = {
isInRightDrawer: boolean;
};
export const [RightDrawerProvider, useIsInRightDrawerOrThrow] =
createRequiredContext<RightDrawerContextType>('RightDrawer');
@@ -15,11 +15,11 @@ const StyledContainer = styled.div`
width: 100%;
`;
type RightDrawerFooterProps = {
type SidePanelFooterProps = {
actions: React.ReactNode[];
};
export const RightDrawerFooter = ({ actions }: RightDrawerFooterProps) => {
export const SidePanelFooter = ({ actions }: SidePanelFooterProps) => {
return (
<StyledContainer>
{actions.map((action, index) => (
@@ -0,0 +1,8 @@
import { createRequiredContext } from '~/utils/createRequiredContext';
type SidePanelContextType = {
isInSidePanel: boolean;
};
export const [SidePanelProvider, useIsInSidePanelOrThrow] =
createRequiredContext<SidePanelContextType>('SidePanel');
@@ -1,4 +1,4 @@
import { SIDE_PANEL_CLOSE_EVENT_NAME } from '@/ui/layout/right-drawer/utils/emitSidePanelCloseEvent';
import { SIDE_PANEL_CLOSE_EVENT_NAME } from '@/ui/layout/side-panel/utils/emitSidePanelCloseEvent';
import { useEffect } from 'react';
export const useListenToSidePanelClosing = (callback: () => void) => {
@@ -1,4 +1,4 @@
import { SIDE_PANEL_OPEN_EVENT_NAME } from '@/ui/layout/right-drawer/utils/emitSidePanelOpenEvent';
import { SIDE_PANEL_OPEN_EVENT_NAME } from '@/ui/layout/side-panel/utils/emitSidePanelOpenEvent';
import { useEffect } from 'react';
export const useListenToSidePanelOpening = (callback: () => void) => {
@@ -46,7 +46,7 @@ export const TabList = ({
tabs,
loading,
behaveAsLinks = true,
isInRightDrawer,
isInSidePanel,
className,
componentInstanceId,
onChangeTab,
@@ -118,7 +118,7 @@ export const TabList = ({
>
<>
<TabListFromUrlOptionalEffect
isInRightDrawer={!!isInRightDrawer}
isInSidePanel={!!isInSidePanel}
tabListIds={tabs.map((tab) => tab.id)}
/>
@@ -6,12 +6,12 @@ import { useLocation } from 'react-router-dom';
type TabListFromUrlOptionalEffectProps = {
tabListIds: string[];
isInRightDrawer: boolean;
isInSidePanel: boolean;
};
export const TabListFromUrlOptionalEffect = ({
tabListIds,
isInRightDrawer,
isInSidePanel,
}: TabListFromUrlOptionalEffectProps) => {
const location = useLocation();
const activeTabId = useAtomComponentStateValue(activeTabIdComponentState);
@@ -20,7 +20,7 @@ export const TabListFromUrlOptionalEffect = ({
const hash = location.hash.replace('#', '');
useEffect(() => {
if (isInRightDrawer) {
if (isInSidePanel) {
return;
}
@@ -31,7 +31,7 @@ export const TabListFromUrlOptionalEffect = ({
if (tabListIds.includes(hash)) {
setActiveTabId(hash);
}
}, [hash, activeTabId, setActiveTabId, tabListIds, isInRightDrawer]);
}, [hash, activeTabId, setActiveTabId, tabListIds, isInSidePanel]);
return <></>;
};
@@ -76,7 +76,7 @@ export const Default: Story = {
componentInstanceId={args.componentInstanceId}
loading={args.loading}
behaveAsLinks={args.behaveAsLinks}
isInRightDrawer={args.isInRightDrawer}
isInSidePanel={args.isInSidePanel}
className={args.className}
/>
</StyledInteractiveContainer>
@@ -5,7 +5,7 @@ export type TabListProps = {
loading?: boolean;
behaveAsLinks?: boolean;
className?: string;
isInRightDrawer?: boolean;
isInSidePanel?: boolean;
componentInstanceId: string;
onChangeTab?: (tabId: string) => void;
};
@@ -4,7 +4,7 @@ import { IconSearch } from 'twenty-ui/display';
import { LightIconButton } from 'twenty-ui/input';
import { themeCssVariables } from 'twenty-ui/theme-constants';
import { useOpenRecordsSearchPageInCommandMenu } from '@/command-menu/hooks/useOpenRecordsSearchPageInCommandMenu';
import { useOpenRecordsSearchPageInSidePanel } from '@/side-panel/hooks/useOpenRecordsSearchPageInSidePanel';
import { PAGE_BAR_MIN_HEIGHT } from '@/ui/layout/page/constants/PageBarMinHeight';
import { MultiWorkspaceDropdownButton } from '@/ui/navigation/navigation-drawer/components/MultiWorkspaceDropdown/MultiWorkspaceDropdownButton';
import { isNavigationDrawerExpandedState } from '@/ui/navigation/states/isNavigationDrawerExpanded';
@@ -56,7 +56,7 @@ export const NavigationDrawerHeader = ({
showCollapseButton,
}: NavigationDrawerHeaderProps) => {
const isMobile = useIsMobile();
const { openRecordsSearchPage } = useOpenRecordsSearchPageInCommandMenu();
const { openRecordsSearchPage } = useOpenRecordsSearchPageInSidePanel();
const isNavigationDrawerExpanded = useAtomStateValue(
isNavigationDrawerExpandedState,
);