diff --git a/.github/workflows/pylint.yml b/.github/workflows/pylint.yml index 1b14149f2..08661e9c2 100644 --- a/.github/workflows/pylint.yml +++ b/.github/workflows/pylint.yml @@ -24,5 +24,5 @@ jobs: pip install pylint - name: Analysing the code with pylint run: | - pylint bookwyrm/ --ignore=migrations,tests --disable=E1101,E1135,E1136,R0903,R0901,R0902,W0707,W0511,W0406,R0401,R0801 + pylint bookwyrm/ --ignore=migrations --disable=E1101,E1135,E1136,R0903,R0901,R0902,W0707,W0511,W0406,R0401,R0801 diff --git a/README.md b/README.md index cec05d45e..c0ca2a255 100644 --- a/README.md +++ b/README.md @@ -9,21 +9,18 @@ Social reading and reviewing, decentralized with ActivityPub. This branch is a f - [What it is and isn't](#what-it-is-and-isnt) - [The role of federation](#the-role-of-federation) - [Features](#features) -- [Book data](#book-data) -- [Set up Bookwyrm](#set-up-bookwyrm) +- [Set up BookWyrm](#set-up-bookwyrm) ## Joining BookWyrm -BookWyrm is still a young piece of software, and isn't at the level of stability and feature-richness that you'd find in a production-ready application. But it does what it says on the box! If you'd like to join an instance, you can check out the [instances](https://joinbookwyrm.com/instances/) list. - -You can request an invite by entering your email address at https://bookwyrm.social. +If you'd like to join an instance, you can check out the [instances](https://joinbookwyrm.com/instances/) list. ## Contributing -See [contributing](https://docs.joinbookwyrm.com/how-to-contribute.html) for code, translation or monetary contributions. +See [contributing](https://docs.joinbookwyrm.com/contributing.html) for code, translation or monetary contributions. ## About BookWyrm ### What it is and isn't -BookWyrm is a platform for social reading! You can use it to track what you're reading, review books, and follow your friends. It isn't primarily meant for cataloguing or as a data-source for books, but it does do both of those things to some degree. +BookWyrm is a platform for social reading. You can use it to track what you're reading, review books, and follow your friends. It isn't primarily meant for cataloguing or as a data-source for books, but it does do both of those things to some degree. ### The role of federation BookWyrm is built on [ActivityPub](http://activitypub.rocks/). With ActivityPub, it inter-operates with different instances of BookWyrm, and other ActivityPub compliant services, like Mastodon. This means you can run an instance for your book club, and still follow your friend who posts on a server devoted to 20th century Russian speculative fiction. It also means that your friend on mastodon can read and comment on a book review that you post on your BookWyrm instance. @@ -78,8 +75,5 @@ Deployment - [Nginx](https://nginx.org/en/) HTTP server -## Book data -The application is set up to share book and author data between instances, and get book data from arbitrary outside sources. Right now, the only connector is to OpenLibrary, but other connectors could be written. - -## Set up Bookwyrm -The [documentation website](https://docs.joinbookwyrm.com/) has instruction on how to set up Bookwyrm in a [developer environment](https://docs.joinbookwyrm.com/developer-environment.html) or [production](https://docs.joinbookwyrm.com/installing-in-production.html). +## Set up BookWyrm +The [documentation website](https://docs.joinbookwyrm.com/) has instruction on how to set up BookWyrm in a [developer environment](https://docs.joinbookwyrm.com/install-dev.html) or [production](https://docs.joinbookwyrm.com/install-prod.html). diff --git a/bookwyrm/activitypub/base_activity.py b/bookwyrm/activitypub/base_activity.py index 6bee25f62..fa1535694 100644 --- a/bookwyrm/activitypub/base_activity.py +++ b/bookwyrm/activitypub/base_activity.py @@ -1,6 +1,7 @@ """ basics for an activitypub serializer """ from dataclasses import dataclass, fields, MISSING from json import JSONEncoder +import logging from django.apps import apps from django.db import IntegrityError, transaction @@ -8,6 +9,8 @@ from django.db import IntegrityError, transaction from bookwyrm.connectors import ConnectorException, get_data from bookwyrm.tasks import app +logger = logging.getLogger(__name__) + class ActivitySerializerError(ValueError): """routine problems serializing activitypub json""" @@ -39,12 +42,12 @@ def naive_parse(activity_objects, activity_json, serializer=None): activity_json["type"] = "PublicKey" activity_type = activity_json.get("type") + if activity_type in ["Question", "Article"]: + return None try: serializer = activity_objects[activity_type] except KeyError as err: # we know this exists and that we can't handle it - if activity_type in ["Question"]: - return None raise ActivitySerializerError(err) return serializer(activity_objects=activity_objects, **activity_json) @@ -65,7 +68,7 @@ class ActivityObject: try: value = kwargs[field.name] if value in (None, MISSING, {}): - raise KeyError() + raise KeyError("Missing required field", field.name) try: is_subclass = issubclass(field.type, ActivityObject) except TypeError: @@ -268,9 +271,9 @@ def resolve_remote_id( try: data = get_data(remote_id) except ConnectorException: - raise ActivitySerializerError( - f"Could not connect to host for remote_id: {remote_id}" - ) + logger.exception("Could not connect to host for remote_id: %s", remote_id) + return None + # determine the model implicitly, if not provided # or if it's a model with subclasses like Status, check again if not model or hasattr(model.objects, "select_subclasses"): diff --git a/bookwyrm/activitystreams.py b/bookwyrm/activitystreams.py index f2dd43fb2..a90d7943b 100644 --- a/bookwyrm/activitystreams.py +++ b/bookwyrm/activitystreams.py @@ -298,8 +298,9 @@ def add_status_on_create_command(sender, instance, created): priority = HIGH # check if this is an old status, de-prioritize if so # (this will happen if federation is very slow, or, more expectedly, on csv import) - one_day = 60 * 60 * 24 - if (instance.created_date - instance.published_date).seconds > one_day: + if instance.published_date < timezone.now() - timedelta( + days=1 + ) or instance.created_date < instance.published_date - timedelta(days=1): priority = LOW add_status_task.apply_async( diff --git a/bookwyrm/forms/forms.py b/bookwyrm/forms/forms.py index 9d8f9f392..4aa1e5758 100644 --- a/bookwyrm/forms/forms.py +++ b/bookwyrm/forms/forms.py @@ -53,7 +53,12 @@ class ReadThroughForm(CustomForm): self.add_error( "finish_date", _("Reading finish date cannot be before start date.") ) + stopped_date = cleaned_data.get("stopped_date") + if start_date and stopped_date and start_date > stopped_date: + self.add_error( + "stopped_date", _("Reading stopped date cannot be before start date.") + ) class Meta: model = models.ReadThrough - fields = ["user", "book", "start_date", "finish_date"] + fields = ["user", "book", "start_date", "finish_date", "stopped_date"] diff --git a/bookwyrm/importers/__init__.py b/bookwyrm/importers/__init__.py index dd3d62e8b..6ce50f160 100644 --- a/bookwyrm/importers/__init__.py +++ b/bookwyrm/importers/__init__.py @@ -1,6 +1,7 @@ """ import classes """ from .importer import Importer +from .calibre_import import CalibreImporter from .goodreads_import import GoodreadsImporter from .librarything_import import LibrarythingImporter from .openlibrary_import import OpenLibraryImporter diff --git a/bookwyrm/importers/calibre_import.py b/bookwyrm/importers/calibre_import.py new file mode 100644 index 000000000..7395e2f7b --- /dev/null +++ b/bookwyrm/importers/calibre_import.py @@ -0,0 +1,28 @@ +""" handle reading a csv from calibre """ +from bookwyrm.models import Shelf + +from . import Importer + + +class CalibreImporter(Importer): + """csv downloads from Calibre""" + + service = "Calibre" + + def __init__(self, *args, **kwargs): + # Add timestamp to row_mappings_guesses for date_added to avoid + # integrity error + row_mappings_guesses = [] + + for field, mapping in self.row_mappings_guesses: + if field in ("date_added",): + row_mappings_guesses.append((field, mapping + ["timestamp"])) + else: + row_mappings_guesses.append((field, mapping)) + + self.row_mappings_guesses = row_mappings_guesses + super().__init__(*args, **kwargs) + + def get_shelf(self, normalized_row): + # Calibre export does not indicate which shelf to use. Go with a default one for now + return Shelf.TO_READ diff --git a/bookwyrm/importers/librarything_import.py b/bookwyrm/importers/librarything_import.py index 37730dee3..c6833547d 100644 --- a/bookwyrm/importers/librarything_import.py +++ b/bookwyrm/importers/librarything_import.py @@ -1,5 +1,8 @@ """ handle reading a tsv from librarything """ import re + +from bookwyrm.models import Shelf + from . import Importer @@ -21,7 +24,7 @@ class LibrarythingImporter(Importer): def get_shelf(self, normalized_row): if normalized_row["date_finished"]: - return "read" + return Shelf.READ_FINISHED if normalized_row["date_started"]: - return "reading" - return "to-read" + return Shelf.READING + return Shelf.TO_READ diff --git a/bookwyrm/management/commands/initdb.py b/bookwyrm/management/commands/initdb.py index 4e23a5306..160502ca0 100644 --- a/bookwyrm/management/commands/initdb.py +++ b/bookwyrm/management/commands/initdb.py @@ -105,16 +105,6 @@ def init_connectors(): ) -def init_federated_servers(): - """big no to nazis""" - built_in_blocks = ["gab.ai", "gab.com"] - for server in built_in_blocks: - models.FederatedServer.objects.create( - server_name=server, - status="blocked", - ) - - def init_settings(): """info about the instance""" models.SiteSettings.objects.create( @@ -163,7 +153,6 @@ class Command(BaseCommand): "group", "permission", "connector", - "federatedserver", "settings", "linkdomain", ] @@ -176,8 +165,6 @@ class Command(BaseCommand): init_permissions() if not limit or limit == "connector": init_connectors() - if not limit or limit == "federatedserver": - init_federated_servers() if not limit or limit == "settings": init_settings() if not limit or limit == "linkdomain": diff --git a/bookwyrm/migrations/0146_auto_20220316_2320.py b/bookwyrm/migrations/0146_auto_20220316_2320.py new file mode 100644 index 000000000..e50bf25ec --- /dev/null +++ b/bookwyrm/migrations/0146_auto_20220316_2320.py @@ -0,0 +1,80 @@ +# Generated by Django 3.2.12 on 2022-03-16 23:20 + +import bookwyrm.models.fields +from django.db import migrations +from bookwyrm.models import Shelf + + +def add_shelves(apps, schema_editor): + """add any superusers to the "admin" group""" + + db_alias = schema_editor.connection.alias + shelf_model = apps.get_model("bookwyrm", "Shelf") + + users = apps.get_model("bookwyrm", "User") + local_users = users.objects.using(db_alias).filter(local=True) + for user in local_users: + remote_id = f"{user.remote_id}/books/stopped" + shelf_model.objects.using(db_alias).create( + name="Stopped reading", + identifier=Shelf.STOPPED_READING, + user=user, + editable=False, + remote_id=remote_id, + ) + + +class Migration(migrations.Migration): + + dependencies = [ + ("bookwyrm", "0145_sitesettings_version"), + ] + + operations = [ + migrations.AlterField( + model_name="comment", + name="reading_status", + field=bookwyrm.models.fields.CharField( + blank=True, + choices=[ + ("to-read", "To-Read"), + ("reading", "Reading"), + ("read", "Read"), + ("stopped-reading", "Stopped-Reading"), + ], + max_length=255, + null=True, + ), + ), + migrations.AlterField( + model_name="quotation", + name="reading_status", + field=bookwyrm.models.fields.CharField( + blank=True, + choices=[ + ("to-read", "To-Read"), + ("reading", "Reading"), + ("read", "Read"), + ("stopped-reading", "Stopped-Reading"), + ], + max_length=255, + null=True, + ), + ), + migrations.AlterField( + model_name="review", + name="reading_status", + field=bookwyrm.models.fields.CharField( + blank=True, + choices=[ + ("to-read", "To-Read"), + ("reading", "Reading"), + ("read", "Read"), + ("stopped-reading", "Stopped-Reading"), + ], + max_length=255, + null=True, + ), + ), + migrations.RunPython(add_shelves, reverse_code=migrations.RunPython.noop), + ] diff --git a/bookwyrm/migrations/0148_alter_user_preferred_language.py b/bookwyrm/migrations/0148_alter_user_preferred_language.py new file mode 100644 index 000000000..05784f280 --- /dev/null +++ b/bookwyrm/migrations/0148_alter_user_preferred_language.py @@ -0,0 +1,39 @@ +# Generated by Django 3.2.12 on 2022-03-31 14:35 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("bookwyrm", "0147_alter_user_preferred_language"), + ] + + operations = [ + migrations.AlterField( + model_name="user", + name="preferred_language", + field=models.CharField( + blank=True, + choices=[ + ("en-us", "English"), + ("de-de", "Deutsch (German)"), + ("es-es", "Español (Spanish)"), + ("gl-es", "Galego (Galician)"), + ("it-it", "Italiano (Italian)"), + ("fi-fi", "Suomi (Finnish)"), + ("fr-fr", "Français (French)"), + ("lt-lt", "Lietuvių (Lithuanian)"), + ("no-no", "Norsk (Norwegian)"), + ("pt-br", "Português do Brasil (Brazilian Portuguese)"), + ("pt-pt", "Português Europeu (European Portuguese)"), + ("ro-ro", "Română (Romanian)"), + ("sv-se", "Svenska (Swedish)"), + ("zh-hans", "简体中文 (Simplified Chinese)"), + ("zh-hant", "繁體中文 (Traditional Chinese)"), + ], + max_length=255, + null=True, + ), + ), + ] diff --git a/bookwyrm/migrations/0148_merge_20220326_2006.py b/bookwyrm/migrations/0148_merge_20220326_2006.py new file mode 100644 index 000000000..978662765 --- /dev/null +++ b/bookwyrm/migrations/0148_merge_20220326_2006.py @@ -0,0 +1,13 @@ +# Generated by Django 3.2.12 on 2022-03-26 20:06 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("bookwyrm", "0146_auto_20220316_2320"), + ("bookwyrm", "0147_alter_user_preferred_language"), + ] + + operations = [] diff --git a/bookwyrm/migrations/0149_merge_20220526_1716.py b/bookwyrm/migrations/0149_merge_20220526_1716.py new file mode 100644 index 000000000..b42bccd3b --- /dev/null +++ b/bookwyrm/migrations/0149_merge_20220526_1716.py @@ -0,0 +1,13 @@ +# Generated by Django 3.2.13 on 2022-05-26 17:16 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("bookwyrm", "0148_alter_user_preferred_language"), + ("bookwyrm", "0148_merge_20220326_2006"), + ] + + operations = [] diff --git a/bookwyrm/migrations/0150_readthrough_stopped_date.py b/bookwyrm/migrations/0150_readthrough_stopped_date.py new file mode 100644 index 000000000..6ce2f89a9 --- /dev/null +++ b/bookwyrm/migrations/0150_readthrough_stopped_date.py @@ -0,0 +1,18 @@ +# Generated by Django 3.2.13 on 2022-05-26 18:33 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("bookwyrm", "0149_merge_20220526_1716"), + ] + + operations = [ + migrations.AddField( + model_name="readthrough", + name="stopped_date", + field=models.DateTimeField(blank=True, null=True), + ), + ] diff --git a/bookwyrm/models/base_model.py b/bookwyrm/models/base_model.py index f8d3b7818..eeb2e940d 100644 --- a/bookwyrm/models/base_model.py +++ b/bookwyrm/models/base_model.py @@ -8,6 +8,7 @@ from django.db.models import Q from django.dispatch import receiver from django.http import Http404 from django.utils.translation import gettext_lazy as _ +from django.utils.text import slugify from bookwyrm.settings import DOMAIN from .fields import RemoteIdField @@ -35,10 +36,11 @@ class BookWyrmModel(models.Model): remote_id = RemoteIdField(null=True, activitypub_field="id") def get_remote_id(self): - """generate a url that resolves to the local object""" + """generate the url that resolves to the local object, without a slug""" base_path = f"https://{DOMAIN}" if hasattr(self, "user"): base_path = f"{base_path}{self.user.local_path}" + model_name = type(self).__name__.lower() return f"{base_path}/{model_name}/{self.id}" @@ -49,8 +51,20 @@ class BookWyrmModel(models.Model): @property def local_path(self): - """how to link to this object in the local app""" - return self.get_remote_id().replace(f"https://{DOMAIN}", "") + """how to link to this object in the local app, with a slug""" + local = self.get_remote_id().replace(f"https://{DOMAIN}", "") + + name = None + if hasattr(self, "name_field"): + name = getattr(self, self.name_field) + elif hasattr(self, "name"): + name = self.name + + if name: + slug = slugify(name) + local = f"{local}/s/{slug}" + + return local def raise_visible_to_user(self, viewer): """is a user authorized to view an object?""" diff --git a/bookwyrm/models/book.py b/bookwyrm/models/book.py index 3ea8e1a8e..190046019 100644 --- a/bookwyrm/models/book.py +++ b/bookwyrm/models/book.py @@ -176,8 +176,8 @@ class Book(BookDataModel): """properties of this edition, as a string""" items = [ self.physical_format if hasattr(self, "physical_format") else None, - self.languages[0] + " language" - if self.languages and self.languages[0] != "English" + f"{self.languages[0]} language" + if self.languages and self.languages[0] and self.languages[0] != "English" else None, str(self.published_date.year) if self.published_date else None, ", ".join(self.publishers) if hasattr(self, "publishers") else None, diff --git a/bookwyrm/models/fields.py b/bookwyrm/models/fields.py index 5a03df015..62c61cc40 100644 --- a/bookwyrm/models/fields.py +++ b/bookwyrm/models/fields.py @@ -125,7 +125,7 @@ class ActivitypubFieldMixin: """model_field_name to activitypubFieldName""" if self.activitypub_field: return self.activitypub_field - name = self.name.split(".")[-1] + name = self.name.rsplit(".", maxsplit=1)[-1] components = name.split("_") return components[0] + "".join(x.title() for x in components[1:]) diff --git a/bookwyrm/models/import_job.py b/bookwyrm/models/import_job.py index bcba391b6..556f133f9 100644 --- a/bookwyrm/models/import_job.py +++ b/bookwyrm/models/import_job.py @@ -175,9 +175,15 @@ class ImportItem(models.Model): def date_added(self): """when the book was added to this dataset""" if self.normalized_data.get("date_added"): - return timezone.make_aware( - dateutil.parser.parse(self.normalized_data.get("date_added")) + parsed_date_added = dateutil.parser.parse( + self.normalized_data.get("date_added") ) + + if timezone.is_aware(parsed_date_added): + # Keep timezone if import already had one + return parsed_date_added + + return timezone.make_aware(parsed_date_added) return None @property diff --git a/bookwyrm/models/readthrough.py b/bookwyrm/models/readthrough.py index ceb8e0b6e..314b40a5c 100644 --- a/bookwyrm/models/readthrough.py +++ b/bookwyrm/models/readthrough.py @@ -27,6 +27,7 @@ class ReadThrough(BookWyrmModel): ) start_date = models.DateTimeField(blank=True, null=True) finish_date = models.DateTimeField(blank=True, null=True) + stopped_date = models.DateTimeField(blank=True, null=True) is_active = models.BooleanField(default=True) def save(self, *args, **kwargs): @@ -34,7 +35,7 @@ class ReadThrough(BookWyrmModel): cache.delete(f"latest_read_through-{self.user.id}-{self.book.id}") self.user.update_active_date() # an active readthrough must have an unset finish date - if self.finish_date: + if self.finish_date or self.stopped_date: self.is_active = False super().save(*args, **kwargs) diff --git a/bookwyrm/models/shelf.py b/bookwyrm/models/shelf.py index 320d495d2..3291d5653 100644 --- a/bookwyrm/models/shelf.py +++ b/bookwyrm/models/shelf.py @@ -6,6 +6,7 @@ from django.db import models from django.utils import timezone from bookwyrm import activitypub +from bookwyrm.settings import DOMAIN from .activitypub_mixin import CollectionItemMixin, OrderedCollectionMixin from .base_model import BookWyrmModel from . import fields @@ -17,8 +18,9 @@ class Shelf(OrderedCollectionMixin, BookWyrmModel): TO_READ = "to-read" READING = "reading" READ_FINISHED = "read" + STOPPED_READING = "stopped-reading" - READ_STATUS_IDENTIFIERS = (TO_READ, READING, READ_FINISHED) + READ_STATUS_IDENTIFIERS = (TO_READ, READING, READ_FINISHED, STOPPED_READING) name = fields.CharField(max_length=100) identifier = models.CharField(max_length=100) @@ -65,6 +67,11 @@ class Shelf(OrderedCollectionMixin, BookWyrmModel): identifier = self.identifier or self.get_identifier() return f"{base_path}/books/{identifier}" + @property + def local_path(self): + """No slugs""" + return self.get_remote_id().replace(f"https://{DOMAIN}", "") + def raise_not_deletable(self, viewer): """don't let anyone delete a default shelf""" super().raise_not_deletable(viewer) diff --git a/bookwyrm/models/status.py b/bookwyrm/models/status.py index 17fcd4587..1e31de774 100644 --- a/bookwyrm/models/status.py +++ b/bookwyrm/models/status.py @@ -116,11 +116,8 @@ class Status(OrderedCollectionPageMixin, BookWyrmModel): def ignore_activity(cls, activity): # pylint: disable=too-many-return-statements """keep notes if they are replies to existing statuses""" if activity.type == "Announce": - try: - boosted = activitypub.resolve_remote_id( - activity.object, get_activity=True - ) - except activitypub.ActivitySerializerError: + boosted = activitypub.resolve_remote_id(activity.object, get_activity=True) + if not boosted: # if we can't load the status, definitely ignore it return True # keep the boost if we would keep the status @@ -265,7 +262,7 @@ class GeneratedNote(Status): ReadingStatusChoices = models.TextChoices( - "ReadingStatusChoices", ["to-read", "reading", "read"] + "ReadingStatusChoices", ["to-read", "reading", "read", "stopped-reading"] ) diff --git a/bookwyrm/models/user.py b/bookwyrm/models/user.py index be5c19922..dce74022c 100644 --- a/bookwyrm/models/user.py +++ b/bookwyrm/models/user.py @@ -374,6 +374,10 @@ class User(OrderedCollectionPageMixin, AbstractUser): "name": "Read", "identifier": "read", }, + { + "name": "Stopped Reading", + "identifier": "stopped-reading", + }, ] for shelf in shelves: diff --git a/bookwyrm/settings.py b/bookwyrm/settings.py index ffddf1d26..ae7864f12 100644 --- a/bookwyrm/settings.py +++ b/bookwyrm/settings.py @@ -11,7 +11,7 @@ from django.utils.translation import gettext_lazy as _ env = Env() env.read_env() DOMAIN = env("DOMAIN") -VERSION = "0.3.4" +VERSION = "0.4.0" RELEASE_API = env( "RELEASE_API", @@ -21,7 +21,7 @@ RELEASE_API = env( PAGE_LENGTH = env("PAGE_LENGTH", 15) DEFAULT_LANGUAGE = env("DEFAULT_LANGUAGE", "English") -JS_CACHE = "bc93172a" +JS_CACHE = "e678183b" # email EMAIL_BACKEND = env("EMAIL_BACKEND", "django.core.mail.backends.smtp.EmailBackend") @@ -293,6 +293,7 @@ LANGUAGES = [ ("es-es", _("Español (Spanish)")), ("gl-es", _("Galego (Galician)")), ("it-it", _("Italiano (Italian)")), + ("fi-fi", _("Suomi (Finnish)")), ("fr-fr", _("Français (French)")), ("lt-lt", _("Lietuvių (Lithuanian)")), ("no-no", _("Norsk (Norwegian)")), diff --git a/bookwyrm/static/css/bookwyrm/components/_details.scss b/bookwyrm/static/css/bookwyrm/components/_details.scss index 5708c9461..c9a0b33b8 100644 --- a/bookwyrm/static/css/bookwyrm/components/_details.scss +++ b/bookwyrm/static/css/bookwyrm/components/_details.scss @@ -114,3 +114,17 @@ details[open] summary .details-close { padding-bottom: 0.25rem; } } + +/** Navbar details + ******************************************************************************/ + +#navbar-dropdown .navbar-item { + color: $text; + font-size: 0.875rem; + padding: 0.375rem 3rem 0.375rem 1rem; + white-space: nowrap; +} + +#navbar-dropdown .navbar-item:hover { + background-color: $background-secondary; +} diff --git a/bookwyrm/static/css/bookwyrm/utilities/_colors.scss b/bookwyrm/static/css/bookwyrm/utilities/_colors.scss index e44efee95..f38d2a40b 100644 --- a/bookwyrm/static/css/bookwyrm/utilities/_colors.scss +++ b/bookwyrm/static/css/bookwyrm/utilities/_colors.scss @@ -23,3 +23,8 @@ .has-background-tertiary { background-color: $background-tertiary !important; } + +/* Workaround for dark theme as .has-text-black doesn't give desired effect. */ +.has-text-default { + color: $text !important; +} diff --git a/bookwyrm/static/css/themes/bookwyrm-dark.scss b/bookwyrm/static/css/themes/bookwyrm-dark.scss index 96997c4a4..88ee865bb 100644 --- a/bookwyrm/static/css/themes/bookwyrm-dark.scss +++ b/bookwyrm/static/css/themes/bookwyrm-dark.scss @@ -53,6 +53,7 @@ $link-hover: $white-bis; $link-hover-border: #51595d; $link-focus: $white-bis; $link-active: $white-bis; +$link-light: #0d1c26; /* bulma overrides */ $background: $background-secondary; @@ -83,6 +84,13 @@ $progress-value-background-color: $border-light; $family-primary: $family-sans-serif; $family-secondary: $family-sans-serif; +.has-text-muted { + color: $grey-lighter !important; +} + +.has-text-more-muted { + color: $grey-light !important; +} @import "../bookwyrm.scss"; @import "../vendor/icons.css"; diff --git a/bookwyrm/static/css/themes/bookwyrm-light.scss b/bookwyrm/static/css/themes/bookwyrm-light.scss index 69c1a8063..75f05164b 100644 --- a/bookwyrm/static/css/themes/bookwyrm-light.scss +++ b/bookwyrm/static/css/themes/bookwyrm-light.scss @@ -57,5 +57,13 @@ $invisible-overlay-background-color: rgba($scheme-invert, 0.66); $family-primary: $family-sans-serif; $family-secondary: $family-sans-serif; +.has-text-muted { + color: $grey-dark !important; +} + +.has-text-more-muted { + color: $grey !important; +} + @import "../bookwyrm.scss"; @import "../vendor/icons.css"; diff --git a/bookwyrm/static/js/status_cache.js b/bookwyrm/static/js/status_cache.js index b19489c1d..0a9f3abc5 100644 --- a/bookwyrm/static/js/status_cache.js +++ b/bookwyrm/static/js/status_cache.js @@ -203,6 +203,8 @@ let StatusCache = new (class { .forEach((item) => (item.disabled = false)); next_identifier = next_identifier == "complete" ? "read" : next_identifier; + next_identifier = + next_identifier == "stopped-reading-complete" ? "stopped-reading" : next_identifier; // Disable the current state button.querySelector( diff --git a/bookwyrm/templates/author/edit_author.html b/bookwyrm/templates/author/edit_author.html index 6f72b8700..b0727c43b 100644 --- a/bookwyrm/templates/author/edit_author.html +++ b/bookwyrm/templates/author/edit_author.html @@ -24,7 +24,7 @@ {% endif %} -