Skip to content

Commit

Permalink
Mobile fixes for tag management UI
Browse files Browse the repository at this point in the history
refs #5845, #5969
- when on mobile devices tag management UI will only display a list and when a tag is accessed the tag settings form will slide in from the right
- tag settings form header has a 'back' button when on mobile to go back to tags list
- switching from mobile to standard modes will auto load the first tag as per standard tags screen on desktop
- if no tags are present then the blank-slate template will be shown when on mobile
  • Loading branch information
kevinansfield committed Nov 2, 2015
1 parent 0c9befc commit 983c6c8
Show file tree
Hide file tree
Showing 14 changed files with 214 additions and 16 deletions.
60 changes: 60 additions & 0 deletions core/client/app/components/gh-tags-management-container.js
@@ -0,0 +1,60 @@
import Ember from 'ember';

const {isBlank} = Ember;

export default Ember.Component.extend({
classNames: ['view-container'],
classNameBindings: ['isMobile'],

mobileWidth: 600,
tags: null,
selectedTag: null,

isMobile: false,
isEmpty: Ember.computed.equal('tags.length', 0),

resizeService: Ember.inject.service('resize-service'),

_resizeListener: null,

displaySettingsPane: Ember.computed('isEmpty', 'selectedTag', 'isMobile', function () {
const isEmpty = this.get('isEmpty'),
selectedTag = this.get('selectedTag'),
isMobile = this.get('isMobile');

// always display settings pane for blank-slate on mobile
if (isMobile && isEmpty) {
return true;
}

// display list if no tag is selected on mobile
if (isMobile && isBlank(selectedTag)) {
return false;
}

// default to displaying settings pane
return true;
}),

toggleMobile: function () {
let width = Ember.$(window).width();

if (width < this.get('mobileWidth')) {
this.set('isMobile', true);
this.sendAction('enteredMobile');
} else {
this.set('isMobile', false);
this.sendAction('leftMobile');
}
},

didInitAttrs: function () {
this._resizeListener = Ember.run.bind(this, this.toggleMobile);
this.get('resizeService').on('debouncedDidResize', this._resizeListener);
this.toggleMobile();
},

willDestroyElement: function () {
this.get('resizeService').off('debouncedDidResize', this._resizeListener);
}
});
36 changes: 32 additions & 4 deletions core/client/app/controllers/settings/tags.js
@@ -1,11 +1,23 @@
import Ember from 'ember';

const {computed, inject} = Ember,
{alias, equal, sort} = computed;

