Merge pull request #1975 from bookwyrm-social/themes

Themes
This commit is contained in:
Mouse Reeve
2022-03-01 12:03:22 -08:00
committed by GitHub
50 changed files with 2049 additions and 746 deletions

View File

@ -8,8 +8,20 @@ def site_settings(request): # pylint: disable=unused-argument
if not request.is_secure():
request_protocol = "http://"
site = models.SiteSettings.objects.get()
theme = "css/themes/bookwyrm-light.scss"
if (
hasattr(request, "user")
and request.user.is_authenticated
and request.user.theme
):
theme = request.user.theme.path
elif site.default_theme:
theme = site.default_theme.path
return {
"site": models.SiteSettings.objects.get(),
"site": site,
"site_theme": theme,
"active_announcements": models.Announcement.active_announcements(),
"thumbnail_generation_enabled": settings.ENABLE_THUMBNAIL_GENERATION,
"media_full_url": settings.MEDIA_FULL_URL,

View File

@ -156,6 +156,7 @@ class EditUserForm(CustomForm):
"hide_follows",
"preferred_timezone",
"preferred_language",
"theme",
]
help_texts = {f: None for f in fields}
widgets = {
@ -455,6 +456,22 @@ class SiteForm(CustomForm):
}
class SiteThemeForm(CustomForm):
class Meta:
model = models.SiteSettings
fields = ["default_theme"]
class ThemeForm(CustomForm):
class Meta:
model = models.Theme
fields = ["name", "path"]
widgets = {
"name": forms.TextInput(attrs={"aria-describedby": "desc_name"}),
"path": forms.Select(attrs={"aria-describedby": "desc_path"}),
}
class AnnouncementForm(CustomForm):
class Meta:
model = models.Announcement

View File

@ -0,0 +1,68 @@
# Generated by Django 3.2.12 on 2022-02-27 17:52
from django.db import migrations, models
import django.db.models.deletion
def add_default_themes(apps, schema_editor):
"""add light and dark themes"""
db_alias = schema_editor.connection.alias
theme_model = apps.get_model("bookwyrm", "Theme")
theme_model.objects.using(db_alias).create(
name="BookWyrm Light",
path="css/themes/bookwyrm-light.scss",
)
theme_model.objects.using(db_alias).create(
name="BookWyrm Dark",
path="css/themes/bookwyrm-dark.scss",
)
class Migration(migrations.Migration):
dependencies = [
("bookwyrm", "0141_alter_report_status"),
]
operations = [
migrations.CreateModel(
name="Theme",
fields=[
(
"id",
models.AutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("created_date", models.DateTimeField(auto_now_add=True)),
("name", models.CharField(max_length=50, unique=True)),
("path", models.CharField(max_length=50, unique=True)),
],
),
migrations.AddField(
model_name="sitesettings",
name="default_theme",
field=models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.SET_NULL,
to="bookwyrm.theme",
),
),
migrations.AddField(
model_name="user",
name="theme",
field=models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.SET_NULL,
to="bookwyrm.theme",
),
),
migrations.RunPython(
add_default_themes, reverse_code=migrations.RunPython.noop
),
]

View File

@ -0,0 +1,13 @@
# Generated by Django 3.2.12 on 2022-02-28 21:28
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
("bookwyrm", "0142_auto_20220227_1752"),
("bookwyrm", "0142_user_hide_follows"),
]
operations = []

View File

@ -0,0 +1,39 @@
# Generated by Django 3.2.12 on 2022-03-01 18:46
from django.db import migrations, models
def remove_white(apps, schema_editor):
"""don't hardcode white announcements"""
db_alias = schema_editor.connection.alias
announcement_model = apps.get_model("bookwyrm", "Announcement")
announcement_model.objects.using(db_alias).filter(display_type="white-ter").update(
display_type=None
)
class Migration(migrations.Migration):
dependencies = [
("bookwyrm", "0143_merge_0142_auto_20220227_1752_0142_user_hide_follows"),
]
operations = [
migrations.AlterField(
model_name="announcement",
name="display_type",
field=models.CharField(
blank=True,
choices=[
("primary-light", "Primary"),
("success-light", "Success"),
("link-light", "Link"),
("warning-light", "Warning"),
("danger-light", "Danger"),
],
max_length=20,
null=True,
),
),
migrations.RunPython(remove_white, reverse_code=migrations.RunPython.noop),
]

