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',
|
||||
display: 'block',
|
||||
margin: theme.spacing(2, 0),
|
||||
fontSize: '1rem',
|
||||
fontSize: theme.fontSizes.bodySize,
|
||||
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,
|
||||
Tooltip,
|
||||
Switch,
|
||||
styled,
|
||||
Theme,
|
||||
} from '@mui/material';
|
||||
import MenuIcon from '@mui/icons-material/Menu';
|
||||
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 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 { IPermission } from 'interfaces/user';
|
||||
import { NavigationMenu } from './NavigationMenu/NavigationMenu';
|
||||
@ -28,13 +30,82 @@ import { getRoutes } from 'component/menu/routes';
|
||||
import { KeyboardArrowDown } from '@mui/icons-material';
|
||||
import { filterByConfig } from 'component/common/util';
|
||||
import { useAuthPermissions } from 'hooks/api/getters/useAuth/useAuthPermissions';
|
||||
import { useStyles } from './Header.styles';
|
||||
import classNames from 'classnames';
|
||||
import { useId } from 'hooks/useId';
|
||||
import { IRoute } from 'interfaces/route';
|
||||
import { ThemeMode } from 'component/common/ThemeMode/ThemeMode';
|
||||
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 { onSetThemeMode, themeMode } = useThemeMode();
|
||||
const theme = useTheme();
|
||||
@ -47,8 +118,6 @@ const Header: VFC = () => {
|
||||
const { permissions } = useAuthPermissions();
|
||||
const { uiConfig, isOss } = useUiConfig();
|
||||
const smallScreen = useMediaQuery(theme.breakpoints.down('md'));
|
||||
const { classes: styles } = useStyles();
|
||||
const { classes: themeStyles } = useThemeStyles();
|
||||
const [openDrawer, setOpenDrawer] = useState(false);
|
||||
|
||||
const toggleDrawer = () => setOpenDrawer(prev => !prev);
|
||||
@ -85,11 +154,13 @@ const Header: VFC = () => {
|
||||
|
||||
if (smallScreen) {
|
||||
return (
|
||||
<AppBar className={styles.header} position="static">
|
||||
<Container className={styles.container}>
|
||||
<StyledHeader position="static">
|
||||
<StyledContainer>
|
||||
<Tooltip title="Menu" arrow>
|
||||
<IconButton
|
||||
className={styles.drawerButton}
|
||||
sx={theme => ({
|
||||
color: theme.palette.text.tertiaryContrast,
|
||||
})}
|
||||
onClick={toggleDrawer}
|
||||
aria-controls="header-drawer"
|
||||
aria-expanded={openDrawer}
|
||||
@ -107,63 +178,40 @@ const Header: VFC = () => {
|
||||
admin={admin}
|
||||
routes={filteredMainRoutes}
|
||||
/>
|
||||
<div className={styles.userContainer}>
|
||||
<StyledUserContainer>
|
||||
<UserProfile />
|
||||
</div>
|
||||
</Container>
|
||||
</AppBar>
|
||||
</StyledUserContainer>
|
||||
</StyledContainer>
|
||||
</StyledHeader>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<AppBar className={styles.header} position="static">
|
||||
<Container className={styles.container}>
|
||||
<Link
|
||||
to="/"
|
||||
className={classNames(
|
||||
themeStyles.flexRow,
|
||||
themeStyles.focusable
|
||||
)}
|
||||
aria-label="Home"
|
||||
>
|
||||
<StyledHeader position="static">
|
||||
<StyledContainer>
|
||||
<StyledLink to="/" sx={flexRow} aria-label="Home">
|
||||
<ThemeMode
|
||||
darkmode={
|
||||
<UnleashLogoWhite
|
||||
className={styles.logo}
|
||||
aria-label="Unleash logo"
|
||||
/>
|
||||
<StyledUnleashLogoWhite aria-label="Unleash logo" />
|
||||
}
|
||||
lightmode={
|
||||
<UnleashLogo
|
||||
className={styles.logo}
|
||||
aria-label="Unleash logo"
|
||||
/>
|
||||
<StyledUnleashLogo aria-label="Unleash logo" />
|
||||
}
|
||||
/>
|
||||
</Link>
|
||||
<nav className={styles.nav}>
|
||||
<div className={styles.links}>
|
||||
<Link to="/projects" className={themeStyles.focusable}>
|
||||
Projects
|
||||
</Link>
|
||||
<Link to="/features" className={themeStyles.focusable}>
|
||||
Feature toggles
|
||||
</Link>
|
||||
<Link
|
||||
to="/playground"
|
||||
className={themeStyles.focusable}
|
||||
>
|
||||
Playground
|
||||
</Link>
|
||||
<button
|
||||
className={styles.advancedNavButton}
|
||||
</StyledLink>
|
||||
<StyledNav>
|
||||
<StyledLinks>
|
||||
<StyledLink to="/projects">Projects</StyledLink>
|
||||
<StyledLink to="/features">Feature toggles</StyledLink>
|
||||
<StyledLink to="/playground">Playground</StyledLink>
|
||||
<StyledAdvancedNavButton
|
||||
onClick={e => setConfigRef(e.currentTarget)}
|
||||
aria-controls={configRef ? configId : undefined}
|
||||
aria-expanded={Boolean(configRef)}
|
||||
>
|
||||
Configure
|
||||
<KeyboardArrowDown className={styles.icon} />
|
||||
</button>
|
||||
<KeyboardArrowDown sx={styledIconProps} />
|
||||
</StyledAdvancedNavButton>
|
||||
<NavigationMenu
|
||||
id={configId}
|
||||
options={filteredMainRoutes.mainNavRoutes}
|
||||
@ -171,8 +219,8 @@ const Header: VFC = () => {
|
||||
handleClose={onConfigureClose}
|
||||
style={{ top: 10 }}
|
||||
/>
|
||||
</div>
|
||||
<div className={styles.userContainer}>
|
||||
</StyledLinks>
|
||||
<StyledUserContainer>
|
||||
<ConditionallyRender
|
||||
condition={Boolean(
|
||||
uiConfig.flags.ENABLE_DARK_MODE_SUPPORT
|
||||
@ -196,7 +244,7 @@ const Header: VFC = () => {
|
||||
rel="noopener noreferrer"
|
||||
size="large"
|
||||
disableRipple
|
||||
className={themeStyles.focusable}
|
||||
sx={focusable}
|
||||
>
|
||||
<MenuBookIcon />
|
||||
</IconButton>
|
||||
@ -205,14 +253,10 @@ const Header: VFC = () => {
|
||||
condition={admin}
|
||||
show={
|
||||
<Tooltip title="Settings" arrow>
|
||||
<IconButton
|
||||
<StyledIconButton
|
||||
onClick={e =>
|
||||
setAdminRef(e.currentTarget)
|
||||
}
|
||||
className={classNames(
|
||||
styles.wideButton,
|
||||
themeStyles.focusable
|
||||
)}
|
||||
aria-controls={
|
||||
adminRef ? adminId : undefined
|
||||
}
|
||||
@ -222,9 +266,9 @@ const Header: VFC = () => {
|
||||
>
|
||||
<SettingsIcon />
|
||||
<KeyboardArrowDown
|
||||
className={styles.icon}
|
||||
sx={styledIconProps}
|
||||
/>
|
||||
</IconButton>
|
||||
</StyledIconButton>
|
||||
</Tooltip>
|
||||
}
|
||||
/>
|
||||
@ -236,10 +280,10 @@ const Header: VFC = () => {
|
||||
style={{ top: 5, left: -100 }}
|
||||
/>{' '}
|
||||
<UserProfile />
|
||||
</div>
|
||||
</nav>
|
||||
</Container>
|
||||
</AppBar>
|
||||
</StyledUserContainer>
|
||||
</StyledNav>
|
||||
</StyledContainer>
|
||||
</StyledHeader>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -1,5 +1,25 @@
|
||||
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 => ({
|
||||
focusable: {
|
||||
'&: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
|
||||
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.
|
||||
|
||||
### 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