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'] +});