Merge remote-tracking branch 'upstream/main' into list-style-fixes

This commit is contained in:
Joachim 2021-05-23 15:14:50 +02:00
commit 251c8bbd08
154 changed files with 5440 additions and 3784 deletions

View File

@ -21,6 +21,7 @@ BOOKWYRM_DATABASE_BACKEND=postgres
MEDIA_ROOT=images/ MEDIA_ROOT=images/
POSTGRES_PORT=5432
POSTGRES_PASSWORD=fedireads POSTGRES_PASSWORD=fedireads
POSTGRES_USER=fedireads POSTGRES_USER=fedireads
POSTGRES_DB=fedireads POSTGRES_DB=fedireads

View File

@ -21,6 +21,7 @@ BOOKWYRM_DATABASE_BACKEND=postgres
MEDIA_ROOT=images/ MEDIA_ROOT=images/
POSTGRES_PORT=5432
POSTGRES_PASSWORD=securedbpassword123 POSTGRES_PASSWORD=securedbpassword123
POSTGRES_USER=fedireads POSTGRES_USER=fedireads
POSTGRES_DB=fedireads POSTGRES_DB=fedireads

View File

@ -55,6 +55,8 @@ class ActivityStream(RedisStore):
return ( return (
models.Status.objects.select_subclasses() models.Status.objects.select_subclasses()
.filter(id__in=statuses) .filter(id__in=statuses)
.select_related("user", "reply_parent")
.prefetch_related("mention_books", "mention_users")
.order_by("-published_date") .order_by("-published_date")
) )

View File

@ -2,7 +2,6 @@
from django.contrib import admin from django.contrib import admin
from bookwyrm import models from bookwyrm import models
admin.site.register(models.SiteSettings)
admin.site.register(models.User) admin.site.register(models.User)
admin.site.register(models.FederatedServer) admin.site.register(models.FederatedServer)
admin.site.register(models.Connector) admin.site.register(models.Connector)

View File

@ -30,7 +30,6 @@ class AbstractMinimalConnector(ABC):
"covers_url", "covers_url",
"search_url", "search_url",
"isbn_search_url", "isbn_search_url",
"max_query_count",
"name", "name",
"identifier", "identifier",
"local", "local",
@ -102,13 +101,6 @@ class AbstractConnector(AbstractMinimalConnector):
# title we handle separately. # title we handle separately.
self.book_mappings = [] self.book_mappings = []
def is_available(self):
"""check if you're allowed to use this connector"""
if self.max_query_count is not None:
if self.connector.query_count >= self.max_query_count:
return False
return True
def get_or_create_book(self, remote_id): def get_or_create_book(self, remote_id):
"""translate arbitrary json into an Activitypub dataclass""" """translate arbitrary json into an Activitypub dataclass"""
# first, check if we have the origin_id saved # first, check if we have the origin_id saved

View File

@ -19,7 +19,7 @@ class ConnectorException(HTTPError):
"""when the connector can't do what was asked""" """when the connector can't do what was asked"""
def search(query, min_confidence=0.1): def search(query, min_confidence=0.1, return_first=False):
"""find books based on arbitary keywords""" """find books based on arbitary keywords"""
if not query: if not query:
return [] return []
@ -31,19 +31,16 @@ def search(query, min_confidence=0.1):
for connector in get_connectors(): for connector in get_connectors():
result_set = None result_set = None
if maybe_isbn: if maybe_isbn and connector.isbn_search_url and connector.isbn_search_url == "":
# Search on ISBN # Search on ISBN
if not connector.isbn_search_url or connector.isbn_search_url == "":
result_set = []
else:
try: try:
result_set = connector.isbn_search(isbn) result_set = connector.isbn_search(isbn)
except Exception as e: # pylint: disable=broad-except except Exception as e: # pylint: disable=broad-except
logger.exception(e) logger.exception(e)
continue # if this fails, we can still try regular search
# if no isbn search or results, we fallback to generic search # if no isbn search results, we fallback to generic search
if result_set in (None, []): if not result_set:
try: try:
result_set = connector.search(query, min_confidence=min_confidence) result_set = connector.search(query, min_confidence=min_confidence)
except Exception as e: # pylint: disable=broad-except except Exception as e: # pylint: disable=broad-except
@ -51,6 +48,11 @@ def search(query, min_confidence=0.1):
logger.exception(e) logger.exception(e)
continue continue
if return_first and result_set:
# if we found anything, return it
return result_set[0]
if result_set or connector.local:
results.append( results.append(
{ {
"connector": connector, "connector": connector,
@ -58,6 +60,9 @@ def search(query, min_confidence=0.1):
} }
) )
if return_first:
return None
return results return results
@ -77,16 +82,12 @@ def isbn_local_search(query, raw=False):
def first_search_result(query, min_confidence=0.1): def first_search_result(query, min_confidence=0.1):
"""search until you find a result that fits""" """search until you find a result that fits"""
for connector in get_connectors(): return search(query, min_confidence=min_confidence, return_first=True) or None
result = connector.search(query, min_confidence=min_confidence)
if result:
return result[0]
return None
def get_connectors(): def get_connectors():
"""load all connectors""" """load all connectors"""
for info in models.Connector.objects.order_by("priority").all(): for info in models.Connector.objects.filter(active=True).order_by("priority").all():
yield load_connector(info) yield load_connector(info)

View File

@ -74,6 +74,14 @@ class Connector(AbstractConnector):
**{k: data.get(k) for k in ["uri", "image", "labels", "sitelinks"]}, **{k: data.get(k) for k in ["uri", "image", "labels", "sitelinks"]},
} }
def search(self, query, min_confidence=None):
"""overrides default search function with confidence ranking"""
results = super().search(query)
if min_confidence:
# filter the search results after the fact
return [r for r in results if r.confidence >= min_confidence]
return results
def parse_search_data(self, data): def parse_search_data(self, data):
return data.get("results") return data.get("results")
@ -84,6 +92,9 @@ class Connector(AbstractConnector):
if images if images
else None else None
) )
# a deeply messy translation of inventaire's scores
confidence = float(search_result.get("_score", 0.1))
confidence = 0.1 if confidence < 150 else 0.999
return SearchResult( return SearchResult(
title=search_result.get("label"), title=search_result.get("label"),
key=self.get_remote_id(search_result.get("uri")), key=self.get_remote_id(search_result.get("uri")),
@ -92,6 +103,7 @@ class Connector(AbstractConnector):
self.base_url, search_result.get("uri") self.base_url, search_result.get("uri")
), ),
cover=cover, cover=cover,
confidence=confidence,
connector=self, connector=self,
) )
@ -123,9 +135,11 @@ class Connector(AbstractConnector):
def load_edition_data(self, work_uri): def load_edition_data(self, work_uri):
"""get a list of editions for a work""" """get a list of editions for a work"""
url = "{:s}?action=reverse-claims&property=wdt:P629&value={:s}".format( url = (
"{:s}?action=reverse-claims&property=wdt:P629&value={:s}&sort=true".format(
self.books_url, work_uri self.books_url, work_uri
) )
)
return get_data(url) return get_data(url)
def get_edition_from_work_data(self, data): def get_edition_from_work_data(self, data):

View File

@ -58,6 +58,13 @@ class Connector(AbstractConnector):
Mapping("bio", formatter=get_description), Mapping("bio", formatter=get_description),
] ]
def get_book_data(self, remote_id):
data = get_data(remote_id)
if data.get("type", {}).get("key") == "/type/redirect":
remote_id = self.base_url + data.get("location")
return get_data(remote_id)
return data
def get_remote_id_from_data(self, data): def get_remote_id_from_data(self, data):
"""format a url from an openlibrary id field""" """format a url from an openlibrary id field"""
try: try:
@ -75,8 +82,11 @@ class Connector(AbstractConnector):
except KeyError: except KeyError:
raise ConnectorException("Invalid book data") raise ConnectorException("Invalid book data")
url = "%s%s/editions" % (self.books_url, key) url = "%s%s/editions" % (self.books_url, key)
data = get_data(url) data = self.get_book_data(url)
return pick_default_edition(data["entries"]) edition = pick_default_edition(data["entries"])
if not edition:
raise ConnectorException("No editions for work")
return edition
def get_work_from_edition_data(self, data): def get_work_from_edition_data(self, data):
try: try:
@ -84,7 +94,7 @@ class Connector(AbstractConnector):
except (IndexError, KeyError): except (IndexError, KeyError):
raise ConnectorException("No work found for edition") raise ConnectorException("No work found for edition")
url = "%s%s" % (self.books_url, key) url = "%s%s" % (self.books_url, key)
return get_data(url) return self.get_book_data(url)
def get_authors_from_data(self, data): def get_authors_from_data(self, data):
"""parse author json and load or create authors""" """parse author json and load or create authors"""
@ -143,7 +153,7 @@ class Connector(AbstractConnector):
def load_edition_data(self, olkey): def load_edition_data(self, olkey):
"""query openlibrary for editions of a work""" """query openlibrary for editions of a work"""
url = "%s/works/%s/editions" % (self.books_url, olkey) url = "%s/works/%s/editions" % (self.books_url, olkey)
return get_data(url) return self.get_book_data(url)
def expand_book_data(self, book): def expand_book_data(self, book):
work = book work = book

View File

@ -4,4 +4,7 @@ from bookwyrm import models
def site_settings(request): # pylint: disable=unused-argument def site_settings(request): # pylint: disable=unused-argument
"""include the custom info about the site""" """include the custom info about the site"""
return {"site": models.SiteSettings.objects.get()} return {
"site": models.SiteSettings.objects.get(),
"active_announcements": models.Announcement.active_announcements(),
}

View File

@ -269,6 +269,12 @@ class SiteForm(CustomForm):
exclude = [] exclude = []
class AnnouncementForm(CustomForm):
class Meta:
model = models.Announcement
exclude = ["remote_id"]
class ListForm(CustomForm): class ListForm(CustomForm):
class Meta: class Meta:
model = models.List model = models.List

View File

@ -3,3 +3,4 @@
from .importer import Importer from .importer import Importer
from .goodreads_import import GoodreadsImporter from .goodreads_import import GoodreadsImporter
from .librarything_import import LibrarythingImporter from .librarything_import import LibrarythingImporter
from .storygraph_import import StorygraphImporter

View File

@ -0,0 +1,34 @@
""" handle reading a csv from librarything """
import re
import math
from . import Importer
class StorygraphImporter(Importer):
"""csv downloads from librarything"""
service = "Storygraph"
# mandatory_fields : fields matching the book title and author
mandatory_fields = ["Title"]
def parse_fields(self, entry):
"""custom parsing for storygraph"""
data = {}
data["import_source"] = self.service
data["Title"] = entry["Title"]
data["Author"] = entry["Authors"] if "Authors" in entry else entry["Author"]
data["ISBN13"] = entry["ISBN"]
data["My Review"] = entry["Review"]
if entry["Star Rating"]:
data["My Rating"] = math.ceil(float(entry["Star Rating"]))
else:
data["My Rating"] = ""
data["Date Added"] = re.sub(r"[/]", "-", entry["Date Added"])
data["Date Read"] = re.sub(r"[/]", "-", entry["Last Date Read"])
data["Exclusive Shelf"] = (
{"read": "read", "currently-reading": "reading", "to-read": "to-read"}
).get(entry["Read Status"], None)
return data

View File

@ -0,0 +1,48 @@
# Generated by Django 3.2 on 2021-05-11 18:29
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("bookwyrm", "0073_sitesettings_footer_item"),
]
operations = [
migrations.RemoveField(
model_name="connector",
name="max_query_count",
),
migrations.RemoveField(
model_name="connector",
name="politeness_delay",
),
migrations.RemoveField(
model_name="connector",
name="query_count",
),
migrations.RemoveField(
model_name="connector",
name="query_count_expiry",
),
migrations.AddField(
model_name="connector",
name="active",
field=models.BooleanField(default=True),
),
migrations.AddField(
model_name="connector",
name="deactivation_reason",
field=models.CharField(
blank=True,
choices=[
("self_deletion", "Self Deletion"),
("moderator_deletion", "Moderator Deletion"),
("domain_block", "Domain Block"),
],
max_length=255,
null=True,
),
),
]

View File

@ -0,0 +1,56 @@
# Generated by Django 3.2 on 2021-05-20 19:34
import bookwyrm.models.fields
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
("bookwyrm", "0074_auto_20210511_1829"),
]
operations = [
migrations.CreateModel(
name="Announcement",
fields=[
(
"id",
models.AutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("created_date", models.DateTimeField(auto_now_add=True)),
("updated_date", models.DateTimeField(auto_now=True)),
(
"remote_id",
bookwyrm.models.fields.RemoteIdField(
max_length=255,
null=True,
validators=[bookwyrm.models.fields.validate_remote_id],
),
),
("preview", models.CharField(max_length=255)),
("content", models.TextField(blank=True, null=True)),
("event_date", models.DateTimeField(blank=True, null=True)),
("start_date", models.DateTimeField(blank=True, null=True)),
("end_date", models.DateTimeField(blank=True, null=True)),
("active", models.BooleanField(default=True)),
(
"user",
models.ForeignKey(
on_delete=django.db.models.deletion.PROTECT,
to=settings.AUTH_USER_MODEL,
),
),
],
options={
"abstract": False,
},
),
]

View File

@ -25,6 +25,7 @@ from .federated_server import FederatedServer
from .import_job import ImportJob, ImportItem from .import_job import ImportJob, ImportItem
from .site import SiteSettings, SiteInvite, PasswordReset, InviteRequest from .site import SiteSettings, SiteInvite, PasswordReset, InviteRequest
from .announcement import Announcement
cls_members = inspect.getmembers(sys.modules[__name__], inspect.isclass) cls_members = inspect.getmembers(sys.modules[__name__], inspect.isclass)
activity_models = { activity_models = {

View File

@ -0,0 +1,28 @@
""" admin announcements """
from django.db import models
from django.db.models import Q
from django.utils import timezone
from .base_model import BookWyrmModel
class Announcement(BookWyrmModel):
"""The admin has something to say"""
user = models.ForeignKey("User", on_delete=models.PROTECT)
preview = models.CharField(max_length=255)
content = models.TextField(null=True, blank=True)
event_date = models.DateTimeField(blank=True, null=True)
start_date = models.DateTimeField(blank=True, null=True)
end_date = models.DateTimeField(blank=True, null=True)
active = models.BooleanField(default=True)
@classmethod
def active_announcements(cls):
"""announcements that should be displayed"""
now = timezone.now()
return cls.objects.filter(
Q(start_date__isnull=True) | Q(start_date__lte=now),
Q(end_date__isnull=True) | Q(end_date__gte=now),
active=True,
)

View File

@ -6,6 +6,16 @@ from bookwyrm.settings import DOMAIN
from .fields import RemoteIdField from .fields import RemoteIdField
DeactivationReason = models.TextChoices(
"DeactivationReason",
[
"self_deletion",
"moderator_deletion",
"domain_block",
],
)
class BookWyrmModel(models.Model): class BookWyrmModel(models.Model):
"""shared fields""" """shared fields"""

View File

@ -2,7 +2,7 @@
from django.db import models from django.db import models
from bookwyrm.connectors.settings import CONNECTORS from bookwyrm.connectors.settings import CONNECTORS
from .base_model import BookWyrmModel from .base_model import BookWyrmModel, DeactivationReason
ConnectorFiles = models.TextChoices("ConnectorFiles", CONNECTORS) ConnectorFiles = models.TextChoices("ConnectorFiles", CONNECTORS)
@ -17,6 +17,10 @@ class Connector(BookWyrmModel):
local = models.BooleanField(default=False) local = models.BooleanField(default=False)
connector_file = models.CharField(max_length=255, choices=ConnectorFiles.choices) connector_file = models.CharField(max_length=255, choices=ConnectorFiles.choices)
api_key = models.CharField(max_length=255, null=True, blank=True) api_key = models.CharField(max_length=255, null=True, blank=True)
active = models.BooleanField(default=True)
deactivation_reason = models.CharField(
max_length=255, choices=DeactivationReason.choices, null=True, blank=True
)
base_url = models.CharField(max_length=255) base_url = models.CharField(max_length=255)
books_url = models.CharField(max_length=255) books_url = models.CharField(max_length=255)
@ -24,13 +28,6 @@ class Connector(BookWyrmModel):
search_url = models.CharField(max_length=255, null=True, blank=True) search_url = models.CharField(max_length=255, null=True, blank=True)
isbn_search_url = models.CharField(max_length=255, null=True, blank=True) isbn_search_url = models.CharField(max_length=255, null=True, blank=True)
politeness_delay = models.IntegerField(null=True, blank=True) # seconds
max_query_count = models.IntegerField(null=True, blank=True)
# how many queries executed in a unit of time, like a day
query_count = models.IntegerField(default=0)
# when to reset the query count back to 0 (ie, after 1 day)
query_count_expiry = models.DateTimeField(auto_now_add=True, blank=True)
def __str__(self): def __str__(self):
return "{} ({})".format( return "{} ({})".format(
self.identifier, self.identifier,

View File

@ -1,5 +1,6 @@
""" connections to external ActivityPub servers """ """ connections to external ActivityPub servers """
from urllib.parse import urlparse from urllib.parse import urlparse
from django.apps import apps
from django.db import models from django.db import models
from .base_model import BookWyrmModel from .base_model import BookWyrmModel
@ -34,6 +35,13 @@ class FederatedServer(BookWyrmModel):
is_active=False, deactivation_reason="domain_block" is_active=False, deactivation_reason="domain_block"
) )
# check for related connectors
if self.application_type == "bookwyrm":
connector_model = apps.get_model("bookwyrm.Connector", require_ready=True)
connector_model.objects.filter(
identifier=self.server_name, active=True
).update(active=False, deactivation_reason="domain_block")
def unblock(self): def unblock(self):
"""unblock a server""" """unblock a server"""
self.status = "federated" self.status = "federated"
@ -43,6 +51,15 @@ class FederatedServer(BookWyrmModel):
is_active=True, deactivation_reason=None is_active=True, deactivation_reason=None
) )
# check for related connectors
if self.application_type == "bookwyrm":
connector_model = apps.get_model("bookwyrm.Connector", require_ready=True)
connector_model.objects.filter(
identifier=self.server_name,
active=False,
deactivation_reason="domain_block",
).update(active=True, deactivation_reason=None)
@classmethod @classmethod
def is_blocked(cls, url): def is_blocked(cls, url):
"""look up if a domain is blocked""" """look up if a domain is blocked"""

View File

@ -128,7 +128,9 @@ class ImportItem(models.Model):
@property @property
def rating(self): def rating(self):
"""x/5 star rating for a book""" """x/5 star rating for a book"""
if self.data.get("My Rating", None):
return int(self.data["My Rating"]) return int(self.data["My Rating"])
return None
@property @property
def date_added(self): def date_added(self):

View File

@ -19,21 +19,11 @@ from bookwyrm.signatures import create_key_pair
from bookwyrm.tasks import app from bookwyrm.tasks import app
from bookwyrm.utils import regex from bookwyrm.utils import regex
from .activitypub_mixin import OrderedCollectionPageMixin, ActivitypubMixin from .activitypub_mixin import OrderedCollectionPageMixin, ActivitypubMixin
from .base_model import BookWyrmModel from .base_model import BookWyrmModel, DeactivationReason
from .federated_server import FederatedServer from .federated_server import FederatedServer
from . import fields, Review from . import fields, Review
DeactivationReason = models.TextChoices(
"DeactivationReason",
[
"self_deletion",
"moderator_deletion",
"domain_block",
],
)
class User(OrderedCollectionPageMixin, AbstractUser): class User(OrderedCollectionPageMixin, AbstractUser):
"""a user who wants to read books""" """a user who wants to read books"""
@ -372,7 +362,10 @@ class AnnualGoal(BookWyrmModel):
def books(self): def books(self):
"""the books you've read this year""" """the books you've read this year"""
return ( return (
self.user.readthrough_set.filter(finish_date__year__gte=self.year) self.user.readthrough_set.filter(
finish_date__year__gte=self.year,
finish_date__year__lt=self.year + 1,
)
.order_by("-finish_date") .order_by("-finish_date")
.all() .all()
) )
@ -388,16 +381,16 @@ class AnnualGoal(BookWyrmModel):
return {r.book.id: r.rating for r in reviews} return {r.book.id: r.rating for r in reviews}
@property @property
def progress_percent(self): def progress(self):
"""how close to your goal, in percent form"""
return int(float(self.book_count / self.goal) * 100)
@property
def book_count(self):
"""how many books you've read this year""" """how many books you've read this year"""
return self.user.readthrough_set.filter( count = self.user.readthrough_set.filter(
finish_date__year__gte=self.year finish_date__year__gte=self.year,
finish_date__year__lt=self.year + 1,
).count() ).count()
return {
"count": count,
"percent": int(float(count / self.goal) * 100),
}
@app.task @app.task

View File

@ -38,7 +38,7 @@ LOCALE_PATHS = [
DEFAULT_AUTO_FIELD = "django.db.models.AutoField" DEFAULT_AUTO_FIELD = "django.db.models.AutoField"
# Quick-start development settings - unsuitable for production # Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/2.0/howto/deployment/checklist/ # See https://docs.djangoproject.com/en/3.2/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret! # SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = env("SECRET_KEY") SECRET_KEY = env("SECRET_KEY")
@ -107,7 +107,7 @@ MAX_STREAM_LENGTH = int(env("MAX_STREAM_LENGTH", 200))
STREAMS = ["home", "local", "federated"] STREAMS = ["home", "local", "federated"]
# Database # Database
# https://docs.djangoproject.com/en/2.0/ref/settings/#databases # https://docs.djangoproject.com/en/3.2/ref/settings/#databases
BOOKWYRM_DATABASE_BACKEND = env("BOOKWYRM_DATABASE_BACKEND", "postgres") BOOKWYRM_DATABASE_BACKEND = env("BOOKWYRM_DATABASE_BACKEND", "postgres")
@ -118,7 +118,7 @@ BOOKWYRM_DBS = {
"USER": env("POSTGRES_USER", "fedireads"), "USER": env("POSTGRES_USER", "fedireads"),
"PASSWORD": env("POSTGRES_PASSWORD", "fedireads"), "PASSWORD": env("POSTGRES_PASSWORD", "fedireads"),
"HOST": env("POSTGRES_HOST", ""), "HOST": env("POSTGRES_HOST", ""),
"PORT": 5432, "PORT": env("POSTGRES_PORT", 5432),
}, },
} }
@ -129,7 +129,7 @@ LOGIN_URL = "/login/"
AUTH_USER_MODEL = "bookwyrm.User" AUTH_USER_MODEL = "bookwyrm.User"
# Password validation # Password validation
# https://docs.djangoproject.com/en/2.0/ref/settings/#auth-password-validators # https://docs.djangoproject.com/en/3.2/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [ AUTH_PASSWORD_VALIDATORS = [
{ {
@ -148,7 +148,7 @@ AUTH_PASSWORD_VALIDATORS = [
# Internationalization # Internationalization
# https://docs.djangoproject.com/en/2.0/topics/i18n/ # https://docs.djangoproject.com/en/3.2/topics/i18n/
LANGUAGE_CODE = "en-us" LANGUAGE_CODE = "en-us"
LANGUAGES = [ LANGUAGES = [
@ -170,7 +170,7 @@ USE_TZ = True
# Static files (CSS, JavaScript, Images) # Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.1/howto/static-files/ # https://docs.djangoproject.com/en/3.2/howto/static-files/
PROJECT_DIR = os.path.dirname(os.path.abspath(__file__)) PROJECT_DIR = os.path.dirname(os.path.abspath(__file__))
STATIC_URL = "/static/" STATIC_URL = "/static/"

View File

@ -101,10 +101,11 @@ body {
.transition-y.is-hidden { .transition-y.is-hidden {
display: block !important; display: block !important;
visibility: hidden !important; visibility: hidden !important;
height: 0; height: 0 !important;
width: 0; width: 0 !important;
margin: 0; margin: 0 !important;
padding: 0; padding: 0 !important;
overflow: auto;
} }
.transition-x, .transition-x,

View File

@ -1,44 +0,0 @@
{% extends 'layout.html' %}
{% load i18n %}
{% load bookwyrm_tags %}
{% block title %}{{ author.name }}{% endblock %}
{% block content %}
<div class="block">
<div class="columns is-mobile">
<div class="column">
<h1 class="title">{{ author.name }}</h1>
</div>
{% if request.user.is_authenticated and perms.bookwyrm.edit_book %}
<div class="column is-narrow">
<a href="{{ author.local_path }}/edit">
<span class="icon icon-pencil" title="{% trans 'Edit Author' %}">
<span class="is-sr-only">{% trans "Edit Author" %}</span>
</span>
</a>
</div>
{% endif %}
</div>
</div>
<div class="block">
{% if author.bio %}
<p>
{{ author.bio | to_markdown | safe }}
</p>
{% endif %}
{% if author.wikipedia_link %}
<p><a href="{{ author.wikipedia_link }}" rel=”noopener” target="_blank">{% trans "Wikipedia" %}</a></p>
{% endif %}
</div>
<div class="block">
<h3 class="title is-4">{% blocktrans with name=author.name %}Books by {{ name }}{% endblocktrans %}</h3>
{% include 'snippets/book_tiles.html' with books=books %}
</div>
{% endblock %}
{% block scripts %}
{% include 'snippets/datepicker_js.html' %}
{% endblock %}

View File

@ -0,0 +1,83 @@
{% extends 'layout.html' %}
{% load i18n %}
{% load markdown %}
{% load humanize %}
{% block title %}{{ author.name }}{% endblock %}
{% block content %}
<div class="block">
<div class="columns is-mobile">
<div class="column">
<h1 class="title">{{ author.name }}</h1>
</div>
{% if request.user.is_authenticated and perms.bookwyrm.edit_book %}
<div class="column is-narrow">
<a href="{{ author.local_path }}/edit">
<span class="icon icon-pencil" title="{% trans 'Edit Author' %}" aria-hidden="True"></span>
<span>{% trans "Edit Author" %}</span>
</a>
</div>
{% endif %}
</div>
</div>
<div class="block content columns">
{% if author.aliases or author.born or author.died or author.wikipedia_link %}
<div class="column is-narrow">
<div class="box">
<dl>
{% if author.aliases %}
<div class="is-flex">
<dt class="mr-1">{% trans "Aliases:" %}</dt>
<dd itemprop="aliases">{{ author.aliases|join:', ' }}</dd>
</div>
{% endif %}
{% if author.born %}
<div class="is-flex">
<dt class="mr-1">{% trans "Born:" %}</dt>
<dd itemprop="aliases">{{ author.born|naturalday }}</dd>
</div>
{% endif %}
{% if author.aliases %}
<div class="is-flex">
<dt class="mr-1">{% trans "Died:" %}</dt>
<dd itemprop="aliases">{{ author.died|naturalday }}</dd>
</div>
{% endif %}
</dl>
{% if author.wikipedia_link %}
<p><a href="{{ author.wikipedia_link }}" rel=”noopener” target="_blank">{% trans "Wikipedia" %}</a></p>
{% endif %}
{% if author.openlibrary_key %}
<p class="mb-0">
<a href="https://openlibrary.org/authors/{{ author.openlibrary_key }}" target="_blank" rel="noopener">{% trans "View on OpenLibrary" %}</a>
</p>
{% endif %}
{% if author.inventaire_id %}
<p class="mb-0">
<a href="https://inventaire.io/entity/{{ author.inventaire_id }}" target="_blank" rel="noopener">{% trans "View on Inventaire" %}</a>
</p>
{% endif %}
</div>
</div>
{% endif %}
<div class="column">
{% if author.bio %}
{{ author.bio|to_markdown|safe }}
{% endif %}
</div>
</div>
<div class="block">
<h3 class="title is-4">{% blocktrans with name=author.name %}Books by {{ name }}{% endblocktrans %}</h3>
<div class="columns is-multiline is-mobile">
{% for book in books %}
<div class="column is-one-fifth">
{% include 'discover/small-book.html' with book=book %}
</div>
{% endfor %}
</div>
</div>
{% endblock %}

View File

@ -29,44 +29,64 @@
<div class="columns"> <div class="columns">
<div class="column"> <div class="column">
<h2 class="title is-4">{% trans "Metadata" %}</h2> <h2 class="title is-4">{% trans "Metadata" %}</h2>
<p><label class="label" for="id_name">{% trans "Name:" %}</label> {{ form.name }}</p> <p class="mb-2"><label class="label" for="id_name">{% trans "Name:" %}</label> {{ form.name }}</p>
{% for error in form.name.errors %} {% for error in form.name.errors %}
<p class="help is-danger">{{ error | escape }}</p> <p class="help is-danger">{{ error | escape }}</p>
{% endfor %} {% endfor %}
<p><label class="label" for="id_bio">{% trans "Bio:" %}</label> {{ form.bio }}</p> <p class="mb-2">
<label class="label" for="id_aliases">{% trans "Aliases:" %}</label>
{{ form.aliases }}
<span class="help">{% trans "Separate multiple values with commas." %}</span>
</p>
{% for error in form.aliases.errors %}
<p class="help is-danger">{{ error | escape }}</p>
{% endfor %}
<p class="mb-2"><label class="label" for="id_bio">{% trans "Bio:" %}</label> {{ form.bio }}</p>
{% for error in form.bio.errors %} {% for error in form.bio.errors %}
<p class="help is-danger">{{ error | escape }}</p> <p class="help is-danger">{{ error | escape }}</p>
{% endfor %} {% endfor %}
<p><label class="label" for="id_wikipedia_link">{% trans "Wikipedia link:" %}</label> {{ form.wikipedia_link }}</p> <p class="mb-2"><label class="label" for="id_wikipedia_link">{% trans "Wikipedia link:" %}</label> {{ form.wikipedia_link }}</p>
{% for error in form.wikipedia_link.errors %} {% for error in form.wikipedia_link.errors %}
<p class="help is-danger">{{ error | escape }}</p> <p class="help is-danger">{{ error | escape }}</p>
{% endfor %} {% endfor %}
<p><label class="label" for="id_born">{% trans "Birth date:" %}</label> {{ form.born }}</p> <p class="mb-2">
<label class="label" for="id_born">{% trans "Birth date:" %}</label>
<input type="date" name="born" value="{{ form.born.value|date:'Y-m-d' }}" class="input" id="id_born">
</p>
{% for error in form.born.errors %} {% for error in form.born.errors %}
<p class="help is-danger">{{ error | escape }}</p> <p class="help is-danger">{{ error | escape }}</p>
{% endfor %} {% endfor %}
<p><label class="label" for="id_died">{% trans "Death date:" %}</label> {{ form.died }}</p> <p class="mb-2">
<label class="label" for="id_died">{% trans "Death date:" %}</label>
<input type="date" name="died" value="{{ form.died.value|date:'Y-m-d' }}" class="input" id="id_died">
</p>
{% for error in form.died.errors %} {% for error in form.died.errors %}
<p class="help is-danger">{{ error | escape }}</p> <p class="help is-danger">{{ error | escape }}</p>
{% endfor %} {% endfor %}
</div> </div>
<div class="column"> <div class="column">
<h2 class="title is-4">{% trans "Author Identifiers" %}</h2> <h2 class="title is-4">{% trans "Author Identifiers" %}</h2>
<p><label class="label" for="id_openlibrary_key">{% trans "Openlibrary key:" %}</label> {{ form.openlibrary_key }}</p> <p class="mb-2"><label class="label" for="id_openlibrary_key">{% trans "Openlibrary key:" %}</label> {{ form.openlibrary_key }}</p>
{% for error in form.openlibrary_key.errors %} {% for error in form.openlibrary_key.errors %}
<p class="help is-danger">{{ error | escape }}</p> <p class="help is-danger">{{ error | escape }}</p>
{% endfor %} {% endfor %}
<p><label class="label" for="id_librarything_key">{% trans "Librarything key:" %}</label> {{ form.librarything_key }}</p> <p class="mb-2"><label class="label" for="id_inventaire_id">{% trans "Inventaire ID:" %}</label> {{ form.inventaire_id }}</p>
{% for error in form.inventaire_id.errors %}
<p class="help is-danger">{{ error | escape }}</p>
{% endfor %}
<p class="mb-2"><label class="label" for="id_librarything_key">{% trans "Librarything key:" %}</label> {{ form.librarything_key }}</p>
{% for error in form.librarything_key.errors %} {% for error in form.librarything_key.errors %}
<p class="help is-danger">{{ error | escape }}</p> <p class="help is-danger">{{ error | escape }}</p>
{% endfor %} {% endfor %}
<p><label class="label" for="id_goodreads_key">{% trans "Goodreads key:" %}</label> {{ form.goodreads_key }}</p> <p class="mb-2"><label class="label" for="id_goodreads_key">{% trans "Goodreads key:" %}</label> {{ form.goodreads_key }}</p>
{% for error in form.goodreads_key.errors %} {% for error in form.goodreads_key.errors %}
<p class="help is-danger">{{ error | escape }}</p> <p class="help is-danger">{{ error | escape }}</p>
{% endfor %} {% endfor %}
@ -81,7 +101,3 @@
</form> </form>
{% endblock %} {% endblock %}
{% block scripts %}
{% include 'snippets/datepicker_js.html' %}
{% endblock %}

View File

@ -1,9 +1,7 @@
{% extends 'layout.html' %} {% extends 'layout.html' %}
{% load i18n %} {% load i18n %}{% load bookwyrm_tags %}{% load humanize %}{% load utilities %}
{% load bookwyrm_tags %}
{% load humanize %}
{% block title %}{{ book.title }}{% endblock %} {% block title %}{{ book|title }}{% endblock %}
{% block content %} {% block content %}
{% with user_authenticated=request.user.is_authenticated can_edit_book=perms.bookwyrm.edit_book %} {% with user_authenticated=request.user.is_authenticated can_edit_book=perms.bookwyrm.edit_book %}
@ -38,9 +36,8 @@
{% if user_authenticated and can_edit_book %} {% if user_authenticated and can_edit_book %}
<div class="column is-narrow"> <div class="column is-narrow">
<a href="{{ book.id }}/edit"> <a href="{{ book.id }}/edit">
<span class="icon icon-pencil" title="{% trans "Edit Book" %}"> <span class="icon icon-pencil" title="{% trans "Edit Book" %}" aria-hidden=True></span>
<span class="is-sr-only">{% trans "Edit Book" %}</span> <span>{% trans "Edit Book" %}</span>
</span>
</a> </a>
</div> </div>
{% endif %} {% endif %}
@ -140,7 +137,7 @@
{# user's relationship to the book #} {# user's relationship to the book #}
<div class="block"> <div class="block">
{% for shelf in user_shelves %} {% for shelf in user_shelfbooks %}
<p> <p>
{% blocktrans with path=shelf.shelf.local_path shelf_name=shelf.shelf.name %}This edition is on your <a href="{{ path }}">{{ shelf_name }}</a> shelf.{% endblocktrans %} {% blocktrans with path=shelf.shelf.local_path shelf_name=shelf.shelf.name %}This edition is on your <a href="{{ path }}">{{ shelf_name }}</a> shelf.{% endblocktrans %}
{% include 'snippets/shelf_selector.html' with current=shelf.shelf %} {% include 'snippets/shelf_selector.html' with current=shelf.shelf %}
@ -163,12 +160,9 @@
</div> </div>
<div class="column is-narrow"> <div class="column is-narrow">
{% trans "Add read dates" as button_text %} {% trans "Add read dates" as button_text %}
{% include 'snippets/toggle/open_button.html' with text=button_text icon="plus" class="is-small" controls_text="add-readthrough" %} {% include 'snippets/toggle/open_button.html' with text=button_text icon_with_text="plus" class="is-small" controls_text="add-readthrough" focus="add-readthrough-focus" %}
</div> </div>
</header> </header>
{% if not readthroughs.exists %}
<p>{% trans "You don't have any reading activity for this book." %}</p>
{% endif %}
<section class="is-hidden box" id="add-readthrough"> <section class="is-hidden box" id="add-readthrough">
<form name="add-readthrough" action="/create-readthrough" method="post"> <form name="add-readthrough" action="/create-readthrough" method="post">
{% include 'snippets/readthrough_form.html' with readthrough=None %} {% include 'snippets/readthrough_form.html' with readthrough=None %}
@ -183,6 +177,9 @@
</div> </div>
</form> </form>
</section> </section>
{% if not readthroughs.exists %}
<p>{% trans "You don't have any reading activity for this book." %}</p>
{% endif %}
{% for readthrough in readthroughs %} {% for readthrough in readthroughs %}
{% include 'snippets/readthrough.html' with readthrough=readthrough %} {% include 'snippets/readthrough.html' with readthrough=readthrough %}
{% endfor %} {% endfor %}
@ -195,7 +192,7 @@
{% endif %} {% endif %}
<div class="block" id="reviews"> <div class="block" id="reviews">
{% if request.user.is_authenticated %} {% if request.user.is_authenticated %}
{% if user_statuses.review_count or user_statuses.comment_count or user_stuatses.quotation_count %} {% if user_statuses.review_count or user_statuses.comment_count or user_statuses.quotation_count %}
<nav class="tabs"> <nav class="tabs">
<ul> <ul>
{% url 'book' book.id as tab_url %} {% url 'book' book.id as tab_url %}
@ -225,46 +222,26 @@
{% endif %} {% endif %}
{% endif %} {% endif %}
{% for review in statuses %} {% for status in statuses %}
<div <div
class="block" class="block"
{% if status.status_type == 'Review' or status.status_type == 'Rating' %}
itemprop="review" itemprop="review"
itemscope itemscope
itemtype="https://schema.org/Review" itemtype="https://schema.org/Review"
{% endif %}
> >
{% with status=review hide_book=True depth=1 %} {% include 'snippets/status/status.html' with status=status hide_book=True depth=1 %}
{% include 'snippets/status/status.html' %}
{% endwith %}
</div> </div>
{% endfor %} {% endfor %}
{% if ratings %}
<div class="block is-flex is-flex-wrap-wrap"> <div class="block is-flex is-flex-wrap-wrap">
{% for rating in ratings %} {% for rating in ratings %}
{% with user=rating.user %} {% include 'book/rating.html' with user=rating.user rating=rating %}
<div class="block mr-5">
<div class="media">
<div class="media-left">
{% include 'snippets/avatar.html' %}
</div>
<div class="media-content">
<div>
<a href="{{ user.local_path }}">{{ user.display_name }}</a>
</div>
<div class="is-flex">
<p class="mr-1">{% trans "rated it" %}</p>
{% include 'snippets/stars.html' with rating=rating.rating %}
</div>
<div>
<a href="{{ rating.remote_id }}">{{ rating.published_date | naturaltime }}</a>
</div>
</div>
</div>
</div>
{% endwith %}
{% endfor %} {% endfor %}
</div> </div>
{% endif %}
<div class="block"> <div class="block">
{% include 'snippets/pagination.html' with page=statuses path=request.path anchor="#reviews" %} {% include 'snippets/pagination.html' with page=statuses path=request.path anchor="#reviews" %}
</div> </div>
@ -333,5 +310,4 @@
{% block scripts %} {% block scripts %}
<script src="/static/js/vendor/tabs.js"></script> <script src="/static/js/vendor/tabs.js"></script>
{% include 'snippets/datepicker_js.html' %}
{% endblock %} {% endblock %}

View File

@ -1,5 +1,4 @@
{% spaceless %} {% spaceless %}
{% load i18n %} {% load i18n %}
<dl> <dl>

View File

@ -88,6 +88,7 @@
<div class="column is-half"> <div class="column is-half">
<section class="block"> <section class="block">
<h2 class="title is-4">{% trans "Metadata" %}</h2> <h2 class="title is-4">{% trans "Metadata" %}</h2>
<p class="mb-2"> <p class="mb-2">
<label class="label" for="id_title">{% trans "Title:" %}</label> <label class="label" for="id_title">{% trans "Title:" %}</label>
<input type="text" name="title" value="{{ form.title.value|default:'' }}" maxlength="255" class="input" required="" id="id_title"> <input type="text" name="title" value="{{ form.title.value|default:'' }}" maxlength="255" class="input" required="" id="id_title">
@ -117,15 +118,27 @@
<p class="help is-danger">{{ error | escape }}</p> <p class="help is-danger">{{ error | escape }}</p>
{% endfor %} {% endfor %}
<p class="mb-2"><label class="label" for="id_series_number">{% trans "Series number:" %}</label> {{ form.series_number }} </p> <p class="mb-2">
<label class="label" for="id_series_number">{% trans "Series number:" %}</label>
{{ form.series_number }}
</p>
{% for error in form.series_number.errors %} {% for error in form.series_number.errors %}
<p class="help is-danger">{{ error | escape }}</p> <p class="help is-danger">{{ error | escape }}</p>
{% endfor %} {% endfor %}
<p class="mb-2">
<label class="label" for="id_languages">{% trans "Languages:" %}</label>
{{ form.languages }}
<span class="help">{% trans "Separate multiple values with commas." %}</span>
</p>
{% for error in form.languages.errors %}
<p class="help is-danger">{{ error | escape }}</p>
{% endfor %}
<p class="mb-2"> <p class="mb-2">
<label class="label" for="id_publishers">{% trans "Publisher:" %}</label> <label class="label" for="id_publishers">{% trans "Publisher:" %}</label>
{{ form.publishers }} {{ form.publishers }}
<span class="help">{% trans "Separate multiple publishers with commas." %}</span> <span class="help">{% trans "Separate multiple values with commas." %}</span>
</p> </p>
{% for error in form.publishers.errors %} {% for error in form.publishers.errors %}
<p class="help is-danger">{{ error | escape }}</p> <p class="help is-danger">{{ error | escape }}</p>
@ -133,11 +146,7 @@
<p class="mb-2"> <p class="mb-2">
<label class="label" for="id_first_published_date">{% trans "First published date:" %}</label> <label class="label" for="id_first_published_date">{% trans "First published date:" %}</label>
<duet-date-picker <input type="date" name="first_published_date" class="input" id="id_first_published_date"{% if form.first_published_date.value %} value="{{ form.first_published_date.value|date:'Y-m-d' }}"{% endif %}>
identifier="id_first_published_date"
name="first_published_date"
{% if form.first_published_date.value %}value="{{ form.first_published_date.value|date:'Y-m-d' }}"{% endif %}
></duet-date-picker>
</p> </p>
{% for error in form.first_published_date.errors %} {% for error in form.first_published_date.errors %}
<p class="help is-danger">{{ error | escape }}</p> <p class="help is-danger">{{ error | escape }}</p>
@ -145,11 +154,7 @@
<p class="mb-2"> <p class="mb-2">
<label class="label" for="id_published_date">{% trans "Published date:" %}</label> <label class="label" for="id_published_date">{% trans "Published date:" %}</label>
<duet-date-picker <input type="date" name="published_date" class="input" id="id_published_date"{% if form.published_date.value %} value="{{ form.published_date.value|date:'Y-m-d'}}"{% endif %}>
identifier="id_published_date"
name="published_date"
{% if form.published_date.value %}value="{{ form.published_date.value|date:'Y-m-d' }}"{% endif %}
></duet-date-picker>
</p> </p>
{% for error in form.published_date.errors %} {% for error in form.published_date.errors %}
<p class="help is-danger">{{ error | escape }}</p> <p class="help is-danger">{{ error | escape }}</p>
@ -170,7 +175,7 @@
{% endif %} {% endif %}
<label class="label" for="id_add_author">{% trans "Add Authors:" %}</label> <label class="label" for="id_add_author">{% trans "Add Authors:" %}</label>
<input class="input" type="text" name="add_author" id="id_add_author" placeholder="{% trans 'John Doe, Jane Smith' %}" value="{{ add_author }}" {% if confirm_mode %}readonly{% endif %}> <input class="input" type="text" name="add_author" id="id_add_author" placeholder="{% trans 'John Doe, Jane Smith' %}" value="{{ add_author }}" {% if confirm_mode %}readonly{% endif %}>
<p class="help">Separate multiple author names with commas.</p> <span class="help">{% trans "Separate multiple values with commas." %}</span>
</section> </section>
</div> </div>
@ -224,18 +229,27 @@
{% for error in form.isbn_13.errors %} {% for error in form.isbn_13.errors %}
<p class="help is-danger">{{ error | escape }}</p> <p class="help is-danger">{{ error | escape }}</p>
{% endfor %} {% endfor %}
<p class="mb-2"><label class="label" for="id_isbn_10">{% trans "ISBN 10:" %}</label> {{ form.isbn_10 }} </p> <p class="mb-2"><label class="label" for="id_isbn_10">{% trans "ISBN 10:" %}</label> {{ form.isbn_10 }} </p>
{% for error in form.isbn_10.errors %} {% for error in form.isbn_10.errors %}
<p class="help is-danger">{{ error | escape }}</p> <p class="help is-danger">{{ error | escape }}</p>
{% endfor %} {% endfor %}
<p class="mb-2"><label class="label" for="id_openlibrary_key">{% trans "Openlibrary key:" %}</label> {{ form.openlibrary_key }} </p>
<p class="mb-2"><label class="label" for="id_openlibrary_key">{% trans "Openlibrary ID:" %}</label> {{ form.openlibrary_key }} </p>
{% for error in form.openlibrary_key.errors %} {% for error in form.openlibrary_key.errors %}
<p class="help is-danger">{{ error | escape }}</p> <p class="help is-danger">{{ error | escape }}</p>
{% endfor %} {% endfor %}
<p class="mb-2"><label class="label" for="id_inventaire_id">{% trans "Inventaire ID:" %}</label> {{ form.inventaire_id }} </p>
{% for error in form.inventaire_id.errors %}
<p class="help is-danger">{{ error | escape }}</p>
{% endfor %}
<p class="mb-2"><label class="label" for="id_oclc_number">{% trans "OCLC Number:" %}</label> {{ form.oclc_number }} </p> <p class="mb-2"><label class="label" for="id_oclc_number">{% trans "OCLC Number:" %}</label> {{ form.oclc_number }} </p>
{% for error in form.oclc_number.errors %} {% for error in form.oclc_number.errors %}
<p class="help is-danger">{{ error | escape }}</p> <p class="help is-danger">{{ error | escape }}</p>
{% endfor %} {% endfor %}
<p class="mb-2"><label class="label" for="id_asin">{% trans "ASIN:" %}</label> {{ form.asin }} </p> <p class="mb-2"><label class="label" for="id_asin">{% trans "ASIN:" %}</label> {{ form.asin }} </p>
{% for error in form.ASIN.errors %} {% for error in form.ASIN.errors %}
<p class="help is-danger">{{ error | escape }}</p> <p class="help is-danger">{{ error | escape }}</p>
@ -253,7 +267,3 @@
</form> </form>
{% endblock %} {% endblock %}
{% block scripts %}
{% include 'snippets/datepicker_js.html' %}
{% endblock %}

View File

@ -1,12 +1,11 @@
{% extends 'layout.html' %} {% extends 'layout.html' %}
{% load i18n %} {% load i18n %}{% load utilities %}
{% load bookwyrm_tags %}
{% block title %}{% blocktrans with book_title=work.title %}Editions of {{ book_title }}{% endblocktrans %}{% endblock %} {% block title %}{% blocktrans with book_title=work|book_title %}Editions of {{ book_title }}{% endblocktrans %}{% endblock %}
{% block content %} {% block content %}
<div class="block"> <div class="block">
<h1 class="title">{% blocktrans with work_path=work.local_path work_title=work.title %}Editions of <a href="{{ work_path }}">"{{ work_title }}"</a>{% endblocktrans %}</h1> <h1 class="title">{% blocktrans with work_path=work.local_path work_title=work|book_title %}Editions of <a href="{{ work_path }}">"{{ work_title }}"</a>{% endblocktrans %}</h1>
</div> </div>
{% include 'book/edition_filters.html' %} {% include 'book/edition_filters.html' %}
@ -23,7 +22,7 @@
<div class="column my-3-mobile ml-3-tablet mr-auto"> <div class="column my-3-mobile ml-3-tablet mr-auto">
<h2 class="title is-5 mb-1"> <h2 class="title is-5 mb-1">
<a href="{{ book.local_path }}" class="has-text-black"> <a href="{{ book.local_path }}" class="has-text-black">
{{ book.title }} {{ book|book_title }}
</a> </a>
</h2> </h2>
@ -51,7 +50,3 @@
{% include 'snippets/pagination.html' with page=editions path=request.path %} {% include 'snippets/pagination.html' with page=editions path=request.path %}
</div> </div>
{% endblock %} {% endblock %}
{% block scripts %}
{% include 'snippets/datepicker_js.html' %}
{% endblock %}

View File

@ -0,0 +1,22 @@
{% load i18n %}{% load status_display %}
<div class="block mr-5">
<div class="media">
<div class="media-left">
{% include 'snippets/avatar.html' with user=user %}
</div>
<div class="media-content">
<div>
<a href="{{ user.local_path }}">{{ user.display_name }}</a>
</div>
<div class="is-flex">
<p class="mr-1">{% trans "rated it" %}</p>
{% include 'snippets/stars.html' with rating=rating.rating %}
</div>
<div>
<a href="{{ rating.remote_id }}">{{ rating.published_date|published_date }}</a>
</div>
</div>
</div>
</div>

View File

@ -1,5 +1,5 @@
{% spaceless %} {% spaceless %}
{% load bookwyrm_tags %} {% load utilities %}
{% with 0|uuid as uuid %} {% with 0|uuid as uuid %}
<div <div

View File

@ -1,6 +1,6 @@
{% extends 'layout.html' %} {% extends 'layout.html' %}
{% load i18n %} {% load i18n %}
{% load bookwyrm_tags %} {% load utilities %}
{% block title %}{% trans "Compose status" %}{% endblock %} {% block title %}{% trans "Compose status" %}{% endblock %}
{% block content %} {% block content %}

View File

@ -49,7 +49,3 @@
</div> </div>
{% endblock %} {% endblock %}
{% block scripts %}
<script src="/static/js/localstorage.js"></script>
{% endblock %}

View File

@ -1,5 +1,6 @@
{% load i18n %} {% load i18n %}
{% load bookwyrm_tags %} {% load utilities %}
{% load markdown %}
{% load humanize %} {% load humanize %}
<div class="card is-stretchable"> <div class="card is-stretchable">

View File

@ -1,6 +1,6 @@
{% extends 'layout.html' %} {% extends 'layout.html' %}
{% load i18n %} {% load i18n %}
{% load bookwyrm_tags %} {% load markdown %}
{% block title %}{% trans "Welcome" %}{% endblock %} {% block title %}{% trans "Welcome" %}{% endblock %}

View File

@ -1,5 +1,5 @@
{% load bookwyrm_tags %} {% load bookwyrm_tags %}
{% load markdown %}
{% load i18n %} {% load i18n %}
{% if book %} {% if book %}

View File

@ -1,7 +1,6 @@
{% extends 'feed/feed_layout.html' %} {% extends 'feed/feed_layout.html' %}
{% load i18n %} {% load i18n %}
{% load bookwyrm_tags %}
{% load humanize %}
{% block panel %} {% block panel %}
<h1 class="title"> <h1 class="title">

View File

@ -1,6 +1,5 @@
{% extends 'layout.html' %} {% extends 'layout.html' %}
{% load i18n %} {% load i18n %}
{% load bookwyrm_tags %}
{% block title %}{% trans "Updates" %}{% endblock %} {% block title %}{% trans "Updates" %}{% endblock %}
@ -105,5 +104,4 @@
{% block scripts %} {% block scripts %}
<script src="/static/js/vendor/tabs.js"></script> <script src="/static/js/vendor/tabs.js"></script>
{% include 'snippets/datepicker_js.html' %}
{% endblock %} {% endblock %}

View File

@ -1,5 +1,5 @@
{% load i18n %} {% load i18n %}
{% load bookwyrm_tags %} {% load utilities %}
{% load humanize %} {% load humanize %}
<div class="columns is-mobile scroll-x mb-0"> <div class="columns is-mobile scroll-x mb-0">
{% for user in suggested_users %} {% for user in suggested_users %}

View File

@ -1,4 +1,4 @@
{% load bookwyrm_tags %} {% load status_display %}
<div class="block"> <div class="block">
{% with depth=depth|add:1 %} {% with depth=depth|add:1 %}

View File

@ -5,7 +5,7 @@
<div class="select is-small mt-1 mb-3"> <div class="select is-small mt-1 mb-3">
<select name="{{ book.id }}" aria-label="{% blocktrans with book_title=book.title %}Have you read {{ book_title }}?{% endblocktrans %}"> <select name="{{ book.id }}" aria-label="{% blocktrans with book_title=book.title %}Have you read {{ book_title }}?{% endblocktrans %}">
<option disabled selected value>Add to your books</option> <option disabled selected value>Add to your books</option>
{% for shelf in request.user.shelf_set.all %} {% for shelf in user_shelves %}
<option value="{{ shelf.id }}">{{ shelf.name }}</option> <option value="{{ shelf.id }}">{{ shelf.name }}</option>
{% endfor %} {% endfor %}
</select> </select>

View File

@ -64,7 +64,3 @@
</form> </form>
{% endblock %} {% endblock %}
{% block scripts %}
{% include 'snippets/datepicker_js.html' %}
{% endblock %}

View File

@ -9,7 +9,7 @@
{% if is_self and goal %} {% if is_self and goal %}
<div class="column is-narrow"> <div class="column is-narrow">
{% trans "Edit Goal" as button_text %} {% trans "Edit Goal" as button_text %}
{% include 'snippets/toggle/open_button.html' with text=button_text icon="pencil" controls_text="show-edit-goal" focus="edit-form-header" %} {% include 'snippets/toggle/open_button.html' with text=button_text icon_with_text="pencil" controls_text="show-edit-goal" focus="edit-form-header" %}
</div> </div>
{% endif %} {% endif %}
</div> </div>

View File

@ -20,6 +20,9 @@
<option value="GoodReads" {% if current == 'GoodReads' %}selected{% endif %}> <option value="GoodReads" {% if current == 'GoodReads' %}selected{% endif %}>
GoodReads (CSV) GoodReads (CSV)
</option> </option>
<option value="Storygraph" {% if current == 'Storygraph' %}selected{% endif %}>
Storygraph (CSV)
</option>
<option value="LibraryThing" {% if current == 'LibraryThing' %}selected{% endif %}> <option value="LibraryThing" {% if current == 'LibraryThing' %}selected{% endif %}>
LibraryThing (TSV) LibraryThing (TSV)
</option> </option>

View File

@ -1,6 +1,5 @@
{% extends 'layout.html' %} {% extends 'layout.html' %}
{% load i18n %} {% load i18n %}
{% load bookwyrm_tags %}
{% load humanize %} {% load humanize %}
{% block title %}{% trans "Import Status" %}{% endblock %} {% block title %}{% trans "Import Status" %}{% endblock %}
@ -54,8 +53,8 @@
<input class="checkbox" type="checkbox" name="import_item" value="{{ item.id }}" id="import-item-{{ item.id }}"> <input class="checkbox" type="checkbox" name="import_item" value="{{ item.id }}" id="import-item-{{ item.id }}">
<label for="import-item-{{ item.id }}"> <label for="import-item-{{ item.id }}">
Line {{ item.index }}: Line {{ item.index }}:
<strong>{{ item.data|dict_key:'Title' }}</strong> by <strong>{{ item.data.Title }}</strong> by
{{ item.data|dict_key:'Author' }} {{ item.data.Author }}
</label> </label>
<p> <p>
{{ item.fail_reason }}. {{ item.fail_reason }}.
@ -90,8 +89,8 @@
<li class="pb-1"> <li class="pb-1">
<p> <p>
Line {{ item.index }}: Line {{ item.index }}:
<strong>{{ item.data|dict_key:'Title' }}</strong> by <strong>{{ item.data.Title }}</strong> by
{{ item.data|dict_key:'Author' }} {{ item.data.Author }}
</p> </p>
<p> <p>
{{ item.fail_reason }}. {{ item.fail_reason }}.
@ -130,10 +129,10 @@
{% endif %} {% endif %}
</td> </td>
<td> <td>
{{ item.data|dict_key:'Title' }} {{ item.data.Title }}
</td> </td>
<td> <td>
{{ item.data|dict_key:'Author' }} {{ item.data.Author }}
</td> </td>
<td> <td>
{% if item.book %} {% if item.book %}

View File

@ -1,5 +1,4 @@
{% load bookwyrm_tags %} {% load layout %}{% load i18n %}
{% load i18n %}
<!DOCTYPE html> <!DOCTYPE html>
<html lang="{% get_lang %}"> <html lang="{% get_lang %}">
<head> <head>
@ -135,12 +134,14 @@
<span class="is-sr-only">{% trans "Notifications" %}</span> <span class="is-sr-only">{% trans "Notifications" %}</span>
</span> </span>
</span> </span>
{% with request.user.unread_notification_count as notification_count %}
<span <span
class="{% if not request.user.unread_notification_count %}is-hidden {% elif request.user.has_unread_mentions %}is-danger {% endif %}tag is-medium transition-x" class="{% if not notification_count %}is-hidden {% elif request.user.has_unread_mentions %}is-danger {% endif %}tag is-medium transition-x"
data-poll-wrapper data-poll-wrapper
> >
<span data-poll="notifications">{{ request.user.unread_notification_count }}</span> <span data-poll="notifications">{{ notification_count }}</span>
</span> </span>
{% endwith %}
</a> </a>
</div> </div>
{% else %} {% else %}
@ -182,11 +183,23 @@
</div> </div>
</nav> </nav>
{% if request.user.is_authenticated and active_announcements.exists %}
<div class="block is-flex-grow-1">
<div class="container">
{% for announcement in active_announcements %}
{% include 'snippets/announcement.html' with announcement=announcement %}
{% endfor %}
</div>
</div>
{% endif %}
<div class="section is-flex-grow-1"> <div class="section is-flex-grow-1">
<div class="container"> <div class="container">
{# almost every view needs to know the user shelves #}
{% with request.user.shelf_set.all as user_shelves %}
{% block content %} {% block content %}
{% endblock %} {% endblock %}
{% endwith %}
</div> </div>
</div> </div>
@ -214,7 +227,7 @@
</p> </p>
{% endif %} {% endif %}
<p> <p>
{% trans 'BookWyrm is open source software. You can contribute or report issues on <a href="https://github.com/mouse-reeve/bookwyrm">GitHub</a>.' %} {% blocktrans %}BookWyrm's source code is freely available. You can contribute or report issues on <a href="https://github.com/mouse-reeve/bookwyrm">GitHub</a>.{% endblocktrans %}
</p> </p>
</div> </div>
{% if site.footer_item %} {% if site.footer_item %}
@ -230,6 +243,7 @@
var csrf_token = '{{ csrf_token }}'; var csrf_token = '{{ csrf_token }}';
</script> </script>
<script src="/static/js/bookwyrm.js"></script> <script src="/static/js/bookwyrm.js"></script>
<script src="/static/js/localstorage.js"></script>
{% block scripts %}{% endblock %} {% block scripts %}{% endblock %}
</body> </body>
</html> </html>

View File

@ -1,6 +1,7 @@
{% extends 'lists/list_layout.html' %} {% extends 'lists/list_layout.html' %}
{% load i18n %} {% load i18n %}
{% load bookwyrm_tags %} {% load bookwyrm_tags %}
{% load markdown %}
{% block panel %} {% block panel %}
{% if request.user == list.user and pending_count %} {% if request.user == list.user and pending_count %}
@ -50,9 +51,9 @@
<p> <p>
{% include 'snippets/stars.html' with rating=item.book|rating:request.user %} {% include 'snippets/stars.html' with rating=item.book|rating:request.user %}
</p> </p>
<p> <div>
{{ book|book_description|to_markdown|default:""|safe|truncatewords_html:20 }} {{ book|book_description|to_markdown|default:""|safe|truncatewords_html:20 }}
</p> </div>
{% include 'snippets/shelve_button/shelve_button.html' %} {% include 'snippets/shelve_button/shelve_button.html' %}
</div> </div>
</div> </div>

View File

@ -1,4 +1,4 @@
{% load bookwyrm_tags %} {% load markdown %}
<div class="columns is-multiline"> <div class="columns is-multiline">
{% for list in lists %} {% for list in lists %}
<div class="column is-one-quarter"> <div class="column is-one-quarter">
@ -22,7 +22,7 @@
{% endwith %} {% endwith %}
<div class="card-content is-flex-grow-0"> <div class="card-content is-flex-grow-0">
<div {% if list.description %}title="{{ list.description }}"{% endif %}> <div class="is-clipped" {% if list.description %}title="{{ list.description }}"{% endif %}>
{% if list.description %} {% if list.description %}
{{ list.description|to_markdown|safe|truncatechars_html:30 }} {{ list.description|to_markdown|safe|truncatechars_html:30 }}
{% else %} {% else %}

View File

@ -1,6 +1,5 @@
{% extends 'layout.html' %} {% extends 'layout.html' %}
{% load i18n %} {% load i18n %}
{% load bookwyrm_tags %}
{% block title %}{{ list.name }}{% endblock %} {% block title %}{{ list.name }}{% endblock %}
@ -16,7 +15,7 @@
{% if request.user == list.user %} {% if request.user == list.user %}
<div class="column is-narrow"> <div class="column is-narrow">
{% trans "Edit List" as button_text %} {% trans "Edit List" as button_text %}
{% include 'snippets/toggle/open_button.html' with text=button_text icon="pencil" controls_text="edit-list" focus="edit-list-header" %} {% include 'snippets/toggle/open_button.html' with text=button_text icon_with_text="pencil" controls_text="edit-list" focus="edit-list-header" %}
</div> </div>
{% endif %} {% endif %}
</header> </header>

View File

@ -1,5 +1,5 @@
{% extends 'layout.html' %} {% extends 'layout.html' %}
{% load bookwyrm_tags %} {% load utilities %}
{% load i18n %} {% load i18n %}
{% block title %}{% trans "Lists" %}{% endblock %} {% block title %}{% trans "Lists" %}{% endblock %}
@ -18,7 +18,7 @@
{% if request.user.is_authenticated %} {% if request.user.is_authenticated %}
<div class="column is-narrow"> <div class="column is-narrow">
{% trans "Create List" as button_text %} {% trans "Create List" as button_text %}
{% include 'snippets/toggle/open_button.html' with controls_text="create-list" icon="plus" text=button_text focus="create-list-header" %} {% include 'snippets/toggle/open_button.html' with controls_text="create-list" icon_with_text="plus" text=button_text focus="create-list-header" %}
</div> </div>
{% endif %} {% endif %}
</header> </header>

View File

@ -38,6 +38,9 @@
</div> </div>
</form> </form>
</div> </div>
</div>
<div class="column">
<div class="box has-background-primary-light"> <div class="box has-background-primary-light">
{% if site.allow_registration %} {% if site.allow_registration %}
<h2 class="title">{% trans "Create an Account" %}</h2> <h2 class="title">{% trans "Create an Account" %}</h2>
@ -50,9 +53,10 @@
{% endif %} {% endif %}
</div> </div>
</div> </div>
</div>
<div class="column">
<div class="block"> <div class="block">
<div class="box">
{% include 'snippets/about.html' %} {% include 'snippets/about.html' %}
<p class="block"> <p class="block">
@ -60,5 +64,4 @@
</p> </p>
</div> </div>
</div> </div>
</div>
{% endblock %} {% endblock %}

View File

@ -1,6 +1,5 @@
{% extends 'settings/admin_layout.html' %} {% extends 'settings/admin_layout.html' %}
{% load i18n %} {% load i18n %}
{% load bookwyrm_tags %}
{% load humanize %} {% load humanize %}
{% block title %}{% blocktrans with report_id=report.id username=report.user.username %}Report #{{ report_id }}: {{ username }}{% endblocktrans %}{% endblock %} {% block title %}{% blocktrans with report_id=report.id username=report.user.username %}Report #{{ report_id }}: {{ username }}{% endblocktrans %}{% endblock %}

View File

@ -1,18 +1,35 @@
{% extends 'layout.html' %} {% extends 'layout.html' %}
{% load i18n %} {% load i18n %}
{% load humanize %}
{% load bookwyrm_tags %} {% load bookwyrm_tags %}
{% load humanize %}
{% block title %}{% trans "Notifications" %}{% endblock %} {% block title %}{% trans "Notifications" %}{% endblock %}
{% block content %} {% block content %}
<div class="block"> <header class="columns">
<div class="column">
<h1 class="title">{% trans "Notifications" %}</h1> <h1 class="title">{% trans "Notifications" %}</h1>
</div>
<form name="clear" action="/notifications" method="POST"> <form name="clear" action="/notifications" method="POST" class="column is-narrow">
{% csrf_token %} {% csrf_token %}
<button class="button is-danger is-light" type="submit" class="secondary">{% trans "Delete notifications" %}</button> <button class="button is-danger is-light" type="submit" class="secondary">{% trans "Delete notifications" %}</button>
</form> </form>
</header>
<div class="block">
<nav class="tabs">
<ul>
{% url 'notifications' as tab_url %}
<li {% if tab_url == request.path %}class="is-active"{% endif %}>
<a href="{{ tab_url }}">{% trans "All" %}</a>
</li>
{% url 'notifications' 'mentions' as tab_url %}
<li {% if tab_url == request.path %}class="is-active"{% endif %}>
<a href="{{ tab_url }}">{% trans "Mentions" %}</a>
</li>
</ul>
</nav>
</div> </div>
<div class="block"> <div class="block">

View File

@ -18,7 +18,7 @@
<a href="{{ user.local_path }}">{% include 'snippets/avatar.html' with user=user %} {{ user.display_name }}</a> <a href="{{ user.local_path }}">{% include 'snippets/avatar.html' with user=user %} {{ user.display_name }}</a>
</p> </p>
<p class="mr-2"> <p class="mr-2">
{% include 'snippets/block_button.html' with user=user %} {% include 'snippets/block_button.html' with user=user blocks=True %}
</p> </p>
</li> </li>
{% endfor %} {% endfor %}

View File

@ -7,7 +7,7 @@
{% with results|first as local_results %} {% with results|first as local_results %}
<ul class="block"> <ul class="block">
{% for result in local_results.results %} {% for result in local_results.results %}
<li class="pd-4"> <li class="pd-4 mb-5">
{% include 'snippets/search_result_text.html' with result=result %} {% include 'snippets/search_result_text.html' with result=result %}
</li> </li>
{% endfor %} {% endfor %}
@ -27,8 +27,10 @@
</h3> </h3>
</div> </div>
<div class="column is-narrow"> <div class="column is-narrow">
{% trans "Show" as button_text %} {% trans "Open" as button_text %}
{% include 'snippets/toggle/open_button.html' with text=button_text small=True controls_text="more-results-panel" controls_uid=result_set.connector.identifier class="is-small" icon="arrow-down" pressed=forloop.first %} {% include 'snippets/toggle/open_button.html' with text=button_text controls_text="more-results-panel" controls_uid=result_set.connector.identifier class="is-small" icon_with_text="arrow-down" pressed=forloop.first %}
{% trans "Close" as button_text %}
{% include 'snippets/toggle/close_button.html' with text=button_text controls_text="more-results-panel" controls_uid=result_set.connector.identifier class="is-small" icon_with_text="arrow-up" pressed=forloop.first %}
</div> </div>
</header> </header>
{% endif %} {% endif %}
@ -36,8 +38,6 @@
<div class="box has-background-white is-shadowless{% if not forloop.first %} is-hidden{% endif %}" id="more-results-panel-{{ result_set.connector.identifier }}"> <div class="box has-background-white is-shadowless{% if not forloop.first %} is-hidden{% endif %}" id="more-results-panel-{{ result_set.connector.identifier }}">
<div class="is-flex is-flex-direction-row-reverse"> <div class="is-flex is-flex-direction-row-reverse">
<div> <div>
{% trans "Close" as button_text %}
{% include 'snippets/toggle/toggle_button.html' with label=button_text class="delete" nonbutton=True controls_text="more-results-panel" controls_uid=result_set.connector.identifier pressed=forloop.first %}
</div> </div>
<ul class="is-flex-grow-1"> <ul class="is-flex-grow-1">

View File

@ -1,5 +1,4 @@
{% extends 'search/layout.html' %} {% extends 'search/layout.html' %}
{% load bookwyrm_tags %}
{% block panel %} {% block panel %}

View File

@ -43,6 +43,10 @@
{% if perms.bookwyrm.edit_instance_settings %} {% if perms.bookwyrm.edit_instance_settings %}
<h2 class="menu-label">{% trans "Instance Settings" %}</h2> <h2 class="menu-label">{% trans "Instance Settings" %}</h2>
<ul class="menu-list"> <ul class="menu-list">
<li>
{% url 'settings-announcements' as url %}
<a href="{{ url }}"{% if url in request.path %} class="is-active" aria-selected="true"{% endif %}>{% trans "Announcements" %}</a>
</li>
<li> <li>
{% url 'settings-site' as url %} {% url 'settings-site' as url %}
<a href="{{ url }}"{% if url in request.path %} class="is-active" aria-selected="true"{% endif %}>{% trans "Site Settings" %}</a> <a href="{{ url }}"{% if url in request.path %} class="is-active" aria-selected="true"{% endif %}>{% trans "Site Settings" %}</a>

View File

@ -0,0 +1,70 @@
{% extends 'settings/admin_layout.html' %}
{% load i18n %}{% load humanize %}
{% block title %}{% trans "Announcement" %} - {{ announcement.preview }}{% endblock %}
{% block header %}
{% trans "Announcement" %}
<a href="{% url 'settings-announcements' %}" class="has-text-weight-normal help">{% trans "Back to list" %}</a>
{% endblock %}
{% block edit-button %}
{% trans "Edit Announcement" as button_text %}
<div class="field has-addons">
<div class="control">
{% include 'snippets/toggle/open_button.html' with controls_text="edit-announcement" icon_with_text="pencil" text=button_text focus="edit-announcement-header" %}
</div>
<form class="control" action="{% url 'settings-announcements-delete' announcement.id %}" method="post">
{% csrf_token %}
<button type="submit" class="button is-danger">
<span class="icon icon-x m-0-mobile" aria-hidden="true"></span>
<span class="is-sr-only-mobile">{% trans "Delete" %}</span>
</button>
</form>
</div>
{% endblock %}
{% block panel %}
<form name="edit-announcement" method="post" action="{% url 'settings-announcements' announcement.id %}" class="block">
{% include 'settings/announcement_form.html' with controls_text="edit-announcement" %}
</form>
<div class="block content">
<dl>
<div class="is-flex notification pt-1 pb-1 mb-0 {% if announcement in active_announcements %}is-success{% else %}is-danger{% endif %}">
<dt class="mr-1 has-text-weight-bold">{% trans "Visible:" %}</dt>
<dd>
{% if announcement in active_announcements %}
{% trans "True" %}
{% else %}
{% trans "False" %}
{% endif %}
</dd>
</div>
{% if announcement.start_date %}
<div class="is-flex notificationi pt-1 pb-1 mb-0 has-background-white">
<dt class="mr-1 has-text-weight-bold">{% trans "Start date:" %}</dt>
<dd>{{ announcement.start_date|naturalday }}</dd>
</div>
{% endif %}
{% if announcement.end_date %}
<div class="is-flex notification pt-1 pb-1 mb-0 has-background-white">
<dt class="mr-1 has-text-weight-bold">{% trans "End date:" %}</dt>
<dd>{{ announcement.end_date|naturalday }}</dd>
</div>
{% endif %}
<div class="is-flex notification pt-1 pb-1 has-background-white">
<dt class="mr-1 has-text-weight-bold">{% trans "Active:" %}</dt>
<dd>{{ announcement.active }}</dd>
</div>
</dl>
<hr aria-hidden="true">
{% include 'snippets/announcement.html' with announcement=announcement pressed=True admin_mode=True %}
</div>
{% endblock %}

View File

@ -0,0 +1,72 @@
{% extends 'components/inline_form.html' %}
{% load i18n %}
{% block header %}
{% if announcement %}
{% trans "Edit Announcement" %}
{% else %}
{% trans "Create Announcement" %}
{% endif %}
{% endblock %}
{% block form %}
{% csrf_token %}
<input type="hidden" name="user" value="{{ request.user.id }}">
<p>
<label class="label" for="id_preview">Preview:</label>
{{ form.preview }}
{% for error in form.preview.errors %}
<p class="help is-danger">{{ error | escape }}</p>
{% endfor %}
</p>
<p>
<label class="label" for="id_content">Content:</label>
{{ form.content }}
{% for error in form.content.errors %}
<p class="help is-danger">{{ error | escape }}</p>
{% endfor %}
</p>
<p>
<label class="label" for="id_event_date">Event date:</label>
<input type="date" name="event_date" value="{{ form.event_date.value|date:'Y-m-d' }}" class="input" id="id_event_date">
{% for error in form.event_date.errors %}
<p class="help is-danger">{{ error | escape }}</p>
{% endfor %}
</p>
<hr aria-hidden="true">
<div class="columns">
<div class="column">
<p>
<label class="label" for="id_start_date">Start date:</label>
<input type="date" name="start_date" class="input" value="{{ form.start_date.value|date:'Y-m-d' }}" id="id_start_date">
{% for error in form.start_date.errors %}
<p class="help is-danger">{{ error | escape }}</p>
{% endfor %}
</p>
</div>
<div class="column">
<p>
<label class="label" for="id_end_date">End date:</label>
<input type="date" name="end_date" class="input" id="id_end_date" value="{{ form.end_date.value|date:'Y-m-d' }}">
{% for error in form.end_date.errors %}
<p class="help is-danger">{{ error | escape }}</p>
{% endfor %}
</p>
</div>
<div class="column is-narrow">
<p>
<label class="label" for="id_active">Active:</label>
{{ form.active }}
{% for error in form.active.errors %}
<p class="help is-danger">{{ error | escape }}</p>
{% endfor %}
</p>
</div>
</div>
<div class="field has-addons">
<div class="control">
<button type="submit" class="button is-primary">{% trans "Save" %}</button>
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,54 @@
{% extends 'settings/admin_layout.html' %}
{% load i18n %}{% load humanize %}
{% block title %}{% trans "Announcements" %}{% endblock %}
{% block header %}{% trans "Announcements" %}{% endblock %}
{% block edit-button %}
{% trans "Create Announcement" as button_text %}
{% include 'snippets/toggle/open_button.html' with controls_text="create-announcement" icon_with_text="plus" text=button_text focus="create-announcement-header" %}
</a>
{% endblock %}
{% block panel %}
<form name="create-announcement" method="post" action="{% url 'settings-announcements' %}" class="block">
{% include 'settings/announcement_form.html' with controls_text="create-announcement" %}
</form>
<table class="table is-striped">
<tr>
<th>
{% url 'settings-announcements' as url %}
{% trans "Date added" as text %}
{% include 'snippets/table-sort-header.html' with field="created_date" sort=sort text=text %}
</th>
<th>
{% trans "Preview" as text %}
{% include 'snippets/table-sort-header.html' with field="preview" sort=sort text=text %}
</th>
<th>
{% trans "Start date" as text %}
{% include 'snippets/table-sort-header.html' with field="start_date" sort=sort text=text %}
</th>
<th>
{% trans "End date" as text %}
{% include 'snippets/table-sort-header.html' with field="end_date" sort=sort text=text %}
</th>
<th>
{% trans "Status" as text %}
{% include 'snippets/table-sort-header.html' with field="active" sort=sort text=text %}
</th>
</tr>
{% for announcement in announcements %}
<tr>
<td>{{ announcement.created_date|naturalday }}</td>
<td><a href="{% url 'settings-announcements' announcement.id %}">{{ announcement.preview }}</a></td>
<td>{{ announcement.start_date|naturaltime|default:'' }}</td>
<td>{{ announcement.end_date|naturaltime|default:'' }}</td>
<td>{% if announcement.active %}{% trans "active" %}{% else %}{% trans "inactive" %}{% endif %}</td>
</tr>
{% endfor %}
</table>
{% include 'snippets/pagination.html' with page=announcements path=request.path %}
{% endblock %}

View File

@ -1,7 +1,8 @@
{% extends 'settings/admin_layout.html' %} {% extends 'settings/admin_layout.html' %}
{% block title %}{{ server.server_name }}{% endblock %}
{% load i18n %} {% load i18n %}
{% load bookwyrm_tags %} {% load markdown %}
{% block title %}{{ server.server_name }}{% endblock %}
{% block header %} {% block header %}
{{ server.server_name }} {{ server.server_name }}
@ -9,13 +10,14 @@
{% if server.status == "blocked" %}<span class="icon icon-x has-text-danger is-size-5" title="{% trans 'Blocked' %}"><span class="is-sr-only">{% trans "Blocked" %}</span></span> {% if server.status == "blocked" %}<span class="icon icon-x has-text-danger is-size-5" title="{% trans 'Blocked' %}"><span class="is-sr-only">{% trans "Blocked" %}</span></span>
{% endif %} {% endif %}
<a href="{% url 'settings-federation' %}" class="has-text-weight-normal help">{% trans "Back to server list" %}</a> <a href="{% url 'settings-federation' %}" class="has-text-weight-normal help">{% trans "Back to list" %}</a>
{% endblock %} {% endblock %}
{% block panel %} {% block panel %}
<div class="columns"> <div class="columns">
<section class="column is-half content"> <section class="column is-half is-flex is-flex-direction-column">
<h2 class="title is-4">{% trans "Details" %}</h2> <h2 class="title is-4">{% trans "Details" %}</h2>
<div class="box is-flex-grow-1 content">
<dl> <dl>
<div class="is-flex"> <div class="is-flex">
<dt>{% trans "Software:" %}</dt> <dt>{% trans "Software:" %}</dt>
@ -30,10 +32,12 @@
<dd>{{ server.status }}</dd> <dd>{{ server.status }}</dd>
</div> </div>
</dl> </dl>
</div>
</section> </section>
<section class="column is-half content"> <section class="column is-half is-flex is-flex-direction-column">
<h2 class="title is-4">{% trans "Activity" %}</h2> <h2 class="title is-4">{% trans "Activity" %}</h2>
<div class="box is-flex-grow-1 content">
<dl> <dl>
<div class="is-flex"> <div class="is-flex">
<dt>{% trans "Users:" %}</dt> <dt>{% trans "Users:" %}</dt>
@ -68,6 +72,7 @@
</dd> </dd>
</div> </div>
</dl> </dl>
</div>
</section> </section>
</div> </div>
@ -78,11 +83,11 @@
</div> </div>
<div class="column is-narrow"> <div class="column is-narrow">
{% trans "Edit" as button_text %} {% trans "Edit" as button_text %}
{% include 'snippets/toggle/open_button.html' with text=button_text icon="pencil" controls_text="edit-notes" %} {% include 'snippets/toggle/open_button.html' with text=button_text icon_with_text="pencil" controls_text="edit-notes" %}
</div> </div>
</header> </header>
{% if server.notes %} {% if server.notes %}
<p id="hide-edit-notes">{{ server.notes|to_markdown|safe }}</p> <div class="box" id="hide-edit-notes">{{ server.notes|to_markdown|safe }}</div>
{% endif %} {% endif %}
<form class="box is-hidden" method="POST" action="{% url 'settings-federated-server' server.id %}" id="edit-notes"> <form class="box is-hidden" method="POST" action="{% url 'settings-federated-server' server.id %}" id="edit-notes">
{% csrf_token %} {% csrf_token %}

View File

@ -6,9 +6,8 @@
{% block edit-button %} {% block edit-button %}
<a href="{% url 'settings-import-blocklist' %}"> <a href="{% url 'settings-import-blocklist' %}">
<span class="icon icon-plus" title="{% trans 'Add server' %}"> <span class="icon icon-plus" title="{% trans 'Add server' %}" aria-hidden="True"></span>
<span class="is-sr-only">{% trans "Add server" %}</span> <span>{% trans "Add server" %}</span>
</span>
</a> </a>
{% endblock %} {% endblock %}

View File

@ -0,0 +1,38 @@
{% load humanize %}{% load i18n %}{% load utilities %}
{% with announcement.id|uuid as uuid %}
<aside
class="notification mb-1 p-3{% if not admin_mode %} is-hidden{% endif %} transition-y"
{% if not admin_mode %}data-hide="hide-announcement-{{ announcement.id }}"{% endif %}
>
<div class="columns mb-0 is-mobile">
<div class="column pb-0">
{% if announcement.event_date %}
<strong>{{ announcement.event_date|naturalday|title }}:</strong>
{% endif %}
{{ announcement.preview }}
</div>
{% if announcement.content %}
<div class="column is-narrow pb-0">
{% trans "Open" as button_text %}
{% include 'snippets/toggle/open_button.html' with text=button_text controls_text="announcement" class="is-small" controls_uid=uuid icon_with_text="arrow-down" %}
{% trans "Close" as button_text %}
{% include 'snippets/toggle/close_button.html' with text=button_text controls_text="announcement" class="is-small" controls_uid=uuid icon_with_text="arrow-up" %}
</div>
{% endif %}
</div>
{% if announcement.content %}
<div class="mb-2 mt-2 {% if not pressed %}is-hidden{% endif %}" id="announcement-{{ uuid }}">
<div class="box is-shadowless mb-0">
{{ announcement.content|safe }}
</div>
</div>
{% endif %}
<div class="is-flex mt-0 help">
<p>{% blocktrans with user_path=announcement.user.local_path username=announcement.user.display_name %}Posted by <a href="{{ user_path }}">{{ username }}</a>{% endblocktrans %}</p>
{% if not admin_mode %}
<span class="mr-2 ml-2" aria-hidden="true">&middot;</span>
<a class="set-display" data-id="hide-announcement-{{ announcement.id }}" data-value="true">{% trans "Dismiss message" %}</a>
{% endif %}
</div>
</aside>
{% endwith %}

View File

@ -1,3 +1,2 @@
{% load bookwyrm_tags %}
<img class="avatar image {% if large %}is-96x96{% elif medium %}is-48x48{% else %}is-32x32{% endif %}" src="{% if user.avatar %}/images/{{ user.avatar }}{% else %}/static/images/default_avi.jpg{% endif %}" {% if ariaHide %}aria-hidden="true"{% endif %} alt="{{ user.alt_text }}"> <img class="avatar image {% if large %}is-96x96{% elif medium %}is-48x48{% else %}is-32x32{% endif %}" src="{% if user.avatar %}/images/{{ user.avatar }}{% else %}/static/images/default_avi.jpg{% endif %}" {% if ariaHide %}aria-hidden="true"{% endif %} alt="{{ user.alt_text }}">

View File

@ -1,5 +1,5 @@
{% load i18n %} {% load i18n %}
{% if not user in request.user.blocks.all %} {% if not blocks %}
<form name="blocks" method="post" action="/block/{{ user.id }}"> <form name="blocks" method="post" action="/block/{{ user.id }}">
{% csrf_token %} {% csrf_token %}
<button class="button is-danger is-light is-small {{ class }}" type="submit">{% trans "Block" %}</button> <button class="button is-danger is-light is-small {{ class }}" type="submit">{% trans "Block" %}</button>

View File

@ -1,6 +1,5 @@
{% spaceless %} {% spaceless %}
{% load bookwyrm_tags %}
{% load i18n %} {% load i18n %}
<figure <figure

View File

@ -1,16 +0,0 @@
<div class="columns is-mobile is-multiline">
{% for book in books %}
<div class="column is-narrow">
<div class="box is-flex is-flex-direction-column is-align-items-center">
<div class="mb-3">
<a href="{{ book.local_path }}">
{% include 'snippets/book_cover.html' with book=book cover_class='is-w-l-mobile is-h-l-mobile is-w-l-tablet is-h-xl-tablet' %}
</a>
</div>
{% include 'snippets/shelve_button/shelve_button.html' with book=book switch_mode=True %}
</div>
</div>
{% endfor %}
</div>

View File

@ -1,8 +1,8 @@
{% load i18n %} {% load i18n %}
{% load bookwyrm_tags %} {% load utilities %}
{% if book.authors %} {% if book.authors %}
{% blocktrans with path=book.local_path title=book|title %}<a href="{{ path }}">{{ title }}</a> by {% endblocktrans %}{% include 'snippets/authors.html' with book=book %} {% blocktrans with path=book.local_path title=book|book_title %}<a href="{{ path }}">{{ title }}</a> by {% endblocktrans %}{% include 'snippets/authors.html' with book=book %}
{% else %} {% else %}
<a href="{{ book.local_path }}">{{ book|title }}</a> <a href="{{ book.local_path }}">{{ book|book_title }}</a>
{% endif %} {% endif %}

View File

@ -1,15 +1,33 @@
{% load bookwyrm_tags %} {% load interaction %}
{% load utilities %}
{% load i18n %} {% load i18n %}
{% 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 }}"> {% with request.user|boosted:status as boosted %}
<form
name="boost"
action="/boost/{{ status.id }}"
method="post"
class="interaction boost-{{ status.id }}-{{ uuid }} {% if boosted %}is-hidden{% endif %}"
data-id="boost-{{ status.id }}-{{ uuid }}"
>
{% csrf_token %} {% csrf_token %}
<button class="button is-small is-light is-transparent" 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 m-0-mobile" title="{% trans 'Boost' %}"></span> <span class="icon icon-boost m-0-mobile" title="{% trans 'Boost' %}"></span>
<span class="is-sr-only-mobile">{% trans "Boost" %}</span> <span class="is-sr-only-mobile">{% trans "Boost" %}</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 boosted %}is-hidden{% endif %}"
data-id="boost-{{ status.id }}-{{ uuid }}"
>
{% csrf_token %} {% csrf_token %}
<button class="button is-small is-light is-transparent" type="submit"> <button class="button is-small is-light is-transparent" type="submit">
<span class="icon icon-boost has-text-primary m-0-mobile" title="{% trans 'Un-boost' %}"></span> <span class="icon icon-boost has-text-primary m-0-mobile" title="{% trans 'Un-boost' %}"></span>
@ -17,3 +35,4 @@
</button> </button>
</form> </form>
{% endwith %} {% endwith %}
{% endwith %}

View File

@ -1,6 +1,6 @@
{% load humanize %} {% load humanize %}
{% load i18n %} {% load i18n %}
{% load bookwyrm_tags %} {% load utilities %}
{% with status_type=request.GET.status_type %} {% with status_type=request.GET.status_type %}
<div class="tab-group"> <div class="tab-group">

View File

@ -1,4 +1,7 @@
{% load bookwyrm_tags %} {% load bookwyrm_tags %}
{% load utilities %}
{% load status_display %}
{% load i18n %} {% load i18n %}
<form class="is-flex-grow-1" name="{{ type }}" action="/post/{% if type == 'direct' %}status{% else %}{{ type }}{% endif %}" method="post" id="tab-{{ type }}-{{ book.id }}{{ reply_parent.id }}"> <form class="is-flex-grow-1" name="{{ type }}" action="/post/{% if type == 'direct' %}status{% else %}{{ type }}{% endif %}" method="post" id="tab-{{ type }}-{{ book.id }}{{ reply_parent.id }}">
{% csrf_token %} {% csrf_token %}

View File

@ -1,3 +0,0 @@
<script type="module" src="https://cdn.jsdelivr.net/npm/@duetds/date-picker@1.3.0/dist/duet/duet.esm.js"></script>
<script nomodule src="https://cdn.jsdelivr.net/npm/@duetds/date-picker@1.3.0/dist/duet/duet.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@duetds/date-picker@1.3.0/dist/duet/themes/default.css" />

View File

@ -1,7 +1,10 @@
{% load bookwyrm_tags %} {% load interaction %}
{% load utilities %}
{% load i18n %} {% load i18n %}
{% 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 }}"> {% with request.user|liked:status as liked %}
<form name="favorite" action="/favorite/{{ status.id }}" method="POST" class="interaction fav-{{ status.id }}-{{ uuid }} {% if liked %}is-hidden{% endif %}" data-id="fav-{{ status.id }}-{{ uuid }}">
{% csrf_token %} {% csrf_token %}
<button class="button is-small is-light is-transparent" type="submit"> <button class="button is-small is-light is-transparent" type="submit">
<span class="icon icon-heart m-0-mobile" title="{% trans 'Like' %}"> <span class="icon icon-heart m-0-mobile" title="{% trans 'Like' %}">
@ -9,7 +12,7 @@
<span class="is-sr-only-mobile">{% trans "Like" %}</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 liked %}is-hidden{% endif %}" data-id="fav-{{ status.id }}-{{ uuid }}">
{% csrf_token %} {% csrf_token %}
<button class="button is-light is-transparent is-small" type="submit"> <button class="button is-light is-transparent is-small" type="submit">
<span class="icon icon-heart has-text-primary m-0-mobile" title="{% trans 'Un-like' %}"></span> <span class="icon icon-heart has-text-primary m-0-mobile" title="{% trans 'Un-like' %}"></span>
@ -17,3 +20,4 @@
</button> </button>
</form> </form>
{% endwith %} {% endwith %}
{% endwith %}

View File

@ -5,9 +5,9 @@
<span class="column is-narrow pb-0"> <span class="column is-narrow pb-0">
{% trans "Show filters" as text %} {% trans "Show filters" as text %}
{% include 'snippets/toggle/open_button.html' with text=text controls_text="filters" icon="arrow-down" class="is-small" focus="filters" %} {% include 'snippets/toggle/open_button.html' with text=text controls_text="filters" icon_with_text="arrow-down" class="is-small" focus="filters" %}
{% trans "Hide filters" as text %} {% trans "Hide filters" as text %}
{% include 'snippets/toggle/close_button.html' with text=text controls_text="filters" icon="x" class="is-small" %} {% include 'snippets/toggle/close_button.html' with text=text controls_text="filters" icon_with_text="arrow-up" class="is-small" %}
</span> </span>
</h2> </h2>

View File

@ -1,7 +1,7 @@
{% load i18n %} {% load i18n %}
{% if request.user == user or not request.user.is_authenticated %} {% if request.user == user or not request.user.is_authenticated %}
{% elif user in request.user.blocks.all %} {% elif user in request.user.blocks.all %}
{% include 'snippets/block_button.html' %} {% include 'snippets/block_button.html' with blocks=True %}
{% else %} {% else %}
<div class="field{% if not minimal %} has-addons{% else %} mb-0{% endif %}"> <div class="field{% if not minimal %} has-addons{% else %} mb-0{% endif %}">

View File

@ -1,6 +1,5 @@
{% load i18n %} {% load i18n %}
{% load bookwyrm_tags %} {% if request.user in user.follow_requests.all %}
{% if request.user|follow_request_exists:user %}
<div class="field is-grouped"> <div class="field is-grouped">
<form action="/accept-follow-request/" method="POST"> <form action="/accept-follow-request/" method="POST">
{% csrf_token %} {% csrf_token %}

View File

@ -1,6 +1,5 @@
{% spaceless %} {% spaceless %}
{% load i18n %} {% load i18n %}
{% load bookwyrm_tags %}
<div class=" <div class="
field is-grouped field is-grouped

View File

@ -1,16 +1,19 @@
{% load i18n %} {% load i18n %}
{% load humanize %} {% load humanize %}
{% with goal.progress as progress %}
<p> <p>
{% if goal.progress_percent >= 100 %} {% if progress.percent >= 100 %}
{% trans "Success!" %} {% trans "Success!" %}
{% elif goal.progress_percent %} {% elif progress.percent %}
{% blocktrans with percent=goal.progress_percent %}{{ percent }}% complete!{% endblocktrans %} {% blocktrans with percent=progress.percent %}{{ percent }}% complete!{% endblocktrans %}
{% endif %} {% endif %}
{% if goal.user == request.user %} {% if goal.user == request.user %}
{% blocktrans with read_count=goal.book_count|intcomma goal_count=goal.goal|intcomma path=goal.local_path %}You've read <a href="{{ path }}">{{ read_count }} of {{ goal_count}} books</a>.{% endblocktrans %} {% blocktrans with read_count=progress.count|intcomma goal_count=goal.goal|intcomma path=goal.local_path %}You've read <a href="{{ path }}">{{ read_count }} of {{ goal_count}} books</a>.{% endblocktrans %}
{% else %} {% else %}
{% blocktrans with username=goal.user.display_name read_count=goal.book_count|intcomma goal_count=goal.goal|intcomma path=goal.local_path %}{{ username }} has read <a href="{{ path }}">{{ read_count }} of {{ goal_count}} books</a>.{% endblocktrans %} {% blocktrans with username=goal.user.display_name read_count=progress.count|intcomma goal_count=goal.goal|intcomma path=goal.local_path %}{{ username }} has read <a href="{{ path }}">{{ read_count }} of {{ goal_count}} books</a>.{% endblocktrans %}
{% endif %} {% endif %}
</p> </p>
<progress class="progress is-large" value="{{ goal.book_count }}" max="{{ goal.goal }}" aria-hidden="true">{{ goal.progress_percent }}%</progress> <progress class="progress is-large" value="{{ progress.count }}" max="{{ goal.goal }}" aria-hidden="true">{{ progress.percent }}%</progress>
{% endwith %}

View File

@ -1,5 +1,5 @@
{% load i18n %} {% load i18n %}
{% load bookwyrm_tags %} {% load utilities %}
<div class="select {{ class }}"> <div class="select {{ class }}">
{% with 0|uuid as uuid %} {% with 0|uuid as uuid %}
{% if not no_label %} {% if not no_label %}

View File

@ -3,13 +3,9 @@
<input type="hidden" name="id" value="{{ readthrough.id }}"> <input type="hidden" name="id" value="{{ readthrough.id }}">
<input type="hidden" name="book" value="{{ book.id }}"> <input type="hidden" name="book" value="{{ book.id }}">
<div class="field"> <div class="field">
<label class="label"> <label class="label" tabindex="0" id="add-readthrough-focus">
{% trans "Started reading" %} {% trans "Started reading" %}
<duet-date-picker <input type="date" name="start_date" class="input" id="id_start_date-{{ readthrough.id }}" value="{{ readthrough.start_date | date:"Y-m-d" }}">
identifier="id_start_date-{{ readthrough.id }}"
name="start_date"
value="{{ readthrough.start_date | date:'Y-m-d' }}">
</duet-date-picker>
</label> </label>
</div> </div>
{# Only show progress for editing existing readthroughs #} {# Only show progress for editing existing readthroughs #}
@ -32,10 +28,6 @@
<div class="field"> <div class="field">
<label class="label"> <label class="label">
{% trans "Finished reading" %} {% trans "Finished reading" %}
<duet-date-picker <input type="date" name="finish_date" class="input" id="id_finish_date-{{ readthrough.id }}" value="{{ readthrough.finish_date | date:"Y-m-d" }}">
identifier="id_finish_date-{{ readthrough.id }}"
name="finish_date"
value="{{ readthrough.finish_date | date:'Y-m-d' }}">
</duet-date-picker>
</label> </label>
</div> </div>

View File

@ -1,5 +1,6 @@
{% load i18n %} {% load i18n %}
{% load bookwyrm_tags %} {% load utilities %}
{% with 0|uuid as report_uuid %} {% with 0|uuid as report_uuid %}
{% trans "Report" as button_text %} {% trans "Report" as button_text %}

View File

@ -6,7 +6,7 @@
{% endblock %} {% endblock %}
{% block dropdown-list %} {% block dropdown-list %}
{% for shelf in request.user.shelf_set.all %} {% for shelf in user_shelves %}
<li role="menuitem" class="dropdown-item p-0"> <li role="menuitem" class="dropdown-item p-0">
<form name="shelve" action="/shelve/" method="post"> <form name="shelve" action="/shelve/" method="post">
{% csrf_token %} {% csrf_token %}

View File

@ -17,21 +17,13 @@
<div class="field"> <div class="field">
<label class="label"> <label class="label">
{% trans "Started reading" %} {% trans "Started reading" %}
<duet-date-picker <input type="date" name="start_date" class="input" id="finish_id_start_date-{{ uuid }}" value="{{ readthrough.start_date | date:"Y-m-d" }}">
identifier="id_start_date-{{ uuid }}"
name="start_date"
value="{{ readthrough.start_date | date:'Y-m-d' }}"
></duet-date-picker>
</label> </label>
</div> </div>
<div class="field"> <div class="field">
<label class="label"> <label class="label">
{% trans "Finished reading" %} {% trans "Finished reading" %}
<duet-date-picker <input type="date" name="finish_date" class="input" id="id_finish_date-{{ uuid }}" value="{% now "Y-m-d" %}">
identifier="id_finish_date-{{ uuid }}"
name="finish_date"
value="{{ readthrough.finish_date | date:'Y-m-d' }}"
></duet-date-picker>
</label> </label>
</div> </div>
</section> </section>

View File

@ -1,4 +1,6 @@
{% load bookwyrm_tags %} {% load bookwyrm_tags %}
{% load utilities %}
{% if request.user.is_authenticated %} {% if request.user.is_authenticated %}
{% with book.id|uuid as uuid %} {% with book.id|uuid as uuid %}
@ -11,7 +13,7 @@
</div> </div>
{% else %} {% else %}
<div class="control"> <div class="control">
{% include 'snippets/shelve_button/shelve_button_options.html' with class="shelf-option is-small" shelves=request.user.shelf_set.all active_shelf=active_shelf button_uuid=uuid %} {% include 'snippets/shelve_button/shelve_button_options.html' with class="shelf-option is-small" shelves=user_shelves active_shelf=active_shelf button_uuid=uuid %}
</div> </div>
{% include 'snippets/shelve_button/shelve_button_dropdown.html' with class="is-small" button_uuid=uuid%} {% include 'snippets/shelve_button/shelve_button_dropdown.html' with class="is-small" button_uuid=uuid%}
{% endif %} {% endif %}
@ -23,7 +25,7 @@
{% include 'snippets/shelve_button/finish_reading_modal.html' with book=active_shelf.book controls_text="finish-reading" controls_uid=uuid readthrough=readthrough %} {% include 'snippets/shelve_button/finish_reading_modal.html' with book=active_shelf.book controls_text="finish-reading" controls_uid=uuid readthrough=readthrough %}
{% include 'snippets/shelve_button/progress_update_modal.html' with book=shelf_book.book controls_text="progress-update" controls_uid=uuid readthrough=readthrough %} {% include 'snippets/shelve_button/progress_update_modal.html' with book=active_shelf_book.book controls_text="progress-update" controls_uid=uuid readthrough=readthrough %}
{% endwith %} {% endwith %}
{% endif %} {% endif %}

View File

@ -7,5 +7,5 @@
{% endblock %} {% endblock %}
{% block dropdown-list %} {% block dropdown-list %}
{% include 'snippets/shelve_button/shelve_button_options.html' with active_shelf=active_shelf shelves=request.user.shelf_set.all dropdown=True class="shelf-option is-fullwidth is-small is-radiusless is-white" %} {% include 'snippets/shelve_button/shelve_button_options.html' with active_shelf=active_shelf shelves=user_shelves dropdown=True class="shelf-option is-fullwidth is-small is-radiusless is-white" %}
{% endblock %} {% endblock %}

View File

@ -1,5 +1,7 @@
{% load bookwyrm_tags %} {% load bookwyrm_tags %}
{% load utilities %}
{% load i18n %} {% load i18n %}
{% for shelf in shelves %} {% for shelf in shelves %}
{% comparison_bool shelf.identifier active_shelf.shelf.identifier as is_current %} {% comparison_bool shelf.identifier active_shelf.shelf.identifier as is_current %}
{% if dropdown %}<li role="menuitem" class="dropdown-item p-0">{% endif %} {% if dropdown %}<li role="menuitem" class="dropdown-item p-0">{% endif %}

View File

@ -15,11 +15,7 @@
<div class="field"> <div class="field">
<label class="label"> <label class="label">
{% trans "Started reading" %} {% trans "Started reading" %}
<duet-date-picker <input type="date" name="start_date" class="input" id="start_id_start_date-{{ uuid }}" value="{% now "Y-m-d" %}">
identifier="start_id_start_date-{{ uuid }}"
name="start_date"
value="{% now "Y-m-d" %}"
></duet-date-picker>
</label> </label>
</div> </div>
</section> </section>

View File

@ -1,4 +1,5 @@
{% load bookwyrm_tags %} {% load bookwyrm_tags %}
{% load markdown %}
{% load i18n %} {% load i18n %}
{% with status_type=status.status_type %} {% with status_type=status.status_type %}

View File

@ -1,6 +1,7 @@
{% spaceless %} {% spaceless %}
{% load bookwyrm_tags %} {% load bookwyrm_tags %}
{% load markdown %}
{% load i18n %} {% load i18n %}
{% if not hide_book %} {% if not hide_book %}

View File

@ -1,7 +1,6 @@
{% extends 'components/card.html' %} {% extends 'components/card.html' %}
{% load i18n %} {% load i18n %}
{% load bookwyrm_tags %} {% load utilities %}
{% load humanize %}
{% block card-header %} {% block card-header %}
<div class="card-header-title has-background-white-ter is-block"> <div class="card-header-title has-background-white-ter is-block">

View File

@ -1,5 +1,6 @@
{% load bookwyrm_tags %} {% load status_display %}
{% load i18n %} {% load i18n %}
{% if not status.deleted %} {% if not status.deleted %}
{% if status.status_type == 'Announce' %} {% if status.status_type == 'Announce' %}
<a href="{{ status.user.local_path }}"> <a href="{{ status.user.local_path }}">

View File

@ -1,4 +1,5 @@
{% load bookwyrm_tags %} {% load utilities %}
{% load status_display %}
{% load i18n %} {% load i18n %}
{% load humanize %} {% load humanize %}
@ -47,7 +48,7 @@
{% 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="{{ status.book.local_path }}">{{ status.book|title }}</a>{% if status.status_type == 'Rating' %}: {% include 'snippets/stars.html' with rating=status.rating %} <a href="{{ status.book.local_path }}">{{ status.book|book_title }}</a>{% if status.status_type == 'Rating' %}: {% include 'snippets/stars.html' with rating=status.rating %}
<span <span
itemprop="reviewRating" itemprop="reviewRating"
itemscope itemscope
@ -58,7 +59,7 @@
{% 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="{{ status.book.local_path }}">{{ status.book|title }}</a>{% if status.status_type == 'Rating' %}: <a href="{{ status.book.local_path }}">{{ status.book|book_title }}</a>{% if status.status_type == 'Rating' %}:
<span <span
itemprop="reviewRating" itemprop="reviewRating"
itemscope itemscope
@ -77,7 +78,7 @@
{% endif %} {% endif %}
{% elif status.mention_books %} {% elif status.mention_books %}
<a href="{{ status.mention_books.first.local_path }}"> <a href="{{ status.mention_books.first.local_path }}">
{{ status.mention_books.first.title }} {{ status.mention_books.first|book_title }}
</a> </a>
{% endif %} {% endif %}
{% include 'snippets/stars.html' with rating=status.rating %} {% include 'snippets/stars.html' with rating=status.rating %}
@ -86,12 +87,12 @@
{% include 'snippets/book_titleby.html' with book=status.book %} {% include 'snippets/book_titleby.html' with book=status.book %}
{% endif %} {% endif %}
{% elif status.mention_books %} {% elif status.mention_books %}
<a href="{{ status.mention_books.first.local_path }}">{{ status.mention_books.first|title }}</a> <a href="{{ status.mention_books.first.local_path }}">{{ status.mention_books.first|book_title }}</a>
{% endif %} {% endif %}
</h3> </h3>
<p class="is-size-7 is-flex is-align-items-center"> <p class="is-size-7 is-flex is-align-items-center">
<a href="{{ status.remote_id }}">{{ status.published_date|timesince }}</a> <a href="{{ status.remote_id }}">{{ status.published_date|published_date }}</a>
{% if status.progress %} {% if status.progress %}
<span class="ml-1"> <span class="ml-1">
{% if status.progress_mode == 'PG' %} {% if status.progress_mode == 'PG' %}

View File

@ -1,6 +1,6 @@
{% extends 'components/dropdown.html' %} {% extends 'components/dropdown.html' %}
{% load i18n %} {% load i18n %}
{% load bookwyrm_tags %} {% load utilities %}
{% block dropdown-trigger %} {% block dropdown-trigger %}
<span class="icon icon-dots-three m-0-mobile"></span> <span class="icon icon-dots-three m-0-mobile"></span>
@ -39,7 +39,7 @@
{% include 'snippets/report_button.html' with user=status.user status=status %} {% include 'snippets/report_button.html' with user=status.user status=status %}
</li> </li>
<li role="menuitem" class="dropdown-item p-0"> <li role="menuitem" class="dropdown-item p-0">
{% include 'snippets/block_button.html' with user=status.user class="is-fullwidth" %} {% include 'snippets/block_button.html' with user=status.user class="is-fullwidth" blocks=False %}
</li> </li>
{% endif %} {% endif %}
{% endblock %} {% endblock %}

View File

@ -1,4 +1,5 @@
{% load bookwyrm_tags %} {% load markdown %}
{% load utilities %}
{% load i18n %} {% load i18n %}
{% with 0|uuid as uuid %} {% with 0|uuid as uuid %}

View File

@ -1,6 +1,6 @@
{% extends 'components/dropdown.html' %} {% extends 'components/dropdown.html' %}
{% load i18n %} {% load i18n %}
{% load bookwyrm_tags %} {% load utilities %}
{% block dropdown-trigger %} {% block dropdown-trigger %}
<span class="icon icon-dots-three"> <span class="icon icon-dots-three">
@ -16,6 +16,6 @@
{% include 'snippets/report_button.html' with user=user class="is-fullwidth" %} {% include 'snippets/report_button.html' with user=user class="is-fullwidth" %}
</li> </li>
<li role="menuitem"> <li role="menuitem">
{% include 'snippets/block_button.html' with user=user class="is-fullwidth" %} {% include 'snippets/block_button.html' with user=user class="is-fullwidth" blocks=False %}
</li> </li>
{% endblock %} {% endblock %}

View File

@ -1,7 +1,8 @@
{% extends 'layout.html' %} {% extends 'layout.html' %}
{% load i18n %} {% load i18n %}
{% load humanize %} {% load humanize %}
{% load bookwyrm_tags %} {% load utilities %}
{% load markdown %}
{% block title %}{{ user.display_name }}{% endblock %} {% block title %}{{ user.display_name }}{% endblock %}
@ -81,8 +82,3 @@
{% block panel %}{% endblock %} {% block panel %}{% endblock %}
{% endblock %} {% endblock %}
{% block scripts %}
{% include 'snippets/datepicker_js.html' %}
{% endblock %}

View File

@ -15,7 +15,7 @@
{% if is_self %} {% if is_self %}
<div class="column is-narrow"> <div class="column is-narrow">
{% trans "Create list" as button_text %} {% trans "Create list" as button_text %}
{% include 'snippets/toggle/open_button.html' with controls_text="create-list" icon="plus" text=button_text %} {% include 'snippets/toggle/open_button.html' with controls_text="create-list" icon_with_text="plus" text=button_text %}
</div> </div>
{% endif %} {% endif %}
</div> </div>

Some files were not shown because too many files have changed in this diff Show More