Two Column User View

This commit is contained in:
Robin Ward 2013-10-10 12:48:26 -04:00
parent f81b2dc3f2
commit dd63e6d28f
16 changed files with 570 additions and 710 deletions

View File

@ -7,25 +7,5 @@
@module Discourse
**/
Discourse.UserActivityController = Discourse.ObjectController.extend({
needs: ['composer'],
privateMessageView: function() {
return (this.get('userActionType') === Discourse.UserAction.TYPES.messages_sent) ||
(this.get('userActionType') === Discourse.UserAction.TYPES.messages_received);
}.property('userActionType'),
actions: {
composePrivateMessage: function() {
return this.get('controllers.composer').open({
action: Discourse.Composer.PRIVATE_MESSAGE,
usernames: this.get('model.username'),
archetypeId: 'private_message',
draftKey: 'new_private_message'
});
}
},
privateMessagesActive: Em.computed.equal('pmView', 'index'),
privateMessagesMineActive: Em.computed.equal('pmView', 'mine'),
privateMessagesUnreadActive: Em.computed.equal('pmView', 'unread')
needs: ['composer']
});

View File

@ -14,7 +14,16 @@ Discourse.UserController = Discourse.ObjectController.extend({
canSeePrivateMessages: function() {
return this.get('viewingSelf') || Discourse.User.currentProp('staff');
}.property('viewingSelf')
}.property('viewingSelf'),
privateMessageView: function() {
return (this.get('userActionType') === Discourse.UserAction.TYPES.messages_sent) ||
(this.get('userActionType') === Discourse.UserAction.TYPES.messages_received);
}.property('userActionType'),
privateMessagesActive: Em.computed.equal('pmView', 'index'),
privateMessagesMineActive: Em.computed.equal('pmView', 'mine'),
privateMessagesUnreadActive: Em.computed.equal('pmView', 'unread')
});

View File

@ -0,0 +1,39 @@
/**
The base route for showing a user's activity
@class UserActivityRoute
@extends Discourse.Route
@namespace Discourse
@module Discourse
**/
Discourse.UserActivityRoute = Discourse.Route.extend({
model: function() {
return this.modelFor('user');
},
setupController: function(controller, user) {
this.controllerFor('userActivity').set('model', user);
this.controllerFor('user').set('pmView', null);
// Bring up a draft
var composerController = this.controllerFor('composer');
controller.set('model', user);
if (Discourse.User.current()) {
Discourse.Draft.get('new_private_message').then(function(data) {
if (data.draft) {
composerController.open({
draft: data.draft,
draftKey: 'new_private_message',
ignoreIfChanged: true,
draftSequence: data.draft_sequence
});
}
});
}
}
});
Discourse.UserPrivateMessagesRoute = Discourse.UserActivityRoute.extend({});

View File

@ -0,0 +1,33 @@
/**
The base route for showing an activity stream.
@class UserActivityStreamRoute
@extends Discourse.Route
@namespace Discourse
@module Discourse
**/
Discourse.UserActivityStreamRoute = Discourse.Route.extend({
model: function() {
return this.modelFor('user').get('stream');
},
afterModel: function() {
return this.modelFor('user').get('stream').filterBy(this.get('userActionType'));
},
renderTemplate: function() {
this.render('user_stream', {into: 'user', outlet: 'userOutlet'});
},
setupController: function(controller, model) {
controller.set('model', model);
this.controllerFor('user_activity').set('userActionType', this.get('userActionType'));
}
});
// Build all activity stream routes
['bookmarks', 'edits', 'likes_given', 'likes_received', 'replies', 'posts', 'index'].forEach(function (userAction) {
Discourse["UserActivity" + userAction.classify() + "Route"] = Discourse.UserActivityStreamRoute.extend({
userActionType: Discourse.UserAction.TYPES[userAction]
});
});

View File

@ -0,0 +1,13 @@
/**
If we request /user/eviltrout without a sub route.
@class UserIndexRoute
@extends Discourse.Route
@namespace Discourse
@module Discourse
**/
Discourse.UserIndexRoute = Discourse.UserActivityRoute.extend({
redirect: function() {
this.transitionTo('userActivity', this.modelFor('user'));
}
});

View File

@ -0,0 +1,17 @@
/**
This route shows who a user has invited
@class UserInvitedRoute
@extends Discourse.Route
@namespace Discourse
@module Discourse
**/
Discourse.UserInvitedRoute = Discourse.Route.extend({
renderTemplate: function() {
this.render({ into: 'user', outlet: 'userOutlet' });
},
model: function() {
return Discourse.InviteList.findInvitedBy(this.modelFor('user'));
}
});

View File

