mirror of
https://github.com/discourse/discourse.git
synced 2025-02-18 13:02:48 +08:00
FEATURE: add flair to avatars using new settings in the groups admin UI
This commit is contained in:
parent
72d7c055f4
commit
d079f69b7b
|
@ -1,5 +1,6 @@
|
||||||
import { popupAjaxError } from 'discourse/lib/ajax-error';
|
import { popupAjaxError } from 'discourse/lib/ajax-error';
|
||||||
import { propertyEqual } from 'discourse/lib/computed';
|
import { propertyEqual } from 'discourse/lib/computed';
|
||||||
|
import { escapeExpression } from 'discourse/lib/utilities';
|
||||||
|
|
||||||
export default Ember.Controller.extend({
|
export default Ember.Controller.extend({
|
||||||
needs: ['adminGroupsType'],
|
needs: ['adminGroupsType'],
|
||||||
|
@ -35,6 +36,23 @@ export default Ember.Controller.extend({
|
||||||
];
|
];
|
||||||
}.property(),
|
}.property(),
|
||||||
|
|
||||||
|
flairPreviewStyle: function() {
|
||||||
|
var style = '';
|
||||||
|
if (this.get('model.flair_url')) {
|
||||||
|
style += 'background-image: url(' + escapeExpression(this.get('model.flair_url')) + '); ';
|
||||||
|
}
|
||||||
|
if (this.get('model.flairBackgroundHexColor')) {
|
||||||
|
style += 'background-color: #' + this.get('model.flairBackgroundHexColor') + ';';
|
||||||
|
}
|
||||||
|
return style;
|
||||||
|
}.property('model.flair_url', 'model.flairBackgroundHexColor'),
|
||||||
|
|
||||||
|
flairPreviewClasses: function() {
|
||||||
|
if (this.get('model.flairBackgroundHexColor')) {
|
||||||
|
return 'rounded';
|
||||||
|
}
|
||||||
|
}.property('model.flairBackgroundHexColor'),
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
next() {
|
next() {
|
||||||
if (this.get("showingLast")) { return; }
|
if (this.get("showingLast")) { return; }
|
||||||
|
|
|
@ -101,6 +101,38 @@
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{/unless}}
|
{{/unless}}
|
||||||
|
|
||||||
|
{{#unless model.automatic}}
|
||||||
|
<div class="flair_inputs">
|
||||||
|
<div class="flair_left">
|
||||||
|
<div>
|
||||||
|
<label for="flair_url">{{i18n 'admin.groups.flair_url'}}</label>
|
||||||
|
{{text-field name="flair_url" value=model.flair_url placeholderKey="admin.groups.flair_url_placeholder"}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label for="flair_bg_color">{{i18n 'admin.groups.flair_bg_color'}}</label>
|
||||||
|
{{text-field name="flair_bg_color" class="flair_bg_color" value=model.flair_bg_color placeholderKey="admin.groups.flair_bg_color_placeholder"}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{#if flairPreviewStyle}}
|
||||||
|
<div class="flair_right">
|
||||||
|
<div>
|
||||||
|
<label>{{i18n 'admin.groups.flair_preview'}}</label>
|
||||||
|
<div class="avatar-flair-preview">
|
||||||
|
<div class="avatar-wrapper">
|
||||||
|
<img alt width="45" height="45" src="https://avatars.discourse.org/v3/letter/a/a3d4f5/45.png" class="avatar actor" title="demo">
|
||||||
|
</div>
|
||||||
|
<div class="avatar-flair demo {{flairPreviewClasses}}" style={{flairPreviewStyle}}></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
<div class="clearfix"></div>
|
||||||
|
</div>
|
||||||
|
{{/unless}}
|
||||||
|
|
||||||
<div class='buttons'>
|
<div class='buttons'>
|
||||||
<button {{action "save"}} disabled={{disableSave}} class='btn btn-primary'>{{i18n 'admin.customize.save'}}</button>
|
<button {{action "save"}} disabled={{disableSave}} class='btn btn-primary'>{{i18n 'admin.customize.save'}}</button>
|
||||||
{{#unless model.automatic}}
|
{{#unless model.automatic}}
|
||||||
|
|
|
@ -28,7 +28,9 @@ export function transformBasicPost(post) {
|
||||||
isDeleted: post.deleted_at || post.user_deleted,
|
isDeleted: post.deleted_at || post.user_deleted,
|
||||||
deletedByAvatarTemplate: null,
|
deletedByAvatarTemplate: null,
|
||||||
deletedByUsername: null,
|
deletedByUsername: null,
|
||||||
primary_group_name: post.primary_group_name,
|
primaryGroupName: post.primary_group_name,
|
||||||
|
primaryGroupFlairUrl: post.primary_group_flair_url,
|
||||||
|
primaryGroupFlairBgColor: post.primary_group_flair_bg_color,
|
||||||
wiki: post.wiki,
|
wiki: post.wiki,
|
||||||
firstPost: post.post_number === 1,
|
firstPost: post.post_number === 1,
|
||||||
post_number: post.post_number,
|
post_number: post.post_number,
|
||||||
|
|
|
@ -90,6 +90,11 @@ const Group = Discourse.Model.extend({
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@computed('flair_bg_color')
|
||||||
|
flairBackgroundHexColor() {
|
||||||
|
return this.get('flair_bg_color') ? this.get('flair_bg_color').replace(new RegExp("[^0-9a-fA-F]", "g"), "") : null;
|
||||||
|
},
|
||||||
|
|
||||||
asJSON() {
|
asJSON() {
|
||||||
return {
|
return {
|
||||||
name: this.get('name'),
|
name: this.get('name'),
|
||||||
|
@ -101,6 +106,8 @@ const Group = Discourse.Model.extend({
|
||||||
primary_group: !!this.get('primary_group'),
|
primary_group: !!this.get('primary_group'),
|
||||||
grant_trust_level: this.get('grant_trust_level'),
|
grant_trust_level: this.get('grant_trust_level'),
|
||||||
incoming_email: this.get("incoming_email"),
|
incoming_email: this.get("incoming_email"),
|
||||||
|
flair_url: this.get('flair_url'),
|
||||||
|
flair_bg_color: this.get('flairBackgroundHexColor'),
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -77,6 +77,29 @@ createWidget('reply-to-tab', {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
createWidget('post-avatar-flair', {
|
||||||
|
tagName: 'div.avatar-flair',
|
||||||
|
|
||||||
|
title(attrs) {
|
||||||
|
return attrs.primaryGroupName;
|
||||||
|
},
|
||||||
|
|
||||||
|
buildClasses(attrs) {
|
||||||
|
return 'avatar-flair-' + attrs.primaryGroupName + (attrs.primaryGroupFlairBgColor ? ' rounded' : '');
|
||||||
|
},
|
||||||
|
|
||||||
|
buildAttributes(attrs) {
|
||||||
|
var style = '';
|
||||||
|
if (attrs.primaryGroupFlairUrl) {
|
||||||
|
style += 'background-image: url(' + attrs.primaryGroupFlairUrl + '); ';
|
||||||
|
}
|
||||||
|
if (attrs.primaryGroupFlairBgColor) {
|
||||||
|
style += 'background-color: #' + attrs.primaryGroupFlairBgColor + '; ';
|
||||||
|
}
|
||||||
|
return {style: style};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
createWidget('post-avatar', {
|
createWidget('post-avatar', {
|
||||||
tagName: 'div.topic-avatar',
|
tagName: 'div.topic-avatar',
|
||||||
|
|
||||||
|
@ -93,11 +116,21 @@ createWidget('post-avatar', {
|
||||||
template: attrs.avatar_template,
|
template: attrs.avatar_template,
|
||||||
username: attrs.username,
|
username: attrs.username,
|
||||||
url: attrs.usernameUrl,
|
url: attrs.usernameUrl,
|
||||||
className: 'main-avatar'
|
className: 'main-avatar',
|
||||||
|
flairUrl: attrs.primaryGroupFlairUrl,
|
||||||
|
flairBgColor: attrs.primaryGroupFlairBgColor
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return [body, h('div.poster-avatar-extra')];
|
const result = [body];
|
||||||
|
|
||||||
|
if (attrs.primaryGroupFlairUrl || attrs.primaryGroupFlairBgColor) {
|
||||||
|
result.push(this.attach('post-avatar-flair', attrs));
|
||||||
|
}
|
||||||
|
|
||||||
|
result.push(h('div.poster-avatar-extra'));
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -406,7 +439,7 @@ export default createWidget('post', {
|
||||||
if (attrs.topicOwner) { classNames.push('topic-owner'); }
|
if (attrs.topicOwner) { classNames.push('topic-owner'); }
|
||||||
if (attrs.hidden) { classNames.push('post-hidden'); }
|
if (attrs.hidden) { classNames.push('post-hidden'); }
|
||||||
if (attrs.deleted) { classNames.push('deleted'); }
|
if (attrs.deleted) { classNames.push('deleted'); }
|
||||||
if (attrs.primary_group_name) { classNames.push(`group-${attrs.primary_group_name}`); }
|
if (attrs.primaryGroupName) { classNames.push(`group-${attrs.primaryGroupName}`); }
|
||||||
if (attrs.wiki) { classNames.push(`wiki`); }
|
if (attrs.wiki) { classNames.push(`wiki`); }
|
||||||
if (attrs.isWhisper) { classNames.push('whisper'); }
|
if (attrs.isWhisper) { classNames.push('whisper'); }
|
||||||
if (attrs.isModeratorAction || (attrs.isWarning && attrs.firstPost)) {
|
if (attrs.isModeratorAction || (attrs.isWarning && attrs.firstPost)) {
|
||||||
|
|
|
@ -35,7 +35,7 @@ export default createWidget('poster-name', {
|
||||||
if (attrs.moderator) { classNames.push('moderator'); }
|
if (attrs.moderator) { classNames.push('moderator'); }
|
||||||
if (attrs.new_user) { classNames.push('new-user'); }
|
if (attrs.new_user) { classNames.push('new-user'); }
|
||||||
|
|
||||||
const primaryGroupName = attrs.primary_group_name;
|
const primaryGroupName = attrs.primaryGroupName;
|
||||||
if (primaryGroupName && primaryGroupName.length) {
|
if (primaryGroupName && primaryGroupName.length) {
|
||||||
classNames.push(primaryGroupName);
|
classNames.push(primaryGroupName);
|
||||||
}
|
}
|
||||||
|
|
|
@ -684,6 +684,39 @@ section.details {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
border-color: dark-light-choose(scale-color($primary, $lightness: 75%), scale-color($secondary, $lightness: 25%));
|
border-color: dark-light-choose(scale-color($primary, $lightness: 75%), scale-color($secondary, $lightness: 25%));
|
||||||
}
|
}
|
||||||
|
.avatar-flair-preview {
|
||||||
|
position: relative;
|
||||||
|
width: 45px;
|
||||||
|
|
||||||
|
.avatar-flair.demo {
|
||||||
|
top: 25px;
|
||||||
|
&.rounded {
|
||||||
|
top: 23px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.form-horizontal {
|
||||||
|
.flair_inputs {
|
||||||
|
margin-top: 30px;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
|
||||||
|
.flair_left {
|
||||||
|
float: left;
|
||||||
|
width: 60%;
|
||||||
|
input[name=flair_url] {
|
||||||
|
width: 90%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.flair_right {
|
||||||
|
float: left;
|
||||||
|
margin-left: 30px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.row.groups input[type='text'].flair_bg_color {
|
||||||
|
width: 200px;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Customise area
|
// Customise area
|
||||||
|
|
|
@ -153,6 +153,25 @@ aside.quote {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.topic-avatar .avatar-flair, .avatar-flair-preview .avatar-flair {
|
||||||
|
display: block;
|
||||||
|
background-size: 20px 20px;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: center;
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
position: absolute;
|
||||||
|
top: 40px;
|
||||||
|
right: -6px;
|
||||||
|
&.rounded {
|
||||||
|
background-size: 18px 18px;
|
||||||
|
border-radius: 12px;
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
top: 38px;
|
||||||
|
right: -8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
.topic-avatar .poster-avatar-extra {
|
.topic-avatar .poster-avatar-extra {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
|
@ -637,7 +637,7 @@ $topic-avatar-width: 45px;
|
||||||
width: $topic-avatar-width;
|
width: $topic-avatar-width;
|
||||||
float: left;
|
float: left;
|
||||||
position: relative;
|
position: relative;
|
||||||
z-index: 2;
|
z-index: 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
.gap {
|
.gap {
|
||||||
|
|
|
@ -65,6 +65,9 @@ class Admin::GroupsController < Admin::AdminController
|
||||||
title = params[:title] if params[:title].present?
|
title = params[:title] if params[:title].present?
|
||||||
group.title = group.automatic ? nil : title
|
group.title = group.automatic ? nil : title
|
||||||
|
|
||||||
|
group.flair_url = params[:flair_url].presence
|
||||||
|
group.flair_bg_color = params[:flair_bg_color].presence
|
||||||
|
|
||||||
if group.save
|
if group.save
|
||||||
Group.reset_counters(group.id, :group_users)
|
Group.reset_counters(group.id, :group_users)
|
||||||
render_serialized(group, BasicGroupSerializer)
|
render_serialized(group, BasicGroupSerializer)
|
||||||
|
|
|
@ -28,6 +28,7 @@ class Group < ActiveRecord::Base
|
||||||
validates_uniqueness_of :name, case_sensitive: false
|
validates_uniqueness_of :name, case_sensitive: false
|
||||||
validate :automatic_membership_email_domains_format_validator
|
validate :automatic_membership_email_domains_format_validator
|
||||||
validate :incoming_email_validator
|
validate :incoming_email_validator
|
||||||
|
validates :flair_url, url: true
|
||||||
|
|
||||||
AUTO_GROUPS = {
|
AUTO_GROUPS = {
|
||||||
:everyone => 0,
|
:everyone => 0,
|
||||||
|
|
|
@ -14,7 +14,9 @@ class BasicGroupSerializer < ApplicationSerializer
|
||||||
:notification_level,
|
:notification_level,
|
||||||
:has_messages,
|
:has_messages,
|
||||||
:is_member,
|
:is_member,
|
||||||
:mentionable
|
:mentionable,
|
||||||
|
:flair_url,
|
||||||
|
:flair_bg_color
|
||||||
|
|
||||||
def include_incoming_email?
|
def include_incoming_email?
|
||||||
scope.is_staff?
|
scope.is_staff?
|
||||||
|
|
|
@ -34,6 +34,8 @@ class PostSerializer < BasicPostSerializer
|
||||||
:category_id,
|
:category_id,
|
||||||
:display_username,
|
:display_username,
|
||||||
:primary_group_name,
|
:primary_group_name,
|
||||||
|
:primary_group_flair_url,
|
||||||
|
:primary_group_flair_bg_color,
|
||||||
:version,
|
:version,
|
||||||
:can_edit,
|
:can_edit,
|
||||||
:can_delete,
|
:can_delete,
|
||||||
|
@ -150,6 +152,16 @@ class PostSerializer < BasicPostSerializer
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def primary_group_flair_url
|
||||||
|
return nil unless object.user && object.user.primary_group_id
|
||||||
|
object.user.primary_group.try(:flair_url)
|
||||||
|
end
|
||||||
|
|
||||||
|
def primary_group_flair_bg_color
|
||||||
|
return nil unless object.user && object.user.primary_group_id
|
||||||
|
object.user.primary_group.try(:flair_bg_color)
|
||||||
|
end
|
||||||
|
|
||||||
def link_counts
|
def link_counts
|
||||||
return @single_post_link_counts if @single_post_link_counts.present?
|
return @single_post_link_counts if @single_post_link_counts.present?
|
||||||
|
|
||||||
|
|
|
@ -2402,6 +2402,11 @@ en:
|
||||||
add_owners: Add owners
|
add_owners: Add owners
|
||||||
incoming_email: "Custom incoming email address"
|
incoming_email: "Custom incoming email address"
|
||||||
incoming_email_placeholder: "enter email address"
|
incoming_email_placeholder: "enter email address"
|
||||||
|
flair_url: "Avatar Flair URL"
|
||||||
|
flair_url_placeholder: "(Optional) Image URL"
|
||||||
|
flair_bg_color: "Avatar Flair Background Color"
|
||||||
|
flair_bg_color_placeholder: "(Optional) Hex color value"
|
||||||
|
flair_preview: "Preview"
|
||||||
|
|
||||||
|
|
||||||
api:
|
api:
|
||||||
|
|
6
db/migrate/20160815210156_add_flair_url_to_groups.rb
Normal file
6
db/migrate/20160815210156_add_flair_url_to_groups.rb
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
class AddFlairUrlToGroups < ActiveRecord::Migration
|
||||||
|
def change
|
||||||
|
add_column :groups, :flair_url, :string
|
||||||
|
add_column :groups, :flair_bg_color, :string
|
||||||
|
end
|
||||||
|
end
|
11
lib/validators/url_validator.rb
Normal file
11
lib/validators/url_validator.rb
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
class UrlValidator < ActiveModel::EachValidator
|
||||||
|
def validate_each(record, attribute, value)
|
||||||
|
if value.present?
|
||||||
|
uri = URI.parse(value) rescue nil
|
||||||
|
|
||||||
|
unless uri
|
||||||
|
record.errors[attribute] << (options[:message] || I18n.t('errors.messages.invalid'))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -35,7 +35,9 @@ describe Admin::GroupsController do
|
||||||
"notification_level"=>2,
|
"notification_level"=>2,
|
||||||
"has_messages"=>false,
|
"has_messages"=>false,
|
||||||
"is_member"=>true,
|
"is_member"=>true,
|
||||||
"mentionable"=>false
|
"mentionable"=>false,
|
||||||
|
"flair_url"=>nil,
|
||||||
|
"flair_bg_color"=>nil
|
||||||
}])
|
}])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -32,7 +32,7 @@ widgetTest('extra classes and glyphs', {
|
||||||
admin: true,
|
admin: true,
|
||||||
moderator: true,
|
moderator: true,
|
||||||
new_user: true,
|
new_user: true,
|
||||||
primary_group_name: 'fish'
|
primaryGroupName: 'fish'
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
test(assert) {
|
test(assert) {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user