diff --git a/superset-frontend/images/icons/dropdown-arrow.svg b/superset-frontend/images/icons/dropdown-arrow.svg new file mode 100644 index 0000000000..1d0d8b35c8 --- /dev/null +++ b/superset-frontend/images/icons/dropdown-arrow.svg @@ -0,0 +1,21 @@ + + + + diff --git a/superset-frontend/src/components/Icon/index.tsx b/superset-frontend/src/components/Icon/index.tsx index f798f1c987..2107de8b9a 100644 --- a/superset-frontend/src/components/Icon/index.tsx +++ b/superset-frontend/src/components/Icon/index.tsx @@ -30,6 +30,7 @@ import { ReactComponent as CloseIcon } from 'images/icons/close.svg'; import { ReactComponent as CompassIcon } from 'images/icons/compass.svg'; import { ReactComponent as DatasetPhysicalIcon } from 'images/icons/dataset_physical.svg'; import { ReactComponent as DatasetVirtualIcon } from 'images/icons/dataset_virtual.svg'; +import { ReactComponent as DropdownArrowIcon } from 'images/icons/dropdown-arrow.svg'; import { ReactComponent as ErrorIcon } from 'images/icons/error.svg'; import { ReactComponent as FavoriteSelectedIcon } from 'images/icons/favorite-selected.svg'; import { ReactComponent as FavoriteUnselectedIcon } from 'images/icons/favorite-unselected.svg'; @@ -58,6 +59,7 @@ type IconName = | 'compass' | 'dataset-physical' | 'dataset-virtual' + | 'dropdown-arrow' | 'error' | 'favorite-selected' | 'favorite-unselected' @@ -88,6 +90,7 @@ export const iconsRegistry: Record< 'favorite-selected': FavoriteSelectedIcon, 'favorite-unselected': FavoriteUnselectedIcon, 'list-view': ListViewIcon, + 'dropdown-arrow': DropdownArrowIcon, 'sort-asc': SortAscIcon, 'sort-desc': SortDescIcon, certified: CertifiedIcon, diff --git a/superset-frontend/src/components/Menu/LanguagePicker.tsx b/superset-frontend/src/components/Menu/LanguagePicker.tsx index d634265c95..69e2846313 100644 --- a/superset-frontend/src/components/Menu/LanguagePicker.tsx +++ b/superset-frontend/src/components/Menu/LanguagePicker.tsx @@ -17,7 +17,8 @@ * under the License. */ import React from 'react'; -import { NavDropdown, MenuItem } from 'react-bootstrap'; +import { MenuItem } from 'react-bootstrap'; +import NavDropdown from 'src/components/NavDropdown'; export interface Languages { [key: string]: { diff --git a/superset-frontend/src/components/Menu/Menu.less b/superset-frontend/src/components/Menu/Menu.less deleted file mode 100644 index 4f037bafb6..0000000000 --- a/superset-frontend/src/components/Menu/Menu.less +++ /dev/null @@ -1,45 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -@import '../../../stylesheets/less/variables.less'; - -#main-menu { - .navbar .caret { - width: 1rem; - padding: 0 0 18px 0; - - &:before { - position: relative; - top: -2px; - } - } - - .navbar-inverse { - border-bottom: 2px solid @gray-bg; - } - - .version-info { - padding: 5px 20px; - color: @gray-heading; - font-size: @font-size-xs; - - div { - white-space: nowrap; - } - } -} diff --git a/superset-frontend/src/components/Menu/Menu.tsx b/superset-frontend/src/components/Menu/Menu.tsx index 193347f685..d22b64dd02 100644 --- a/superset-frontend/src/components/Menu/Menu.tsx +++ b/superset-frontend/src/components/Menu/Menu.tsx @@ -24,7 +24,6 @@ import MenuObject, { MenuObjectProps } from './MenuObject'; import NewMenu from './NewMenu'; import UserMenu from './UserMenu'; import LanguagePicker, { Languages } from './LanguagePicker'; -import './Menu.less'; interface BrandProps { path: string; @@ -56,32 +55,65 @@ export interface MenuProps { } const StyledHeader = styled.header` + .caret { + display: none; + } + + .navbar-inverse { + border: none; + } + + .version-info { + padding: 5px 20px; + color: ${({ theme }) => theme.colors.grayscale.base}; + font-size: ${({ theme }) => theme.typography.sizes.xs}px; + + div { + white-space: nowrap; + } + } + .navbar-brand { display: flex; flex-direction: column; justify-content: center; } + .nav > li > a { + padding: ${({ theme }) => theme.gridUnit * 4}px; + } + .navbar-nav > li > a { + color: ${({ theme }) => theme.colors.grayscale.dark1}; + border-bottom: none; + &:focus { + border-bottom: none; + } &:after { content: ''; position: absolute; bottom: -3px; - left: 0; - width: 100%; + left: 50%; + width: 0; height: 3px; background-color: ${({ theme }) => theme.colors.primary.base}; opacity: 0; - transition: opacity ${({ theme }) => theme.transitionTiming * 2}s; + transform: translateX(-50%); + transition: all ${({ theme }) => theme.transitionTiming}s; } &:hover { + color: ${({ theme }) => theme.colors.grayscale.dark1}; border-bottom: none; - &:after { opacity: 1; + width: 100%; } } + &:hover, + &:focus { + margin: 0; + } } `; diff --git a/superset-frontend/src/components/Menu/MenuObject.tsx b/superset-frontend/src/components/Menu/MenuObject.tsx index 8de30edc8e..24609c3243 100644 --- a/superset-frontend/src/components/Menu/MenuObject.tsx +++ b/superset-frontend/src/components/Menu/MenuObject.tsx @@ -17,7 +17,8 @@ * under the License. */ import React from 'react'; -import { NavItem, NavDropdown, MenuItem } from 'react-bootstrap'; +import { NavItem, MenuItem } from 'react-bootstrap'; +import NavDropdown from '../NavDropdown'; interface MenuObjectChildProps { label: string; @@ -44,23 +45,13 @@ export default function MenuObject({ if (url) { return ( -   {label} + {label} ); } - const navTitle = ( - <> - -   {label} - - ); return ( - + {childs?.map((child: MenuObjectChildProps | string, index1: number) => { if (typeof child === 'string' && child === '-') { return ; @@ -71,7 +62,6 @@ export default function MenuObject({ href={child.url} eventKey={parseFloat(`${index}.${index1}`)} > -   {child.label} ); diff --git a/superset-frontend/src/components/Menu/UserMenu.tsx b/superset-frontend/src/components/Menu/UserMenu.tsx index 4712d49fe7..bbda0ef4de 100644 --- a/superset-frontend/src/components/Menu/UserMenu.tsx +++ b/superset-frontend/src/components/Menu/UserMenu.tsx @@ -17,7 +17,8 @@ * under the License. */ import React from 'react'; -import { NavDropdown, MenuItem } from 'react-bootstrap'; +import { MenuItem } from 'react-bootstrap'; +import NavDropdown from 'src/components/NavDropdown'; import { t } from '@superset-ui/translation'; interface UserMenuProps { @@ -42,14 +43,8 @@ export default function UserMenu({ } > - - - {t('Profile')} - - - - {t('Logout')} - + {t('Profile')} + {t('Logout')} {(versionString || versionSha) && (
  • {versionString &&
    Version: {versionString}
    } diff --git a/superset-frontend/src/components/NavDropdown/index.tsx b/superset-frontend/src/components/NavDropdown/index.tsx new file mode 100644 index 0000000000..cb80c5cfd5 --- /dev/null +++ b/superset-frontend/src/components/NavDropdown/index.tsx @@ -0,0 +1,72 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import styled from '@superset-ui/style'; +import { NavDropdown as ReactBootstrapNavDropdown } from 'react-bootstrap'; + +const NavDropdown = styled(ReactBootstrapNavDropdown)` + &.dropdown > a.dropdown-toggle { + padding-right: ${({ theme }) => theme.gridUnit * 6}px; + } + & > a { + transition: background-color ${({ theme }) => theme.transitionTiming}s; + } + &.dropdown.open > a.dropdown-toggle { + background: ${({ theme }) => theme.colors.primary.light4}; + } + + :after { + content: ''; + height: ${({ theme }) => theme.gridUnit}px; + width: ${({ theme }) => theme.gridUnit * 2}px; + background: url('/static/assets/images/icons/dropdown-arrow.svg'); + background-size: contain; + background-position: center center; + background-repeat: no-repeat; + position: absolute; + top: 50%; + transform: translateY(-50%); + right: ${({ theme }) => theme.gridUnit * 2}px; + transition: opacity ${({ theme }) => theme.transitionTiming}s; + opacity: ${({ theme }) => theme.opacity.mediumLight}; + pointer-events: none; + } + &:hover, + &.active { + &:after { + opacity: ${({ theme }) => theme.opacity.mediumHeavy}; + } + } + .dropdown-menu { + padding: ${({ theme }) => theme.gridUnit}px 0; + top: 100%; + border: none; + & li a { + padding: ${({ theme }) => theme.gridUnit}px + ${({ theme }) => theme.gridUnit * 4}px; + transition: all ${({ theme }) => theme.transitionTiming}s; + &:hover { + background: ${({ theme }) => theme.colors.primary.light4}; + color: ${({ theme }) => theme.colors.grayscale.dark1}; + } + } + } +`; + +export default NavDropdown; diff --git a/superset-frontend/stylesheets/less/cosmo/bootswatch.less b/superset-frontend/stylesheets/less/cosmo/bootswatch.less index 6daabb44d8..a83537e7e6 100644 --- a/superset-frontend/stylesheets/less/cosmo/bootswatch.less +++ b/superset-frontend/stylesheets/less/cosmo/bootswatch.less @@ -43,7 +43,7 @@ } .navbar-inverse { - border: 3px solid @navbar-inverse-bg; + border: none; } .navbar-inverse .navbar-nav > li > a:hover,