Merge branch 'main' into frontend-book-cover

This commit is contained in:
Fabien Basmaison 2021-04-26 11:35:10 +02:00
commit 30bed6c963
17 changed files with 404 additions and 377 deletions

View file

@ -29,6 +29,40 @@ body {
min-width: 75% !important; min-width: 75% !important;
} }
/** Utilities not covered by Bulma
******************************************************************************/
@media only screen and (max-width: 768px) {
.is-sr-only-mobile {
border: none !important;
clip: rect(0, 0, 0, 0) !important;
height: 0.01em !important;
overflow: hidden !important;
padding: 0 !important;
position: absolute !important;
white-space: nowrap !important;
width: 0.01em !important;
}
.m-0-mobile {
margin: 0 !important;
}
}
.button.is-transparent {
background-color: transparent;
}
.card.is-stretchable {
display: flex;
flex-direction: column;
height: 100%;
}
.card.is-stretchable .card-content {
flex-grow: 1;
}
/** Shelving /** Shelving
******************************************************************************/ ******************************************************************************/
@ -257,3 +291,53 @@ body {
height: 150px; height: 150px;
} }
} }
/* Book preview table
******************************************************************************/
.book-preview td {
vertical-align: middle;
}
@media only screen and (max-width: 768px) {
table.is-mobile,
table.is-mobile tbody {
display: block;
}
table.is-mobile tr {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
border-top: 1px solid #dbdbdb;
}
table.is-mobile td {
display: block;
box-sizing: border-box;
flex: 1 0 100%;
order: 2;
border-bottom: 0;
}
table.is-mobile td.book-preview-top-row {
order: 1;
flex-basis: auto;
}
table.is-mobile td[data-title]:not(:empty)::before {
content: attr(data-title);
display: block;
font-size: 0.75em;
font-weight: bold;
}
table.is-mobile td:empty {
padding: 0;
}
table.is-mobile th,
table.is-mobile thead {
display: none;
}
}

View file

@ -245,7 +245,36 @@
</div> </div>
<div class="block" id="reviews"> <div class="block" id="reviews">
{% for review in reviews %} {% if request.user.is_authenticated %}
<nav class="tabs">
<ul>
{% url 'book' book.id as tab_url %}
<li {% if tab_url == request.path %}class="is-active"{% endif %}>
<a href="{{ tab_url }}">{% trans "Reviews" %} ({{ review_count }})</a>
</li>
{% if user_statuses.review_count %}
{% url 'book-user-statuses' book.id 'review' as tab_url %}
<li {% if tab_url == request.path %}class="is-active"{% endif %}>
<a href="{{ tab_url }}">{% trans "Your reviews" %} ({{ user_statuses.review_count }})</a>
</li>
{% endif %}
{% if user_statuses.comment_count %}
{% url 'book-user-statuses' book.id 'comment' as tab_url %}
<li {% if tab_url == request.path %}class="is-active"{% endif %}>
<a href="{{ tab_url }}">{% trans "Your comments" %} ({{ user_statuses.comment_count }})</a>
</li>
{% endif %}
{% if user_statuses.quotation_count %}
{% url 'book-user-statuses' book.id 'quote' as tab_url %}
<li {% if tab_url == request.path %}class="is-active"{% endif %}>
<a href="{{ tab_url }}">{% trans "Your quotes" %} ({{ user_statuses.quotation_count }})</a>
</li>
{% endif %}
</ul>
</nav>
{% endif %}
{% for review in statuses %}
<div <div
class="block" class="block"
itemprop="review" itemprop="review"
@ -286,7 +315,7 @@
{% endfor %} {% endfor %}
</div> </div>
<div class="block"> <div class="block">
{% include 'snippets/pagination.html' with page=reviews path=book.local_path anchor="#reviews" %} {% include 'snippets/pagination.html' with page=statuses path=request.path anchor="#reviews" %}
</div> </div>
</div> </div>
</div> </div>

View file

@ -41,7 +41,7 @@
<div class="columns is-multiline"> <div class="columns is-multiline">
{% for user in users %} {% for user in users %}
<div class="column is-one-third"> <div class="column is-one-third">
<div class="card block"> <div class="card is-stretchable">
<div class="card-content"> <div class="card-content">
<div class="media"> <div class="media">
<a href="{{ user.local_path }}" class="media-left"> <a href="{{ user.local_path }}" class="media-left">
@ -56,13 +56,13 @@
</div> </div>
</div> </div>
<div class="content"> <div>
{% if user.summary %} {% if user.summary %}
{{ user.summary | to_markdown | safe | truncatechars_html:40 }} {{ user.summary | to_markdown | safe | truncatechars_html:40 }}
{% else %}&nbsp;{% endif %} {% else %}&nbsp;{% endif %}
</div> </div>
</div> </div>
<footer class="card-footer content"> <footer class="card-footer">
{% if user != request.user %} {% if user != request.user %}
{% if user.mutuals %} {% if user.mutuals %}
<div class="card-footer-item"> <div class="card-footer-item">

