summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMaxime Quandalle <maxime@quandalle.com>2015-05-24 21:40:21 +0200
committerMaxime Quandalle <maxime@quandalle.com>2015-05-24 22:16:40 +0200
commit9a45f3752fe7c8499960b4fb6d185f9f5f8afbda (patch)
treef8b726271a7055d84e223704a560a4b937db16eb
parent781577db041e0008de22f31bcc1cb11ae96670e0 (diff)
downloadwekan-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.
-rw-r--r--.jshintrc1
-rw-r--r--.meteor/packages1
-rw-r--r--.meteor/versions1
-rw-r--r--bower.json7
-rw-r--r--client/components/boards/body.jade4
-rw-r--r--client/components/boards/body.js22
-rw-r--r--client/components/boards/body.styl16
-rw-r--r--client/components/cards/details.js8
-rw-r--r--client/components/cards/minicard.styl14
-rw-r--r--client/components/lists/body.jade79
-rw-r--r--client/components/lists/body.js14
-rw-r--r--client/components/lists/main.jade5
-rw-r--r--client/components/lists/main.js7
-rw-r--r--client/components/lists/main.styl59
-rw-r--r--client/components/mixins/infiniteScrolling.js (renamed from client/components/sidebar/infiniteScrolling.js)0
-rw-r--r--client/components/mixins/perfectScrollbar.js6
-rw-r--r--client/components/mixins/perfectScrollbar.styl2
-rw-r--r--client/components/sidebar/helpers.js2
-rw-r--r--client/components/sidebar/rendered.js21
-rw-r--r--client/components/sidebar/sidebar.jade (renamed from client/components/sidebar/templates.jade)4
-rw-r--r--client/components/sidebar/sidebar.js26
-rw-r--r--client/styles/fancy-scrollbar.styl45
22 files changed, 162 insertions, 182 deletions
diff --git a/.jshintrc b/.jshintrc
index ebbf3c24..c6fcaf8d 100644
--- a/.jshintrc
+++ b/.jshintrc
@@ -54,6 +54,7 @@
"SubsManager": false,
"Mousetrap": false,
"Avatar": true,
+ "Ps": true,
// Our collections
"Boards": true,
diff --git a/.meteor/packages b/.meteor/packages
index 96888a0d..c04186c6 100644
--- a/.meteor/packages
+++ b/.meteor/packages
@@ -32,6 +32,7 @@ audit-argument-checks
iron:router
meteorhacks:subs-manager
mquandalle:autofocus
+mquandalle:bower
mquandalle:moment
ongoworks:speakingurl
raix:handlebar-helpers
diff --git a/.meteor/versions b/.meteor/versions
index 9b5f0177..bfa2145d 100644
--- a/.meteor/versions
+++ b/.meteor/versions
@@ -77,6 +77,7 @@ mongo@1.1.0
mongo-livedata@1.0.8
mousetrap:mousetrap@1.4.6_1
mquandalle:autofocus@1.0.0
+mquandalle:bower@1.4.1
mquandalle:jade@0.4.3
mquandalle:jade-compiler@0.4.3
mquandalle:jquery-textcomplete@0.3.9_1
diff --git a/bower.json b/bower.json
new file mode 100644
index 00000000..deca1fda
--- /dev/null
+++ b/bower.json
@@ -0,0 +1,7 @@
+{
+ "name": "LibreBoard",
+ "dependencies": {
+ "perfect-scrollbar": "0.6.2"
+ },
+ "private": true
+}
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