mirror of
https://github.com/Unleash/unleash.git
synced 2025-01-25 00:07:47 +01:00
refactor: styled component in header (#2808)
This commit is contained in:
parent
88d649d239
commit
cc1512cd44
@ -4,6 +4,6 @@ export const FooterTitle = styled('h2')(({ theme }) => ({
|
|||||||
all: 'unset',
|
all: 'unset',
|
||||||
display: 'block',
|
display: 'block',
|
||||||
margin: theme.spacing(2, 0),
|
margin: theme.spacing(2, 0),
|
||||||
fontSize: '1rem',
|
fontSize: theme.fontSizes.bodySize,
|
||||||
fontWeight: theme.fontWeight.bold,
|
fontWeight: theme.fontWeight.bold,
|
||||||
}));
|
}));
|
||||||
|
@ -1,89 +0,0 @@
|
|||||||
import { makeStyles } from 'tss-react/mui';
|
|
||||||
|
|
||||||
export const useStyles = makeStyles()(theme => ({
|
|
||||||
header: {
|
|
||||||
backgroundColor: theme.palette.headerBackground,
|
|
||||||
padding: '0.5rem',
|
|
||||||
boxShadow: 'none',
|
|
||||||
position: 'relative',
|
|
||||||
zIndex: 300,
|
|
||||||
},
|
|
||||||
links: {
|
|
||||||
display: 'flex',
|
|
||||||
justifyContent: 'center',
|
|
||||||
marginLeft: '1.5rem',
|
|
||||||
'& a': {
|
|
||||||
textDecoration: 'none',
|
|
||||||
color: 'inherit',
|
|
||||||
marginRight: '1.5rem',
|
|
||||||
display: 'flex',
|
|
||||||
alignItems: 'center',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
container: {
|
|
||||||
display: 'flex',
|
|
||||||
alignItems: 'center',
|
|
||||||
maxWidth: 1280,
|
|
||||||
[theme.breakpoints.down('md')]: {
|
|
||||||
padding: '0',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
nav: {
|
|
||||||
display: 'flex',
|
|
||||||
alignItems: 'center',
|
|
||||||
flexGrow: 1,
|
|
||||||
},
|
|
||||||
drawerButton: {
|
|
||||||
color: '#000',
|
|
||||||
},
|
|
||||||
advancedNavButton: {
|
|
||||||
border: 'none',
|
|
||||||
background: 'transparent',
|
|
||||||
height: '100%',
|
|
||||||
display: 'flex',
|
|
||||||
fontSize: '1rem',
|
|
||||||
fontFamily: theme.typography.fontFamily,
|
|
||||||
alignItems: 'center',
|
|
||||||
color: 'inherit',
|
|
||||||
cursor: 'pointer',
|
|
||||||
},
|
|
||||||
headerTitle: {
|
|
||||||
fontSize: '1.4rem',
|
|
||||||
},
|
|
||||||
userContainer: {
|
|
||||||
marginLeft: 'auto',
|
|
||||||
display: 'flex',
|
|
||||||
alignItems: 'center',
|
|
||||||
},
|
|
||||||
logoOnly: {
|
|
||||||
width: '60px',
|
|
||||||
},
|
|
||||||
logo: {
|
|
||||||
width: '150px',
|
|
||||||
},
|
|
||||||
popover: {
|
|
||||||
top: '25px',
|
|
||||||
},
|
|
||||||
menuItem: {
|
|
||||||
minWidth: '150px',
|
|
||||||
},
|
|
||||||
menuItemBox: {
|
|
||||||
width: '12.5px',
|
|
||||||
height: '12.5px',
|
|
||||||
display: 'block',
|
|
||||||
backgroundColor: theme.palette.primary.main,
|
|
||||||
marginRight: '1rem',
|
|
||||||
borderRadius: '2px',
|
|
||||||
},
|
|
||||||
navMenuLink: {
|
|
||||||
textDecoration: 'none',
|
|
||||||
alignItems: 'center',
|
|
||||||
display: 'flex',
|
|
||||||
},
|
|
||||||
icon: {
|
|
||||||
color: theme.palette.grey[700],
|
|
||||||
},
|
|
||||||
wideButton: {
|
|
||||||
borderRadius: 100,
|
|
||||||
},
|
|
||||||
}));
|
|
@ -9,6 +9,8 @@ import {
|
|||||||
IconButton,
|
IconButton,
|
||||||
Tooltip,
|
Tooltip,
|
||||||
Switch,
|
Switch,
|
||||||
|
styled,
|
||||||
|
Theme,
|
||||||
} from '@mui/material';
|
} 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 SettingsIcon from '@mui/icons-material/Settings';
|
||||||
@ -20,7 +22,7 @@ import { ReactComponent as UnleashLogoWhite } from 'assets/img/logoWithWhiteText
|
|||||||
|
|
||||||
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 { useThemeStyles } from 'themes/themeStyles';
|
import { flexRow, focusable, useThemeStyles } from 'themes/themeStyles';
|
||||||
import { ADMIN } from 'component/providers/AccessProvider/permissions';
|
import { ADMIN } from 'component/providers/AccessProvider/permissions';
|
||||||
import { IPermission } from 'interfaces/user';
|
import { IPermission } from 'interfaces/user';
|
||||||
import { NavigationMenu } from './NavigationMenu/NavigationMenu';
|
import { NavigationMenu } from './NavigationMenu/NavigationMenu';
|
||||||
@ -28,13 +30,82 @@ import { getRoutes } from 'component/menu/routes';
|
|||||||
import { KeyboardArrowDown } from '@mui/icons-material';
|
import { KeyboardArrowDown } from '@mui/icons-material';
|
||||||
import { filterByConfig } from 'component/common/util';
|
import { filterByConfig } from 'component/common/util';
|
||||||
import { useAuthPermissions } from 'hooks/api/getters/useAuth/useAuthPermissions';
|
import { useAuthPermissions } from 'hooks/api/getters/useAuth/useAuthPermissions';
|
||||||
import { useStyles } from './Header.styles';
|
|
||||||
import classNames from 'classnames';
|
|
||||||
import { useId } from 'hooks/useId';
|
import { useId } from 'hooks/useId';
|
||||||
import { IRoute } from 'interfaces/route';
|
import { IRoute } from 'interfaces/route';
|
||||||
import { ThemeMode } from 'component/common/ThemeMode/ThemeMode';
|
import { ThemeMode } from 'component/common/ThemeMode/ThemeMode';
|
||||||
import { useThemeMode } from 'hooks/useThemeMode';
|
import { useThemeMode } from 'hooks/useThemeMode';
|
||||||
|
|
||||||
|
const StyledHeader = styled(AppBar)(({ theme }) => ({
|
||||||
|
backgroundColor: theme.palette.headerBackground,
|
||||||
|
padding: theme.spacing(1),
|
||||||
|
boxShadow: 'none',
|
||||||
|
position: 'relative',
|
||||||
|
zIndex: 300,
|
||||||
|
}));
|
||||||
|
|
||||||
|
const StyledContainer = styled(Container)(({ theme }) => ({
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
maxWidth: 1280,
|
||||||
|
[theme.breakpoints.down('md')]: {
|
||||||
|
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 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 }) => ({
|
||||||
|
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 StyledIconButton = styled(IconButton)(({ theme }) => ({
|
||||||
|
...focusable(theme),
|
||||||
|
borderRadius: 100,
|
||||||
|
}));
|
||||||
|
|
||||||
const Header: VFC = () => {
|
const Header: VFC = () => {
|
||||||
const { onSetThemeMode, themeMode } = useThemeMode();
|
const { onSetThemeMode, themeMode } = useThemeMode();
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
@ -47,8 +118,6 @@ const Header: VFC = () => {
|
|||||||
const { permissions } = useAuthPermissions();
|
const { permissions } = useAuthPermissions();
|
||||||
const { uiConfig, isOss } = useUiConfig();
|
const { uiConfig, isOss } = useUiConfig();
|
||||||
const smallScreen = useMediaQuery(theme.breakpoints.down('md'));
|
const smallScreen = useMediaQuery(theme.breakpoints.down('md'));
|
||||||
const { classes: styles } = useStyles();
|
|
||||||
const { classes: themeStyles } = useThemeStyles();
|
|
||||||
const [openDrawer, setOpenDrawer] = useState(false);
|
const [openDrawer, setOpenDrawer] = useState(false);
|
||||||
|
|
||||||
const toggleDrawer = () => setOpenDrawer(prev => !prev);
|
const toggleDrawer = () => setOpenDrawer(prev => !prev);
|
||||||
@ -85,11 +154,13 @@ const Header: VFC = () => {
|
|||||||
|
|
||||||
if (smallScreen) {
|
if (smallScreen) {
|
||||||
return (
|
return (
|
||||||
<AppBar className={styles.header} position="static">
|
<StyledHeader position="static">
|
||||||
<Container className={styles.container}>
|
<StyledContainer>
|
||||||
<Tooltip title="Menu" arrow>
|
<Tooltip title="Menu" arrow>
|
||||||
<IconButton
|
<IconButton
|
||||||
className={styles.drawerButton}
|
sx={theme => ({
|
||||||
|
color: theme.palette.text.tertiaryContrast,
|
||||||
|
})}
|
||||||
onClick={toggleDrawer}
|
onClick={toggleDrawer}
|
||||||
aria-controls="header-drawer"
|
aria-controls="header-drawer"
|
||||||
aria-expanded={openDrawer}
|
aria-expanded={openDrawer}
|
||||||
@ -107,63 +178,40 @@ const Header: VFC = () => {
|
|||||||
admin={admin}
|
admin={admin}
|
||||||
routes={filteredMainRoutes}
|
routes={filteredMainRoutes}
|
||||||
/>
|
/>
|
||||||
<div className={styles.userContainer}>
|
<StyledUserContainer>
|
||||||
<UserProfile />
|
<UserProfile />
|
||||||
</div>
|
</StyledUserContainer>
|
||||||
</Container>
|
</StyledContainer>
|
||||||
</AppBar>
|
</StyledHeader>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AppBar className={styles.header} position="static">
|
<StyledHeader position="static">
|
||||||
<Container className={styles.container}>
|
<StyledContainer>
|
||||||
<Link
|
<StyledLink to="/" sx={flexRow} aria-label="Home">
|
||||||
to="/"
|
|
||||||
className={classNames(
|
|
||||||
themeStyles.flexRow,
|
|
||||||
themeStyles.focusable
|
|
||||||
)}
|
|
||||||
aria-label="Home"
|
|
||||||
>
|
|
||||||
<ThemeMode
|
<ThemeMode
|
||||||
darkmode={
|
darkmode={
|
||||||
<UnleashLogoWhite
|
<StyledUnleashLogoWhite aria-label="Unleash logo" />
|
||||||
className={styles.logo}
|
|
||||||
aria-label="Unleash logo"
|
|
||||||
/>
|
|
||||||
}
|
}
|
||||||
lightmode={
|
lightmode={
|
||||||
<UnleashLogo
|
<StyledUnleashLogo aria-label="Unleash logo" />
|
||||||
className={styles.logo}
|
|
||||||
aria-label="Unleash logo"
|
|
||||||
/>
|
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</Link>
|
</StyledLink>
|
||||||
<nav className={styles.nav}>
|
<StyledNav>
|
||||||
<div className={styles.links}>
|
<StyledLinks>
|
||||||
<Link to="/projects" className={themeStyles.focusable}>
|
<StyledLink to="/projects">Projects</StyledLink>
|
||||||
Projects
|
<StyledLink to="/features">Feature toggles</StyledLink>
|
||||||
</Link>
|
<StyledLink to="/playground">Playground</StyledLink>
|
||||||
<Link to="/features" className={themeStyles.focusable}>
|
<StyledAdvancedNavButton
|
||||||
Feature toggles
|
|
||||||
</Link>
|
|
||||||
<Link
|
|
||||||
to="/playground"
|
|
||||||
className={themeStyles.focusable}
|
|
||||||
>
|
|
||||||
Playground
|
|
||||||
</Link>
|
|
||||||
<button
|
|
||||||
className={styles.advancedNavButton}
|
|
||||||
onClick={e => setConfigRef(e.currentTarget)}
|
onClick={e => setConfigRef(e.currentTarget)}
|
||||||
aria-controls={configRef ? configId : undefined}
|
aria-controls={configRef ? configId : undefined}
|
||||||
aria-expanded={Boolean(configRef)}
|
aria-expanded={Boolean(configRef)}
|
||||||
>
|
>
|
||||||
Configure
|
Configure
|
||||||
<KeyboardArrowDown className={styles.icon} />
|
<KeyboardArrowDown sx={styledIconProps} />
|
||||||
</button>
|
</StyledAdvancedNavButton>
|
||||||
<NavigationMenu
|
<NavigationMenu
|
||||||
id={configId}
|
id={configId}
|
||||||
options={filteredMainRoutes.mainNavRoutes}
|
options={filteredMainRoutes.mainNavRoutes}
|
||||||
@ -171,8 +219,8 @@ const Header: VFC = () => {
|
|||||||
handleClose={onConfigureClose}
|
handleClose={onConfigureClose}
|
||||||
style={{ top: 10 }}
|
style={{ top: 10 }}
|
||||||
/>
|
/>
|
||||||
</div>
|
</StyledLinks>
|
||||||
<div className={styles.userContainer}>
|
<StyledUserContainer>
|
||||||
<ConditionallyRender
|
<ConditionallyRender
|
||||||
condition={Boolean(
|
condition={Boolean(
|
||||||
uiConfig.flags.ENABLE_DARK_MODE_SUPPORT
|
uiConfig.flags.ENABLE_DARK_MODE_SUPPORT
|
||||||
@ -196,7 +244,7 @@ const Header: VFC = () => {
|
|||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
size="large"
|
size="large"
|
||||||
disableRipple
|
disableRipple
|
||||||
className={themeStyles.focusable}
|
sx={focusable}
|
||||||
>
|
>
|
||||||
<MenuBookIcon />
|
<MenuBookIcon />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
@ -205,14 +253,10 @@ const Header: VFC = () => {
|
|||||||
condition={admin}
|
condition={admin}
|
||||||
show={
|
show={
|
||||||
<Tooltip title="Settings" arrow>
|
<Tooltip title="Settings" arrow>
|
||||||
<IconButton
|
<StyledIconButton
|
||||||
onClick={e =>
|
onClick={e =>
|
||||||
setAdminRef(e.currentTarget)
|
setAdminRef(e.currentTarget)
|
||||||
}
|
}
|
||||||
className={classNames(
|
|
||||||
styles.wideButton,
|
|
||||||
themeStyles.focusable
|
|
||||||
)}
|
|
||||||
aria-controls={
|
aria-controls={
|
||||||
adminRef ? adminId : undefined
|
adminRef ? adminId : undefined
|
||||||
}
|
}
|
||||||
@ -222,9 +266,9 @@ const Header: VFC = () => {
|
|||||||
>
|
>
|
||||||
<SettingsIcon />
|
<SettingsIcon />
|
||||||
<KeyboardArrowDown
|
<KeyboardArrowDown
|
||||||
className={styles.icon}
|
sx={styledIconProps}
|
||||||
/>
|
/>
|
||||||
</IconButton>
|
</StyledIconButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
@ -236,10 +280,10 @@ const Header: VFC = () => {
|
|||||||
style={{ top: 5, left: -100 }}
|
style={{ top: 5, left: -100 }}
|
||||||
/>{' '}
|
/>{' '}
|
||||||
<UserProfile />
|
<UserProfile />
|
||||||
</div>
|
</StyledUserContainer>
|
||||||
</nav>
|
</StyledNav>
|
||||||
</Container>
|
</StyledContainer>
|
||||||
</AppBar>
|
</StyledHeader>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,5 +1,25 @@
|
|||||||
import { makeStyles } from 'tss-react/mui';
|
import { makeStyles } from 'tss-react/mui';
|
||||||
|
import { Theme } from '@mui/material';
|
||||||
|
|
||||||
|
export const focusable = (theme: Theme) => ({
|
||||||
|
'&:focus-visible': {
|
||||||
|
outline: 0,
|
||||||
|
outlineStyle: 'solid',
|
||||||
|
outlineWidth: 2,
|
||||||
|
outlineOffset: 2,
|
||||||
|
outlineColor: theme.palette.primary.main,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export const flexRow = {
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Please extract styles below into MUI fragments as shown above
|
||||||
|
* @deprecated
|
||||||
|
*/
|
||||||
export const useThemeStyles = makeStyles()(theme => ({
|
export const useThemeStyles = makeStyles()(theme => ({
|
||||||
focusable: {
|
focusable: {
|
||||||
'&:focus-visible': {
|
'&:focus-visible': {
|
||||||
|
@ -14,3 +14,30 @@ In the codebase, we need to have a uniform way of performing style updates.
|
|||||||
We have decided to move away from using makeStyles as it's currently deprecated from @material/ui, and kept alive with an
|
We have decided to move away from using makeStyles as it's currently deprecated from @material/ui, and kept alive with an
|
||||||
external interop package to maintain compatability with the latest version. The preferred path forward is to use styled components which is
|
external interop package to maintain compatability with the latest version. The preferred path forward is to use styled components which is
|
||||||
supported natively in @material/ui and sparingly use the sx prop available on all mui components.
|
supported natively in @material/ui and sparingly use the sx prop available on all mui components.
|
||||||
|
|
||||||
|
### Consequences: code sharing
|
||||||
|
|
||||||
|
With makeStyles it was common to reuse CSS fragments via library utilities.
|
||||||
|
In the styled components approach we use themeable functions and object literals
|
||||||
|
|
||||||
|
```ts
|
||||||
|
import { Theme } from '@mui/material';
|
||||||
|
|
||||||
|
export const focusable = (theme: Theme) => ({
|
||||||
|
color: theme.palette.primary.main,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const flexRow = {
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
```ts
|
||||||
|
const StyledLink = styled(Link)(({ theme }) => ({
|
||||||
|
...focusable(theme),
|
||||||
|
}));
|
||||||
|
|
||||||
|
<IconButton sx={focusable}/>
|
||||||
|
```
|
||||||
|
Loading…
Reference in New Issue
Block a user