Renaissance

_,,ad8888888888bba,_
                  ,ad88888I888888888888888ba,
                ,88888888I88888888888888888888a,
              ,d888888888I8888888888888888888888b,
             d88888PP"""" ""YY88888888888888888888b,
           ,d88"'__,,--------,,,,.;ZZZY8888888888888,
          ,8IIl'"                ;;l"ZZZIII8888888888,
         ,I88l;'                  ;lZZZZZ888III8888888,
       ,II88Zl;.                  ;llZZZZZ888888I888888,
      ,II888Zl;.                .;;;;;lllZZZ888888I8888b
     ,II8888Z;;                 `;;;;;''llZZ8888888I8888,
     II88888Z;'                        .;lZZZ8888888I888b
     II88888Z; _,aaa,      .,aaaaa,__.l;llZZZ88888888I888
     II88888IZZZZZZZZZ,  .ZZZZZZZZZZZZZZ;llZZ88888888I888,
     II88888IZZ<'(@@>Z|  |ZZZ<'(@@>ZZZZ;;llZZ888888888I88I
    ,II88888;   `""" ;|  |ZZ; `"""     ;;llZ8888888888I888
    II888888l            `;;          .;llZZ8888888888I888,
   ,II888888Z;           ;;;        .;;llZZZ8888888888I888I
   III888888Zl;    ..,   `;;       ,;;lllZZZ88888888888I888
   II88888888Z;;...;(_    _)      ,;;;llZZZZ88888888888I888,
   II88888888Zl;;;;;' `--'Z;.   .,;;;;llZZZZ88888888888I888b
   ]I888888888Z;;;;'   ";llllll;..;;;lllZZZZ88888888888I8888,
   II888888888Zl.;;"Y88bd888P";;,..;lllZZZZZ88888888888I8888I
   II8888888888Zl;.; `"PPP";;;,..;lllZZZZZZZ88888888888I88888
   II888888888888Zl;;. `;;;l;;;;lllZZZZZZZZW88888888888I88888
   `II8888888888888Zl;.    ,;;lllZZZZZZZZWMZ88888888888I88888
    II8888888888888888ZbaalllZZZZZZZZZWWMZZZ8888888888I888888,
    `II88888888888888888b"WWZZZZZWWWMMZZZZZZI888888888I888888b
     `II88888888888888888;ZZMMMMMMZZZZZZZZllI888888888I8888888
      `II8888888888888888 `;lZZZZZZZZZZZlllll888888888I8888888,
       II8888888888888888, `;lllZZZZllllll;;.Y88888888I8888888b,
      ,II8888888888888888b   .;;lllllll;;;.;..88888888I88888888b,
      II888888888888888PZI;.  .`;;;.;;;..; ...88888888I8888888888,
      II888888888888PZ;;';;.   ;. .;.  .;. .. Y8888888I88888888888b,
     ,II888888888PZ;;'                        `8888888I8888888888888b,
     II888888888'                              888888I8888888888888888
    ,II888888888                              ,888888I8888888888888888
   ,d88888888888                              d888888I8888888888ZZZZZZ
,ad888888888888I                              8888888I8888ZZZZZZZZZZZZ
888888888888888'                              888888IZZZZZZZZZZZZZZZZZ
8888888888P'8P'                               Y888ZZZZZZZZZZZZZZZZZZZZ
888888888,  "                                 ,ZZZZZZZZZZZZZZZZZZZZZZZ
8888888888,                                ,ZZZZZZZZZZZZZZZZZZZZZZZZZZ
888888888888a,      _                    ,ZZZZZZZZZZZZZZZZZZZZ88888888
888888888888888ba,_d'                  ,ZZZZZZZZZZZZZZZZZ8888888888888
8888888888888888888888bbbaaa,,,______,ZZZZZZZZZZZZZZZ88888888888888888
88888888888888888888888888888888888ZZZZZZZZZZZZZZZ88888888888888888888
8888888888888888888888888888888888ZZZZZZZZZZZZZZ8888888888888888888888
888888888888888888888888888888888ZZZZZZZZZZZZZZ88888888888888888888888
8888888888888888888888888888888ZZZZZZZZZZZZZZ8888888888888888888888888
88888888888888888888888888888ZZZZZZZZZZZZZZ888888888888888888888888888
8888888888888888888888888888ZZZZZZZZZZZZZZ88888888888888888 Normand  8
88888888888888888888888888ZZZZZZZZZZZZZZ8888888888888888888 Veilleux 8
8888888888888888888888888ZZZZZZZZZZZZZZ8888888888888888888888888888888
This commit is contained in:
Maxime Quandalle 2015-05-12 19:20:58 +02:00
commit 2dbea30842
128 changed files with 10521 additions and 0 deletions

View file

