User page

This commit is contained in:
Mouse Reeve 2020-03-16 16:10:59 -07:00
parent d28efe54dd
commit c41b53bdbe
7 changed files with 180 additions and 108 deletions

View file

@ -39,6 +39,7 @@ h2 {
font-size: 1rem; font-size: 1rem;
padding: 0.5rem 0.2rem; padding: 0.5rem 0.2rem;
margin-bottom: 1rem; margin-bottom: 1rem;
border-bottom: 3px solid #B2DBBF;
} }
#top-bar { #top-bar {
@ -69,6 +70,9 @@ h2 {
#actions > * { #actions > * {
display: inline-block; display: inline-block;
} }
#actions > *:last-child {
margin-left: 0.5em;
}
#notifications .icon { #notifications .icon {
font-size: 1.1rem; font-size: 1.1rem;
@ -165,6 +169,21 @@ ul.menu a {
.row > * { .row > * {
flex-grow: 1; flex-grow: 1;
width: min-content; width: min-content;
margin-right: 1em;
}
.row > *:last-child {
margin-right: 0;
}
.row.shrink > * {
flex-grow: 0;
width: max-content;
}
.follow-requests .row {
margin-bottom: 0.5em;
}
.follow-requests .row > *:first-child {
width: 15em;
} }
.login form { .login form {
@ -196,9 +215,8 @@ button.secondary {
border: 2px solid #247BA0; border: 2px solid #247BA0;
color: #247BA0; color: #247BA0;
} }
button.warning {
.login h2 { background-color: #FF1654;
border-bottom: 3px solid #B2DBBF;
} }
.tabs { .tabs {
@ -235,6 +253,25 @@ button.secondary {
position: relative; position: relative;
bottom: 0.35em; bottom: 0.35em;
} }
.user-pic.large {
width: 5em;
height: 5em;
}
.user-profile h2 a {
text-decoration: none;
font-size: 0.9em;
float: right;
}
.user-profile h2 .icon {
font-size: 1.2em;
}
.user-profile .row > * {
flex-grow: 0;
}
.user-profile .row > *:last-child {
flex-grow: 1;
}
.review-form label { .review-form label {
display: block; display: block;
@ -285,8 +322,19 @@ button.secondary {
.all-shelves > div:first-child > * { .all-shelves > div:first-child > * {
padding-left: 1em; padding-left: 1em;
} }
.all-shelves h2 {
border-bottom: 3px solid #B2DBBF; .user-shelves .covers-shelf {
flex-wrap: wrap;
}
.user-shelves > div {
margin: 1em 0;
padding: 0;
}
.user-shelves > div > * {
padding-left: 1em;
}
.user-shelves .covers-shelf .book-cover {
height: 9em;
} }
.covers-shelf { .covers-shelf {
@ -378,7 +426,14 @@ button.secondary {
} }
blockquote { blockquote {
white-space: pre-wrap; white-space: pre-line;
margin-left: 2em;
}
blockquote .icon-quote-open {
float: left;
font-size: 2rem;
margin-right: 0.5rem;
color: #888;
} }
.interaction { .interaction {
@ -456,6 +511,7 @@ th, td {
.post h2, .compose-suggestion h2 { .post h2, .compose-suggestion h2 {
position: relative; position: relative;
right: 2em; right: 2em;
border: none;
} }
.post .time-ago { .post .time-ago {
position: relative; position: relative;
@ -487,6 +543,11 @@ th, td {
background-color: #DDD; background-color: #DDD;
} }
a .icon {
color: black;
text-decoration: none;
}
.hidden-text { .hidden-text {
height: 0; height: 0;
width: 0; width: 0;

View file

@ -3,25 +3,7 @@
{% block content %} {% block content %}
<div class="all-shelves content-container"> <div class="all-shelves content-container">
{% for shelf in shelves %} {% include 'snippets/covers_shelf.html' with shelves=shelves user=request.user %}
{% if shelf.books %}
<div>
<h2>{{ shelf.name }}
{% if shelf.size > shelf.books|length %}
<small>(<a href="/shelf/{{ user | username }}/{{ shelf.identifier }}">See all {{ shelf.size }}</a>)</small>
{% endif %}
</h2>
<div class="covers-shelf {{ shelf.identifier }}">
{% for book in shelf.books %}
<div class="book-preview" onclick="show_compose(this)" id="book-{{ book.id }}">
{% include 'snippets/book_cover.html' with book=book %}
{% include 'snippets/shelve_button.html' with book=book %}
</div>
{% endfor %}
</div>
</div>
{% endif %}
{% endfor %}
</div> </div>
{% for shelf in shelves %} {% for shelf in shelves %}

View file

@ -1,2 +1,2 @@
<img class="user-pic" src="{% if user.avatar %}/images/{{ user.avatar }}{% else %}/static/images/default_avi.jpg{% endif %}"> <img class="user-pic{% if large %} large{% endif %}" src="{% if user.avatar %}/images/{{ user.avatar }}{% else %}/static/images/default_avi.jpg{% endif %}">

View file

@ -1,6 +1,20 @@
{% load fr_display %} {% load fr_display %}
{% for book in books %} {% for shelf in shelves %}
<div class="book-preview"> {% if shelf.books %}
{% include 'snippets/book.html' with rating=rating %} <div>
<h2>{{ shelf.name }}
{% if shelf.size > shelf.books|length %}
<small>(<a href="/shelf/{{ user | username }}/{{ shelf.identifier }}">See all {{ shelf.size }}</a>)</small>
{% endif %}
</h2>
<div class="covers-shelf {{ shelf.identifier }}">
{% for book in shelf.books %}
<div class="book-preview" onclick="show_compose(this)" id="book-{{ book.id }}">
{% include 'snippets/book_cover.html' with book=book %}
{% include 'snippets/shelve_button.html' with book=book %}
</div> </div>
{% endfor %}
</div>
</div>
{% endif %}
{% endfor %} {% endfor %}

View file

@ -1,10 +1,10 @@
<form action="/accept_follow_request/" method="POST"> <form action="/accept_follow_request/" method="POST">
{% csrf_token %} {% csrf_token %}
<input type=hidden name="user" value="{{ user.username }}"> <input type="hidden" name="user" value="{{ user.username }}">
<input type=submit value="Accept"> <button type="submit">Accept</button>
</form> </form>
<form action="/delete_follow_request/" method="POST"> <form action="/delete_follow_request/" method="POST">
{% csrf_token %} {% csrf_token %}
<input type=hidden name="user" value="{{ user.username }}"> <input type="hidden" name="user" value="{{ user.username }}">
<input type=submit value="Delete"> <button type="submit" class="warning">Delete</button>
</form> </form>

View file

@ -1,64 +1,61 @@
{% extends 'layout.html' %} {% extends 'layout.html' %}
{% load humanize %}
{% block content %} {% block content %}
<div id="sidebar"> <div class="content-container user-profile">
<div class="user-profile"> <h2>User Profile
<h2> {% if is_self %}
{% include 'snippets/avatar.html' with user=user %} <a href="/user-edit/">edit
{% if user.name %}{{ user.name }}{% endif %} <span class="icon icon-pencil">
<small>{{ user.username }}</small> <span class="hidden-text">Edit profile</span>
</h2> </span>
{% if user.summary %} </a>
<blockquote>{{ user.summary | safe }}</blockquote>
{% endif %} {% endif %}
</h2>
<div class="row">
<div class="pic-container">
{% include 'snippets/avatar.html' with user=user large=True %}
</div>
<div>
<p>{% if user.name %}{{ user.name }}{% else %}{{ user.localname }}{% endif %}</p>
<p>{{ user.username }}</p>
<p>Joined {{ user.created_date | naturaltime }}</p>
</div>
{% if user.summary %}
<blockquote><span class="icon icon-quote-open"></span>{{ user.summary | safe }}</blockquote>
{% endif %}
</div>
{% if not is_self %} {% if not is_self %}
{% include 'snippets/follow_button.html' with user=user %} {% include 'snippets/follow_button.html' with user=user %}
{% endif %} {% endif %}
{% if is_self %}
<div class="interaction">
<a href="/user-edit/">Edit profile</a>
</div>
{% endif %}
</div>
{% if is_self and user.follower_requests.all %} {% if is_self and user.follower_requests.all %}
<div> <div class="follow-requests">
<h2>Follow Requests</h2> <h2>Follow Requests</h2>
{% for requester in user.follower_requests.all %} {% for requester in user.follower_requests.all %}
<div> <div class="row shrink">
<p>
{% include 'snippets/username.html' with user=requester show_full=True %} {% include 'snippets/username.html' with user=requester show_full=True %}
</p>
{% include 'snippets/follow_request_buttons.html' with user=requester %} {% include 'snippets/follow_request_buttons.html' with user=requester %}
</div> </div>
{% endfor %} {% endfor %}
</div> </div>
{% endif %} {% endif %}
<div>
<h2>Followers</h2>
{% for follower in user.followers.all %}
<div>
{% include 'snippets/username.html' with user=follower show_full=True %}
{% include 'snippets/follow_button.html' with user=follower %}
</div>
{% endfor %}
</div>
<div>
<h2>Following</h2>
{% for following in user.following.all %}
<div>
{% include 'snippets/username.html' with user=following show_full=True %}
{% include 'snippets/follow_button.html' with user=following %}
</div>
{% endfor %}
</div>
</div> </div>
<div id="content"> <div class="all-shelves content-container">
{% for shelf in shelves %} {% include 'snippets/covers_shelf.html' with shelves=shelves user=user %}
<div> </div>
<h2>{{ shelf.name }}</h2>
{% include 'snippets/shelf.html' with shelf=shelf ratings=ratings %} <div>
<div class="content-container"><h2>User Activity</h2></div>
{% for activity in activities %}
<div class="content-container">
{% include 'snippets/status.html' with status=activity %}
</div> </div>
{% endfor %} {% endfor %}
</div> </div>

View file

@ -37,39 +37,20 @@ def home(request):
def home_tab(request, tab): def home_tab(request, tab):
''' user's homepage with activity feed ''' ''' user's homepage with activity feed '''
shelves = [] shelves = []
book_count = 6 shelves = get_user_shelf_preview(
for (identifier, count) in [('reading', 3), ('read', 1), ('to-read', 3)]: request.user,
if book_count <= 0: [('reading', 3), ('read', 1), ('to-read', 3)]
break
shelf = models.Shelf.objects.get(
user=request.user,
identifier=identifier,
) )
if not shelf.books.count(): size = sum(len(s['books']) for s in shelves)
continue
books = models.ShelfBook.objects.filter(
shelf=shelf,
).order_by(
'-updated_date'
)[:count]
book_count -= len(books)
shelves.append({
'name': shelf.name,
'identifier': shelf.identifier,
'books': [b.book for b in books],
'size': shelf.books.count(),
})
# books new to the instance, for discovery # books new to the instance, for discovery
if book_count > 0: if size < 6:
shelves.append({ shelves.append({
'name': 'Recently added', 'name': 'Recently added',
'identifier': None, 'identifier': None,
'books': models.Book.objects.order_by( 'books': models.Book.objects.order_by(
'-created_date' '-created_date'
)[:book_count], )[:6 - size],
'count': book_count, 'count': 6 - size,
}) })
# allows us to check if a user has shelved a book # allows us to check if a user has shelved a book
@ -138,7 +119,6 @@ def notifications_page(request):
notifications.update(read=True) notifications.update(read=True)
return TemplateResponse(request, 'notifications.html', data) return TemplateResponse(request, 'notifications.html', data)
@csrf_exempt @csrf_exempt
def user_page(request, username): def user_page(request, username):
''' profile page for a user ''' ''' profile page for a user '''
@ -153,15 +133,19 @@ def user_page(request, username):
# otherwise we're at a UI view # otherwise we're at a UI view
# TODO: change display with privacy and authentication considerations # TODO: change display with privacy and authentication considerations
shelves = models.Shelf.objects.filter(user=user) shelves = get_user_shelf_preview(user)
ratings = {r.book.id: r.rating for r in \
models.Review.objects.filter(user=user, book__shelves__user=user)} activities = models.Status.objects.filter(
user=user,
).order_by(
'-created_date',
).select_subclasses()[:10]
data = { data = {
'user': user, 'user': user,
'shelves': shelves, 'shelves': shelves,
'ratings': ratings,
'is_self': request.user.id == user.id, 'is_self': request.user.id == user.id,
'activities': activities,
} }
return TemplateResponse(request, 'user.html', data) return TemplateResponse(request, 'user.html', data)
@ -390,3 +374,37 @@ def shelf_page(request, username, shelf_identifier):
} }
return TemplateResponse(request, 'shelf.html', data) return TemplateResponse(request, 'shelf.html', data)
def get_user_shelf_preview(user, shelf_proportions=None):
''' data for the covers shelf (user page and feed page) '''
shelves = []
shelf_max = 6
if not shelf_proportions:
shelf_proportions = [('reading', 3), ('read', 2), ('to-read', -1)]
for (identifier, count) in shelf_proportions:
if shelf_max <= 0:
break
if count > shelf_max or count < 0:
count = shelf_max
shelf = models.Shelf.objects.get(
user=user,
identifier=identifier,
)
if not shelf.books.count():
continue
books = models.ShelfBook.objects.filter(
shelf=shelf,
).order_by(
'-updated_date'
)[:count]
shelf_max -= len(books)
shelves.append({
'name': shelf.name,
'identifier': shelf.identifier,
'books': [b.book for b in books],
'size': shelf.books.count(),
})
return shelves