View File

@ -26,7 +26,7 @@ from .group import Group, GroupMember, GroupMemberInvitation
from .import_job import ImportJob, ImportItem
from .site import SiteSettings, SiteInvite
from .site import SiteSettings, Theme, SiteInvite
from .site import PasswordReset, InviteRequest
from .announcement import Announcement
from .antispam import EmailBlocklist, IPBlocklist, AutoMod, automod_task

View File

@ -8,7 +8,6 @@ from .base_model import BookWyrmModel
DisplayTypes = [
("white-ter", _("None")),
("primary-light", _("Primary")),
("success-light", _("Success")),
("link-light", _("Link")),
@ -28,11 +27,7 @@ class Announcement(BookWyrmModel):
end_date = models.DateTimeField(blank=True, null=True)
active = models.BooleanField(default=True)
display_type = models.CharField(
max_length=20,
blank=False,
null=False,
choices=DisplayTypes,
default="white-ter",
max_length=20, choices=DisplayTypes, null=True, blank=True
)
@classmethod

View File

@ -24,6 +24,9 @@ class SiteSettings(models.Model):
)
instance_description = models.TextField(default="This instance has no description.")
instance_short_description = models.CharField(max_length=255, blank=True, null=True)
default_theme = models.ForeignKey(
"Theme", null=True, blank=True, on_delete=models.SET_NULL
)
# admin setup options
install_mode = models.BooleanField(default=False)
@ -104,6 +107,18 @@ class SiteSettings(models.Model):
super().save(*args, **kwargs)
class Theme(models.Model):
"""Theme files"""
created_date = models.DateTimeField(auto_now_add=True)
name = models.CharField(max_length=50, unique=True)
path = models.CharField(max_length=50, unique=True)
def __str__(self):
# pylint: disable=invalid-str-returned
return self.name
class SiteInvite(models.Model):
"""gives someone access to create an account on the instance"""

View File

@ -136,6 +136,7 @@ class User(OrderedCollectionPageMixin, AbstractUser):
updated_date = models.DateTimeField(auto_now=True)
last_active_date = models.DateTimeField(default=timezone.now)
manually_approves_followers = fields.BooleanField(default=False)
theme = models.ForeignKey("Theme", null=True, blank=True, on_delete=models.SET_NULL)
hide_follows = fields.BooleanField(default=False)
# options to turn features on and off

View File

@ -1,7 +1,4 @@
@charset "utf-8";
@import "instance-settings";
@import "themes/light.scss";
@import "vendor/bulma/bulma.sass";
@import "vendor/icons.css";
@import "bookwyrm/all.scss";

View File

