diff options
Diffstat (limited to 'client/components/boards')
-rw-r--r-- | client/components/boards/body.jade | 33 | ||||
-rw-r--r-- | client/components/boards/body.js | 70 | ||||
-rw-r--r-- | client/components/boards/body.styl | 54 | ||||
-rw-r--r-- | client/components/boards/colors.styl | 34 | ||||
-rw-r--r-- | client/components/boards/events.js | 96 | ||||
-rw-r--r-- | client/components/boards/header.jade | 87 | ||||
-rw-r--r-- | client/components/boards/header.js | 7 | ||||
-rw-r--r-- | client/components/boards/header.styl | 137 | ||||
-rw-r--r-- | client/components/boards/helpers.js | 45 | ||||
-rw-r--r-- | client/components/boards/list.jade | 14 | ||||
-rw-r--r-- | client/components/boards/list.styl | 85 | ||||
-rw-r--r-- | client/components/boards/router.js | 34 |
12 files changed, 696 insertions, 0 deletions
diff --git a/client/components/boards/body.jade b/client/components/boards/body.jade new file mode 100644 index 00000000..5406ee2f --- /dev/null +++ b/client/components/boards/body.jade @@ -0,0 +1,33 @@ +//- + XXX This template can't be transformed into a component because it is + included by iron-router. That's a bug. +template(name="board") + +boardComponent + +template(name="boardComponent") + if this + .board-wrapper(class=colorClass) + .board-canvas(class=sidebarSize) + .lists.js-lists + each lists + +list(this) + if currentUser.isBoardMember + +addlistForm + +boardSidebar + if currentCard + +cardSidebar(currentCard) + else + +message(label="board-no-found") + +template(name="addlistForm") + .list.js-list.add-list.js-add-list + +inlinedForm(autoclose=false) + input.list-name-input(type="text" placeholder="{{_ 'add-list'}}" + autocomplete="off" autofocus) + div.edit-controls.clearfix + button.primary.confirm.js-save-edit(type="submit") {{_ 'save'}} + a.fa.fa-times.dark-hover.cancel.js-close-inlined-form + else + .js-open-inlined-form + i.fa.fa-plus + | {{_ 'add-list'}} diff --git a/client/components/boards/body.js b/client/components/boards/body.js new file mode 100644 index 00000000..2b4baf53 --- /dev/null +++ b/client/components/boards/body.js @@ -0,0 +1,70 @@ +BlazeComponent.extendComponent({ + template: function() { + return 'boardComponent'; + }, + + openNewListForm: function() { + this.componentChildren('addlistForm')[0].open(); + }, + + scrollLeft: function() { + // TODO + }, + + onRendered: function() { + var self = this; + + self.scrollLeft(); + + if (Meteor.user().isBoardMember()) { + self.$('.js-lists').sortable({ + tolerance: 'pointer', + appendTo: '.js-lists', + helper: 'clone', + items: '.js-list:not(.add-list)', + 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( + function(i, list) { + var data = Blaze.getData(list); + Lists.update(data._id, { + $set: { + sort: i + } + }); + } + ); + } + }); + + // If there is no data in the board (ie, no lists) we autofocus the list + // creation form by clicking on the corresponding element. + if (self.data().lists().count() === 0) { + this.openNewListForm(); + } + } + }, + + sidebarSize: function() { + var sidebar = this.componentChildren('boardSidebar')[0]; + if (Session.get('currentCard') !== null) + return 'next-large-sidebar'; + else if (sidebar && sidebar.isOpen()) + return 'next-small-sidebar'; + } +}).register('boardComponent'); + +BlazeComponent.extendComponent({ + template: function() { + return 'addlistForm'; + }, + + // Proxy + open: function() { + this.componentChildren('inlinedForm')[0].open(); + } +}).register('addlistForm'); diff --git a/client/components/boards/body.styl b/client/components/boards/body.styl new file mode 100644 index 00000000..cb351e46 --- /dev/null +++ b/client/components/boards/body.styl @@ -0,0 +1,54 @@ +@import 'nib' + +.board-wrapper + left: 0 + top: 0 + bottom: 0 + right: 0 + position: absolute + overflow: hidden + + .board-canvas + position: absolute + left: 0 + right: 0 + top: 0 + bottom: 0 + transition: margin .1s + + &.next-small-sidebar + margin-right: 248px + + &.next-large-sidebar + opacity: 0.8 + margin-right: 496px + +.lists + align-items: flex-start + display: flex + flex-direction: row + margin-bottom: 10px + overflow-x: auto + overflow-y: hidden + padding-bottom: 10px + position: absolute + top: 0 + 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/boards/colors.styl b/client/components/boards/colors.styl new file mode 100644 index 00000000..1db44845 --- /dev/null +++ b/client/components/boards/colors.styl @@ -0,0 +1,34 @@ +// We define a set of six board colors that we took from the FlatUI palette. +// http://flatuicolors.com + +setBoardColor(color) + &#header, + &.sk-spinner div, + .board-backgrounds-list &.background-box, + &.pop-over .pop-over-list li a:hover, + .board-list & a + background-color: color + + & .minicard.is-selected .minicard-details + border-bottom: 2px solid color + + button[type=submit].primary, input[type=submit].primary + background-color: darken(color, 20%) + +.board-color-nephritis + setBoardColor(#27AE60) + +.board-color-pomegranate + setBoardColor(#C0392B) + +.board-color-belize + setBoardColor(#2980B9) + +.board-color-wisteria + setBoardColor(#8E44AD) + +.board-color-midnight + setBoardColor(#2C3E50) + +.board-color-pumpkin + setBoardColor(#E67E22) diff --git a/client/components/boards/events.js b/client/components/boards/events.js new file mode 100644 index 00000000..6f9d7fc6 --- /dev/null +++ b/client/components/boards/events.js @@ -0,0 +1,96 @@ +var toggleBoardStar = function(boardId) { + var queryType = Meteor.user().hasStarred(boardId) ? '$pull' : '$addToSet'; + var query = {}; + query[queryType] = { + 'profile.starredBoards': boardId + }; + Meteor.users.update(Meteor.userId(), query); +}; + +Template.boards.events({ + 'click .js-star-board': function(evt) { + toggleBoardStar(this._id); + evt.preventDefault(); + } +}); + +Template.headerBoard.events({ + 'click .js-star-board': function() { + toggleBoardStar(this._id); + }, + 'click .js-open-board-menu': Popup.open('boardMenu'), + 'click #permission-level:not(.no-edit)': Popup.open('boardChangePermission'), + 'click .js-filter-cards-indicator': function(evt) { + Session.set('currentWidget', 'filter'); + evt.preventDefault(); + }, + 'click .js-filter-card-clear': function(evt) { + Filter.reset(); + evt.stopPropagation(); + } +}); + +Template.boardMenuPopup.events({ + 'click .js-rename-board': Popup.open('boardChangeTitle'), + 'click .js-change-board-color': Popup.open('boardChangeColor') +}); + +Template.createBoardPopup.events({ + 'submit #CreateBoardForm': function(evt, t) { + var title = t.$('#boardNewTitle'); + + // trim value title + if ($.trim(title.val())) { + // İnsert Board title + var boardId = Boards.insert({ + title: title.val(), + permission: 'public' + }); + + // Go to Board _id + Utils.goBoardId(boardId); + } + evt.preventDefault(); + } +}); + +Template.boardChangeTitlePopup.events({ + 'submit #ChangeBoardTitleForm': function(evt, t) { + var title = t.$('.js-board-name').val().trim(); + if (title) { + Boards.update(this._id, { + $set: { + title: title + } + }); + Popup.close(); + } + evt.preventDefault(); + } +}); + +Template.boardChangePermissionPopup.events({ + 'click .js-select': function(evt) { + var $this = $(evt.currentTarget); + var permission = $this.attr('name'); + + Boards.update(this._id, { + $set: { + permission: permission + } + }); + Popup.close(); + } +}); + +Template.boardChangeColorPopup.events({ + 'click .js-select-background': function(evt) { + var currentBoardId = Session.get('currentBoard'); + Boards.update(currentBoardId, { + $set: { + color: this.toString() + } + }); + evt.preventDefault(); + } +}); diff --git a/client/components/boards/header.jade b/client/components/boards/header.jade new file mode 100644 index 00000000..189cdac4 --- /dev/null +++ b/client/components/boards/header.jade @@ -0,0 +1,87 @@ +template(name="headerBoard") + h1.header-board-menu.js-open-board-menu + = title + span.fa.fa-angle-down + + .board-header-btns.left + unless isSandstorm + a.board-header-btn.js-star-board(class="{{#if isStarred}}board-header-starred{{/if}}" + title="{{# if isStarred }}{{_ 'click-to-unstar'}}{{ else }}{{_ 'click-to-star'}}{{/ if }} {{_ 'starred-boards-description'}}") + span.board-header-btn-icon.icon-sm.fa(class="fa-star{{#unless isStarred}}-o{{/unless}}") + //- XXX To implement + span.board-header-btn-text Starred + //- + XXX Normally we would disable this field for sandstorm, but we keep it + until sandstorm implements sharing capabilities + + a.board-header-btn.perms-btn.js-change-vis(class="{{#unless currentUser.isBoardAdmin}}no-edit{{/ unless}}" id="permission-level") + span.board-header-btn-icon.icon-sm.fa(class="{{#if isPublic}}fa-globe{{else}}fa-lock{{/if}}") + span.board-header-btn-text {{_ permission}} + + a.board-header-btn.js-search + span.board-header-btn-icon.icon-sm.fa.fa-tag + span.board-header-btn-text Labels + + //- XXX Clicking here should open a search field + a.board-header-btn.js-search + span.board-header-btn-icon.icon-sm.fa.fa-search + span.board-header-btn-text {{_ 'search'}} + + //- +boardMembersHeader + +template(name="boardMembersHeader") + .board-header-members + each currentBoard.members + +userAvatar(userId=userId draggable=true showBadges=true) + unless isSandstorm + if currentUser.isBoardAdmin + a.member.add-board-member.js-open-manage-board-members + i.fa.fa-plus + +template(name="boardMenuPopup") + ul.pop-over-list + li: a.js-rename-board {{_ 'rename-board'}} + li: a.js-change-board-color Change color + li: a Copy this board + li: a Rules + +template(name="boardChangeTitlePopup") + form#ChangeBoardTitleForm + label {{_ 'name'}} + input.js-board-name(type="text" value="{{ title }}" autofocus) + input.primary.wide.js-rename-board(type="submit" value="{{_ 'rename'}}") + +template(name="boardChangePermissionPopup") + ul.pop-over-list + li + a.js-select.light-hover(name="private") + span.icon-sm.fa.fa-lock.vis-icon + | {{_ 'private'}} + if check 'private' + span.icon-sm.fa.fa-check + span.sub-name {{_ 'private-desc'}} + li + a.js-select.light-hover(name="public") + span.icon-sm.fa.fa-globe.vis-icon + | {{_ 'public'}} + if check 'public' + span.icon-sm.fa.fa-check + span.sub-name {{_ 'public-desc'}} + +template(name="boardChangeColorPopup") + .board-backgrounds-list.clearfix + each backgroundColors + .board-background-select.js-select-background + span.background-box(class="board-color-{{this}}") + if isSelected + i.fa.fa-check + +template(name="createBoardPopup") + .content.clearfix + form#CreateBoardForm + label(for="boardNewTitle") {{_ 'title'}} + input#boardNewTitle.non-empty(type="text" name="name" placeholder="{{_ 'bucket-example'}}" autofocus) + p.quiet + span.icon-sm.fa.fa-globe + | {{{_ 'board-public-info'}}} + input.primary.wide(type="submit" value="{{_ 'create'}}") diff --git a/client/components/boards/header.js b/client/components/boards/header.js new file mode 100644 index 00000000..7d02df48 --- /dev/null +++ b/client/components/boards/header.js @@ -0,0 +1,7 @@ +Template.headerBoard.helpers({ + isStarred: function() { + var boardId = Session.get('currentBoard'); + var user = Meteor.user(); + return boardId && user && user.hasStarred(boardId); + } +}); diff --git a/client/components/boards/header.styl b/client/components/boards/header.styl new file mode 100644 index 00000000..44c38a4b --- /dev/null +++ b/client/components/boards/header.styl @@ -0,0 +1,137 @@ +@import 'nib' + +.board-header { + height: auto; + overflow: hidden; + padding: 10px 30px 10px 8px; + position: relative; + transition: padding .15s ease-in; +} + +.board-header-btns { + position: relative; + display: block; +} + +.board-header-btn { + border-radius: 3px; + color: #f6f6f6; + cursor: default; + float: left; + font-size: 12px; + height: 30px; + line-height: 32px; + margin: 2px 4px 0 0; + overflow: hidden; + padding-left: 30px; + position: relative; + text-decoration: none; +} + +.board-header-btn:empty { + display: none; +} + +.board-header-btn-without-icon { + padding-left: 8px; +} + +.board-header-btn-icon { + background-clip: content-box; + background-origin: content-box; + color: #f6f6f6 !important; + padding: 6px; + position: absolute; + top: 0; + left: 0; +} + +.board-header-btn-text { + padding-right: 8px; +} + +.board-header-btn:not(.no-edit) .text { + text-decoration: underline; +} + +.board-header-btn:not(.no-edit):hover { + background: rgba(0, 0, 0, .12); + cursor: pointer; +} + +.board-header-btn:hover { + color: #f6f6f6; +} + +.board-header-btn.board-header-btn-enabled { + background-color: rgba(0, 0, 0, .1); + + &:hover { + background-color: rgba(0, 0, 0, .3); + } + + .board-header-btn-icon.icon-star { + color: #e6bf00 !important; + } +} + +.board-header-btn-name { + cursor: default; + font-size: 18px; + font-weight: 700; + line-height: 30px; + padding-left: 4px; + text-decoration: none; + + .board-header-btn-text { + padding-left: 6px; + } +} + +.board-header-btn-name-org-logo { + border-radius: 3px; + height: 30px; + left: 0; + position: absolute; + top: 0; + width: 30px; + + .board-header-btn-text { + padding-left: 32px; + } +} + +.board-header-btn-org-name { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + max-width: 400px; +} + +.board-header-btn-filter-indicator { + background: #3d990f; + padding-right: 30px; + color: #fff; + text-shadow: 0; + + &:hover { + background: #43a711 !important; + } + + .board-header-btn-icon-close { + background: #43a711; + border-top-left-radius: 0; + border-top-right-radius: 3px; + border-bottom-right-radius: 3px; + border-bottom-left-radius: 0; + color: #fff; + padding: 6px; + position: absolute; + right: 0; + top: 0; + + &:hover { + background: #48b512; + } + } +} diff --git a/client/components/boards/helpers.js b/client/components/boards/helpers.js new file mode 100644 index 00000000..05be987d --- /dev/null +++ b/client/components/boards/helpers.js @@ -0,0 +1,45 @@ +Template.boards.helpers({ + boards: function() { + return Boards.find({}, { + sort: ['title'] + }); + }, + + starredBoards: function() { + var cursor = Boards.find({ + _id: { $in: Meteor.user().profile.starredBoards || [] } + }, { + sort: ['title'] + }); + return cursor.count() === 0 ? null : cursor; + }, + + isStarred: function() { + var user = Meteor.user(); + return user && user.hasStarred(this._id); + } +}); + +Template.boardChangePermissionPopup.helpers({ + check: function(perm) { + return this.permission === perm; + } +}); + +Template.boardChangeColorPopup.helpers({ + backgroundColors: function() { + return Boards.simpleSchema()._schema.color.allowedValues; + }, + + isSelected: function() { + var currentBoard = Boards.findOne(Session.get('currentBoard')); + return currentBoard.color === this.toString(); + } +}); + +Blaze.registerHelper('currentBoard', function() { + var boardId = Session.get('currentBoard'); + if (boardId) { + return Boards.findOne(boardId); + } +}); diff --git a/client/components/boards/list.jade b/client/components/boards/list.jade new file mode 100644 index 00000000..3a8fecd2 --- /dev/null +++ b/client/components/boards/list.jade @@ -0,0 +1,14 @@ +template(name="boards") + if boards + ul.board-list.clearfix + each boards + li(class="{{#if isStarred}}starred{{/if}}" class=colorClass) + a.js-open-board(href="{{ pathFor route='Board' boardId=_id }}") + span.details + span.board-list-item-name= title + i.fa.fa-star-o.js-star-board( + class="{{#if isStarred}}is-star-active{{/if}}" + title="{{_ 'star-board-title'}}") + else + p.quiet {{_ 'no-boards'}} + button.js-add-board {{_ 'add-board'}} diff --git a/client/components/boards/list.styl b/client/components/boards/list.styl new file mode 100644 index 00000000..c068dbb0 --- /dev/null +++ b/client/components/boards/list.styl @@ -0,0 +1,85 @@ +.board-list + margin: 25px auto + width: 1200px + + li + float: left + width: 25% + box-sizing: border-box + position: relative + + &.starred .fa-star-o + opacity: 1 + + a + background-color: #999 + color: #f6f6f6 + height: 90px + font-size: 16px + line-height: 22px + border-radius: 3px + display: block + font-weight: 700 + min-height: 18px + padding: 8px 12px 8px 12px + margin: 0 16px 16px 0 + position: relative + text-decoration: none + + &.tile + background-size: auto + background-repeat: repeat + + .details + height: 84px + padding-right: 36px + bottom: 0 + left: 0 + overflow: hidden + padding: 9px 12px + position: absolute + right: 0 + top: 0 + + .board-list-item-sub-name + color: rgba(255, 255, 255, .5) + display: block + font-size: 14px + font-weight: 400 + line-height: 22px + + .fa-star-o + bottom: 0 + font-size: 14px + height: 18px + line-height: 18px + opacity: 0 + padding: 9px 9px + position: absolute + right: 0 + top: 0 + transition-duration: .15s + transition-property: color, font-size, background + + .is-star-active + color: #e6bf00 + + li:hover a + color: #f6f6f6 + + .fa-star-o + color: #fff + opacity: .75 + + &:hover + font-size: 18px + opacity: 1 + + &.is-star-active + color: #e6bf00 + opacity: 1 + + &:hover + color: #ffd91a + font-size: 16px + opacity: 1 diff --git a/client/components/boards/router.js b/client/components/boards/router.js new file mode 100644 index 00000000..6845b7f2 --- /dev/null +++ b/client/components/boards/router.js @@ -0,0 +1,34 @@ +Meteor.subscribe('boards'); + +BoardSubsManager = new SubsManager(); + +Router.route('/boards', { + name: 'Boards', + template: 'boards', + authenticated: true, + onBeforeAction: function() { + Session.set('currentBoard', ''); + Filter.reset(); + this.next(); + } +}); + +Router.route('/boards/:_id/:slug', { + name: 'Board', + template: 'board', + onAfterAction: function() { + Session.set('sidebarIsOpen', true); + Session.set('currentWidget', 'home'); + Session.set('menuWidgetIsOpen', false); + }, + waitOn: function() { + var params = this.params; + Session.set('currentBoard', params._id); + Session.set('currentCard', null); + + return BoardSubsManager.subscribe('board', params._id, params.slug); + }, + data: function() { + return Boards.findOne(this.params._id); + } +}); |