From e48b5edbb4d3cd157f4d3a8c4623e2bec7cb10c7 Mon Sep 17 00:00:00 2001 From: Matt Enlow Date: Mon, 15 Sep 2014 22:55:37 -0600 Subject: [PATCH] Abstract mobile transition interactions Closes #4032 - Created "mobile" views: `parent-view`, `content-view` and `index-view` - `mobile/parent-view` has three callbacks for managing layout, and a mediaQuery listener to keep in sync with the user - content-view and index-view use their parent-views callbacks to bring themselves into and out of the viewport as appropriate - fixed media queries for post content list from 800px to 900px - Created `mobile-index-route` to intelligently transition to a new route on desktops (used by both PostsIndexRoute and SettingsIndexRoute) - Extract mobile interactions from settings views to new mobile utility views - `js-` prefixed settings view transitions - removed unused openEditor action from PostsRoute - removed unused mobile util "responsiveAction" --- .../admin/assets/sass/components/modals.scss | 10 ++-- ghost/admin/assets/sass/layouts/content.scss | 20 ++++---- ghost/admin/assets/sass/layouts/settings.scss | 8 +-- ghost/admin/assets/sass/patterns/_shame.scss | 4 +- ghost/admin/controllers/posts/post.js | 12 +---- ghost/admin/routes/mobile-index-route.js | 29 +++++++++++ ghost/admin/routes/posts.js | 3 -- ghost/admin/routes/posts/index.js | 28 +++++++---- ghost/admin/routes/posts/post.js | 5 -- ghost/admin/routes/settings/index.js | 31 ++++-------- ghost/admin/templates/posts/index.hbs | 2 + ghost/admin/templates/posts/post.hbs | 2 +- ghost/admin/templates/settings.hbs | 2 +- ghost/admin/templates/settings/about.hbs | 2 +- ghost/admin/utils/mobile.js | 18 +------ ghost/admin/views/application.js | 4 +- ghost/admin/views/mobile/content-view.js | 12 +++++ ghost/admin/views/mobile/index-view.js | 12 +++++ ghost/admin/views/mobile/parent-view.js | 33 +++++++++++++ ghost/admin/views/post-item-view.js | 3 +- ghost/admin/views/posts.js | 27 +++++----- ghost/admin/views/posts/index.js | 5 ++ ghost/admin/views/posts/post.js | 5 ++ ghost/admin/views/settings.js | 49 +++++-------------- ghost/admin/views/settings/content-base.js | 8 ++- ghost/admin/views/settings/index.js | 9 ++-- 26 files changed, 190 insertions(+), 153 deletions(-) create mode 100644 ghost/admin/routes/mobile-index-route.js create mode 100644 ghost/admin/views/mobile/content-view.js create mode 100644 ghost/admin/views/mobile/index-view.js create mode 100644 ghost/admin/views/mobile/parent-view.js create mode 100644 ghost/admin/views/posts/index.js create mode 100644 ghost/admin/views/posts/post.js diff --git a/ghost/admin/assets/sass/components/modals.scss b/ghost/admin/assets/sass/components/modals.scss index bcbbea4eb6..cc81c79c57 100644 --- a/ghost/admin/assets/sass/components/modals.scss +++ b/ghost/admin/assets/sass/components/modals.scss @@ -48,7 +48,7 @@ z-index: 1050; pointer-events: auto; - @media (max-width: 800px) { + @media (max-width: 900px) { width: auto; padding: 10px; }; @@ -57,7 +57,7 @@ min-width: 100px; } - @media (max-width: 800px) { + @media (max-width: 900px) { width: 100%; margin-left: 0; } @@ -77,7 +77,7 @@ @extend %modal; padding: 60px 0 30px; - @media (max-width: 800px) { + @media (max-width: 900px) { padding: 30px 0; } } @@ -134,11 +134,11 @@ .modal-style-wide { width: 550px; - @media (max-width: 800px) { + @media (max-width: 900px) { width: 100%; } } .modal-style-centered { text-align: center; -} \ No newline at end of file +} diff --git a/ghost/admin/assets/sass/layouts/content.scss b/ghost/admin/assets/sass/layouts/content.scss index 7d289d8b83..e059176b2c 100644 --- a/ghost/admin/assets/sass/layouts/content.scss +++ b/ghost/admin/assets/sass/layouts/content.scss @@ -9,7 +9,7 @@ height: 100%; width: 100%; - @media (max-width: 800px) { + @media (max-width: 900px) { overflow-x: hidden; } } @@ -24,7 +24,7 @@ border-right: $lightbrown 1px solid; background: #fff; - @media (max-width: 800px) { + @media (max-width: 900px) { width: auto; right: 0; z-index: 500; @@ -77,7 +77,7 @@ float: right; text-align: right; margin-left: 15px; - @media (max-width: 800px) { + @media (max-width: 900px) { float: none; } } @@ -118,7 +118,7 @@ @media (max-width: 400px) { padding: 15px; } - @media (max-width: 800px) { + @media (max-width: 900px) { padding-right: 40px; } @@ -128,7 +128,7 @@ margin-top: -6px; right: 15px; } - @media (min-width: 801px) { + @media (min-width: 901px) { &:after { display: none; } @@ -143,7 +143,7 @@ } // li li.active { - @media (min-width: 801px) { + @media (min-width: 901px) { // only apply active styles on larger devices border-bottom: lighten($midgrey, 40%) 1px solid; @@ -178,7 +178,7 @@ right:0; overflow: auto; background: #fff; - @media (max-width: 800px) { + @media (max-width: 900px) { width: auto; left: 100%; right: -100%; @@ -245,7 +245,7 @@ padding: 0px; display: table; z-index: 600; - @media (max-width: 800px) { + @media (max-width: 900px) { position: fixed; top: 45%; left: 50%; @@ -255,7 +255,7 @@ vertical-align: middle; display: table-cell; text-align: center; - @media (max-width: 800px) { + @media (max-width: 900px) { display: block; position: relative; left: -50%; @@ -268,4 +268,4 @@ } } // ,no-posts -} // .no-posts-box \ No newline at end of file +} // .no-posts-box diff --git a/ghost/admin/assets/sass/layouts/settings.scss b/ghost/admin/assets/sass/layouts/settings.scss index 27a2326c22..dbd781f244 100644 --- a/ghost/admin/assets/sass/layouts/settings.scss +++ b/ghost/admin/assets/sass/layouts/settings.scss @@ -49,7 +49,7 @@ top: 50%; left: 30px; transform: translateY(-50%); - + transition: color 0.1s; color: $brown; @@ -139,8 +139,8 @@ // The main content panel on the right .settings-content { margin-left: 25%; - - @media (max-width: 800px) { + + @media (max-width: 900px) { &.fade-in { animation: none; } @@ -312,4 +312,4 @@ float: right; } } -} \ No newline at end of file +} diff --git a/ghost/admin/assets/sass/patterns/_shame.scss b/ghost/admin/assets/sass/patterns/_shame.scss index 5c48abf7b9..0aa659b5a7 100644 --- a/ghost/admin/assets/sass/patterns/_shame.scss +++ b/ghost/admin/assets/sass/patterns/_shame.scss @@ -72,7 +72,7 @@ border-width: 10px 8px 10px 0; } - @media (max-width: 800px) { + @media (max-width: 900px) { display: inline-block; } } @@ -142,4 +142,4 @@ .ghost-popover.open { display: block !important; -} \ No newline at end of file +} diff --git a/ghost/admin/controllers/posts/post.js b/ghost/admin/controllers/posts/post.js index 49f1649907..8bcfd9fc8e 100644 --- a/ghost/admin/controllers/posts/post.js +++ b/ghost/admin/controllers/posts/post.js @@ -1,4 +1,3 @@ -import {mobileQuery} from 'ghost/utils/mobile'; var PostController = Ember.ObjectController.extend({ isPublished: Ember.computed.equal('status', 'published'), classNameBindings: ['featured'], @@ -13,17 +12,8 @@ var PostController = Ember.ObjectController.extend({ self.notifications.showErrors(errors); }); }, - hidePostContent: function () { - if (mobileQuery.matches) { - $('.js-content-list').animate({right: '0', left: '0', 'margin-right': '0'}, 300); - $('.js-content-preview').animate({right: '-100%', left: '100%', 'margin-left': '15px'}, 300); - } - }, showPostContent: function () { - if (mobileQuery.matches) { - $('.js-content-list').animate({right: '100%', left: '-100%', 'margin-right': '15px'}, 300); - $('.js-content-preview').animate({right: '0', left: '0', 'margin-left': '0'}, 300); - } + this.transitionToRoute('posts.post', this.get('model')); } } }); diff --git a/ghost/admin/routes/mobile-index-route.js b/ghost/admin/routes/mobile-index-route.js new file mode 100644 index 0000000000..91544f5116 --- /dev/null +++ b/ghost/admin/routes/mobile-index-route.js @@ -0,0 +1,29 @@ +import mobileQuery from 'ghost/utils/mobile'; + +//Routes that extend MobileIndexRoute need to implement +// desktopTransition, a function which is called when +// the user resizes to desktop levels. +var MobileIndexRoute = Ember.Route.extend({ + desktopTransition: Ember.K, + + activate: function attachDesktopTransition() { + this._super(); + mobileQuery.addListener(this.desktopTransitionMQ); + }, + + deactivate: function removeDesktopTransition() { + this._super(); + mobileQuery.removeListener(this.desktopTransitionMQ); + }, + + setDesktopTransitionMQ: function () { + var self = this; + this.set('desktopTransitionMQ', function desktopTransitionMQ() { + if (!mobileQuery.matches) { + self.desktopTransition(); + } + }); + }.on('init') +}); + +export default MobileIndexRoute; diff --git a/ghost/admin/routes/posts.js b/ghost/admin/routes/posts.js index cfcd211d7a..37ad9c271e 100644 --- a/ghost/admin/routes/posts.js +++ b/ghost/admin/routes/posts.js @@ -60,9 +60,6 @@ var PostsRoute = Ember.Route.extend(SimpleAuth.AuthenticatedRouteMixin, Shortcut 'down': 'moveDown' }, actions: { - openEditor: function (post) { - this.transitionTo('editor.edit', post); - }, moveUp: function () { this.stepThroughPosts(-1); }, diff --git a/ghost/admin/routes/posts/index.js b/ghost/admin/routes/posts/index.js index e3654ea082..b6a638a0f1 100644 --- a/ghost/admin/routes/posts/index.js +++ b/ghost/admin/routes/posts/index.js @@ -1,28 +1,38 @@ +import MobileIndexRoute from 'ghost/routes/mobile-index-route'; import loadingIndicator from 'ghost/mixins/loading-indicator'; +import mobileQuery from 'ghost/utils/mobile'; -var PostsIndexRoute = Ember.Route.extend(SimpleAuth.AuthenticatedRouteMixin, loadingIndicator, { - //Transition to posts.post if there are any posts the user can see +var PostsIndexRoute = MobileIndexRoute.extend(SimpleAuth.AuthenticatedRouteMixin, loadingIndicator, { + // Transition to a specific post if we're not on mobile beforeModel: function () { + if (!mobileQuery.matches) { + return this.goToPost(); + } + }, + + goToPost: function () { var self = this, - // the store has been populated so we can work with the local copy + // the store has been populated by PostsRoute posts = this.store.all('post'), post; - return this.store.find('user', 'me').then(function (user) { - // return the first post find that matches the following criteria: - // * User is an author, and is the author of this post - // * User has a role other than author post = posts.find(function (post) { + // Authors can only see posts they've written if (user.get('isAuthor')) { return post.isAuthoredByUser(user); - } else { - return true; } + return true; }); if (post) { return self.transitionTo('posts.post', post); } + self.get('controller').set('noPosts', true); }); + }, + + //Mobile posts route callback + desktopTransition: function () { + this.goToPost(); } }); diff --git a/ghost/admin/routes/posts/post.js b/ghost/admin/routes/posts/post.js index c030e4c656..c20a8e6355 100644 --- a/ghost/admin/routes/posts/post.js +++ b/ghost/admin/routes/posts/post.js @@ -1,6 +1,5 @@ import loadingIndicator from 'ghost/mixins/loading-indicator'; import ShortcutsRoute from 'ghost/mixins/shortcuts-route'; -import {mobileQuery} from 'ghost/utils/mobile'; var PostsPostRoute = Ember.Route.extend(SimpleAuth.AuthenticatedRouteMixin, loadingIndicator, ShortcutsRoute, { model: function (params) { @@ -53,10 +52,6 @@ var PostsPostRoute = Ember.Route.extend(SimpleAuth.AuthenticatedRouteMixin, load this._super(controller, model); this.controllerFor('posts').set('currentPost', model); - - if (mobileQuery.matches) { - this.controllerFor('posts.post').send('hidePostContent'); - } }, shortcuts: { diff --git a/ghost/admin/routes/settings/index.js b/ghost/admin/routes/settings/index.js index c0db77bc32..a48b516456 100644 --- a/ghost/admin/routes/settings/index.js +++ b/ghost/admin/routes/settings/index.js @@ -1,36 +1,25 @@ -import {mobileQuery} from 'ghost/utils/mobile'; +import MobileIndexRoute from 'ghost/routes/mobile-index-route'; import CurrentUserSettings from 'ghost/mixins/current-user-settings'; +import mobileQuery from 'ghost/utils/mobile'; -var SettingsIndexRoute = Ember.Route.extend(SimpleAuth.AuthenticatedRouteMixin, CurrentUserSettings, { - // redirect to general tab, unless on a mobile phone +var SettingsIndexRoute = MobileIndexRoute.extend(SimpleAuth.AuthenticatedRouteMixin, CurrentUserSettings, { + // Redirect users without permission to view settings, + // and show the settings.general route unless the user + // is mobile beforeModel: function () { var self = this; - this.currentUser() + return this.currentUser() .then(this.transitionAuthor()) .then(this.transitionEditor()) .then(function () { if (!mobileQuery.matches) { self.transitionTo('settings.general'); - } else { - //fill the empty {{outlet}} in settings.hbs if the user - //goes to fullscreen - - //fillOutlet needs special treatment so that it is - //properly bound to this when called from a MQ event - self.set('fillOutlet', _.bind(function fillOutlet(mq) { - if (!mq.matches) { - self.transitionTo('settings.general'); - } - }, self)); - mobileQuery.addListener(self.fillOutlet); } }); }, - - deactivate: function () { - if (this.get('fillOutlet')) { - mobileQuery.removeListener(this.fillOutlet); - } + + desktopTransition: function () { + this.transitionTo('settings.general'); } }); diff --git a/ghost/admin/templates/posts/index.hbs b/ghost/admin/templates/posts/index.hbs index 8c43534772..2399915b80 100644 --- a/ghost/admin/templates/posts/index.hbs +++ b/ghost/admin/templates/posts/index.hbs @@ -1,6 +1,8 @@ +{{#if noPosts}}

You Haven't Written Any Posts Yet!

{{#link-to "editor.new"}}{{/link-to}}
+{{/if}} diff --git a/ghost/admin/templates/posts/post.hbs b/ghost/admin/templates/posts/post.hbs index 68b37e56c2..63c7f941d7 100644 --- a/ghost/admin/templates/posts/post.hbs +++ b/ghost/admin/templates/posts/post.hbs @@ -1,5 +1,5 @@
- + {{#link-to "posts" tagName="button" class="btn btn-default btn-back"}}Back{{/link-to}} diff --git a/ghost/admin/templates/settings.hbs b/ghost/admin/templates/settings.hbs index a7c42fae77..8e523542e7 100644 --- a/ghost/admin/templates/settings.hbs +++ b/ghost/admin/templates/settings.hbs @@ -4,7 +4,7 @@
-