Worked on user view appearance

This commit is contained in:
Marcin Kurczewski 2014-09-07 09:57:01 +02:00
parent 3ec1b94ee7
commit f5606c4169
21 changed files with 279 additions and 51 deletions

View file

@ -8,6 +8,11 @@ body {
font-size: 17px;
}
h2 {
font-variant: small-caps;
font-weight: normal;
}
#middle {
padding: 0 2em;
}

View file

@ -1,5 +1,7 @@
.form-wrapper {
display: table;
margin: 0 auto;
text-align: left !important;
}
.form-row {

View file

@ -14,6 +14,7 @@
#top-navigation li a {
display: inline-block;
font-variant: small-caps;
padding: 0.5em 1em;
color: #000;
}

View file

@ -1,5 +1,6 @@
#user-list {
min-width: 20em;
text-align: center;
}
#user-list ul {
@ -25,3 +26,34 @@
display: inline-block;
padding: 0.2em 0.5em;
}
#user-list .users {
display: inline-block;
margin: 1em auto;
}
#user-list .users li {
text-align: left;
margin: 0.5em 0;
}
#user-list li:after {
clear: left;
content: '';
display: block;
}
#user-list .user img {
float: left;
vertical-align: top;
margin-right: 1em;
}
#user-list .user .details {
float: left;
vertical-align: top;
}
#user-list .user h1 {
margin-top: 0;
font-weight: normal;
font-size: 16pt;
}

51
public_html/css/user.css Normal file
View file

@ -0,0 +1,51 @@
#user-view {
min-width: 30em;
text-align: center;
}
#user-view .side {
text-align: center;
width: 150px;
float: left;
}
#user-view .top {
display: inline-block;
margin: 0 auto;
}
#user-view ul {
display: inline-block;
list-style-type: none;
text-align: left;
margin: 0;
padding: 0;
}
#user-view ul a {
cursor: pointer;
display: inline-block;
padding: 0.2em 0.5em;
}
#user-view ul a.active {
background: #faffca;
}
#user-view .tab {
display: none;
margin-top: 1.5em;
clear: both;
}
#user-view .tab.active {
display: block;
}
#user-view .tab.basic-info table {
margin: 0 auto;
text-align: left;
}
#user-view .tab.basic-info td {
padding: 0.2em 0.5em;
}

View file

@ -16,6 +16,7 @@
<link rel="stylesheet" type="text/css" href="/css/login-form.css"/>
<link rel="stylesheet" type="text/css" href="/css/registration-form.css"/>
<link rel="stylesheet" type="text/css" href="/css/user-list.css"/>
<link rel="stylesheet" type="text/css" href="/css/user.css"/>
</head>
<body>

View file