View file

@ -4,18 +4,16 @@
{% with status.id|uuid as uuid %} {% with status.id|uuid as uuid %}
<form name="boost" action="/boost/{{ status.id }}" method="post" class="interaction boost-{{ status.id }}-{{ uuid }} {% if request.user|boosted:status %}is-hidden{% endif %}" data-id="boost-{{ status.id }}-{{ uuid }}"> <form name="boost" action="/boost/{{ status.id }}" method="post" class="interaction boost-{{ status.id }}-{{ uuid }} {% if request.user|boosted:status %}is-hidden{% endif %}" data-id="boost-{{ status.id }}-{{ uuid }}">
{% csrf_token %} {% csrf_token %}
<button class="button is-small" type="submit" {% if not status.boostable %}disabled{% endif %}> <button class="button is-small is-light is-transparent" type="submit" {% if not status.boostable %}disabled{% endif %}>
<span class="icon icon-boost" title="{% trans 'Boost status' %}"> <span class="icon icon-boost m-0-mobile" title="{% trans 'Boost' %}"></span>
<span class="is-sr-only">{% trans "Boost status" %}</span> <span class="is-sr-only-mobile">{% trans "Boost" %}</span>
</span>
</button> </button>
</form> </form>
<form name="unboost" action="/unboost/{{ status.id }}" method="post" class="interaction boost-{{ status.id }}-{{ uuid }} active {% if not request.user|boosted:status %}is-hidden{% endif %}" data-id="boost-{{ status.id }}-{{ uuid }}"> <form name="unboost" action="/unboost/{{ status.id }}" method="post" class="interaction boost-{{ status.id }}-{{ uuid }} active {% if not request.user|boosted:status %}is-hidden{% endif %}" data-id="boost-{{ status.id }}-{{ uuid }}">
{% csrf_token %} {% csrf_token %}
<button class="button is-small is-primary" type="submit"> <button class="button is-small is-light is-transparent" type="submit">
<span class="icon icon-boost" title="{% trans 'Un-boost status' %}"> <span class="icon icon-boost has-text-primary m-0-mobile" title="{% trans 'Un-boost' %}"></span>
<span class="is-sr-only">{% trans "Un-boost status" %}</span> <span class="is-sr-only-mobile">{% trans "Un-boost" %}</span>
</span>
</button> </button>
</form> </form>
{% endwith %} {% endwith %}

View file

@ -3,18 +3,17 @@
{% with status.id|uuid as uuid %} {% with status.id|uuid as uuid %}
<form name="favorite" action="/favorite/{{ status.id }}" method="POST" class="interaction fav-{{ status.id }}-{{ uuid }} {% if request.user|liked:status %}is-hidden{% endif %}" data-id="fav-{{ status.id }}-{{ uuid }}"> <form name="favorite" action="/favorite/{{ status.id }}" method="POST" class="interaction fav-{{ status.id }}-{{ uuid }} {% if request.user|liked:status %}is-hidden{% endif %}" data-id="fav-{{ status.id }}-{{ uuid }}">
{% csrf_token %} {% csrf_token %}
<button class="button is-small" type="submit"> <button class="button is-small is-light is-transparent" type="submit">
<span class="icon icon-heart" title="{% trans 'Like status' %}"> <span class="icon icon-heart m-0-mobile" title="{% trans 'Like' %}">
<span class="is-sr-only">{% trans "Like status" %}</span>
</span> </span>
<span class="is-sr-only-mobile">{% trans "Like" %}</span>
</button> </button>
</form> </form>
<form name="unfavorite" action="/unfavorite/{{ status.id }}" method="POST" class="interaction fav-{{ status.id }}-{{ uuid }} active {% if not request.user|liked:status %}is-hidden{% endif %}" data-id="fav-{{ status.id }}-{{ uuid }}"> <form name="unfavorite" action="/unfavorite/{{ status.id }}" method="POST" class="interaction fav-{{ status.id }}-{{ uuid }} active {% if not request.user|liked:status %}is-hidden{% endif %}" data-id="fav-{{ status.id }}-{{ uuid }}">
{% csrf_token %} {% csrf_token %}
<button class="button is-primary is-small" type="submit"> <button class="button is-light is-transparent is-small" type="submit">
<span class="icon icon-heart" title="{% trans 'Un-like status' %}"> <span class="icon icon-heart has-text-primary m-0-mobile" title="{% trans 'Un-like' %}"></span>
<span class="is-sr-only">{% trans "Un-like status" %}</span> <span class="is-sr-only-mobile">{% trans "Un-like" %}</span>
</span>
</button> </button>
</form> </form>
{% endwith %} {% endwith %}

View file

