diff --git a/hc/accounts/admin.py b/hc/accounts/admin.py index 5bc79920..40e1444b 100644 --- a/hc/accounts/admin.py +++ b/hc/accounts/admin.py @@ -45,6 +45,7 @@ class ProfileFieldset(Fieldset): "email", "reports", "tz", + "theme", "next_report_date", "nag_period", "next_nag_date", diff --git a/hc/accounts/migrations/0038_profile_theme.py b/hc/accounts/migrations/0038_profile_theme.py new file mode 100644 index 00000000..09aefc9e --- /dev/null +++ b/hc/accounts/migrations/0038_profile_theme.py @@ -0,0 +1,18 @@ +# Generated by Django 3.2.4 on 2021-06-18 09:44 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('accounts', '0037_profile_tz'), + ] + + operations = [ + migrations.AddField( + model_name='profile', + name='theme', + field=models.CharField(blank=True, max_length=10, null=True), + ), + ] diff --git a/hc/accounts/models.py b/hc/accounts/models.py index 52167d2f..81b80fd6 100644 --- a/hc/accounts/models.py +++ b/hc/accounts/models.py @@ -73,6 +73,7 @@ class Profile(models.Model): deletion_notice_date = models.DateTimeField(null=True, blank=True) last_active_date = models.DateTimeField(null=True, blank=True) tz = models.CharField(max_length=36, default="UTC") + theme = models.CharField(max_length=10, null=True, blank=True) objects = ProfileManager() diff --git a/hc/accounts/urls.py b/hc/accounts/urls.py index 15341527..dd269c91 100644 --- a/hc/accounts/urls.py +++ b/hc/accounts/urls.py @@ -13,6 +13,7 @@ urlpatterns = [ name="hc-check-token", ), path("profile/", views.profile, name="hc-profile"), + path("profile/appearance/", views.appearance, name="hc-appearance"), path("profile/notifications/", views.notifications, name="hc-notifications"), path("close/", views.close, name="hc-close"), path( diff --git a/hc/accounts/views.py b/hc/accounts/views.py index 2f4e785c..8d5f2dc5 100644 --- a/hc/accounts/views.py +++ b/hc/accounts/views.py @@ -742,3 +742,23 @@ def login_webauthn(request): ctx = {"options": base64.b64encode(cbor.encode(options)).decode()} return render(request, "accounts/login_webauthn.html", ctx) + + +@login_required +def appearance(request): + profile = request.profile + + ctx = { + "page": "appearance", + "profile": profile, + "status": "default", + } + + if request.method == "POST": + theme = request.POST.get("theme", "") + if theme in ("", "dark"): + profile.theme = theme + profile.save() + ctx["status"] = "info" + + return render(request, "accounts/appearance.html", ctx) diff --git a/static/css/appearance.css b/static/css/appearance.css new file mode 100644 index 00000000..a1a30b8f --- /dev/null +++ b/static/css/appearance.css @@ -0,0 +1,11 @@ +.theme img { + border: 1px solid var(--border-color); + padding: 4px; + width: 100%; +} + +.theme .radio-container { + margin-top: 12px; + margin-left: 12px; +} + diff --git a/static/img/theme-dark.png b/static/img/theme-dark.png new file mode 100644 index 00000000..9c5400d9 Binary files /dev/null and b/static/img/theme-dark.png differ diff --git a/static/img/theme-light.png b/static/img/theme-light.png new file mode 100644 index 00000000..389e5c87 Binary files /dev/null and b/static/img/theme-light.png differ diff --git a/static/js/appearance.js b/static/js/appearance.js new file mode 100644 index 00000000..da938cb0 --- /dev/null +++ b/static/js/appearance.js @@ -0,0 +1,5 @@ +$(function () { + $("input[type=radio][name=theme]").change(function() { + document.body.classList.toggle("dark", this.value == "dark"); + }); +}); diff --git a/templates/accounts/appearance.html b/templates/accounts/appearance.html new file mode 100644 index 00000000..219d6214 --- /dev/null +++ b/templates/accounts/appearance.html @@ -0,0 +1,90 @@ +{% extends "base.html" %} +{% load compress hc_extras static tz %} + +{% block title %}Account Settings - {{ site_name }}{% endblock %} + +{% block content %} +