1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-01-25 00:07:47 +01:00

feat: hide top nav (#7140)

This commit is contained in:
Mateusz Kwasniewski 2024-05-24 12:08:08 +02:00 committed by GitHub
parent d2176880e2
commit 8b5e39c997
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 354 additions and 109 deletions

View File

@ -20,11 +20,18 @@ import { AdminIndex } from './AdminIndex';
import { AdminTabsMenu } from './menu/AdminTabsMenu'; import { AdminTabsMenu } from './menu/AdminTabsMenu';
import { Banners } from './banners/Banners'; import { Banners } from './banners/Banners';
import { License } from './license/License'; import { License } from './license/License';
import { useUiFlag } from 'hooks/useUiFlag';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
export const Admin = () => { export const Admin = () => {
const sidebarNavigationEnabled = useUiFlag('navigationSidebar');
return ( return (
<> <>
<AdminTabsMenu /> <ConditionallyRender
condition={!sidebarNavigationEnabled}
show={<AdminTabsMenu />}
/>
<Routes> <Routes>
<Route index element={<AdminIndex />} /> <Route index element={<AdminIndex />} />
<Route path='users/*' element={<UsersAdmin />} /> <Route path='users/*' element={<UsersAdmin />} />

View File

@ -1,6 +1,7 @@
import { forwardRef, type ReactNode } from 'react'; import { forwardRef, type ReactNode } from 'react';
import { Box, Grid, styled, useMediaQuery, useTheme } from '@mui/material'; import { Box, Grid, styled, useMediaQuery, useTheme } from '@mui/material';
import Header from 'component/menu/Header/Header'; import Header from 'component/menu/Header/Header';
import OldHeader from 'component/menu/Header/OldHeader';
import Footer from 'component/menu/Footer/Footer'; import Footer from 'component/menu/Footer/Footer';
import Proclamation from 'component/common/Proclamation/Proclamation'; import Proclamation from 'component/common/Proclamation/Proclamation';
import BreadcrumbNav from 'component/common/BreadcrumbNav/BreadcrumbNav'; import BreadcrumbNav from 'component/common/BreadcrumbNav/BreadcrumbNav';
@ -110,7 +111,12 @@ export const MainLayout = forwardRef<HTMLDivElement, IMainLayoutProps>(
return ( return (
<> <>
<SkipNavLink /> <SkipNavLink />
<Header /> <ConditionallyRender
condition={sidebarNavigationEnabled}
show={<Header />}
elseShow={<OldHeader />}
/>
<SkipNavTarget /> <SkipNavTarget />
<MainLayoutContainer> <MainLayoutContainer>
<MainLayoutContentWrapper> <MainLayoutContentWrapper>

View File

@ -2,16 +2,8 @@ import { useState, type VFC } from 'react';
import useMediaQuery from '@mui/material/useMediaQuery'; import useMediaQuery from '@mui/material/useMediaQuery';
import { useTheme } from '@mui/material/styles'; import { useTheme } from '@mui/material/styles';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import { import { AppBar, Box, IconButton, styled, Tooltip } from '@mui/material';
AppBar,
IconButton,
Tooltip,
styled,
type Theme,
Box,
} from '@mui/material';
import MenuIcon from '@mui/icons-material/Menu'; import MenuIcon from '@mui/icons-material/Menu';
import SettingsIcon from '@mui/icons-material/Settings';
import UserProfile from 'component/user/UserProfile'; import UserProfile from 'component/user/UserProfile';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import MenuBookIcon from '@mui/icons-material/MenuBook'; import MenuBookIcon from '@mui/icons-material/MenuBook';
@ -23,20 +15,16 @@ import { ReactComponent as CelebatoryUnleashLogoWhite } from 'assets/img/unleash
import { DrawerMenu } from './DrawerMenu/DrawerMenu'; import { DrawerMenu } from './DrawerMenu/DrawerMenu';
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig'; import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
import { flexRow, focusable } from 'themes/themeStyles'; import { flexRow, focusable } from 'themes/themeStyles';
import { NavigationMenu } from './NavigationMenu/NavigationMenu'; import { getCondensedRoutes, getRoutes } from 'component/menu/routes';
import { getRoutes, getCondensedRoutes } from 'component/menu/routes';
import DarkModeOutlined from '@mui/icons-material/DarkModeOutlined'; import DarkModeOutlined from '@mui/icons-material/DarkModeOutlined';
import KeyboardArrowDown from '@mui/icons-material/KeyboardArrowDown';
import LightModeOutlined from '@mui/icons-material/LightModeOutlined'; import LightModeOutlined from '@mui/icons-material/LightModeOutlined';
import { filterByConfig, mapRouteLink } from 'component/common/util'; import { filterByConfig, mapRouteLink } from 'component/common/util';
import { useId } from 'hooks/useId';
import { ThemeMode } from 'component/common/ThemeMode/ThemeMode'; import { ThemeMode } from 'component/common/ThemeMode/ThemeMode';
import { useThemeMode } from 'hooks/useThemeMode'; import { useThemeMode } from 'hooks/useThemeMode';
import { Notifications } from 'component/common/Notifications/Notifications'; import { Notifications } from 'component/common/Notifications/Notifications';
import { useAdminRoutes } from 'component/admin/useAdminRoutes'; import { useAdminRoutes } from 'component/admin/useAdminRoutes';
import InviteLinkButton from './InviteLink/InviteLinkButton/InviteLinkButton'; import InviteLinkButton from './InviteLink/InviteLinkButton/InviteLinkButton';
import { useUiFlag } from 'hooks/useUiFlag'; import { useUiFlag } from 'hooks/useUiFlag';
import { Badge } from '../../common/Badge/Badge';
const HeaderComponent = styled(AppBar)(({ theme }) => ({ const HeaderComponent = styled(AppBar)(({ theme }) => ({
backgroundColor: theme.palette.background.paper, backgroundColor: theme.palette.background.paper,
@ -44,9 +32,8 @@ const HeaderComponent = styled(AppBar)(({ theme }) => ({
boxShadow: 'none', boxShadow: 'none',
position: 'relative', position: 'relative',
zIndex: 300, zIndex: 300,
maxWidth: '1512px', paddingRight: theme.spacing(9),
[theme.breakpoints.down('lg')]: { [theme.breakpoints.down('lg')]: {
maxWidth: '1280px',
paddingLeft: theme.spacing(1), paddingLeft: theme.spacing(1),
paddingRight: theme.spacing(1), paddingRight: theme.spacing(1),
}, },
@ -98,23 +85,6 @@ const StyledLinks = styled('div')(({ theme }) => ({
}, },
})); }));
const StyledAdvancedNavButton = styled('button')(({ theme }) => ({
...focusable(theme),
border: 'none',
background: 'transparent',
height: '100%',
display: 'flex',
fontSize: theme.fontSizes.bodySize,
fontFamily: theme.typography.fontFamily,
alignItems: 'center',
color: 'inherit',
cursor: 'pointer',
}));
const styledIconProps = (theme: Theme) => ({
color: theme.palette.neutral.main,
});
const StyledLink = styled(Link)(({ theme }) => focusable(theme)); const StyledLink = styled(Link)(({ theme }) => focusable(theme));
const StyledText = styled('div')(({ theme }) => ({ const StyledText = styled('div')(({ theme }) => ({
@ -123,17 +93,6 @@ const StyledText = styled('div')(({ theme }) => ({
gap: theme.spacing(1), gap: theme.spacing(1),
})); }));
const StyledLinkWithBetaBadge = ({
title,
to,
}: { title: string; to: string }) => (
<StyledLink to={to} sx={{ margin: 0 }}>
<StyledText>
<span>{title}</span> <Badge color='success'>Beta</Badge>
</StyledText>
</StyledLink>
);
const StyledIconButton = styled(IconButton)<{ const StyledIconButton = styled(IconButton)<{
component?: 'a' | 'button'; component?: 'a' | 'button';
href?: string; href?: string;
@ -151,25 +110,13 @@ const StyledIconButton = styled(IconButton)<{
const Header: VFC = () => { const Header: VFC = () => {
const { onSetThemeMode, themeMode } = useThemeMode(); const { onSetThemeMode, themeMode } = useThemeMode();
const theme = useTheme(); const theme = useTheme();
const adminId = useId();
const configId = useId();
const [adminRef, setAdminRef] = useState<HTMLButtonElement | null>(null);
const [configRef, setConfigRef] = useState<HTMLButtonElement | null>(null);
const disableNotifications = useUiFlag('disableNotifications'); const disableNotifications = useUiFlag('disableNotifications');
const { uiConfig, isOss } = useUiConfig(); const { uiConfig, isOss } = useUiConfig();
const sidebarNavigationEnabled = useUiFlag('navigationSidebar'); const smallScreen = useMediaQuery(theme.breakpoints.down('lg'));
const smallScreen = useMediaQuery(
sidebarNavigationEnabled
? theme.breakpoints.down('lg')
: theme.breakpoints.down('md'),
);
const [openDrawer, setOpenDrawer] = useState(false); const [openDrawer, setOpenDrawer] = useState(false);
const toggleDrawer = () => setOpenDrawer((prev) => !prev); const toggleDrawer = () => setOpenDrawer((prev) => !prev);
const onAdminClose = () => setAdminRef(null);
const onConfigureClose = () => setConfigRef(null);
const celebatoryUnleash = useUiFlag('celebrateUnleash'); const celebatoryUnleash = useUiFlag('celebrateUnleash');
const insightsDashboard = useUiFlag('executiveDashboardUI');
const routes = getRoutes(); const routes = getRoutes();
const adminRoutes = useAdminRoutes(); const adminRoutes = useAdminRoutes();
@ -242,35 +189,6 @@ const Header: VFC = () => {
</StyledLink> </StyledLink>
<StyledNav> <StyledNav>
<StyledLinks>
<StyledLink to='/projects'>Projects</StyledLink>
<StyledLink to={'/search'}>Search</StyledLink>
<StyledLink to='/playground'>Playground</StyledLink>
<ConditionallyRender
condition={insightsDashboard}
show={
<StyledLinkWithBetaBadge
to={'/insights'}
title={'Insights'}
/>
}
/>
<StyledAdvancedNavButton
onClick={(e) => setConfigRef(e.currentTarget)}
aria-controls={configRef ? configId : undefined}
aria-expanded={Boolean(configRef)}
>
Configure
<KeyboardArrowDown sx={styledIconProps} />
</StyledAdvancedNavButton>
<NavigationMenu
id={configId}
options={filteredMainRoutes.mainNavRoutes}
anchorEl={configRef}
handleClose={onConfigureClose}
style={{ top: 10 }}
/>
</StyledLinks>
<StyledUserContainer> <StyledUserContainer>
<InviteLinkButton /> <InviteLinkButton />
<Tooltip <Tooltip
@ -303,30 +221,11 @@ const Header: VFC = () => {
target='_blank' target='_blank'
rel='noopener noreferrer' rel='noopener noreferrer'
size='large' size='large'
sx={{ mr: 1 }}
> >
<MenuBookIcon /> <MenuBookIcon />
</StyledIconButton> </StyledIconButton>
</Tooltip> </Tooltip>
<Tooltip title='Settings' arrow>
<StyledIconButton
onClick={(e) => setAdminRef(e.currentTarget)}
aria-controls={adminRef ? adminId : undefined}
aria-expanded={Boolean(adminRef)}
size='large'
>
<SettingsIcon />
</StyledIconButton>
</Tooltip>
<NavigationMenu
id={adminId}
options={filteredMainRoutes.adminRoutes}
anchorEl={adminRef}
handleClose={onAdminClose}
style={{
top: 5,
left: -100,
}}
/>{' '}
<UserProfile /> <UserProfile />
</StyledUserContainer> </StyledUserContainer>
</StyledNav> </StyledNav>

View File

@ -0,0 +1,333 @@
import { useState, type VFC } from 'react';
import useMediaQuery from '@mui/material/useMediaQuery';
import { useTheme } from '@mui/material/styles';
import { Link } from 'react-router-dom';
import {
AppBar,
IconButton,
Tooltip,
styled,
type Theme,
Box,
} from '@mui/material';
import MenuIcon from '@mui/icons-material/Menu';
import SettingsIcon from '@mui/icons-material/Settings';
import UserProfile from 'component/user/UserProfile';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import MenuBookIcon from '@mui/icons-material/MenuBook';
import { ReactComponent as UnleashLogo } from 'assets/img/logoDarkWithText.svg';
import { ReactComponent as UnleashLogoWhite } from 'assets/img/logoWithWhiteText.svg';
import { ReactComponent as CelebatoryUnleashLogo } from 'assets/img/unleashHoliday.svg';
import { ReactComponent as CelebatoryUnleashLogoWhite } from 'assets/img/unleashHolidayDark.svg';
import { DrawerMenu } from './DrawerMenu/DrawerMenu';
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
import { flexRow, focusable } from 'themes/themeStyles';
import { NavigationMenu } from './NavigationMenu/NavigationMenu';
import { getRoutes, getCondensedRoutes } from 'component/menu/routes';
import DarkModeOutlined from '@mui/icons-material/DarkModeOutlined';
import KeyboardArrowDown from '@mui/icons-material/KeyboardArrowDown';
import LightModeOutlined from '@mui/icons-material/LightModeOutlined';
import { filterByConfig, mapRouteLink } from 'component/common/util';
import { useId } from 'hooks/useId';
import { ThemeMode } from 'component/common/ThemeMode/ThemeMode';
import { useThemeMode } from 'hooks/useThemeMode';
import { Notifications } from 'component/common/Notifications/Notifications';
import { useAdminRoutes } from 'component/admin/useAdminRoutes';
import InviteLinkButton from './InviteLink/InviteLinkButton/InviteLinkButton';
import { useUiFlag } from 'hooks/useUiFlag';
import { Badge } from '../../common/Badge/Badge';
const HeaderComponent = styled(AppBar)(({ theme }) => ({
backgroundColor: theme.palette.background.paper,
padding: theme.spacing(1),
boxShadow: 'none',
position: 'relative',
zIndex: 300,
maxWidth: '1512px',
[theme.breakpoints.down('lg')]: {
maxWidth: '1280px',
paddingLeft: theme.spacing(1),
paddingRight: theme.spacing(1),
},
[theme.breakpoints.down(1024)]: {
marginLeft: 0,
marginRight: 0,
},
[theme.breakpoints.down('sm')]: {
minWidth: '100%',
},
margin: '0 auto',
}));
const ContainerComponent = styled(Box)(() => ({
display: 'flex',
alignItems: 'center',
width: '100%',
'&&&': { padding: 0 },
}));
const StyledUserContainer = styled('div')({
marginLeft: 'auto',
display: 'flex',
alignItems: 'center',
});
const StyledNav = styled('nav')({
display: 'flex',
alignItems: 'center',
flexGrow: 1,
});
const StyledUnleashLogoWhite = styled(UnleashLogoWhite)({ width: '150px' });
const StyledUnleashLogo = styled(UnleashLogo)({ width: '150px' });
const StyledCelebatoryLogo = styled(CelebatoryUnleashLogo)({ width: '150px' });
const StyledLinks = styled('div')(({ theme }) => ({
display: 'flex',
justifyContent: 'center',
marginLeft: theme.spacing(3),
'& a': {
textDecoration: 'none',
color: 'inherit',
marginRight: theme.spacing(3),
display: 'flex',
alignItems: 'center',
},
}));
const StyledAdvancedNavButton = styled('button')(({ theme }) => ({
...focusable(theme),
border: 'none',
background: 'transparent',
height: '100%',
display: 'flex',
fontSize: theme.fontSizes.bodySize,
fontFamily: theme.typography.fontFamily,
alignItems: 'center',
color: 'inherit',
cursor: 'pointer',
}));
const styledIconProps = (theme: Theme) => ({
color: theme.palette.neutral.main,
});
const StyledLink = styled(Link)(({ theme }) => focusable(theme));
const StyledText = styled('div')(({ theme }) => ({
display: 'flex',
alignItems: 'center',
gap: theme.spacing(1),
}));
const StyledLinkWithBetaBadge = ({
title,
to,
}: { title: string; to: string }) => (
<StyledLink to={to} sx={{ margin: 0 }}>
<StyledText>
<span>{title}</span> <Badge color='success'>Beta</Badge>
</StyledText>
</StyledLink>
);
const StyledIconButton = styled(IconButton)<{
component?: 'a' | 'button';
href?: string;
target?: string;
}>(({ theme }) => ({
borderRadius: 100,
'&:focus-visible': {
outlineStyle: 'solid',
outlineWidth: 2,
outlineColor: theme.palette.primary.main,
borderRadius: '100%',
},
}));
const OldHeader: VFC = () => {
const { onSetThemeMode, themeMode } = useThemeMode();
const theme = useTheme();
const adminId = useId();
const configId = useId();
const [adminRef, setAdminRef] = useState<HTMLButtonElement | null>(null);
const [configRef, setConfigRef] = useState<HTMLButtonElement | null>(null);
const disableNotifications = useUiFlag('disableNotifications');
const { uiConfig, isOss } = useUiConfig();
const smallScreen = useMediaQuery(theme.breakpoints.down('md'));
const [openDrawer, setOpenDrawer] = useState(false);
const toggleDrawer = () => setOpenDrawer((prev) => !prev);
const onAdminClose = () => setAdminRef(null);
const onConfigureClose = () => setConfigRef(null);
const celebatoryUnleash = useUiFlag('celebrateUnleash');
const insightsDashboard = useUiFlag('executiveDashboardUI');
const routes = getRoutes();
const adminRoutes = useAdminRoutes();
const filteredMainRoutes = {
mainNavRoutes: getCondensedRoutes(routes.mainNavRoutes)
.filter(filterByConfig(uiConfig))
.map(mapRouteLink),
mobileRoutes: getCondensedRoutes(routes.mobileRoutes)
.filter(filterByConfig(uiConfig))
.map(mapRouteLink),
adminRoutes,
};
if (smallScreen) {
return (
<HeaderComponent position='static'>
<ContainerComponent>
<Tooltip title='Menu' arrow>
<IconButton
sx={{
color: (theme) => theme.palette.text.primary,
}}
onClick={toggleDrawer}
aria-controls='header-drawer'
aria-expanded={openDrawer}
size='large'
>
<MenuIcon />
</IconButton>
</Tooltip>
<DrawerMenu
links={uiConfig.links}
open={openDrawer}
toggleDrawer={toggleDrawer}
routes={filteredMainRoutes}
/>
<StyledUserContainer>
<UserProfile />
</StyledUserContainer>
</ContainerComponent>
</HeaderComponent>
);
}
return (
<HeaderComponent position='static'>
<ContainerComponent>
<StyledLink to='/' sx={flexRow} aria-label='Home'>
<ThemeMode
darkmode={
<ConditionallyRender
condition={celebatoryUnleash}
show={<CelebatoryUnleashLogoWhite />}
elseShow={
<StyledUnleashLogoWhite aria-label='Unleash logo' />
}
/>
}
lightmode={
<ConditionallyRender
condition={celebatoryUnleash}
show={<StyledCelebatoryLogo />}
elseShow={
<StyledUnleashLogo aria-label='Unleash logo' />
}
/>
}
/>
</StyledLink>
<StyledNav>
<StyledLinks>
<StyledLink to='/projects'>Projects</StyledLink>
<StyledLink to={'/search'}>Search</StyledLink>
<StyledLink to='/playground'>Playground</StyledLink>
<ConditionallyRender
condition={insightsDashboard}
show={
<StyledLinkWithBetaBadge
to={'/insights'}
title={'Insights'}
/>
}
/>
<StyledAdvancedNavButton
onClick={(e) => setConfigRef(e.currentTarget)}
aria-controls={configRef ? configId : undefined}
aria-expanded={Boolean(configRef)}
>
Configure
<KeyboardArrowDown sx={styledIconProps} />
</StyledAdvancedNavButton>
<NavigationMenu
id={configId}
options={filteredMainRoutes.mainNavRoutes}
anchorEl={configRef}
handleClose={onConfigureClose}
style={{ top: 10 }}
/>
</StyledLinks>
<StyledUserContainer>
<InviteLinkButton />
<Tooltip
title={
themeMode === 'dark'
? 'Switch to light theme'
: 'Switch to dark theme'
}
arrow
>
<StyledIconButton
onClick={onSetThemeMode}
size='large'
>
<ConditionallyRender
condition={themeMode === 'dark'}
show={<DarkModeOutlined />}
elseShow={<LightModeOutlined />}
/>
</StyledIconButton>
</Tooltip>
<ConditionallyRender
condition={!isOss() && !disableNotifications}
show={<Notifications />}
/>
<Tooltip title='Documentation' arrow>
<StyledIconButton
component='a'
href='https://docs.getunleash.io/'
target='_blank'
rel='noopener noreferrer'
size='large'
>
<MenuBookIcon />
</StyledIconButton>
</Tooltip>
<Tooltip title='Settings' arrow>
<StyledIconButton
onClick={(e) => setAdminRef(e.currentTarget)}
aria-controls={adminRef ? adminId : undefined}
aria-expanded={Boolean(adminRef)}
size='large'
>
<SettingsIcon />
</StyledIconButton>
</Tooltip>
<NavigationMenu
id={adminId}
options={filteredMainRoutes.adminRoutes}
anchorEl={adminRef}
handleClose={onAdminClose}
style={{
top: 5,
left: -100,
}}
/>{' '}
<UserProfile />
</StyledUserContainer>
</StyledNav>
</ContainerComponent>
</HeaderComponent>
);
};
export default OldHeader;

View File

@ -56,7 +56,7 @@ process.nextTick(async () => {
createProjectWithEnvironmentConfig: true, createProjectWithEnvironmentConfig: true,
manyStrategiesPagination: true, manyStrategiesPagination: true,
enableLegacyVariants: false, enableLegacyVariants: false,
navigationSidebar: true, navigationSidebar: false,
}, },
}, },
authentication: { authentication: {