From f4c80d1315c181300bd37ef5de98c365325bc130 Mon Sep 17 00:00:00 2001 From: Maxime Quandalle Date: Sat, 30 May 2015 15:50:48 +0200 Subject: Implement presence indicators --- client/components/sidebar/sidebar.jade | 3 +- client/components/users/avatar.jade | 7 -- client/components/users/events.js | 53 ------------- client/components/users/form.styl | 50 ------------ client/components/users/headerButtons.jade | 23 ------ client/components/users/headerButtons.js | 5 -- client/components/users/helpers.js | 27 ------- client/components/users/member.styl | 107 -------------------------- client/components/users/router.js | 1 - client/components/users/templates.html | 118 ----------------------------- client/components/users/userAvatar.jade | 23 ++++++ client/components/users/userAvatar.js | 22 ++++++ client/components/users/userAvatar.styl | 108 ++++++++++++++++++++++++++ client/components/users/userForm.styl | 49 ++++++++++++ client/components/users/userHeader.jade | 27 +++++++ client/components/users/userHeader.js | 39 ++++++++++ client/components/users/userProfile.html | 79 +++++++++++++++++++ client/components/users/userProfile.js | 31 ++++++++ client/config/router.js | 21 ++--- client/styles/temp.styl | 110 --------------------------- 20 files changed, 387 insertions(+), 516 deletions(-) delete mode 100644 client/components/users/avatar.jade delete mode 100644 client/components/users/events.js delete mode 100644 client/components/users/form.styl delete mode 100644 client/components/users/headerButtons.jade delete mode 100644 client/components/users/headerButtons.js delete mode 100644 client/components/users/helpers.js delete mode 100644 client/components/users/member.styl delete mode 100644 client/components/users/templates.html create mode 100644 client/components/users/userAvatar.jade create mode 100644 client/components/users/userAvatar.js create mode 100644 client/components/users/userAvatar.styl create mode 100644 client/components/users/userForm.styl create mode 100644 client/components/users/userHeader.jade create mode 100644 client/components/users/userHeader.js create mode 100644 client/components/users/userProfile.html create mode 100644 client/components/users/userProfile.js delete mode 100644 client/styles/temp.styl (limited to 'client') diff --git a/client/components/sidebar/sidebar.jade b/client/components/sidebar/sidebar.jade index 9dd47b0d..40e0dae3 100644 --- a/client/components/sidebar/sidebar.jade +++ b/client/components/sidebar/sidebar.jade @@ -31,10 +31,11 @@ template(name="membersWidget") userId=this.userId draggable=true size="small" - showBadges=true) + showStatus=true) unless isSandstorm if currentUser.isBoardAdmin a.js-open-manage-board-members + .clearfix template(name="labelsWidget") .board-widget.board-widget-labels diff --git a/client/components/users/avatar.jade b/client/components/users/avatar.jade deleted file mode 100644 index 70ef69e0..00000000 --- a/client/components/users/avatar.jade +++ /dev/null @@ -1,7 +0,0 @@ -template(name="userAvatar") - .member(class="{{class}} {{# if draggable }}js-member{{else}}js-member-on-card-menu{{/if}}" - title="{{userData.profile.name}} ({{userData.username}})") - +avatar(user=userData size=size) - if showBadges - span.member-status(class="{{# if userData.profile.status}}active{{/if}}") - span.member-type(class=memberType) diff --git a/client/components/users/events.js b/client/components/users/events.js deleted file mode 100644 index b741532f..00000000 --- a/client/components/users/events.js +++ /dev/null @@ -1,53 +0,0 @@ -Template.memberMenuPopup.events({ - 'click .js-language': Popup.open('setLanguage'), - 'click .js-logout': function(evt) { - evt.preventDefault(); - - Meteor.logout(function() { - Router.go('Home'); - }); - } -}); - -Template.setLanguagePopup.events({ - 'click .js-set-language': function(evt) { - Users.update(Meteor.userId(), { - $set: { - 'profile.language': this.tag - } - }); - evt.preventDefault(); - } -}); - -Template.profileEditForm.events({ - 'click .js-edit-profile': function() { - Session.set('ProfileEditForm', true); - }, - 'click .js-cancel-edit-profile': function() { - Session.set('ProfileEditForm', false); - }, - 'submit #ProfileEditForm': function(evt, t) { - var name = t.find('#name').value; - var bio = t.find('#bio').value; - - // trim and update - if ($.trim(name)) { - Users.update(this.profile()._id, { - $set: { - 'profile.name': name, - 'profile.bio': bio - } - }, function() { - - // update complete close profileEditForm - Session.set('ProfileEditForm', false); - }); - } - evt.preventDefault(); - } -}); - -Template.memberName.events({ - 'click .js-show-mem-menu': Popup.open('user') -}); diff --git a/client/components/users/form.styl b/client/components/users/form.styl deleted file mode 100644 index 845c810d..00000000 --- a/client/components/users/form.styl +++ /dev/null @@ -1,50 +0,0 @@ -.at-form-landing-logo - width: 275px - margin: auto - margin-top: 50px - margin-top: 17vh - - img - width: 275px - - -.at-form - margin: auto - width: 275px - padding: 25px - margin-top: 20px - padding-bottom: 10px - background: #fff - border-radius: 3px - border: 1px solid #dbdbdb - border-bottom-color: #c2c2c2 - box-shadow: 0 1px 6px rgba(0, 0, 0, .3) - - .at-link - color: darken(#27AE60, 40%) - - label - margin-bottom: 3px - - input - width: 100% - - .at-title - background: #F7F7F7 - margin: -25px - padding: 15px 25px 5px - margin-bottom: 20px - border-bottom: 1px solid #dcdcdc - color: darken(white, 70%) - font-weight: bold - - .at-signup-link, - .at-signin-link, - .at-forgotPwd - font-size: 0.9em - margin-top: 15px - color: darken(white, 70%) - - .at-signUp, - .at-signIn - font-weight: bold diff --git a/client/components/users/headerButtons.jade b/client/components/users/headerButtons.jade deleted file mode 100644 index 0a2f64cf..00000000 --- a/client/components/users/headerButtons.jade +++ /dev/null @@ -1,23 +0,0 @@ -template(name="headerUserBar") - a#header-user-bar.js-open-header-member-menu - .header-user-bar-name - i.fa.fa-chevron-down - if currentUser.profile.name - = currentUser.profile.name - else - = currentUser.username - +userAvatar(user=currentUser) - -template(name="memberHeader") - a.header-member.js-open-header-member-menu - span= currentUser.profile.name - +userAvatar(user=currentUser size="small") - -template(name="memberMenuPopup") - ul.pop-over-list - li: a(href="{{pathFor route='Profile' username=currentUser.username}}") {{_ 'profile'}} - li: a.js-language {{_ 'language'}} - li: a(href = "{{pathFor route='Settings'}}") {{_ 'settings'}} - hr - ul.pop-over-list - li: a.js-logout {{_ 'log-out'}} diff --git a/client/components/users/headerButtons.js b/client/components/users/headerButtons.js deleted file mode 100644 index 70594fb5..00000000 --- a/client/components/users/headerButtons.js +++ /dev/null @@ -1,5 +0,0 @@ -Template.headerUserBar.events({ - 'click .js-sign-in': Popup.open('signup'), - 'click .js-log-in': Popup.open('login'), - 'click .js-open-header-member-menu': Popup.open('memberMenu') -}); diff --git a/client/components/users/helpers.js b/client/components/users/helpers.js deleted file mode 100644 index 33867298..00000000 --- a/client/components/users/helpers.js +++ /dev/null @@ -1,27 +0,0 @@ -Template.userAvatar.helpers({ - userData: function() { - if (! this.user) { - this.user = Users.findOne(this.userId); - } - return this.user; - }, - memberType: function() { - var userId = this.userId || this.user._id; - var user = Users.findOne(userId); - return user && user.isBoardAdmin() ? 'admin' : 'normal'; - } -}); - -Template.setLanguagePopup.helpers({ - languages: function() { - return _.map(TAPi18n.getLanguages(), function(lang, tag) { - return { - tag: tag, - name: lang.name - }; - }); - }, - isCurrentLanguage: function() { - return this.tag === TAPi18n.getLanguage(); - } -}); diff --git a/client/components/users/member.styl b/client/components/users/member.styl deleted file mode 100644 index 3dfdaa37..00000000 --- a/client/components/users/member.styl +++ /dev/null @@ -1,107 +0,0 @@ -@import 'nib' - -avatar-radius = 50% - -.member - border-radius: 3px - display: block - float: left - height: 30px - width: @height - margin: 0 4px 4px 0 - position: relative - cursor: pointer - user-select: none - z-index: 1 - text-decoration: none - border-radius: avatar-radius - - .avatar - height: 100% - width: @height - display: flex - align-items: center - justify-content: center - overflow: hidden - border-radius: avatar-radius - - .avatar-initials - font-weight: bold - max-width: 100% - max-height: 100% - font-size: 14px - line-height: 200% - background-color: #dbdbdb - color: #444444 - - .avatar-image - max-width: 100% - max-height: 100% - - .member-status - background-color: #b3b3b3 - border: 1px solid #fff - border-radius: 50% - height: 8px - width: @height - position: absolute - right: 0px - bottom: 0px - border: 1px solid white - - &.active - background: #64c464 - border-color: #daf1da - - &.idle - background: #e4e467 - border-color: #f7f7d4 - - &.disconnected - background: #bdbdbd - border-color: #ededed - - &.extra-small - .avatar-initials - font-size: 9px - width: 18px - height: 18px - line-height: 18px - - .avatar-image - width: 18px - height: 18px - - &.small - width: 30px - height: 30px - - .avatar-initials - font-size: 12px - line-height: 30px - - &.large - height: 85px - line-height: 85px - width: 85px - - .avatar - width: 85px - height: 85px - - .avatar-initials - font-size: 16px - font-weight: 700 - line-height: 85px - width: 85px - -.atMention - background: #dbdbdb - border-radius: 3px - padding: 1px 4px - margin: -1px 0 - display: inline-block - - &.me - background: #cfdfe8 - diff --git a/client/components/users/router.js b/client/components/users/router.js index d59e174d..6c4ab3b6 100644 --- a/client/components/users/router.js +++ b/client/components/users/router.js @@ -1,4 +1,3 @@ - _.each(['signIn', 'signUp', 'resetPwd', 'forgotPwd', 'enrollAccount', 'changePwd'], function(routeName) { AccountsTemplates.configureRoute(routeName, { diff --git a/client/components/users/templates.html b/client/components/users/templates.html deleted file mode 100644 index 5783eebf..00000000 --- a/client/components/users/templates.html +++ /dev/null @@ -1,118 +0,0 @@ - - - - - - - - - - - - diff --git a/client/components/users/userAvatar.jade b/client/components/users/userAvatar.jade new file mode 100644 index 00000000..a76c4617 --- /dev/null +++ b/client/components/users/userAvatar.jade @@ -0,0 +1,23 @@ +template(name="userAvatar") + .member(class="{{class}} {{# if draggable }}js-member{{else}}js-member-on-card-menu{{/if}}" + title="{{userData.profile.name}} ({{userData.username}})") + +avatar(user=userData size=size) + if showStatus + span.member-presence-status(class=presenceStatusClassName) + span.member-type(class=memberType) + + +template(name="userPopup") + .board-member-menu + .mini-profile-info + +userAvatar(user=user) + .info + h3.bottom + a.js-profile(href="{{ pathFor route='Profile' username=user.username }}")= user.profile.name + p.quiet.bottom @{{ user.username }} + +template(name="memberName") + a.inline-object.js-show-mem-menu(href="{{ pathFor route='Profile' username=user.username }}") + = user.profile.name + if username + | ({{ user.username }}) diff --git a/client/components/users/userAvatar.js b/client/components/users/userAvatar.js new file mode 100644 index 00000000..d7d221db --- /dev/null +++ b/client/components/users/userAvatar.js @@ -0,0 +1,22 @@ +Template.userAvatar.helpers({ + userData: function() { + if (! this.user) { + this.user = Users.findOne(this.userId); + } + return this.user; + }, + memberType: function() { + var userId = this.userId || this.user._id; + var user = Users.findOne(userId); + return user && user.isBoardAdmin() ? 'admin' : 'normal'; + }, + presenceStatusClassName: function() { + var userPresence = Presences.findOne({ userId: this.user._id }); + if (! userPresence) + return 'disconnected'; + else if (Session.equals('currentBoard', userPresence.state.currentBoardId)) + return 'active'; + else + return 'idle'; + } +}); diff --git a/client/components/users/userAvatar.styl b/client/components/users/userAvatar.styl new file mode 100644 index 00000000..dfe59143 --- /dev/null +++ b/client/components/users/userAvatar.styl @@ -0,0 +1,108 @@ +@import 'nib' + +avatar-radius = 50% + +.member + border-radius: 3px + display: block + float: left + height: 30px + width: @height + margin: 0 4px 4px 0 + position: relative + cursor: pointer + user-select: none + z-index: 1 + text-decoration: none + border-radius: avatar-radius + + .avatar + height: 100% + width: @height + display: flex + align-items: center + justify-content: center + overflow: hidden + border-radius: avatar-radius + + .avatar-initials + font-weight: bold + max-width: 100% + max-height: 100% + font-size: 14px + line-height: 200% + background-color: #dbdbdb + color: #444444 + + .avatar-image + max-width: 100% + max-height: 100% + + .member-presence-status + background-color: #b3b3b3 + border: 1px solid #fff + border-radius: 50% + height: 7px + width: @height + position: absolute + right: -1px + bottom: -1px + border: 1px solid white + z-index: 15 + + &.active + background: #64c464 + border-color: #daf1da + + &.idle + background: #e4e467 + border-color: #f7f7d4 + + &.disconnected + background: #bdbdbd + border-color: #ededed + + &.extra-small + .avatar-initials + font-size: 9px + width: 18px + height: 18px + line-height: 18px + + .avatar-image + width: 18px + height: 18px + + &.small + width: 30px + height: 30px + + .avatar-initials + font-size: 12px + line-height: 30px + + &.large + height: 85px + line-height: 85px + width: 85px + + .avatar + width: 85px + height: 85px + + .avatar-initials + font-size: 16px + font-weight: 700 + line-height: 85px + width: 85px + +.atMention + background: #dbdbdb + border-radius: 3px + padding: 1px 4px + margin: -1px 0 + display: inline-block + + &.me + background: #cfdfe8 + diff --git a/client/components/users/userForm.styl b/client/components/users/userForm.styl new file mode 100644 index 00000000..5ecef7aa --- /dev/null +++ b/client/components/users/userForm.styl @@ -0,0 +1,49 @@ +.at-form-landing-logo + width: 275px + margin: auto + margin-top: 50px + margin-top: 17vh + + img + width: 275px + +.at-form + margin: auto + width: 275px + padding: 25px + margin-top: 20px + padding-bottom: 10px + background: #fff + border-radius: 3px + border: 1px solid #dbdbdb + border-bottom-color: #c2c2c2 + box-shadow: 0 1px 6px rgba(0, 0, 0, .3) + + .at-link + color: darken(#27AE60, 40%) + + label + margin-bottom: 3px + + input + width: 100% + + .at-title + background: #F7F7F7 + margin: -25px + padding: 15px 25px 5px + margin-bottom: 20px + border-bottom: 1px solid #dcdcdc + color: darken(white, 70%) + font-weight: bold + + .at-signup-link, + .at-signin-link, + .at-forgotPwd + font-size: 0.9em + margin-top: 15px + color: darken(white, 70%) + + .at-signUp, + .at-signIn + font-weight: bold diff --git a/client/components/users/userHeader.jade b/client/components/users/userHeader.jade new file mode 100644 index 00000000..eb3d265c --- /dev/null +++ b/client/components/users/userHeader.jade @@ -0,0 +1,27 @@ +template(name="headerUserBar") + a#header-user-bar.js-open-header-member-menu + .header-user-bar-name + i.fa.fa-chevron-down + if currentUser.profile.name + = currentUser.profile.name + else + = currentUser.username + +userAvatar(user=currentUser) + +template(name="memberMenuPopup") + ul.pop-over-list + li: a(href="{{pathFor route='Profile' username=currentUser.username}}") {{_ 'profile'}} + li: a.js-language {{_ 'language'}} + li: a(href = "{{pathFor route='Settings'}}") {{_ 'settings'}} + hr + ul.pop-over-list + li: a.js-logout {{_ 'log-out'}} + +template(name="setLanguagePopup") + ul.pop-over-list + each languages + li(class="{{# if isCurrentLanguage}}active{{/if}}") + a.js-set-language + = name + if isCurrentLanguage + i.fa.fa-check diff --git a/client/components/users/userHeader.js b/client/components/users/userHeader.js new file mode 100644 index 00000000..3bb9e623 --- /dev/null +++ b/client/components/users/userHeader.js @@ -0,0 +1,39 @@ +Template.headerUserBar.events({ + 'click .js-open-header-member-menu': Popup.open('memberMenu') +}); + +Template.setLanguagePopup.helpers({ + languages: function() { + return _.map(TAPi18n.getLanguages(), function(lang, tag) { + return { + tag: tag, + name: lang.name + }; + }); + }, + isCurrentLanguage: function() { + return this.tag === TAPi18n.getLanguage(); + } +}); + +Template.memberMenuPopup.events({ + 'click .js-language': Popup.open('setLanguage'), + 'click .js-logout': function(evt) { + evt.preventDefault(); + + Meteor.logout(function() { + Router.go('Home'); + }); + } +}); + +Template.setLanguagePopup.events({ + 'click .js-set-language': function(evt) { + Users.update(Meteor.userId(), { + $set: { + 'profile.language': this.tag + } + }); + evt.preventDefault(); + } +}); diff --git a/client/components/users/userProfile.html b/client/components/users/userProfile.html new file mode 100644 index 00000000..3d1f8c9b --- /dev/null +++ b/client/components/users/userProfile.html @@ -0,0 +1,79 @@ + + + + + diff --git a/client/components/users/userProfile.js b/client/components/users/userProfile.js new file mode 100644 index 00000000..040abed0 --- /dev/null +++ b/client/components/users/userProfile.js @@ -0,0 +1,31 @@ +Template.profileEditForm.events({ + 'click .js-edit-profile': function() { + Session.set('ProfileEditForm', true); + }, + 'click .js-cancel-edit-profile': function() { + Session.set('ProfileEditForm', false); + }, + 'submit #ProfileEditForm': function(evt, t) { + var name = t.find('#name').value; + var bio = t.find('#bio').value; + + // trim and update + if ($.trim(name)) { + Users.update(this.profile()._id, { + $set: { + 'profile.name': name, + 'profile.bio': bio + } + }, function() { + + // update complete close profileEditForm + Session.set('ProfileEditForm', false); + }); + } + evt.preventDefault(); + } +}); + +Template.memberName.events({ + 'click .js-show-mem-menu': Popup.open('user') +}); diff --git a/client/config/router.js b/client/config/router.js index ed9a069d..8fa74bee 100644 --- a/client/config/router.js +++ b/client/config/router.js @@ -24,6 +24,13 @@ Router.configure({ return this.redirect('atSignIn'); } + // We want to execute our EscapeActions.executeLowerThan method any time the + // route is changed, but not if the stays the same but only the parameters + // change (eg when a user is navigation from a card A to a card B). Iron- + // Router onBeforeAction is a reactive context (which is a bad desig choice + // as explained in + // https://github.com/meteorhacks/flow-router#routercurrent-is-evil) so we + // need to use Tracker.nonreactive Tracker.nonreactive(function() { if (! options.noEscapeActions && ! (previousRoute && previousRoute.options.noEscapeActions)) @@ -35,17 +42,3 @@ Router.configure({ this.next(); } }); - -// We want to execute our EscapeActions.executeLowerThan method any time the -// route is changed, but not if the stays the same but only the parameters -// change (eg when a user is navigation from a card A to a card B). This is why -// we can’t put this function in the above `onBeforeAction` that is being run -// too many times, instead we register a dependency only on the route name and -// use Tracker.autorun. The following paragraph explains the problem quite well: -// https://github.com/meteorhacks/flow-router#routercurrent-is-evil -// Tracker.autorun(function(computation) { -// routeName.get(); -// if (! computation.firstRun) { -// EscapeActions.executeLowerThan('inlinedForm'); -// } -// }); diff --git a/client/styles/temp.styl b/client/styles/temp.styl deleted file mode 100644 index 9dab7802..00000000 --- a/client/styles/temp.styl +++ /dev/null @@ -1,110 +0,0 @@ -/** - * We should merge these declarations in the appropriate stylus files. - */ - -.dn { - display:none; -} - -.header-btn-btn { - padding-left:23px!important; -} - -.bgnone { - background:none!important; -} - -.tac { - text-align:center; - - h1 { - font-size: 2em; - } -} - -.tdn { - text-decoration:none; -} - -.header-member { - min-width:105px!important; - text-align:center; -} - -.primarys { - font-size:20px; - line-height: 1.44em; - padding: .6em 1.3em!important; - border-radius: 3px!important; - box-shadow: 0 2px 0 #4d4d4d!important; -} - -.layout-twothirds-center { - display: block; - max-width: 585px; - margin: 0 auto; - position: relative; - font-size:20px; - line-height: 100px; -} - -#WindowTitleEdit .single-line, .single-line2 { - overflow: hidden; - word-wrap: break-word; - resize: none; - height: 60px; -} - -.single-line2 { - overflow: hidden; - word-wrap: break-word; - resize: none; - height: 108px; -} - -#header-search { - float: left; - margin: 1px 8px 0 0; - position: relative; - z-index: 1; - - label { - display:none; - } - input[type="text"] { - background:rgba(255,255,255,0.5); - border-top-left-radius:3px; - border-top-right-radius:0; - border-bottom-right-radius:0; - border-bottom-left-radius:3px; - border:none; - float:left; - font-size:13px; - height:29px; - min-height:29px; - line-height:19px; - width:160px; - margin:0; - - &:hover{ - background:rgba(255,255,255,0.7); - } - - &:focus{ - background:#e8ebee; - -webkit-box-shadow:none; - box-shadow:none - } - } - - .header-btn{ - border-top-left-radius:0; - border-top-right-radius:3px; - border-bottom-right-radius:3px; - border-bottom-left-radius:0 - } - - input[type="submit"]{ - display:none - } -} -- cgit v1.2.3-1-g7c22