UX: Make user info rendering more consistent

This commit is contained in:
Robin Ward 2016-03-24 13:05:09 -04:00
parent 476a5fd43c
commit db15772ab1
19 changed files with 98 additions and 128 deletions

View File

@ -0,0 +1,23 @@
import { url } from 'discourse/lib/computed';
import computed from 'ember-addons/ember-computed-decorators';
function normalize(name) {
return name.replace(/[\-\_ \.]/g, '').toLowerCase();
}
export default Ember.Component.extend({
classNameBindings: [':user-info', 'size'],
size: 'small',
userPath: url('user.username', '/users/%@'),
// TODO: In later ember releases `hasBlock` works without this
hasBlock: Ember.computed.alias('template'),
@computed('user.name', 'user.username')
name(name, username) {
if (name && normalize(username) !== normalize(name)) {
return name;
}
}
});

View File

@ -1,15 +0,0 @@
import { url } from 'discourse/lib/computed';
export default Ember.Component.extend({
classNames: ['user-small'],
userPath: url('user.username', '/users/%@'),
name: function() {
const name = this.get('user.name');
if (name && this.get('user.username') !== name) {
return name;
}
}.property('user.name')
});

View File

@ -6,7 +6,7 @@ export default Ember.Controller.extend({
userBadges: null, userBadges: null,
needs: ["application"], needs: ["application"],
user: function(){ user: function() {
if (this.get("username")) { if (this.get("username")) {
return this.get('userBadges')[0].get('user'); return this.get('userBadges')[0].get('user');
} }
@ -37,16 +37,6 @@ export default Ember.Controller.extend({
} }
}, },
layoutClass: function(){
var user = this.get("user") ? " single-user" : "";
var ub = this.get("userBadges");
if(ub && ub[0] && ub[0].post_id){
return "user-badge-with-posts" + user;
} else {
return "user-badge-no-posts" + user;
}
}.property("userBadges"),
canLoadMore: function() { canLoadMore: function() {
if (this.get('noMoreBadges')) { return false; } if (this.get('noMoreBadges')) { return false; }

View File

@ -25,3 +25,5 @@ registerUnbound('format-date', function(val, params) {
return new Handlebars.SafeString(autoUpdatingRelativeAge(date, {format: format, title: title, leaveAgo: leaveAgo})); return new Handlebars.SafeString(autoUpdatingRelativeAge(date, {format: format, title: title, leaveAgo: leaveAgo}));
} }
}); });

View File

@ -0,0 +1,6 @@
import { relativeAge } from 'discourse/lib/formatter';
export default function(dt, params) {
dt = params.data.view.getStream(dt).value();
return relativeAge(new Date(dt));
}

View File

