mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-11-25 09:03:12 +03:00
Refactor general UI state into a service
no issue - moves general UI state control such as menu display, autonav, settings menu, etc into a `ui` service for easier use within components - no longer required to jump through hoops passing state and actions down from application controller into components - removes indirect "route" actions in favour of calling actions/methods directly on the `ui` service
This commit is contained in:
parent
b643d47054
commit
267ce40945
@ -1,15 +1,15 @@
|
||||
import $ from 'jquery';
|
||||
import Component from 'ember-component';
|
||||
import observer from 'ember-metal/observer';
|
||||
|
||||
export default Component.extend({
|
||||
classNames: ['gh-app'],
|
||||
|
||||
showSettingsMenu: false,
|
||||
|
||||
toggleSettingsMenuBodyClass: observer('showSettingsMenu', function () {
|
||||
didReceiveAttrs() {
|
||||
this._super(...arguments);
|
||||
let showSettingsMenu = this.get('showSettingsMenu');
|
||||
|
||||
$('body').toggleClass('settings-menu-expanded', showSettingsMenu);
|
||||
})
|
||||
}
|
||||
});
|
||||
|
@ -6,23 +6,25 @@ should be closed when the user clicks elsewhere.
|
||||
|
||||
Example:
|
||||
```
|
||||
{{gh-content-cover onClick="closeMenus" onMouseEnter="closeAutoNav"}}
|
||||
{{gh-content-cover}}
|
||||
```
|
||||
**/
|
||||
|
||||
import Component from 'ember-component';
|
||||
import {inject as injectService} from '@ember/service';
|
||||
|
||||
export default Component.extend({
|
||||
ui: injectService(),
|
||||
|
||||
classNames: ['content-cover'],
|
||||
|
||||
onClick: null,
|
||||
onMouseEnter: null,
|
||||
|
||||
click() {
|
||||
this.sendAction('onClick');
|
||||
this.get('ui').closeMenus();
|
||||
},
|
||||
|
||||
mouseEnter() {
|
||||
this.sendAction('onMouseEnter');
|
||||
this.get('ui').closeAutoNav();
|
||||
}
|
||||
});
|
||||
|
@ -19,6 +19,10 @@ export default Component.extend({
|
||||
isMobile: reads('mediaQueries.isMobile'),
|
||||
maximise: false,
|
||||
|
||||
// closure actions
|
||||
desktopAction() {},
|
||||
mobileAction() {},
|
||||
|
||||
iconClass: computed('maximise', 'isMobile', function () {
|
||||
if (this.get('maximise') && !this.get('isMobile')) {
|
||||
return 'icon-maximise';
|
||||
@ -29,10 +33,10 @@ export default Component.extend({
|
||||
|
||||
click() {
|
||||
if (this.get('isMobile')) {
|
||||
this.sendAction('mobileAction');
|
||||
this.mobileAction();
|
||||
} else {
|
||||
this.toggleProperty('maximise');
|
||||
this.sendAction('desktopAction');
|
||||
this.desktopAction();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -1,12 +1,9 @@
|
||||
import Component from 'ember-component';
|
||||
import {inject as injectService} from '@ember/service';
|
||||
|
||||
export default Component.extend({
|
||||
tagName: 'nav',
|
||||
classNames: ['gh-mobile-nav-bar'],
|
||||
ui: injectService(),
|
||||
|
||||
actions: {
|
||||
openMobileMenu() {
|
||||
this.sendAction('openMobileMenu');
|
||||
}
|
||||
}
|
||||
tagName: 'nav',
|
||||
classNames: ['gh-mobile-nav-bar']
|
||||
});
|
||||
|
@ -6,10 +6,11 @@ import {htmlSafe} from 'ember-string';
|
||||
|
||||
export default Component.extend({
|
||||
config: injectService(),
|
||||
session: injectService(),
|
||||
ghostPaths: injectService(),
|
||||
feature: injectService(),
|
||||
ghostPaths: injectService(),
|
||||
routing: injectService('-routing'),
|
||||
session: injectService(),
|
||||
ui: injectService(),
|
||||
|
||||
tagName: 'nav',
|
||||
classNames: ['gh-nav'],
|
||||
@ -74,20 +75,8 @@ export default Component.extend({
|
||||
},
|
||||
|
||||
actions: {
|
||||
toggleAutoNav() {
|
||||
this.sendAction('toggleMaximise');
|
||||
},
|
||||
|
||||
showMarkdownHelp() {
|
||||
this.sendAction('showMarkdownHelp');
|
||||
},
|
||||
|
||||
closeMobileMenu() {
|
||||
this.sendAction('closeMobileMenu');
|
||||
},
|
||||
|
||||
openAutoNav() {
|
||||
this.sendAction('openAutoNav');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -7,7 +7,6 @@ import injectService from 'ember-service/inject';
|
||||
import moment from 'moment';
|
||||
import run from 'ember-runloop';
|
||||
import {guidFor} from 'ember-metal/utils';
|
||||
import {invokeAction} from 'ember-invoke-action';
|
||||
import {task, timeout} from 'ember-concurrency';
|
||||
|
||||
const PSM_ANIMATION_LENGTH = 400;
|
||||
@ -23,6 +22,7 @@ export default Component.extend(SettingsMenuMixin, {
|
||||
slugGenerator: injectService(),
|
||||
session: injectService(),
|
||||
settings: injectService(),
|
||||
ui: injectService(),
|
||||
|
||||
model: null,
|
||||
|
||||
@ -495,14 +495,6 @@ export default Component.extend(SettingsMenuMixin, {
|
||||
});
|
||||
},
|
||||
|
||||
closeNavMenu() {
|
||||
invokeAction(this, 'closeNavMenu');
|
||||
},
|
||||
|
||||
closeMenus() {
|
||||
invokeAction(this, 'closeMenus');
|
||||
},
|
||||
|
||||
changeAuthor(newAuthor) {
|
||||
let author = this.get('model.author');
|
||||
let model = this.get('model');
|
||||
|
@ -1,12 +1,9 @@
|
||||
import Component from 'ember-component';
|
||||
import {inject as injectService} from '@ember/service';
|
||||
|
||||
export default Component.extend({
|
||||
tagName: 'h2',
|
||||
classNames: ['view-title'],
|
||||
ui: injectService(),
|
||||
|
||||
actions: {
|
||||
openMobileMenu() {
|
||||
this.sendAction('openMobileMenu');
|
||||
}
|
||||
}
|
||||
tagName: 'h2',
|
||||
classNames: ['view-title']
|
||||
});
|
||||
|
@ -1,11 +1,12 @@
|
||||
import Controller from 'ember-controller';
|
||||
import computed from 'ember-computed';
|
||||
import injectService from 'ember-service/inject';
|
||||
import Controller from '@ember/controller';
|
||||
import {computed} from '@ember/object';
|
||||
import {inject as injectService} from '@ember/service';
|
||||
|
||||
export default Controller.extend({
|
||||
dropdown: injectService(),
|
||||
session: injectService(),
|
||||
settings: injectService(),
|
||||
ui: injectService(),
|
||||
|
||||
showNavMenu: computed('currentPath', 'session.isAuthenticated', 'session.user.isFulfilled', function () {
|
||||
// we need to defer showing the navigation menu until the session.user
|
||||
@ -19,45 +20,11 @@ export default Controller.extend({
|
||||
}),
|
||||
|
||||
topNotificationCount: 0,
|
||||
showMobileMenu: false,
|
||||
showSettingsMenu: false,
|
||||
showMarkdownHelpModal: false,
|
||||
|
||||
autoNav: false,
|
||||
autoNavOpen: computed('autoNav', {
|
||||
get() {
|
||||
return false;
|
||||
},
|
||||
set(key, value) {
|
||||
if (this.get('autoNav')) {
|
||||
return value;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}),
|
||||
|
||||
actions: {
|
||||
topNotificationChange(count) {
|
||||
this.set('topNotificationCount', count);
|
||||
},
|
||||
|
||||
toggleAutoNav() {
|
||||
this.toggleProperty('autoNav');
|
||||
},
|
||||
|
||||
openAutoNav() {
|
||||
this.set('autoNavOpen', true);
|
||||
},
|
||||
|
||||
closeAutoNav() {
|
||||
if (this.get('autoNavOpen')) {
|
||||
this.get('dropdown').closeDropdowns();
|
||||
}
|
||||
this.set('autoNavOpen', false);
|
||||
},
|
||||
|
||||
closeMobileMenu() {
|
||||
this.set('showMobileMenu', false);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -44,6 +44,7 @@ export default Mixin.create({
|
||||
notifications: injectService(),
|
||||
clock: injectService(),
|
||||
slugGenerator: injectService(),
|
||||
ui: injectService(),
|
||||
|
||||
wordcount: 0,
|
||||
cards: [], // for apps
|
||||
@ -587,14 +588,6 @@ export default Mixin.create({
|
||||
}
|
||||
},
|
||||
|
||||
closeNavMenu() {
|
||||
this.get('application').send('closeAutoNav');
|
||||
},
|
||||
|
||||
closeMenus() {
|
||||
this.get('application').send('closeMenus');
|
||||
},
|
||||
|
||||
toggleLeaveEditorModal(transition) {
|
||||
let leaveTransition = this.get('leaveEditorTransition');
|
||||
|
||||
@ -673,10 +666,6 @@ export default Mixin.create({
|
||||
|
||||
setWordcount(wordcount) {
|
||||
this.set('wordcount', wordcount);
|
||||
},
|
||||
|
||||
toggleAutoNav() {
|
||||
this.get('application').send('toggleAutoNav');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -30,12 +30,12 @@ export default Route.extend(ApplicationRouteMixin, ShortcutsRoute, {
|
||||
|
||||
config: injectService(),
|
||||
feature: injectService(),
|
||||
dropdown: injectService(),
|
||||
lazyLoader: injectService(),
|
||||
notifications: injectService(),
|
||||
settings: injectService(),
|
||||
upgradeNotification: injectService(),
|
||||
tour: injectService(),
|
||||
ui: injectService(),
|
||||
|
||||
beforeModel() {
|
||||
return this.get('config').fetch();
|
||||
@ -129,20 +129,8 @@ export default Route.extend(ApplicationRouteMixin, ShortcutsRoute, {
|
||||
},
|
||||
|
||||
actions: {
|
||||
openMobileMenu() {
|
||||
this.controller.set('showMobileMenu', true);
|
||||
},
|
||||
|
||||
openSettingsMenu() {
|
||||
this.controller.set('showSettingsMenu', true);
|
||||
},
|
||||
|
||||
closeMenus() {
|
||||
this.get('dropdown').closeDropdowns();
|
||||
this.controller.setProperties({
|
||||
showSettingsMenu: false,
|
||||
showMobileMenu: false
|
||||
});
|
||||
this.get('ui').closeMenus();
|
||||
},
|
||||
|
||||
didTransition() {
|
||||
|
88
ghost/admin/app/services/ui.js
Normal file
88
ghost/admin/app/services/ui.js
Normal file
@ -0,0 +1,88 @@
|
||||
import Service from '@ember/service';
|
||||
import injectService from 'ember-service/inject';
|
||||
import {computed} from '@ember/object';
|
||||
|
||||
export default Service.extend({
|
||||
dropdown: injectService(),
|
||||
|
||||
autoNav: false,
|
||||
showMobileMenu: false,
|
||||
showSettingsMenu: false,
|
||||
|
||||
autoNavOpen: computed('autoNav', {
|
||||
get() {
|
||||
return false;
|
||||
},
|
||||
set(key, value) {
|
||||
if (this.get('autoNav')) {
|
||||
return value;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}),
|
||||
|
||||
closeMenus() {
|
||||
this.get('dropdown').closeDropdowns();
|
||||
this.setProperties({
|
||||
showSettingsMenu: false,
|
||||
showMobileMenu: false
|
||||
});
|
||||
},
|
||||
|
||||
openAutoNav() {
|
||||
this.set('autoNavOpen', true);
|
||||
},
|
||||
|
||||
closeAutoNav() {
|
||||
if (this.get('autoNavOpen')) {
|
||||
this.get('dropdown').closeDropdowns();
|
||||
}
|
||||
this.set('autoNavOpen', false);
|
||||
},
|
||||
|
||||
closeMobileMenu() {
|
||||
this.set('showMobileMenu', false);
|
||||
},
|
||||
|
||||
openMobileMenu() {
|
||||
this.set('showMobileMenu', true);
|
||||
},
|
||||
|
||||
openSettingsMenu() {
|
||||
this.set('showSettingsMenu', true);
|
||||
},
|
||||
|
||||
toggleAutoNav() {
|
||||
this.toggleProperty('autoNav');
|
||||
},
|
||||
|
||||
actions: {
|
||||
closeMenus() {
|
||||
this.closeMenus();
|
||||
},
|
||||
|
||||
openAutoNav() {
|
||||
this.openAutoNav();
|
||||
},
|
||||
|
||||
closeAutoNav() {
|
||||
this.closeAutoNav();
|
||||
},
|
||||
|
||||
closeMobileMenu() {
|
||||
this.closeMobileMenu();
|
||||
},
|
||||
|
||||
openMobileMenu() {
|
||||
this.openMobileMenu();
|
||||
},
|
||||
|
||||
openSettingsMenu() {
|
||||
this.openSettingsMenu();
|
||||
},
|
||||
|
||||
toggleAutoNav() {
|
||||
this.toggleAutoNav();
|
||||
}
|
||||
}
|
||||
});
|
@ -1,29 +1,26 @@
|
||||
{{#gh-app showSettingsMenu=showSettingsMenu}}
|
||||
{{#gh-app showSettingsMenu=ui.showSettingsMenu}}
|
||||
{{#gh-skip-link anchor=".gh-main"}}Skip to main content{{/gh-skip-link}}
|
||||
|
||||
{{gh-alerts notify="topNotificationChange"}}
|
||||
|
||||
<div class="gh-viewport {{if autoNav 'gh-autonav'}} {{if showSettingsMenu 'settings-menu-expanded'}} {{if showMobileMenu 'mobile-menu-expanded'}}">
|
||||
<div class="gh-viewport {{if ui.autoNav 'gh-autonav'}} {{if ui.showSettingsMenu 'settings-menu-expanded'}} {{if ui.showMobileMenu 'mobile-menu-expanded'}}">
|
||||
{{#if showNavMenu}}
|
||||
{{gh-nav-menu
|
||||
open=autoNavOpen
|
||||
open=ui.autoNavOpen
|
||||
icon=settings.settledIcon
|
||||
toggleMaximise="toggleAutoNav"
|
||||
openAutoNav="openAutoNav"
|
||||
showMarkdownHelp="toggleMarkdownHelpModal"
|
||||
closeMobileMenu="closeMobileMenu"}}
|
||||
showMarkdownHelp="toggleMarkdownHelpModal"}}
|
||||
{{/if}}
|
||||
|
||||
{{#gh-main onMouseEnter="closeAutoNav" data-notification-count=topNotificationCount}}
|
||||
{{#gh-main onMouseEnter=(action "closeAutoNav" target=ui) data-notification-count=topNotificationCount}}
|
||||
{{outlet}}
|
||||
{{/gh-main}}
|
||||
|
||||
|
||||
{{gh-notifications}}
|
||||
|
||||
{{gh-content-cover onClick="closeMenus" onMouseEnter="closeAutoNav"}}
|
||||
{{gh-content-cover}}
|
||||
|
||||
{{gh-mobile-nav-bar openMobileMenu="openMobileMenu"}}
|
||||
{{gh-mobile-nav-bar}}
|
||||
</div>{{!gh-viewport}}
|
||||
{{/gh-app}}
|
||||
|
||||
|
@ -5,5 +5,5 @@
|
||||
{{#link-to "posts" classNames="gh-nav-main-content"}}{{inline-svg "content"}}Content{{/link-to}}
|
||||
{{/if}}
|
||||
{{#link-to "team" classNames="gh-nav-main-users"}}{{inline-svg "account-group"}}Team{{/link-to}}
|
||||
<div class="gh-mobile-nav-bar-more" {{action "openMobileMenu"}}>{{inline-svg "icon" class="icon-gh"}}More</div>
|
||||
<div class="gh-mobile-nav-bar-more" {{action "openMobileMenu" target=ui}}>{{inline-svg "icon" class="icon-gh"}}More</div>
|
||||
{{yield}}
|
||||
|
@ -1,4 +1,4 @@
|
||||
{{gh-menu-toggle desktopAction="toggleAutoNav" mobileAction="closeMobileMenu"}}
|
||||
{{gh-menu-toggle desktopAction=(action "toggleAutoNav" target=ui) mobileAction=(action "closeMobileMenu" target=ui)}}
|
||||
{{#gh-basic-dropdown horizontalPosition="right" calculatePosition=userDropdownPosition as |dropdown|}}
|
||||
{{#dropdown.trigger tagName="header" class="gh-nav-menu"}}
|
||||
<div class="gh-nav-menu-icon" style={{iconStyle}}></div>
|
||||
@ -91,7 +91,7 @@
|
||||
<footer class="gh-nav-foot">
|
||||
<a class="gh-nav-foot-sitelink" href="{{config.blogUrl}}/" target="_blank">View site {{inline-svg "external"}}</a>
|
||||
</footer>
|
||||
<div class="gh-autonav-toggle" {{action "openAutoNav" on="mouseEnter"}}></div>
|
||||
<div class="gh-autonav-toggle" {{action "openAutoNav" on="mouseEnter" target=ui}}></div>
|
||||
|
||||
{{gh-tour-item "getting-started"
|
||||
target=".gh-menu-toggle"
|
||||
|
@ -3,7 +3,7 @@
|
||||
<div class="{{if isViewingSubview 'settings-menu-pane-out-left' 'settings-menu-pane-in'}} settings-menu settings-menu-pane">
|
||||
<div class="settings-menu-header">
|
||||
<h4>Post Settings</h4>
|
||||
<button class="close settings-menu-header-action" {{action "closeMenus"}} data-test-close-settings-menu>
|
||||
<button class="close settings-menu-header-action" {{action "closeMenus" target=ui}} data-test-close-settings-menu>
|
||||
{{inline-svg "close"}}<span class="hidden">Close</span>
|
||||
</button>
|
||||
</div>
|
||||
|
@ -1,2 +1,2 @@
|
||||
<button {{action "openMobileMenu"}} class="gh-mobilemenu-button" role="presentation">{{inline-svg "icon" class="icon-gh"}}<span class="sr-only">Menu</span></button>
|
||||
<button {{action "openMobileMenu" target=ui}} class="gh-mobilemenu-button" role="presentation">{{inline-svg "icon" class="icon-gh"}}<span class="sr-only">Menu</span></button>
|
||||
{{yield}}
|
||||
|
@ -25,7 +25,7 @@
|
||||
onOpen=(action "cancelAutosave")}}
|
||||
{{/unless}}
|
||||
|
||||
<button type="button" class="post-settings" title="Settings" {{action "openSettingsMenu"}} data-test-psm-trigger>
|
||||
<button type="button" class="post-settings" title="Settings" {{action "openSettingsMenu" target=ui}} data-test-psm-trigger>
|
||||
{{inline-svg "settings"}}
|
||||
</button>
|
||||
</section>
|
||||
@ -151,9 +151,7 @@
|
||||
{{#liquid-wormhole}}
|
||||
{{gh-post-settings-menu
|
||||
model=model
|
||||
showSettingsMenu=application.showSettingsMenu
|
||||
closeNavMenu=(action "closeNavMenu")
|
||||
closeMenus=(action "closeMenus")
|
||||
showSettingsMenu=ui.showSettingsMenu
|
||||
deletePost=(action "toggleDeletePostModal")
|
||||
updateSlug=updateSlug
|
||||
}}
|
||||
|
@ -1,6 +1,6 @@
|
||||
<section class="gh-view">
|
||||
<header class="view-header">
|
||||
{{#gh-view-title openMobileMenu="openMobileMenu"}}<span>Tags</span>{{/gh-view-title}}
|
||||
{{#gh-view-title}}<span>Tags</span>{{/gh-view-title}}
|
||||
<section class="view-actions">
|
||||
{{#link-to "settings.tags.new" class="gh-btn gh-btn-green"}}<span>New Tag</span>{{/link-to}}
|
||||
</section>
|
||||
|
@ -1,6 +1,6 @@
|
||||
<section class="gh-view">
|
||||
<header class="view-header">
|
||||
{{#gh-view-title openMobileMenu="openMobileMenu"}}<span>Tags</span>{{/gh-view-title}}
|
||||
{{#gh-view-title}}<span>Tags</span>{{/gh-view-title}}
|
||||
<section class="view-actions">
|
||||
{{#link-to "settings.tags.new" class="gh-btn gh-btn-green"}}<span>New Tag</span>{{/link-to}}
|
||||
</section>
|
||||
|
15
ghost/admin/tests/unit/services/ui-test.js
Normal file
15
ghost/admin/tests/unit/services/ui-test.js
Normal file
@ -0,0 +1,15 @@
|
||||
import {describe, it} from 'mocha';
|
||||
import {expect} from 'chai';
|
||||
import {setupTest} from 'ember-mocha';
|
||||
|
||||
describe('Unit: Service: ui', function() {
|
||||
setupTest('service:ui', {
|
||||
needs: ['service:dropdown']
|
||||
});
|
||||
|
||||
// Replace this with your real tests.
|
||||
it('exists', function() {
|
||||
let service = this.subject();
|
||||
expect(service).to.be.ok;
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue
Block a user