summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSarah Abderemane <sarahabderemane@gmail.com>2022-07-13 13:51:06 +0200
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2022-08-02 17:14:24 +0200
commitbc7aa2a5e91cf65fc7510edaf1776528c7ad07b4 (patch)
treee4c1a1348a6c284446c6fc8a23ca6c25e24f90f1
parent5028a02352cb1fe3e64d63a614912ef694838862 (diff)
downloaddjango-bc7aa2a5e91cf65fc7510edaf1776528c7ad07b4.tar.gz
Fixed #33690 -- Added switch button for dark mode in the admin.
-rw-r--r--django/contrib/admin/static/admin/css/base.css3
-rw-r--r--django/contrib/admin/static/admin/css/dark_mode.css84
-rw-r--r--django/contrib/admin/static/admin/js/theme.js56
-rw-r--r--django/contrib/admin/templates/admin/base.html10
-rw-r--r--django/contrib/admin/templates/admin/base_site.html3
-rw-r--r--django/contrib/admin/templates/admin/color_theme_toggle.html12
-rw-r--r--django/contrib/admin/templates/registration/password_change_done.html1
-rw-r--r--django/contrib/admin/templates/registration/password_change_form.html1
-rw-r--r--docs/releases/4.2.txt3
9 files changed, 171 insertions, 2 deletions
diff --git a/django/contrib/admin/static/admin/css/base.css b/django/contrib/admin/static/admin/css/base.css
index 8cff31d891..bc077b8f84 100644
--- a/django/contrib/admin/static/admin/css/base.css
+++ b/django/contrib/admin/static/admin/css/base.css
@@ -5,6 +5,7 @@
@import url(fonts.css);
/* VARIABLE DEFINITIONS */
+html[data-theme="light"],
:root {
--primary: #79aec8;
--secondary: #417690;
@@ -900,7 +901,7 @@ a.deletelink:focus, a.deletelink:hover {
}
#branding {
- float: left;
+ display: flex;
}
#branding h1 {
diff --git a/django/contrib/admin/static/admin/css/dark_mode.css b/django/contrib/admin/static/admin/css/dark_mode.css
index 547717cc6b..7407447398 100644
--- a/django/contrib/admin/static/admin/css/dark_mode.css
+++ b/django/contrib/admin/static/admin/css/dark_mode.css
@@ -31,3 +31,87 @@
--close-button-hover-bg: #666666;
}
}
+
+
+html[data-theme="dark"] {
+ --primary: #264b5d;
+ --primary-fg: #f7f7f7;
+
+ --body-fg: #eeeeee;
+ --body-bg: #121212;
+ --body-quiet-color: #e0e0e0;
+ --body-loud-color: #ffffff;
+
+ --breadcrumbs-link-fg: #e0e0e0;
+ --breadcrumbs-bg: var(--primary);
+
+ --link-fg: #81d4fa;
+ --link-hover-color: #4ac1f7;
+ --link-selected-fg: #6f94c6;
+
+ --hairline-color: #272727;
+ --border-color: #353535;
+
+ --error-fg: #e35f5f;
+ --message-success-bg: #006b1b;
+ --message-warning-bg: #583305;
+ --message-error-bg: #570808;
+
+ --darkened-bg: #212121;
+ --selected-bg: #1b1b1b;
+ --selected-row: #00363a;
+
+ --close-button-bg: #333333;
+ --close-button-hover-bg: #666666;
+}
+
+/* THEME SWITCH */
+.theme-toggle {
+ cursor: pointer;
+ border: none;
+ padding: 0;
+ background: transparent;
+ vertical-align: middle;
+ margin-left: 5px;
+ margin-top: -1px;
+}
+
+.theme-toggle svg {
+ vertical-align: middle;
+ height: 1rem;
+ width: 1rem;
+ display: none;
+}
+
+/* ICONS */
+.theme-toggle svg.theme-icon-when-auto,
+.theme-toggle svg.theme-icon-when-dark,
+.theme-toggle svg.theme-icon-when-light {
+ fill: var(--header-link-color);
+ color: var(--header-bg);
+}
+
+html[data-theme="auto"] .theme-toggle svg.theme-icon-when-auto {
+ display: block;
+}
+
+html[data-theme="dark"] .theme-toggle svg.theme-icon-when-dark {
+ display: block;
+}
+
+html[data-theme="light"] .theme-toggle svg.theme-icon-when-light {
+ display: block;
+}
+
+.visually-hidden {
+ position: absolute;
+ width: 1px;
+ height: 1px;
+ padding: 0;
+ overflow: hidden;
+ clip: rect(0,0,0,0);
+ white-space: nowrap;
+ border: 0;
+ color: var(--body-fg);
+ background-color: var(--body-bg);
+}
diff --git a/django/contrib/admin/static/admin/js/theme.js b/django/contrib/admin/static/admin/js/theme.js
new file mode 100644
index 0000000000..794cd15f70
--- /dev/null
+++ b/django/contrib/admin/static/admin/js/theme.js
@@ -0,0 +1,56 @@
+'use strict';
+{
+ window.addEventListener('load', function(e) {
+
+ function setTheme(mode) {
+ if (mode !== "light" && mode !== "dark" && mode !== "auto") {
+ console.error(`Got invalid theme mode: ${mode}. Resetting to auto.`);
+ mode = "auto";
+ }
+ document.documentElement.dataset.theme = mode;
+ localStorage.setItem("theme", mode);
+ }
+
+ function cycleTheme() {
+ const currentTheme = localStorage.getItem("theme") || "auto";
+ const prefersDark = window.matchMedia("(prefers-color-scheme: dark)").matches;
+
+ if (prefersDark) {
+ // Auto (dark) -> Light -> Dark
+ if (currentTheme === "auto") {
+ setTheme("light");
+ } else if (currentTheme === "light") {
+ setTheme("dark");
+ } else {
+ setTheme("auto");
+ }
+ } else {
+ // Auto (light) -> Dark -> Light
+ if (currentTheme === "auto") {
+ setTheme("dark");
+ } else if (currentTheme === "dark") {
+ setTheme("light");
+ } else {
+ setTheme("auto");
+ }
+ }
+ }
+
+ function initTheme() {
+ // set theme defined in localStorage if there is one, or fallback to auto mode
+ const currentTheme = localStorage.getItem("theme");
+ currentTheme ? setTheme(currentTheme) : setTheme("auto");
+ }
+
+ function setupTheme() {
+ // Attach event handlers for toggling themes
+ const buttons = document.getElementsByClassName("theme-toggle");
+ Array.from(buttons).forEach((btn) => {
+ btn.addEventListener("click", cycleTheme);
+ });
+ initTheme();
+ }
+
+ setupTheme();
+ });
+}
diff --git a/django/contrib/admin/templates/admin/base.html b/django/contrib/admin/templates/admin/base.html
index cd4b759256..19d89e8b47 100644
--- a/django/contrib/admin/templates/admin/base.html
+++ b/django/contrib/admin/templates/admin/base.html
@@ -6,6 +6,7 @@
<link rel="stylesheet" href="{% block stylesheet %}{% static "admin/css/base.css" %}{% endblock %}">
{% block dark-mode-vars %}
<link rel="stylesheet" href="{% static "admin/css/dark_mode.css" %}">
+ <script src="{% static "admin/js/theme.js" %}" defer></script>
{% endblock %}
{% if not is_popup and is_nav_sidebar_enabled %}
<link rel="stylesheet" href="{% static "admin/css/nav_sidebar.css" %}">
@@ -59,6 +60,7 @@
{% csrf_token %}
<button type="submit">{% translate 'Log out' %}</button>
</form>
+ {% include "admin/color_theme_toggle.html" %}
{% endblock %}
</div>
{% endif %}
@@ -107,5 +109,13 @@
</div>
</div>
<!-- END Container -->
+
+<!-- SVGs -->
+<svg xmlns="http://www.w3.org/2000/svg">
+ <symbol viewBox="0 0 24 24" width="16" height="16" id="icon-auto"><path d="M0 0h24v24H0z" fill="currentColor"/><path d="M12 22C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10-4.477 10-10 10zm0-2V4a8 8 0 1 0 0 16z"/></symbol>
+ <symbol viewBox="0 0 24 24" width="16" height="16" id="icon-moon"><path d="M0 0h24v24H0z" fill="currentColor"/><path d="M10 7a7 7 0 0 0 12 4.9v.1c0 5.523-4.477 10-10 10S2 17.523 2 12 6.477 2 12 2h.1A6.979 6.979 0 0 0 10 7zm-6 5a8 8 0 0 0 15.062 3.762A9 9 0 0 1 8.238 4.938 7.999 7.999 0 0 0 4 12z"/></symbol>
+ <symbol viewBox="0 0 24 24" width="16" height="16" id="icon-sun"><path d="M0 0h24v24H0z" fill="currentColor"/><path d="M12 18a6 6 0 1 1 0-12 6 6 0 0 1 0 12zm0-2a4 4 0 1 0 0-8 4 4 0 0 0 0 8zM11 1h2v3h-2V1zm0 19h2v3h-2v-3zM3.515 4.929l1.414-1.414L7.05 5.636 5.636 7.05 3.515 4.93zM16.95 18.364l1.414-1.414 2.121 2.121-1.414 1.414-2.121-2.121zm2.121-14.85l1.414 1.415-2.121 2.121-1.414-1.414 2.121-2.121zM5.636 16.95l1.414 1.414-2.121 2.121-1.414-1.414 2.121-2.121zM23 11v2h-3v-2h3zM4 11v2H1v-2h3z"/></symbol>
+</svg>
+<!-- END SVGs -->
</body>
</html>
diff --git a/django/contrib/admin/templates/admin/base_site.html b/django/contrib/admin/templates/admin/base_site.html
index 9e8cc604c5..d83ac0df9b 100644
--- a/django/contrib/admin/templates/admin/base_site.html
+++ b/django/contrib/admin/templates/admin/base_site.html
@@ -4,6 +4,9 @@
{% block branding %}
<h1 id="site-name"><a href="{% url 'admin:index' %}">{{ site_header|default:_('Django administration') }}</a></h1>
+{% if user.is_anonymous %}
+ {% include "admin/color_theme_toggle.html" %}
+{% endif %}
{% endblock %}
{% block nav-global %}{% endblock %}
diff --git a/django/contrib/admin/templates/admin/color_theme_toggle.html b/django/contrib/admin/templates/admin/color_theme_toggle.html
new file mode 100644
index 0000000000..8df59f58b0
--- /dev/null
+++ b/django/contrib/admin/templates/admin/color_theme_toggle.html
@@ -0,0 +1,12 @@
+<button class="theme-toggle">
+ <div class="visually-hidden">Toggle Light / Dark / Auto color theme</div>
+ <svg class="theme-icon-when-auto">
+ <use xlink:href="#icon-auto" />
+ </svg>
+ <svg class="theme-icon-when-dark">
+ <use xlink:href="#icon-moon" />
+ </svg>
+ <svg class="theme-icon-when-light">
+ <use xlink:href="#icon-sun" />
+ </svg>
+</button>
diff --git a/django/contrib/admin/templates/registration/password_change_done.html b/django/contrib/admin/templates/registration/password_change_done.html
index cb017825f2..784ab37278 100644
--- a/django/contrib/admin/templates/registration/password_change_done.html
+++ b/django/contrib/admin/templates/registration/password_change_done.html
@@ -6,6 +6,7 @@
{% csrf_token %}
<button type="submit">{% translate 'Log out' %}</button>
</form>
+ {% include "admin/color_theme_toggle.html" %}
{% endblock %}
{% block breadcrumbs %}
<div class="breadcrumbs">
diff --git a/django/contrib/admin/templates/registration/password_change_form.html b/django/contrib/admin/templates/registration/password_change_form.html
index 37e5ddd5a8..3f5acdc186 100644
--- a/django/contrib/admin/templates/registration/password_change_form.html
+++ b/django/contrib/admin/templates/registration/password_change_form.html
@@ -7,6 +7,7 @@
{% csrf_token %}
<button type="submit">{% translate 'Log out' %}</button>
</form>
+ {% include "admin/color_theme_toggle.html" %}
{% endblock %}
{% block breadcrumbs %}
<div class="breadcrumbs">
diff --git a/docs/releases/4.2.txt b/docs/releases/4.2.txt
index 452aebdd6b..fefba040e2 100644
--- a/docs/releases/4.2.txt
+++ b/docs/releases/4.2.txt
@@ -32,7 +32,8 @@ Minor features
:mod:`django.contrib.admin`
~~~~~~~~~~~~~~~~~~~~~~~~~~~
-* ...
+* The light or dark color theme of the admin can now be toggled in the UI, as
+ well as being set to follow the system setting.
:mod:`django.contrib.admindocs`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~