@ -14,11 +14,18 @@
{% if not hide_book %} {% if not hide_book %}
{% with book=status.book|default:status.mention_books.first %} {% with book=status.book|default:status.mention_books.first %}
{% if book %} {% if book %}
<div class="column is-narrow is-hidden-mobile"> <div class="column is-narrow">
<div class="columns is-mobile">
<div class="column is-narrow">
<a href="{{ book.local_path }}">{% include 'snippets/book_cover.html' with book=book %}</a> <a href="{{ book.local_path }}">{% include 'snippets/book_cover.html' with book=book %}</a>
{% include 'snippets/stars.html' with rating=book|rating:request.user %} {% include 'snippets/stars.html' with rating=book|rating:request.user %}
{% include 'snippets/shelve_button/shelve_button.html' with book=book %} {% include 'snippets/shelve_button/shelve_button.html' with book=book %}
</div> </div>
<div class="column is-hidden-tablet">
<p>{{ book|book_description|to_markdown|default:""|safe|truncatewords_html:15 }}</p>
</div>
</div>
</div>
{% endif %} {% endif %}
{% endwith %} {% endwith %}
{% endif %} {% endif %}

View file

@ -4,16 +4,16 @@
{% load humanize %} {% load humanize %}
{% block card-header %} {% block card-header %}
<h3 class="card-header-title has-background-white-ter is-block"> <div class="card-header-title has-background-white-ter is-block">
{% include 'snippets/status/status_header.html' with status=status %} {% include 'snippets/status/status_header.html' with status=status %}
</h3> </div>
{% endblock %} {% endblock %}
{% block card-content %}{% endblock %} {% block card-content %}{% endblock %}
{% block card-footer %} {% block card-footer %}
<div class="card-footer-item">
{% if moderation_mode and perms.bookwyrm.moderate_post %} {% if moderation_mode and perms.bookwyrm.moderate_post %}
<div class="card-footer-item">
{# moderation options #} {# moderation options #}
<form name="delete-{{status.id}}" action="/delete-status/{{ status.id }}" method="post"> <form name="delete-{{status.id}}" action="/delete-status/{{ status.id }}" method="post">
@ -22,54 +22,45 @@
{% trans "Delete status" %} {% trans "Delete status" %}
</button> </button>
</form> </form>
</div>
{% elif no_interact %} {% elif no_interact %}
{# nothing here #} {# nothing here #}
{% elif request.user.is_authenticated %} {% elif request.user.is_authenticated %}
<div class="field has-addons"> <div class="card-footer-item">
<div class="control">
{% trans "Reply" as button_text %} {% trans "Reply" as button_text %}
{% include 'snippets/toggle/toggle_button.html' with controls_text="show-comment" controls_uid=status.id text=button_text icon="comment" class="is-small toggle-button" focus="id_content_reply" %} {% include 'snippets/toggle/toggle_button.html' with controls_text="show-comment" controls_uid=status.id text=button_text icon_with_text="comment" class="is-small is-light is-transparent toggle-button" focus="id_content_reply" %}
</div> </div>
<div class="control"> <div class="card-footer-item">
{% include 'snippets/boost_button.html' with status=status %} {% include 'snippets/boost_button.html' with status=status %}
</div> </div>
<div class="control"> <div class="card-footer-item">
{% include 'snippets/fav_button.html' with status=status %} {% include 'snippets/fav_button.html' with status=status %}
</div> </div>
</div>
{% else %}
<a href="/login">
<span class="icon icon-comment" title="{% trans 'Reply' %}">
<span class="is-sr-only">{% trans "Reply" %}</span>
</span>
<span class="icon icon-boost" title="{% trans 'Boost status' %}">
<span class="is-sr-only">{% trans "Boost status" %}</span>
</span>
<span class="icon icon-heart" title="{% trans 'Like status' %}">
<span class="is-sr-only">{% trans "Like status" %}</span>
</span>
</a>
{% endif %}
</div>
<div class="card-footer-item">
{% include 'snippets/privacy-icons.html' with item=status %}
</div>
<div class="card-footer-item">
<a href="{{ status.remote_id }}">{{ status.published_date|timesince }}</a>
</div>
{% if not moderation_mode %} {% if not moderation_mode %}
<div class="card-footer-item"> <div class="card-footer-item">
{% include 'snippets/status/status_options.html' with class="is-small" right=True %} {% include 'snippets/status/status_options.html' with class="is-small is-light is-transparent" right=True %}
</div>
{% endif %}
{% else %}
<div class="card-footer-item">
<a href="/login">
<span class="icon icon-comment is-small" title="{% trans 'Reply' %}">
<span class="is-sr-only">{% trans "Reply" %}</span>
</span>
<span class="icon icon-boost is-small ml-4" title="{% trans 'Boost status' %}">
<span class="is-sr-only">{% trans "Boost status" %}</span>
</span>
<span class="icon icon-heart is-small ml-4" title="{% trans 'Like status' %}">
<span class="is-sr-only">{% trans "Like status" %}</span>
</span>
</a>
</div> </div>
{% endif %} {% endif %}
{% endblock %} {% endblock %}
{% block card-bonus %} {% block card-bonus %}
{% if request.user.is_authenticated and not moderation_mode %} {% if request.user.is_authenticated and not moderation_mode %}
{% with status.id|uuid as uuid %} {% with status.id|uuid as uuid %}

View file

@ -1,134 +0,0 @@
{% load bookwyrm_tags %}
{% load i18n %}
{% with status_type=status.status_type %}
<div
class="block"
{% if status_type == 'Review' %}
{% firstof "reviewBody" as body_prop %}
{% firstof 'itemprop="reviewRating" itemscope itemtype="https://schema.org/Rating"' as rating_type %}
{% endif %}
{% if status_type == 'Rating' %}
itemprop="rating"
itemtype="https://schema.org/Rating"
{% endif %}
>
{% if status_type == 'Review' or status_type == 'Rating' %}
<div>
{% if status.name %}
<h3
class="title is-5 has-subtitle"
dir="auto"
itemprop="name"
>
{{ status.name|escape }}
</h3>
{% endif %}
<span
class="is-sr-only"
{{ rating_type }}
>
<meta itemprop="ratingValue" content="{{ status.rating|floatformat }}">
{% if status_type == 'Rating' %}
{# @todo Is it possible to not hard-code the value? #}
<meta itemprop="bestRating" content="5">
{% endif %}
</span>
{% include 'snippets/stars.html' with rating=status.rating %}
</div>
{% endif %}
{% if status.content_warning %}
<div>
<p>{{ status.content_warning }}</p>
{% trans "Show more" as button_text %}
{% with text=button_text class="is-small" controls_text="show-status-cw" controls_uid=status.id %}
{% include 'snippets/toggle/open_button.html' %}
{% endwith %}
</div>
{% endif %}
<div
{% if status.content_warning %}
id="show-status-cw-{{ status.id }}"
class="is-hidden"
{% endif %}
>
{% if status.content_warning %}
{% trans "Show less" as button_text %}
{% with text=button_text class="is-small" controls_text="show-status-cw" controls_uid=status.id %}
{% include 'snippets/toggle/close_button.html' %}
{% endwith %}
{% endif %}
{% if status.quote %}
<div class="quote block">
<blockquote dir="auto" class="content mb-2">{{ status.quote | safe }}</blockquote>
<p> &mdash; {% include 'snippets/book_titleby.html' with book=status.book %}</p>
</div>
{% endif %}
{% if status.content and status_type != 'GeneratedNote' and status_type != 'Announce' %}
{% with full=status.content|safe no_trim=status.content_warning itemprop=body_prop %}
{% include 'snippets/trimmed_text.html' %}
{% endwith %}
{% endif %}
{% if status.attachments.exists %}
<div class="block">
<div class="columns">
{% for attachment in status.attachments.all %}
<div class="column is-narrow">
<figure class="image is-128x128">
<a
href="/images/{{ attachment.image }}"
target="_blank"
aria-label="{% trans 'Open image in new window' %}"
>
<img
src="/images/{{ attachment.image }}"
{% if attachment.caption %}
alt="{{ attachment.caption }}"
title="{{ attachment.caption }}"
{% endif %}
>
</a>
</figure>
</div>
{% endfor %}
</div>
</div>
{% endif %}
</div>
</div>
{% if not hide_book %}
{% if status.book or status.mention_books.count %}
<div
{% if status_type != 'GeneratedNote' %}
class="box has-background-white-bis"
{% endif %}
>
{% if status.book %}
{% with book=status.book %}
{% include 'snippets/status/book_preview.html' %}
{% endwith %}
{% elif status.mention_books.count %}
{% with book=status.mention_books.first %}
{% include 'snippets/status/book_preview.html' %}
{% endwith %}
{% endif %}
</div>
{% endif %}
{% endif %}
{% endwith %}

View file

@ -1,16 +1,29 @@
{% load bookwyrm_tags %} {% load bookwyrm_tags %}
{% load i18n %} {% load i18n %}
{% load humanize %}
<div class="media">
<figure class="media-left" aria-hidden="true">
<a class="image is-48x48" href="{{ status.user.local_path }}">
{% include 'snippets/avatar.html' with user=status.user ariaHide="true" medium="true" %}
</a>
</figure>
<div class="media-content">
<h3 class="has-text-weight-bold">
<span <span
itemprop="author" itemprop="author"
itemscope itemscope
itemtype="https://schema.org/Person" itemtype="https://schema.org/Person"
> >
{% if status.user.avatar %}
<meta itemprop="image" content="/images/{{ status.user.avatar }}">
{% endif %}
<a <a
href="{{ status.user.local_path }}" href="{{ status.user.local_path }}"
itemprop="url" itemprop="url"
> >
{% include 'snippets/avatar.html' with user=status.user ariaHide="true" %}
<span itemprop="name">{{ status.user.display_name }}</span> <span itemprop="name">{{ status.user.display_name }}</span>
</a> </a>
</span> </span>
@ -28,19 +41,21 @@
{% elif status.reply_parent %} {% elif status.reply_parent %}
{% with parent_status=status|parent %} {% with parent_status=status|parent %}
{% if parent_status.status_type == 'Review' %}
{% blocktrans with username=parent_status.user.display_name user_path=parent_status.user.local_path status_path=parent_status.local_path %}replied to <a href="{{ user_path }}">{{ username}}'s</a> <a href="{{ status_path }}">review</a>{% endblocktrans %}
{% elif parent_status.status_type == 'Comment' %}
{% blocktrans with username=parent_status.user.display_name user_path=parent_status.user.local_path status_path=parent_status.local_path %}replied to <a href="{{ user_path }}">{{ username}}'s</a> <a href="{{ status_path }}">comment</a>{% endblocktrans %}
{% elif parent_status.status_type == 'Quotation' %}
{% blocktrans with username=parent_status.user.display_name user_path=parent_status.user.local_path status_path=parent_status.local_path %}replied to <a href="{{ user_path }}">{{ username}}'s</a> <a href="{{ status_path }}">quote</a>{% endblocktrans %}
{% else %}
{% blocktrans with username=parent_status.user.display_name user_path=parent_status.user.local_path status_path=parent_status.local_path %}replied to <a href="{{ user_path }}">{{ username}}'s</a> <a href="{{ status_path }}">status</a>{% endblocktrans %} {% blocktrans with username=parent_status.user.display_name user_path=parent_status.user.local_path status_path=parent_status.local_path %}replied to <a href="{{ user_path }}">{{ username}}'s</a> <a href="{{ status_path }}">status</a>{% endblocktrans %}
{% endif %}
{% endwith %} {% endwith %}
{% endif %} {% endif %}
{% if status.book %}
{% if status.status_type == 'GeneratedNote' or status.status_type == 'Rating' %}
<a href="/book/{{ status.book.id }}">{{ status.book|title }}</a>{% if status.status_type == 'Rating' %}:
<span
itemprop="reviewRating"
itemscope
itemtype="https://schema.org/Rating"
>
<span class="is-hidden" {{ rating_type }}>
<meta itemprop="ratingValue" content="{{ status.rating|floatformat }}">
{% if status.book %} {% if status.book %}
{% if status.status_type == 'GeneratedNote' or status.status_type == 'Rating' %} {% if status.status_type == 'GeneratedNote' or status.status_type == 'Rating' %}
<a href="/book/{{ status.book.id }}">{{ status.book|title }}</a>{% if status.status_type == 'Rating' %}: <a href="/book/{{ status.book.id }}">{{ status.book|title }}</a>{% if status.status_type == 'Rating' %}:
@ -61,12 +76,33 @@
{% else %} {% else %}
{% include 'snippets/book_titleby.html' with book=status.book %} {% include 'snippets/book_titleby.html' with book=status.book %}
{% endif %} {% endif %}
{% elif status.mention_books %}
<a href="/book/{{ status.mention_books.first.id }}">
{{ status.mention_books.first.title }}
</a>
{% endif %}
{% include 'snippets/stars.html' with rating=status.rating %}
{% endif %}
{% else %}
{% include 'snippets/book_titleby.html' with book=status.book %}
{% endif %}
{% elif status.mention_books %} {% elif status.mention_books %}
<a href="/book/{{ status.mention_books.first.id }}">{{ status.mention_books.first|title }}</a> <a href="/book/{{ status.mention_books.first.id }}">{{ status.mention_books.first|title }}</a>
{% endif %} {% endif %}
</h3>
<p class="is-size-7 is-flex is-align-items-center">
<a href="{{ status.remote_id }}">{{ status.published_date|timesince }}</a>
{% if status.progress %} {% if status.progress %}
<p class="help"> <span class="ml-1">
({% if status.progress_mode == 'PG' %}{% include 'snippets/page_text.html' with page=status.progress total_pages=status.book.pages %}{% else %}{{ status.progress }}%{% endif %}) {% if status.progress_mode == 'PG' %}
</p> ({% include 'snippets/page_text.html' with page=status.progress total_pages=status.book.pages %})
{% else %}
({{ status.progress }}%)
{% endif %} {% endif %}
</span>
{% endif %}
{% include 'snippets/privacy-icons.html' with item=status %}
</p>
</div>
</div>

View file

@ -3,9 +3,8 @@
{% load bookwyrm_tags %} {% load bookwyrm_tags %}
{% block dropdown-trigger %} {% block dropdown-trigger %}
<span class="icon icon-dots-three"> <span class="icon icon-dots-three m-0-mobile"></span>
<span class="is-sr-only">{% trans "More options" %}</span> <span class="is-sr-only-mobile">{% trans "More options" %}</span>
</span>
{% endblock %} {% endblock %}
{% block dropdown-list %} {% block dropdown-list %}

View file

@ -10,9 +10,12 @@
> >
{% if icon %} {% if icon %}
<span class="icon icon-{{ icon }}" title="{{ text }}"> <span class="icon icon-{{ icon }} m-0-mobile" title="{{ text }}">
<span class="is-sr-only">{{ text }}</span> <span class="is-sr-only">{{ text }}</span>
</span> </span>
{% elif icon_with_text %}
<span class="icon icon-{{ icon_with_text }} m-0-mobile" title="{{ text }}"></span>
<span class="is-sr-only-mobile">{{ text }}</span>
{% else %} {% else %}
<span>{{ text }}</span> <span>{{ text }}</span>
{% endif %} {% endif %}

View file

@ -68,10 +68,9 @@
<div class="block"> <div class="block">
<div> <div>
{% if books|length > 0 %} {% if books|length > 0 %}
<div class="scroll-x"> <table class="table is-striped is-fullwidth is-mobile">
<table class="table is-striped is-fullwidth"> <thead>
<tr>
<tr class="book-preview">
<th>{% trans "Cover" %}</th> <th>{% trans "Cover" %}</th>
<th>{% trans "Title" %}</th> <th>{% trans "Title" %}</th>
<th>{% trans "Author" %}</th> <th>{% trans "Author" %}</th>
@ -83,34 +82,37 @@
<th aria-hidden="true"></th> <th aria-hidden="true"></th>
{% endif %} {% endif %}
</tr> </tr>
</thead>
<tbody>
{% for book in books %} {% for book in books %}
{% spaceless %}
<tr class="book-preview"> <tr class="book-preview">
<td> <td class="book-preview-top-row">
<a href="{{ book.local_path }}">{% include 'snippets/book_cover.html' with book=book cover_class='is-h-small' %}</a> <a href="{{ book.local_path }}">{% include 'snippets/book_cover.html' with book=book size="small" %}</a>
</td> </td>
<td> <td data-title="{% trans "Title" %}">
<a href="{{ book.local_path }}">{{ book.title }}</a> <a href="{{ book.local_path }}">{{ book.title }}</a>
</td> </td>
<td> <td data-title="{% trans "Author" %}">
{% include 'snippets/authors.html' %} {% include 'snippets/authors.html' %}
</td> </td>
<td> <td data-title="{% trans "Shelved" %}">
{{ book.created_date | naturalday }} {{ book.created_date | naturalday }}
</td> </td>
{% latest_read_through book user as read_through %} {% latest_read_through book user as read_through %}
<td> <td data-title="{% trans "Started" %}">
{{ read_through.start_date | naturalday |default_if_none:""}} {{ read_through.start_date | naturalday |default_if_none:""}}
</td> </td>
<td> <td data-title="{% trans "Finished" %}">
{{ read_through.finish_date | naturalday |default_if_none:""}} {{ read_through.finish_date | naturalday |default_if_none:""}}
</td> </td>
{% if ratings %} {% if ratings %}
<td> <td data-title="{% trans "Rating" %}">
{% include 'snippets/stars.html' with rating=ratings|dict_key:book.id %} {% include 'snippets/stars.html' with rating=ratings|dict_key:book.id %}
</td> </td>
{% endif %} {% endif %}
{% if shelf.user == request.user %} {% if shelf.user == request.user %}
<td> <td class="book-preview-top-row has-text-right">
{% with right=True %} {% with right=True %}
{% if not shelf.id %} {% if not shelf.id %}
{% active_shelf book as current %} {% active_shelf book as current %}
@ -122,9 +124,10 @@
</td> </td>
{% endif %} {% endif %}
</tr> </tr>
{% endspaceless %}
{% endfor %} {% endfor %}
</tbody>
</table> </table>
</div>
{% else %} {% else %}
<p>{% trans "This shelf is empty." %}</p> <p>{% trans "This shelf is empty." %}</p>
{% if shelf.id and shelf.editable %} {% if shelf.id and shelf.editable %}

View file

@ -260,7 +260,12 @@ urlpatterns = [
re_path(r"^boost/(?P<status_id>\d+)/?$", views.Boost.as_view()), re_path(r"^boost/(?P<status_id>\d+)/?$", views.Boost.as_view()),
re_path(r"^unboost/(?P<status_id>\d+)/?$", views.Unboost.as_view()), re_path(r"^unboost/(?P<status_id>\d+)/?$", views.Unboost.as_view()),
# books # books
re_path(r"%s(.json)?/?$" % book_path, views.Book.as_view()), re_path(r"%s(.json)?/?$" % book_path, views.Book.as_view(), name="book"),
re_path(
r"%s/(?P<user_statuses>review|comment|quote)/?$" % book_path,
views.Book.as_view(),
name="book-user-statuses",
),
re_path(r"%s/edit/?$" % book_path, views.EditBook.as_view()), re_path(r"%s/edit/?$" % book_path, views.EditBook.as_view()),
re_path(r"%s/confirm/?$" % book_path, views.ConfirmEditBook.as_view()), re_path(r"%s/confirm/?$" % book_path, views.ConfirmEditBook.as_view()),
re_path(r"^create-book/?$", views.EditBook.as_view()), re_path(r"^create-book/?$", views.EditBook.as_view()),

View file

@ -28,7 +28,7 @@ from .helpers import is_api_request, get_edition, privacy_filter
class Book(View): class Book(View):
""" a book! this is the stuff """ """ a book! this is the stuff """
def get(self, request, book_id): def get(self, request, book_id, user_statuses=False):
""" info about a book """ """ info about a book """
try: try:
book = models.Book.objects.select_subclasses().get(id=book_id) book = models.Book.objects.select_subclasses().get(id=book_id)
@ -40,22 +40,39 @@ class Book(View):
if isinstance(book, models.Work): if isinstance(book, models.Work):
book = book.get_default_edition() book = book.get_default_edition()
if not book: if not book or not book.parent_work:
return HttpResponseNotFound() return HttpResponseNotFound()
work = book.parent_work work = book.parent_work
if not work:
return HttpResponseNotFound()
# all reviews for the book # all reviews for the book
reviews = models.Review.objects.filter(book__in=work.editions.all()) reviews = privacy_filter(
reviews = privacy_filter(request.user, reviews) request.user, models.Review.objects.filter(book__in=work.editions.all())
)
# the reviews to show # the reviews to show
paginated = Paginator( if user_statuses and request.user.is_authenticated:
reviews.exclude(Q(content__isnull=True) | Q(content="")), PAGE_LENGTH if user_statuses == "review":
) queryset = book.review_set
reviews_page = paginated.get_page(request.GET.get("page")) elif user_statuses == "comment":
queryset = book.comment_set
else:
queryset = book.quotation_set
queryset = queryset.filter(user=request.user)
else:
queryset = reviews.exclude(Q(content__isnull=True) | Q(content=""))
paginated = Paginator(queryset, PAGE_LENGTH)
data = {
"book": book,
"statuses": paginated.get_page(request.GET.get("page")),
"review_count": reviews.count(),
"ratings": reviews.filter(Q(content__isnull=True) | Q(content="")),
"rating": reviews.aggregate(Avg("rating"))["rating__avg"],
"lists": privacy_filter(
request.user, book.list_set.filter(listitem__approved=True)
),
}
if request.user.is_authenticated: if request.user.is_authenticated:
readthroughs = models.ReadThrough.objects.filter( readthroughs = models.ReadThrough.objects.filter(
@ -67,29 +84,24 @@ class Book(View):
readthrough.progress_updates = ( readthrough.progress_updates = (
readthrough.progressupdate_set.all().order_by("-updated_date") readthrough.progressupdate_set.all().order_by("-updated_date")
) )
data["readthroughs"] = readthroughs
user_shelves = models.ShelfBook.objects.filter(user=request.user, book=book) data["user_shelves"] = models.ShelfBook.objects.filter(
user=request.user, book=book
)
other_edition_shelves = models.ShelfBook.objects.filter( data["other_edition_shelves"] = models.ShelfBook.objects.filter(
~Q(book=book), ~Q(book=book),
user=request.user, user=request.user,
book__parent_work=book.parent_work, book__parent_work=book.parent_work,
) )
data = { data["user_statuses"] = {
"book": book, "review_count": book.review_set.filter(user=request.user).count(),
"reviews": reviews_page, "comment_count": book.comment_set.filter(user=request.user).count(),
"review_count": reviews.count(), "quotation_count": book.quotation_set.filter(user=request.user).count(),
"ratings": reviews.filter(Q(content__isnull=True) | Q(content="")),
"rating": reviews.aggregate(Avg("rating"))["rating__avg"],
"lists": privacy_filter(
request.user, book.list_set.filter(listitem__approved=True)
),
"user_shelves": user_shelves,
"other_edition_shelves": other_edition_shelves,
"readthroughs": readthroughs,
"path": "/book/%s" % book_id,
} }
return TemplateResponse(request, "book/book.html", data) return TemplateResponse(request, "book/book.html", data)

1
fr-dev
View file

@ -1 +0,0 @@
bw-dev

Binary file not shown.

View file

@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: 0.0.1\n" "Project-Id-Version: 0.0.1\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-04-22 15:55+0000\n" "POT-Creation-Date: 2021-04-25 04:01+0000\n"
"PO-Revision-Date: 2021-03-19 11:49+0800\n" "PO-Revision-Date: 2021-03-19 11:49+0800\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@ -18,57 +18,57 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: bookwyrm/forms.py:232 #: bookwyrm/forms.py:224
msgid "A user with this email already exists." msgid "A user with this email already exists."
msgstr "Ya existe un usuario con ese correo electrónico." msgstr "Ya existe un usuario con ese correo electrónico."
#: bookwyrm/forms.py:246 #: bookwyrm/forms.py:238
msgid "One Day" msgid "One Day"
msgstr "Un día" msgstr "Un día"
#: bookwyrm/forms.py:247 #: bookwyrm/forms.py:239
msgid "One Week" msgid "One Week"
msgstr "Una semana" msgstr "Una semana"
#: bookwyrm/forms.py:248 #: bookwyrm/forms.py:240
msgid "One Month" msgid "One Month"
msgstr "Un mes" msgstr "Un mes"
#: bookwyrm/forms.py:249 #: bookwyrm/forms.py:241
msgid "Does Not Expire" msgid "Does Not Expire"
msgstr "Nunca se vence" msgstr "Nunca se vence"
#: bookwyrm/forms.py:254 #: bookwyrm/forms.py:246
#, python-format #, python-format
msgid "%(count)d uses" msgid "%(count)d uses"
msgstr "%(count)d usos" msgstr "%(count)d usos"
#: bookwyrm/forms.py:257 #: bookwyrm/forms.py:249
msgid "Unlimited" msgid "Unlimited"
msgstr "Sin límite" msgstr "Sin límite"
#: bookwyrm/forms.py:301 #: bookwyrm/forms.py:293
msgid "List Order" msgid "List Order"
msgstr "Orden de la lista" msgstr "Orden de la lista"
#: bookwyrm/forms.py:302 #: bookwyrm/forms.py:294
msgid "Book Title" msgid "Book Title"
msgstr "Título" msgstr "Título"
#: bookwyrm/forms.py:303 bookwyrm/templates/snippets/create_status_form.html:31 #: bookwyrm/forms.py:295 bookwyrm/templates/snippets/create_status_form.html:31
#: bookwyrm/templates/user/shelf.html:81 #: bookwyrm/templates/user/shelf.html:81
msgid "Rating" msgid "Rating"
msgstr "Calificación" msgstr "Calificación"
#: bookwyrm/forms.py:305 bookwyrm/templates/lists/list.html:72 #: bookwyrm/forms.py:297 bookwyrm/templates/lists/list.html:72
msgid "Sort By" msgid "Sort By"
msgstr "Ordenar por" msgstr "Ordenar por"
#: bookwyrm/forms.py:309 #: bookwyrm/forms.py:301
msgid "Ascending" msgid "Ascending"
msgstr "Ascendente" msgstr "Ascendente"
#: bookwyrm/forms.py:310 #: bookwyrm/forms.py:302
msgid "Descending" msgid "Descending"
msgstr "Descendente" msgstr "Descendente"
@ -2047,7 +2047,7 @@ msgstr "Texto de registración cerrada:"
msgid "No cover" msgid "No cover"
msgstr "Sin portada" msgstr "Sin portada"
#: bookwyrm/templates/snippets/book_titleby.html:3 #: bookwyrm/templates/snippets/book_titleby.html:4
#, python-format #, python-format
msgid "<a href=\"%(path)s\">%(title)s</a> by " msgid "<a href=\"%(path)s\">%(title)s</a> by "
msgstr "<a href=\"%(path)s\">%(title)s</a> por " msgstr "<a href=\"%(path)s\">%(title)s</a> por "
@ -2527,19 +2527,6 @@ msgstr "En orden ascendente"
msgid "Sorted descending" msgid "Sorted descending"
msgstr "En orden descendente" msgstr "En orden descendente"
#: bookwyrm/templates/snippets/tag.html:14
msgid "Remove tag"
msgstr "Eliminar etiqueta"
#: bookwyrm/templates/snippets/tag.html:18
msgid "Add tag"
msgstr "Agregar etiqueta"
#: bookwyrm/templates/tag.html:9
#, python-format
msgid "Books tagged \"%(tag.name)s\""
msgstr "Libros etiquetados con \"%(tag.name)s\""
#: bookwyrm/templates/user/books_header.html:5 #: bookwyrm/templates/user/books_header.html:5
#, python-format #, python-format
msgid "%(username)s's books" msgid "%(username)s's books"
@ -2754,6 +2741,15 @@ msgstr "No se pudo encontrar un usuario con esa dirección de correo electrónic
msgid "A password reset link sent to %s" msgid "A password reset link sent to %s"
msgstr "Un enlace para reestablecer tu contraseña se enviará a %s" msgstr "Un enlace para reestablecer tu contraseña se enviará a %s"
#~ msgid "Remove tag"
#~ msgstr "Eliminar etiqueta"
#~ msgid "Add tag"
#~ msgstr "Agregar etiqueta"
#~ msgid "Books tagged \"%(tag.name)s\""
#~ msgstr "Libros etiquetados con \"%(tag.name)s\""
#~ msgid "Deactivate user" #~ msgid "Deactivate user"
#~ msgstr "Desactivar usuario" #~ msgstr "Desactivar usuario"