1
0
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:
Mateusz Kwasniewski 2023-01-03 14:52:10 +01:00 committed by GitHub
parent 88d649d239
commit cc1512cd44
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 155 additions and 153 deletions

View File

@ -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,
})); }));

View File

@ -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,
},
}));

View File

@ -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>
); );
}; };

View File

@ -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': {

View File

@ -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}/>
```