mirror of
https://github.com/grafana/grafana.git
synced 2025-09-28 04:43:50 +08:00
NavBar: Styling tweaks to tidy up appearance (#39871)
* NavBar: Styling tweaks to tidy up appearance * NavBar: Add external link icon to external links * NavBar: Dim the external link icon * bump drone * NavBar: Rename variable to better describe what it's doing
This commit is contained in:
@ -80,7 +80,7 @@ export function createComponents(colors: ThemeColors, shadows: ThemeShadows): Th
|
|||||||
background: colors.mode === 'dark' ? 'rgba(0, 0, 0, 0.45)' : 'rgba(208, 209, 211, 0.24)',
|
background: colors.mode === 'dark' ? 'rgba(0, 0, 0, 0.45)' : 'rgba(208, 209, 211, 0.24)',
|
||||||
},
|
},
|
||||||
sidemenu: {
|
sidemenu: {
|
||||||
width: 60,
|
width: 44,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -101,7 +101,8 @@ const getStyles = (theme: GrafanaTheme2) => ({
|
|||||||
display: none;
|
display: none;
|
||||||
|
|
||||||
${theme.breakpoints.up('md')} {
|
${theme.breakpoints.up('md')} {
|
||||||
display: block;
|
display: flex;
|
||||||
|
flex-direction: inherit;
|
||||||
margin-bottom: ${theme.spacing(2)};
|
margin-bottom: ${theme.spacing(2)};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,6 +31,12 @@ describe('DropdownChild', () => {
|
|||||||
expect(icon).toBeInTheDocument();
|
expect(icon).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('displays an external link icon if the target is _blank', () => {
|
||||||
|
render(<DropdownChild text={mockText} icon={mockIcon} url={mockUrl} target="_blank" />);
|
||||||
|
const icon = screen.getByTestId('external-link-icon');
|
||||||
|
expect(icon).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
it('displays a divider instead when isDivider is true', () => {
|
it('displays a divider instead when isDivider is true', () => {
|
||||||
render(<DropdownChild text={mockText} icon={mockIcon} url={mockUrl} isDivider />);
|
render(<DropdownChild text={mockText} icon={mockIcon} url={mockUrl} isDivider />);
|
||||||
|
|
||||||
|
@ -17,10 +17,15 @@ const DropdownChild = ({ isDivider = false, icon, onClick, target, text, url }:
|
|||||||
const styles = getStyles(theme);
|
const styles = getStyles(theme);
|
||||||
|
|
||||||
const linkContent = (
|
const linkContent = (
|
||||||
<>
|
<div className={styles.linkContent}>
|
||||||
{icon && <Icon data-testid="dropdown-child-icon" name={icon} className={styles.icon} />}
|
<div>
|
||||||
{text}
|
{icon && <Icon data-testid="dropdown-child-icon" name={icon} className={styles.icon} />}
|
||||||
</>
|
{text}
|
||||||
|
</div>
|
||||||
|
{target === '_blank' && (
|
||||||
|
<Icon data-testid="external-link-icon" name="external-link-alt" className={styles.externalLinkIcon} />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
let element = (
|
let element = (
|
||||||
@ -53,7 +58,17 @@ const getStyles = (theme: GrafanaTheme2) => ({
|
|||||||
display: flex;
|
display: flex;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
`,
|
`,
|
||||||
|
externalLinkIcon: css`
|
||||||
|
color: ${theme.colors.text.secondary};
|
||||||
|
margin-left: ${theme.spacing(1)};
|
||||||
|
`,
|
||||||
icon: css`
|
icon: css`
|
||||||
margin-right: ${theme.spacing(1)};
|
margin-right: ${theme.spacing(1)};
|
||||||
`,
|
`,
|
||||||
|
linkContent: css`
|
||||||
|
display: flex;
|
||||||
|
flex: 1;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: space-between;
|
||||||
|
`,
|
||||||
});
|
});
|
||||||
|
@ -49,16 +49,16 @@ NavBar.displayName = 'NavBar';
|
|||||||
|
|
||||||
const getStyles = (theme: GrafanaTheme2) => ({
|
const getStyles = (theme: GrafanaTheme2) => ({
|
||||||
sidemenu: css`
|
sidemenu: css`
|
||||||
border-right: 1px solid ${theme.components.panel.borderColor};
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
width: ${theme.components.sidemenu.width}px;
|
|
||||||
z-index: ${theme.zIndex.sidemenu};
|
z-index: ${theme.zIndex.sidemenu};
|
||||||
|
|
||||||
${theme.breakpoints.up('md')} {
|
${theme.breakpoints.up('md')} {
|
||||||
background-color: ${theme.colors.background.primary};
|
background-color: ${theme.colors.background.primary};
|
||||||
|
border-right: 1px solid ${theme.components.panel.borderColor};
|
||||||
position: relative;
|
position: relative;
|
||||||
|
width: ${theme.components.sidemenu.width}px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidemenu-hidden & {
|
.sidemenu-hidden & {
|
||||||
|
@ -23,8 +23,9 @@ const NavBarDropdown = ({
|
|||||||
reverseDirection = false,
|
reverseDirection = false,
|
||||||
subtitleText,
|
subtitleText,
|
||||||
}: Props) => {
|
}: Props) => {
|
||||||
|
const filteredItems = items.filter((item) => !item.hideFromMenu);
|
||||||
const theme = useTheme2();
|
const theme = useTheme2();
|
||||||
const styles = getStyles(theme, reverseDirection);
|
const styles = getStyles(theme, reverseDirection, filteredItems);
|
||||||
|
|
||||||
let header = (
|
let header = (
|
||||||
<button onClick={onHeaderClick} className={styles.header}>
|
<button onClick={onHeaderClick} className={styles.header}>
|
||||||
@ -47,19 +48,17 @@ const NavBarDropdown = ({
|
|||||||
return (
|
return (
|
||||||
<ul className={`${styles.menu} dropdown-menu dropdown-menu--sidemenu`} role="menu">
|
<ul className={`${styles.menu} dropdown-menu dropdown-menu--sidemenu`} role="menu">
|
||||||
<li>{header}</li>
|
<li>{header}</li>
|
||||||
{items
|
{filteredItems.map((child, index) => (
|
||||||
.filter((item) => !item.hideFromMenu)
|
<DropdownChild
|
||||||
.map((child, index) => (
|
key={`${child.url}-${index}`}
|
||||||
<DropdownChild
|
isDivider={child.divider}
|
||||||
key={`${child.url}-${index}`}
|
icon={child.icon as IconName}
|
||||||
isDivider={child.divider}
|
onClick={child.onClick}
|
||||||
icon={child.icon as IconName}
|
target={child.target}
|
||||||
onClick={child.onClick}
|
text={child.text}
|
||||||
target={child.target}
|
url={child.url}
|
||||||
text={child.text}
|
/>
|
||||||
url={child.url}
|
))}
|
||||||
/>
|
|
||||||
))}
|
|
||||||
{subtitleText && <li className={styles.subtitle}>{subtitleText}</li>}
|
{subtitleText && <li className={styles.subtitle}>{subtitleText}</li>}
|
||||||
</ul>
|
</ul>
|
||||||
);
|
);
|
||||||
@ -67,52 +66,62 @@ const NavBarDropdown = ({
|
|||||||
|
|
||||||
export default NavBarDropdown;
|
export default NavBarDropdown;
|
||||||
|
|
||||||
const getStyles = (theme: GrafanaTheme2, reverseDirection: Props['reverseDirection']) => ({
|
const getStyles = (
|
||||||
header: css`
|
theme: GrafanaTheme2,
|
||||||
background-color: ${theme.colors.background.secondary};
|
reverseDirection: Props['reverseDirection'],
|
||||||
border: none;
|
filteredItems: Props['items']
|
||||||
color: ${theme.colors.text.primary};
|
) => {
|
||||||
font-size: ${theme.typography.h4.fontSize};
|
const adjustHeightForBorder = filteredItems!.length === 0;
|
||||||
font-weight: ${theme.typography.h4.fontWeight};
|
|
||||||
padding: ${theme.spacing(1)} ${theme.spacing(1)} ${theme.spacing(1)} ${theme.spacing(2)} !important;
|
|
||||||
white-space: nowrap;
|
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
&:hover {
|
return {
|
||||||
background-color: ${theme.colors.action.hover};
|
header: css`
|
||||||
}
|
background-color: ${theme.colors.background.secondary};
|
||||||
|
border: none;
|
||||||
.sidemenu-open--xs & {
|
color: ${theme.colors.text.primary};
|
||||||
display: flex;
|
height: ${theme.components.sidemenu.width - (adjustHeightForBorder ? 2 : 1)}px;
|
||||||
font-size: ${theme.typography.body.fontSize};
|
font-size: ${theme.typography.h4.fontSize};
|
||||||
font-weight: ${theme.typography.body.fontWeight};
|
font-weight: ${theme.typography.h4.fontWeight};
|
||||||
padding-left: ${theme.spacing(1)} !important;
|
padding: ${theme.spacing(1)} ${theme.spacing(1)} ${theme.spacing(1)} ${theme.spacing(2)} !important;
|
||||||
}
|
white-space: nowrap;
|
||||||
`,
|
|
||||||
menu: css`
|
|
||||||
flex-direction: ${reverseDirection ? 'column-reverse' : 'column'};
|
|
||||||
|
|
||||||
.sidemenu-open--xs & {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
float: none;
|
|
||||||
margin-bottom: ${theme.spacing(1)};
|
|
||||||
position: unset;
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
|
||||||
`,
|
|
||||||
subtitle: css`
|
|
||||||
border-bottom: 1px solid ${theme.colors.border.weak};
|
|
||||||
color: ${theme.colors.text.secondary};
|
|
||||||
font-size: ${theme.typography.bodySmall.fontSize};
|
|
||||||
font-weight: ${theme.typography.bodySmall.fontWeight};
|
|
||||||
margin-bottom: ${theme.spacing(1)};
|
|
||||||
padding: ${theme.spacing(1)} ${theme.spacing(2)} ${theme.spacing(1)};
|
|
||||||
white-space: nowrap;
|
|
||||||
|
|
||||||
.sidemenu-open--xs & {
|
&:hover {
|
||||||
border-bottom: none;
|
background-color: ${theme.colors.action.hover};
|
||||||
margin-bottom: 0;
|
}
|
||||||
}
|
|
||||||
`,
|
.sidemenu-open--xs & {
|
||||||
});
|
display: flex;
|
||||||
|
font-size: ${theme.typography.body.fontSize};
|
||||||
|
font-weight: ${theme.typography.body.fontWeight};
|
||||||
|
padding-left: ${theme.spacing(1)} !important;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
menu: css`
|
||||||
|
border: 1px solid ${theme.components.panel.borderColor};
|
||||||
|
flex-direction: ${reverseDirection ? 'column-reverse' : 'column'};
|
||||||
|
|
||||||
|
.sidemenu-open--xs & {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
float: none;
|
||||||
|
margin-bottom: ${theme.spacing(1)};
|
||||||
|
position: unset;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
subtitle: css`
|
||||||
|
border-bottom: 1px solid ${theme.colors.border.weak};
|
||||||
|
color: ${theme.colors.text.secondary};
|
||||||
|
font-size: ${theme.typography.bodySmall.fontSize};
|
||||||
|
font-weight: ${theme.typography.bodySmall.fontWeight};
|
||||||
|
margin-bottom: ${theme.spacing(1)};
|
||||||
|
padding: ${theme.spacing(1)} ${theme.spacing(2)} ${theme.spacing(1)};
|
||||||
|
white-space: nowrap;
|
||||||
|
|
||||||
|
.sidemenu-open--xs & {
|
||||||
|
border-bottom: none;
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
@ -95,7 +95,6 @@ const getStyles = (theme: GrafanaTheme2, isActive: Props['isActive']) => ({
|
|||||||
|
|
||||||
.dropdown-menu {
|
.dropdown-menu {
|
||||||
animation: dropdown-anim 150ms ease-in-out 100ms forwards;
|
animation: dropdown-anim 150ms ease-in-out 100ms forwards;
|
||||||
border: none;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
// important to overlap it otherwise it can be hidden
|
// important to overlap it otherwise it can be hidden
|
||||||
// again by the mouse getting outside the hover space
|
// again by the mouse getting outside the hover space
|
||||||
@ -117,9 +116,10 @@ const getStyles = (theme: GrafanaTheme2, isActive: Props['isActive']) => ({
|
|||||||
border: none;
|
border: none;
|
||||||
color: inherit;
|
color: inherit;
|
||||||
display: block;
|
display: block;
|
||||||
line-height: 42px;
|
line-height: ${theme.components.sidemenu.width}px;
|
||||||
|
padding: 0;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
width: ${theme.components.sidemenu.width - 1}px;
|
width: ${theme.components.sidemenu.width}px;
|
||||||
|
|
||||||
&::before {
|
&::before {
|
||||||
display: ${isActive ? 'block' : 'none'};
|
display: ${isActive ? 'block' : 'none'};
|
||||||
|
@ -53,7 +53,8 @@ const getStyles = (theme: GrafanaTheme2) => ({
|
|||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
|
|
||||||
${theme.breakpoints.up('md')} {
|
${theme.breakpoints.up('md')} {
|
||||||
display: block;
|
display: flex;
|
||||||
|
flex-direction: inherit;
|
||||||
margin-top: ${theme.spacing(5)};
|
margin-top: ${theme.spacing(5)};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user