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_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'; import { t } from '@lingui/core/macro'; import { motion } from 'framer-motion'; import { useContext } from 'react'; import { AppTooltip, TooltipDelay, TooltipPosition } from 'twenty-ui/display'; import { AnimatedButton } from 'twenty-ui/input'; import { getOsControlSymbol, useIsMobile } from 'twenty-ui/utilities'; import { ThemeContext, themeCssVariables } from 'twenty-ui/theme-constants'; const StyledButtonWrapper = styled.div<{ alignToTop: boolean }>` align-items: ${({ alignToTop }) => (alignToTop ? 'center' : 'initial')}; display: ${({ alignToTop }) => (alignToTop ? 'flex' : 'block')}; height: ${({ alignToTop }) => 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.SidePanelButton}; `; const StyledTooltipWrapper = styled.div` font-size: ${themeCssVariables.font.size.md}; `; const xPaths = { topLeft: `M12 12 L6 6`, topRight: `M12 12 L18 6`, bottomLeft: `M12 12 L6 18`, bottomRight: `M12 12 L18 18`, }; const AnimatedIcon = ({ isSidePanelOpened, }: { isSidePanelOpened: boolean; }) => { const { theme } = useContext(ThemeContext); return ( {/* Center dot */} {/* X lines expanding from center */} {Object.values(xPaths).map((path, index) => ( ))} {/* Top dot */} {/* Bottom dot */} ); }; export const PageHeaderToggleSidePanelButton = () => { const { toggleSidePanelMenu } = useSidePanelMenu(); const isSidePanelOpened = useAtomStateValue(isSidePanelOpenedState); const isNavigationMenuInEditMode = useAtomStateValue( isNavigationMenuInEditModeState, ); const isMobile = useIsMobile(); const alignWithSidePanelTopBar = isMobile && isNavigationMenuInEditMode && isSidePanelOpened; const ariaLabel = isSidePanelOpened ? t`Close side panel` : t`Open side panel`; const { theme } = useContext(ThemeContext); return ( } 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={toggleSidePanelMenu} animate={{ rotate: isSidePanelOpened ? 90 : 0, }} transition={{ duration: theme.animation.duration.normal, ease: 'easeInOut', }} /> ); };