From e66f11134854649d1a7afe0653cefc24f8537a3c Mon Sep 17 00:00:00 2001 From: Robin Ward <robin.ward@gmail.com> Date: Wed, 26 Aug 2015 14:42:42 -0400 Subject: [PATCH] UX: Use dropdown for hamburger on wide screens, full height on smaller --- .../components/hamburger-menu.js.es6 | 59 ++++++++++++++++--- .../templates/components/hamburger-menu.hbs | 11 ++-- .../discourse/templates/header.hbs | 2 +- .../javascripts/discourse/views/header.js.es6 | 6 +- .../stylesheets/common/base/hamburger.scss | 41 +++++++------ .../acceptance/hamburger-menu-test.js.es6 | 16 +---- 6 files changed, 90 insertions(+), 45 deletions(-) diff --git a/app/assets/javascripts/discourse/components/hamburger-menu.js.es6 b/app/assets/javascripts/discourse/components/hamburger-menu.js.es6 index 3c9a13fef..e7066dbc8 100644 --- a/app/assets/javascripts/discourse/components/hamburger-menu.js.es6 +++ b/app/assets/javascripts/discourse/components/hamburger-menu.js.es6 @@ -2,19 +2,56 @@ import { default as computed, on, observes } from 'ember-addons/ember-computed-d export default Ember.Component.extend({ - classNameBindings: ['visible::slideright'], + classNameBindings: ['visible::hidden', 'viewMode'], + attributeBindings: ['style'], elementId: 'hamburger-menu', + viewMode: 'dropDown', + + showClose: Ember.computed.equal('viewMode', 'slide-in'), + + @computed('viewMode') + style(viewMode) { + if (viewMode === 'drop-down') { + const $buttonPanel = $('header ul.icons'); + + const buttonPanelPos = $buttonPanel.offset(); + const myWidth = this.$().width(); + + const posTop = parseInt(buttonPanelPos.top + $buttonPanel.height()); + const posLeft = parseInt(buttonPanelPos.left + $buttonPanel.width() - myWidth); + + return `left: ${posLeft}px; top: ${posTop}px`.htmlSafe(); + } + }, + + @computed('viewMode') + bodyStyle(viewMode) { + if (viewMode === 'drop-down') { + const height = parseInt($(window).height() * 0.8) + return `height: ${height}px`.htmlSafe(); + } + }, @observes('visible') - _catchClickOutside() { + _visibleChanged() { if (this.get('visible')) { + $('.hamburger-dropdown').addClass('active'); + + if ($(window).width() < 1024) { + this.set('viewMode', 'slide-in'); + } else { + this.set('viewMode', 'drop-down'); + } + $('html').on('click.close-hamburger', (e) => { const $target = $(e.target); - if ($target.closest('.dropdown.hamburger').length > 0) { return; } + if ($target.closest('.hamburger-dropdown').length > 0) { return; } if ($target.closest('#hamburger-menu').length > 0) { return; } - this.set('visible', false); + this.hide(); }); + } else { + $('.hamburger-dropdown').removeClass('active'); $('html').off('click.close-hamburger'); } }, @@ -42,19 +79,21 @@ export default Ember.Component.extend({ @on('didInsertElement') _bindEvents() { this.$().on('click.discourse-hamburger', 'a', () => { - this.set('visible', false); + this.hide(); }); + this.appEvents.on('dropdowns:closeAll', this, this.hide); + $('body').on('keydown.discourse-hambuger', (e) => { if (e.which === 27) { - this.set('visible', false); + this.hide(); } }); - }, @on('willDestroyElement') _removeEvents() { + this.appEvents.off('dropdowns:closeAll', this, this.hide); this.$().off('click.discourse-hamburger'); $('body').off('keydown.discourse-hambuger'); $('html').off('click.close-hamburger'); @@ -73,9 +112,13 @@ export default Ember.Component.extend({ }); }, + hide() { + this.set('visible', false); + }, + actions: { close() { - this.set('visible', false); + this.hide(); }, keyboardShortcuts() { this.sendAction('showKeyboardAction'); diff --git a/app/assets/javascripts/discourse/templates/components/hamburger-menu.hbs b/app/assets/javascripts/discourse/templates/components/hamburger-menu.hbs index 7cef85af9..474e3a3cd 100644 --- a/app/assets/javascripts/discourse/templates/components/hamburger-menu.hbs +++ b/app/assets/javascripts/discourse/templates/components/hamburger-menu.hbs @@ -1,8 +1,11 @@ {{#if visible}} - <div class='hamburger-header clearfix'> - <a href {{action "close"}} class='close-hamburger'>{{fa-icon 'times'}}</a> - </div> - <div class='hamburger-body'> + {{#if showClose}} + <div class='hamburger-header clearfix'> + <a href {{action "close"}} class='close-hamburger'>{{fa-icon 'times'}}</a> + </div> + {{/if}} + + <div class='hamburger-body' style={{bodyStyle}}> <ul class="location-links"> {{#if currentUser.staff}} <li> diff --git a/app/assets/javascripts/discourse/templates/header.hbs b/app/assets/javascripts/discourse/templates/header.hbs index 6c7a40313..6d833d3f3 100644 --- a/app/assets/javascripts/discourse/templates/header.hbs +++ b/app/assets/javascripts/discourse/templates/header.hbs @@ -42,7 +42,7 @@ </a> {{/if}} </li> - <li class='hamburger categories dropdown'> + <li class='hamburger-dropdown'> {{#if loginRequired}} <a class='icon' href diff --git a/app/assets/javascripts/discourse/views/header.js.es6 b/app/assets/javascripts/discourse/views/header.js.es6 index 310a06604..2251fe080 100644 --- a/app/assets/javascripts/discourse/views/header.js.es6 +++ b/app/assets/javascripts/discourse/views/header.js.es6 @@ -7,9 +7,11 @@ export default Ember.View.extend({ templateName: 'header', renderDropdowns: false, - showDropdown: function($target) { + showDropdown($target) { var self = this; + this.appEvents.trigger('dropdowns:closeAll'); + if (!this.get("renderDropdowns")) { this.set("renderDropdowns", true); Em.run.next(function(){ @@ -138,7 +140,7 @@ export default Ember.View.extend({ const self = this; this.$('a[data-dropdown]').on('click.dropdown', function(e) { - self.showDropdown.apply(self, [$(e.currentTarget)]); + self.showDropdown.call(self, $(e.currentTarget)); return false; }); this.$().on('click.notifications','a.unread-private-messages, a.unread-notifications, a[data-notifications]', function(e) { diff --git a/app/assets/stylesheets/common/base/hamburger.scss b/app/assets/stylesheets/common/base/hamburger.scss index 8fb4a2f13..c42b094c7 100644 --- a/app/assets/stylesheets/common/base/hamburger.scss +++ b/app/assets/stylesheets/common/base/hamburger.scss @@ -1,15 +1,27 @@ -#hamburger-menu { +#hamburger-menu.slide-in { position: fixed; right: 0; top: 0; - background-color: $secondary; - z-index: 1002; height: 100%; - overflow: none; - transition: 0.3s ease-in-out; - @include transform(translateX(0)); - box-shadow: 0 4px 4px 4px rgba(0,0,0, .25); + + .hamburger-body { + position: absolute; + top: 40px; + bottom: 37px; + } +} + +#hamburger-menu.drop-down { + border: 1px solid dark-light-diff($primary, $secondary, 90%, -60%); + box-shadow: 0 2px 2px rgba(0,0,0, .25); + position: absolute; +} + +#hamburger-menu { + background-color: $secondary; + z-index: 1100; + overflow: none; padding: 0.5em 0.5em 0.5em 0.5em; width: 300px; @@ -28,13 +40,6 @@ right: 20px; } - .hamburger-body { - overflow-y: auto; - overflow-x: hidden; - position: absolute; - top: 40px; - bottom: 37px; - } ul { @@ -73,8 +78,10 @@ font-weight: normal; font-size: 11px; } + + .hamburger-body { + overflow-y: auto; + overflow-x: hidden; + } } -#hamburger-menu.slideright { - @include transform(translateX(330px)); -} diff --git a/test/javascripts/acceptance/hamburger-menu-test.js.es6 b/test/javascripts/acceptance/hamburger-menu-test.js.es6 index 312cab6e3..0b135767f 100644 --- a/test/javascripts/acceptance/hamburger-menu-test.js.es6 +++ b/test/javascripts/acceptance/hamburger-menu-test.js.es6 @@ -5,27 +5,17 @@ acceptance("Hamburger Menu"); test("Toggle Menu", (assert) => { visit("/"); andThen(() => { - assert.ok(exists("#hamburger-menu.slideright"), "hidden by default"); + assert.ok(exists("#hamburger-menu.hidden"), "hidden by default"); }); click("#toggle-hamburger-menu"); andThen(() => { - assert.ok(!exists("#hamburger-menu.slideright"), "a click makes it appear"); - }); - - click(".close-hamburger"); - andThen(() => { - assert.ok(exists("#hamburger-menu.slideright"), "clicking the X hides it"); - }); - - click("#toggle-hamburger-menu"); - andThen(() => { - assert.ok(!exists("#hamburger-menu.slideright"), "it opens again"); + assert.ok(!exists("#hamburger-menu.hidden"), "a click makes it appear"); }); click('#main-outlet') andThen(() => { - assert.ok(exists("#hamburger-menu.slideright"), "clicking the body hides the menu"); + assert.ok(exists("#hamburger-menu.hidden"), "clicking the body hides the menu"); }); });