@ -0,0 +1,47 @@
template(name="cardSidebar")
.card-sidebar.sidebar
.card-detail.sidebar-content.js-card-sidebar-content
if cover
.card-detail-cover(style="background-image: url({{ card.cover.url }})")
.card-detail-header(class="{{#if currentUser.isBoardMember}}editable{{/if}}")
a.js-close-card-detail
i.fa.fa-times
h2.card-detail-title.js-card-title= title
p.card-detail-list.js-move-card
| {{_ 'in-list'}}
a.card-detail-list-title(
class="{{#if currentUser.isBoardMember}}js-open-move-from-header is-editable{{/if}}")
= list.title
hr
//- if card.members
.card-detail-item.card-detail-item-members.clearfix.js-card-detail-members
h3.card-detail-item-header {{_ 'members'}}
.js-card-detail-members-list.clearfix
each members
+userAvatar(userId=this size="small" cardId=../_id)
a.card-detail-item-add-button.dark-hover.js-details-edit-members
i.fa.fa-plus
//- We should use "editable" to avoide repetiting ourselves
.clearfix
if currentUser.isBoardMember
h3 Description
+inlinedForm(classNames="js-card-description")
i.fa.fa-times.js-close-inlined-form
textarea(autofocus)= description
button(type="submit") {{_ 'edit'}}
else
.js-open-inlined-form
a {{_ 'edit'}}
+viewer
= description
else if description
h3 Description
+viewer
= description
hr
if attachments.count
+WindowAttachmentsModule(card=this)
+WindowActivityModule(card=this)
template(name="moveCardPopup")
+boardLists

View file

@ -0,0 +1,103 @@
BlazeComponent.extendComponent({
template: function() {
return 'cardSidebar';
},
mixins: function() {
return [Mixins.InfiniteScrolling];
},
calculateNextPeak: function() {
var altitude = this.find('.js-card-sidebar-content').scrollHeight;
this.callFirstWith(this, 'setNextPeak', altitude);
},
reachNextPeak: function() {
var activitiesComponent = this.componentChildren('activities')[0];
activitiesComponent.loadNextPage();
},
events: function() {
return [{
'click .js-move-card': Popup.open('moveCard'),
'submit .js-card-description': function(evt) {
evt.preventDefault();
var cardId = Session.get('currentCard');
var form = this.componentChildren('inlinedForm')[0];
var newDescription = form.getValue();
Cards.update(cardId, {
$set: {
description: newDescription
}
});
form.close();
},
'click .js-close-card-detail': function() {
Utils.goBoardId(Session.get('currentBoard'));
},
'click .editable .js-card-title': function(event, t) {
var editable = t.$('.card-detail-title');
// add class editing and focus
$('.editing').removeClass('editing');
editable.addClass('editing');
editable.find('#title').focus();
},
'click .js-edit-desc': function(event, t) {
var editable = t.$('.card-detail-item');
// editing remove based and add current editing.
$('.editing').removeClass('editing');
editable.addClass('editing');
editable.find('#desc').focus();
event.preventDefault();
},
'click .js-cancel-edit': function(event, t) {
// remove editing hide.
$('.editing').removeClass('editing');
},
'submit #WindowTitleEdit': function(event, t) {
var title = t.find('#title').value;
if ($.trim(title)) {
Cards.update(this.card._id, {
$set: {
title: title
}
}, function (err, res) {
if (!err) $('.editing').removeClass('editing');
});
}
event.preventDefault();
},
'submit #WindowDescEdit': function(event, t) {
Cards.update(this.card._id, {
$set: {
description: t.find('#desc').value
}
}, function(err) {
if (!err) $('.editing').removeClass('editing');
});
event.preventDefault();
},
'click .member': Popup.open('cardMember'),
'click .js-details-edit-members': Popup.open('cardMembers'),
'click .js-details-edit-labels': Popup.open('cardLabels')
}];
}
}).register('cardSidebar');
Template.moveCardPopup.events({
'click .js-select-list': function() {
// XXX We should *not* get the currentCard from the global state, but
// instead from a “component” state.
var cardId = Session.get('currentCard');
var newListId = this._id;
Cards.update(cardId, {
$set: {
listId: newListId
}
});
}
});

View file

@ -0,0 +1,161 @@
@import 'nib'
.card-detail.sidebar-content
width: 496px - 2 * 20px
top: -46px !important
z-index: 20 !important
// XXX Animate apparition
.card-detail-header
background: #F7F7F7
border-bottom: 1px solid darken(white, 10%)
position: absolute
min-height: 38px
top: 0
left: 0
right: 0
padding 7px 20px 0
i.fa
float: right
font-size: 1.3em
color: darken(white, 35%)
margin-top: 7px
.card-detail-title
font-weight: bold
font-size: 1.7em
margin: 3px 0 0
padding: 0
.card-detail-list
font-size: 0.85em
margin-bottom: 3px
a.card-detail-list-title
font-weight: bold
&.is-editable
display: inline-block
background: darken(white, 10%)
border-radius: 3px
padding: 0px 5px
.new-comment
position: relative
margin: 0 0 20px 38px
.member
opacity: .7
position: absolute
top: 1px
left: -38px
.helper
bottom: 0
display: none
position: absolute
right: 9px
&.focus
.member
opacity: 1
.helper
display: inline-block
.new-comment-input
min-height: 108px
color: #4d4d4d
cursor: auto
overflow: hidden
word-wrap: break-word
.too-long
margin-top: 8px
.new-comment-input
background-color: #fff
border: 0
box-shadow: 0 1px 2px rgba(0, 0, 0, .23)
color: #8c8c8c
height: 36px
margin: 4px 4px 6px 0
padding: 9px 11px
width: 100%
&:hover,
&:focus
background-color: #fff
box-shadow: 0 1px 3px rgba(0, 0, 0, .33)
border: 0
cursor: pointer
&:focus
cursor: auto
.list-voters.compact .voter
position: relative
min-height: 36px
.member
left: 0
position: absolute
top: 0
.title
display: block
line-height: 30px
left: 0
overflow: hidden
padding-left: 38px
position: absolute
text-overflow: ellipsis
top: 0
white-space: nowrap
width: 230px
.list-voters .title
display: none
.card-composer
padding-bottom: 8px
.cc-controls
margin-top: 1px
input[type="submit"]
float: left
margin-top: 0
padding: 5px 18px
.icon-lg
float: left
.cc-opt
float: right
.minicard-placeholder,
.minicard.placeholder
background: silver
border: none
min-height: 18px
.hook
height: 18px
position: absolute
right: 0
top: 0
width: 18px
input[type="text"].attachment-add-link-input
float: left
margin: 0 0 8px
width: 80%
input[type="submit"].attachment-add-link-submit
float: left
margin: 0 0 8px 4px
padding: 6px 12px
width: 18%

View file

@ -0,0 +1,285 @@
// Template.cards.events({
// // 'click .js-cancel': function(event, t) {
// // var composer = t.$('.card-composer');
// // // Keep the old value in memory to display it again next time
// // var inputCacheKey = "addCard-" + this.listId;
// // var oldValue = composer.find('.js-card-title').val();
// // InputsCache.set(inputCacheKey, oldValue);
// // // add composer hide class
// // composer.addClass('hide');
// // composer.find('.js-card-title').val('');
// // // remove hide open link class
// // $('.js-open-card-composer').removeClass('hide');
// // },
// 'submit': function(evt, tpl) {
// evt.preventDefault();
// var textarea = $(evt.currentTarget).find('textarea');
// var title = textarea.val();
// var lastCard = tpl.find('.js-minicard:last-child');
// var sort;
// if (lastCard === null) {
// sort = 0;
// } else {
// sort = Blaze.getData(lastCard).sort + 1;
// }
// // debugger
// // Clear the form in-memory cache
// // var inputCacheKey = "addCard-" + this.listId;
// // InputsCache.set(inputCacheKey, '');
// // title trim if not empty then
// if ($.trim(title)) {
// Cards.insert({
// title: title,
// listId: Template.currentData().listId,
// boardId: Template.currentData().board._id,
// sort: sort
// }, function(err, _id) {
// // In case the filter is active we need to add the newly
// // inserted card in the list of exceptions -- cards that are
// // not filtered. Otherwise the card will disappear instantly.
// // See https://github.com/libreboard/libreboard/issues/80
// Filter.addException(_id);
// });
// // empty and focus.
// textarea.val('').focus();
// // focus complete then scroll top
// Utils.Scroll(tpl.find('.js-minicards')).top(1000, true);
// }
// }
// });
// Template.cards.events({
// 'click .member': Popup.open('cardMember')
// });
Template.cardMemberPopup.events({
'click .js-remove-member': function() {
Cards.update(this.cardId, {$pull: {members: this.userId}});
Popup.close();
}
});
Template.WindowActivityModule.events({
'click .js-new-comment:not(.focus)': function(evt) {
var $this = $(evt.currentTarget);
$this.addClass('focus');
},
'submit #CommentForm': function(evt, t) {
var text = t.$('.js-new-comment-input');
if ($.trim(text.val())) {
CardComments.insert({
boardId: this.card.boardId,
cardId: this.card._id,
text: text.val()
});
text.val('');
$('.focus').removeClass('focus');
}
evt.preventDefault();
}
});
Template.WindowSidebarModule.events({
'click .js-change-card-members': Popup.open('cardMembers'),
'click .js-edit-labels': Popup.open('cardLabels'),
'click .js-archive-card': function(evt) {
// Update
Cards.update(this.card._id, {
$set: {
archived: true
}
});
evt.preventDefault();
},
'click .js-unarchive-card': function(evt) {
Cards.update(this.card._id, {
$set: {
archived: false
}
});
evt.preventDefault();
},
'click .js-delete-card': Popup.afterConfirm('cardDelete', function() {
Cards.remove(this.card._id);
// redirect board
Utils.goBoardId(this.card.board()._id);
Popup.close();
}),
'click .js-more-menu': Popup.open('cardMore'),
'click .js-attach': Popup.open('cardAttachments')
});
Template.WindowAttachmentsModule.events({
'click .js-attach': Popup.open('cardAttachments'),
'click .js-confirm-delete': Popup.afterConfirm('attachmentDelete',
function() {
Attachments.remove(this._id);
Popup.close();
}
),
// If we let this event bubble, Iron-Router will handle it and empty the
// page content, see #101.
'click .js-open-viewer, click .js-download': function(event) {
event.stopPropagation();
},
'click .js-add-cover': function() {
Cards.update(this.cardId, { $set: { coverId: this._id } });
},
'click .js-remove-cover': function() {
Cards.update(this.cardId, { $unset: { coverId: '' } });
}
});
Template.cardMembersPopup.events({
'click .js-select-member': function(evt) {
var cardId = Template.parentData(2).data._id;
var memberId = this.userId;
var operation;
if (Cards.find({ _id: cardId, members: memberId}).count() === 0)
operation = '$addToSet';
else
operation = '$pull';
var query = {};
query[operation] = {
members: memberId
};
Cards.update(cardId, query);
evt.preventDefault();
}
});
Template.cardLabelsPopup.events({
'click .js-select-label': function(evt) {
var cardId = Template.parentData(2).data._id;
var labelId = this._id;
var operation;
if (Cards.find({ _id: cardId, labelIds: labelId}).count() === 0)
operation = '$addToSet';
else
operation = '$pull';
var query = {};
query[operation] = {
labelIds: labelId
};
Cards.update(cardId, query);
evt.preventDefault();
},
'click .js-edit-label': Popup.open('editLabel'),
'click .js-add-label': Popup.open('createLabel')
});
Template.formLabel.events({
'click .js-palette-color': function(evt) {
var $this = $(evt.currentTarget);
// hide selected ll colors
$('.js-palette-select').addClass('hide');
// show select color
$this.find('.js-palette-select').removeClass('hide');
}
});
Template.createLabelPopup.events({
// Create the new label
'submit .create-label': function(evt, tpl) {
var name = tpl.$('#labelName').val().trim();
var boardId = Session.get('currentBoard');
var selectLabelDom = tpl.$('.js-palette-select:not(.hide)').get(0);
var selectLabel = Blaze.getData(selectLabelDom);
Boards.update(boardId, {
$push: {
labels: {
_id: Random.id(6),
name: name,
color: selectLabel.color
}
}
});
Popup.back();
evt.preventDefault();
}
});
Template.editLabelPopup.events({
'click .js-delete-label': Popup.afterConfirm('deleteLabel', function() {
var boardId = Session.get('currentBoard');
Boards.update(boardId, {
$pull: {
labels: {
_id: this._id
}
}
});
Popup.back(2);
}),
'submit .edit-label': function(evt, tpl) {
var name = tpl.$('#labelName').val().trim();
var boardId = Session.get('currentBoard');
var getLabel = Utils.getLabelIndex(boardId, this._id);
var selectLabelDom = tpl.$('.js-palette-select:not(.hide)').get(0);
var selectLabel = Blaze.getData(selectLabelDom);
var $set = {};
// set label index
$set[getLabel.key('name')] = name;
// set color
$set[getLabel.key('color')] = selectLabel.color;
// update
Boards.update(boardId, { $set: $set });
// return to the previous popup view trigger
Popup.back();
evt.preventDefault();
},
'click .js-select-label': function() {
Cards.remove(this.cardId);
// redirect board
Utils.goBoardId(this.boardId);
}
});
Template.cardMorePopup.events({
'click .js-delete': Popup.afterConfirm('cardDelete', function() {
Cards.remove(this.card._id);
// redirect board
Utils.goBoardId(this.card.board()._id);
})
});
Template.cardAttachmentsPopup.events({
'change .js-attach-file': function(evt) {
var card = this.card;
FS.Utility.eachFile(evt, function(f) {
var file = new FS.File(f);
// set Ids
file.boardId = card.boardId;
file.cardId = card._id;
// upload file
Attachments.insert(file);
Popup.close();
});
},
'click .js-computer-upload': function(evt, t) {
t.find('.js-attach-file').click();
evt.preventDefault();
}
});

View file

@ -0,0 +1,48 @@
Template.cardMembersPopup.helpers({
isCardMember: function() {
var cardId = Template.parentData()._id;
var cardMembers = Cards.findOne(cardId).members || [];
return _.contains(cardMembers, this.userId);
},
user: function() {
return Users.findOne(this.userId);
}
});
Template.cardLabelsPopup.helpers({
isLabelSelected: function(cardId) {
return _.contains(Cards.findOne(cardId).labelIds, this._id);
}
});
var labelColors;
Meteor.startup(function() {
labelColors = Boards.simpleSchema()._schema['labels.$.color'].allowedValues;
});
Template.createLabelPopup.helpers({
// This is the default color for a new label. We search the first color that
// is not already used in the board (although it's not a problem if two
// labels have the same color).
defaultColor: function() {
var labels = this.labels || this.card.board().labels;
var usedColors = _.pluck(labels, 'color');
var availableColors = _.difference(labelColors, usedColors);
return availableColors.length > 1 ? availableColors[0] : 'green';
}
});
Template.formLabel.helpers({
labels: function() {
return _.map(labelColors, function(color) {
return { color: color, name: '' };
});
}
});
Blaze.registerHelper('currentCard', function() {
var cardId = Session.get('currentCard');
if (cardId) {
return Cards.findOne(cardId);
}
});

View file

@ -0,0 +1,183 @@
@import 'nib'
// XXX Use .board-widget-labels as a flexbox container
.card-label
background-color: #b3b3b3
border-radius: 4px
color: white
display: inline-block
font-weight: 700
font-size: 13px
margin-right: 4px
padding: 3px 8px
position:relative
max-width: 100%
min-width: 8px
overflow: ellipsis
height: 18px
&:hover
color: white
.card-label-green
background-color: #3cb500
.card-label-yellow
background-color: #fad900
.card-label-orange
background-color: #ff9f19
.card-label-red
background-color: #eb4646
.card-label-purple
background-color: #a632db
.card-label-blue
background-color: #0079bf
.card-label-pink
background-color: #ff78cb
.card-label-sky
background-color: #00c2e0
.card-label-black
background-color: #4d4d4d
.card-label-lime
background-color: #51e898
.edit-label,
.create-label
.card-label
float: left
height: 25px
margin: 0px 3% 7px 0px
width: 10.5%
cursor: pointer
.edit-labels
input[type="text"]
margin: 4px 0 6px 38px
width: 243px
.card-label
height: 30px
left: 0
padding: 1px 5px
position: absolute
top: 0
width: 24px
.labels-static .card-label
line-height: 30px
margin-bottom: 4px
position: relative
top: auto
left: 0
width: 260px
.minicard-labels
position: relative
z-index: 30
top: -6px
.card-label
border-radius: 0
float: left
height: 4px
margin-bottom: 1px
padding: 0
width: 40px
line-height: 100px
.card-detail-item-labels .card-label
border-radius: 3px
display: block
float: left
height: 20px
line-height: 20px
margin: 0 4px 4px 0
min-width: 30px
padding: 5px 10px
width: auto
.editable-labels .card-label:hover
cursor: pointer
opacity: .75
.edit-labels-pop-over
margin-bottom: 8px
.edit-labels-pop-over .shortcut
display: inline-block
.card-label-selectable
border-radius: 3px
cursor: pointer
margin: 0 50px 4px 0
min-height: 18px
padding: 8px
position: relative
transition: margin-right .1s
.card-label-selectable-icon
position: absolute
top: 8px
right: -20px
&.active:hover,
&.active,
&.active.selected:hover,
&.active.selected
margin-right: 38px
padding-right: 32px
.card-label-selectable-icon
right: 6px
&.active:hover:hover,
&.active:hover,
&.active.selected:hover:hover,
&.active.selected:hover
margin-right: 38px
&.selected,
&:hover
margin-right: 38px
opacity: .8
.active .card-label-selectable
&,
&:hover
margin-right: 0
.card-label-selectable-icon
right: 8px
.card-label-edit-button
border-radius: 3px
float: right
padding: 8px
&:hover
background: #dbdbdb
.card-label-color-select-icon
left: 14px
position: absolute
top: 9px
.phenom .card-label
display: inline-block
font-size: 12px
height: 14px
line-height: 13px
padding: 0 4px
min-width: 16px
overflow: ellipsis
.board-widget .phenom .card-label
max-width: 130px

View file

@ -0,0 +1,136 @@
.minicard
background-color: #fff
box-shadow: 0 1px 2px rgba(0,0,0,.2)
border-radius: 2px
cursor: pointer
margin-bottom: 9px
max-width: 300px
min-height: 20px
position: relative
z-index: 0
overflow: hidden
a
color: #4d4d4d
&.active-card
background-color: #f0f0f0
border-bottom-color: #c2c2c2
.minicard-operation
display: block
&.draggable-hover-card
background-color: #f0f0f0
border-bottom-color: #c2c2c2
.minicard-cover
background-position: center
background-repeat: no-repeat
background-size: cover
height: 145px
user-select: none
margin: -6px -8px 6px -8px
border-radius: top 2px
&.no-preview-size
background-size: auto
background-position: center
.minicard-details
padding: 6px 8px 2px
position: relative
z-index: 10
&.is-selected
.minicard-details
padding-bottom: 0
a.minicard-details
text-decoration:none
.minicard-details-overlay
background: transparent
bottom: 0
left: 0
position: absolute
right: 0
top: 0
.minicard-dropzone
display: none
.minicard.drophover .minicard-dropzone
background: rgba(255, 255, 255, .8)
// border-radius: 3px
// bottom: 0
// display: block
// font-weight: 700
// line-height: 100%
// left: 0
// margin: 0
// opacity: 1
// padding: 0
// position: absolute
// right: 0
// text-align: center
// top: 0
// z-index: 40
.minicard-title
display: block
font-weight: 400
margin: 0 0 4px
overflow: hidden
text-decoration: none
word-wrap: break-word
&::selection
background: transparent
.minicard-labels
padding-top: 3px
margin-top: 4px
float: right
.minicard-label
float: right
width: 8px
height: @width
border-radius: 2px
margin-left: 4px
.minicard-members
float: right
margin: 2px -8px -2px 0
.member
float: right
border-radius: 50%
height: 28px
width: @height
+ .badges
margin-top: 10px
.minicard-members:empty
display: none
.badges
float: left
&:empty
display: none
textarea.minicard-composer-textarea,
textarea.minicard-composer-textarea:focus
background: none
border: none
box-shadow: none
height: auto
margin-bottom: 4px
padding: 0
max-height: 162px
min-height: 54px
overflow-y: auto

