summaryrefslogtreecommitdiffstats
path: root/client/components
diff options
context:
space:
mode:
Diffstat (limited to 'client/components')
-rw-r--r--client/components/activities/activities.jade14
-rw-r--r--client/components/activities/activities.js4
-rw-r--r--client/components/activities/activities.styl8
-rw-r--r--client/components/boards/boardHeader.js2
-rw-r--r--client/components/cards/cardDate.jade20
-rw-r--r--client/components/cards/cardDate.js228
-rw-r--r--client/components/cards/cardDate.styl58
-rw-r--r--client/components/cards/cardDetails.jade17
-rw-r--r--client/components/cards/cardDetails.js5
-rw-r--r--client/components/cards/cardDetails.styl7
-rw-r--r--client/components/cards/checklists.jade61
-rw-r--r--client/components/cards/checklists.js89
-rw-r--r--client/components/cards/checklists.styl68
-rw-r--r--client/components/cards/minicard.jade13
-rw-r--r--client/components/cards/minicard.styl21
-rw-r--r--client/components/lists/list.js2
-rw-r--r--client/components/lists/listHeader.jade7
-rw-r--r--client/components/lists/listHeader.js14
-rw-r--r--client/components/main/layouts.styl5
-rw-r--r--client/components/sidebar/sidebar.jade9
-rw-r--r--client/components/sidebar/sidebar.js3
-rw-r--r--client/components/sidebar/sidebar.styl1
-rw-r--r--client/components/sidebar/sidebarFilters.jade13
-rw-r--r--client/components/users/userHeader.jade24
-rw-r--r--client/components/users/userHeader.js39
25 files changed, 714 insertions, 18 deletions
diff --git a/client/components/activities/activities.jade b/client/components/activities/activities.jade
index 9ff73864..fad147fc 100644
--- a/client/components/activities/activities.jade
+++ b/client/components/activities/activities.jade
@@ -26,6 +26,12 @@ template(name="boardActivities")
+viewer
= comment.text
+ if($eq activityType 'addChecklist')
+ | {{{_ 'activity-checklist-added' cardLink}}}.
+ .activity-checklist(href="{{ card.absoluteUrl }}")
+ +viewer
+ = checklist.title
+
if($eq activityType 'archivedCard')
| {{{_ 'activity-archived' cardLink}}}.
@@ -41,6 +47,9 @@ template(name="boardActivities")
if($eq activityType 'createList')
| {{_ 'activity-added' list.title boardLabel}}.
+ if($eq activityType 'removeList')
+ | {{_ 'activity-removed' title boardLabel}}.
+
if($eq activityType 'importBoard')
| {{{_ 'activity-imported-board' boardLabel sourceLink}}}.
@@ -103,6 +112,11 @@ template(name="cardActivities")
| {{{_ 'activity-attached' attachmentLink cardLabel}}}.
if attachment.isImage
img.attachment-image-preview(src=attachment.url)
+ if($eq activityType 'addChecklist')
+ | {{{_ 'activity-checklist-added' cardLabel}}}.
+ .activity-checklist
+ +viewer
+ = checklist.title
if($eq activityType 'addComment')
+inlinedForm(classNames='js-edit-comment')
diff --git a/client/components/activities/activities.js b/client/components/activities/activities.js
index 0bd6a272..6600849c 100644
--- a/client/components/activities/activities.js
+++ b/client/components/activities/activities.js
@@ -12,10 +12,12 @@ BlazeComponent.extendComponent({
const capitalizedMode = Utils.capitalize(mode);
const id = Session.get(`current${capitalizedMode}`);
const limit = this.page.get() * activitiesPerPage;
+ const user = Meteor.user();
+ const hideSystem = user ? user.hasHiddenSystemMessages() : false;
if (id === null)
return;
- this.subscribe('activities', mode, id, limit, () => {
+ this.subscribe('activities', mode, id, limit, hideSystem, () => {
this.loadNextPageLocked = false;
// If the sibear peak hasn't increased, that mean that there are no more
diff --git a/client/components/activities/activities.styl b/client/components/activities/activities.styl
index 1f0494c7..2285fc0a 100644
--- a/client/components/activities/activities.styl
+++ b/client/components/activities/activities.styl
@@ -26,6 +26,14 @@
margin-top: 5px
padding: 5px
+ .activity-checklist
+ display: block
+ border-radius: 3px
+ background: white
+ text-decoration: none
+ box-shadow: 0 1px 2px rgba(0,0,0,.2)
+ margin-top: 5px
+ padding: 5px
.activity-meta
font-size: 0.8em
color: darken(white, 40%)
diff --git a/client/components/boards/boardHeader.js b/client/components/boards/boardHeader.js
index b72bb162..a76b566a 100644
--- a/client/components/boards/boardHeader.js
+++ b/client/components/boards/boardHeader.js
@@ -33,7 +33,7 @@ Template.boardChangeTitlePopup.events({
const newDesc = tpl.$('.js-board-desc').val().trim();
if (newTitle) {
this.rename(newTitle);
- this.setDesciption(newDesc);
+ this.setDescription(newDesc);
Popup.close();
}
evt.preventDefault();
diff --git a/client/components/cards/cardDate.jade b/client/components/cards/cardDate.jade
new file mode 100644
index 00000000..a2a28bbd
--- /dev/null
+++ b/client/components/cards/cardDate.jade
@@ -0,0 +1,20 @@
+template(name="editCardDate")
+ .edit-card-date
+ form.edit-date
+ .fields
+ .left
+ label(for="date") {{_ 'date'}}
+ input.js-date-field#date(type="text" name="date" value=showDate placeholder=dateFormat autofocus)
+ .right
+ label(for="time") {{_ 'time'}}
+ input.js-time-field#time(type="text" name="time" value=showTime placeholder=timeFormat)
+ .js-datepicker
+ if error.get
+ .warning {{_ error.get}}
+ button.primary.wide.left.js-submit-date(type="submit") {{_ 'save'}}
+ button.js-delete-date.negate.wide.right.js-delete-date {{_ 'delete'}}
+
+template(name="dateBadge")
+ a.js-edit-date.card-date(title="{{showTitle}}" class="{{classes}}")
+ time(datetime="{{showISODate}}")
+ | {{showDate}}
diff --git a/client/components/cards/cardDate.js b/client/components/cards/cardDate.js
new file mode 100644
index 00000000..4d129e8e
--- /dev/null
+++ b/client/components/cards/cardDate.js
@@ -0,0 +1,228 @@
+// Edit start & due dates
+const EditCardDate = BlazeComponent.extendComponent({
+ template() {
+ return 'editCardDate';
+ },
+
+ onCreated() {
+ this.error = new ReactiveVar('');
+ this.card = this.data();
+ this.date = new ReactiveVar(moment.invalid());
+ },
+
+ onRendered() {
+ const $picker = this.$('.js-datepicker').datepicker({
+ todayHighlight: true,
+ todayBtn: 'linked',
+ language: TAPi18n.getLanguage(),
+ }).on('changeDate', function(evt) {
+ this.find('#date').value = moment(evt.date).format('L');
+ this.error.set('');
+ this.find('#time').focus();
+ }.bind(this));
+
+ if (this.date.get().isValid()) {
+ $picker.datepicker('update', this.date.get().toDate());
+ }
+ },
+
+ showDate() {
+ if (this.date.get().isValid())
+ return this.date.get().format('L');
+ return '';
+ },
+ showTime() {
+ if (this.date.get().isValid())
+ return this.date.get().format('LT');
+ return '';
+ },
+ dateFormat() {
+ return moment.localeData().longDateFormat('L');
+ },
+ timeFormat() {
+ return moment.localeData().longDateFormat('LT');
+ },
+
+ events() {
+ return [{
+ 'keyup .js-date-field'() {
+ // parse for localized date format in strict mode
+ const dateMoment = moment(this.find('#date').value, 'L', true);
+ if (dateMoment.isValid()) {
+ this.error.set('');
+ this.$('.js-datepicker').datepicker('update', dateMoment.toDate());
+ }
+ },
+ 'keyup .js-time-field'() {
+ // parse for localized time format in strict mode
+ const dateMoment = moment(this.find('#time').value, 'LT', true);
+ if (dateMoment.isValid()) {
+ this.error.set('');
+ }
+ },
+ 'submit .edit-date'(evt) {
+ evt.preventDefault();
+
+ // if no time was given, init with 12:00
+ const time = evt.target.time.value || moment(new Date().setHours(12, 0, 0)).format('LT');
+
+ const dateString = `${evt.target.date.value} ${time}`;
+ const newDate = moment(dateString, 'L LT', true);
+ if (newDate.isValid()) {
+ this._storeDate(newDate.toDate());
+ Popup.close();
+ }
+ else {
+ this.error.set('invalid-date');
+ evt.target.date.focus();
+ }
+ },
+ 'click .js-delete-date'(evt) {
+ evt.preventDefault();
+ this._deleteDate();
+ Popup.close();
+ },
+ }];
+ },
+});
+
+// editCardStartDatePopup
+(class extends EditCardDate {
+ onCreated() {
+ super.onCreated();
+ this.data().startAt && this.date.set(moment(this.data().startAt));
+ }
+
+ _storeDate(date) {
+ this.card.setStart(date);
+ }
+
+ _deleteDate() {
+ this.card.unsetStart();
+ }
+}).register('editCardStartDatePopup');
+
+// editCardDueDatePopup
+(class extends EditCardDate {
+ onCreated() {
+ super.onCreated();
+ this.data().dueAt && this.date.set(moment(this.data().dueAt));
+ }
+
+ onRendered() {
+ super.onRendered();
+ if (moment.isDate(this.card.startAt)) {
+ this.$('.js-datepicker').datepicker('setStartDate', this.card.startAt);
+ }
+ }
+
+ _storeDate(date) {
+ this.card.setDue(date);
+ }
+
+ _deleteDate() {
+ this.card.unsetDue();
+ }
+}).register('editCardDueDatePopup');
+
+
+// Display start & due dates
+const CardDate = BlazeComponent.extendComponent({
+ template() {
+ return 'dateBadge';
+ },
+
+ onCreated() {
+ const self = this;
+ self.date = ReactiveVar();
+ self.now = ReactiveVar(moment());
+ window.setInterval(() => {
+ self.now.set(moment());
+ }, 60000);
+ },
+
+ showDate() {
+ // this will start working once mquandalle:moment
+ // is updated to at least moment.js 2.10.5
+ // until then, the date is displayed in the "L" format
+ return this.date.get().calendar(null, {
+ sameElse: 'llll',
+ });
+ },
+
+ showISODate() {
+ return this.date.get().toISOString();
+ },
+});
+
+class CardStartDate extends CardDate {
+ onCreated() {
+ super.onCreated();
+ const self = this;
+ self.autorun(() => {
+ self.date.set(moment(self.data().startAt));
+ });
+ }
+
+ classes() {
+ if (this.date.get().isBefore(this.now.get(), 'minute') &&
+ this.now.get().isBefore(this.data().dueAt)) {
+ return 'current';
+ }
+ return '';
+ }
+
+ showTitle() {
+ return `${TAPi18n.__('card-start-on')} ${this.date.get().format('LLLL')}`;
+ }
+
+ events() {
+ return super.events().concat({
+ 'click .js-edit-date': Popup.open('editCardStartDate'),
+ });
+ }
+}
+CardStartDate.register('cardStartDate');
+
+class CardDueDate extends CardDate {
+ onCreated() {
+ super.onCreated();
+ const self = this;
+ self.autorun(() => {
+ self.date.set(moment(self.data().dueAt));
+ });
+ }
+
+ classes() {
+ if (this.now.get().diff(this.date.get(), 'days') >= 2)
+ return 'long-overdue';
+ else if (this.now.get().diff(this.date.get(), 'minute') >= 0)
+ return 'due';
+ else if (this.now.get().diff(this.date.get(), 'days') >= -1)
+ return 'almost-due';
+ return '';
+ }
+
+ showTitle() {
+ return `${TAPi18n.__('card-due-on')} ${this.date.get().format('LLLL')}`;
+ }
+
+ events() {
+ return super.events().concat({
+ 'click .js-edit-date': Popup.open('editCardDueDate'),
+ });
+ }
+}
+CardDueDate.register('cardDueDate');
+
+(class extends CardStartDate {
+ showDate() {
+ return this.date.get().format('l');
+ }
+}).register('minicardStartDate');
+
+(class extends CardDueDate {
+ showDate() {
+ return this.date.get().format('l');
+ }
+}).register('minicardDueDate');
diff --git a/client/components/cards/cardDate.styl b/client/components/cards/cardDate.styl
new file mode 100644
index 00000000..1631baa5
--- /dev/null
+++ b/client/components/cards/cardDate.styl
@@ -0,0 +1,58 @@
+.edit-card-date
+ .fields
+ .left
+ width: 56%
+ .right
+ width: 38%
+ .datepicker
+ width: 100%
+ table
+ width: 100%
+ border: none
+ border-spacing: 0
+ border-collapse: collapse
+ thead
+ background: none
+ td, th
+ box-sizing: border-box
+
+
+.card-date
+ display: block
+ border-radius: 4px
+ padding: 1px 3px
+
+ background-color: #dbdbdb
+ &:hover, &.is-active
+ background-color: #b3b3b3
+
+ &.current, &.almost-due, &.due, &.long-overdue
+ color: #fff
+
+ &.current
+ background-color: #5ba639
+ &:hover, &.is-active
+ background-color: darken(#5ba639, 10)
+
+ &.almost-due
+ background-color: #edc909
+ &:hover, &.is-active
+ background-color: darken(#edc909, 10)
+
+ &.due
+ background-color: #fa3f00
+ &:hover, &.is-active
+ background-color: darken(#fa3f00, 10)
+
+ &.long-overdue
+ background-color: #fd5d47
+ &:hover, &.is-active
+ background-color: darken(#fd5d47, 7)
+
+ time
+ &::before
+ font: normal normal normal 14px/1 FontAwesome
+ font-size: inherit
+ -webkit-font-smoothing: antialiased
+ content: "\f017" // clock symbol
+ margin-right: 0.3em \ No newline at end of file
diff --git a/client/components/cards/cardDetails.jade b/client/components/cards/cardDetails.jade
index 734fc7e3..cf113951 100644
--- a/client/components/cards/cardDetails.jade
+++ b/client/components/cards/cardDetails.jade
@@ -35,6 +35,17 @@ template(name="cardDetails")
a.card-label.add-label.js-add-labels(title="{{_ 'card-labels-title'}}")
i.fa.fa-plus
+ if startAt
+ .card-details-item.card-details-item-start
+ h3.card-details-item-title {{_ 'card-start'}}
+ +cardStartDate
+
+ if dueAt
+ .card-details-item.card-details-item-due
+ h3.card-details-item-title {{_ 'card-due'}}
+ +cardDueDate
+
+
//- XXX We should use "editable" to avoid repetiting ourselves
if currentUser.isBoardMember
h3.card-details-item-title {{_ 'description'}}
@@ -61,6 +72,10 @@ template(name="cardDetails")
h3.card-details-item-title {{_ 'description'}}
+viewer
= description
+
+ hr
+ +checklists(cardId = _id)
+
if attachments.count
hr
h2
@@ -91,6 +106,8 @@ template(name="cardDetailsActionsPopup")
li: a.js-members {{_ 'card-edit-members'}}
li: a.js-labels {{_ 'card-edit-labels'}}
li: a.js-attachments {{_ 'card-edit-attachments'}}
+ li: a.js-start-date {{_ 'editCardStartDatePopup-title'}}
+ li: a.js-due-date {{_ 'editCardDueDatePopup-title'}}
hr
ul.pop-over-list
li: a.js-move-card-to-top {{_ 'moveCardToTop-title'}}
diff --git a/client/components/cards/cardDetails.js b/client/components/cards/cardDetails.js
index b6f17c23..b7e0ef76 100644
--- a/client/components/cards/cardDetails.js
+++ b/client/components/cards/cardDetails.js
@@ -65,6 +65,9 @@ BlazeComponent.extendComponent({
[`${CSSEvents.transitionend} .js-card-details`]() {
this.isLoaded.set(true);
},
+ [`${CSSEvents.animationend} .js-card-details`]() {
+ this.isLoaded.set(true);
+ },
};
return [{
@@ -143,6 +146,8 @@ Template.cardDetailsActionsPopup.events({
'click .js-members': Popup.open('cardMembers'),
'click .js-labels': Popup.open('cardLabels'),
'click .js-attachments': Popup.open('cardAttachments'),
+ 'click .js-start-date': Popup.open('editCardStartDate'),
+ 'click .js-due-date': Popup.open('editCardDueDate'),
'click .js-move-card': Popup.open('moveCard'),
'click .js-move-card-to-top'(evt) {
evt.preventDefault();
diff --git a/client/components/cards/cardDetails.styl b/client/components/cards/cardDetails.styl
index d7d29551..f209862c 100644
--- a/client/components/cards/cardDetails.styl
+++ b/client/components/cards/cardDetails.styl
@@ -73,8 +73,13 @@
margin: 15px 0
.card-details-item
+ margin-right: 0.5em
+ &:last-child
+ margin-right: 0
&.card-details-item-labels,
- &.card-details-item-members
+ &.card-details-item-members,
+ &.card-details-item-start,
+ &.card-details-item-due
width: 50%
flex-shrink: 1
diff --git a/client/components/cards/checklists.jade b/client/components/cards/checklists.jade
new file mode 100644
index 00000000..987e6cd9
--- /dev/null
+++ b/client/components/cards/checklists.jade
@@ -0,0 +1,61 @@
+template(name="checklists")
+ h2 {{_ 'checklists'}}
+ .card-checklist-items
+ each checklist in currentCard.checklists
+ +checklistDetail(checklist = checklist)
+ +inlinedForm(classNames="js-add-checklist" cardId = cardId)
+ +addChecklistItemForm
+ else
+ a.js-open-inlined-form
+ i.fa.fa-plus
+ | {{_ 'add-checklist'}}...
+
+template(name="checklistDetail")
+ +inlinedForm(classNames="js-edit-checklist-title" checklist = checklist)
+ +editChecklistItemForm(checklist = checklist)
+ else
+ .checklist-title
+ .checkbox.fa.fa-check-square-o
+ a.js-delete-checklist {{_ "delete"}}...
+ span.checklist-stat(class="{{#if checklist.isFinished}}is-finished{{/if}}") {{checklist.finishedCount}}/{{checklist.itemCount}}
+ h2.title.js-open-inlined-form.is-editable {{checklist.title}}
+ +checklistItems(checklist = checklist)
+
+template(name="addChecklistItemForm")
+ textarea.js-add-checklist-item(rows='1' autofocus)
+ .edit-controls.clearfix
+ button.primary.confirm.js-submit-add-checklist-item-form(type="submit") {{_ 'save'}}
+ a.fa.fa-times-thin.js-close-inlined-form
+
+template(name="editChecklistItemForm")
+ textarea.js-edit-checklist-item(rows='1' autofocus)
+ if $eq type 'item'
+ = item.title
+ else
+ = checklist.title
+ .edit-controls.clearfix
+ button.primary.confirm.js-submit-edit-checklist-item-form(type="submit") {{_ 'save'}}
+ a.fa.fa-times-thin.js-close-inlined-form
+ span(title=createdAt) {{ moment createdAt }}
+ if currentUser.isBoardMember
+ a.js-delete-checklist-item {{_ "delete"}}...
+
+template(name="checklistItems")
+ .checklist-items
+ each item in checklist.items
+ +inlinedForm(classNames="js-edit-checklist-item" item = item checklist = checklist)
+ +editChecklistItemForm(type = 'item' item = item checklist = checklist)
+ else
+ +itemDetail(item = item checklist = checklist)
+ if currentUser.isBoardMember
+ +inlinedForm(classNames="js-add-checklist-item" checklist = checklist)
+ +addChecklistItemForm
+ else
+ a.add-checklist-item.js-open-inlined-form
+ i.fa.fa-plus
+ | {{_ 'add-checklist-item'}}...
+
+template(name='itemDetail')
+ .item
+ .check-box.materialCheckBox(class="{{#if item.isFinished }}is-checked{{/if}}")
+ .item-title.js-open-inlined-form.is-editable(class="{{#if item.isFinished }}is-checked{{/if}}") {{item.title}}
diff --git a/client/components/cards/checklists.js b/client/components/cards/checklists.js
new file mode 100644
index 00000000..5dac7bd3
--- /dev/null
+++ b/client/components/cards/checklists.js
@@ -0,0 +1,89 @@
+BlazeComponent.extendComponent({
+ addChecklist(event) {
+ event.preventDefault();
+ const textarea = this.find('textarea.js-add-checklist-item');
+ const title = textarea.value.trim();
+ const cardId = this.currentData().cardId;
+ Checklists.insert({
+ cardId,
+ title,
+ });
+ },
+
+ addChecklistItem(event) {
+ event.preventDefault();
+ const textarea = this.find('textarea.js-add-checklist-item');
+ const title = textarea.value.trim();
+ const checklist = this.currentData().checklist;
+ checklist.addItem(title);
+ },
+
+ editChecklist(event) {
+ event.preventDefault();
+ const textarea = this.find('textarea.js-edit-checklist-item');
+ const title = textarea.value.trim();
+ const checklist = this.currentData().checklist;
+ checklist.setTitle(title);
+ },
+
+ editChecklistItem(event) {
+ event.preventDefault();
+
+ const textarea = this.find('textarea.js-edit-checklist-item');
+ const title = textarea.value.trim();
+ const itemId = this.currentData().item._id;
+ const checklist = this.currentData().checklist;
+ checklist.editItem(itemId, title);
+ },
+
+ deleteItem() {
+ const checklist = this.currentData().checklist;
+ const item = this.currentData().item;
+ if (checklist && item && item._id) {
+ checklist.removeItem(item._id);
+ }
+ },
+
+ deleteChecklist() {
+ const checklist = this.currentData().checklist;
+ if (checklist && checklist._id) {
+ Checklists.remove(checklist._id);
+ }
+ },
+
+ pressKey(event) {
+ //If user press enter key inside a form, submit it, so user doesn't have to leave keyboard to submit a form.
+ if (event.keyCode === 13) {
+ event.preventDefault();
+ const $form = $(event.currentTarget).closest('form');
+ $form.find('button[type=submit]').click();
+ }
+ },
+
+ events() {
+ return [{
+ 'submit .js-add-checklist': this.addChecklist,
+ 'submit .js-edit-checklist-title': this.editChecklist,
+ 'submit .js-add-checklist-item': this.addChecklistItem,
+ 'submit .js-edit-checklist-item': this.editChecklistItem,
+ 'click .js-delete-checklist-item': this.deleteItem,
+ 'click .js-delete-checklist': this.deleteChecklist,
+ keydown: this.pressKey,
+ }];
+ },
+}).register('checklists');
+
+BlazeComponent.extendComponent({
+ toggleItem() {
+ const checklist = this.currentData().checklist;
+ const item = this.currentData().item;
+ if (checklist && item && item._id) {
+ checklist.toggleItem(item._id);
+ }
+ },
+ events() {
+ return [{
+ 'click .item .check-box': this.toggleItem,
+ }];
+ },
+}).register('itemDetail');
diff --git a/client/components/cards/checklists.styl b/client/components/cards/checklists.styl
new file mode 100644
index 00000000..885d7528
--- /dev/null
+++ b/client/components/cards/checklists.styl
@@ -0,0 +1,68 @@
+.js-add-checklist
+ color: #8c8c8c
+
+textarea.js-add-checklist-item, textarea.js-edit-checklist-item
+ overflow: hidden
+ word-wrap: break-word
+ resize: none
+ height: 34px
+
+.delete-text
+ color: #8c8c8c
+ text-decoration: underline
+ word-wrap: break-word
+ float: right
+ padding-top: 6px
+ &:hover
+ color: inherit
+
+.checklist-title
+ .checkbox
+ float: left
+ width: 30px
+ height 30px
+ font-size: 18px
+ line-height: 30px
+
+ .title
+ font-size: 18px
+ line-height: 30px
+
+ .checklist-stat
+ margin: 0 0.5em
+ float: right
+ padding-top: 6px
+ &.is-finished
+ color: #3cb500
+
+ .js-delete-checklist
+ @extends .delete-text
+
+.checklist-items
+ margin: 0 0 0.5em 1.33em
+
+ .item
+ line-height: 25px
+ font-size: 1.1em
+ margin-top: 3px
+ display: flex
+
+ .check-box
+ margin-top: 5px
+ &.is-checked
+ border-bottom: 2px solid #3cb500
+ border-right: 2px solid #3cb500
+
+ .item-title
+ padding-left: 10px;
+ &.is-checked
+ color: #8c8c8c
+ font-style: italic
+
+ .js-delete-checklist-item
+ @extends .delete-text
+ padding: 12px 0 0 0
+
+ .add-checklist-item
+ padding-top: 0.5em
+ display: inline-block
diff --git a/client/components/cards/minicard.jade b/client/components/cards/minicard.jade
index 1dfd2f8e..8b46ee74 100644
--- a/client/components/cards/minicard.jade
+++ b/client/components/cards/minicard.jade
@@ -14,7 +14,7 @@ template(name="minicard")
.badges
if comments.count
.badge(title="{{_ 'card-comments-title' comments.count }}")
- span.badge-icon.fa.fa-comment-o
+ span.badge-icon.fa.fa-comment-o.badge-comment
span.badge-text= comments.count
if description
.badge.badge-state-image-only(title=description)
@@ -23,3 +23,14 @@ template(name="minicard")
.badge
span.badge-icon.fa.fa-paperclip
span.badge-text= attachments.count
+ if startAt
+ .badge
+ +minicardStartDate
+ if dueAt
+ .badge
+ +minicardDueDate
+ if checklists.count
+ .badge(class="{{#if checklistFinished}}is-finished{{/if}}")
+ span.badge-icon.fa.fa-check-square-o
+ span.badge-text.check-list-text {{checklistFinishedCount}}/{{checklistItemCount}}
+
diff --git a/client/components/cards/minicard.styl b/client/components/cards/minicard.styl
index 0f6f8ad2..12a89785 100644
--- a/client/components/cards/minicard.styl
+++ b/client/components/cards/minicard.styl
@@ -91,15 +91,34 @@
margin-right: 11px
margin-bottom: 3px
font-size: 0.9em
+
+ &:last-of-type
+ margin-right: 0
.badge-icon,
.badge-text
- vertical-align: top
+ vertical-align: middle
+
+ &.is-finished
+ background: #3cb500
+ padding: 0px 3px
+ border-radius: 3px
+ color: white
+
+ .badge-icon,
+ .badge-text
+ vertical-align: middle//didn't figure why use top, it'd be easier to fill bg if it's middle. This was introduced in commit "91cfcf7b12b5e7c137c2e765b2c378dde6b82966" & "* Improve the design of the minicards badges" was mentioned.
+ &.badge-comment
+ margin-bottom: 0.1rem
.badge-text
font-size: 0.9em
padding-left: 2px
line-height: 14px
+ .check-list-text
+ padding-left: 0px
+ line-height: 12px
+
.minicard-members
float: right
diff --git a/client/components/lists/list.js b/client/components/lists/list.js
index e1909783..187d8ec3 100644
--- a/client/components/lists/list.js
+++ b/client/components/lists/list.js
@@ -44,7 +44,7 @@ BlazeComponent.extendComponent({
placeholder: 'minicard-wrapper placeholder',
start(evt, ui) {
ui.placeholder.height(ui.helper.height());
- EscapeActions.executeUpTo('popup');
+ EscapeActions.executeUpTo('popup-close');
boardComponent.setIsDragging(true);
},
stop(evt, ui) {
diff --git a/client/components/lists/listHeader.jade b/client/components/lists/listHeader.jade
index f9fe065f..29aa4282 100644
--- a/client/components/lists/listHeader.jade
+++ b/client/components/lists/listHeader.jade
@@ -6,6 +6,10 @@ template(name="listHeader")
h2.list-header-name(
class="{{#if currentUser.isBoardMember}}js-open-inlined-form is-editable{{/if}}")
= title
+ if showCardsCountForList cards.count
+ = cards.count
+ span.lowercase
+ | {{_ 'cards'}}
if currentUser.isBoardMember
if isWatching
i.list-header-watch-icon.fa.fa-eye
@@ -29,6 +33,9 @@ template(name="listActionPopup")
hr
ul.pop-over-list
li: a.js-close-list {{_ 'archive-list'}}
+ hr
+ ul.pop-over-list
+ li: a.js-remove-list {{_ 'remove-list'}}
template(name="boardLists")
ul.pop-over-list
diff --git a/client/components/lists/listHeader.js b/client/components/lists/listHeader.js
index c7ae8e62..f352022d 100644
--- a/client/components/lists/listHeader.js
+++ b/client/components/lists/listHeader.js
@@ -13,6 +13,14 @@ BlazeComponent.extendComponent({
return list.findWatcher(Meteor.userId());
},
+ limitToShowCardsCount() {
+ return Meteor.user().getLimitToShowCardsCount();
+ },
+
+ showCardsCountForList(count) {
+ return count > this.limitToShowCardsCount();
+ },
+
events() {
return [{
'click .js-open-list-menu': Popup.open('listAction'),
@@ -52,4 +60,10 @@ Template.listActionPopup.events({
this.archive();
Popup.close();
},
+ 'click .js-remove-list'(evt) {
+ const currentList = this;
+ evt.preventDefault();
+ Lists.remove(currentList._id);
+ Popup.close();
+ },
});
diff --git a/client/components/main/layouts.styl b/client/components/main/layouts.styl
index c515eed0..40f50cfd 100644
--- a/client/components/main/layouts.styl
+++ b/client/components/main/layouts.styl
@@ -374,3 +374,8 @@ a
.wrapper
height: 100%
margin: 0px
+
+.inline-input
+ height: 37px
+ margin: 8px 10px 0 0
+ width: 50px
diff --git a/client/components/sidebar/sidebar.jade b/client/components/sidebar/sidebar.jade
index 4f5586cb..f3fdd1bc 100644
--- a/client/components/sidebar/sidebar.jade
+++ b/client/components/sidebar/sidebar.jade
@@ -30,10 +30,13 @@ template(name="membersWidget")
.board-widget-content
each currentBoard.activeMembers
+userAvatar(userId=this.userId showStatus=true)
- unless isSandstorm
- if currentUser.isBoardAdmin
- a.member.add-member.js-manage-board-members
+ if isSandstorm
+ if currentUser.isBoardMember
+ a.member.add-member.sandstorm-powerbox-request-identity
i.fa.fa-plus
+ else if currentUser.isBoardAdmin
+ a.member.add-member.js-manage-board-members
+ i.fa.fa-plus
.clearfix
if isInvited
hr
diff --git a/client/components/sidebar/sidebar.js b/client/components/sidebar/sidebar.js
index 0af32f8f..f32a27c5 100644
--- a/client/components/sidebar/sidebar.js
+++ b/client/components/sidebar/sidebar.js
@@ -163,6 +163,9 @@ Template.membersWidget.helpers({
Template.membersWidget.events({
'click .js-member': Popup.open('member'),
'click .js-manage-board-members': Popup.open('addMember'),
+ 'click .sandstorm-powerbox-request-identity'() {
+ window.sandstormRequestIdentity();
+ },
'click .js-member-invite-accept'() {
const boardId = Session.get('currentBoard');
Meteor.user().removeInvite(boardId);
diff --git a/client/components/sidebar/sidebar.styl b/client/components/sidebar/sidebar.styl
index 9007af59..24abe990 100644
--- a/client/components/sidebar/sidebar.styl
+++ b/client/components/sidebar/sidebar.styl
@@ -51,6 +51,7 @@
.member, .card-label
margin-right: 7px
+ margin-top: 5px
.sidebar-list-item-description
flex: 1
diff --git a/client/components/sidebar/sidebarFilters.jade b/client/components/sidebar/sidebarFilters.jade
index 2b326493..9a9774bb 100644
--- a/client/components/sidebar/sidebarFilters.jade
+++ b/client/components/sidebar/sidebarFilters.jade
@@ -5,6 +5,12 @@
template(name="filterSidebar")
ul.sidebar-list
+ li(class="{{#if Filter.labelIds.isSelected undefined}}active{{/if}}")
+ a.name.js-toggle-label-filter
+ span.sidebar-list-item-description
+ | {{_ 'filter-no-label'}}
+ if Filter.labelIds.isSelected undefined
+ i.fa.fa-check
each currentBoard.labels
li
a.name.js-toggle-label-filter
@@ -18,6 +24,12 @@ template(name="filterSidebar")
i.fa.fa-check
hr
ul.sidebar-list
+ li(class="{{#if Filter.members.isSelected undefined}}active{{/if}}")
+ a.name.js-toggle-member-filter
+ span.sidebar-list-item-description
+ | {{_ 'filter-no-member'}}
+ if Filter.members.isSelected undefined
+ i.fa.fa-check
each currentBoard.activeMembers
with getUser userId
li(class="{{#if Filter.members.isSelected _id}}active{{/if}}")
@@ -86,4 +98,3 @@ template(name="disambiguateMultiMemberPopup")
template(name="moveSelectionPopup")
+boardLists
-
diff --git a/client/components/users/userHeader.jade b/client/components/users/userHeader.jade
index a71e7fc7..ad41e8aa 100644
--- a/client/components/users/userHeader.jade
+++ b/client/components/users/userHeader.jade
@@ -12,10 +12,11 @@ template(name="memberMenuPopup")
ul.pop-over-list
with currentUser
li: a.js-edit-profile {{_ 'edit-profile'}}
- li: a.js-change-avatar {{_ 'edit-avatar'}}
- li: a.js-change-password {{_ 'changePasswordPopup-title'}}
- li: a.js-change-language {{_ 'changeLanguagePopup-title'}}
- li: a.js-edit-notification {{_ 'editNotificationPopup-title'}}
+ li: a.js-change-settings {{_ 'change-settings'}}
+ li: a.js-change-avatar {{_ 'edit-avatar'}}
+ li: a.js-change-password {{_ 'changePasswordPopup-title'}}
+ li: a.js-change-language {{_ 'changeLanguagePopup-title'}}
+ li: a.js-edit-notification {{_ 'editNotificationPopup-title'}}
hr
ul.pop-over-list
li: a.js-logout {{_ 'log-out'}}
@@ -27,6 +28,8 @@ template(name="editProfilePopup")
input.js-profile-fullname(type="text" value=profile.fullname autofocus)
label
| {{_ 'username'}}
+ span.error.hide.username-taken
+ | {{_ 'error-username-taken'}}
input.js-profile-username(type="text" value=username)
label
| {{_ 'initials'}}
@@ -61,3 +64,16 @@ template(name="changeLanguagePopup")
= name
if isCurrentLanguage
i.fa.fa-check
+
+template(name="changeSettingsPopup")
+ ul.pop-over-list
+ li
+ a.js-toggle-system-messages
+ | {{_ 'hide-system-messages'}}
+ if hiddenSystemMessages
+ i.fa.fa-check
+ li
+ label.bold
+ | {{_ 'show-cards-minimum-count'}}
+ input#show-cards-count-at.inline-input.left(type="number" value="#{showCardsCountAt}" min="1" max="99" onkeydown="return false")
+ input.js-apply-show-cards-at.left(type="submit" value="{{_ 'apply'}}")
diff --git a/client/components/users/userHeader.js b/client/components/users/userHeader.js
index 10fdf699..98053ed1 100644
--- a/client/components/users/userHeader.js
+++ b/client/components/users/userHeader.js
@@ -5,6 +5,7 @@ Template.headerUserBar.events({
Template.memberMenuPopup.events({
'click .js-edit-profile': Popup.open('editProfile'),
+ 'click .js-change-settings': Popup.open('changeSettings'),
'click .js-change-avatar': Popup.open('changeAvatar'),
'click .js-change-password': Popup.open('changePassword'),
'click .js-change-language': Popup.open('changeLanguage'),
@@ -26,11 +27,18 @@ Template.editProfilePopup.events({
'profile.fullname': fullname,
'profile.initials': initials,
}});
- // XXX We should report the error to the user.
+
if (username !== Meteor.user().username) {
- Meteor.call('setUsername', username);
- }
- Popup.back();
+ Meteor.call('setUsername', username, function(error) {
+ const messageElement = tpl.$('.username-taken');
+ if (error) {
+ messageElement.show();
+ } else {
+ messageElement.hide();
+ Popup.back();
+ }
+ });
+ } else Popup.back();
},
});
@@ -82,3 +90,26 @@ Template.changeLanguagePopup.events({
evt.preventDefault();
},
});
+
+Template.changeSettingsPopup.helpers({
+ hiddenSystemMessages() {
+ return Meteor.user().hasHiddenSystemMessages();
+ },
+ showCardsCountAt() {
+ return Meteor.user().getLimitToShowCardsCount();
+ },
+});
+
+Template.changeSettingsPopup.events({
+ 'click .js-toggle-system-messages'() {
+ Meteor.call('toggleSystemMessages');
+ },
+ 'click .js-apply-show-cards-at'(evt, tpl) {
+ evt.preventDefault();
+ const minLimit = parseInt(tpl.$('#show-cards-count-at').val(), 10);
+ if (!isNaN(minLimit)) {
+ Meteor.call('changeLimitToShowCardsCount', minLimit);
+ Popup.back();
+ }
+ },
+});