From 72901812ee9c265b2043baa3a1833efc3f64dab9 Mon Sep 17 00:00:00 2001 From: Sean Hammond Date: Mon, 26 Jun 2017 13:49:08 +0100 Subject: [PATCH 1/2] Add new feature-flagged view-switcher If the 'view-switcher' feature flat is enabled then use the new view switcher component, otherwise uses the old selection tabs component. The view switcher component is just a placeholder for now. --- src/sidebar/app.js | 1 + src/sidebar/components/sidebar-content.js | 1 + .../components/test/view-switcher-test.js | 63 +++++++++++++++++++ src/sidebar/components/view-switcher.js | 42 +++++++++++++ src/sidebar/templates/sidebar-content.html | 11 +++- src/sidebar/templates/view-switcher.html | 1 + src/styles/app.scss | 1 + src/styles/view-switcher.scss | 0 8 files changed, 119 insertions(+), 1 deletion(-) create mode 100644 src/sidebar/components/test/view-switcher-test.js create mode 100644 src/sidebar/components/view-switcher.js create mode 100644 src/sidebar/templates/view-switcher.html create mode 100644 src/styles/view-switcher.scss diff --git a/src/sidebar/app.js b/src/sidebar/app.js index 870a790bc86..23bf66ed1a6 100644 --- a/src/sidebar/app.js +++ b/src/sidebar/app.js @@ -170,6 +170,7 @@ module.exports = angular.module('h', [ .component('threadList', require('./components/thread-list')) .component('timestamp', require('./components/timestamp')) .component('topBar', require('./components/top-bar')) + .component('viewSwitcher', require('./components/view-switcher')) .directive('formInput', require('./directive/form-input')) .directive('formValidate', require('./directive/form-validate')) diff --git a/src/sidebar/components/sidebar-content.js b/src/sidebar/components/sidebar-content.js index 2275795aaca..4eb48ae5817 100644 --- a/src/sidebar/components/sidebar-content.js +++ b/src/sidebar/components/sidebar-content.js @@ -55,6 +55,7 @@ function SidebarContentController( totalNotes: counts.notes, totalAnnotations: counts.annotations, totalOrphans: counts.orphans, + viewSwitcherEnabled: features.flagEnabled('view-switcher'), waitingToAnchorAnnotations: counts.anchoring > 0, }); }); diff --git a/src/sidebar/components/test/view-switcher-test.js b/src/sidebar/components/test/view-switcher-test.js new file mode 100644 index 00000000000..dd25a1904a8 --- /dev/null +++ b/src/sidebar/components/test/view-switcher-test.js @@ -0,0 +1,63 @@ +'use strict'; + +var angular = require('angular'); + +var util = require('../../directive/test/util'); + +describe('viewSwitcher', function () { + before(function () { + angular.module('app', []) + .component('viewSwitcher', require('../view-switcher')); + }); + + beforeEach(function () { + var fakeAnnotationUI = {}; + var fakeFeatures = { + flagEnabled: sinon.stub().returns(true), + }; + + angular.mock.module('app', { + annotationUI: fakeAnnotationUI, + features: fakeFeatures, + }); + }); + + context('displays tabs, counts and selected tab', function () { + it('should display the tabs and counts of annotations and notes', function () { + var elem = util.createDirective(document, 'viewSwitcher', { + selectedTab: 'annotation', + totalAnnotations: '123', + totalNotes: '456', + }); + + var tabs = elem[0].querySelectorAll('a'); + + assert.include(tabs[0].textContent, 'Annotations'); + assert.include(tabs[1].textContent, 'Notes'); + assert.include(tabs[0].textContent, '123'); + assert.include(tabs[1].textContent, '456'); + }); + + it('should display annotations tab as selected', function () { + var elem = util.createDirective(document, 'selectionTabs', { + selectedTab: 'annotation', + totalAnnotations: '123', + totalNotes: '456', + }); + + var tabs = elem[0].querySelectorAll('a'); + assert.isTrue(tabs[0].classList.contains('is-selected')); + }); + + it('should display notes tab as selected', function () { + var elem = util.createDirective(document, 'selectionTabs', { + selectedTab: 'note', + totalAnnotations: '123', + totalNotes: '456', + }); + + var tabs = elem[0].querySelectorAll('a'); + assert.isTrue(tabs[1].classList.contains('is-selected')); + }); + }); +}); diff --git a/src/sidebar/components/view-switcher.js b/src/sidebar/components/view-switcher.js new file mode 100644 index 00000000000..24da331aed6 --- /dev/null +++ b/src/sidebar/components/view-switcher.js @@ -0,0 +1,42 @@ +'use strict'; + +var uiConstants = require('../ui-constants'); + +module.exports = { + controllerAs: 'vm', + //@ngInject + controller: function ($element, annotationUI, features) { + this.TAB_ANNOTATIONS = uiConstants.TAB_ANNOTATIONS; + this.TAB_NOTES = uiConstants.TAB_NOTES; + this.TAB_ORPHANS = uiConstants.TAB_ORPHANS; + + this.selectTab = function (type) { + annotationUI.clearSelectedAnnotations(); + annotationUI.selectTab(type); + }; + + this.orphansTabFlagEnabled = function () { + return features.flagEnabled('orphans_tab'); + }; + + this.showAnnotationsUnavailableMessage = function () { + return this.selectedTab === this.TAB_ANNOTATIONS && + this.totalAnnotations === 0 && + !this.isWaitingToAnchorAnnotations; + }; + + this.showNotesUnavailableMessage = function () { + return this.selectedTab === this.TAB_NOTES && + this.totalNotes === 0; + }; + }, + bindings: { + isLoading: '<', + isWaitingToAnchorAnnotations: '<', + selectedTab: '<', + totalAnnotations: '<', + totalNotes: '<', + totalOrphans: '<', + }, + template: require('../templates/view-switcher.html'), +}; diff --git a/src/sidebar/templates/sidebar-content.html b/src/sidebar/templates/sidebar-content.html index e5da39e1c62..bebcf658486 100644 --- a/src/sidebar/templates/sidebar-content.html +++ b/src/sidebar/templates/sidebar-content.html @@ -1,5 +1,5 @@ + + Date: Thu, 29 Jun 2017 11:23:40 +0100 Subject: [PATCH 2/2] Implement the new view switcher HTML and CSS --- .../components/test/view-switcher-test.js | 10 +-- src/sidebar/templates/view-switcher.html | 58 +++++++++++++++++- src/styles/view-switcher.scss | 61 +++++++++++++++++++ 3 files changed, 123 insertions(+), 6 deletions(-) diff --git a/src/sidebar/components/test/view-switcher-test.js b/src/sidebar/components/test/view-switcher-test.js index dd25a1904a8..59b487db35b 100644 --- a/src/sidebar/components/test/view-switcher-test.js +++ b/src/sidebar/components/test/view-switcher-test.js @@ -30,7 +30,7 @@ describe('viewSwitcher', function () { totalNotes: '456', }); - var tabs = elem[0].querySelectorAll('a'); + var tabs = elem[0].querySelectorAll('button'); assert.include(tabs[0].textContent, 'Annotations'); assert.include(tabs[1].textContent, 'Notes'); @@ -39,24 +39,24 @@ describe('viewSwitcher', function () { }); it('should display annotations tab as selected', function () { - var elem = util.createDirective(document, 'selectionTabs', { + var elem = util.createDirective(document, 'viewSwitcher', { selectedTab: 'annotation', totalAnnotations: '123', totalNotes: '456', }); - var tabs = elem[0].querySelectorAll('a'); + var tabs = elem[0].querySelectorAll('button'); assert.isTrue(tabs[0].classList.contains('is-selected')); }); it('should display notes tab as selected', function () { - var elem = util.createDirective(document, 'selectionTabs', { + var elem = util.createDirective(document, 'viewSwitcher', { selectedTab: 'note', totalAnnotations: '123', totalNotes: '456', }); - var tabs = elem[0].querySelectorAll('a'); + var tabs = elem[0].querySelectorAll('button'); assert.isTrue(tabs[1].classList.contains('is-selected')); }); }); diff --git a/src/sidebar/templates/view-switcher.html b/src/sidebar/templates/view-switcher.html index e5b30fd6420..f1ec9bee464 100644 --- a/src/sidebar/templates/view-switcher.html +++ b/src/sidebar/templates/view-switcher.html @@ -1 +1,57 @@ -VIEW SWITCHER! +
+ + + + + +
+ +
+
+

+ There are no page notes in this group. +
+ Create one by clicking the + + button. +

+
+
+

+ There are no annotations in this group. +
+ Create one by selecting some text and clicking the + button. +

+
+
diff --git a/src/styles/view-switcher.scss b/src/styles/view-switcher.scss index e69de29bb2d..36b7ab8af0f 100644 --- a/src/styles/view-switcher.scss +++ b/src/styles/view-switcher.scss @@ -0,0 +1,61 @@ +.view-switcher { + display: flex; + justify-content: center; + + // These are the exact margins required to vertically align the top of the + // view switcher with the top of the Hide Highlights button to its left, + // and the top of the first annotation card below the view switcher with the + // top of the New Page Note button to its left. + margin-top: 1px; + margin-bottom: 6px; +} + +.view-switcher__tab { + @include smallshadow + + height: 30px; // Same height as used for Hide Highlights and New Page Note + // buttons to left of view switcher. + padding-left: 12px; + padding-right: 12px; + + background: $white; + transition: background-color .1s linear; + + border: 1px solid $gray-lighter; + + cursor: pointer; + user-select: none; +} + +.view-switcher__tab { + border-right-width: 0; +} +.view-switcher__tab:last-child { + border-right-width: 1px; +} + +.view-switcher__tab:first-child { + border-top-left-radius: 4px; + border-bottom-left-radius: 4px; +} +.view-switcher__tab:last-child { + border-top-right-radius: 4px; + border-bottom-right-radius: 4px; +} + +.view-switcher__tab:focus { + outline: 0; +} +.view-switcher__tab::-moz-focus-inner { + border: 0; +} + +.view-switcher__tab:hover, +.view-switcher__tab.is-selected { + background-color: #e6e6e6; +} + +.view-switcher__empty-message { + position: relative; + top: 10px; +}