night-mode: Add custom CSS through JS.

This adds custom CSS through JavaScript for things that do not
scope well and will override other inherited styles.

This should ONLY be used for problematic CSS that has no obvious
or easy CSS-only solution.

(Specifically, we need this for the "default link" styling, which is
hard to override because we don't want to start winning ties due to
specificity that we would not have won in the light theme).
This commit is contained in:
Brock Whittaker 2017-11-29 17:31:21 -08:00 committed by Tim Abbott
parent 6d887dc6ee
commit e0236646bf
7 changed files with 111 additions and 11 deletions

View File

@ -34,6 +34,7 @@
"server_events_dispatch": false,
"ui": false,
"ui_report": false,
"night_mode": false,
"ui_util": false,
"lightbox": false,
"input_pill": false,

100
static/js/night_mode.js Normal file
View File

@ -0,0 +1,100 @@
var night_mode = (function () {
var exports = {};
var create_stylesheet = function () {
var stylesheet = document.createElement('style');
stylesheet.type = "text/css";
stylesheet.classList.add("night-mode-stylesheet");
// disable the stylesheet by default in case the user isn't running night mode.
stylesheet.disabled = true;
return stylesheet;
};
// this transforms an object into CSS. The top level keys of the object are
// the CSS selectors and the second level keys are attributes which should have
// valid CSS values.
//
// EXAMPLE:
//
// {
// h1: { // h1 {
// color: "red", // color: red;
// }, // }
// p: { // p {
// "font-size": "1em", // font-size: 1em;
// "line-spacing": 1.2, // line-spacing: 1.2;
// }, // }
// }
//
// All CSS selectors are supported, everything from `h1` to
// complex selectors like `.night:not(.test)::after`.
var object_to_css = function (object) {
var css = "";
// for each CSS selector.
for (var selector in object) {
// ensure the object properties are its own and not ones injected into
// the Object.prototype.
if (object.hasOwnProperty(selector)) {
// create the `h1 {` line...
css += selector + " {";
// and for each of the properties of the selector...
for (var attr in object[selector]) {
if (object[selector].hasOwnProperty(attr)) {
// add the attribute and its value like `attr: value;`.
css += "\n\t" + attr + ": " + object[selector][attr] + ";";
}
}
css += "\n}\n";
}
}
// trim the excess newline.
return css.trim();
};
(function () {
// the object to be converted to CSS.
// this should ONLY be used if there is no obvious way to perform this action
// by prefixing the selector with `body.night-mode`.
var css_skeleton = {
"a:hover": {
color: "#65c0ed",
},
};
// create a stylesheet that can be appended to the <head>.
var stylesheet = create_stylesheet();
// convert to CSS.
var css = object_to_css(css_skeleton);
if (stylesheet.styleSheet) {
stylesheet.styleSheet.cssText = css;
} else {
stylesheet.appendChild(document.createTextNode(css));
}
// append the stylesheet.
(document.head || document.getElementsByTagName('head')[0]).appendChild(stylesheet);
exports.enable = function () {
// we can also query for this in the DOM with the
// `.night-mode-stylesheet` class.
stylesheet.disabled = false;
$("body").addClass("dark-mode");
};
exports.disable = function () {
stylesheet.disabled = true;
$("body").removeClass("dark-mode");
};
}());
return exports;
}());
if (typeof module !== 'undefined') {
module.exports = night_mode;
}

View File

@ -302,7 +302,11 @@ exports.dispatch_normal_event = function dispatch_normal_event(event) {
if (event.setting_name === 'night_mode') {
$("body").fadeOut(300);
setTimeout(function () {
$("body").toggleClass("dark-mode");
if (event.setting === true) {
night_mode.enable();
} else {
night_mode.disable();
}
$("body").fadeIn(300);
}, 300);
}

View File

@ -284,6 +284,10 @@ $(function () {
exports.initialize = function () {
i18n.ensure_i18n(_setup_info_overlay);
exports.show_error_for_unsupported_platform();
if (page_params.night_mode) {
night_mode.enable();
}
};
return exports;

View File

@ -10,9 +10,3 @@ var current_msg_list = home_msg_list;
if (typeof module !== 'undefined') {
module.exports.current_msg_list = current_msg_list;
}
$(function () {
if (page_params.night_mode) {
$("body").addClass("dark-mode");
}
});

View File

@ -5,10 +5,6 @@ body.dark-mode {
-webkit-font-smoothing: antialiased;
}
body.dark-mode a:hover {
color: #65c0ed;
}
body.dark-mode .app-main,
body.dark-mode .header-main {
background-color: #212d3b;

View File

@ -1022,6 +1022,7 @@ JS_SPECS = {
'js/lightbox.js',
'js/ui_report.js',
'js/ui.js',
'js/night_mode.js',
'js/ui_util.js',
'js/pointer.js',
'js/click_handlers.js',