simplify: move ! modes to explicit global options

This commit is contained in:
tophf 2022-02-15 16:07:32 +03:00
parent 33e517c4a9
commit 933191d25c
9 changed files with 66 additions and 58 deletions

View File

@ -1086,11 +1086,8 @@
"optionsAdvancedNewStyleAsUsercss": {
"message": "Write new style as usercss"
},
"optionsAdvancedAutoSwitchScheme": {
"message": "Toggle Light/Dark Mode styles automatically"
},
"optionsAdvancedAutoSwitchSchemeNever": {
"message": "Never"
"message": "Disabled. The dark/light setting in styles is ignored."
},
"optionsAdvancedAutoSwitchSchemeBySystem": {
"message": "By system preference"
@ -1312,26 +1309,20 @@
"description": "Label for the checkbox controlling section order in the popup."
},
"preferScheme": {
"message": "Dark/Light mode preference:"
"message": "Dark/Light mode preference"
},
"preferSchemeAlways": {
"message": "Currently ignored (the style always applies) because the global Dark/Light mode is disabled"
},
"preferSchemeDark": {
"message": "Dark"
},
"preferSchemeDarkOnly": {
"message": "Dark (strict)"
},
"preferSchemeLight": {
"message": "Light"
},
"preferSchemeLightOnly": {
"message": "Light (strict)"
},
"preferSchemeNone": {
"message": "None (always applied)"
},
"preferSchemeTip": {
"message": "The style will be applied in a matching Dark/Light global mode. For strict options, the mode being active is mandatory, so the style doesn't apply when the mode is 'Never'. For non-strict options, the style also applies when the user doesn't care i.e. the global mode is 'Never'."
},
"prefShowBadge": {
"message": "Number of styles active for the current site",
"description": "Label for the checkbox controlling toolbar badge text."

View File

@ -8,11 +8,17 @@ const colorScheme = (() => {
const kSTATE = 'schemeSwitcher.enabled';
const kSTART = 'schemeSwitcher.nightStart';
const kEND = 'schemeSwitcher.nightEnd';
const SCHEMES = ['dark', 'light', 'dark!', 'light!']; // ! = only if schemeSwitcher is enabled
const isDark = {never: null, system: false, time: false};
const SCHEMES = ['dark', 'light'];
const isDark = {
never: null,
dark: true,
light: false,
system: false,
time: false,
};
let isDarkNow = false;
prefs.subscribe(kSTATE, () => emitChange());
prefs.subscribe(kSTATE, () => update());
prefs.subscribe([kSTART, kEND], (key, value) => {
updateTimePreferDark();
createAlarm(key, value);
@ -28,17 +34,25 @@ const colorScheme = (() => {
onChange(listener) {
changeListeners.add(listener);
},
shouldIncludeStyle({preferScheme: val}) {
return !SCHEMES.includes(val) ||
!val.endsWith('!') && prefs.get(kSTATE) === 'never' ||
val.startsWith('dark') === isDarkNow;
/** @param {StyleObj | 'darkUI'} val - the string is used by the built-in dark themer */
shouldIncludeStyle(val) {
return val === 'darkUI'
? isDarkNow
: prefs.get(kSTATE) === 'never' ||
!SCHEMES.includes(val = val.preferScheme) ||
isDarkNow === (val === 'dark');
},
updateSystemPreferDark(val) {
emitChange('system', val);
update('system', val);
return true;
},
};
function calcTime(key) {
const [h, m] = prefs.get(key).split(':');
return (h * 3600 + m * 60) * 1000;
}
function createAlarm(key, value) {
const date = new Date();
const [h, m] = value.split(':');
@ -59,22 +73,20 @@ const colorScheme = (() => {
const val = start > end ?
now >= start || now < end :
now >= start && now < end;
emitChange('time', val);
update('time', val);
}
function calcTime(key) {
const [h, m] = prefs.get(key).split(':');
return (h * 3600 + m * 60) * 1000;
}
function emitChange(type, val) {
function update(type, val) {
if (type) {
if (isDark[type] === val) return;
isDark[type] = val;
}
isDarkNow = isDark[prefs.get(kSTATE)];
for (const listener of changeListeners) {
listener(isDarkNow);
val = isDark[prefs.get(kSTATE)];
if (isDarkNow !== val) {
isDarkNow = val;
for (const listener of changeListeners) {
listener(isDarkNow);
}
}
}
})();

View File

@ -85,7 +85,7 @@
background: linear-gradient(0deg, hsla(180, 100%, 30%, .75) 2px, hsla(180, 100%, 30%, .2) 2px);
}
@media not screen, dark {
@media (prefers-color-scheme: dark) {
.CodeMirror-dialog {
background-color: #333;
}
@ -127,7 +127,7 @@
.cm-s-default .cm-operator { color: #d2c057 }
.cm-s-default .cm-string { color: #f28b54 }
.cm-s-default .cm-variable { color: #d9d9d9 }
.cm-s-default .cm-variable-2 { color: #05a }
.cm-s-default .cm-variable-2 { color: #72b9ff }
.cm-s-default .cm-variable-3 { color: #9bbbdc }
@keyframes highlight {

View File

@ -8,9 +8,7 @@
</div>
<div id="ss-scheme">
<div i18n-text="preferScheme">
<a tabindex="0" data-cmd="note" i18n-title="preferSchemeTip">
<svg class="svg-icon info"><use xlink:href="#svg-icon-help"/></svg>
</a>
<div><small id="ss-scheme-off" i18n-text="preferSchemeAlways" hidden></small></div>
</div>
<label i18n-text-append="preferSchemeNone" class="ss-radio">
<input name="ss-scheme" type="radio" value="none">
@ -18,15 +16,9 @@
<label i18n-text-append="preferSchemeDark" class="ss-radio">
<input name="ss-scheme" type="radio" value="dark">
</label>
<label i18n-text-append="preferSchemeDarkOnly" class="ss-radio">
<input name="ss-scheme" type="radio" value="dark!">
</label>
<label i18n-text-append="preferSchemeLight" class="ss-radio">
<input name="ss-scheme" type="radio" value="light">
</label>
<label i18n-text-append="preferSchemeLightOnly" class="ss-radio">
<input name="ss-scheme" type="radio" value="light!">
</label>
</div>
<label i18n-text="styleIncludeLabel">
<textarea id="ss-inclusions" spellcheck="false" class="w100"

View File

@ -2,11 +2,12 @@
/* global API */// msg.js
/* global editor */
/* global helpPopup */// util.js
/* global prefs */
/* global t */// localization.js
/* global debounce tryURL */// toolbox.js
/* exported StyleSettings */
'use strict';
/* exported StyleSettings */
async function StyleSettings() {
const AUTOSAVE_DELAY = 500; // same as config-dialog.js
const SS_ID = 'styleSettings';
@ -31,6 +32,9 @@ async function StyleSettings() {
initArea('exclusions'),
];
update();
prefs.subscribe('schemeSwitcher.enabled', (_, val) => {
$('#ss-scheme-off', ui).hidden = val !== 'never';
}, {runNow: true});
window.on(SS_ID, update);
window.on('closeHelp', () => window.off(SS_ID, update), {once: true});
helpPopup.show(t(SS_ID), ui, {

View File

@ -1,4 +1,4 @@
@media not screen, dark {
@media (prefers-color-scheme: dark) {
:root {
/* Comfortable dark themes don't use absolutes so the range is compressed */
--c00: hsl(0, 0%, 80%);

View File

@ -45,7 +45,12 @@ setTimeout(() => !cm && showSpinner($('#header')), 200);
}
({tabId, initialUrl} = preinit);
liveReload = initLiveReload();
preinit.tpl.then(el => $('#ss-scheme').append(...$('#ss-scheme', el).children));
preinit.tpl.then(el => {
$('#ss-scheme').append(...$('#ss-scheme', el).children);
prefs.subscribe('schemeSwitcher.enabled', (_, val) => {
$('#ss-scheme-off').hidden = val !== 'never';
}, {runNow: true});
});
const [
{dup, style, error, sourceCode},

View File

@ -4,12 +4,13 @@
/**
* This file must be loaded in a <script> tag placed after all the <link> tags
* that contain dark themes so that the stylesheets are loaded synchronously
* by the time this script runs. The CSS must use `@media not screen, dark {}`
* to ensure the rules are loaded before the first paint in inactive state,
* then we activate it here.
* by the time this script runs. The CSS must use `@media (prefers-color-scheme: dark) {}`
* to ensure the rules are loaded before the first paint, then we toggle the rule here,
* which also happens before the first paint unless the browser "yields", but that's abnormal
* and not even a problem in the most popular case of using system dark/light mode.
*/
API.colorScheme.shouldIncludeStyle({preferScheme: 'dark!'}).then(val => {
API.colorScheme.shouldIncludeStyle('darkUI').then(val => {
let isDark = val;
toggleDarkStyles();
msg.onExtension(e => {
@ -21,8 +22,8 @@ API.colorScheme.shouldIncludeStyle({preferScheme: 'dark!'}).then(val => {
function toggleDarkStyles() {
for (const sheet of document.styleSheets) {
for (const {media: m} of sheet.cssRules) {
if (m && m[1] === 'dark' && (m[0] === 'screen') !== isDark) {
m.mediaText = `${isDark ? '' : 'not '}screen, dark`;
if (m && /dark/.test(m) && (m[0] === 'screen') !== isDark) {
m.mediaText = isDark ? 'screen,dark' : 'dark';
}
}
}

View File

@ -52,14 +52,14 @@
<h1 i18n-text="stylePreferSchemeLabel"></h1>
<div class="items">
<div class="radio-group">
<span i18n-text="optionsAdvancedAutoSwitchScheme" class="radio-group-label"></span>
<label class="radio-group-item">
<input type="radio" value="never" name="schemeSwitcher.enabled" class="radio">
<span i18n-text="optionsAdvancedAutoSwitchSchemeNever"></span>
<label class="radio-group-item" i18n-text-append="preferSchemeDark">
<input type="radio" value="light" name="schemeSwitcher.enabled" class="radio">
</label>
<label class="radio-group-item">
<label class="radio-group-item" i18n-text-append="preferSchemeLight">
<input type="radio" value="dark" name="schemeSwitcher.enabled" class="radio">
</label>
<label class="radio-group-item" i18n-text-append="optionsAdvancedAutoSwitchSchemeBySystem">
<input type="radio" value="system" name="schemeSwitcher.enabled" class="radio">
<span i18n-text="optionsAdvancedAutoSwitchSchemeBySystem"></span>
</label>
<label class="radio-group-item">
<input type="radio" value="time" name="schemeSwitcher.enabled" class="radio">
@ -68,6 +68,9 @@
~
<input type="time" required id="schemeSwitcher.nightEnd">
</label>
<label class="radio-group-item" i18n-text-append="optionsAdvancedAutoSwitchSchemeNever">
<input type="radio" value="never" name="schemeSwitcher.enabled" class="radio">
</label>
</div>
</div>
</div>