User Menu (#478)
This commit is contained in:
@@ -3,7 +3,6 @@ files:
|
||||
include: 'frontend/**/*.s+(a|c)ss'
|
||||
ignore:
|
||||
- 'frontend/styles/_fonts.scss'
|
||||
- 'frontend/styles/_icons.scss'
|
||||
options:
|
||||
formatter: stylish
|
||||
merge-default-rules: false
|
||||
|
||||
@@ -8,6 +8,7 @@ import { activeTabFromPathname, activeSubTabFromPathname } from './helpers';
|
||||
import configInterface from '../../../interfaces/config';
|
||||
import kolideLogo from '../../../../assets/images/kolide-logo.svg';
|
||||
import navItems from './navItems';
|
||||
import UserMenu from './UserMenu';
|
||||
import userInterface from '../../../interfaces/user';
|
||||
|
||||
class SiteNavSidePanel extends Component {
|
||||
@@ -32,6 +33,7 @@ class SiteNavSidePanel extends Component {
|
||||
activeTab,
|
||||
activeSubItem,
|
||||
showSubItems: false,
|
||||
userMenuOpened: false,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -94,35 +96,58 @@ class SiteNavSidePanel extends Component {
|
||||
};
|
||||
}
|
||||
|
||||
toggleUserMenu = () => {
|
||||
const { userMenuOpened } = this.state;
|
||||
|
||||
this.setState({ userMenuOpened: !userMenuOpened });
|
||||
}
|
||||
|
||||
renderHeader = () => {
|
||||
const {
|
||||
config: {
|
||||
org_name: orgName,
|
||||
},
|
||||
user: {
|
||||
enabled,
|
||||
username,
|
||||
},
|
||||
user,
|
||||
} = this.props;
|
||||
|
||||
const { userMenuOpened } = this.state;
|
||||
const { toggleUserMenu } = this;
|
||||
const { enabled, username } = user;
|
||||
|
||||
const headerBaseClass = 'site-nav-header';
|
||||
|
||||
const headerToggleClass = classnames(
|
||||
headerBaseClass,
|
||||
'button',
|
||||
'button--unstyled',
|
||||
{ [`${headerBaseClass}--open`]: userMenuOpened }
|
||||
);
|
||||
|
||||
const userStatusClass = classnames(
|
||||
`${headerBaseClass}__user-status`,
|
||||
{ [`${headerBaseClass}__user-status--enabled`]: enabled }
|
||||
);
|
||||
|
||||
return (
|
||||
<header className={headerBaseClass}>
|
||||
<img
|
||||
alt="Company logo"
|
||||
src={kolideLogo}
|
||||
className={`${headerBaseClass}__logo`}
|
||||
/>
|
||||
<h1 className={`${headerBaseClass}__org-name`}>{orgName}</h1>
|
||||
<div className={userStatusClass} />
|
||||
<h2 className={`${headerBaseClass}__username`}>{username}</h2>
|
||||
<i className={`${headerBaseClass}__org-chevron kolidecon-chevrondownbold`} />
|
||||
<header>
|
||||
<button className={headerToggleClass} onClick={toggleUserMenu}>
|
||||
<div className={`${headerBaseClass}__org`}>
|
||||
<img
|
||||
alt="Company logo"
|
||||
src={kolideLogo}
|
||||
className={`${headerBaseClass}__logo`}
|
||||
/>
|
||||
<h1 className={`${headerBaseClass}__org-name`}>{orgName}</h1>
|
||||
<div className={userStatusClass} />
|
||||
<h2 className={`${headerBaseClass}__username`}>{username}</h2>
|
||||
<i className={`${headerBaseClass}__org-chevron kolidecon-chevrondown`} />
|
||||
</div>
|
||||
|
||||
<UserMenu
|
||||
user={user}
|
||||
isOpened={userMenuOpened}
|
||||
/>
|
||||
</button>
|
||||
</header>
|
||||
);
|
||||
}
|
||||
@@ -147,17 +172,14 @@ class SiteNavSidePanel extends Component {
|
||||
onClick={setActiveTab(navItem)}
|
||||
style={{ width: '100%' }}
|
||||
>
|
||||
{active && <div className={`${navItemBaseClass}__active-nav`} />}
|
||||
<li
|
||||
key={name}
|
||||
className={navItemClasses}
|
||||
>
|
||||
<div style={{ position: 'relative', textAlign: 'left' }}>
|
||||
<i className={`${navItemBaseClass}__icon ${icon}`} />
|
||||
<span className={`${navItemBaseClass}__name`}>
|
||||
{name}
|
||||
</span>
|
||||
</div>
|
||||
<i className={`${navItemBaseClass}__icon ${icon}`} />
|
||||
<span className={`${navItemBaseClass}__name`}>
|
||||
{name}
|
||||
</span>
|
||||
</li>
|
||||
</button>
|
||||
{active && renderSubItems(subItems)}
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
import React, { Component, PropTypes } from 'react';
|
||||
import classnames from 'classnames';
|
||||
|
||||
class UserMenu extends Component {
|
||||
static propTypes = {
|
||||
isOpened: PropTypes.bool,
|
||||
user: PropTypes.shape({
|
||||
gravatarURL: PropTypes.string,
|
||||
name: PropTypes.string,
|
||||
position: PropTypes.string,
|
||||
}).isRequired,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
isOpened: false,
|
||||
};
|
||||
|
||||
render () {
|
||||
const {
|
||||
isOpened,
|
||||
user: {
|
||||
gravatarURL,
|
||||
name,
|
||||
position,
|
||||
},
|
||||
} = this.props;
|
||||
|
||||
const toggleBaseClass = 'user-menu-toggle';
|
||||
const userMenuClass = classnames(
|
||||
toggleBaseClass,
|
||||
{ [`${toggleBaseClass}--open`]: isOpened }
|
||||
);
|
||||
|
||||
return (
|
||||
<div className={userMenuClass}>
|
||||
<img
|
||||
alt="User Avatar"
|
||||
src={gravatarURL}
|
||||
className={`${toggleBaseClass}__avatar`}
|
||||
/>
|
||||
|
||||
<p className={`${toggleBaseClass}__name`}>{ name }</p>
|
||||
<p className={`${toggleBaseClass}__position`}>{ position }</p>
|
||||
|
||||
<nav className={`${toggleBaseClass}__nav`}>
|
||||
<ul className={`${toggleBaseClass}__nav-list`}>
|
||||
<li className={`${toggleBaseClass}__nav-item`}><a href="#user-settings"><i className="kolidecon-user-settings" /><span>Account Settings</span></a></li>
|
||||
<li className={`${toggleBaseClass}__nav-item`}><a href="#logout"><i className="kolidecon-logout" /><span>Log Out</span></a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default UserMenu;
|
||||
@@ -1,35 +1,51 @@
|
||||
.site-nav-header {
|
||||
border-bottom: 1px solid $accent-light;
|
||||
height: 62px;
|
||||
@include transition(background 150ms $ease-in-quad);
|
||||
cursor: pointer;
|
||||
padding-left: 54px;
|
||||
padding-top: 26px;
|
||||
margin-right: 16px;
|
||||
padding: $pad-large $pad-medium 0;
|
||||
position: relative;
|
||||
display: block;
|
||||
width: 100%;
|
||||
color: $text-ultradark;
|
||||
text-align: left;
|
||||
border-radius: 0;
|
||||
|
||||
&:hover {
|
||||
background: $bg-medium;
|
||||
}
|
||||
|
||||
@media (max-width: 760px) {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
&__org {
|
||||
@include transition(border 150ms $ease-in-quad);
|
||||
@include clearfix;
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
border-bottom: 1px solid $accent-light;
|
||||
padding-bottom: $pad-medium;
|
||||
max-height: 100px;
|
||||
}
|
||||
|
||||
&__logo {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 23px;
|
||||
height: 42px;
|
||||
@include size(42px);
|
||||
float: left;
|
||||
margin-right: 10px;
|
||||
border: 1px solid $accent-medium;
|
||||
border-radius: 100%;
|
||||
border-radius: 50%;
|
||||
|
||||
@media (max-width: 760px) {
|
||||
left: 5px;
|
||||
margin: $pad-half 5px;
|
||||
}
|
||||
}
|
||||
|
||||
&__org-name {
|
||||
@include ellipsis(110px);
|
||||
font-size: 16px;
|
||||
letter-spacing: 0.5px;
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
padding: 0;
|
||||
position: relative;
|
||||
text-overflow: ellipsis;
|
||||
top: 1px;
|
||||
display: block;
|
||||
white-space: nowrap;
|
||||
|
||||
@media (max-width: 760px) {
|
||||
@@ -55,15 +71,14 @@
|
||||
}
|
||||
|
||||
&__username {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
@include ellipsis(110px);
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
top: -3px;
|
||||
left: 4px;
|
||||
font-size: 13px;
|
||||
letter-spacing: 0.6px;
|
||||
text-transform: uppercase;
|
||||
position: relative;
|
||||
line-height: 16px;
|
||||
|
||||
@media (max-width: 760px) {
|
||||
display: none;
|
||||
@@ -71,19 +86,128 @@
|
||||
}
|
||||
|
||||
&__org-chevron {
|
||||
@include transition(transform 150ms $ease-in-quad);
|
||||
color: $accent-medium;
|
||||
font-size: 12px;
|
||||
position: absolute;
|
||||
top: 50px;
|
||||
right: 35px;
|
||||
float: right;
|
||||
|
||||
@media (max-width: 760px) {
|
||||
top: auto;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 6px;
|
||||
float: none;
|
||||
text-align: center;
|
||||
display: block;
|
||||
clear: both;
|
||||
}
|
||||
}
|
||||
|
||||
&--open {
|
||||
background-color: $text-dark;
|
||||
|
||||
.site-nav-header__org {
|
||||
border-color: $text-ultradark;
|
||||
}
|
||||
|
||||
.site-nav-header__org-name,
|
||||
.site-nav-header__username {
|
||||
color: $white;
|
||||
}
|
||||
|
||||
.site-nav-header__org-chevron {
|
||||
@include transform(rotate(180deg));
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: $text-dark;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.user-menu-toggle {
|
||||
@include transition(opacity 150ms ease-in-out);
|
||||
height: 0;
|
||||
background-color: $text-dark;
|
||||
width: 222px;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
padding: 0;
|
||||
z-index: 2;
|
||||
overflow: hidden;
|
||||
opacity: 0;
|
||||
box-sizing: border-box;
|
||||
|
||||
@media (max-width: 760px) {
|
||||
width: 53px;
|
||||
}
|
||||
|
||||
&--open {
|
||||
height: auto;
|
||||
padding: $pad-medium 0 0;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
&__avatar {
|
||||
@include size(42px);
|
||||
float: left;
|
||||
border: solid 1px $accent-medium;
|
||||
border-radius: 50%;
|
||||
margin: 0 10px 0 $pad-medium;
|
||||
|
||||
@media (max-width: 760px) {
|
||||
margin: $pad-xsmall 5px;
|
||||
}
|
||||
}
|
||||
|
||||
&__name,
|
||||
&__position {
|
||||
@include ellipsis(135px);
|
||||
color: $white;
|
||||
font-size: $small;
|
||||
margin: 0;
|
||||
line-height: $large;
|
||||
float: left;
|
||||
|
||||
@media (max-width: 760px) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
&__nav {
|
||||
clear: both;
|
||||
padding-top: $pad-small;
|
||||
}
|
||||
|
||||
&__nav-list {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
&__nav-item {
|
||||
font-size: $small;
|
||||
text-transform: uppercase;
|
||||
|
||||
a {
|
||||
@include transition(background 150ms $ease-in-quad);
|
||||
letter-spacing: 0.5px;
|
||||
color: $white;
|
||||
display: block;
|
||||
line-height: 50px;
|
||||
text-decoration: none;
|
||||
padding: 0 $pad-medium;
|
||||
|
||||
i {
|
||||
margin-right: $pad-half;
|
||||
font-size: $large;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background: $accent-text;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 760px) {
|
||||
span {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -93,36 +217,21 @@
|
||||
|
||||
&__icon {
|
||||
position: relative;
|
||||
font-size: 22px;
|
||||
margin-right: 16px;
|
||||
top: 4px;
|
||||
left: 0;
|
||||
font-size: $large;
|
||||
margin-right: $pad-medium;
|
||||
vertical-align: middle;
|
||||
|
||||
@media (max-width: 760px) {
|
||||
display: block;
|
||||
text-align: center;
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&__active-nav {
|
||||
content: '';
|
||||
width: 6px;
|
||||
height: 50px;
|
||||
position: absolute;
|
||||
left: -16px;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
background-color: #9a61c6;
|
||||
|
||||
@media (max-width: 760px) {
|
||||
left: 0;
|
||||
line-height: 40px;
|
||||
}
|
||||
}
|
||||
|
||||
&__name {
|
||||
display: inline-block;
|
||||
text-decoration: none;
|
||||
vertical-align: middle;
|
||||
|
||||
@media (max-width: 760px) {
|
||||
display: none;
|
||||
@@ -131,14 +240,15 @@
|
||||
|
||||
&__item {
|
||||
@include transition(color 200ms ease-in-out);
|
||||
min-height: 40px;
|
||||
line-height: 40px;
|
||||
position: relative;
|
||||
color: $text-light;
|
||||
cursor: pointer;
|
||||
font-size: 13px;
|
||||
font-size: $small;
|
||||
letter-spacing: 0.5px;
|
||||
text-transform: uppercase;
|
||||
padding-top: $pad-half;
|
||||
padding: 0 $pad-medium;
|
||||
text-align: left;
|
||||
|
||||
&:hover {
|
||||
color: $text-dark;
|
||||
@@ -152,8 +262,25 @@
|
||||
color: $brand-dark;
|
||||
}
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
width: 6px;
|
||||
height: 55px;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
background-color: $brand;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
@media (max-width: 760px) {
|
||||
border-bottom: 6px solid #9a61c6;
|
||||
border-left: 6px solid #9a61c6;
|
||||
padding: 0;
|
||||
|
||||
&::before {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -289,7 +416,6 @@
|
||||
box-shadow: 2px 0 8px 0 rgba($black, 0.1);
|
||||
box-sizing: border-box;
|
||||
left: 0;
|
||||
padding-left: 16px;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
width: 223px;
|
||||
@@ -302,7 +428,7 @@
|
||||
|
||||
@media (max-width: 760px) {
|
||||
.sub-nav {
|
||||
width: 22px;
|
||||
width: 0;
|
||||
|
||||
&-expanded {
|
||||
width: 188px;
|
||||
|
||||
Reference in New Issue
Block a user