diff options
22 files changed, 162 insertions, 182 deletions
@@ -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 |