@ -13,26 +13,20 @@ App.Controls.FileDropper = function(
$fileInput.attr('multiple', allowMultiple);
$fileInput.hide();
$fileInput.change(function(e)
{
$fileInput.change(function(e) {
addFiles(this.files);
});
$dropDiv.on('dragenter', function(e)
{
$dropDiv.on('dragenter', function(e) {
$dropDiv.addClass('active');
}).on('dragleave', function(e)
{
}).on('dragleave', function(e) {
$dropDiv.removeClass('active');
}).on('dragover', function(e)
{
}).on('dragover', function(e) {
e.preventDefault();
}).on('drop', function(e)
{
}).on('drop', function(e) {
e.preventDefault();
addFiles(e.originalEvent.dataTransfer.files);
}).on('click', function(e)
{
}).on('click', function(e) {
$fileInput.show().focus().trigger('click').hide();
$dropDiv.addClass('active');
});

View file

@ -16,7 +16,9 @@ App.Presenters.PagedCollectionPresenter = function(util, promise, api) {
var totalRecords;
function init(args) {
parseSearchArgs(args.searchArgs);
pageNumber = parseInt(args.page) || 1;
searchOrder = args.order;
searchQuery = args.query;
baseUri = args.baseUri;
backendUri = args.backendUri;
renderCallback = args.renderCallback;
@ -99,13 +101,6 @@ App.Presenters.PagedCollectionPresenter = function(util, promise, api) {
});
}
function parseSearchArgs(searchArgs) {
var args = util.parseComplexRouteArgs(searchArgs);
pageNumber = parseInt(args.page) || 1;
searchOrder = args.order;
searchQuery = args.query;
}
return {
init: init,
render: render,

View file

@ -33,7 +33,7 @@ App.Presenters.UserAccountRemovalPresenter = function(
}
function render() {
$el = jQuery(target);
var $el = jQuery(target);
$el.html(template({
user: user,
canDeleteAccount: privileges.canDeleteAccount}));
@ -47,7 +47,8 @@ App.Presenters.UserAccountRemovalPresenter = function(
function accountRemovalFormSubmitted(e) {
e.preventDefault();
$messages = jQuery(target).find('.messages');
var $el = jQuery(target);
$messages = $el.find('.messages');
messagePresenter.hideMessages($messages);
if (!$el.find('input[name=confirmation]:visible').prop('checked')) {
messagePresenter.showError($messages, 'Must confirm to proceed.');

View file

@ -28,7 +28,7 @@ App.Presenters.UserBrowsingSettingsPresenter = function(
}
function render() {
$el = jQuery(target);
var $el = jQuery(target);
$el.html(template({user: user}));
}

View file

@ -26,9 +26,13 @@ App.Presenters.UserListPresenter = function(
}
function initPaginator(args) {
activeSearchOrder = util.parseComplexRouteArgs(args.searchArgs).order;
var searchArgs = util.parseComplexRouteArgs(args.searchArgs);
searchArgs.order = searchArgs.order || 'name';
activeSearchOrder = searchArgs.order;
pagedCollectionPresenter.init({
searchArgs: args.searchArgs,
pageNumber: searchArgs.page,
order: searchArgs.order,
baseUri: '#/users',
backendUri: '/users',
renderCallback: function updateCollection(data) {
@ -44,6 +48,7 @@ App.Presenters.UserListPresenter = function(
function render() {
$el.html(template({
userList: userList,
formatRelativeTime: util.formatRelativeTime,
}));
$el.find('.order a').click(orderLinkClicked);
$el.find('.order [data-order="' + activeSearchOrder + '"]').parent('li').addClass('active');
@ -52,8 +57,7 @@ App.Presenters.UserListPresenter = function(
pagedCollectionPresenter.render($pager);
};
function orderLinkClicked(e)
{
function orderLinkClicked(e) {
e.preventDefault();
var $orderLink = jQuery(this);
activeSearchOrder = $orderLink.attr('data-order');

View file

@ -18,6 +18,7 @@ App.Presenters.UserPresenter = function(
var template;
var user;
var userName;
var activeTab;
function init(args) {
userName = args.userName;
@ -39,7 +40,9 @@ App.Presenters.UserPresenter = function(
userBrowsingSettingsPresenter.init(_.extend(extendedContext, {target: '#browsing-settings-target'})),
userAccountSettingsPresenter.init(_.extend(extendedContext, {target: '#account-settings-target'})),
userAccountRemovalPresenter.init(_.extend(extendedContext, {target: '#account-removal-target'})))
.then(render);
.then(function() {
initTabs(args);
})
}).fail(function(response) {
$el.empty();
@ -47,6 +50,11 @@ App.Presenters.UserPresenter = function(
});
}
function initTabs(args) {
activeTab = args.tab || 'basic-info';
render();
}
function render() {
$el.html(template({
user: user,
@ -56,10 +64,23 @@ App.Presenters.UserPresenter = function(
userBrowsingSettingsPresenter.render();
userAccountSettingsPresenter.render();
userAccountRemovalPresenter.render();
};
changeTab(activeTab);
}
function changeTab(targetTab) {
var $link = $el.find('a[data-tab=' + targetTab + ']');
var $links = $link.closest('ul').find('a[data-tab]');
var tab = $link.attr('data-tab');
var $tabs = $link.closest('.tab-wrapper').find('.tab');
$links.removeClass('active');
$link.addClass('active');
$tabs.removeClass('active');
$tabs.filter('[data-tab=' + tab + ']').addClass('active');
}
return {
init: init,
reinit: initTabs,
render: render
};

View file

@ -25,6 +25,7 @@ App.Router = function(jQuery, util, appState) {
inject('#/users', 'userListPresenter');
inject('#/users/:searchArgs', 'userListPresenter');
inject('#/user/:userName', 'userPresenter');
inject('#/user/:userName/:tab', 'userPresenter');
setRoot('#/users');
};

View file

@ -90,12 +90,64 @@ App.Util = (function(jQuery, promise) {
});
}
function formatRelativeTime(timeString) {
if (!timeString)
return 'never';
var time = Date.parse(timeString);
var now = Date.now();
var difference = Math.abs(now - time);
var future = now < time;
var text = (function(difference) {
var mul = 1000;
var prevMul;
mul *= 60;
if (difference < mul)
return 'a few seconds';
if (difference < mul * 2)
return 'a minute';
prevMul = mul; mul *= 60;
if (difference < mul)
return Math.round(difference / prevMul) + ' minutes';
if (difference < mul * 2)
return 'an hour';
prevMul = mul; mul *= 24;
if (difference < mul)
return Math.round(difference / prevMul) + ' hours';
if (difference < mul * 2)
return 'a day';
prevMul = mul; mul *= 30.42;
if (difference < mul)
return Math.round(difference / prevMul) + ' days';
if (difference < mul * 2)
return 'a month';
prevMul = mul; mul *= 12;
if (difference < mul)
return Math.round(difference / prevMul) + ' months';
if (difference < mul * 2)
return 'a year';
return Math.round(difference / mul) + ' years';
})(difference);
if (text == 'a day')
return future ? 'tomorrow' : 'yesterday';
return future ? 'in ' + text : text + ' ago';
}
return {
promiseTemplate: promiseTemplate,
initPresenter : initPresenter,
initContentPresenter: initContentPresenter,
parseComplexRouteArgs: parseComplexRouteArgs,
compileComplexRouteArgs: compileComplexRouteArgs,
formatRelativeTime: formatRelativeTime,
};
});

View file

@ -1,6 +1,6 @@
<form class="account-removal">
<div class="messages"></div>
<form class="form-wrapper account-removal">
<div class="form-row">
<label class="form-label" for="account-removal-confirmation">Confirmation:</label>
<div class="form-input">

View file

@ -1,6 +1,6 @@
<form class="account-settings">
<div class="messages"></div>
<form class="form-wrapper account-settings">
<% if (canChangeAvatarStyle) { %>
<div class="form-row">
<label class="form-label">User picture:</label>

View file

@ -1,6 +1,6 @@
<form class="browsing-settings">
<div class="messages"></div>
<form class="form-wrapper browsing-settings">
<div class="form-row">
<label class="form-label">Safety:</label>
<div class="form-input">

View file

@ -6,7 +6,7 @@
<div class="messages"></div>
<form method="post" class="form-wrapper">
<form class="form-wrapper">
<div class="form-row">
<label class="form-label" for="login-user">User name:</label>
<div class="form-input">

View file

@ -6,7 +6,7 @@
<div class="messages"></div>
<form method="post" class="form-wrapper">
<form class="form-wrapper">
<div class="form-row">
<label class="form-label" for="registration-user">User name:</label>
<div class="form-input">

View file

@ -14,11 +14,28 @@
</li>
</ul>
<ul class="users">
<% _.each(userList, function(user) { %>
<div class="user">
User name: <a href="#/user/<%= user.name %>"><%= user.name %></a>
<li class="user">
<a href="#/user/<%= user.name %>">
<img src="/api/users/<%= user.name %>/avatar/80" alt="<%= user.name %>"/>
</a>
<div class="details">
<h1>
<a href="#/user/<%= user.name %>">
<%= user.name %>
</a>
</h1>
<div class="date-joined" title="<%= user.registrationTime %>">
Joined: <%= formatRelativeTime(user.registrationTime) %>
</div>
<div class="date-seen">
Last seen: <%= formatRelativeTime(user.lastLoginTime) %>
</div>
</div>
</li>
<% }); %>
</ul>
<div class="pager"></div>
</div>

View file

@ -1,22 +1,73 @@
<div id="user-view">
<div id="user-view" class="tab-wrapper">
<div class="messages"></div>
<img src="/api/users/<%= user.name %>/avatar/50" alt="Avatar"/>
<div class="top">
<div class="side">
<img src="/api/users/<%= user.name %>/avatar/100" alt="Avatar"/>
<br/>
<%= user.name %>
</div>
<ul>
<li>
<a href="#/user/<%= user.name %>" data-tab="basic-info">Basic information</a>
</li>
<% if (canChangeBrowsingSettings) { %>
<h2>Browsing settings</h2>
<div id="browsing-settings-target"></div>
<li>
<a href="#/user/<%= user.name %>/browsing-settings" data-tab="browsing-settings">Browsing settings</a>
</li>
<% } %>
<% if (canChangeAccountSettings) { %>
<h2>Account settings</h2>
<div id="account-settings-target"></div>
<li>
<a href="#/user/<%= user.name %>/account-settings" data-tab="account-settings">Account settings</a>
</li>
<% } %>
<% if (canDeleteAccount) { %>
<li>
<a href="#/user/<%= user.name %>/account-removal" data-tab="account-removal">Account removal</a>
</li>
<% } %>
</ul>
</div>
<div class="tab basic-info" data-tab="basic-info">
<h2>Basic information</h2>
<table>
<tr>
<td>Registered:</td>
<td><%= user.registrationTime %></td>
</tr>
<tr>
<td>Seen:</td>
<td><%= user.lastLoginTime %></td>
</tr>
</table>
</div>
<% if (canChangeBrowsingSettings) { %>
<div class="tab" data-tab="browsing-settings">
<h2>Browsing settings</h2>
<div id="browsing-settings-target"></div>
</div>
<% } %>
<% if (canChangeAccountSettings) { %>
<div class="tab" data-tab="account-settings">
<h2>Account settings</h2>
<div id="account-settings-target"></div>
</div>
<% } %>
<% if (canDeleteAccount) { %>
<div class="tab" data-tab="account-removal">
<h2>Account removal</h2>
<div id="account-removal-target"></div>
</div>
<% } %>
</div>