@ -115,7 +115,7 @@ button .button-invisible-overlay {
align-items: center;
flex-direction: column;
justify-content: center;
background: rgba($scheme-invert, 0.66);
background: $invisible-overlay-background-color;
color: white;
opacity: 0;
transition: opacity 0.2s ease;

View File

@ -53,7 +53,7 @@ details.dropdown .dropdown-menu a:focus-visible {
@media only screen and (max-width: 768px) {
details.dropdown[open] summary.dropdown-trigger::before {
background-color: rgba($scheme-invert, 0.5);
background-color: $modal-background-background-color;
z-index: 30;
}

View File

@ -3,7 +3,7 @@
.toggle-button[aria-pressed="true"],
.toggle-button[aria-pressed="true"]:hover {
background-color: hsl(171deg, 100%, 41%);
background-color: $primary;
color: white;
}

View File

@ -0,0 +1,84 @@
@import "../vendor/bulma/sass/utilities/initial-variables.sass";
/* Colors
******************************************************************************/
/* states */
$primary: #005e50;
$primary-light: #1d2b28;
$info: #1f4666;
$success: #246447;
$warning: #8b6c15;
$danger: #872538;
$danger-light: #481922;
$light: #393939;
$red: #ffa1b4;
/* book cover standins */
$no-cover-color: #002549;
/* background colors */
$scheme-main: rgb(24, 27, 28);
$scheme-invert: #fff;
$scheme-main-bis: rgb(28, 30, 32);
$scheme-main-ter: rgb(32, 34, 36);
$background-body: rgb(24, 27, 28);
$background-secondary: rgb(28, 30, 32);
$background-tertiary: rgb(32, 34, 36);
$modal-background-background-color: rgba($black, 0.8);
/* highlight colors */
$primary-highlight: $primary;
$info-highlight: $info;
$success-highlight: $success;
/* borders */
$border: #2b3031;
$border-light: #444;
$border-hover: #51595d;
/* text */
$text: $grey-lightest;
$text-light: $grey-lighter;
$text-strong: $white-ter;
/* links */
$link: #2e7eb9;
$link-background: $background-tertiary;
$link-hover: $white-bis;
$link-hover-border: #51595d;
$link-focus: $white-bis;
$link-active: $white-bis;
/* bulma overrides */
$background: $background-secondary;
$menu-item-active-background-color: $link-background;
$navbar-dropdown-item-hover-color: $white;
/* These element's colors are hardcoded, probably a bug in bulma? */
@media screen and (min-width: 769px) {
.navbar-dropdown {
box-shadow: 0 8px 8px rgba($black, 0.2) !important;
}
}
@media screen and (max-width: 768px) {
.navbar-menu {
box-shadow: 0 8px 8px rgba($black, 0.2) !important;
}
}
/* misc */
$shadow: 0 0.5em 1em -0.125em rgba($black, 0.2), 0 0px 0 1px rgba($black, 0.02);
$card-header-shadow: 0 0.125em 0.25em rgba($black, 0.1);
$invisible-overlay-background-color: rgba($black, 0.66);
$progress-value-background-color: $border-light;
/* Fonts
******************************************************************************/
$family-primary: $family-sans-serif;
$family-secondary: $family-sans-serif;
@import "../bookwyrm.scss";
@import "../vendor/icons.css";

View File

@ -47,7 +47,13 @@ $link-active: $grey-darker;
$background: $background-secondary;
$menu-item-active-background-color: $link-background;
/* misc */
$invisible-overlay-background-color: rgba($scheme-invert, 0.66);
/* Fonts
******************************************************************************/
$family-primary: $family-sans-serif;
$family-secondary: $family-sans-serif;
@import "../bookwyrm.scss";
@import "../vendor/icons.css";

View File

@ -1,55 +0,0 @@
@import "../vendor/bulma/sass/utilities/derived-variables.sass";
/* Colors
******************************************************************************/
/* states */
$primary: #016a5b;
$info: #1f4666;
$success: #246447;
$warning: #8b6c15;
$danger: #872538;
/* book cover standins */
$no-cover-color: #002549;
/* background colors */
$scheme-main: $grey-darker;
$scheme-main-bis: $black-ter;
$background-body: $grey-darker;
$background-secondary: $grey-dark;
$background-tertiary: #555;
/* highlight colors */
$primary-highlight: $primary;
$info-highlight: $info;
$success-highlight: $success;
/* borders */
$border: $grey;
$border-hover: $grey-light;
$border-light: $grey;
$border-light-hover: $grey-light;
/* text */
$text: $grey-lightest;
$text-light: $grey-lighter;
$text-strong: $white-ter;
/* links */
$link: $white;
$link-background: $background-tertiary;
$link-hover: $white-bis;
$link-focus: $white-bis;
$link-active: $white-bis;
/* misc */
/* bulma overrides */
$background: $background-secondary;
$menu-item-active-background-color: $link-background;
/* Fonts
******************************************************************************/
$family-primary: $family-sans-serif;
$family-secondary: $family-sans-serif;

View File

@ -8,7 +8,7 @@
<head>
<title>{% block title %}BookWyrm{% endblock %} - {{ site.name }}</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="{% sass_src 'css/bookwyrm.scss' %}" rel="stylesheet" type="text/css" />
<link href="{% sass_src site_theme %}" rel="stylesheet" type="text/css" />
<link rel="search" type="application/opensearchdescription+xml" href="{% url 'opensearch' %}" title="{% blocktrans with site_name=site.name %}{{ site_name }} search{% endblocktrans %}" />

View File

@ -10,7 +10,7 @@
{% block profile-tabs %}
<ul class="menu-list">
<li><a href="#profile">{% trans "Profile" %}</a></li>
<li><a href="#display-preferences">{% trans "Display preferences" %}</a></li>
<li><a href="#display-preferences">{% trans "Display" %}</a></li>
<li><a href="#privacy">{% trans "Privacy" %}</a></li>
</ul>
{% endblock %}
@ -61,7 +61,7 @@
<hr aria-hidden="true">
<section class="block" id="display-preferences">
<h2 class="title is-4">{% trans "Display preferences" %}</h2>
<h2 class="title is-4">{% trans "Display" %}</h2>
<div class="box">
<div class="field">
<label class="checkbox label" for="id_show_goal">
@ -97,6 +97,12 @@
{{ form.preferred_language }}
</div>
</div>
<div class="field">
<label class="label" for="id_them">{% trans "Theme:" %}</label>
<div class="select">
{{ form.theme }}
</div>
</div>
</div>
</section>

View File

@ -86,6 +86,10 @@
<a href="{{ url }}"{% if url in request.path %} class="is-active" aria-selected="true"{% endif %}>{% trans "Site Settings" %}</a>
{% block site-subtabs %}{% endblock %}
</li>
<li>
{% url 'settings-themes' as url %}
<a href="{{ url }}"{% if url in request.path %} class="is-active" aria-selected="true"{% endif %}>{% trans "Themes" %}</a>
</li>
</ul>
{% endif %}
</nav>

View File

@ -8,7 +8,7 @@
{% block site-subtabs %}
<ul class="menu-list">
<li><a href="#instance-info">{% trans "Instance Info" %}</a></li>
<li><a href="#images">{% trans "Images" %}</a></li>
<li><a href="#display">{% trans "Display" %}</a></li>
<li><a href="#footer">{% trans "Footer Content" %}</a></li>
<li><a href="#registration">{% trans "Registration" %}</a></li>
</ul>
@ -33,7 +33,12 @@
</div>
{% endif %}
<form action="{% url 'settings-site' %}" method="POST" class="content" enctype="multipart/form-data">
<form
action="{% url 'settings-site' %}"
method="POST"
class="content"
enctype="multipart/form-data"
>
{% csrf_token %}
<section class="block" id="instance_info">
<h2 class="title is-4">{% trans "Instance Info" %}</h2>
@ -68,20 +73,33 @@
<hr aria-hidden="true">
<section class="block" id="images">
<h2 class="title is-4">{% trans "Images" %}</h2>
<div class="box is-flex">
<div>
<label class="label" for="id_logo">{% trans "Logo:" %}</label>
{{ site_form.logo }}
<section class="block" id="display">
<h2 class="title is-4">{% trans "Display" %}</h2>
<div class="box">
<h3 class="title is-5">{% trans "Images" %}</h3>
<div class="block is-flex">
<div>
<label class="label" for="id_logo">{% trans "Logo:" %}</label>
{{ site_form.logo }}
</div>
<div>
<label class="label" for="id_logo_small">{% trans "Logo small:" %}</label>
{{ site_form.logo_small }}
</div>
<div>
<label class="label" for="id_favicon">{% trans "Favicon:" %}</label>
{{ site_form.favicon }}
</div>
</div>
<div>
<label class="label" for="id_logo_small">{% trans "Logo small:" %}</label>
{{ site_form.logo_small }}
</div>
<div>
<label class="label" for="id_favicon">{% trans "Favicon:" %}</label>
{{ site_form.favicon }}
<h3 class="title is-5">{% trans "Themes" %}</h3>
<div class="block">
<label class="label" for="id_default_theme">
{% trans "Default theme:" %}
</label>
<div class="select">
{{ site_form.default_theme }}
</div>
</div>
</div>
</section>

View File

@ -0,0 +1,140 @@
{% extends 'settings/layout.html' %}
{% load i18n %}
{% block title %}{% trans "Themes" %}{% endblock %}
{% block header %}{% trans "Themes" %}{% endblock %}
{% block breadcrumbs %}
<a class="subtitle help is-link" href="{% url 'settings-site' %}/#display">
{% trans "Set instance default theme" %}
</a>
{% endblock %}
{% block panel %}
{% if success %}
<div class="notification is-success is-light">
<span class="icon icon-check" aria-hidden="true"></span>
<span>
{% trans "Successfully added theme" %}
</span>
</div>
{% endif %}
<section class="block">
<div class="notification content">
<h2 class="title is-5">{% trans "How to add a theme" %}</h2>
<ol>
<li>
{% trans "Copy the theme file into the <code>bookwyrm/static/css/themes</code> directory on your server from the command line." %}
</li>
<li>
{% trans "Run <code>./bw-dev compilescss</code>." %}
</li>
<li>
{% trans "Add the file name using the form below to make it available in the application interface." %}
</li>
</ol>
</div>
</section>
<section class="block content">
<h2 class="title is-4">{% trans "Add theme" %}</h2>
{% if theme_form.errors %}
<div class="notification is-danger is-light">
<span class="icon icon-x" aria-hidden="true"></span>
<span>
{% trans "Unable to save theme" %}
</span>
</div>
{% endif %}
<form
method="POST"
action="{% url 'settings-themes' %}"
class="box"
enctype="multipart/form-data"
>
{% if not choices %}
<div class="notification is-warning">
{% trans "No available theme files detected" %}
</div>
{% endif %}
<fieldset {% if not choices %}disabled{% endif %}>
{% csrf_token %}
<div class="columns">
<div class="column is-half">
<label class="label" for="id_name">
{% trans "Theme name" %}
</label>
<div class="control">
{{ theme_form.name }}
{% include 'snippets/form_errors.html' with errors_list=theme_form.name.errors id="desc_name" %}
</div>
</div>
<div class="column">
<label class="label" for="id_path">
{% trans "Theme filename" %}
</label>
<div class="control">
<div class="select">
<select
name="path"
aria-describedby="desc_path"
class=""
id="id_path"
>
{% for choice in choices %}
<option value="{{ choice }}">
{{ choice }}
</option>
{% endfor %}
</select>
</div>
{% include 'snippets/form_errors.html' with errors_list=theme_form.path.errors id="desc_path" %}
</div>
</div>
</div>
<button type="submit" class="button">{% trans "Add theme" %}</button>
</fieldset>
</form>
</section>
<section class="block content">
<h2 class="title is-4">{% trans "Available Themes" %}</h2>
<div class="table-container">
<table class="table is-striped">
<tr>
<th>
{% trans "Theme name" %}
</th>
<th>
{% trans "File" %}
</th>
<th>
{% trans "Actions" %}
</th>
</tr>
{% for theme in themes %}
<tr>
<td>{{ theme.name }}</td>
<td><code>{{ theme.path }}</code></td>
<td>
<form method="POST" action="{% url 'settings-themes-delete' theme.id %}">
{% csrf_token %}
<button type="submit" class="button is-danger is-light is-small">
<span class="icon icon-x" aria-hideen="true"></span>
<span>{% trans "Remove theme" %}</span>
</button>
</form>
</td>
</tr>
{% endfor %}
</table>
</div>
</section>
{% endblock %}

View File

@ -1,7 +1,7 @@
{% 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 has-background-{{ announcement.display_type }}"
class="notification mb-1 p-3{% if not admin_mode %} is-hidden{% endif %} transition-y {% if announcement.display_type %}has-background-{{ announcement.display_type }}{% endif %}"
{% if not admin_mode %}data-hide="hide_announcement_{{ announcement.id }}"{% endif %}
>
<details>

View File

@ -0,0 +1,86 @@
""" test for context processor """
from unittest.mock import patch
from django.contrib.auth.models import AnonymousUser
from django.test import TestCase
from django.test.client import RequestFactory
from bookwyrm import models
from bookwyrm.context_processors import site_settings
class ContextProcessor(TestCase):
"""pages you land on without really trying"""
def setUp(self):
"""we need basic test data and mocks"""
self.factory = RequestFactory()
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
), patch("bookwyrm.lists_stream.populate_lists_task.delay"):
self.local_user = models.User.objects.create_user(
"mouse@local.com",
"mouse@mouse.mouse",
"password",
local=True,
localname="mouse",
)
self.anonymous_user = AnonymousUser
self.anonymous_user.is_authenticated = False
self.site = models.SiteSettings.objects.create()
def test_theme_unset(self):
"""logged in user, no selected theme"""
request = self.factory.get("")
request.user = self.local_user
settings = site_settings(request)
self.assertEqual(settings["site_theme"], "css/themes/bookwyrm-light.scss")
def test_theme_unset_logged_out(self):
"""logged out user, no selected theme"""
request = self.factory.get("")
request.user = self.anonymous_user
settings = site_settings(request)
self.assertEqual(settings["site_theme"], "css/themes/bookwyrm-light.scss")
def test_theme_instance_default(self):
"""logged in user, instance default theme"""
self.site.default_theme = models.Theme.objects.get(name="BookWyrm Dark")
self.site.save()
request = self.factory.get("")
request.user = self.local_user
settings = site_settings(request)
self.assertEqual(settings["site_theme"], "css/themes/bookwyrm-dark.scss")
def test_theme_instance_default_logged_out(self):
"""logged out user, instance default theme"""
self.site.default_theme = models.Theme.objects.get(name="BookWyrm Dark")
self.site.save()
request = self.factory.get("")
request.user = self.anonymous_user
settings = site_settings(request)
self.assertEqual(settings["site_theme"], "css/themes/bookwyrm-dark.scss")
def test_theme_user_set(self):
"""logged in user, user theme"""
self.local_user.theme = models.Theme.objects.get(name="BookWyrm Dark")
self.local_user.save(broadcast=False, update_fields=["theme"])
request = self.factory.get("")
request.user = self.local_user
settings = site_settings(request)
self.assertEqual(settings["site_theme"], "css/themes/bookwyrm-dark.scss")
def test_theme_user_set_instance_default(self):
"""logged in user, instance default theme"""
self.site.default_theme = models.Theme.objects.get(name="BookWyrm Dark")
self.site.save()
self.local_user.theme = models.Theme.objects.get(name="BookWyrm Light")
self.local_user.save(broadcast=False, update_fields=["theme"])
request = self.factory.get("")
request.user = self.local_user
settings = site_settings(request)
self.assertEqual(settings["site_theme"], "css/themes/bookwyrm-light.scss")

View File

@ -86,6 +86,12 @@ urlpatterns = [
r"^settings/dashboard/?$", views.Dashboard.as_view(), name="settings-dashboard"
),
re_path(r"^settings/site-settings/?$", views.Site.as_view(), name="settings-site"),
re_path(r"^settings/themes/?$", views.Themes.as_view(), name="settings-themes"),
re_path(
r"^settings/themes/(?P<theme_id>\d+)/delete/?$",
views.delete_theme,
name="settings-themes-delete",
),
re_path(
r"^settings/announcements/?$",
views.Announcements.as_view(),

View File

@ -21,6 +21,7 @@ from .admin.reports import (
moderator_delete_user,
)
from .admin.site import Site
from .admin.themes import Themes, delete_theme
from .admin.user_admin import UserAdmin, UserAdminList
# user preferences

View File

@ -29,7 +29,7 @@ class Site(View):
if not form.is_valid():
data = {"site_form": form}
return TemplateResponse(request, "settings/site.html", data)
form.save()
site = form.save()
data = {"site_form": forms.SiteForm(instance=site), "success": True}
return TemplateResponse(request, "settings/site.html", data)

View File

@ -0,0 +1,59 @@
""" manage themes """
from django.contrib.auth.decorators import login_required, permission_required
from django.contrib.staticfiles.utils import get_files
from django.contrib.staticfiles.storage import StaticFilesStorage
from django.shortcuts import get_object_or_404, redirect
from django.template.response import TemplateResponse
from django.utils.decorators import method_decorator
from django.views import View
from django.views.decorators.http import require_POST
from bookwyrm import forms, models
# pylint: disable= no-self-use
@method_decorator(login_required, name="dispatch")
@method_decorator(
permission_required("bookwyrm.edit_instance_settings", raise_exception=True),
name="dispatch",
)
class Themes(View):
"""manage things like the instance name"""
def get(self, request):
"""view existing themes and set defaults"""
return TemplateResponse(request, "settings/themes.html", get_view_data())
def post(self, request):
"""edit the site settings"""
form = forms.ThemeForm(request.POST, request.FILES)
if form.is_valid():
form.save()
data = get_view_data()
if not form.is_valid():
data["theme_form"] = form
else:
data["success"] = True
return TemplateResponse(request, "settings/themes.html", data)
def get_view_data():
"""data for view"""
choices = list(get_files(StaticFilesStorage(), location="css/themes"))
current = models.Theme.objects.values_list("path", flat=True)
return {
"themes": models.Theme.objects.all(),
"choices": [c for c in choices if c not in current and c[-5:] == ".scss"],
"theme_form": forms.ThemeForm(),
}
@require_POST
@permission_required("bookwyrm.edit_instance_settings", raise_exception=True)
# pylint: disable=unused-argument
def delete_theme(request, theme_id):
"""Remove a theme"""
get_object_or_404(models.Theme, id=theme_id).delete()
return redirect("settings-themes")