From 0746e15cad5bd333e20f53d2ec47531a3fa9dedc Mon Sep 17 00:00:00 2001 From: Kyle Knight Date: Tue, 15 Nov 2016 11:17:33 -0600 Subject: [PATCH] User Menu (#478) --- .sass-lint.yml | 1 - .../SiteNavSidePanel/SiteNavSidePanel.jsx | 64 +++-- .../side_panels/SiteNavSidePanel/UserMenu.jsx | 56 +++++ .../side_panels/SiteNavSidePanel/_styles.scss | 228 ++++++++++++++---- 4 files changed, 276 insertions(+), 73 deletions(-) create mode 100644 frontend/components/side_panels/SiteNavSidePanel/UserMenu.jsx diff --git a/.sass-lint.yml b/.sass-lint.yml index d29a996687..a7c48881cd 100644 --- a/.sass-lint.yml +++ b/.sass-lint.yml @@ -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 diff --git a/frontend/components/side_panels/SiteNavSidePanel/SiteNavSidePanel.jsx b/frontend/components/side_panels/SiteNavSidePanel/SiteNavSidePanel.jsx index 1c142a64d5..a3a7091faa 100644 --- a/frontend/components/side_panels/SiteNavSidePanel/SiteNavSidePanel.jsx +++ b/frontend/components/side_panels/SiteNavSidePanel/SiteNavSidePanel.jsx @@ -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 ( -
- Company logo -

{orgName}

-
-

{username}

- +
+
); } @@ -147,17 +172,14 @@ class SiteNavSidePanel extends Component { onClick={setActiveTab(navItem)} style={{ width: '100%' }} > - {active &&
}
  • -
    - - - {name} - -
    + + + {name} +
  • {active && renderSubItems(subItems)} diff --git a/frontend/components/side_panels/SiteNavSidePanel/UserMenu.jsx b/frontend/components/side_panels/SiteNavSidePanel/UserMenu.jsx new file mode 100644 index 0000000000..9b1b0423b6 --- /dev/null +++ b/frontend/components/side_panels/SiteNavSidePanel/UserMenu.jsx @@ -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 ( +
    + User Avatar + +

    { name }

    +

    { position }

    + + +
    + ); + } +} + +export default UserMenu; diff --git a/frontend/components/side_panels/SiteNavSidePanel/_styles.scss b/frontend/components/side_panels/SiteNavSidePanel/_styles.scss index ca8241ac85..91062a6d9e 100644 --- a/frontend/components/side_panels/SiteNavSidePanel/_styles.scss +++ b/frontend/components/side_panels/SiteNavSidePanel/_styles.scss @@ -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;