UX: Make user info rendering more consistent
This commit is contained in:
parent
476a5fd43c
commit
db15772ab1
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
|
@ -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')
|
|
||||||
|
|
||||||
});
|
|
|
@ -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; }
|
||||||
|
|
||||||
|
|
|
@ -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}));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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));
|
||||||
|
}
|
|
@ -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"
|
||||||
});
|
});
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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}}
|
||||||
|
|
|
@ -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>
|
|
@ -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>
|
||||||
|
|
|
@ -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"}}
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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%));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -169,7 +169,7 @@
|
||||||
color: $primary;
|
color: $primary;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.user-small {
|
.user-info {
|
||||||
width: 245px;
|
width: 245px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue