mirror of https://github.com/zulip/zulip.git
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:
parent
6d887dc6ee
commit
e0236646bf
|
@ -34,6 +34,7 @@
|
|||
"server_events_dispatch": false,
|
||||
"ui": false,
|
||||
"ui_report": false,
|
||||
"night_mode": false,
|
||||
"ui_util": false,
|
||||
"lightbox": false,
|
||||
"input_pill": false,
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
});
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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',
|
||||
|
|
Loading…
Reference in New Issue