diff --git a/framework/core/ember/app/components/discussion/post-header/user.js b/framework/core/ember/app/components/discussion/post-header/user.js
index 8e35102e6..0b655af32 100644
--- a/framework/core/ember/app/components/discussion/post-header/user.js
+++ b/framework/core/ember/app/components/discussion/post-header/user.js
@@ -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}}
{{#link-to "user" post.user}}{{user-avatar post.user}} {{user-name post.user}}{{/link-to}} {{ui/item-list items=post.user.badges class="badges"}}
{{#if showCard}}{{user/user-card user=post.user class="user-card-popover" controlsButtonClass="btn btn-default btn-icon btn-sm btn-naked"}}{{/if}}{{else}}{{user-avatar post.user}} {{user-name post.user}}
{{/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);
+ });
+ }
});
diff --git a/framework/core/ember/app/components/user/user-card.js b/framework/core/ember/app/components/user/user-card.js
new file mode 100644
index 000000000..a49905787
--- /dev/null
+++ b/framework/core/ember/app/components/user/user-card.js
@@ -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');
+ }
+});
diff --git a/framework/core/ember/app/controllers/user.js b/framework/core/ember/app/controllers/user.js
new file mode 100644
index 000000000..b461f2cd3
--- /dev/null
+++ b/framework/core/ember/app/controllers/user.js
@@ -0,0 +1,5 @@
+import Ember from 'ember';
+
+export default Ember.Controller.extend({
+
+});
diff --git a/framework/core/ember/app/models/user.js b/framework/core/ember/app/models/user.js
index 33579bb52..3b8039a64 100644
--- a/framework/core/ember/app/models/user.js
+++ b/framework/core/ember/app/models/user.js
@@ -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'),
diff --git a/framework/core/ember/app/router.js b/framework/core/ember/app/router.js
index 5912c29da..33a4c27a2 100644
--- a/framework/core/ember/app/router.js
+++ b/framework/core/ember/app/router.js
@@ -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;
diff --git a/framework/core/ember/app/routes/user.js b/framework/core/ember/app/routes/user.js
new file mode 100644
index 000000000..d4efb89ca
--- /dev/null
+++ b/framework/core/ember/app/routes/user.js
@@ -0,0 +1,7 @@
+import Ember from 'ember';
+
+export default Ember.Route.extend({
+ model: function(params) {
+ return this.store.find('user', params.username);
+ }
+});
diff --git a/framework/core/ember/app/styles/app.less b/framework/core/ember/app/styles/app.less
index 6361546d5..93525dbd0 100644
--- a/framework/core/ember/app/styles/app.less
+++ b/framework/core/ember/app/styles/app.less
@@ -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";
diff --git a/framework/core/ember/app/styles/flarum/avatars.less b/framework/core/ember/app/styles/flarum/avatars.less
index 8c895ab0a..9a23ac6b4 100644
--- a/framework/core/ember/app/styles/flarum/avatars.less
+++ b/framework/core/ember/app/styles/flarum/avatars.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;
diff --git a/framework/core/ember/app/styles/flarum/badges.less b/framework/core/ember/app/styles/flarum/badges.less
index 55594e7c5..318513738 100644
--- a/framework/core/ember/app/styles/flarum/badges.less
+++ b/framework/core/ember/app/styles/flarum/badges.less
@@ -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;
diff --git a/framework/core/ember/app/styles/flarum/discussion.less b/framework/core/ember/app/styles/flarum/discussion.less
index f68993991..fb1dc8557 100644
--- a/framework/core/ember/app/styles/flarum/discussion.less
+++ b/framework/core/ember/app/styles/flarum/discussion.less
@@ -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 {
diff --git a/framework/core/ember/app/styles/flarum/hero.less b/framework/core/ember/app/styles/flarum/hero.less
index a6d3815c9..ea402b18b 100644
--- a/framework/core/ember/app/styles/flarum/hero.less
+++ b/framework/core/ember/app/styles/flarum/hero.less
@@ -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;
}
diff --git a/framework/core/ember/app/styles/flarum/layout.less b/framework/core/ember/app/styles/flarum/layout.less
index d1b71acd8..0648e3403 100644
--- a/framework/core/ember/app/styles/flarum/layout.less
+++ b/framework/core/ember/app/styles/flarum/layout.less
@@ -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;
diff --git a/framework/core/ember/app/styles/flarum/user.less b/framework/core/ember/app/styles/flarum/user.less
new file mode 100644
index 000000000..19bab8f95
--- /dev/null
+++ b/framework/core/ember/app/styles/flarum/user.less
@@ -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;
+ }
+ }
+}
diff --git a/framework/core/ember/app/templates/components/user/user-card.hbs b/framework/core/ember/app/templates/components/user/user-card.hbs
new file mode 100644
index 000000000..73a5ac780
--- /dev/null
+++ b/framework/core/ember/app/templates/components/user/user-card.hbs
@@ -0,0 +1,29 @@
+
+ {{#if controls}}
+ {{ui/dropdown-button items=controls class="contextual-controls" menuClass="pull-right" buttonClass=controlsButtonClass}}
+ {{/if}}
+
+
+
+ {{#link-to "user" user}}{{user-avatar user}}{{user-name user}}{{/link-to}}
+
+
+ {{ui/item-list items=user.badges class="badges user-badges"}}
+
+ {{#if showBio}}
+
+ {{#if editingBio}}
+ {{textarea value=user.bio class="form-control"}}
+ {{else}}
+ {{#if user.bioHtml}}
+ {{{user.bioHtml}}}
+ {{else if bioEditable}}
+
Write something about yourself...
+ {{/if}}
+ {{/if}}
+
+ {{/if}}
+
+ {{ui/item-list items=info class="user-info"}}
+
+
diff --git a/framework/core/ember/app/templates/user.hbs b/framework/core/ember/app/templates/user.hbs
new file mode 100644
index 000000000..c9421f2f9
--- /dev/null
+++ b/framework/core/ember/app/templates/user.hbs
@@ -0,0 +1,9 @@
+{{user/user-card user=model class="hero user-hero" editable=true controlsButtonClass="btn btn-default"}}
+
+
+
+
+ {{outlet}}
+
diff --git a/framework/core/ember/app/views/user.js b/framework/core/ember/app/views/user.js
new file mode 100644
index 000000000..9ad36642a
--- /dev/null
+++ b/framework/core/ember/app/views/user.js
@@ -0,0 +1,7 @@
+import Ember from 'ember';
+
+import HasItemLists from 'flarum/mixins/has-item-lists';
+
+export default Ember.View.extend(HasItemLists, {
+ itemLists: ['sidebar']
+});