mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Sidemenu: Refactor Sidemenu to use emotion (#38995)
* Chore(Sidemenu): Refactor Sidemenu scss into emotion * Fix unit test * Sidemenu: use cx instead of template strings
This commit is contained in:
@@ -1,4 +1,3 @@
|
||||
|
||||
<!-- 8.1.3 START -->
|
||||
|
||||
# 8.1.3 (2021-09-08)
|
||||
|
||||
@@ -24,4 +24,3 @@ list = false
|
||||
- **Plugins:** Track signed files + add warn log for plugin assets which are not signed. [#38938](https://github.com/grafana/grafana/pull/38938), [@wbrowne](https://github.com/wbrowne)
|
||||
- **Postgres/MySQL/MSSQL:** Fix region annotations not displayed correctly. [#38936](https://github.com/grafana/grafana/pull/38936), [@marefr](https://github.com/marefr)
|
||||
- **Prometheus:** Fix validate selector in metrics browser. [#38921](https://github.com/grafana/grafana/pull/38921), [@ivanahuckova](https://github.com/ivanahuckova)
|
||||
|
||||
|
||||
@@ -60,7 +60,9 @@ describe('BottomSection', () => {
|
||||
it('creates the correct children for the help link', () => {
|
||||
render(
|
||||
<BrowserRouter>
|
||||
<BottomSection />
|
||||
<div className="sidemenu-open--xs">
|
||||
<BottomSection />
|
||||
</div>
|
||||
</BrowserRouter>
|
||||
);
|
||||
|
||||
|
||||
@@ -1,19 +1,22 @@
|
||||
import React, { useState } from 'react';
|
||||
import { cloneDeep } from 'lodash';
|
||||
import { NavModelItem } from '@grafana/data';
|
||||
import { Icon, IconName } from '@grafana/ui';
|
||||
import appEvents from '../../app_events';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
import SideMenuItem from './SideMenuItem';
|
||||
import { ShowModalReactEvent } from '../../../types/events';
|
||||
import { cloneDeep } from 'lodash';
|
||||
import { css } from '@emotion/css';
|
||||
import { GrafanaTheme2, NavModelItem } from '@grafana/data';
|
||||
import { Icon, IconName, styleMixins, useTheme2 } from '@grafana/ui';
|
||||
import { contextSrv } from 'app/core/services/context_srv';
|
||||
import appEvents from '../../app_events';
|
||||
import { ShowModalReactEvent } from '../../../types/events';
|
||||
import config from '../../config';
|
||||
import { OrgSwitcher } from '../OrgSwitcher';
|
||||
import { getFooterLinks } from '../Footer/Footer';
|
||||
import { HelpModal } from '../help/HelpModal';
|
||||
import config from '../../config';
|
||||
import SideMenuItem from './SideMenuItem';
|
||||
import { getForcedLoginUrl } from './utils';
|
||||
|
||||
export default function BottomSection() {
|
||||
const theme = useTheme2();
|
||||
const styles = getStyles(theme);
|
||||
const navTree: NavModelItem[] = cloneDeep(config.bootData.navTree);
|
||||
const bottomNav = navTree.filter((item) => item.hideFromMenu);
|
||||
const isSignedIn = contextSrv.isSignedIn;
|
||||
@@ -39,7 +42,7 @@ export default function BottomSection() {
|
||||
}
|
||||
|
||||
return (
|
||||
<div data-testid="bottom-section-items" className="sidemenu__bottom">
|
||||
<div data-testid="bottom-section-items" className={styles.container}>
|
||||
{!isSignedIn && (
|
||||
<SideMenuItem label="Sign In" target="_self" url={forcedLoginUrl}>
|
||||
<Icon name="signout" size="xl" />
|
||||
@@ -90,3 +93,18 @@ export default function BottomSection() {
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const getStyles = (theme: GrafanaTheme2) => ({
|
||||
container: css`
|
||||
display: none;
|
||||
|
||||
@media ${styleMixins.mediaUp(`${theme.breakpoints.values.md}px`)} {
|
||||
display: block;
|
||||
margin-bottom: ${theme.spacing(2)};
|
||||
}
|
||||
|
||||
.sidemenu-open--xs & {
|
||||
display: block;
|
||||
}
|
||||
`,
|
||||
});
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import React from 'react';
|
||||
import { css } from '@emotion/css';
|
||||
import { GrafanaTheme2 } from '@grafana/data';
|
||||
import { Icon, IconName, Link, useTheme2 } from '@grafana/ui';
|
||||
|
||||
export interface Props {
|
||||
@@ -13,35 +14,28 @@ export interface Props {
|
||||
|
||||
const DropDownChild = ({ isDivider = false, icon, onClick, target, text, url }: Props) => {
|
||||
const theme = useTheme2();
|
||||
const iconClassName = css`
|
||||
margin-right: ${theme.spacing(1)};
|
||||
`;
|
||||
const resetButtonStyles = css`
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
width: 100%;
|
||||
`;
|
||||
const styles = getStyles(theme);
|
||||
|
||||
const linkContent = (
|
||||
<>
|
||||
{icon && <Icon data-testid="dropdown-child-icon" name={icon} className={iconClassName} />}
|
||||
{icon && <Icon data-testid="dropdown-child-icon" name={icon} className={styles.icon} />}
|
||||
{text}
|
||||
</>
|
||||
);
|
||||
|
||||
let element = (
|
||||
<button className={resetButtonStyles} onClick={onClick}>
|
||||
<button className={styles.element} onClick={onClick}>
|
||||
{linkContent}
|
||||
</button>
|
||||
);
|
||||
if (url) {
|
||||
element =
|
||||
!target && url.startsWith('/') ? (
|
||||
<Link onClick={onClick} href={url}>
|
||||
<Link className={styles.element} onClick={onClick} href={url}>
|
||||
{linkContent}
|
||||
</Link>
|
||||
) : (
|
||||
<a href={url} target={target} rel="noopener" onClick={onClick}>
|
||||
<a className={styles.element} href={url} target={target} rel="noopener" onClick={onClick}>
|
||||
{linkContent}
|
||||
</a>
|
||||
);
|
||||
@@ -51,3 +45,15 @@ const DropDownChild = ({ isDivider = false, icon, onClick, target, text, url }:
|
||||
};
|
||||
|
||||
export default DropDownChild;
|
||||
|
||||
const getStyles = (theme: GrafanaTheme2) => ({
|
||||
element: css`
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
`,
|
||||
icon: css`
|
||||
margin-right: ${theme.spacing(1)};
|
||||
`,
|
||||
});
|
||||
|
||||
@@ -1,16 +1,20 @@
|
||||
import React, { FC, useCallback } from 'react';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
import { css, cx } from '@emotion/css';
|
||||
import { GrafanaTheme2 } from '@grafana/data';
|
||||
import { Icon, styleMixins, useTheme2 } from '@grafana/ui';
|
||||
import appEvents from '../../app_events';
|
||||
import TopSection from './TopSection';
|
||||
import BottomSection from './BottomSection';
|
||||
import { Branding } from 'app/core/components/Branding/Branding';
|
||||
import config from 'app/core/config';
|
||||
import { CoreEvents, KioskMode } from 'app/types';
|
||||
import { Branding } from 'app/core/components/Branding/Branding';
|
||||
import { Icon } from '@grafana/ui';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
import TopSection from './TopSection';
|
||||
import BottomSection from './BottomSection';
|
||||
|
||||
const homeUrl = config.appSubUrl || '/';
|
||||
|
||||
export const SideMenu: FC = React.memo(() => {
|
||||
const theme = useTheme2();
|
||||
const styles = getStyles(theme);
|
||||
const location = useLocation();
|
||||
const query = new URLSearchParams(location.search);
|
||||
const kiosk = query.get('kiosk') as KioskMode;
|
||||
@@ -24,21 +28,87 @@ export const SideMenu: FC = React.memo(() => {
|
||||
}
|
||||
|
||||
return (
|
||||
<nav className="sidemenu" data-testid="sidemenu" aria-label="Main menu">
|
||||
<a href={homeUrl} className="sidemenu__logo" key="logo">
|
||||
<nav className={cx(styles.sidemenu, 'sidemenu')} data-testid="sidemenu" aria-label="Main menu">
|
||||
<a href={homeUrl} className={styles.homeLogo}>
|
||||
<Branding.MenuLogo />
|
||||
</a>
|
||||
<div className="sidemenu__logo_small_breakpoint" onClick={toggleSideMenuSmallBreakpoint} key="hamburger">
|
||||
<div className={styles.mobileSidemenuLogo} onClick={toggleSideMenuSmallBreakpoint} key="hamburger">
|
||||
<Icon name="bars" size="xl" />
|
||||
<span className="sidemenu__close">
|
||||
<span className={styles.closeButton}>
|
||||
<Icon name="times" />
|
||||
Close
|
||||
Close
|
||||
</span>
|
||||
</div>
|
||||
<TopSection key="topsection" />
|
||||
<BottomSection key="bottomsection" />
|
||||
<TopSection />
|
||||
<BottomSection />
|
||||
</nav>
|
||||
);
|
||||
});
|
||||
|
||||
SideMenu.displayName = 'SideMenu';
|
||||
|
||||
const getStyles = (theme: GrafanaTheme2) => ({
|
||||
sidemenu: css`
|
||||
border-right: 1px solid ${theme.components.panel.borderColor};
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: fixed;
|
||||
width: ${theme.components.sidemenu.width}px;
|
||||
z-index: ${theme.zIndex.sidemenu};
|
||||
|
||||
@media ${styleMixins.mediaUp(`${theme.breakpoints.values.md}px`)} {
|
||||
background-color: ${theme.colors.background.primary};
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.sidemenu-hidden & {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.sidemenu-open--xs & {
|
||||
background-color: ${theme.colors.background.primary};
|
||||
box-shadow: ${theme.shadows.z1};
|
||||
height: auto;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
}
|
||||
`,
|
||||
homeLogo: css`
|
||||
display: none;
|
||||
min-height: ${theme.components.sidemenu.width}px;
|
||||
|
||||
&:hover {
|
||||
background-color: ${theme.colors.action.hover};
|
||||
}
|
||||
|
||||
img {
|
||||
width: ${theme.spacing(3.5)};
|
||||
}
|
||||
|
||||
@media ${styleMixins.mediaUp(`${theme.breakpoints.values.md}px`)} {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
`,
|
||||
closeButton: css`
|
||||
display: none;
|
||||
|
||||
.sidemenu-open--xs & {
|
||||
display: block;
|
||||
font-size: ${theme.typography.fontSize}px;
|
||||
}
|
||||
`,
|
||||
mobileSidemenuLogo: css`
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
padding: ${theme.spacing(2)};
|
||||
|
||||
@media ${styleMixins.mediaUp(`${theme.breakpoints.values.md}px`)} {
|
||||
display: none;
|
||||
}
|
||||
`,
|
||||
});
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import React from 'react';
|
||||
import DropDownChild from './DropDownChild';
|
||||
import { NavModelItem } from '@grafana/data';
|
||||
import { IconName, Link } from '@grafana/ui';
|
||||
import { css } from '@emotion/css';
|
||||
import { GrafanaTheme2, NavModelItem } from '@grafana/data';
|
||||
import { IconName, Link, useTheme2 } from '@grafana/ui';
|
||||
import DropDownChild from './DropDownChild';
|
||||
|
||||
interface Props {
|
||||
headerTarget?: HTMLAnchorElement['target'];
|
||||
@@ -23,32 +23,30 @@ const SideMenuDropDown = ({
|
||||
reverseDirection = false,
|
||||
subtitleText,
|
||||
}: Props) => {
|
||||
const headerContent = <span className="sidemenu-item-text">{headerText}</span>;
|
||||
const theme = useTheme2();
|
||||
const styles = getStyles(theme, reverseDirection);
|
||||
|
||||
let header = (
|
||||
<button onClick={onHeaderClick} className="side-menu-header-link">
|
||||
{headerContent}
|
||||
<button onClick={onHeaderClick} className={styles.header}>
|
||||
{headerText}
|
||||
</button>
|
||||
);
|
||||
if (headerUrl) {
|
||||
header =
|
||||
!headerTarget && headerUrl.startsWith('/') ? (
|
||||
<Link href={headerUrl} onClick={onHeaderClick} className="side-menu-header-link">
|
||||
{headerContent}
|
||||
<Link href={headerUrl} onClick={onHeaderClick} className={styles.header}>
|
||||
{headerText}
|
||||
</Link>
|
||||
) : (
|
||||
<a href={headerUrl} target={headerTarget} onClick={onHeaderClick} className="side-menu-header-link">
|
||||
{headerContent}
|
||||
<a href={headerUrl} target={headerTarget} onClick={onHeaderClick} className={styles.header}>
|
||||
{headerText}
|
||||
</a>
|
||||
);
|
||||
}
|
||||
|
||||
const menuClass = css`
|
||||
flex-direction: ${reverseDirection ? 'column-reverse' : 'column'};
|
||||
`;
|
||||
|
||||
return (
|
||||
<ul className={`${menuClass} dropdown-menu dropdown-menu--sidemenu`} role="menu">
|
||||
<li className="side-menu-header">{header}</li>
|
||||
<ul className={`${styles.menu} dropdown-menu dropdown-menu--sidemenu`} role="menu">
|
||||
<li>{header}</li>
|
||||
{items
|
||||
.filter((item) => !item.hideFromMenu)
|
||||
.map((child, index) => (
|
||||
@@ -62,13 +60,59 @@ const SideMenuDropDown = ({
|
||||
url={child.url}
|
||||
/>
|
||||
))}
|
||||
{subtitleText && (
|
||||
<li className="sidemenu-subtitle">
|
||||
<span className="sidemenu-item-text">{subtitleText}</span>
|
||||
</li>
|
||||
)}
|
||||
{subtitleText && <li className={styles.subtitle}>{subtitleText}</li>}
|
||||
</ul>
|
||||
);
|
||||
};
|
||||
|
||||
export default SideMenuDropDown;
|
||||
|
||||
const getStyles = (theme: GrafanaTheme2, reverseDirection: Props['reverseDirection']) => ({
|
||||
header: css`
|
||||
background-color: ${theme.colors.background.secondary};
|
||||
border: none;
|
||||
color: ${theme.colors.text.primary};
|
||||
font-size: ${theme.typography.h4.fontSize};
|
||||
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 {
|
||||
background-color: ${theme.colors.action.hover};
|
||||
}
|
||||
|
||||
.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`
|
||||
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;
|
||||
}
|
||||
`,
|
||||
});
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import React, { ReactNode } from 'react';
|
||||
import { css, cx } from '@emotion/css';
|
||||
import { GrafanaTheme2, NavModelItem } from '@grafana/data';
|
||||
import { Link, styleMixins, useTheme2 } from '@grafana/ui';
|
||||
import SideMenuDropDown from './SideMenuDropDown';
|
||||
import { Link } from '@grafana/ui';
|
||||
import { NavModelItem } from '@grafana/data';
|
||||
import { cx } from '@emotion/css';
|
||||
|
||||
export interface Props {
|
||||
children: ReactNode;
|
||||
@@ -25,9 +25,11 @@ const SideMenuItem = ({
|
||||
target,
|
||||
url,
|
||||
}: Props) => {
|
||||
const theme = useTheme2();
|
||||
const styles = getStyles(theme);
|
||||
let element = (
|
||||
<button className="sidemenu-link" onClick={onClick} aria-label={label}>
|
||||
<span className="icon-circle sidemenu-icon">{children}</span>
|
||||
<button className={styles.element} onClick={onClick} aria-label={label}>
|
||||
<span className={styles.icon}>{children}</span>
|
||||
</button>
|
||||
);
|
||||
|
||||
@@ -35,24 +37,24 @@ const SideMenuItem = ({
|
||||
element =
|
||||
!target && url.startsWith('/') ? (
|
||||
<Link
|
||||
className="sidemenu-link"
|
||||
className={styles.element}
|
||||
href={url}
|
||||
target={target}
|
||||
aria-label={label}
|
||||
onClick={onClick}
|
||||
aria-haspopup="true"
|
||||
>
|
||||
<span className="icon-circle sidemenu-icon">{children}</span>
|
||||
<span className={styles.icon}>{children}</span>
|
||||
</Link>
|
||||
) : (
|
||||
<a href={url} target={target} className="sidemenu-link" onClick={onClick} aria-label={label}>
|
||||
<span className="icon-circle sidemenu-icon">{children}</span>
|
||||
<a href={url} target={target} className={styles.element} onClick={onClick} aria-label={label}>
|
||||
<span className={styles.icon}>{children}</span>
|
||||
</a>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={cx('sidemenu-item', 'dropdown', { dropup: reverseMenuDirection })}>
|
||||
<div className={cx(styles.container, 'dropdown', { dropup: reverseMenuDirection })}>
|
||||
{element}
|
||||
<SideMenuDropDown
|
||||
headerTarget={target}
|
||||
@@ -68,3 +70,76 @@ const SideMenuItem = ({
|
||||
};
|
||||
|
||||
export default SideMenuItem;
|
||||
|
||||
const getStyles = (theme: GrafanaTheme2) => ({
|
||||
container: css`
|
||||
position: relative;
|
||||
|
||||
@keyframes dropdown-anim {
|
||||
0% {
|
||||
opacity: 0;
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@media ${styleMixins.mediaUp(`${theme.breakpoints.values.md}px`)} {
|
||||
// needs to be in here to work on safari...
|
||||
&:not(:hover) {
|
||||
border-left: 2px solid transparent;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: ${theme.colors.action.hover};
|
||||
border-image: ${theme.colors.gradients.brandVertical};
|
||||
border-image-slice: 1;
|
||||
border-style: solid;
|
||||
border-top: 0;
|
||||
border-right: 0;
|
||||
border-bottom: 0;
|
||||
border-left-width: 2px;
|
||||
|
||||
.dropdown-menu {
|
||||
animation: dropdown-anim 150ms ease-in-out 100ms forwards;
|
||||
border: none;
|
||||
display: flex;
|
||||
// important to overlap it otherwise it can be hidden
|
||||
// again by the mouse getting outside the hover space
|
||||
left: ${theme.components.sidemenu.width - 3}px;
|
||||
margin: 0;
|
||||
opacity: 0;
|
||||
top: 0;
|
||||
z-index: ${theme.zIndex.sidemenu};
|
||||
}
|
||||
|
||||
&.dropup .dropdown-menu {
|
||||
top: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
element: css`
|
||||
background-color: transparent;
|
||||
border: 1px solid transparent;
|
||||
color: ${theme.colors.text.secondary};
|
||||
display: block;
|
||||
line-height: 42px;
|
||||
text-align: center;
|
||||
width: ${theme.components.sidemenu.width - 2}px;
|
||||
|
||||
.sidemenu-open--xs & {
|
||||
display: none;
|
||||
}
|
||||
`,
|
||||
icon: css`
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
|
||||
img {
|
||||
border-radius: 50%;
|
||||
height: 28px;
|
||||
width: 28px;
|
||||
}
|
||||
`,
|
||||
});
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
import React from 'react';
|
||||
import { cloneDeep } from 'lodash';
|
||||
import { css } from '@emotion/css';
|
||||
import { GrafanaTheme2, NavModelItem } from '@grafana/data';
|
||||
import { locationService } from '@grafana/runtime';
|
||||
import { Icon, IconName } from '@grafana/ui';
|
||||
import SideMenuItem from './SideMenuItem';
|
||||
import { Icon, IconName, styleMixins, useTheme2 } from '@grafana/ui';
|
||||
import config from '../../config';
|
||||
import { NavModelItem } from '@grafana/data';
|
||||
import SideMenuItem from './SideMenuItem';
|
||||
|
||||
const TopSection = () => {
|
||||
const theme = useTheme2();
|
||||
const styles = getStyles(theme);
|
||||
const navTree: NavModelItem[] = cloneDeep(config.bootData.navTree);
|
||||
const mainLinks = navTree.filter((item) => !item.hideFromMenu);
|
||||
|
||||
@@ -15,7 +18,7 @@ const TopSection = () => {
|
||||
};
|
||||
|
||||
return (
|
||||
<div data-testid="top-section-items" className="sidemenu__top">
|
||||
<div data-testid="top-section-items" className={styles.container}>
|
||||
<SideMenuItem label="Search dashboards" onClick={onOpenSearch}>
|
||||
<Icon name="search" size="xl" />
|
||||
</SideMenuItem>
|
||||
@@ -38,3 +41,19 @@ const TopSection = () => {
|
||||
};
|
||||
|
||||
export default TopSection;
|
||||
|
||||
const getStyles = (theme: GrafanaTheme2) => ({
|
||||
container: css`
|
||||
display: none;
|
||||
flex-grow: 1;
|
||||
|
||||
@media ${styleMixins.mediaUp(`${theme.breakpoints.values.md}px`)} {
|
||||
display: block;
|
||||
margin-top: ${theme.spacing(5)};
|
||||
}
|
||||
|
||||
.sidemenu-open--xs & {
|
||||
display: block;
|
||||
}
|
||||
`,
|
||||
});
|
||||
|
||||
@@ -54,7 +54,6 @@
|
||||
@import 'components/tables_lists';
|
||||
@import 'components/search';
|
||||
@import 'components/gf-form';
|
||||
@import 'components/sidemenu';
|
||||
@import 'components/navbar';
|
||||
@import 'components/filter-controls';
|
||||
@import 'components/filter-list';
|
||||
|
||||
@@ -124,15 +124,6 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&--sidemenu {
|
||||
li.sidemenu-org-switcher {
|
||||
> a,
|
||||
> button {
|
||||
padding: 8px 10px 8px 15px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.dropdown-item-text {
|
||||
|
||||
@@ -1,283 +0,0 @@
|
||||
$mobile-menu-breakpoint: md;
|
||||
|
||||
.sidemenu {
|
||||
position: fixed;
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
flex-direction: column;
|
||||
width: $side-menu-width;
|
||||
z-index: $zindex-sidemenu;
|
||||
border-right: $panel-border;
|
||||
|
||||
a:focus {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.sidemenu__logo_small_breakpoint {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.sidemenu__close {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@include media-breakpoint-up($mobile-menu-breakpoint) {
|
||||
background: $side-menu-bg;
|
||||
height: auto;
|
||||
position: relative;
|
||||
z-index: $zindex-sidemenu;
|
||||
}
|
||||
}
|
||||
|
||||
// body class that hides sidemenu
|
||||
.sidemenu-hidden {
|
||||
.sidemenu {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.sidemenu__top {
|
||||
padding-top: 40px;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.sidemenu__bottom {
|
||||
padding-bottom: $spacer;
|
||||
}
|
||||
|
||||
.sidemenu__top,
|
||||
.sidemenu__bottom {
|
||||
display: none;
|
||||
|
||||
@include media-breakpoint-up($mobile-menu-breakpoint) {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.sidemenu-item {
|
||||
position: relative;
|
||||
@include left-brand-border();
|
||||
|
||||
@include media-breakpoint-up($mobile-menu-breakpoint) {
|
||||
&.active,
|
||||
&:hover {
|
||||
background-color: $side-menu-item-hover-bg;
|
||||
@include left-brand-border-gradient();
|
||||
|
||||
.dropdown-menu {
|
||||
border: none;
|
||||
margin: 0;
|
||||
display: flex;
|
||||
opacity: 0;
|
||||
top: 0px;
|
||||
// important to overlap it otherwise it can be hidden
|
||||
// again by the mouse getting outside the hover space
|
||||
left: $side-menu-width - 3px;
|
||||
@include animation('dropdown-anim 150ms ease-in-out 100ms forwards');
|
||||
z-index: $zindex-sidemenu;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.dropup.sidemenu-item:hover .dropdown-menu {
|
||||
top: auto !important;
|
||||
}
|
||||
|
||||
.sidemenu-link {
|
||||
background-color: transparent;
|
||||
color: $side-menu-icon-color !important;
|
||||
line-height: 42px;
|
||||
padding: 0px 10px 0px 10px;
|
||||
display: block;
|
||||
position: relative;
|
||||
font-size: 16px;
|
||||
border: 1px solid transparent;
|
||||
text-align: center;
|
||||
|
||||
img {
|
||||
border-radius: 50%;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
}
|
||||
}
|
||||
|
||||
@include keyframes(dropdown-anim) {
|
||||
0% {
|
||||
opacity: 0;
|
||||
//transform: translate3d(-5%,0,0);
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
//transform: translate3d(0,0,0);
|
||||
}
|
||||
}
|
||||
|
||||
.icon-circle {
|
||||
width: 35px;
|
||||
height: 35px;
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
|
||||
img {
|
||||
position: relative;
|
||||
}
|
||||
}
|
||||
|
||||
.side-menu-header {
|
||||
padding: 10px 10px 10px 20px;
|
||||
white-space: nowrap;
|
||||
background-color: $side-menu-item-hover-bg;
|
||||
font-size: 17px;
|
||||
color: $side-menu-header-color;
|
||||
}
|
||||
|
||||
.side-menu-header-link {
|
||||
background-color: transparent;
|
||||
border: none !important;
|
||||
color: $side-menu-header-color !important;
|
||||
font-size: inherit;
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
.dropdown-menu--sidemenu > li > .side-menu-header-link:hover {
|
||||
color: #fff !important;
|
||||
background-color: $side-menu-item-hover-bg !important;
|
||||
}
|
||||
|
||||
.sidemenu-subtitle {
|
||||
padding: $space-sm $space-md $space-sm;
|
||||
font-size: $font-size-sm;
|
||||
color: $text-color-weak;
|
||||
border-bottom: 1px solid $dropdownDividerBottom;
|
||||
margin-bottom: $space-xs;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
li.sidemenu-org-switcher {
|
||||
border-bottom: 1px solid $dropdownDividerBottom;
|
||||
}
|
||||
|
||||
.sidemenu-org-switcher__org-name {
|
||||
font-size: $font-size-base;
|
||||
}
|
||||
|
||||
.sidemenu-org-switcher__org-current {
|
||||
font-size: $font-size-xs;
|
||||
color: $text-color-weak;
|
||||
position: relative;
|
||||
top: -2px;
|
||||
}
|
||||
|
||||
.sidemenu-org-switcher__switch {
|
||||
font-size: $font-size-sm;
|
||||
padding-left: $space-lg;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
> i.fa.fa-random {
|
||||
margin-right: $space-xs;
|
||||
top: 1px;
|
||||
}
|
||||
}
|
||||
|
||||
.sidemenu__logo {
|
||||
display: block;
|
||||
padding: 6px 14px 6px 9px;
|
||||
min-height: $navbarHeight;
|
||||
position: relative;
|
||||
height: $navbarHeight - 1px;
|
||||
|
||||
&:hover {
|
||||
background: lightOrDark($gray33, $gray25);
|
||||
}
|
||||
|
||||
img {
|
||||
width: 26px;
|
||||
position: relative;
|
||||
top: 5px;
|
||||
left: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
@include media-breakpoint-down(sm) {
|
||||
.sidemenu-open--xs {
|
||||
li {
|
||||
font-size: $font-size-md;
|
||||
}
|
||||
|
||||
.sidemenu {
|
||||
width: 100%;
|
||||
background: $side-menu-bg-mobile;
|
||||
height: auto;
|
||||
box-shadow: $side-menu-shadow;
|
||||
position: absolute;
|
||||
z-index: $zindex-sidemenu;
|
||||
}
|
||||
|
||||
.sidemenu__close {
|
||||
display: block;
|
||||
font-size: $font-size-md;
|
||||
position: relative;
|
||||
top: -3px;
|
||||
}
|
||||
|
||||
.sidemenu__top,
|
||||
.sidemenu__bottom {
|
||||
display: block;
|
||||
}
|
||||
.sidemenu-item {
|
||||
border-right: 2px solid transparent;
|
||||
}
|
||||
}
|
||||
|
||||
.sidemenu {
|
||||
.sidemenu__logo {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.sidemenu__logo_small_breakpoint {
|
||||
padding: 16px 13px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
align-items: baseline;
|
||||
cursor: pointer;
|
||||
|
||||
.fa-bars {
|
||||
font-size: 25px;
|
||||
}
|
||||
}
|
||||
|
||||
.sidemenu__top {
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
.side-menu-header {
|
||||
padding-left: 10px;
|
||||
}
|
||||
|
||||
.sidemenu-link {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.dropdown-menu--sidemenu {
|
||||
display: flex;
|
||||
position: unset;
|
||||
width: 100%;
|
||||
float: none;
|
||||
margin-bottom: $space-sm;
|
||||
|
||||
> li > a,
|
||||
> li > button {
|
||||
padding-left: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
.sidemenu__bottom {
|
||||
.dropdown-menu--sidemenu {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user