@ -8,6 +8,22 @@
**/
Discourse.UserRoute = Discourse.Route.extend({
actions: {
logout: function() {
Discourse.logout();
},
composePrivateMessage: function() {
var user = this.modelFor('user');
return this.controllerFor('composer').open({
action: Discourse.Composer.PRIVATE_MESSAGE,
usernames: user.get('username'),
archetypeId: 'private_message',
draftKey: 'new_private_message'
});
}
},
model: function(params) {
// If we're viewing the currently logged in user, return that object
@ -53,157 +69,3 @@ Discourse.UserRoute = Discourse.Route.extend({
}
});
/**
This route shows who a user has invited
@class UserInvitedRoute
@extends Discourse.Route
@namespace Discourse
@module Discourse
**/
Discourse.UserInvitedRoute = Discourse.Route.extend({
renderTemplate: function() {
this.render({ into: 'user', outlet: 'userOutlet' });
},
model: function() {
return Discourse.InviteList.findInvitedBy(this.modelFor('user'));
}
});
/**
The base route for showing a user's activity
@class UserActivityRoute
@extends Discourse.Route
@namespace Discourse
@module Discourse
**/
Discourse.UserActivityRoute = Discourse.Route.extend({
renderTemplate: function() {
this.render('user_activity', {into: 'user', outlet: 'userOutlet' });
},
model: function() {
return this.modelFor('user');
},
setupController: function(controller, user) {
this.controllerFor('userActivity').set('model', user);
var composerController = this.controllerFor('composer');
controller.set('model', user);
if (Discourse.User.current()) {
Discourse.Draft.get('new_private_message').then(function(data) {
if (data.draft) {
composerController.open({
draft: data.draft,
draftKey: 'new_private_message',
ignoreIfChanged: true,
draftSequence: data.draft_sequence
});
}
});
}
}
});
Discourse.UserPrivateMessagesRoute = Discourse.UserActivityRoute.extend({});
/**
If we request /user/eviltrout without a sub route.
@class UserIndexRoute
@extends Discourse.Route
@namespace Discourse
@module Discourse
**/
Discourse.UserIndexRoute = Discourse.UserActivityRoute.extend({
redirect: function() {
this.transitionTo('userActivity', this.modelFor('user'));
}
});
/**
The base route for showing an activity stream.
@class UserActivityStreamRoute
@extends Discourse.Route
@namespace Discourse
@module Discourse
**/
Discourse.UserActivityStreamRoute = Discourse.Route.extend({
model: function() {
return this.modelFor('user').get('stream');
},
afterModel: function() {
return this.modelFor('user').get('stream').filterBy(this.get('userActionType'));
},
renderTemplate: function() {
this.render('user_stream', {into: 'user_activity', outlet: 'activity'});
},
setupController: function(controller, model) {
controller.set('model', model);
this.controllerFor('user_activity').set('userActionType', this.get('userActionType'));
}
});
// Build all activity stream routes
['bookmarks', 'edits', 'likes_given', 'likes_received', 'replies', 'posts', 'index'].forEach(function (userAction) {
Discourse["UserActivity" + userAction.classify() + "Route"] = Discourse.UserActivityStreamRoute.extend({
userActionType: Discourse.UserAction.TYPES[userAction]
});
});
Discourse.UserTopicListRoute = Discourse.Route.extend({
renderTemplate: function() {
this.render('paginated_topic_list', {into: 'user_activity', outlet: 'activity'});
},
setupController: function(controller, model) {
this.controllerFor('user_activity').set('userActionType', this.get('userActionType'));
controller.set('model', model);
}
});
function createPMRoute(viewName, path, type) {
return Discourse.UserTopicListRoute.extend({
userActionType: Discourse.UserAction.TYPES.messages_received,
model: function() {
return Discourse.TopicList.find('topics/' + path + '/' + this.modelFor('user').get('username_lower'));
},
setupController: function(controller, model) {
this._super(controller, model);
controller.set('hideCategories', true);
this.controllerFor('userActivity').set('pmView', viewName);
}
});
}
Discourse.UserPrivateMessagesIndexRoute = createPMRoute('index', 'private-messages');
Discourse.UserPrivateMessagesMineRoute = createPMRoute('mine', 'private-messages-sent');
Discourse.UserPrivateMessagesUnreadRoute = createPMRoute('unread', 'private-messages-unread');
Discourse.UserActivityTopicsRoute = Discourse.UserTopicListRoute.extend({
userActionType: Discourse.UserAction.TYPES.topics,
model: function() {
return Discourse.TopicList.find('topics/created-by/' + this.modelFor('user').get('username_lower'));
}
});
Discourse.UserActivityFavoritesRoute = Discourse.UserTopicListRoute.extend({
userActionType: Discourse.UserAction.TYPES.favorites,
model: function() {
return Discourse.TopicList.find('favorited?user_id=' + this.modelFor('user').get('id'));
}
});

View File

@ -0,0 +1,48 @@
Discourse.UserTopicListRoute = Discourse.Route.extend({
renderTemplate: function() {
this.render('paginated_topic_list', {into: 'user', outlet: 'userOutlet'});
},
setupController: function(controller, model) {
this.controllerFor('user_activity').set('userActionType', this.get('userActionType'));
controller.set('model', model);
}
});
function createPMRoute(viewName, path, type) {
return Discourse.UserTopicListRoute.extend({
userActionType: Discourse.UserAction.TYPES.messages_received,
model: function() {
return Discourse.TopicList.find('topics/' + path + '/' + this.modelFor('user').get('username_lower'));
},
setupController: function(controller, model) {
this._super(controller, model);
controller.set('hideCategories', true);
this.controllerFor('user').set('pmView', viewName);
}
});
}
Discourse.UserPrivateMessagesIndexRoute = createPMRoute('index', 'private-messages');
Discourse.UserPrivateMessagesMineRoute = createPMRoute('mine', 'private-messages-sent');
Discourse.UserPrivateMessagesUnreadRoute = createPMRoute('unread', 'private-messages-unread');
Discourse.UserActivityTopicsRoute = Discourse.UserTopicListRoute.extend({
userActionType: Discourse.UserAction.TYPES.topics,
model: function() {
return Discourse.TopicList.find('topics/created-by/' + this.modelFor('user').get('username_lower'));
}
});
Discourse.UserActivityFavoritesRoute = Discourse.UserTopicListRoute.extend({
userActionType: Discourse.UserAction.TYPES.favorites,
model: function() {
return Discourse.TopicList.find('favorited?user_id=' + this.modelFor('user').get('id'));
}
});

View File

@ -1,70 +1,3 @@
<div id='user-info'>
<nav class='buttons'>
{{#if can_edit}}
{{#link-to "preferences" class="btn"}}{{i18n user.edit}}{{/link-to}}
{{/if}}
<br/>
{{#if can_send_private_message_to_user}}
<button class='btn create' {{action composePrivateMessage}}>
<i class='icon icon-envelope'></i>
{{i18n user.private_message}}
</button>
{{/if}}
</nav>
<div class='clearfix'></div>
<ul class='action-list nav-stacked side-nav'>
{{#if privateMessageView}}
<li {{bindAttr class=":noGlyph privateMessagesActive:active"}}>
{{#link-to 'userPrivateMessages.index' model}}{{i18n user.messages.all}}{{/link-to}}
</li>
<li {{bindAttr class=":noGlyph privateMessagesMineActive:active"}}>
{{#link-to 'userPrivateMessages.mine' model}}{{i18n user.messages.mine}}{{/link-to}}
</li>
<li {{bindAttr class=":noGlyph privateMessagesUnreadActive:active"}}>
{{#link-to 'userPrivateMessages.unread' model}}{{i18n user.messages.unread}}{{/link-to}}
</li>
{{else}}
{{activityFilter count=statsCountNonPM user=model}}
{{#each stat in statsExcludingPms}}
{{activityFilter content=stat user=model}}
{{/each}}
{{/if}}
</ul>
<div class='show'>
<dl>
{{#if websiteName}}
<dt>{{i18n user.website}}:</dt><dd><a {{bindAttr href="website"}} target="_blank">{{websiteName}}</a></dd>
{{/if}}
{{#if created_at}}
<dt>{{i18n user.created}}:</dt><dd>{{date created_at}}</dd>
{{/if}}
{{#if last_posted_at}}
<dt>{{i18n user.last_posted}}:</dt><dd>{{date last_posted_at}}</dd>
{{/if}}
{{#if last_seen_at}}
<dt>{{i18n user.last_seen}}:</dt><dd>{{date last_seen_at}}</dd>
{{/if}}
{{#if invited_by}}
<dt>{{i18n user.invited_by}}:</dt><dd>{{#link-to 'userActivity' invited_by}}{{invited_by.username}}{{/link-to}}</dd>
{{/if}}
{{#if email}}
<dt>{{i18n user.email.title}}:</dt><dd {{bindAttr title="email"}}>{{email}}</dd>
{{/if}}
<dt>{{i18n user.trust_level}}:</dt><dd>{{trustLevel.name}}</dd>
</dl>
</div>
{{#if can_edit}}
<div style='margin-top: 10px'>
<button class='btn' data-not-implemented='true' disabled title="{{i18n not_implemented}}">{{i18n user.download_archive}}</button>
</div>
{{/if}}
</div>
<div id='user-activity'>
{{outlet activity}}
</div>
YOU SHOULD REMOVE THIS
{{outlet activity}}

View File

@ -1,127 +1,130 @@
<form class="form-horizontal">
<section class='user-content'>
<div class="control-group">
<label class="control-label">{{i18n user.username.title}}</label>
<div class="controls">
<span class='static'>{{username}}</span>
{{#if can_edit_username}}
{{#link-to "preferences.username" class="btn pad-left"}}<i class="icon-pencil"></i>{{/link-to}}
{{/if}}
</div>
<div class='instructions'>
{{{i18n user.username.short_instructions username="username"}}}
</div>
</div>
<form class="form-horizontal">
<div class="control-group">
<label class="control-label">{{i18n user.name.title}}</label>
<div class="controls">
{{textField value=name classNames="input-xxlarge"}}
</div>
<div class='instructions'>
{{i18n user.name.instructions}}
</div>
</div>
<div class="control-group">
<label class="control-label">{{i18n user.email.title}}</label>
<div class="controls">
<span class='static'>{{email}}</span>
{{#if can_edit_email}}
{{#link-to "preferences.email" class="btn pad-left"}}<i class="icon-pencil"></i>{{/link-to}}
{{/if}}
</div>
<div class='instructions'>
{{i18n user.email.instructions}}
</div>
</div>
<div class="control-group">
<label class="control-label">{{i18n user.password.title}}</label>
<div class="controls">
<a href="#" {{action changePassword}} class='btn'><i class="icon icon-envelope"></i>{{i18n user.change_password.action}}</a> {{passwordProgress}}
</div>
</div>
<div class="control-group">
<label class="control-label">{{i18n user.avatar.title}}</label>
<div class="controls">
{{boundAvatar model imageSize="large"}}
<button {{action showAvatarSelector}} class="btn pad-left"><i class="icon-pencil"></i></button>
</div>
</div>
<div class="control-group">
<label class="control-label">{{i18n user.bio}}</label>
<div class="controls">
{{pagedown value=bio_raw}}
</div>
</div>
<div class="control-group">
<label class="control-label">{{i18n user.website}}</label>
<div class="controls">
{{textField value=website classNames="input-xxlarge"}}
</div>
</div>
<div class="control-group">
<label class="control-label">{{i18n user.email_settings}}</label>
<div class="controls">
<label>{{view Ember.Checkbox checkedBinding="email_digests"}}
{{i18n user.email_digests.title}}</label>
{{#if email_digests}}
<div class='control-indent'>
{{combobox valueAttribute="value" content=digestFrequencies value=digest_after_days}}
</div>
{{/if}}
<label>{{view Ember.Checkbox checkedBinding="email_private_messages"}}
{{i18n user.email_private_messages}}</label>
<label>{{view Ember.Checkbox checkedBinding="email_direct"}}
{{i18n user.email_direct}}</label>
<label>{{view Ember.Checkbox checkedBinding="email_always"}}
{{i18n user.email_always}}</label>
</div>
<div class='instructions'>
{{i18n user.email.frequency}}
</div>
</div>
<div class="control-group other">
<label class="control-label">{{i18n user.other_settings}}</label>
<div class="controls">
<label>{{i18n user.auto_track_topics}}</label>
{{combobox valueAttribute="value" content=autoTrackDurations value=auto_track_topics_after_msecs}}
<div class="control-group">
<label class="control-label">{{i18n user.username.title}}</label>
<div class="controls">
<span class='static'>{{username}}</span>
{{#if can_edit_username}}
{{#link-to "preferences.username" class="btn pad-left"}}<i class="icon-pencil"></i>{{/link-to}}
{{/if}}
</div>
<div class='instructions'>
{{{i18n user.username.short_instructions username="username"}}}
</div>
</div>
<div class="controls">
<label>{{i18n user.new_topic_duration.label}}</label>
{{combobox valueAttribute="value" content=considerNewTopicOptions value=new_topic_duration_minutes}}
<div class="control-group">
<label class="control-label">{{i18n user.name.title}}</label>
<div class="controls">
{{textField value=name classNames="input-xxlarge"}}
</div>
<div class='instructions'>
{{i18n user.name.instructions}}
</div>
</div>
<div class="controls">
<label>{{view Ember.Checkbox checkedBinding="external_links_in_new_tab"}}
{{i18n user.external_links_in_new_tab}}</label>
<label>{{view Ember.Checkbox checkedBinding="enable_quoting"}}
{{i18n user.enable_quoting}}</label>
<div class="control-group">
<label class="control-label">{{i18n user.email.title}}</label>
<div class="controls">
<span class='static'>{{email}}</span>
{{#if can_edit_email}}
{{#link-to "preferences.email" class="btn pad-left"}}<i class="icon-pencil"></i>{{/link-to}}
{{/if}}
</div>
<div class='instructions'>
{{i18n user.email.instructions}}
</div>
</div>
<div class="controls">
<label>
{{view Ember.Checkbox checkedBinding="dynamic_favicon"}}
{{i18n user.dynamic_favicon}}
</label>
<div class="control-group">
<label class="control-label">{{i18n user.password.title}}</label>
<div class="controls">
<a href="#" {{action changePassword}} class='btn'><i class="icon icon-envelope"></i>{{i18n user.change_password.action}}</a> {{passwordProgress}}
</div>
</div>
</div>
<div class="control-group">
<div class="controls">
<button {{action save}} {{bindAttr disabled="saveDisabled"}} class="btn btn-primary">{{saveButtonText}}</button>
{{#if saved}}{{i18n saved}}{{/if}}
<div class="control-group">
<label class="control-label">{{i18n user.avatar.title}}</label>
<div class="controls">
{{boundAvatar model imageSize="large"}}
<button {{action showAvatarSelector}} class="btn pad-left"><i class="icon-pencil"></i></button>
</div>
</div>
</div>
</form>
<div class="control-group">
<label class="control-label">{{i18n user.bio}}</label>
<div class="controls">
{{pagedown value=bio_raw}}
</div>
</div>
<div class="control-group">
<label class="control-label">{{i18n user.website}}</label>
<div class="controls">
{{textField value=website classNames="input-xxlarge"}}
</div>
</div>
<div class="control-group">
<label class="control-label">{{i18n user.email_settings}}</label>
<div class="controls">
<label>{{view Ember.Checkbox checkedBinding="email_digests"}}
{{i18n user.email_digests.title}}</label>
{{#if email_digests}}
<div class='control-indent'>
{{combobox valueAttribute="value" content=digestFrequencies value=digest_after_days}}
</div>
{{/if}}
<label>{{view Ember.Checkbox checkedBinding="email_private_messages"}}
{{i18n user.email_private_messages}}</label>
<label>{{view Ember.Checkbox checkedBinding="email_direct"}}
{{i18n user.email_direct}}</label>
<label>{{view Ember.Checkbox checkedBinding="email_always"}}
{{i18n user.email_always}}</label>
</div>
<div class='instructions'>
{{i18n user.email.frequency}}
</div>
</div>
<div class="control-group other">
<label class="control-label">{{i18n user.other_settings}}</label>
<div class="controls">
<label>{{i18n user.auto_track_topics}}</label>
{{combobox valueAttribute="value" content=autoTrackDurations value=auto_track_topics_after_msecs}}
</div>
<div class="controls">
<label>{{i18n user.new_topic_duration.label}}</label>
{{combobox valueAttribute="value" content=considerNewTopicOptions value=new_topic_duration_minutes}}
</div>
<div class="controls">
<label>{{view Ember.Checkbox checkedBinding="external_links_in_new_tab"}}
{{i18n user.external_links_in_new_tab}}</label>
<label>{{view Ember.Checkbox checkedBinding="enable_quoting"}}
{{i18n user.enable_quoting}}</label>
</div>
<div class="controls">
<label>
{{view Ember.Checkbox checkedBinding="dynamic_favicon"}}
{{i18n user.dynamic_favicon}}
</label>
</div>
</div>
<div class="control-group">
<div class="controls">
<button {{action save}} {{bindAttr disabled="saveDisabled"}} class="btn btn-primary">{{saveButtonText}}</button>
{{#if saved}}{{i18n saved}}{{/if}}
</div>
</div>
</form>
</section>

View File

@ -1,47 +1,102 @@
{{#unless loading}}
<div class="user-heading">
<div class="container">
<div class="full-width" id='user-menu'>
<h1>{{name}}<span>{{username}}{{{statusIcon}}}</span></h1>
<div class="container">
{{#if viewingSelf}}
<button {{action "logout" target="Discourse"}} class='btn'>{{i18n user.log_out}}</button>
{{/if}}
{{#if currentUser.staff}}
<a {{bindAttr href="adminPath"}} class='btn'><i class="icon-wrench"></i>&nbsp;{{i18n admin.user.show_admin_profile}}</a>
{{/if}}
<ul class="nav nav-pills">
<li>
{{#link-to 'userActivity'}}{{i18n user.activity_stream}}{{/link-to}}
<section class='user-navigation'>
<ul class='action-list nav-stacked'>
{{activityFilter count=statsCountNonPM user=model}}
{{#each stat in statsExcludingPms}}
{{activityFilter content=stat user=model}}
{{/each}}
</ul>
{{#if viewingSelf}}
<h3><i class='icon icon-envelope'></i> {{i18n user.private_messages}}</h3>
<ul class='action-list nav-stacked'>
<li {{bindAttr class=":noGlyph privateMessagesActive:active"}}>
{{#link-to 'userPrivateMessages.index' model}}{{i18n user.messages.all}}<span class='icon-chevron-right'></span>{{/link-to}}
</li>
{{#if canSeePrivateMessages}}
<li>
{{#link-to 'userPrivateMessages'}}{{i18n user.private_messages}}{{/link-to}}
</li>
{{/if}}
<li>
{{#link-to 'user.invited'}}{{i18n user.invited.title}}{{/link-to}}
<li {{bindAttr class=":noGlyph privateMessagesMineActive:active"}}>
{{#link-to 'userPrivateMessages.mine' model}}{{i18n user.messages.mine}}<span class='icon-chevron-right'></span>{{/link-to}}
</li>
<li {{bindAttr class=":noGlyph privateMessagesUnreadActive:active"}}>
{{#link-to 'userPrivateMessages.unread' model}}{{i18n user.messages.unread}}<span class='icon-chevron-right'></span>{{/link-to}}
</li>
{{#if can_edit}}
<li>
{{#link-to 'preferences'}}{{i18n user.preferences}}{{/link-to}}
</li>
{{/if}}
</ul>
<div class='avatar-wrapper'>
{{boundAvatar model imageSize="huge"}}
{{/if}}
{{#if can_edit}}
<div style='margin-top: 10px'>
<button class='btn' data-not-implemented='true' disabled title="{{i18n not_implemented}}"><i class='icon icon-download-alt'></i>{{i18n user.download_archive}}</button>
</div>
</div>
</div>
</div>
<div class="container">
<div class='user-info clearfix'>
<div class='about-me'>
{{{bio_excerpt}}}
</div>
</div>
</div>
<div class="container">
{{outlet userOutlet}}
{{/if}}
</section>
<section class='user-main'>
<section class='about'>
<div class='details'>
<div class='primary'>
{{boundAvatar model imageSize="huge"}}
<h1>{{username}} {{{statusIcon}}}</h1>
<h2>{{name}}</h2>
<div class='bio'>{{{bio_excerpt}}}</div>
</div>
<div class='secondary'>
<dl>
{{#if websiteName}}
<dt>{{i18n user.website}}</dt><dd><a {{bindAttr href="website"}} target="_blank">{{websiteName}}</a></dd>
{{/if}}
{{#if created_at}}
<dt>{{i18n user.created}}</dt><dd>{{date created_at}}</dd>
{{/if}}
{{#if last_posted_at}}
<dt>{{i18n user.last_posted}}</dt><dd>{{date last_posted_at}}</dd>
{{/if}}
{{#if last_seen_at}}
<dt>{{i18n user.last_seen}}</dt><dd>{{date last_seen_at}}</dd>
{{/if}}
{{#if invited_by}}
<dt>{{i18n user.invited_by}}</dt><dd>{{#link-to 'userActivity' invited_by}}{{invited_by.username}}{{/link-to}}</dd>
{{/if}}
{{#if email}}
<dt>{{i18n user.email.title}}</dt><dd {{bindAttr title="email"}}>{{email}}</dd>
{{/if}}
<dt>{{i18n user.trust_level}}</dt><dd>{{trustLevel.name}}</dd>
</dl>
</div>
<div style='clear: both'></div>
</div>
<section class='controls'>
{{#if can_send_private_message_to_user}}
<button class='btn btn-primary right' {{action composePrivateMessage}}>
<i class='icon icon-envelope'></i>
{{i18n user.private_message}}
</button>
{{/if}}
{{#if viewingSelf}}
<button {{action "logout"}} class='btn btn-danger right'><i class='icon icon-signout'></i>{{i18n user.log_out}}</button>
{{/if}}
{{#if currentUser.staff}}
<a {{bindAttr href="adminPath"}} class='btn'><i class="icon-wrench"></i>&nbsp;{{i18n admin.user.show_admin_profile}}</a>
{{/if}}
{{#if can_edit}}
{{#link-to 'preferences' class="btn"}}<i class='icon icon-cog'></i>{{i18n user.preferences}}{{/link-to}}
{{/if}}
{{#link-to 'user.invited' class="btn"}}<i class='icon icon-envelope-alt'></i>{{i18n user.invited.title}}{{/link-to}}
</section>
</section>
{{outlet userOutlet}}
</section>
</div>
{{/unless}}

View File

@ -7,7 +7,6 @@
@module Discourse
**/
Discourse.UserActivityView = Discourse.View.extend({
templateName: 'user/activity',
userBinding: 'controller.content',
didInsertElement: function() {

View File

@ -71,7 +71,7 @@ $nav-pills-background-color-active: #e45735 !default;
// Stacked nav
$nav-stacked-border-color: #b9b9b9 !default;
$nav-stacked-border-color: #ccc !default;
$nav-stacked-background-color: #fafafa !default;
$nav-stacked-divider-color: #e6e6e6 !default;
$nav-stacked-chevron-color: #ccc !default;

View File

@ -7,6 +7,21 @@
width: 530px;
height: 100px;
}
input[type=text] {
@include small-width {
width: 450px;
}
}
#pagedown-editor {
width: 450px;
textarea {
width: 440px;
}
}
.static {
color: $black;
margin-top: 5px;
@ -40,29 +55,15 @@
}
}
#user-menu {
.btn {
float: right;
margin: 5px 0 0 10px;
}
}
#about-me {
padding: 4px;
margin: -4px;
display: block;
width: 220px;
min-height: 200px;
background-color: #f8f8f8;
border-radius: 5px;
color: #444;
word-wrap: break-word;
}
#user-info {
.user-navigation {
width: 240px;
margin-right: 20px;
float: left;
h3 {
color: #666;
}
.summary {
height: 50px;
}
@ -88,43 +89,6 @@
cursor: pointer;
}
}
.show {
dl {
width: 100%;
overflow: hidden;
dt {
margin: 0;
padding: 0;
width: 80px;
font-size: 12px;
color: #555555;
float: left;
clear: left;
}
dd {
margin: 0;
padding: 0;
width: 100px;
float: left;
color: #444444;
}
}
}
.avatar {
vertical-align: bottom;
a {
display: inline-block;
}
}
form {
.bio {
width: 220px;
height: 150px;
}
}
.side-nav {
margin-top: 5px;
}
}
#no-invites {
@ -144,104 +108,97 @@
}
}
#user-menu h1 {
color: #2d3234;
float: left;
padding-left: 150px;
span {
font-size: 18px;
color: #676b6c;
margin-left: 15px;
font-weight: lighter;
position: relative;
top: -4px;
.icon {
margin-left: 5px;
font-size: 14px;
}
}
}
#user-menu {
margin: 10px 0 0;
}
.user-heading {
border-bottom: 1px solid #bcbcbc;
background-color: #e6e6e6;
margin-top: -15px;
margin-bottom: 10px;
position: relative;
.nav {
float: right;
margin: 5px 0 14px 5px;
}
}
.user-info {
margin-bottom: 10px;
.about-me {
position: relative;
border: 1px solid #b9b9b9;
padding: 6px;
@include border-radius-all(4px);
float: left;
width: 936px;
height: 57px;
margin-left: 150px;
background-color: white;
@include box-shadow((0 1px 2px rgba($black, 0.07), inset 0 -4px 4px -4px rgba($black, 0.14)));
&:before,
&:after {
position: absolute;
width: 0;
height: 0;
content: "";
border-style: solid;
border-color: transparent;
pointer-events: none;
}
&:before {
top: 12px;
left: -10px;
border-width: 10px 10px 10px 0;
border-right-color: #b9b9b9;
}
&:after {
top: 13px;
left: -9px;
border-width: 9px 9px 9px 0;
border-right-color: $white;
}
.missing-profile {
color: lighten(#000, 70%);
}
}
@include medium-width {
.about-me {
width: 821px;
}
}
@include small-width {
.about-me {
width: 776px;
}
}
}
.user-heading {
.avatar-wrapper {
position: absolute;
display: block;
width: 120px;
}
}
#user-activity {
.user-main {
width: 840px;
float: left;
margin-bottom: 50px;
@include medium-width {
width: 730px;
}
@include small-width {
width: 650px;
}
.user-content {
padding: 10px 8px;
background-color: white;
border: 1px solid #ddd;
margin-bottom: 10px;
@include border-radius-all(4px);
}
.about {
background-color: #444;
margin-bottom: 10px;
overflow: hidden;
border: 1px solid #bbb;
color: #fff;
@include border-radius-all(4px);
.details {
text-align: center;
padding: 10px;
h1 {
font-size: 30px;
font-weight: normal;
}
h2 {
font-size: 20px;
margin-bottom: 6px;
font-weight: normal;
}
a[href] {
color: #fff;
}
img.avatar {
border: 3px solid #eee;
margin-bottom: 4px;
}
.primary {
margin-top: 30px;
float: left;
width: 75%;
}
.secondary {
float: right;
background-color: #222;
text-align: right;
padding: 0 10px;
width: 20%;
@include border-radius-all(4px);
dd {
color: white;
margin: 0 0 7px 0;
}
dt {
color: #aaa;
margin: 0;
}
}
}
.controls {
background-color: #ddd;
margin-top: 10px;
padding: 5px;
.right {
float: right;
}
}
}
.user-stream {
.excerpt {
margin: 5px 0px;
@ -263,10 +220,9 @@
.item {
padding: 10px 8px;
background-color: white;
border: 1px solid #b9b9b9;
border: 1px solid #ddd;
margin-bottom: 10px;
@include border-radius-all(4px);
@include box-shadow((0 1px 2px rgba($black, 0.07), inset 0 -4px 4px -4px rgba($black, 0.14)));
}
.type {
color: lighten($black, 40%);
@ -313,17 +269,6 @@
}
}
@include medium-width {
#user-activity {
width: 725px;
}
}
@include small-width {
#user-activity {
width: 680px;
}
}
.avatar-selector {
label {
display: inline-block;

View File

@ -40,13 +40,6 @@
}
}
#user-menu {
.btn {
float: right;
margin: 5px 0 0 10px;
}
}
#about-me {
padding: 4px;
margin: -4px;
@ -59,9 +52,12 @@
word-wrap: break-word;
}
#user-info {
margin-right: 20px;
float: left;
.user-navigation {
h3 {
color: #666;
}
.summary {
height: 50px;
}
@ -87,55 +83,6 @@
cursor: pointer;
}
}
.show {
dl {
width: 100%;
overflow: hidden;
dt {
margin: 0;
padding: 0;
width: 80px;
font-size: 12px;
color: #555555;
float: left;
clear: left;
}
dd {
margin: 0;
padding: 0;
width: 100px;
float: left;
color: #444444;
}
}
}
.avatar {
vertical-align: bottom;
a {
display: inline-block;
}
}
form {
.bio {
width: 220px;
height: 150px;
}
}
.nav-stacked {
> li {
display: inline-block;
> a {
padding: 7px;
}
}
.icon-chevron-right {
padding-left: 7px;
}
}
.side-nav {
margin: 0 5px;
max-width: 100%;
}
}
#no-invites {
@ -155,91 +102,69 @@
}
}
#user-menu h1 {
color: #2d3234;
float: left;
padding-left: 150px;
span {
font-size: 18px;
color: #676b6c;
font-weight: lighter;
position: relative;
top: 5px;
display: block;
.icon {
margin-left: 5px;
font-size: 14px;
}
}
}
#user-menu {
margin: 10px 0 0;
}
.user-heading {
border-bottom: 1px solid #bcbcbc;
background-color: #e6e6e6;
margin-top: -15px;
margin-bottom: 10px;
position: relative;
.nav {
float: left;
margin: 5px 0 10px 147px;
}
}
.user-info {
margin-bottom: 10px;
.about-me {
position: relative;
border: 1px solid #b9b9b9;
padding: 6px;
@include border-radius-all(4px);
float: left;
margin: 0 5px 0 20px;
background-color: white;
@include box-shadow((0 1px 2px rgba($black, 0.07), inset 0 -4px 4px -4px rgba($black, 0.14)));
&:before,
&:after {
position: absolute;
width: 0;
height: 0;
content: "";
border-style: solid;
border-color: transparent;
pointer-events: none;
}
&:before {
top: 12px;
left: -10px;
border-width: 10px 10px 10px 0;
border-right-color: #b9b9b9;
}
&:after {
top: 13px;
left: -9px;
border-width: 9px 9px 9px 0;
border-right-color: $white;
}
.missing-profile {
color: lighten(#000, 70%);
}
}
}
.user-heading {
.avatar-wrapper {
position: absolute;
display: block;
width: 120px;
}
}
#user-activity {
float: left;
.user-main {
clear: both;
margin-bottom: 50px;
.about {
background-color: #444;
margin-bottom: 10px;
overflow: hidden;
border: 1px solid #bbb;
color: #fff;
@include border-radius-all(4px);
.details {
text-align: center;
padding: 10px;
h1 {
font-size: 30px;
font-weight: normal;
}
h2 {
font-size: 20px;
margin-bottom: 6px;
font-weight: normal;
}
a[href] {
color: #fff;
}
img.avatar {
border: 3px solid #eee;
margin-bottom: 4px;
}
.secondary {
background-color: #222;
text-align: left;
padding: 0 10px;
@include border-radius-all(4px);
dd {
color: white;
margin: 0 0 7px 0;
}
dt {
color: #aaa;
margin: 0;
}
}
}
.controls {
background-color: #ddd;
margin-top: 0px;
padding: 5px;
button { margin-bottom: 3px; }
}
}
.user-stream {
.excerpt {
margin: 5px 0px;
@ -264,7 +189,6 @@
border: 1px solid #b9b9b9;
margin-bottom: 10px;
@include border-radius-all(4px);
@include box-shadow((0 1px 2px rgba($black, 0.07), inset 0 -4px 4px -4px rgba($black, 0.14)));
}
.type {
color: lighten($black, 40%);

View File

@ -5,8 +5,8 @@ test("Activity Streams", function() {
var streamTest = function(url) {
visit(url).then(function() {
ok(exists(".user-heading"), "The heading is rendered");
ok(exists("#user-activity"), "The activity is rendered");
ok(exists(".user-main"), "The main content is rendered");
ok(exists(".user-navigation"), "The navigation is rendered");
});
};