mirror of
https://github.com/flarum/framework.git
synced 2025-02-21 07:38:08 +08:00
Implement user hover cards and basic profile pages
This commit is contained in:
parent
f1ceb41d3f
commit
2cd59c876d
@ -6,7 +6,22 @@ var precompileTemplate = Ember.Handlebars.compile;
|
||||
Component for the username/avatar in a post header.
|
||||
*/
|
||||
export default Ember.Component.extend({
|
||||
tagName: 'h3',
|
||||
classNames: ['post-user'],
|
||||
layout: precompileTemplate('{{#if post.user}}{{#link-to "user" post.user}}{{user-avatar post.user}} {{user-name post.user}}{{/link-to}}{{else}}{{user-avatar post.user}} {{user-name post.user}}{{/if}}{{ui/item-list items=post.user.badges class="badges"}}')
|
||||
layout: precompileTemplate('{{#if post.user}}<h3>{{#link-to "user" post.user}}{{user-avatar post.user}} {{user-name post.user}}{{/link-to}} {{ui/item-list items=post.user.badges class="badges"}}</h3>{{#if showCard}}{{user/user-card user=post.user class="user-card-popover" controlsButtonClass="btn btn-default btn-icon btn-sm btn-naked"}}{{/if}}{{else}}<h3>{{user-avatar post.user}} {{user-name post.user}}</h3>{{/if}}'),
|
||||
|
||||
didInsertElement: function() {
|
||||
var component = this;
|
||||
var timeout;
|
||||
this.$().bind('mouseover', '> a, .user-card', function() {
|
||||
clearTimeout(timeout);
|
||||
timeout = setTimeout(function() {
|
||||
component.set('showCard', true);
|
||||
}, 250);
|
||||
}).bind('mouseout', '> a, .user-card', function() {
|
||||
clearTimeout(timeout);
|
||||
timeout = setTimeout(function() {
|
||||
component.set('showCard', false);
|
||||
}, 250);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
62
framework/core/ember/app/components/user/user-card.js
Normal file
62
framework/core/ember/app/components/user/user-card.js
Normal file
@ -0,0 +1,62 @@
|
||||
import Ember from 'ember';
|
||||
|
||||
import HasItemLists from 'flarum/mixins/has-item-lists';
|
||||
|
||||
export default Ember.Component.extend(HasItemLists, {
|
||||
layoutName: 'components/user/user-card',
|
||||
classNames: ['user-card'],
|
||||
attributeBindings: ['style'],
|
||||
itemLists: ['controls', 'info'],
|
||||
|
||||
style: Ember.computed('user.color', function() {
|
||||
return 'background-color: '+this.get('user.color');
|
||||
}),
|
||||
|
||||
bioEditable: Ember.computed.and('user.canEdit', 'editable'),
|
||||
showBio: Ember.computed.or('user.bioHtml', 'bioEditable'),
|
||||
|
||||
didInsertElement: function() {
|
||||
this.$().on('click', '.user-bio a', function(e) {
|
||||
e.stopPropagation();
|
||||
});
|
||||
},
|
||||
|
||||
actions: {
|
||||
editBio: function() {
|
||||
if (!this.get('bioEditable')) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.set('editingBio', true);
|
||||
var component = this;
|
||||
Ember.run.scheduleOnce('afterRender', this, function() {
|
||||
this.$('.user-bio textarea').focus().blur(function() {
|
||||
component.send('saveBio', $(this).val());
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
saveBio: function(value) {
|
||||
var user = this.get('user');
|
||||
user.set('bio', value);
|
||||
user.save();
|
||||
this.set('editingBio', false);
|
||||
}
|
||||
},
|
||||
|
||||
populateControls: function(items) {
|
||||
this.addActionItem(items, 'edit', 'Edit', 'pencil');
|
||||
this.addActionItem(items, 'delete', 'Delete', 'times');
|
||||
},
|
||||
|
||||
populateInfo: function(items) {
|
||||
items.pushObjectWithTag(Ember.Component.extend({
|
||||
layout: Ember.Handlebars.compile('{{fa-icon "circle"}} Online')
|
||||
}), 'lastActiveTime');
|
||||
|
||||
items.pushObjectWithTag(Ember.Component.extend({
|
||||
layout: Ember.Handlebars.compile('Joined {{human-time user.joinTime}}'),
|
||||
user: this.get('user')
|
||||
}), 'joinTime');
|
||||
}
|
||||
});
|
5
framework/core/ember/app/controllers/user.js
Normal file
5
framework/core/ember/app/controllers/user.js
Normal file
@ -0,0 +1,5 @@
|
||||
import Ember from 'ember';
|
||||
|
||||
export default Ember.Controller.extend({
|
||||
|
||||
});
|
@ -10,6 +10,8 @@ export default DS.Model.extend(HasItemLists, {
|
||||
email: DS.attr('string'),
|
||||
password: DS.attr('string'),
|
||||
avatarUrl: DS.attr('string'),
|
||||
bio: DS.attr('string'),
|
||||
bioHtml: DS.attr('string'),
|
||||
|
||||
groups: DS.hasMany('group'),
|
||||
|
||||
|
@ -6,7 +6,6 @@ var Router = Ember.Router.extend({
|
||||
});
|
||||
|
||||
Router.map(function() {
|
||||
|
||||
this.resource('index', {path: '/'}, function() {
|
||||
this.resource('discussion', {path: '/:id/:slug'}, function() {
|
||||
this.route('near', {path: '/:near'});
|
||||
@ -16,9 +15,10 @@ Router.map(function() {
|
||||
this.resource('user', {path: '/u/:username'}, function() {
|
||||
this.route('activity');
|
||||
this.route('posts');
|
||||
this.resource('preferences');
|
||||
this.route('edit');
|
||||
});
|
||||
|
||||
this.resource('settings');
|
||||
});
|
||||
|
||||
export default Router;
|
||||
|
7
framework/core/ember/app/routes/user.js
Normal file
7
framework/core/ember/app/routes/user.js
Normal file
@ -0,0 +1,7 @@
|
||||
import Ember from 'ember';
|
||||
|
||||
export default Ember.Route.extend({
|
||||
model: function(params) {
|
||||
return this.store.find('user', params.username);
|
||||
}
|
||||
});
|
@ -33,5 +33,6 @@
|
||||
|
||||
@import "@{flarum-base}index.less";
|
||||
@import "@{flarum-base}discussion.less";
|
||||
@import "@{flarum-base}user.less";
|
||||
@import "@{flarum-base}login.less";
|
||||
@import "@{flarum-base}signup.less";
|
||||
|
@ -1,12 +1,13 @@
|
||||
.avatar-size(@size) {
|
||||
width: @size;
|
||||
height: @size;
|
||||
border-radius: @size / 2;
|
||||
border-radius: @size;
|
||||
font-size: @size / 2;
|
||||
line-height: @size;
|
||||
}
|
||||
.avatar {
|
||||
display: inline-block;
|
||||
box-sizing: content-box;
|
||||
color: @fl-body-bg;
|
||||
font-weight: 300;
|
||||
text-align: center;
|
||||
|
@ -20,7 +20,8 @@
|
||||
.badge {
|
||||
.badge-size(24px);
|
||||
border: 2px solid @fl-body-bg;
|
||||
background: @fl-body-secondary-color;
|
||||
background: @fl-body-muted-color;
|
||||
color: #fff;
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
text-align: center;
|
||||
|
@ -150,14 +150,14 @@
|
||||
margin-bottom: 10px;
|
||||
color: @fl-body-muted-color;
|
||||
|
||||
&, & a {
|
||||
color: @fl-body-muted-color;
|
||||
}
|
||||
& > ul {
|
||||
list-style-type: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
|
||||
&, & a {
|
||||
color: @fl-body-muted-color;
|
||||
}
|
||||
& > li {
|
||||
display: inline;
|
||||
margin-right: 10px;
|
||||
@ -166,11 +166,16 @@
|
||||
& .post-user {
|
||||
margin: 0;
|
||||
display: inline;
|
||||
font-weight: bold;
|
||||
font-size: 15px;
|
||||
font-weight: normal;
|
||||
position: relative;
|
||||
|
||||
&, & a {
|
||||
& h3 {
|
||||
display: inline;
|
||||
}
|
||||
& h3, & h3 a {
|
||||
color: @fl-body-heading-color;
|
||||
font-weight: bold;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
& .badges {
|
||||
@ -182,6 +187,13 @@
|
||||
position: relative;
|
||||
}
|
||||
}
|
||||
|
||||
& .user-card {
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
margin-top: 5px;
|
||||
z-index: @zindex-popover;
|
||||
}
|
||||
}
|
||||
}
|
||||
.post-body {
|
||||
|
@ -7,6 +7,14 @@
|
||||
&, & a, & .close {
|
||||
color: @fl-body-hero-color;
|
||||
}
|
||||
& h2 {
|
||||
margin: 0;
|
||||
font-size: 16px;
|
||||
font-weight: normal;
|
||||
line-height: 1.5em;
|
||||
}
|
||||
}
|
||||
.welcome-hero {
|
||||
& a, & .close {
|
||||
opacity: 0.5;
|
||||
}
|
||||
@ -14,12 +22,6 @@
|
||||
float: right;
|
||||
margin-top: -10px;
|
||||
}
|
||||
& h2 {
|
||||
margin: 0;
|
||||
font-size: 16px;
|
||||
font-weight: normal;
|
||||
line-height: 1.5em;
|
||||
}
|
||||
& p {
|
||||
margin: 5px 0 0;
|
||||
}
|
||||
|
@ -170,6 +170,7 @@ body {
|
||||
}
|
||||
& .btn-default.active, .open > .dropdown-toggle.btn-default {
|
||||
background: fadein(@fl-drawer-control-bg, 5%);
|
||||
color: @fl-drawer-control-color;
|
||||
}
|
||||
& .btn-naked {
|
||||
background: transparent;
|
||||
|
80
framework/core/ember/app/styles/flarum/user.less
Normal file
80
framework/core/ember/app/styles/flarum/user.less
Normal file
@ -0,0 +1,80 @@
|
||||
.user-card {
|
||||
.drawer-components();
|
||||
}
|
||||
.user-hero {
|
||||
& .contextual-controls {
|
||||
float: right;
|
||||
|
||||
& .dropdown-toggle .icon-glyph {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
.user-card-popover {
|
||||
width: 500px;
|
||||
padding: 20px;
|
||||
border-radius: @border-radius-base;
|
||||
.box-shadow(0 2px 6px @fl-shadow-color);
|
||||
|
||||
& .container {
|
||||
width: auto !important;
|
||||
padding: 0 !important;
|
||||
}
|
||||
& .user-identity {
|
||||
font-size: 22px;
|
||||
}
|
||||
}
|
||||
.user-profile {
|
||||
text-align: left;
|
||||
padding-left: 130px;
|
||||
max-width: 800px;
|
||||
|
||||
& .user-identity {
|
||||
display: inline;
|
||||
vertical-align: middle;
|
||||
}
|
||||
& .avatar {
|
||||
.avatar-size(96px);
|
||||
float: left;
|
||||
margin-left: -130px;
|
||||
border: 4px solid #fff;
|
||||
}
|
||||
& .badges {
|
||||
margin-left: 10px;
|
||||
}
|
||||
& .user-bio {
|
||||
margin-top: 15px;
|
||||
padding: 10px 10px 1px;
|
||||
margin: 5px -10px -5px;
|
||||
|
||||
&.editable:not(.editing) {
|
||||
cursor: text;
|
||||
|
||||
&:hover {
|
||||
border: 1px dashed rgba(255, 255, 255, 0.5);
|
||||
border-radius: @border-radius-base;
|
||||
padding: 9px 9px 0;
|
||||
}
|
||||
}
|
||||
|
||||
&, & textarea {
|
||||
font-size: 14px;
|
||||
}
|
||||
& textarea {
|
||||
padding: 10px;
|
||||
margin: -10px -10px 0;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
& .user-info {
|
||||
margin: 15px 0 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
font-size: 12px;
|
||||
|
||||
& > li {
|
||||
display: inline-block;
|
||||
margin-right: 15px;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
<div class="container">
|
||||
{{#if controls}}
|
||||
{{ui/dropdown-button items=controls class="contextual-controls" menuClass="pull-right" buttonClass=controlsButtonClass}}
|
||||
{{/if}}
|
||||
|
||||
<div class="user-profile">
|
||||
<h2 class="user-identity">
|
||||
{{#link-to "user" user}}{{user-avatar user}}{{user-name user}}{{/link-to}}
|
||||
</h2>
|
||||
|
||||
{{ui/item-list items=user.badges class="badges user-badges"}}
|
||||
|
||||
{{#if showBio}}
|
||||
<div class="user-bio {{if bioEditable "editable"}} {{if editingBio "editing"}}" {{action "editBio"}}>
|
||||
{{#if editingBio}}
|
||||
{{textarea value=user.bio class="form-control"}}
|
||||
{{else}}
|
||||
{{#if user.bioHtml}}
|
||||
{{{user.bioHtml}}}
|
||||
{{else if bioEditable}}
|
||||
<p>Write something about yourself...</p>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{ui/item-list items=info class="user-info"}}
|
||||
</div>
|
||||
</div>
|
9
framework/core/ember/app/templates/user.hbs
Normal file
9
framework/core/ember/app/templates/user.hbs
Normal file
@ -0,0 +1,9 @@
|
||||
{{user/user-card user=model class="hero user-hero" editable=true controlsButtonClass="btn btn-default"}}
|
||||
|
||||
<div class="container">
|
||||
<nav class="user-nav">
|
||||
{{ui/item-list items=view.sidebar}}
|
||||
</nav>
|
||||
|
||||
{{outlet}}
|
||||
</div>
|
7
framework/core/ember/app/views/user.js
Normal file
7
framework/core/ember/app/views/user.js
Normal file
@ -0,0 +1,7 @@
|
||||
import Ember from 'ember';
|
||||
|
||||
import HasItemLists from 'flarum/mixins/has-item-lists';
|
||||
|
||||
export default Ember.View.extend(HasItemLists, {
|
||||
itemLists: ['sidebar']
|
||||
});
|
Loading…
x
Reference in New Issue
Block a user