@ -6,13 +6,8 @@ const UserBadge = Discourse.Model.extend({
return "/t/-/" + this.get('topic_id') + "/" + this.get('post_number'); return "/t/-/" + this.get('topic_id') + "/" + this.get('post_number');
} }
}.property(), // avoid the extra bindings for now }.property(), // avoid the extra bindings for now
/**
Revoke this badge.
@method revoke revoke() {
@returns {Promise} a promise that resolves when the badge has been revoked.
**/
revoke: function() {
return Discourse.ajax("/user_badges/" + this.get('id'), { return Discourse.ajax("/user_badges/" + this.get('id'), {
type: "DELETE" type: "DELETE"
}); });

View File

@ -15,10 +15,7 @@ export default Discourse.Route.extend({
}, },
serialize(model) { serialize(model) {
return { return model.getProperties('id', 'slug');
id: model.get("id"),
slug: model.get("slug")
};
}, },
model(params) { model(params) {
@ -29,13 +26,12 @@ export default Discourse.Route.extend({
} }
}, },
afterModel(model,transition) { afterModel(model, transition) {
const username = transition.queryParams && transition.queryParams.username; const username = transition.queryParams && transition.queryParams.username;
return UserBadge.findByBadgeId(model.get("id"), {username}).then(userBadges => { return UserBadge.findByBadgeId(model.get("id"), {username}).then(userBadges => {
this.userBadges = userBadges; this.userBadges = userBadges;
}); });
}, },
titleToken() { titleToken() {

View File

@ -22,8 +22,8 @@
<section class='about admins'> <section class='about admins'>
<h3>{{i18n 'about.our_admins'}}</h3> <h3>{{i18n 'about.our_admins'}}</h3>
{{#each a in model.admins}} {{#each model.admins as |a|}}
{{user-small user=a}} {{user-info user=a}}
{{/each}} {{/each}}
<div class='clearfix'></div> <div class='clearfix'></div>
@ -35,8 +35,8 @@
<h3>{{i18n 'about.our_moderators'}}</h3> <h3>{{i18n 'about.our_moderators'}}</h3>
<div class='users'> <div class='users'>
{{#each m in model.moderators}} {{#each model.moderators as |m|}}
{{user-small user=m}} {{user-info user=m}}
{{/each}} {{/each}}
</div> </div>
<div class='clearfix'></div> <div class='clearfix'></div>

View File

@ -21,16 +21,8 @@
</div> </div>
</div> </div>
{{#if user}} {{#if user}}
<div class='badge-user-info'> <div class='badge-user-info'>
{{#link-to 'user' user}}
{{avatar user imageSize="extra_large"}}
<div class="details clearfix">
<div class='username'>{{user.username}}</div>
</div>
{{/link-to}}
<div class='earned'> <div class='earned'>
{{i18n 'badges.earned_n_times' count=grantCount}} {{i18n 'badges.earned_n_times' count=grantCount}}
</div> </div>
@ -38,33 +30,22 @@
{{/if}} {{/if}}
{{#if userBadges}} {{#if userBadges}}
<div class={{unbound layoutClass}}> <div class="user-badges">
{{#each ub in userBadges}} {{#each userBadges as |ub|}}
<div class="badge-user"> {{#user-info user=ub.user size="medium" class="badge-info" date=ub.granted_at}}
{{#if user}} <div class="granted-on">{{i18n 'badges.granted_on' date=(inline-date ub.granted_at)}}</div>
{{format-date ub.granted_at}}
{{else}}
{{#link-to 'user' ub.user classNames="badge-info"}}
{{avatar ub.user imageSize="large"}}
<div class="details">
<span class="username">{{ub.user.username}}</span>
{{format-date ub.granted_at}}
</div>
{{/link-to}}
{{/if}}
{{#if ub.post_number}} {{#if ub.post_number}}
<a class="post-link" href="{{unbound ub.topic.url}}/{{unbound ub.post_number}}">{{{ub.topic.fancyTitle}}}</a> <a class="post-link" href="{{unbound ub.topic.url}}/{{unbound ub.post_number}}">{{{ub.topic.fancyTitle}}}</a>
{{/if}} {{/if}}
</div> {{/user-info}}
{{/each}} {{/each}}
{{#unless canLoadMore}} {{#unless canLoadMore}}
{{#if user}} {{#if user}}
<a class='load-more' href='{{model.url}}'>{{i18n 'badges.more_with_badge'}}</a> {{log model}}
<a class='btn' href='{{model.url}}'>{{i18n 'badges.others_count' count=model.grant_count}}</a>
{{/if}} {{/if}}
{{/unless}} {{/unless}}
</div> </div>
{{conditional-loading-spinner condition=canLoadMore}} {{conditional-loading-spinner condition=canLoadMore}}

View File

@ -8,4 +8,11 @@
<span class="name">{{unbound name}}</span> <span class="name">{{unbound name}}</span>
</div> </div>
<div class="title">{{unbound user.title}}</div> <div class="title">{{unbound user.title}}</div>
{{#if hasBlock}}
<div class='details'>
{{yield}}
</div>
{{/if}}
</div> </div>

View File

@ -18,7 +18,7 @@
{{#each model.members as |m|}} {{#each model.members as |m|}}
<tr> <tr>
<td class='avatar'> <td class='avatar'>
{{user-small user=m}} {{user-info user=m}}
{{#if m.owner}}<span class='is-owner'>{{i18n "groups.owner"}}</span>{{/if}} {{#if m.owner}}<span class='is-owner'>{{i18n "groups.owner"}}</span>{{/if}}
</td> </td>
<td> <td>

View File

@ -13,7 +13,7 @@
{{#each ic in model itemController="directory-item"}} {{#each ic in model itemController="directory-item"}}
<div class="user {{if ic.me 'me'}}"> <div class="user {{if ic.me 'me'}}">
{{#with ic.model as |it|}} {{#with ic.model as |it|}}
{{user-small user=it.user}} {{user-info user=it.user}}
{{user-stat value=it.likes_received label="directory.likes_received" icon="heart"}} {{user-stat value=it.likes_received label="directory.likes_received" icon="heart"}}
{{user-stat value=it.likes_given label="directory.likes_given" icon="heart"}} {{user-stat value=it.likes_given label="directory.likes_given" icon="heart"}}
{{user-stat value=it.topic_count label="directory.topic_count"}} {{user-stat value=it.topic_count label="directory.topic_count"}}

View File

@ -28,7 +28,7 @@
{{#each ic in model itemController="directory-item"}} {{#each ic in model itemController="directory-item"}}
<tr class="{{if ic.me 'me'}}"> <tr class="{{if ic.me 'me'}}">
{{#with ic.model as |it|}} {{#with ic.model as |it|}}
<td>{{user-small user=it.user}}</td> <td>{{user-info user=it.user}}</td>
<td>{{number it.likes_received}}</td> <td>{{number it.likes_received}}</td>
<td>{{number it.likes_given}}</td> <td>{{number it.likes_given}}</td>
<td>{{number it.topic_count}}</td> <td>{{number it.topic_count}}</td>

View File

@ -1,6 +1,10 @@
.directory { .directory {
margin-bottom: 100px; margin-bottom: 100px;
.user-info {
margin-bottom: 0;
}
.period-chooser { .period-chooser {
float: left; float: left;
} }

View File

@ -135,66 +135,23 @@
} }
} }
} }
.user-info.medium.badge-info {
min-height: 80px;
.granted-on {
/* /badges/:id/:slug page styling. */ color: dark-light-choose(scale-color($primary, $lightness: 50%), scale-color($secondary, $lightness: 50%));
.show-badge {
.badge-user {
text-align: center;
width: 100px;
padding: 5px 10px;
margin-bottom: 10px;
display: inline-block;
vertical-align: top;
.details {
margin: 0 10px;
padding-top: 3px;
color: $primary;
}
.username {
word-wrap: break-word;
}
.date {
display: block;
color: lighten($primary, 40%);
font-size: 0.714em;
}
}
}
.show-badge .user-badge-with-posts .badge-user {
width: 45%;
padding: 0 0 0 4%;
margin-bottom: 20px;
.badge-info {
width: 100px;
display: block;
float: left;
} }
.post-link { .post-link {
width: 250px;
display: block; display: block;
float: left; margin-top: 0.2em;
margin-left: 18px;
text-align: left;
} }
} }
.show-badge .badge-user-info { .show-badge .badge-user-info {
margin-left: 2%;
.earned { .earned {
margin-top: 15px;
font-size: 1.3em; font-size: 1.3em;
} margin-bottom: 1em;
.username {
margin-top: 5px;
display: block;
color: dark-light-choose(scale-color($primary, $lightness: 30%), scale-color($secondary, $lightness: 70%));
} }
} }

View File

@ -92,10 +92,10 @@
margin-bottom: 15px; margin-bottom: 15px;
} }
.user-small { .user-info {
display: inline-block; display: inline-block;
width: 333px;
clear: both; clear: both;
margin-bottom: 1em;
.user-image { .user-image {
float: left; float: left;
@ -128,7 +128,30 @@
margin-top: 3px; margin-top: 3px;
color: dark-light-choose(scale-color($primary, $lightness: 50%), scale-color($secondary, $lightness: 50%)); color: dark-light-choose(scale-color($primary, $lightness: 50%), scale-color($secondary, $lightness: 50%));
} }
}
}
.user-info.small {
width: 333px;
}
.user-info.medium {
width: 550px;
min-height: 60px;
.user-image {
width: 55px;
}
.user-detail {
width: 450px;
}
.username, .name {
display: block;
}
.name {
margin-left: 0;
} }
} }

View File

@ -169,7 +169,7 @@
color: $primary; color: $primary;
} }
} }
.user-small { .user-info {
width: 245px; width: 245px;
} }
} }

View File

@ -2855,7 +2855,8 @@ en:
earned_n_times: earned_n_times:
one: "Earned this badge 1 time" one: "Earned this badge 1 time"
other: "Earned this badge %{count} times" other: "Earned this badge %{count} times"
more_with_badge: "Others with this badge" granted_on: "Granted %{date}"
others_count: "Others with this badge (%{count})"
title: Badges title: Badges
allow_title: "can be used as a title" allow_title: "can be used as a title"
multiple_grant: "can be awarded multiple times" multiple_grant: "can be awarded multiple times"

View File

@ -4,8 +4,8 @@ acceptance("About");
test("viewing", () => { test("viewing", () => {
visit("/about"); visit("/about");
andThen(() => { andThen(() => {
ok(exists('.about.admins .user-small'), 'has admins'); ok(exists('.about.admins .user-info'), 'has admins');
ok(exists('.about.moderators .user-small'), 'has moderators'); ok(exists('.about.moderators .user-info'), 'has moderators');
ok(exists('.about.stats tr td'), 'has stats'); ok(exists('.about.stats tr td'), 'has stats');
}); });
}); });