diff options
author | Maxime Quandalle <maxime@quandalle.com> | 2015-05-24 21:40:21 +0200 |
---|---|---|
committer | Maxime Quandalle <maxime@quandalle.com> | 2015-05-24 22:16:40 +0200 |
commit | 9a45f3752fe7c8499960b4fb6d185f9f5f8afbda (patch) | |
tree | f8b726271a7055d84e223704a560a4b937db16eb /client | |
parent | 781577db041e0008de22f31bcc1cb11ae96670e0 (diff) | |
download | wekan-9a45f3752fe7c8499960b4fb6d185f9f5f8afbda.tar.gz wekan-9a45f3752fe7c8499960b4fb6d185f9f5f8afbda.tar.bz2 wekan-9a45f3752fe7c8499960b4fb6d185f9f5f8afbda.zip |
Improve scrolling
We now replace native scrollbar by custom ones on the list card (which
is required by the new ergonomics in the parent commit), but the
"scrolling engine", is still native, we just hide the scrollbar and
draw our own in HTML/CSS using the perfect-scrollbar package (from
bower).
This commit also implements component scrolling when certain actions
are performed, eg scroll to the bottom when the new card composer is
opened.
Diffstat (limited to 'client')
-rw-r--r-- | client/components/boards/body.jade | 4 | ||||
-rw-r--r-- | client/components/boards/body.js | 22 | ||||
-rw-r--r-- | client/components/boards/body.styl | 16 | ||||
-rw-r--r-- | client/components/cards/details.js | 8 | ||||
-rw-r--r-- | client/components/cards/minicard.styl | 14 | ||||
-rw-r--r-- | client/components/lists/body.jade | 79 | ||||
-rw-r--r-- | client/components/lists/body.js | 14 | ||||
-rw-r--r-- | client/components/lists/main.jade | 5 | ||||
-rw-r--r-- | client/components/lists/main.js | 7 | ||||
-rw-r--r-- | client/components/lists/main.styl | 59 | ||||
-rw-r--r-- | client/components/mixins/infiniteScrolling.js (renamed from client/components/sidebar/infiniteScrolling.js) | 0 | ||||
-rw-r--r-- | client/components/mixins/perfectScrollbar.js | 6 | ||||
-rw-r--r-- | client/components/mixins/perfectScrollbar.styl | 2 | ||||
-rw-r--r-- | client/components/sidebar/helpers.js | 2 | ||||
-rw-r--r-- | client/components/sidebar/rendered.js | 21 | ||||
-rw-r--r-- | client/components/sidebar/sidebar.jade (renamed from client/components/sidebar/templates.jade) | 4 | ||||
-rw-r--r-- | client/components/sidebar/sidebar.js | 26 | ||||
-rw-r--r-- | client/styles/fancy-scrollbar.styl | 45 |
18 files changed, 152 insertions, 182 deletions
diff --git a/client/components/boards/body.jade b/client/components/boards/body.jade index 4b4c2b90..b157b742 100644 --- a/client/components/boards/body.jade +++ b/client/components/boards/body.jade @@ -16,12 +16,12 @@ template(name="boardComponent") +cardDetails(currentCard) if currentUser.isBoardMember +addListForm - +boardSidebar + +sidebar else +message(label="board-no-found") template(name="addListForm") - .list.js-list.add-list.js-add-list + .list.js-list.list-composer.js-list-composer +inlinedForm(autoclose=false) input.list-name-input(type="text" placeholder="{{_ 'add-list'}}" autocomplete="off" autofocus value=getCache) diff --git a/client/components/boards/body.js b/client/components/boards/body.js index 5e743001..e4aad646 100644 --- a/client/components/boards/body.js +++ b/client/components/boards/body.js @@ -22,8 +22,20 @@ BlazeComponent.extendComponent({ }); }, - scrollLeft: function() { - // TODO + scrollLeft: function(position) { + position = position || 0; + var $container = $(this.find('.js-lists')); + var containerWidth = $container.width(); + var currentScrollPosition = $container.scrollLeft(); + if (position < currentScrollPosition) { + $container.animate({ + scrollLeft: position + }); + } else if (position > currentScrollPosition + containerWidth) { + $container.animate({ + scrollLeft: Math.max(0, position - containerWidth) + }); + } }, currentCardIsInThisList: function() { @@ -67,14 +79,14 @@ BlazeComponent.extendComponent({ tolerance: 'pointer', appendTo: '.js-lists', helper: 'clone', - items: '.js-list:not(.add-list)', + items: '.js-list:not(.js-list-composer)', placeholder: 'list placeholder', start: function(event, ui) { $('.list.placeholder').height(ui.item.height()); Popup.close(); }, stop: function() { - self.$('.js-lists').find('.js-list:not(.add-list)').each( + self.$('.js-lists').find('.js-list:not(.js-list-composer)').each( function(i, list) { var data = Blaze.getData(list); Lists.update(data._id, { @@ -95,7 +107,7 @@ BlazeComponent.extendComponent({ }, sidebarSize: function() { - var sidebar = this.componentChildren('boardSidebar')[0]; + var sidebar = this.componentChildren('sidebar')[0]; if (sidebar && sidebar.isOpen()) return 'next-sidebar'; } diff --git a/client/components/boards/body.styl b/client/components/boards/body.styl index 07f35bb8..de4963ab 100644 --- a/client/components/boards/body.styl +++ b/client/components/boards/body.styl @@ -32,19 +32,3 @@ right: 0 bottom: 0 left: 0 - - &::-webkit-scrollbar - height: 13px - width: 13px - - &::-webkit-scrollbar-thumb:vertical, - &::-webkit-scrollbar-thumb:horizontal - background: rgba(255, 255, 255, .4) - - &::-webkit-scrollbar-track-piece - background: rgba(0, 0, 0, .15) - - &::-webkit-scrollbar-button - display: block - height: 5px - width: 5px diff --git a/client/components/cards/details.js b/client/components/cards/details.js index d0395129..385310bb 100644 --- a/client/components/cards/details.js +++ b/client/components/cards/details.js @@ -17,6 +17,14 @@ BlazeComponent.extendComponent({ activitiesComponent.loadNextPage(); }, + onRendered: function() { + var bodyBoardComponent = this.componentParent(); + var additionalMargin = 550; + var $cardDetails = this.$(this.firstNode()); + var scollLeft = $cardDetails.offset().left + additionalMargin; + bodyBoardComponent.scrollLeft(scollLeft); + }, + events: function() { return [{ 'click .js-move-card': Popup.open('moveCard'), diff --git a/client/components/cards/minicard.styl b/client/components/cards/minicard.styl index 1b9e60b5..775d31eb 100644 --- a/client/components/cards/minicard.styl +++ b/client/components/cards/minicard.styl @@ -8,6 +8,9 @@ position: relative z-index: 0 overflow: hidden + transition: transform 0.2s, + border-radius 0.2s, + border-left 0.2s a color: #4d4d4d @@ -39,19 +42,15 @@ .minicard-details padding: 6px 8px 2px position: relative - z-index: 10 + // z-index: 1 &.is-selected - margin-left: -11px - transform: translateX(- @margin-left) + transform: translateX(11px) border-bottom-right-radius: 0 border-top-right-radius: 0 z-index: 100 box-shadow: -2px 1px 2px rgba(0,0,0,.2) - .minicard-details - margin-right: 11px - a.minicard-details text-decoration:none @@ -122,6 +121,9 @@ .minicard-members:empty display: none + &.ui-sortable-helper + transform: rotate(4deg) + .badges float: left diff --git a/client/components/lists/body.jade b/client/components/lists/body.jade index dfbe05b7..9d4a903d 100644 --- a/client/components/lists/body.jade +++ b/client/components/lists/body.jade @@ -1,43 +1,44 @@ template(name="listBody") - .minicards.clearfix.js-minicards - if cards.count - +inlinedForm(autoclose=false position="top") - +addCardForm(listId=_id position="top") - each cards - .minicard.card.js-minicard( - class="{{#if isSelected}}is-selected{{/if}}") - a.minicard-details.clearfix.show(href=absoluteUrl) - if cover - .minicard-cover.js-card-cover(style="background-image: url({{cover.url}});") - if labels - .minicard-labels - each labels - .minicard-label(class="card-label-{{color}}" title="{{name}}") - .minicard-title= title - if members - .minicard-members.js-minicard-members - each members - +userAvatar(userId=this size="small" cardId="{{../_id}}") - .badges - if comments.count - .badge(title="{{_ 'card-comments-title' comments.count }}") - span.badge-icon.icon-sm.fa.fa-comment-o - .badge-text= comments.count - if description - .badge.badge-state-image-only(title=description) - span.badge-icon.icon-sm.fa.fa-align-left - if attachments.count - .badge - span.badge-icon.icon-sm.fa.fa-paperclip - span.badge-text= attachments.count - if currentUser.isBoardMember - +inlinedForm(autoclose=false position="bottom") - +addCardForm(listId=_id position="bottom") - else - if newCardFormIsVisible.get - a.open-card-composer.js-open-inlined-form - i.fa.fa-plus - | {{_ 'add-card'}} + .list-body.js-perfect-scrollbar + .minicards.clearfix.js-minicards + if cards.count + +inlinedForm(autoclose=false position="top") + +addCardForm(listId=_id position="top") + each cards + .minicard.card.js-minicard( + class="{{#if isSelected}}is-selected{{/if}}") + a.minicard-details.clearfix.show(href=absoluteUrl) + if cover + .minicard-cover.js-card-cover(style="background-image: url({{cover.url}});") + if labels + .minicard-labels + each labels + .minicard-label(class="card-label-{{color}}" title="{{name}}") + .minicard-title= title + if members + .minicard-members.js-minicard-members + each members + +userAvatar(userId=this size="small" cardId="{{../_id}}") + .badges + if comments.count + .badge(title="{{_ 'card-comments-title' comments.count }}") + span.badge-icon.icon-sm.fa.fa-comment-o + .badge-text= comments.count + if description + .badge.badge-state-image-only(title=description) + span.badge-icon.icon-sm.fa.fa-align-left + if attachments.count + .badge + span.badge-icon.icon-sm.fa.fa-paperclip + span.badge-text= attachments.count + if currentUser.isBoardMember + +inlinedForm(autoclose=false position="bottom") + +addCardForm(listId=_id position="bottom") + else + if newCardFormIsVisible.get + a.open-card-composer.js-open-inlined-form + i.fa.fa-plus + | {{_ 'add-card'}} template(name="addCardForm") .minicard.js-composer diff --git a/client/components/lists/body.js b/client/components/lists/body.js index 70db42d1..d8238c9a 100644 --- a/client/components/lists/body.js +++ b/client/components/lists/body.js @@ -3,6 +3,10 @@ BlazeComponent.extendComponent({ return 'listBody'; }, + mixins: function() { + return [Mixins.PerfectScrollbar]; + }, + isSelected: function() { return Session.equals('currentCard', this.currentData()._id); }, @@ -62,13 +66,21 @@ BlazeComponent.extendComponent({ this.newCardFormIsVisible.set(value); }, + scrollToBottom: function() { + var $container = $(this.firstNode()); + $container.animate({ + scrollTop: $container.height() + }); + }, + onCreated: function() { this.newCardFormIsVisible = new ReactiveVar(true); }, events: function() { return [{ - submit: this.addCard + submit: this.addCard, + 'click .open-card-composer': this.scrollToBottom }]; } }).register('listBody'); diff --git a/client/components/lists/main.jade b/client/components/lists/main.jade index dd4bb49a..c959b87f 100644 --- a/client/components/lists/main.jade +++ b/client/components/lists/main.jade @@ -1,5 +1,4 @@ template(name='list') .list.js-list(id="js-list-{{_id}}") - .list-wrapper - +listHeader - +listBody + +listHeader + +listBody diff --git a/client/components/lists/main.js b/client/components/lists/main.js index 8a96f5ce..3464865a 100644 --- a/client/components/lists/main.js +++ b/client/components/lists/main.js @@ -19,9 +19,10 @@ BlazeComponent.extendComponent({ // XXX The jQuery UI sortable plugin is far from ideal here. First we include // all jQuery components but only use one. Second, it modifies the DOM itself, // resulting in Blaze abandoning reactive update of the nodes that have been - // moved which result in bugs if multiple users use the board in real time. - // I tried sortable:sortable but that was not better. Should we “simply” write - // the drag&drop code ourselves? + // moved which result in bugs if multiple users use the board in real time. I + // tried sortable:sortable but that was not better. And dragula is not + // powerful enough for our use casesShould we “simply” write the drag&drop + // code ourselves? onRendered: function() { if (Meteor.user().isBoardMember()) { var boardComponent = this.componentParent(); diff --git a/client/components/lists/main.styl b/client/components/lists/main.styl index 60a6ab98..47dfcf28 100644 --- a/client/components/lists/main.styl +++ b/client/components/lists/main.styl @@ -11,8 +11,7 @@ background: darken(white, 10%) height: 100% border-left: 1px solid darken(white, 20%) - padding: 12px 7px 5px - overflow-y: auto + padding: 0 &:first-child margin-left: 5px @@ -21,15 +20,20 @@ .card-detail + & border-left: none - &.editable - cursor: grab + &.ui-sortable-helper + cursor: grabbing + box-shadow: -2px 2px 8px rgba(0, 0, 0, .3), + 0 0 1px rgba(0, 0, 0, .5) + transform: rotate(4deg) - .list-wrapper - cursor: default + &.placeholder + background-color: rgba(0, 0, 0, .2) + border-color: transparent + box-shadow: none + height: 100px - &.add-list - &.fade - opacity: 0 + &.list-composer + padding: 17px .list-name-input background: rgba(0, 0, 0, .05) @@ -55,7 +59,7 @@ .list-header flex: 0 0 auto - padding: 10px 26px 4px 6px + margin: 20px 15px 4px position: relative min-height: 20px @@ -74,24 +78,23 @@ .list-header-menu-icon background-clip: content-box background-origin: content-box - padding: 6px 8px + // padding: 6px 8px position: absolute - top: 3px - right: -5px + top: 0 + right: 0 color: #a6a6a6 .list-header-num-cards color: #8c8c8c margin: 0 -.minicards - padding: 4px 4px 1px - z-index: 1 - height: 100% +.list-body + flex: 1 + overflow-y: auto + padding: 5px 11px - &::-webkit-scrollbar-button - display: block - height: 4px + .ps-scrollbar-y-rail + transform: translateX(2px) .open-card-composer border-radius: 2px @@ -100,6 +103,7 @@ padding: 7px 10px position: relative text-decoration: none + animation: fadeIn 0.3s i.fa margin-right: 7px @@ -117,18 +121,3 @@ opacity: 0 to opacity: 1 - -.list.placeholder - background-color: rgba(0, 0, 0, .2) - border-color: transparent - box-shadow: none - height: 100px - -.list.ui-sortable-helper - cursor: grabbing - box-shadow: -2px 2px 8px rgba(0, 0, 0, .3), 0 0 1px rgba(0, 0, 0, .5) - transform: rotate(4deg) - - -.list.ui-sortable-helper .list-header-menu-icon - display: none diff --git a/client/components/sidebar/infiniteScrolling.js b/client/components/mixins/infiniteScrolling.js index df3b8901..df3b8901 100644 --- a/client/components/sidebar/infiniteScrolling.js +++ b/client/components/mixins/infiniteScrolling.js diff --git a/client/components/mixins/perfectScrollbar.js b/client/components/mixins/perfectScrollbar.js new file mode 100644 index 00000000..06e8aedd --- /dev/null +++ b/client/components/mixins/perfectScrollbar.js @@ -0,0 +1,6 @@ +Mixins.PerfectScrollbar = BlazeComponent.extendComponent({ + onRendered: function() { + var component = this.mixinParent(); + Ps.initialize(component.find('.js-perfect-scrollbar')); + } +}); diff --git a/client/components/mixins/perfectScrollbar.styl b/client/components/mixins/perfectScrollbar.styl new file mode 100644 index 00000000..c8267668 --- /dev/null +++ b/client/components/mixins/perfectScrollbar.styl @@ -0,0 +1,2 @@ +.ps-container + position: relative diff --git a/client/components/sidebar/helpers.js b/client/components/sidebar/helpers.js index a76dad7f..15035bd4 100644 --- a/client/components/sidebar/helpers.js +++ b/client/components/sidebar/helpers.js @@ -3,7 +3,7 @@ var widgetTitles = { background: 'change-background' }; -Template.boardSidebar.helpers({ +Template.sidebar.helpers({ currentWidget: function() { return Session.get('currentWidget') + 'Sidebar'; }, diff --git a/client/components/sidebar/rendered.js b/client/components/sidebar/rendered.js deleted file mode 100644 index 36b1255c..00000000 --- a/client/components/sidebar/rendered.js +++ /dev/null @@ -1,21 +0,0 @@ -Template.membersWidget.onRendered(function() { - var self = this; - if (! Meteor.user().isBoardMember()) - return; - - _.each(['.js-member', '.js-label'], function(className) { - $(document).on('mouseover', function() { - self.$(className).draggable({ - appendTo: 'body', - helper: 'clone', - revert: 'invalid', - revertDuration: 150, - snap: false, - snapMode: 'both', - start: function() { - Popup.close(); - } - }); - }); - }); -}); diff --git a/client/components/sidebar/templates.jade b/client/components/sidebar/sidebar.jade index 23a1a87e..07cd777c 100644 --- a/client/components/sidebar/templates.jade +++ b/client/components/sidebar/sidebar.jade @@ -1,9 +1,9 @@ -template(name="boardSidebar") +template(name="sidebar") .board-sidebar.sidebar(class="{{#if isOpen}}is-open{{/if}}") a.sidebar-tongue.js-toogle-sidebar( class="{{#if isTongueHidden}}is-hidden{{/if}}") i.fa.fa-chevron-left - .sidebar-content.js-board-sidebar-content + .sidebar-content.js-board-sidebar-content.js-perfect-scrollbar //- XXX https://github.com/peerlibrary/meteor-blaze-components/issues/30 if Filter.isActive +filterSidebar diff --git a/client/components/sidebar/sidebar.js b/client/components/sidebar/sidebar.js index af676bf2..764f16eb 100644 --- a/client/components/sidebar/sidebar.js +++ b/client/components/sidebar/sidebar.js @@ -1,10 +1,10 @@ BlazeComponent.extendComponent({ template: function() { - return 'boardSidebar'; + return 'sidebar'; }, mixins: function() { - return [Mixins.InfiniteScrolling]; + return [Mixins.InfiniteScrolling, Mixins.PerfectScrollbar]; }, onCreated: function() { @@ -46,6 +46,26 @@ BlazeComponent.extendComponent({ return this.isOpen() && Filter.isActive(); }, + onRendered: function() { + var self = this; + if (! Meteor.user().isBoardMember()) + return; + + $(document).on('mouseover', function() { + self.$('.js-member,.js-label').draggable({ + appendTo: 'body', + helper: 'clone', + revert: 'invalid', + revertDuration: 150, + snap: false, + snapMode: 'both', + start: function() { + Popup.close(); + } + }); + }); + }, + events: function() { // XXX Hacky, we need some kind of `super` var mixinEvents = this.getMixin(Mixins.InfiniteScrolling).events(); @@ -53,4 +73,4 @@ BlazeComponent.extendComponent({ 'click .js-toogle-sidebar': this.toogle }]); } -}).register('boardSidebar'); +}).register('sidebar'); diff --git a/client/styles/fancy-scrollbar.styl b/client/styles/fancy-scrollbar.styl deleted file mode 100644 index c7a30018..00000000 --- a/client/styles/fancy-scrollbar.styl +++ /dev/null @@ -1,45 +0,0 @@ -.fancy-scrollbar - -webkit-overflow-scrolling: touch - - .fancy-scrollbar::-webkit-scrollbar - height: 9px - width: 9px - - &::-webkit-scrollbar-button:start:decrement, - &::-webkit-scrollbar-button:end:increment - background: transparent - display: none - - &::-webkit-scrollbar-track-piece - background: #dbdbdb - - &:vertical:start - border-top-left-radius: 5px - border-top-right-radius: 5px - border-bottom-right-radius: 0 - border-bottom-left-radius: 0 - - &:vertical:end - border-top-left-radius: 0 - border-top-right-radius: 0 - border-bottom-right-radius: 5px - border-bottom-left-radius: 5px - - &:horizontal:start - border-top-left-radius: 5px - border-top-right-radius: 0 - border-bottom-right-radius: 0 - border-bottom-left-radius: 5px - - &:horizontal:end - border-top-left-radius: 0 - border-top-right-radius: 5px - border-bottom-right-radius: 5px - border-bottom-left-radius: 0 - - &::-webkit-scrollbar-thumb:vertical, - &::-webkit-scrollbar-thumb:horizontal - background: #c2c2c2 - border-radius: 5px - display: block - height: 50px |