8000 feat: Configurable dark mode (#7329) · django-cms/django-cms@05b6d83 · GitHub
[go: up one dir, main page]

Skip to content

Commit 05b6d83

Browse files
fsbraunvinitkumarSimon KrullVinit Kumar
authored
feat: Configurable dark mode (#7329)
* Feat: Dark mode support, including input from @marksweb, bugfix for tooltips * Add: Color scheme configurable * Add: Toolbar toggle (always on) * Add: CMS_COLOR_SCHEME_TOGGLE setting * Add: color scheme toggle test * Fix: Only set color scheme in cms iframes * Add: Basic documentation of new settings * Fix: color scheme switch as css variables * Fix: Cascade settings into iframes of iframes (e.g., cms plugins inside ckeditor) * Fix: no toggle in collapsed toolbar Co-authored-by: Vinit Kumar <mail@vinitkumar.me> Co-authored-by: Simon Krull <krull@punkt.de> Co-authored-by: Vinit Kumar <vinit.kumar@kidskonnect.nl>
1 parent 4d1ec5c commit 05b6d83
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ Changelog
55
unreleased
66
==========
77

8-
* Added dark mode support to css
8+
* Added dark mode support to css, dark mode settings and toggle button
99
* Fix publishing of static placeholders outside of CMS pages
1010
* Allow to override the template rendered after a plugin has been saved.
1111
* Revert change to the toolbar sites menu to use ``http`` protocol.
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
HttpResponse, HttpResponseBadRequest, HttpResponseRedirect,
1212
)
1313
from django.http.request import QueryDict
14-
from django.urls import re_path
14+
from django.urls import Resolver404, re_path, resolve
1515
from django.utils.translation import override
1616

1717
from cms.admin.forms import RequestToolbarForm
@@ -97,6 +97,10 @@ def get_toolbar(self, request):
9797
request = copy.copy(request)
9898
request.GET = data
9999
request.current_page = current_page
100+
try:
101+
request.resolver_match = resolve(origin_url.path)
102+
except Resolver404:
103+
pass
100104
request.toolbar = CMSToolbar(request, request_path=origin_url.path, _async=True)
101105
request.toolbar.set_object(attached_obj or current_page)
102106
return HttpResponse(request.toolbar.render())
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,22 @@ def add_wizard_button(self):
9494
disabled=disabled,
9595
on_close=REFRESH_PAGE)
9696

97+
@toolbar_pool.register
98+
class AppearanceToolbar(CMSToolbar):
99+
"""
100+
Adds appearance switches, esp. for dark and light mode
101+
"""
102+
color_scheme_toggle = get_cms_setting('COLOR_SCHEME_TOGGLE')
103+
104+
def populate(self):
105+
if self.color_scheme_toggle:
106+
dark_mode_toggle = TemplateItem(
107+
template="cms/toolbar/items/dark_mode_toggle.html",
108+
side=self.toolbar.RIGHT,
109+
)
110+
self.toolbar.add_item(dark_mode_toggle)
111+
112+
97113

98114
@toolbar_pool.register
99115
class BasicToolbar(CMSToolbar):
Original file line numberDiff line numberDiff line change
@@ -1022,26 +1022,24 @@ class StructureBoard {
10221022
// refresh toolbar
10231023
var currentMode = CMS.settings.mode;
10241024

1025-
this._loadToolbar()
1026-
.done(newToolbar => {
1027-
CMS.API.Toolbar._refreshMarkup($(newToolbar).find('.cms-toolbar'));
1028-
})
1029-
.fail(() => Helpers.reloadBrowser());
1030-
10311025
if (currentMode === 'structure') {
10321026
this._requestcontent = null;
10331027

10341028
if (this._loadedContent && action !== 'COPY') {
10351029
this.updateContent();
1030+
return; // Toolbar loaded
10361031
}
1037-
return;
1038-
}
1039-
1040-
// invalidate the content mode
1041-
if (action !== 'COPY') {
1032+
} else if (action !== 'COPY') {
10421033
this._requestcontent = null;
10431034
this.updateContent();
1035+
return; // Toolbar loaded
1036+
10441037
}
1038+
this._loadToolbar()
1039+
.done(newToolbar => {
1040+
CMS.API.Toolbar._refreshMarkup($(newToolbar).find('.cms-toolbar'));
1041+
})
1042+
.fail(() => Helpers.reloadBrowser());
10451043
}
10461044

