diff --git a/superset-frontend/src/features/home/Menu.tsx b/superset-frontend/src/features/home/Menu.tsx index 6d7de2df558..9d8c35341bb 100644 --- a/superset-frontend/src/features/home/Menu.tsx +++ b/superset-frontend/src/features/home/Menu.tsx @@ -18,9 +18,8 @@ */ import { useState, useEffect } from 'react'; import { styled, css, useTheme } from '@apache-superset/core/ui'; -import { debounce } from 'lodash'; import { getUrlParam } from 'src/utils/urlUtils'; -import { MainNav, MenuMode } from '@superset-ui/core/components/Menu'; +import { MainNav, MenuItem } from '@superset-ui/core/components/Menu'; import { Tooltip, Grid, Row, Col, Image } from '@superset-ui/core/components'; import { GenericLink } from 'src/components'; import { NavLink, useLocation } from 'react-router-dom'; @@ -34,6 +33,7 @@ import { MenuData, } from 'src/types/bootstrapTypes'; import RightMenu from './RightMenu'; +import { NAVBAR_MENU_POPUP_OFFSET } from './commonMenuData'; interface MenuProps { data: MenuData; @@ -93,27 +93,7 @@ const StyledMainNav = styled(MainNav)` margin-inline-start: 0; } - @media (max-width: 767px) { - .ant-menu-item { - padding: 0 ${theme.sizeUnit * 6}px 0 ${theme.sizeUnit * 3}px !important; - } - - .ant-menu > .ant-menu-item > span > a { - padding: 0; - } - - &.main-nav .ant-menu-submenu-title > svg:nth-of-type(1) { - display: none; - } - } - `} -`; - -const { SubMenu } = MainNav; - -const StyledSubMenu = styled(SubMenu)` - ${({ theme }) => css` - &.ant-menu-submenu.ant-menu-submenu-horizontal { + .ant-menu-submenu.ant-menu-submenu-horizontal { display: flex; align-items: center; height: 100%; @@ -156,7 +136,7 @@ const StyledSubMenu = styled(SubMenu)` } } - &.ant-menu-submenu-selected.ant-menu-submenu-horizontal::after { + .ant-menu-submenu-selected.ant-menu-submenu-horizontal::after { transform: scale(1); } `} @@ -197,6 +177,10 @@ const StyledCol = styled(Col)` `} `; +const StyledImage = styled(Image)` + object-fit: contain; +`; + const { useBreakpoint } = Grid; export function Menu({ @@ -209,23 +193,10 @@ export function Menu({ }, isFrontendRoute = () => false, }: MenuProps) { - const [showMenu, setMenu] = useState('horizontal'); const screens = useBreakpoint(); const uiConfig = useUiConfig(); const theme = useTheme(); - useEffect(() => { - function handleResize() { - if (window.innerWidth <= 767) { - setMenu('inline'); - } else setMenu('horizontal'); - } - handleResize(); - const windowResize = debounce(() => handleResize(), 10); - window.addEventListener('resize', windowResize); - return () => window.removeEventListener('resize', windowResize); - }, []); - enum Paths { Explore = '/explore', Dashboard = '/dashboard', @@ -261,65 +232,55 @@ export function Menu({ const standalone = getUrlParam(URL_PARAMS.standalone); if (standalone || uiConfig.hideNav) return <>; - const renderSubMenu = ({ + const buildMenuItem = ({ label, childs, url, - index, isFrontendRoute, - }: MenuObjectProps) => { + }: MenuObjectProps): MenuItem => { if (url && isFrontendRoute) { - return ( - + return { + key: label, + label: ( {label} - - ); + ), + }; } + if (url) { - return ( - - {label} - - ); + return { + key: label, + label: {label}, + }; } - return ( - : - } - > - {childs?.map((child: MenuObjectChildProps | string, index1: number) => { - if (typeof child === 'string' && child === '-' && label !== 'Data') { - return ; - } - if (typeof child !== 'string') { - return ( - - {child.isFrontendRoute ? ( - - {child.label} - - ) : ( - - {child.label} - - )} - - ); - } - return null; - })} - - ); + + const childItems: MenuItem[] = []; + childs?.forEach((child: MenuObjectChildProps | string, index1: number) => { + if (typeof child === 'string' && child === '-' && label !== 'Data') { + childItems.push({ type: 'divider', key: `divider-${index1}` }); + } else if (typeof child !== 'string') { + childItems.push({ + key: `${child.label}`, + label: child.isFrontendRoute ? ( + + {child.label} + + ) : ( + {child.label} + ), + }); + } + }); + + return { + key: label, + label, + icon: , + popupOffset: NAVBAR_MENU_POPUP_OFFSET, + children: childItems, + }; }; const renderBrand = () => { let link; @@ -327,7 +288,7 @@ export function Menu({ link = ( - {theme.brandLogoAlt - {brand.alt} + ); } else { @@ -352,7 +313,7 @@ export function Menu({ href={brand.path} tabIndex={-1} > - {brand.alt} + ); } @@ -377,15 +338,13 @@ export function Menu({ )} - {menu.map((item, index) => { + items={menu.map(item => { const props = { - index, ...item, isFrontendRoute: isFrontendRoute(item.url), childs: item.childs?.map(c => { @@ -400,9 +359,9 @@ export function Menu({ }), }; - return renderSubMenu(props); + return buildMenuItem(props); })} - + /> , children: buildNewDropdownItems(), + popupOffset: NAVBAR_MENU_POPUP_OFFSET, }); } @@ -576,6 +579,7 @@ const RightMenu = ({ icon: , children: buildSettingsMenuItems(), className: 'submenu-with-caret', + popupOffset: NAVBAR_MENU_POPUP_OFFSET, }); return items; @@ -660,6 +664,8 @@ const RightMenu = ({ display: flex; flex-direction: row; align-items: center; + height: 100%; + border-bottom: none !important; /* Remove the underline from menu items */ .ant-menu-item:after, @@ -668,11 +674,14 @@ const RightMenu = ({ } .submenu-with-caret { + height: 100%; padding: 0; .ant-menu-submenu-title { + align-items: center; display: flex; gap: ${theme.sizeUnit * 2}px; flex-direction: row-reverse; + height: 100%; } &.ant-menu-submenu::after { inset-inline: ${theme.sizeUnit}px; diff --git a/superset-frontend/src/features/home/commonMenuData.ts b/superset-frontend/src/features/home/commonMenuData.ts index 1a60189e62d..ae36697aad3 100644 --- a/superset-frontend/src/features/home/commonMenuData.ts +++ b/superset-frontend/src/features/home/commonMenuData.ts @@ -18,6 +18,11 @@ */ import { t } from '@superset-ui/core'; +/** + * Shared popup offset configuration for navbar menu dropdowns. + */ +export const NAVBAR_MENU_POPUP_OFFSET: [number, number] = [0, -8]; + export const commonMenuData = { name: t('SQL'), tabs: [ diff --git a/superset-frontend/src/hooks/useThemeMenuItems.tsx b/superset-frontend/src/hooks/useThemeMenuItems.tsx index 3e4b7fc1970..4fcf9ef6a39 100644 --- a/superset-frontend/src/hooks/useThemeMenuItems.tsx +++ b/superset-frontend/src/hooks/useThemeMenuItems.tsx @@ -21,6 +21,7 @@ import { Icons, Tooltip } from '@superset-ui/core/components'; import type { MenuItem } from '@superset-ui/core/components/Menu'; import { t } from '@superset-ui/core'; import { ThemeMode, ThemeAlgorithm } from '@apache-superset/core/ui'; +import { NAVBAR_MENU_POPUP_OFFSET } from 'src/features/home/commonMenuData'; export interface ThemeSubMenuOption { key: ThemeMode; @@ -138,5 +139,6 @@ export const useThemeMenuItems = ({ icon: , className: 'submenu-with-caret', children, + popupOffset: NAVBAR_MENU_POPUP_OFFSET, }; };