diff options
Diffstat (limited to 'client/components/sidebar')
-rw-r--r-- | client/components/sidebar/events.js | 17 | ||||
-rw-r--r-- | client/components/sidebar/helpers.js | 14 | ||||
-rw-r--r-- | client/components/sidebar/sidebar.jade | 39 | ||||
-rw-r--r-- | client/components/sidebar/sidebar.js | 25 | ||||
-rw-r--r-- | client/components/sidebar/sidebar.styl | 30 | ||||
-rw-r--r-- | client/components/sidebar/sidebarFilters.jade | 57 | ||||
-rw-r--r-- | client/components/sidebar/sidebarFilters.js | 94 | ||||
-rw-r--r-- | client/components/sidebar/templates.html | 77 | ||||
-rw-r--r-- | client/components/sidebar/templates.html.old | 307 |
9 files changed, 282 insertions, 378 deletions
diff --git a/client/components/sidebar/events.js b/client/components/sidebar/events.js index 1067421f..a1aeb13a 100644 --- a/client/components/sidebar/events.js +++ b/client/components/sidebar/events.js @@ -1,20 +1,3 @@ -Template.filterSidebar.events({ - 'click .js-toggle-label-filter': function(event) { - Filter.labelIds.toogle(this._id); - Filter.resetExceptions(); - event.preventDefault(); - }, - 'click .js-toogle-member-filter': function(event) { - Filter.members.toogle(this._id); - Filter.resetExceptions(); - event.preventDefault(); - }, - 'click .js-clear-all': function(event) { - Filter.reset(); - event.preventDefault(); - } -}); - var getMemberIndex = function(board, searchId) { for (var i = 0; i < board.members.length; i++) { if (board.members[i].userId === searchId) diff --git a/client/components/sidebar/helpers.js b/client/components/sidebar/helpers.js index 15035bd4..9d3340ad 100644 --- a/client/components/sidebar/helpers.js +++ b/client/components/sidebar/helpers.js @@ -1,17 +1,3 @@ -var widgetTitles = { - filter: 'filter-cards', - background: 'change-background' -}; - -Template.sidebar.helpers({ - currentWidget: function() { - return Session.get('currentWidget') + 'Sidebar'; - }, - currentWidgetTitle: function() { - return TAPi18n.__(widgetTitles[Session.get('currentWidget')]); - } -}); - // Template.addMemberPopup.helpers({ // isBoardMember: function() { // var user = Users.findOne(this._id); diff --git a/client/components/sidebar/sidebar.jade b/client/components/sidebar/sidebar.jade index 07d6bbcf..9dd47b0d 100644 --- a/client/components/sidebar/sidebar.jade +++ b/client/components/sidebar/sidebar.jade @@ -4,49 +4,22 @@ template(name="sidebar") class="{{#if isTongueHidden}}is-hidden{{/if}}") i.fa.fa-chevron-left .sidebar-content.js-board-sidebar-content.js-perfect-scrollbar + unless isDefaultView + h2 + a.fa.fa-chevron-left.js-back-home + = getViewTitle +Template.dynamic(template=getViewTemplate) template(name='homeSidebar') +membersWidget - hr.clear + hr +labelsWidget - hr.clear + hr h3 i.fa.fa-comments-o | {{_ 'activities'}} +activities(mode="board") -template(name="filterSidebar") - ul.pop-over-label-list.checkable - each currentBoard.labels - li.item.matches-filter - a.name.js-toggle-label-filter - span.card-label(class="card-label-{{color}}") - span.full-name - if name - = name - else - span.quiet {{_ "label-default" color}} - if Filter.labelIds.isSelected _id}} - span.icon-sm.fa.fa-check - hr - ul.pop-over-member-list.checkable - each currentBoard.members - if isActive - with getUser userId - li.item.js-member-item( - class="{{#if Filter.members.isSelected _id}}active{{/if}}") - a.name.js-toogle-member-filter - +userAvatar(user=this size="small") - span.full-name - = profile.name - | (<span class="username">{{ username }}</span>) - if Filter.members.isSelected _id - span.icon-sm.fa.fa-check - hr - a.js-clear-all(class="{{#unless Filter.isActive}}disabled{{/unless}}") - | {{_ 'filter-clear'}} - template(name="membersWidget") .board-widget.board-widget-members h3 diff --git a/client/components/sidebar/sidebar.js b/client/components/sidebar/sidebar.js index b737e9de..777d72e1 100644 --- a/client/components/sidebar/sidebar.js +++ b/client/components/sidebar/sidebar.js @@ -1,6 +1,11 @@ +Sidebar = null; + var defaultView = 'home'; -Sidebar = null; +var viewTitles = { + filter: 'filter-cards', + multiselection: 'multi-selection' +}; BlazeComponent.extendComponent({ template: function() { @@ -60,14 +65,23 @@ BlazeComponent.extendComponent({ }, setView: function(view) { - view = view || defaultView; + view = _.isString(view) ? view : defaultView; this._view.set(view); + this.open(); + }, + + isDefaultView: function() { + return this.getView() === defaultView; }, getViewTemplate: function() { return this.getView() + 'Sidebar'; }, + getViewTitle: function() { + return TAPi18n.__(viewTitles[this.getView()]); + }, + // Board members can assign people or labels by drag-dropping elements from // the sidebar to the cards on the board. In order to re-initialize the // jquery-ui plugin any time a draggable member or label is modified or @@ -108,12 +122,13 @@ BlazeComponent.extendComponent({ // XXX Hacky, we need some kind of `super` var mixinEvents = this.getMixin(Mixins.InfiniteScrolling).events(); return mixinEvents.concat([{ - 'click .js-toogle-sidebar': this.toogle + 'click .js-toogle-sidebar': this.toogle, + 'click .js-back-home': this.setView }]); } }).register('sidebar'); EscapeActions.register('sidebarView', - function() { return Sidebar && Sidebar.getView() !== defaultView; }, - function() { Sidebar.setView(defaultView); } + function() { Sidebar.setView(defaultView); }, + function() { return Sidebar && Sidebar.getView() !== defaultView; } ); diff --git a/client/components/sidebar/sidebar.styl b/client/components/sidebar/sidebar.styl index a5bc3dc5..e24b7de2 100644 --- a/client/components/sidebar/sidebar.styl +++ b/client/components/sidebar/sidebar.styl @@ -7,7 +7,7 @@ right: 0 .sidebar-content - padding: 10px 20px + padding: 12px background: white box-shadow: -10px 0px 5px -10px darken(white, 30%) z-index: 10 @@ -23,7 +23,33 @@ color: darken(white, 50%) hr - margin: 8px 0 + margin: 13px 0 + + ul.sidebar-list + display: flex + flex-direction: column + + li a + display: flex + height: 30px + margin: 0 + padding: 4px + border-radius: 3px + align-items: center + + &:hover + &, i, .quiet + color white + + .member, .card-label + margin-right: 7px + + .sidebar-list-item-description + flex: 1 + overflow: ellipsis + + .fa.fa-check + margin: 0 4px .board-sidebar width: 248px diff --git a/client/components/sidebar/sidebarFilters.jade b/client/components/sidebar/sidebarFilters.jade new file mode 100644 index 00000000..34b3074f --- /dev/null +++ b/client/components/sidebar/sidebarFilters.jade @@ -0,0 +1,57 @@ +//- + XXX There is a *lot* of code duplication in the above templates and in the + corresponding JavaScript components. We will probably need the upcoming #let + and #each x in y constructors. + +template(name="filterSidebar") + ul.sidebar-list + each currentBoard.labels + li + a.name.js-toggle-label-filter + span.card-label.square(class="card-label-{{color}}") + span.sidebar-list-item-description + if name + = name + else + span.quiet {{_ "label-default" color}} + if Filter.labelIds.isSelected _id + i.fa.fa-check + hr + ul.sidebar-list + each currentBoard.members + if isActive + with getUser userId + li(class="{{#if Filter.members.isSelected _id}}active{{/if}}") + a.name.js-toogle-member-filter + +userAvatar(user=this size="small") + span.sidebar-list-item-description + = profile.name + | (<span class="username">{{ username }}</span>) + if Filter.members.isSelected _id + i.fa.fa-check + hr + a.js-clear-all(class="{{#unless Filter.isActive}}disabled{{/unless}}") + | {{_ 'filter-clear'}} + +template(name="multiselectionSidebar") + ul.sidebar-list + each currentBoard.labels + li + a.name.js-toggle-label-multiselection + span.card-label.square(class="card-label-{{color}}") + span.sidebar-list-item-description + if name + = name + else + span.quiet {{_ "label-default" color}} + if allSelectedElementHave 'label' _id + i.fa.fa-check + else if someSelectedElementHave 'label' _id + i.fa.fa-ellipsis-h + //- + XXX We should be able to assign a member to the list of selected cards. + +template(name="disambiguateMultiLabelPopup") + p What do you want to do? + button.wide.js-remove-label Remove the label + button.wide.js-add-label Add the label diff --git a/client/components/sidebar/sidebarFilters.js b/client/components/sidebar/sidebarFilters.js new file mode 100644 index 00000000..df0db529 --- /dev/null +++ b/client/components/sidebar/sidebarFilters.js @@ -0,0 +1,94 @@ +BlazeComponent.extendComponent({ + template: function() { + return 'filterSidebar'; + }, + + events: function() { + return [{ + 'click .js-toggle-label-filter': function(event) { + Filter.labelIds.toogle(this._id); + Filter.resetExceptions(); + event.preventDefault(); + }, + 'click .js-toogle-member-filter': function(event) { + Filter.members.toogle(this._id); + Filter.resetExceptions(); + event.preventDefault(); + }, + 'click .js-clear-all': function(event) { + Filter.reset(); + event.preventDefault(); + } + }]; + } +}).register('filterSidebar'); + +var updateSelectedCards = function(query) { + Cards.find(MultiSelection.getMongoSelector()).forEach(function(card) { + Cards.update(card._id, query); + }); +}; + +BlazeComponent.extendComponent({ + template: function() { + return 'multiselectionSidebar'; + }, + + mapSelection: function(kind, _id) { + return Cards.find(MultiSelection.getMongoSelector()).map(function(card) { + var methodName = kind === 'label' ? 'hasLabel' : 'isAssigned'; + return card[methodName](_id); + }); + }, + + allSelectedElementHave: function(kind, _id) { + if (MultiSelection.isEmpty()) + return false; + else + return _.every(this.mapSelection(kind, _id)); + }, + + someSelectedElementHave: function(kind, _id) { + if (MultiSelection.isEmpty()) + return false; + else + return _.some(this.mapSelection(kind, _id)); + }, + + events: function() { + return [{ + 'click .js-toggle-label-multiselection': function(evt, tpl) { + var labelId = this.currentData()._id; + var mappedSelection = this.mapSelection('label', labelId); + var operation; + if (_.every(mappedSelection)) + operation = '$pull'; + else if (_.every(mappedSelection, function(bool) { return ! bool; })) + operation = '$addToSet'; + else { + var popup = Popup.open('disambiguateMultiLabel'); + // XXX We need to have a better integration between the popup and the + // UI components systems. + return popup.call(this.currentData(), evt, tpl); + } + + var query = {}; + query[operation] = { + labelIds: labelId + }; + updateSelectedCards(query); + } + }]; + } +}).register('multiselectionSidebar'); + +Template.disambiguateMultiLabelPopup.events({ + 'click .js-remove-label': function() { + updateSelectedCards({$pull: {labelIds: this._id}}); + Popup.close(); + }, + 'click .js-add-label': function() { + updateSelectedCards({$addToSet: {labelIds: this._id}}); + Popup.close(); + } +}); diff --git a/client/components/sidebar/templates.html b/client/components/sidebar/templates.html new file mode 100644 index 00000000..12e7be0a --- /dev/null +++ b/client/components/sidebar/templates.html @@ -0,0 +1,77 @@ +<!-- XXX Translate these template into jade --> +<template name="closeBoardPopup"> + <p>{{_ 'close-board-pop'}}</p> + <input type="submit" class="js-confirm negate full" value="{{_ 'close'}}"> +</template> + +<template name="removeMemberPopup"> + <p>{{_ 'remove-member-pop' + name=user.profile.name + username=user.username + boardTitle=board.title}}</p> + <input type="submit" class="js-confirm negate full" value="{{_ 'remove-member'}}"> +</template> + +<template name="addMemberPopup"> + <div class="search-with-spinner"> + {{> esInput index="users" }} + </div> + + <div class="manage-member-section hide js-search-results" style="display: block;"> + <ul class="pop-over-member-list options js-list"> + {{# esEach index="users"}} + <li class="item js-member-item {{# if isBoardMember }}disabled{{/if}}"> + <a href="#" class="name js-select-member {{# if isBoardMember }}multi-line{{/if}}" title="{{ profile.name }} ({{ username }})"> + {{> userAvatar user=this size="small" }} + <span class="full-name"> + {{ profile.name }} (<span class="username">{{ username }}</span>) + </span> + {{# if isBoardMember }} + <div class="extra-text quiet">({{_ 'joined'}})</div> + {{/if}} + <span class="icon-sm fa fa-chevron-right light option js-open-option"></span> + </a> + </li> + {{/esEach }} + </ul> + </div> + + {{# ifEsIsSearching index='users' }} + <div class="tac"> + <span class="tabbed-pane-main-col-loading-spinner spinner"></span> + </div> + {{ /ifEsIsSearching }} + + {{# ifEsHasNoResults index="users" }} + <div class="manage-member-section js-no-results"> + <p class="quiet center" style="padding: 16px 4px;">{{_ 'no-results'}}</p> + </div> + {{ /ifEsHasNoResults }} + + <div class="manage-member-section js-helper"> + <p class="bottom quiet" style="padding: 6px;">{{_ 'search-member-desc'}}</p> + </div> +</template> + +<template name="changePermissionsPopup"> + <ul class="pop-over-list"> + <li> + <a class="{{#if isLastAdmin}}disabled{{else}}js-set-admin{{/if}}"> + {{_ 'admin'}} + {{#if isAdmin}}<span class="icon-sm fa fa-check"></span>{{/if}} + <span class="sub-name">{{_ 'admin-desc'}}</span> + </a> + </li> + <li> + <a class="{{#if isLastAdmin}}disabled{{else}}js-set-normal{{/if}}"> + {{_ 'normal'}} + {{#unless isAdmin}}<span class="icon-sm fa fa-check"></span>{{/unless}} + <span class="sub-name">{{_ 'normal-desc'}}</span> + </a> + </li> + </ul> + {{#if isLastAdmin}} + <hr> + <p class="quiet bottom">{{_ 'last-admin-desc'}}</p> + {{/if}} +</template> diff --git a/client/components/sidebar/templates.html.old b/client/components/sidebar/templates.html.old deleted file mode 100644 index d8b063f0..00000000 --- a/client/components/sidebar/templates.html.old +++ /dev/null @@ -1,307 +0,0 @@ -<template name="boardWidgets"> - <a href="#" class="sidebar-show-btn dark-hover js-show-sidebar"> - <span class="icon-sm fa fa-chevron-left"></span> - <span class="text">{{_ 'show-sidebar'}}</span> - </a> - <div class="board-widgets {{#if session 'sidebarIsOpen'}}show{{else}}hide{{/if}}"> - <div> - <a href="#" class="sidebar-hide-btn dark-hover js-hide-sidebar" title="{{_ 'close-sidebar-title'}}"> - <span class="icon-sm fa fa-chevron-right"></span> - </a> - {{#unless isTrue currentWidget "homeWidget"}} - <div class="board-widgets-title clearfix"> - <a href="#" class="board-sidebar-back-btn js-pop-widget-view"> - <span class="left-arrow"></span>{{_ 'back'}} - </a> - <h3 class="text">{{currentWidgetTitle}}</h3> - <hr> - </div> - {{/unless}} - <div class="board-widgets-content-wrapper"> - <div class="board-widgets-content default fancy-scrollbar short{{#unless session 'menuWidgetIsOpen'}} short{{/unless}}"> - {{> UI.dynamic template=currentWidget data=this }} - </div> - </div> - </div> - </div> -</template> - -<template name="homeWidget"> -{{ > menuWidget }} -{{ > membersWidget }} -{{ > activityWidget }} -</template> - -<template name="menuWidget"> - <div class="board-widget board-widget-nav clearfix{{#unless session 'menuWidgetIsOpen'}} collapsed{{/unless}}"> - <h3 class="dark-hover toggle-widget-nav js-toggle-widget-nav">{{_ 'menu'}} - <span class="icon-sm fa fa-chevron-circle-down toggle-menu-icon"></span> - </h3> - <ul class="nav-list"> - <hr style="margin-top: 0;"> - <li> - <a href="#" class="nav-list-item js-open-archive"> - <span class="icon-sm fa fa-archive icon-type"></span> - {{_ 'archived-items'}} - </a> - </li> - <li> - <a href="#" class="nav-list-item js-open-card-filter"> - <span class="icon-sm fa fa-filter icon-type"></span> - {{_ 'filter-cards'}} - </a> - </li> - {{#if currentUser.isBoardAdmin}} - <hr> - <li> - <a class="nav-list-item nav-list-sub-item board-settings-background js-change-background"> - <span class="board-settings-background-preview" style="background-color:{{board.background.color}}"></span> - {{_ 'change-background'}}… - </a> - </li> - {{#unless isSandstorm }} - <li> - <a class="nav-list-item nav-list-sub-item js-close-board" href="#">{{_ 'close-board'}}</a> - </li> - {{/unless}} - {{/if}} - {{! - XXX Language should be handled by sandstorm, but for now display a language selection link in the board menu. - This link is normally present in the header bar that is not displayed on sandstorm. - }} - {{#if isSandstorm}} - <hr> - <li> - <a class="nav-list-item nav-list-sub-item js-language">{{_ 'language'}}</a> - </li> - {{/if}} - </ul> - </div> -</template> - -<template name="membersWidget"> - <hr> - <div class="board-widget board-widget-members clearfix"> - <div class="board-widget-title"> - <h3>{{_ 'members'}}</h3> - </div> - <div class="board-widget-content"> - <div class="board-widget-members js-list-board-members clearfix js-list-draggable-board-members"> - {{# each board.members }} - {{> userAvatar userId=this.userId draggable=true size="small" showBadges=true}} - {{/ each }} - </div> - {{# unless isSandstrom }} - {{# if currentUser.isBoardAdmin }} - <a href="#" class="button-link js-open-manage-board-members"> - <span class="icon-sm fa fa-user"></span> {{_ 'add-members'}} - </a> - {{/ if }} - {{/ unless }} - </div> - </div> -</template> - -<template name="activityWidget"> - {{# if board.activities.count }} - <hr> - <div class="board-widget board-widget-activity bottom clearfix"> - <div class="board-widget-title"> - <h3>{{_ 'activity'}}</h3> - </div> - <div class="board-widget-content"> - <div class="activity-gradient-t"></div> - <div class="activity-gradient-b"></div> - <div class="board-actions-list fancy-scrollbar"> - {{ > activities }} - </div> - </div> - </div> - {{/if}} -</template> - -<template name="memberPopup"> - <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"> - {{# if currentUser.isBoardAdmin }} - <li> - <a class="js-change-role" href="#"> - {{_ 'change-permissions'}} <span class="quiet" style="font-weight: normal;">({{ memberType }})</span> - </a> - </li> - {{/ if }} - - <li> - {{# if currentUser.isBoardAdmin }} - <a class="js-remove-member">{{_ 'remove-from-board'}}</a> - {{ else }} - <a class="js-leave-member">{{_ 'leave-board'}}</a> - {{/ if }} - </li> - </ul> - {{/ if }} - </div> -</template> - -<template name="filterWidget"> - <ul class="pop-over-label-list checkable"> - {{#each board.labels}} - <li class="item matches-filter"> - <a class="name js-toggle-label-filter"> - <span class="card-label card-label-{{color}}"></span> - <span class="full-name"> - {{#if name}} - {{name}} - {{else}} - <span class="quiet">{{_ "label-default" color}}</span> - {{/if}} - </span> - {{#if Filter.labelIds.isSelected _id}} - <span class="icon-sm fa fa-check"></span> - {{/if}} - </a> - </li> - {{/each}} - </ul> - <hr> - <ul class="pop-over-member-list checkable"> - {{#each board.members}} - {{#with getUser userId}} - <li class="item js-member-item {{#if Filter.members.isSelected _id}}active{{/if}}"> - <a href="#" class="name js-toogle-member-filter"> - {{> userAvatar user=this size="small" }} - <span class="full-name"> - {{ profile.name }} - (<span class="username">{{ username }}</span>) - </span> - {{#if Filter.members.isSelected _id}} - <span class="icon-sm fa fa-check checked-icon"></span> - {{/if}} - </a> - </li> - {{/with}} - {{/each}} - </ul> - <hr> - <ul class="pop-over-list inset normal-weight"> - <li> - <a class="js-clear-all {{#unless Filter.isActive}}disabled{{/unless}}" style="padding-left: 40px;"> - {{_ 'filter-clear'}} - </a> - </li> - </ul> -</template> - -<template name="backgroundWidget"> - <div class="board-widgets-content-wrapper fancy-scrollbar"> - <div class="board-widgets-content"> - <div class="board-backgrounds-list clearfix"> - {{#each backgroundColors}} - <div class="board-background-select js-select-background"> - <span class="background-box " style="background-color: {{this}}; "></span> - </div> - {{/each}} - </div> - {{!-- - <h2 class="clear">Photos</h2> - <div class="board-backgrounds-list relative clearfix js-gold-photos-list disabled"> - <div class="board-background-select js-select-background"> - <span class="background-box " style="background-image: url("{{url}}");"> - <a class="background-option js-background-attribution" href={{href}} target="_blank" title={{title}}> - <img src="https://d78fikflryjgj.cloudfront.net/images/d906fe5c1274c56c5571d49705547587/cc.png" style="height: 14px; width: 14px; vertical-align: text-top;" title="http://creativecommons.org/licenses/by/2.0/deed.en"> - <span class="text" style="margin-left: 2px;">{{author}}</span> - </a> - </span> - </div> - </div> - --}} - </div> - </div> -</template> - -<template name="closeBoardPopup"> - <p>{{_ 'close-board-pop'}}</p> - <input type="submit" class="js-confirm negate full" value="{{_ 'close'}}"> -</template> - -<template name="removeMemberPopup"> - <p>{{_ 'remove-member-pop' - name=user.profile.name - username=user.username - boardTitle=board.title}}</p> - <input type="submit" class="js-confirm negate full" value="{{_ 'remove-member'}}"> -</template> - -<template name="addMemberPopup"> - <div class="search-with-spinner"> - {{> esInput index="users" }} - </div> - - <div class="manage-member-section hide js-search-results" style="display: block;"> - <ul class="pop-over-member-list options js-list"> - {{# esEach index="users"}} - <li class="item js-member-item {{# if isBoardMember }}disabled{{/if}}"> - <a href="#" class="name js-select-member {{# if isBoardMember }}multi-line{{/if}}" title="{{ profile.name }} ({{ username }})"> - {{> userAvatar user=this size="small" }} - <span class="full-name"> - {{ profile.name }} (<span class="username">{{ username }}</span>) - </span> - {{# if isBoardMember }} - <div class="extra-text quiet">({{_ 'joined'}})</div> - {{/if}} - <span class="icon-sm fa fa-chevron-right light option js-open-option"></span> - </a> - </li> - {{/esEach }} - </ul> - </div> - - {{# ifEsIsSearching index='users' }} - <div class="tac"> - <span class="tabbed-pane-main-col-loading-spinner spinner"></span> - </div> - {{ /ifEsIsSearching }} - - {{# ifEsHasNoResults index="users" }} - <div class="manage-member-section js-no-results"> - <p class="quiet center" style="padding: 16px 4px;">{{_ 'no-results'}}</p> - </div> - {{ /ifEsHasNoResults }} - - <div class="manage-member-section js-helper"> - <p class="bottom quiet" style="padding: 6px;">{{_ 'search-member-desc'}}</p> - </div> -</template> - -<template name="changePermissionsPopup"> - <ul class="pop-over-list"> - <li> - <a class="{{#if isLastAdmin}}disabled{{else}}js-set-admin{{/if}}"> - {{_ 'admin'}} - {{#if isAdmin}}<span class="icon-sm fa fa-check"></span>{{/if}} - <span class="sub-name">{{_ 'admin-desc'}}</span> - </a> - </li> - <li> - <a class="{{#if isLastAdmin}}disabled{{else}}js-set-normal{{/if}}"> - {{_ 'normal'}} - {{#unless isAdmin}}<span class="icon-sm fa fa-check"></span>{{/unless}} - <span class="sub-name">{{_ 'normal-desc'}}</span> - </a> - </li> - </ul> - {{#if isLastAdmin}} - <hr> - <p class="quiet bottom">{{_ 'last-admin-desc'}}</p> - {{/if}} -</template> |