export default Ember.Controller.extend({

tagListFocused: Ember.computed.equal('keyboardFocus', 'tagList'),
tagContentFocused: Ember.computed.equal('keyboardFocus', 'tagContent'),
tagController: inject.controller('settings.tags.tag'),

// set at controller level because it's shared by routes and components
mobileWidth: 600,

isMobile: false,
selectedTag: alias('tagController.tag'),

tagListFocused: equal('keyboardFocus', 'tagList'),
tagContentFocused: equal('keyboardFocus', 'tagContent'),

tags: Ember.computed.sort('model', function (a, b) {
// TODO: replace with ordering by page count once supported by the API
tags: sort('model', function (a, b) {
const idA = +a.get('id'),
idB = +b.get('id');

Expand All @@ -16,6 +28,22 @@ export default Ember.Controller.extend({
}

return 0;
})
}),

actions: {
enteredMobile: function () {
this.set('isMobile', true);
},

leftMobile: function () {
this.set('isMobile', false);

// redirect to first tag if possible so that you're not left with
// tag settings blank slate when switching from portrait to landscape
if (this.get('tags.length') && !this.get('tagController.tag')) {
this.transitionToRoute('settings.tags.tag', this.get('tags.firstObject'));
}
}
}

});
5 changes: 4 additions & 1 deletion core/client/app/controllers/settings/tags/tag.js
@@ -1,11 +1,14 @@
import Ember from 'ember';

const {computed} = Ember,
const {computed, inject} = Ember,
{alias} = computed;

export default Ember.Controller.extend({

tag: alias('model'),
isMobile: alias('tagsController.isMobile'),

tagsController: inject.controller('settings.tags'),

saveTagProperty: function (propKey, newValue) {
const tag = this.get('tag'),
Expand Down
8 changes: 6 additions & 2 deletions core/client/app/routes/settings/tags/index.js
@@ -1,11 +1,15 @@
import Ember from 'ember';
import AuthenticatedRoute from 'ghost/routes/authenticated';

export default AuthenticatedRoute.extend({

// HACK: ugly way of changing behaviour when on mobile
beforeModel: function () {
const firstTag = this.modelFor('settings.tags').get('firstObject');
const firstTag = this.modelFor('settings.tags').get('firstObject'),
mobileWidth = this.controllerFor('settings.tags').get('mobileWidth'),
viewportWidth = Ember.$(window).width();

if (firstTag) {
if (firstTag && viewportWidth > mobileWidth) {
this.transitionTo('settings.tags.tag', firstTag);
}
}
Expand Down
5 changes: 5 additions & 0 deletions core/client/app/routes/settings/tags/new.js
Expand Up @@ -10,6 +10,11 @@ export default AuthenticatedRoute.extend({

renderTemplate: function () {
this.render('settings.tags.tag');
},

// reset the model so that mobile screens react to an empty selectedTag
deactivate: function () {
this.set('controller.model', null);
}

});
5 changes: 5 additions & 0 deletions core/client/app/routes/settings/tags/tag.js
Expand Up @@ -4,6 +4,11 @@ export default AuthenticatedRoute.extend({

model: function (params) {
return this.store.findRecord('tag', params.tag_id);
},

// reset the model so that mobile screens react to an empty selectedTag
deactivate: function () {
this.set('controller.model', null);
}

});
2 changes: 1 addition & 1 deletion core/client/app/styles/layouts/flow.css
Expand Up @@ -6,7 +6,7 @@
display: flex;
flex-direction: column;
overflow-y: auto;
min-height: 100vh;
min-height: 100%;
}

.gh-flow-head {
Expand Down
13 changes: 11 additions & 2 deletions core/client/app/styles/layouts/main.css
@@ -1,20 +1,29 @@
/* Global Layout
/* ---------------------------------------------------------- */

/*
Ember's app container, set height so that .gh-app and .gh-viewport
don't need to use 100vh where bottom of screen gets covered by iOS menus
http://nicolas-hoizey.com/2015/02/viewport-height-is-taller-than-the-visible-part-of-the-document-in-some-mobile-browsers.html
*/
body > .ember-view {
height: 100%;
}

/* Main viewport, contains main content, and alerts */
.gh-app {
display: flex;
flex-direction: column;
overflow: hidden;
height: 100vh;
height: 100%;
}

/* Content viewport, contains everything else */
.gh-viewport {
flex-grow: 1;
display: flex;
overflow: hidden;
max-height: 100vh;
max-height: 100%;
}

.gh-main {
Expand Down
34 changes: 34 additions & 0 deletions core/client/app/styles/layouts/tags.css
Expand Up @@ -76,6 +76,17 @@
background: #fff;
}

@media (max-width: 600px) {
.tag-list {
max-width: 100%;
width: 100%;
}

.settings-tag .tag-edit-button.active {
border-left: none;
}
}

/* Tag Settings (Right pane)
/* ---------------------------------------------------------- */

Expand All @@ -94,6 +105,29 @@
transform: none;
}

.tag-settings .no-posts {
padding: 1em;
}

.tag-settings .no-posts h3 {
text-align: center;
}

.tag-settings .settings-menu-pane {
transition: transform 0.4s cubic-bezier(0.1, 0.7, 0.1, 1);
}

@media (max-width: 600px) {
.tag-settings {
min-width: 0;
width: 100%;
transition: transform 0.4s cubic-bezier(0.1, 0.7, 0.1, 1);
transform: translate3d(100%, 0px, 0px);

transform-style: preserve-3d;
}

.tag-settings-in {
transform: translate3d(0px, 0px, 0px);
}
}
10 changes: 8 additions & 2 deletions core/client/app/templates/components/gh-tag-settings-form.hbs
@@ -1,6 +1,12 @@
<div class="{{if isViewingSubview 'settings-menu-pane-out-left' 'settings-menu-pane-in'}} settings-menu settings-menu-pane tag-settings-pane">
<div class="settings-menu-header">
<h4>{{title}}</h4>
<div class="settings-menu-header {{if isMobile 'subview'}}">
{{#if isMobile}}
{{#link-to 'settings.tags' class="back icon-arrow-left settings-menu-header-action"}}<span class="hidden">Back</span>{{/link-to}}
<h4>{{title}}</h4>
<div style="width:23px;">{{!flexbox space-between}}</div>
{{else}}
<h4>{{title}}</h4>
{{/if}}
</div>
<div class="settings-menu-content">
{{gh-uploader uploaded="setCoverImage" canceled="clearCoverImage" description="Add tag image" image=tag.image initUploader="setUploaderReference" tagName="section"}}
Expand Down
@@ -0,0 +1 @@
{{yield this}}
6 changes: 3 additions & 3 deletions core/client/app/templates/settings/tags.hbs
Expand Up @@ -7,7 +7,7 @@
</section>
</header>

<div class="view-container">
{{#gh-tags-management-container mobileWidth=mobileWidth tags=tags selectedTag=selectedTag enteredMobile="enteredMobile" leftMobile="leftMobile" as |container|}}
{{#gh-infinite-scroll
fetch="loadNextPage"
isLoading=isLoading
Expand All @@ -26,8 +26,8 @@
{{/each}}
</section>
{{/gh-infinite-scroll}}
<section class="settings-menu-container tag-settings {{if tagContentFocused 'keyboard-focused'}}">
<section class="settings-menu-container tag-settings {{if tagContentFocused 'keyboard-focused'}} {{if container.displaySettingsPane 'tag-settings-in'}}">
{{outlet}}
</section>
</div>
{{/gh-tags-management-container}}
</section>
2 changes: 1 addition & 1 deletion core/client/app/templates/settings/tags/tag.hbs
@@ -1 +1 @@
{{gh-tag-settings-form tag=tag setProperty=(action "setProperty") openModal="openModal"}}
{{gh-tag-settings-form tag=tag setProperty=(action "setProperty") openModal="openModal" isMobile=isMobile}}
@@ -0,0 +1,43 @@
/* jshint expr:true */
import { expect } from 'chai';
import {
describeComponent,
it
} from 'ember-mocha';
import hbs from 'htmlbars-inline-precompile';
import Ember from 'ember';

const resizeStub = Ember.Service.extend(Ember.Evented, {

});

describeComponent(
'gh-tags-management-container',
'Integration: Component: gh-tags-management-container',
{
integration: true
},
function () {
beforeEach(function () {
this.register('service:resize-service', resizeStub);
this.inject.service('resize-service', {as: 'resize-service'});
});

it('renders', function () {
this.set('mobileWidth', 600);
this.set('tags', []);
this.set('selectedTag', null);
this.on('enteredMobile', function () {
// noop
});
this.on('leftMobile', function () {
// noop
});

this.render(hbs`
{{#gh-tags-management-container mobileWidth=mobileWidth tags=tags selectedTag=selectedTag enteredMobile="enteredMobile" leftMobile="leftMobile"}}{{/gh-tags-management-container}}
`);
expect(this.$()).to.have.length(1);
});
}
);

0 comments on commit 983c6c8

Please sign in to comment.