10471045
_propagateInvalidatedState(action, data) {
Original file line numberDiff line numberDiff line change
@@ -421,6 +421,12 @@ var Toolbar = new Class({
421421
this._debug();
422422
}
423423

424+
if (CMS.settings.color_scheme) {
425+
this.set_color_scheme (CMS.settings.color_scheme);
426+
} else if (CMS.config.color_scheme) {
427+
this.set_color_scheme (CMS.config.color_scheme);
428+
}
429+
424430
// check if there are messages and display them
425431
if (CMS.config.messages) {
426432
CMS.API.Messages.open({
@@ -616,6 +622,18 @@ var Toolbar = new Class({
616622
onSuccess: el.data('on-success')
617623
});
618624
break;
625+
case 'color-toggle':
626+
switch (this.get_color_scheme()) {
627+
case 'light':
628+
this.set_color_scheme('dark');
629+
break;
630+
case 'dark':
631+
this.set_color_scheme('light');
632+
break;
633+
default:
634+
break;
635+
}
636+
break;
619637
default:
620638
Helpers._getWindow().location.href = el.attr('href');
621639
}
@@ -756,6 +774,55 @@ var Toolbar = new Class({
756774
CMS.API.Clipboard.ui.triggers = $('.cms-clipboard-trigger a');
757775
CMS.API.Clipboard.ui.triggerRemove = $('.cms-clipboard-empty a');
758776
CMS.API.Clipboard._toolbarEvents();
777+
},
778+
779+
/**
780+
* Get color scheme either from :root[data-color-scheme] or user system setting
781+
*
782+
* @method get_color_scheme
783+
* @public
784+
* @returns {String}
785+
*/
786+
get_color_scheme: function () {
787+
let state = this.ui.body.attr('data-color-scheme');
788+
789+
if (!state && window.matchMedia) {
790+
if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
791+
state = 'dark'; // dark mode
792+
} else {
793+
state = 'light';
794+
}
795+
}
796+
return state;
797+
},
798+
799+
/**
800+
* Sets the color scheme for the current document and all iframes contained.
801+
*
802+
* @method set_color_scheme
803+
* @public
804+
* @param scheme {String}
805+
* @retiurns {void}
806+
*/
807+
808+
set_color_scheme: function (scheme) {
809+
CMS.API.Helpers.setSettings({ color_scheme: scheme });
810+
if (scheme === 'auto') {
811+
this.ui.body.removeAttr('data-color-scheme');
812+
this.ui.body.find('div.cms iframe').each(function(i, e) {
813+
delete e.contentDocument.documentElement.dataset.colorScheme;
814+
});
815+
} else {
816+
this.ui.body.attr('data-color-scheme', scheme);
817+
this.ui.body.find('div.cms iframe').each(function setFrameColorScheme(i, e) {
818+
if (e.contentDocument) {
819+
e.contentDocument.documentElement.dataset.colorScheme = scheme;
820+
// ckeditor (and potentially other apps) have iframes inside their admin forms
821+
// also set color scheme there
822+
$(e.contentDocument).find('iframe').each(setFrameColorScheme);
823+
}
824+
});
825+
}
759826
}
760827
});
761828

Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
@import "components/dialog";
1919
@import "components/content";
2020
@import "components/loader";
21+
@import "components/dark-mode-toggle";
2122

2223
// div.cms needs to beat .cms-reset a selectors
2324
div.cms {
@@ -33,8 +34,6 @@ div.cms {
3334
@import "components/pluginpicker";
3435
@import "components/shortcuts";
3536

36-
color-scheme: light dark;
37-
3837
*:not(.cms-modal):focus {
3938
outline: 2px dotted $gray-darker;
4039
outline-offset: -3px;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
@use "sass:math";
2+
3+
div.cms .cms-toolbar-item-dark-mode-toggle span.cms-icon.cms-toggle {
4+
font-size: 170%;
5+
line-height: 150%;
6+
color: var(--dca-gray-darkest);
7+
}
8+
9+
html[data-color-scheme="light"] .cms-toolbar-item-dark-mode-toggle .cms-toggle {
10+
@extend .cms-icon-moon;
11+
}
12+
13+
html[data-color-scheme="dark"] .cms-toolbar-item-dark-mode-toggle .cms-toggle {
14+
@extend .cms-icon-sun;
15+
}
16+
17+
html:not([data-color-scheme]) .cms-toolbar-item-dark-mode-toggle .cms-toggle {
18+
@extend .cms-icon-moon;
19+
}
20+
21+
@media (prefers-color-scheme: dark) {
22+
html:not([data-color-scheme]) .cms-toolbar-item-dark-mode-toggle .cms-toggle {
23+
// @extend .cms-icon-sun;
24+
}
25+
}
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
//##############################################################################
22
// DIALOG
3+
@use "sass:math";
34

45
// used in: /cms/admin/page/tree/copy_premissions
56
.cms-dialog {
@@ -9,7 +10,7 @@
910
z-index: z(dialog);
1011
box-sizing: border-box;
1112
width: $dialog-width;
12-
margin: -100px 0 0 (-$dialog-width/2);
13+
margin: -100px 0 0 math.div(-$dialog-width, 2);
1314
padding: $padding-large;
1415
border: 1px solid $gray-lighter;
1516
border-radius: $dialog-border-radius;