UX: Use dropdown for hamburger on wide screens, full height on smaller
This commit is contained in:
parent
9760369e4c
commit
e66f111348
|
@ -2,19 +2,56 @@ import { default as computed, on, observes } from 'ember-addons/ember-computed-d
|
||||||
|
|
||||||
|
|
||||||
export default Ember.Component.extend({
|
export default Ember.Component.extend({
|
||||||
classNameBindings: ['visible::slideright'],
|
classNameBindings: ['visible::hidden', 'viewMode'],
|
||||||
|
attributeBindings: ['style'],
|
||||||
elementId: 'hamburger-menu',
|
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')
|
@observes('visible')
|
||||||
_catchClickOutside() {
|
_visibleChanged() {
|
||||||
if (this.get('visible')) {
|
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) => {
|
$('html').on('click.close-hamburger', (e) => {
|
||||||
const $target = $(e.target);
|
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; }
|
if ($target.closest('#hamburger-menu').length > 0) { return; }
|
||||||
this.set('visible', false);
|
this.hide();
|
||||||
});
|
});
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
$('.hamburger-dropdown').removeClass('active');
|
||||||
$('html').off('click.close-hamburger');
|
$('html').off('click.close-hamburger');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -42,19 +79,21 @@ export default Ember.Component.extend({
|
||||||
@on('didInsertElement')
|
@on('didInsertElement')
|
||||||
_bindEvents() {
|
_bindEvents() {
|
||||||
this.$().on('click.discourse-hamburger', 'a', () => {
|
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) => {
|
$('body').on('keydown.discourse-hambuger', (e) => {
|
||||||
if (e.which === 27) {
|
if (e.which === 27) {
|
||||||
this.set('visible', false);
|
this.hide();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
@on('willDestroyElement')
|
@on('willDestroyElement')
|
||||||
_removeEvents() {
|
_removeEvents() {
|
||||||
|
this.appEvents.off('dropdowns:closeAll', this, this.hide);
|
||||||
this.$().off('click.discourse-hamburger');
|
this.$().off('click.discourse-hamburger');
|
||||||
$('body').off('keydown.discourse-hambuger');
|
$('body').off('keydown.discourse-hambuger');
|
||||||
$('html').off('click.close-hamburger');
|
$('html').off('click.close-hamburger');
|
||||||
|
@ -73,9 +112,13 @@ export default Ember.Component.extend({
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
hide() {
|
||||||
|
this.set('visible', false);
|
||||||
|
},
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
close() {
|
close() {
|
||||||
this.set('visible', false);
|
this.hide();
|
||||||
},
|
},
|
||||||
keyboardShortcuts() {
|
keyboardShortcuts() {
|
||||||
this.sendAction('showKeyboardAction');
|
this.sendAction('showKeyboardAction');
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
{{#if visible}}
|
{{#if visible}}
|
||||||
<div class='hamburger-header clearfix'>
|
{{#if showClose}}
|
||||||
<a href {{action "close"}} class='close-hamburger'>{{fa-icon 'times'}}</a>
|
<div class='hamburger-header clearfix'>
|
||||||
</div>
|
<a href {{action "close"}} class='close-hamburger'>{{fa-icon 'times'}}</a>
|
||||||
<div class='hamburger-body'>
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
<div class='hamburger-body' style={{bodyStyle}}>
|
||||||
<ul class="location-links">
|
<ul class="location-links">
|
||||||
{{#if currentUser.staff}}
|
{{#if currentUser.staff}}
|
||||||
<li>
|
<li>
|
||||||
|
|
|
@ -42,7 +42,7 @@
|
||||||
</a>
|
</a>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</li>
|
</li>
|
||||||
<li class='hamburger categories dropdown'>
|
<li class='hamburger-dropdown'>
|
||||||
{{#if loginRequired}}
|
{{#if loginRequired}}
|
||||||
<a class='icon'
|
<a class='icon'
|
||||||
href
|
href
|
||||||
|
|
|
@ -7,9 +7,11 @@ export default Ember.View.extend({
|
||||||
templateName: 'header',
|
templateName: 'header',
|
||||||
renderDropdowns: false,
|
renderDropdowns: false,
|
||||||
|
|
||||||
showDropdown: function($target) {
|
showDropdown($target) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
|
this.appEvents.trigger('dropdowns:closeAll');
|
||||||
|
|
||||||
if (!this.get("renderDropdowns")) {
|
if (!this.get("renderDropdowns")) {
|
||||||
this.set("renderDropdowns", true);
|
this.set("renderDropdowns", true);
|
||||||
Em.run.next(function(){
|
Em.run.next(function(){
|
||||||
|
@ -138,7 +140,7 @@ export default Ember.View.extend({
|
||||||
const self = this;
|
const self = this;
|
||||||
|
|
||||||
this.$('a[data-dropdown]').on('click.dropdown', function(e) {
|
this.$('a[data-dropdown]').on('click.dropdown', function(e) {
|
||||||
self.showDropdown.apply(self, [$(e.currentTarget)]);
|
self.showDropdown.call(self, $(e.currentTarget));
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
this.$().on('click.notifications','a.unread-private-messages, a.unread-notifications, a[data-notifications]', function(e) {
|
this.$().on('click.notifications','a.unread-private-messages, a.unread-notifications, a[data-notifications]', function(e) {
|
||||||
|
|
|
@ -1,15 +1,27 @@
|
||||||
#hamburger-menu {
|
#hamburger-menu.slide-in {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
right: 0;
|
right: 0;
|
||||||
top: 0;
|
top: 0;
|
||||||
background-color: $secondary;
|
|
||||||
z-index: 1002;
|
|
||||||
height: 100%;
|
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);
|
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;
|
padding: 0.5em 0.5em 0.5em 0.5em;
|
||||||
width: 300px;
|
width: 300px;
|
||||||
|
|
||||||
|
@ -28,13 +40,6 @@
|
||||||
right: 20px;
|
right: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.hamburger-body {
|
|
||||||
overflow-y: auto;
|
|
||||||
overflow-x: hidden;
|
|
||||||
position: absolute;
|
|
||||||
top: 40px;
|
|
||||||
bottom: 37px;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
ul {
|
ul {
|
||||||
|
@ -73,8 +78,10 @@
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.hamburger-body {
|
||||||
|
overflow-y: auto;
|
||||||
|
overflow-x: hidden;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#hamburger-menu.slideright {
|
|
||||||
@include transform(translateX(330px));
|
|
||||||
}
|
|
||||||
|
|
|
@ -5,27 +5,17 @@ acceptance("Hamburger Menu");
|
||||||
test("Toggle Menu", (assert) => {
|
test("Toggle Menu", (assert) => {
|
||||||
visit("/");
|
visit("/");
|
||||||
andThen(() => {
|
andThen(() => {
|
||||||
assert.ok(exists("#hamburger-menu.slideright"), "hidden by default");
|
assert.ok(exists("#hamburger-menu.hidden"), "hidden by default");
|
||||||
});
|
});
|
||||||
|
|
||||||
click("#toggle-hamburger-menu");
|
click("#toggle-hamburger-menu");
|
||||||
andThen(() => {
|
andThen(() => {
|
||||||
assert.ok(!exists("#hamburger-menu.slideright"), "a click makes it appear");
|
assert.ok(!exists("#hamburger-menu.hidden"), "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");
|
|
||||||
});
|
});
|
||||||
|
|
||||||
click('#main-outlet')
|
click('#main-outlet')
|
||||||
andThen(() => {
|
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");
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue