add a notification drawer like trello

This commit is contained in:
Jonathan Baird 2020-03-27 11:35:03 -06:00
parent 29d62440a5
commit 9819c9f801
20 changed files with 701 additions and 257 deletions

View file

@ -0,0 +1,10 @@
template(name='notification')
li.notification(class="{{#if read}}read{{/if}}")
.read-status
.materialCheckBox(class="{{#if read}}is-checked{{/if}}")
+notificationIcon(activityData)
.details
+activity(activity=activityData mode='none')
if read
.remove
a.fa.fa-trash

View file

@ -0,0 +1,28 @@
Template.notification.events({
'click .read-status .materialCheckBox'() {
const update = {};
update[`profile.notifications.${this.index}.read`] = this.read
? null
: Date.now();
Users.update(Meteor.userId(), { $set: update });
},
'click .remove a'() {
Meteor.user().removeNotification(this.activityData._id);
},
});
Template.notification.helpers({
mode: 'board',
isOfActivityType(activityId, type) {
const activity = Activities.findOne(activityId);
return activity && activity.activityType === type;
},
activityType(activityId) {
const activity = Activities.findOne(activityId);
return activity ? activity.activityType : '';
},
activityUser(activityId) {
const activity = Activities.findOne(activityId);
return activity && activity.userId;
},
});

View file

@ -0,0 +1,57 @@
#notifications-drawer
&.show-read .notification.read
display: flex
.notification
display: flex
float: none
padding: 12px 8px 8px
color: black
border-bottom: 1px solid #dbdbdb
&.read
display: none
.read-status
width: 30px
input
width: 24px
height: 24px
.activity-type
margin: 16px 0 0
width: 17px
height: 17px
font-size: 17px
display: block
color: #bbb
.details
width: calc(100% - 30px)
.activity
display: flex
.activity-desc
width: 100%;
.activity-comment
display: block
width: 100%
border-radius: 3px
background: #fff
text-decoration: none
box-shadow: 0 1px 2px rgba(0,0,0,0.2)
margin-top: 5px
padding: 5px
.activity-meta
display: block
font-size: 0.8em
color: #999
font-style: italic
.remove
a:hover
color #eb4646 !important

View file

@ -0,0 +1,53 @@
template(name='notificationIcon')
if($in activityType 'deleteAttachment' 'addAttachment')
i.fa.fa-paperclip.activity-type(title="attachment")
else if($in activityType 'createBoard' 'importBoard')
i.fa.fa-chalkboard.activity-type(title="board")
else if($in activityType 'createCard' 'importCard' 'moveCard')
+cardNotificationIcon
else if($in activityType 'moveCardBoard' 'archivedCard' 'restoredCard')
+cardNotificationIcon
//- $in can only handle up to 3 cases so we have to break this case over 2 cases... use a simple template to keep it
//- DRY and consistant
else if($in activityType 'addChecklist' 'removedChecklist' 'completeChecklist')
+checklistNotificationIcon
else if($in activityType 'uncompleteChecklist')
+checklistNotificationIcon
//- $in can only handle up to 3 cases so we have to break this case over 2 cases... use a simple template to keep it
//- DRY and consistant
else if($in activityType 'checkedItem' 'uncheckedItem' 'addChecklistItem' 'removedChecklistItem')
i.fa.fa-check-square.activity-type(title="checklist item")
else if($in activityType 'addComment')
i.fa.fa-comment-o.activity-type(title="comment")
else if($in activityType 'createCustomField' 'setCustomField' 'unsetCustomField')
i.fa.fa-code.activity-type(title="custom field")
else if($in activityType 'addedLabel' 'removedLabel')
i.fa.fa-tag.activity-type(title="label")
else if($in activityType 'createList' 'removeList' 'archivedList')
+listNotificationIcon
else if($in activityType 'importList')
+listNotificationIcon
//- $in can only handle up to 3 cases so we have to break this case over 2 cases... use a simple template to keep it
//- DRY and consistant
//- elswhere in the app we use fa-trello to indicate lists...
//- i personally like fa-columns a bit better
else if($in activityType 'unjoinMember' 'addBoardMember' 'joinMember' 'removeBoardMember')
i.fa.fa-user.activity-type(title="member")
else if($in activityType 'createSwimlane' 'archivedSwimlane')
i.fa.fa-th-large.activity-type(title="swimlane")
else
i.fa.fa-bug.activity-type(title="can't find icon for #{activityType}")
template(name='cardNotificationIcon')
i.fa.fa-clone.activity-type(title="card")
template(name='checklistNotificationIcon')
i.fa.fa-list.activity-type(title="checklist")
template(name='listNotificationIcon')
i.fa.fa-columns.activity-type(title="list")

View file

@ -0,0 +1,5 @@
template(name='notifications')
#notifications.board-header-btns.right
a.notifications-drawer-toggle.fa.fa-bell(class="{{#if $gt unreadNotifications 0}}alert{{/if}}")
if $.Session.get 'showNotificationsDrawer'
+notificationsDrawer(unreadNotifications=unreadNotifications)

View file

@ -0,0 +1,32 @@
// this hides the notifications drawer if anyone clicks off of the panel
Template.body.events({
click(event) {
if (
!$(event.target).is('#notifications *') &&
Session.get('showNotificationsDrawer')
) {
toggleNotificationsDrawer();
}
},
});
Template.notifications.helpers({
unreadNotifications() {
const notifications = Users.findOne(Meteor.userId()).notifications();
const unreadNotifications = _.filter(notifications, v => !v.read);
return unreadNotifications.length;
},
});
Template.notifications.events({
'click .notifications-drawer-toggle'() {
toggleNotificationsDrawer();
},
});
export function toggleNotificationsDrawer() {
Session.set(
'showNotificationsDrawer',
!Session.get('showNotificationsDrawer'),
);
}

View file

@ -0,0 +1,17 @@
#notifications
position: relative
.notifications-drawer-toggle
display: block
line-height: 28px
color: #f2f2f2
margin: 0 10px
width: 28px
height: 28px
text-align: center
border: 0
padding: 0
&.alert
background-color: #eb4646;

View file

@ -0,0 +1,16 @@
template(name='notificationsDrawer')
section#notifications-drawer(class="{{#if $.Session.get 'showReadNotifications'}}show-read{{/if}}")
.header
if $.Session.get 'showReadNotifications'
a.toggle-read Filter by Unread
else
a.toggle-read View All
h5 Notifications
if($gt unreadNotifications 0)
|(#{unreadNotifications})
a.fa.fa-times-thin.close
ul.notifications
each transformedProfile.notifications
+notification(activityData=activity index=dbIndex read=read)
if($gt unreadNotifications 0)
a.all-read Mark all as read

View file

@ -0,0 +1,38 @@
import { toggleNotificationsDrawer } from './notifications.js';
Template.notificationsDrawer.onCreated(function() {
Meteor.subscribe('notificationActivities');
Meteor.subscribe('notificationCards');
Meteor.subscribe('notificationUsers');
Meteor.subscribe('notificationsAttachments');
Meteor.subscribe('notificationChecklistItems');
Meteor.subscribe('notificationChecklists');
Meteor.subscribe('notificationComments');
Meteor.subscribe('notificationLists');
Meteor.subscribe('notificationSwimlanes');
});
Template.notificationsDrawer.helpers({
transformedProfile() {
return Users.findOne(Meteor.userId());
},
});
Template.notificationsDrawer.events({
'click .all-read'() {
const notifications = Meteor.user().profile.notifications;
for (const index in notifications) {
if (notifications.hasOwnProperty(index) && !notifications[index].read) {
const update = {};
update[`profile.notifications.${index}.read`] = Date.now();
Users.update(Meteor.userId(), { $set: update });
}
}
},
'click .close'() {
toggleNotificationsDrawer();
},
'click .toggle-read'() {
Session.set('showReadNotifications', !Session.get('showReadNotifications'));
},
});

View file

@ -0,0 +1,57 @@
belize = #2980b9
section#notifications-drawer
position: fixed
top: 28px
right: 0
width: 400px
background-color: #fafafa
box-shadow: 0 1px 2px rgba(0,0,0,0.15)
border-radius: 2px
max-height: calc(100vh - 28px - 36px)
color: black
padding-top 36px;
overflow: scroll
a:hover
color: belize !important
.header
position: fixed
top 28px
right 0
width calc(400px - 32px)
padding: 8px 16px
background: #ededed
border-bottom: 1px solid #dbdbdb
z-index 2
.toggle-read
position absolute
left 16px
top calc(50% - 8px)
color belize
h5
text-align: center
margin: 0
.close
position: absolute
top: calc(50% - 12px)
right: 12px
font-size: 24px
height: 24px
line-height: 24px
opacity 1
.all-read
color belize
background-color: #fafafa
margin 8px 16px 12px
display inline-block
ul.notifications
display: block
padding: 0px 16px
margin: 0