View file

@ -0,0 +1,12 @@
template(name="cardMembersPopup")
//- input.js-search-mem(autofocus placeholder="Search members…" type="text")
ul.pop-over-member-list.checkable.js-mem-list
each board.members
li.item.js-member-item(class="{{#if isCardMember}}active{{/if}}")
a.name.js-select-member(href="#")
+userAvatar(user=user size="small")
span.full-name
= user.profile.name
| (<span class="username">{{ user.username }}</span>)
if isCardMember
i.fa.fa-check

View file

@ -0,0 +1,15 @@
Router.route('/boards/:boardId/:slug/:cardId', {
name: 'Card',
template: 'board',
waitOn: function() {
var params = this.params;
// XXX We probably shouldn't rely on Session
Session.set('currentBoard', params.boardId);
Session.set('currentCard', params.cardId);
return BoardSubsManager.subscribe('board', params.boardId, params.slug);
},
data: function() {
return Boards.findOne(this.params.boardId);
}
});

View file

@ -0,0 +1,336 @@
<template name="cardModal">
{{ > modal template='cardDetailWindow' card=this board=this.board }}
</template>
<template name="cardMemberPopup">
<div class="board-member-menu">
<div class="mini-profile-info">
{{> userAvatar user=user }}
<div class="info">
<h3 class="bottom" style="margin-right: 40px;">
<a class="js-profile" href="{{ pathFor route='Profile' username=user.username }}">{{ user.profile.name }}</a>
</h3>
<p class="quiet bottom">@{{ user.username }}</p>
</div>
</div>
{{# if currentUser.isBoardMember }}
<ul class="pop-over-list">
<li><a class="js-remove-member">{{_ 'remove-member-from-card'}}</a></li>
</ul>
{{/ if }}
</div>
</template>
<template name="cardMorePopup">
<p class="quiet bottom">
<span class="clearfix">
<span>{{_ 'link-card'}}</span>
<span class="icon-sm fa {{#if card.board.isPublic}}fa-globe{{else}}fa-lock{{/if}}"></span>
<input class="js-url js-autoselect inline-input" type="text" readonly="readonly" value="{{ card.rootUrl }}">
</span>
{{_ 'added'}} <span class="date" title="{{ card.createdAt }}">{{ moment card.createdAt 'LLL' }}</span> -
<a class="js-delete" href="#" title="{{_ 'card-delete-notice'}}">{{_ 'delete'}}</a>
</p>
</template>
<template name="cardLabelsPopup">
<div>
{{! <input id="labelSearch" name="search" class="js-autofocus js-label-search" placeholder="Search labels…" value="" type="text"> }}
<ul class="edit-labels-pop-over js-labels-list">
{{# each card.board.labels }}
<li>
<a href="#" class="card-label-edit-button icon-sm fa fa-pencil js-edit-label"></a>
<span class="card-label card-label-selectable card-label-{{color}} js-select-label {{# if isLabelSelected ../card._id }}active{{/ if }}">
{{name}}
{{# if currentUser.isBoardAdmin }}
<span class="card-label-selectable-icon icon-sm fa fa-check light"></span>
{{/ if }}
</span>
</li>
{{/ each}}
</ul>
<a class="quiet-button full js-add-label">{{_ 'label-create'}}</a>
</div>
</template>
<template name="cardAttachmentsPopup">
<div>
<ul class="pop-over-list">
<li>
<input type="file" name="file" class="js-attach-file hide" multiple>
<a class="js-computer-upload" href="#">
{{_ 'computer'}}
</a>
</li>
</ul>
</div>
</template>
<template name="formLabel">
<div class="colors clearfix">
<label for="labelName">{{_ 'name'}}</label>
<input id="labelName" type="text" name="name" class="js-label-name" value='{{ name }}' autofocus>
<label>{{_ "select-color"}}</label>
{{# each labels }}
<span class="card-label card-label--selectable card-label-{{ color }} palette-color js-palette-color">
<span class="card-label-color-select-icon icon-sm fa fa-check light js-palette-select {{#if $neq color ../color}}hide{{/if}}"></span>
</span>
{{/each}}
</div>
</template>
<template name="createLabelPopup">
<form class="create-label">
{{#with color=defaultColor}}
{{> formLabel}}
{{/with}}
<input type="submit" class="primary wide left" value="{{_ 'create'}}">
</form>
</template>
<template name="editLabelPopup">
<form class="edit-label">
{{> formLabel}}
<input type="submit" class="primary wide left" value="{{_ 'save'}}">
<span class="right">
<input type="submit" value="{{_ 'delete'}}" class="negate js-delete-label">
</span>
</form>
</template>
<template name="deleteLabelPopup">
<p>{{_ "label-delete-pop"}}</p>
<input type="submit" class="js-confirm negate full" value="{{_ 'delete'}}">
</template>
<template name="cardDeletePopup">
<p>{{_ "card-delete-pop"}}</p>
<input type="submit" class="js-confirm negate full" value="{{_ 'delete'}}">
</template>
<template name="attachmentDeletePopup">
<p>{{_ "attachment-delete-pop"}}</p>
<input type="submit" class="js-confirm negate full" value="{{_ 'delete'}}">
</template>
<template name="cardDetailSidebarOld">
<div class="card-detail-window clearfix">
{{# if card.cover }}
<div class="window-cover js-card-cover-box js-open-card-cover-in-viewer has-cover" style="background-image: url({{ card.cover.url }}); background-color: rgb(119, 119, 119); background-size: contain;">
</div>
{{ /if }}
{{ #if card.archived }}
<div class="window-archive-banner js-archive-banner">
<span class="icon-lg fa fa-archive window-archive-banner-icon"></span>
<p class="window-archive-banner-text">{{_ "card-archived"}}</p>
</div>
{{ /if }}
<div class="window-header clearfix">
<span class="window-header-icon icon-lg fa fa-calendar-o"></span>
<div class="window-title card-detail-title non-empty inline {{# if currentUser.isBoardMember }}editable{{/ if }}">
<h2 class="window-title-text current hide-on-edit js-card-title">{{ card.title }}</h2>
<div class="edit edit-heavy">
<form id="WindowTitleEdit">
<textarea type="text" class="field single-line" id="title">{{ card.title }}</textarea>
<div class="edit-controls clearfix">
<input type="submit" class="primary confirm js-title-save-edit" value="{{_ 'save'}}">
<a href="#" class="icon-lg fa fa-times dark-hover cancel js-cancel-edit"></a>
</div>
</form>
</div>
<div class="quiet hide-on-edit window-header-inline-content js-current-list">
<p class="inline-block bottom">
{{_ 'in-list'}}
<a href="#" class="{{# if currentUser.isBoardMember }}js-open-move-from-header{{else}}disabled{{/ if }}"><strong>{{ card.list.title }}</strong></a>
</p>
</div>
</div>
</div>
<div class="window-main-col clearfix">
<div class="card-detail-data gutter clearfix">
<div class="card-detail-item card-detail-item-block clear clearfix editable">
{{# if card.members }}
<div class="card-detail-item card-detail-item-members clearfix js-card-detail-members">
<h3 class="card-detail-item-header">{{_ 'members'}}</h3>
<div class="js-card-detail-members-list clearfix">
{{# each card.members }}
{{> userAvatar userId=this size="small" cardId=../card._id }}
{{/ each }}
<a class="card-detail-item-add-button dark-hover js-details-edit-members">
<span class="icon-sm fa fa-plus"></span>
</a>
</div>
</div>
{{/ if }}
{{# if card.labels }}
<div class="card-detail-item card-detail-item-labels clearfix js-card-detail-labels">
<h3 class="card-detail-item-header">{{_ 'labels'}}</h3>
<div class="js-card-detail-labels-list clearfix editable-labels js-edit-label">
{{# each card.labels }}
<span class="card-label card-label-{{color}}" title="{{name}}">{{ name }}</span>
{{/ each }}
<a class="card-detail-item-add-button dark-hover js-details-edit-labels">
<span class="icon-sm fa fa-plus"></span>
</a>
</div>
</div>
{{/ if }}
<div class="card-detail-item card-detail-item-block clear clearfix editable" attr="desc">
{{# if card.description }}
<h3 class="card-detail-item-header js-show-with-desc">{{_ 'description'}}</h3>
{{# if currentUser.isBoardMember }}
<a href="#" class="card-detail-item-header-edit hide-on-edit js-show-with-desc js-edit-desc">{{_ 'edit'}}</a>
{{/ if }}
<div class="current markeddown hide-on-edit js-card-desc js-show-with-desc">
{{#viewer}}{{ card.description }}{{/viewer}}
</div>
{{ else }}
{{# if currentUser.isBoardMember }}
<p class="bottom">
<a href="#" class="hide-on-edit quiet-button w-img js-edit-desc js-hide-with-desc">
<span class="icon-sm fa fa-align-left"></span>
{{_ 'edit-description'}}
</a>
</p>
{{/ if }}
{{/ if }}
<div class="card-detail-edit edit">
<form id="WindowDescEdit">
{{#editor class="field single-line2" id="desc"}}{{ card.description }}{{/editor}}
<div class="edit-controls clearfix">
<input type="submit" class="primary confirm js-title-save-edit" value="{{_ 'save'}}">
<a href="#" class="icon-lg fa fa-times dark-hover cancel js-cancel-edit"></a>
</div>
</form>
</div>
</div>
</div>
</div>
{{# if card.attachments.count }}
{{ > WindowAttachmentsModule card=card }}
{{/ if}}
{{ > WindowActivityModule card=card }}
</div>
{{# if currentUser.isBoardMember }}
{{ > WindowSidebarModule card=card }}
{{/if}}
</div>
</template>
<template name="WindowActivityModule">
<div class="card-detailwindow-module">
<div class="window-module-title window-module-title-no-divider">
<span class="window-module-title-icon icon-lg fa fa-comments-o"></span>
<h3>{{ _ 'activity'}}</h3>
</div>
{{# if currentUser.isBoardMember }}
<div class="new-comment js-new-comment">
{{> userAvatar user=currentUser size="small" class="member-no-menu" }}
<form id="CommentForm">
{{#editor class="new-comment-input js-new-comment-input"}}{{/editor}}
<div class="add-controls clearfix">
<input type="submit" class="primary confirm clear js-add-comment" value="{{_ 'comment'}}" tabindex="2">
</div>
</form>
</div>
{{/ if }}
{{ > activities mode="card" }}
</div>
</template>
<template name="WindowAttachmentsModule">
<div class="window-module js-attachments-section clearfix">
<div class="window-module-title window-module-title-no-divider">
<span class="window-module-title-icon icon-lg fa fa-paperclip"></span>
<h3 class="inline-block">{{_ 'attachments'}}</h3>
</div>
<div class="gutter">
<div class="clearfix js-attachment-list">
{{# each card.attachments }}
<div class="attachment-thumbnail">
{{# if isUploaded }}
<a href="{{ url download=true }}" class="attachment-thumbnail-preview js-open-viewer attachment-thumbnail-preview-is-cover">
{{# if isImage }}
<img src="{{ url }}">
{{ else }}
<span class="attachment-thumbnail-preview-ext">{{ extension }}</span>
{{ /if }}
</a>
<p class="attachment-thumbnail-details js-open-viewer">
<a href="" class="attachment-thumbnail-details-title js-attachment-thumbnail-details">
{{ name }}
<span class="block quiet">
{{_ 'added'}} <span class="date">{{ moment uploadedAt }}</span>
</span>
</a>
<span class="quiet attachment-thumbnail-details-options">
<a href="{{ url download=true }}" class="attachment-thumbnail-details-options-item dark-hover js-download">
<span class="icon-sm fa fa-download"></span>
<span class="attachment-thumbnail-details-options-item-text">{{_ 'download'}}</span>
</a>
{{# if isImage }}
<a class="attachment-thumbnail-details-options-item dark-hover {{#if $eq ../card.coverId _id}}js-remove-cover{{else}}js-add-cover{{/if}}">
<span class="icon-sm fa fa-thumb-tack"></span>
<span class="attachment-thumbnail-details-options-item-text">{{#if $eq ../card.coverId _id}}{{_ 'remove-cover'}}{{else}}{{_ 'add-cover'}}{{/if}}</span>
</a>
{{/if}}
<a href="#" class="attachment-thumbnail-details-options-item attachment-thumbnail-details-options-item-delete dark-hover js-confirm-delete">
<span class="icon-sm fa fa-close"></span>
<span class="attachment-thumbnail-details-options-item-text">{{_ 'delete'}}</span>
</a>
</span>
</p>
{{ else }}
+spinner
{{/ if }}
</div>
{{/each}}
</div>
<p>
<a href="#" class="quiet-button js-attach">{{_ 'add-attachment' }}</a>
</p>
</div>
</div>
</template>
<template name="WindowSidebarModule">
<div class="window-sidebar" style="position: relative;">
<div class="window-module clearfix">
<h3>{{_ 'add'}}</h3>
<div class="clearfix">
<a href="#" class="button-link js-change-card-members" title="{{_ 'members-title'}}">
<span class="icon-sm fa fa-user"></span> {{_ 'members'}}
</a>
<a href="#" class="button-link js-edit-labels" title="{{_ 'labels-title'}}">
<span class="icon-sm fa fa-tags"></span> {{_ 'labels'}}
</a>
<a href="#" class="button-link js-attach" title="{{_ 'attachment-title'}}">
<span class="icon-sm fa fa-paperclip"></span> {{_ 'attachment'}}
</a>
</div>
</div>
<div class="window-module other-actions clearfix">
<h3>{{_ 'actions'}}</h3>
<div class="clearfix">
<hr>
{{ #if card.archived }}
<a href="#" class="button-link js-unarchive-card" title="{{_ 'send-to-board-title'}}">
<span class="icon-sm fa fa-recycle"></span> {{_ 'send-to-board'}}
</a>
<a href="#" class="button-link negate js-delete-card" title="{{_ 'delete-title'}}">
<span class="icon-sm fa fa-trash-o"></span> {{_ 'delete'}}
</a>
{{ else }}
<a href="#" class="button-link js-archive-card" title="{{_ 'archive-title'}}">
<span class="icon-sm fa fa-archive"></span> {{_ 'archive'}}
</a>
{{ /if }}
</div>
</div>
<div class="window-module clearfix">
<p class="quiet bottom">
<a href="#" class="quiet-button js-more-menu" title="{{_ 'share-and-more-title'}}">{{_ 'share-and-more'}}</a>
</p>
</div>
</div>
</template>