From b7cfbe6e66732feb44f9cb958ba4ae12500b3e97 Mon Sep 17 00:00:00 2001 From: tophf Date: Thu, 17 Feb 2022 03:10:59 +0300 Subject: [PATCH] use color palette and enable a simple dark theme (#1405) * add 'auto' iconset and use it by default * expose `data-ui-theme` on html Co-authored-by: narcolepticinsomniac --- _locales/en/messages.json | 35 +++--- background/color-scheme.js | 124 ++++++++++------------ background/icon-manager.js | 16 ++- background/style-manager.js | 13 +-- content/apply.js | 14 +-- edit.html | 2 + edit/codemirror-default.css | 71 ++++++++++++- edit/edit.css | 43 ++++---- edit/edit.js | 1 - edit/global-search.js | 4 +- edit/moz-section-widget.js | 1 + edit/settings.css | 11 +- edit/settings.html | 10 +- edit/settings.js | 6 +- global-dark.css | 159 ++++++++++++++++++++++++++++ global.css | 104 +++++++++++------- injection-order/injection-order.css | 2 +- install-usercss.html | 45 ++++++++ install-usercss/install-usercss.css | 14 ++- install-usercss/install-usercss.js | 36 ++----- js/color/color-mimicry.js | 12 ++- js/dark-themer.js | 33 ++++++ js/dlg/config-dialog.css | 8 +- js/dlg/message-box.css | 6 +- js/dom.js | 5 +- js/prefs.js | 6 +- manage.html | 2 + manage/manage.css | 55 +++++----- options.html | 75 ++++++++----- options/onoffswitch.css | 8 +- options/options.css | 101 +++++------------- popup.html | 2 + popup/popup.css | 89 +++++++--------- popup/popup.js | 3 + popup/search.css | 41 ++++--- 35 files changed, 739 insertions(+), 418 deletions(-) create mode 100644 global-dark.css create mode 100644 js/dark-themer.js diff --git a/_locales/en/messages.json b/_locales/en/messages.json index e1b3416c..57bf1b02 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -623,18 +623,6 @@ "message": "Update style", "description": "Label for update button" }, - "installPreferSchemeLabel": { - "message": "The style should be applied:" - }, - "installPreferSchemeNone": { - "message": "Always" - }, - "installPreferSchemeDark": { - "message": "In Dark Mode" - }, - "installPreferSchemeLight": { - "message": "In Light Mode" - }, "installUpdate": { "message": "Install update", "description": "Label for the button to install an update for a single style" @@ -1098,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" @@ -1153,6 +1138,9 @@ "message": "Options", "description": "Heading for options section on manage page." }, + "optionsIconAuto": { + "message": "Match the Dark/Light mode" + }, "optionsIconDark": { "message": "Dark browser themes" }, @@ -1323,6 +1311,21 @@ "message": "Styles before commands", "description": "Label for the checkbox controlling section order in the popup." }, + "preferScheme": { + "message": "Dark/Light mode preference" + }, + "preferSchemeAlways": { + "message": "Currently ignored (the style always applies) because the global Dark/Light mode is disabled" + }, + "preferSchemeDark": { + "message": "Dark" + }, + "preferSchemeLight": { + "message": "Light" + }, + "preferSchemeNone": { + "message": "None (always applied)" + }, "prefShowBadge": { "message": "Number of styles active for the current site", "description": "Label for the checkbox controlling toolbar badge text." diff --git a/background/color-scheme.js b/background/color-scheme.js index 66e2e4c6..1c389623 100644 --- a/background/color-scheme.js +++ b/background/color-scheme.js @@ -4,33 +4,59 @@ 'use strict'; const colorScheme = (() => { - let systemPreferDark = false; - let timePreferDark = false; const changeListeners = new Set(); + const kSTATE = 'schemeSwitcher.enabled'; + const kSTART = 'schemeSwitcher.nightStart'; + const kEND = 'schemeSwitcher.nightEnd'; + const SCHEMES = ['dark', 'light']; + const isDark = { + never: null, + dark: true, + light: false, + system: false, + time: false, + }; + let isDarkNow = false; - const checkTime = ['schemeSwitcher.nightStart', 'schemeSwitcher.nightEnd']; - prefs.subscribe(checkTime, (key, value) => { + prefs.subscribe(kSTATE, () => update()); + prefs.subscribe([kSTART, kEND], (key, value) => { updateTimePreferDark(); createAlarm(key, value); - }); - checkTime.forEach(key => createAlarm(key, prefs.get(key))); - - prefs.subscribe(['schemeSwitcher.enabled'], emitChange); - - chrome.alarms.onAlarm.addListener(info => { - if (checkTime.includes(info.name)) { + }, {runNow: true}); + chrome.alarms.onAlarm.addListener(({name}) => { + if (name === kSTART || name === kEND) { updateTimePreferDark(); } }); - updateSystemPreferDark(); - updateTimePreferDark(); + return { + SCHEMES, + onChange(listener) { + changeListeners.add(listener); + }, + /** @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) { + update('system', val); + return true; + }, + }; - return {shouldIncludeStyle, onChange, updateSystemPreferDark}; + function calcTime(key) { + const [h, m] = prefs.get(key).split(':'); + return (h * 3600 + m * 60) * 1000; + } function createAlarm(key, value) { const date = new Date(); - applyDate(date, value); + const [h, m] = value.split(':'); + date.setHours(h, m, 0, 0); if (date.getTime() < Date.now()) { date.setDate(date.getDate() + 1); } @@ -40,61 +66,27 @@ const colorScheme = (() => { }); } - function shouldIncludeStyle(style) { - const isDark = style.preferScheme === 'dark'; - const isLight = style.preferScheme === 'light'; - if (!isDark && !isLight) { - return true; - } - const switcherState = prefs.get('schemeSwitcher.enabled'); - if (switcherState === 'never') { - return true; - } - if (switcherState === 'system') { - return systemPreferDark && isDark || - !systemPreferDark && isLight; - } - return timePreferDark && isDark || - !timePreferDark && isLight; - } - - function updateSystemPreferDark() { - const oldValue = systemPreferDark; - systemPreferDark = window.matchMedia('(prefers-color-scheme: dark)').matches; - if (systemPreferDark !== oldValue) { - emitChange(); - } - return true; - } - function updateTimePreferDark() { - const oldValue = timePreferDark; - const date = new Date(); - const now = date.getTime(); - applyDate(date, prefs.get('schemeSwitcher.nightStart')); - const start = date.getTime(); - applyDate(date, prefs.get('schemeSwitcher.nightEnd')); - const end = date.getTime(); - timePreferDark = start > end ? + const now = Date.now() - new Date().setHours(0, 0, 0, 0); + const start = calcTime(kSTART); + const end = calcTime(kEND); + const val = start > end ? now >= start || now < end : now >= start && now < end; - if (timePreferDark !== oldValue) { - emitChange(); + update('time', val); + } + + function update(type, val) { + if (type) { + if (isDark[type] === val) return; + isDark[type] = val; } - } - - function applyDate(date, time) { - const [h, m] = time.split(':').map(Number); - date.setHours(h, m, 0, 0); - } - - function onChange(listener) { - changeListeners.add(listener); - } - - function emitChange() { - for (const listener of changeListeners) { - listener(); + val = isDark[prefs.get(kSTATE)]; + if (isDarkNow !== val) { + isDarkNow = val; + for (const listener of changeListeners) { + listener(isDarkNow); + } } } })(); diff --git a/background/icon-manager.js b/background/icon-manager.js index 9b8d1f2d..97490d43 100644 --- a/background/icon-manager.js +++ b/background/icon-manager.js @@ -1,5 +1,6 @@ /* global API */// msg.js /* global addAPI bgReady */// common.js +/* global colorScheme */ /* global prefs */ /* global tabMan */ /* global CHROME FIREFOX UA debounce ignoreChromeError */// toolbox.js @@ -13,7 +14,7 @@ const iconMan = (() => { const badgeOvr = {color: '', text: ''}; // https://github.com/openstyles/stylus/issues/1287 Fenix can't use custom ImageData const FIREFOX_ANDROID = FIREFOX && UA.mobile; - + let isDark; // https://github.com/openstyles/stylus/issues/335 let hasCanvas = FIREFOX_ANDROID ? false : loadImage(`/images/icon/${ICON_SIZES[0]}.png`) .then(({data}) => (hasCanvas = data.some(b => b !== 255))); @@ -37,13 +38,17 @@ const iconMan = (() => { chrome.webNavigation.onCommitted.addListener(({tabId, frameId}) => { if (!frameId) tabMan.set(tabId, 'styleIds', undefined); }); - chrome.runtime.onConnect.addListener(port => { if (port.name === 'iframe') { port.onDisconnect.addListener(onPortDisconnected); } }); - + colorScheme.onChange(val => { + isDark = val; + if (prefs.get('iconset') === -1) { + debounce(refreshAllIcons); + } + }); bgReady.all.then(() => { prefs.subscribe([ 'disableAll', @@ -95,9 +100,10 @@ const iconMan = (() => { } function getIconName(hasStyles = false) { - const iconset = prefs.get('iconset') === 1 ? 'light/' : ''; + const i = prefs.get('iconset'); + const prefix = i === 0 || i === -1 && isDark ? '' : 'light/'; const postfix = prefs.get('disableAll') ? 'x' : !hasStyles ? 'w' : ''; - return `${iconset}$SIZE$${postfix}`; + return `${prefix}$SIZE$${postfix}`; } function refreshIcon(tabId, force = false) { diff --git a/background/style-manager.js b/background/style-manager.js index fed12aee..a4094c40 100644 --- a/background/style-manager.js +++ b/background/style-manager.js @@ -84,11 +84,11 @@ const styleMan = (() => { handleDraft(port); } }); - // function handleColorScheme() { - colorScheme.onChange(() => { - for (const {style: data} of dataMap.values()) { - if (data.preferScheme === 'dark' || data.preferScheme === 'light') { - broadcastStyleUpdated(data, 'colorScheme', undefined, false); + colorScheme.onChange(value => { + msg.broadcastExtension({method: 'colorScheme', value}); + for (const {style} of dataMap.values()) { + if (colorScheme.SCHEMES.includes(style.preferScheme)) { + broadcastStyleUpdated(style, 'colorScheme'); } } }); @@ -320,7 +320,8 @@ const styleMan = (() => { async config(id, prop, value) { if (ready.then) await ready; const style = Object.assign({}, id2style(id)); - style[prop] = value; + const {preview = {}} = dataMap.get(id); + style[prop] = preview[prop] = value; return saveStyle(style, {reason: 'config'}); }, }; diff --git a/content/apply.js b/content/apply.js index 5d490ff4..ce2e86a7 100644 --- a/content/apply.js +++ b/content/apply.js @@ -52,6 +52,12 @@ xo.observe(el); }; + // FIXME: move this to background page when following bugs are fixed: + // https://bugzil.la/1587723, https://crbug.com/968651 + const mqDark = matchMedia('(prefers-color-scheme: dark)'); + mqDark.onchange = e => API.colorScheme.updateSystemPreferDark(e.matches); + mqDark.onchange(mqDark); + // Declare all vars before init() or it'll throw due to "temporal dead zone" of const/let const ready = init(); @@ -70,13 +76,6 @@ window.addEventListener(orphanEventId, orphanCheck, true); } - // detect media change in content script - // FIXME: move this to background page when following bugs are fixed: - // https://bugzilla.mozilla.org/show_bug.cgi?id=1561546 - // https://bugs.chromium.org/p/chromium/issues/detail?id=968651 - const media = window.matchMedia('(prefers-color-scheme: dark)'); - media.addListener(() => API.colorScheme.updateSystemPreferDark().catch(console.error)); - function onInjectorUpdate() { if (!isOrphaned) { updateCount(); @@ -265,6 +264,7 @@ // In Chrome content script is orphaned on an extension update/reload // so we need to detach event listeners window.removeEventListener(orphanEventId, orphanCheck, true); + mqDark.onchange = null; isOrphaned = true; setTimeout(styleInjector.clear, 1000); // avoiding FOUC tryCatch(msg.off, applyOnMessage); diff --git a/edit.html b/edit.html index 8dd7cf5e..1b08f9eb 100644 --- a/edit.html +++ b/edit.html @@ -5,6 +5,7 @@ + @@ -239,6 +240,7 @@ + diff --git a/edit/codemirror-default.css b/edit/codemirror-default.css index 73347813..0a8ef287 100644 --- a/edit/codemirror-default.css +++ b/edit/codemirror-default.css @@ -4,13 +4,23 @@ z-index: 999; } .CodeMirror-hint:hover { - color: white; + color: var(--bg); background: #08f; } .CodeMirror { - border: solid #CCC 1px; + border: solid var(--c80) 1px; transition: box-shadow .1s; } +.CodeMirror { + color: inherit; + background-color: inherit; + border: solid var(--c80) 1px; + transition: box-shadow .1s; +} +.CodeMirror-gutters { + background-color: var(--c95); + border-color: var(--c85); +} #stylus#stylus .CodeMirror { /* Using a specificity hack to override userstyles */ /* Not using the ring-color hack as it became ugly in new Chrome */ @@ -26,7 +36,7 @@ width: 5em; } .CodeMirror-search-hint { - color: #888; + color: var(--c50); } .CodeMirror-activeline .applies-to:before { background-color: hsla(214, 100%, 90%, 0.15); @@ -74,3 +84,58 @@ .gutter-bookmark { background: linear-gradient(0deg, hsla(180, 100%, 30%, .75) 2px, hsla(180, 100%, 30%, .2) 2px); } + +@media screen and (prefers-color-scheme: dark), dark { + .CodeMirror-dialog { + background-color: #333; + } + .CodeMirror-dialog-top { + border-color: #555; + } + .CodeMirror-activeline-background { + background: hsl(180, 21%, 18%); + } + .CodeMirror-selected, + .CodeMirror-focused .CodeMirror-selected, + .CodeMirror-line::selection, + .CodeMirror-line > span::selection, + .CodeMirror-line > span > span::selection { + background: #444; + } + .CodeMirror-line::-moz-selection, + .CodeMirror-line > span::-moz-selection, + .CodeMirror-line > span > span::-moz-selection { + /* TODO: remove this when strict_min_version >= 62 */ + background: #444; + } + .cm-s-default div.CodeMirror-cursor { + border-left: 1px solid #fff; + } + /* Using Chromium's dark devtools colors */ + .cm-s-default .cm-atom, + .cm-s-default .cm-number { color: #a1f7b5 } + .cm-s-default .cm-attribute { color: #6194c6 } + .cm-s-default .cm-bracket { color: #997 } + .cm-s-default .cm-builtin, + .cm-s-default .cm-link { color: #9fb4d6 } + .cm-s-default .cm-comment { color: #747474 } + .cm-s-default .cm-qualifier { color: #ffa34f } + .cm-s-default .cm-def, + .cm-s-default .cm-header, + .cm-s-default .cm-tag, + .cm-s-default .cm-type { color: #5db0d7 } + .cm-s-default .cm-hr { color: #999 } + .cm-s-default .cm-keyword { color: #9a7fd5 } + .cm-s-default .cm-meta { color: #ddfb55 } + .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: #72b9ff } + .cm-s-default .cm-variable-3 { color: #9bbbdc } + + @keyframes highlight { + from { + background-color: #888; + } + } +} diff --git a/edit/edit.css b/edit/edit.css index b8acdf96..8ee54035 100644 --- a/edit/edit.css +++ b/edit/edit.css @@ -5,12 +5,11 @@ } body { - margin: 0; height: 100vh; } a { - color: #000; + color: var(--fg); transition: color .5s; } a:hover { @@ -55,8 +54,8 @@ html:not(.is-new-style) #heading::after { top: 0; z-index: 1001; border: none; - background: #fff; - box-shadow: 0 0 30px #000; + background: var(--bg); + box-shadow: 0 0 30px var(--fg); } #popup-iframe:not([data-loaded]) { opacity: 0; @@ -97,7 +96,7 @@ label { position: fixed; top: 0; padding-top: var(--pad); - box-shadow: 0 0 3rem -1.2rem black; + box-shadow: 0 0 3rem -1.2rem #000; box-sizing: border-box; z-index: 10; display: flex; @@ -173,7 +172,7 @@ label { #preview-errors { background-color: red; - color: white; + color: var(--bg); padding: 0 6px; border-radius: 9px; margin-left: -.5em; @@ -206,12 +205,12 @@ label { .svg-icon:hover, .svg-icon.info, .svg-icon.settings { - fill: #666; + fill: var(--c40); } .svg-icon, .svg-icon.info:hover, .svg-icon.settings:hover { - fill: #000; + fill: var(--fg); } #options span .svg-icon { margin-top: -3px; /* inline info and config icons */ @@ -256,7 +255,7 @@ input:invalid { text-overflow: ellipsis; } #header summary:hover h2 { - border-color: #bbb; + border-color: var(--c70); } #header summary svg { margin-top: -3px; @@ -385,7 +384,7 @@ input:invalid { padding: 1rem; } .sectioned .section:not(:first-child) { - border-top: 2px solid hsl(0, 0%, 80%); + border-top: 2px solid var(--c80); } .add-section:after { content: attr(short-text); @@ -649,14 +648,14 @@ body:not(.find-open) [data-match-highlight-count="1"] .CodeMirror-selection-high .add-applies-to .svg-icon, .remove-applies-to .svg-icon { pointer-events: none; - fill: hsl(0, 0%, 60%); + fill: var(--c60); height: 12px; width: 12px; } .add-applies-to:hover .svg-icon, .remove-applies-to:hover .svg-icon { pointer-events: none; - fill: hsl(0, 0%, 0%); + fill: var(--fg); } .test-regexp { display: none; @@ -688,7 +687,7 @@ body:not(.find-open) [data-match-highlight-count="1"] .CodeMirror-selection-high color: darkgreen; } .regexp-report details[data-type="partial"] { - color: darkgray; + color: var(--c65); } .regexp-report details[data-type="invalid"] { color: maroon; @@ -721,7 +720,7 @@ body:not(.find-open) [data-match-highlight-count="1"] .CodeMirror-selection-high margin-right: .5em; } .regexp-report-note { - color: #999; + color: var(--c60); position: absolute; bottom: 0; hyphens: auto; @@ -736,7 +735,7 @@ body:not(.find-open) [data-match-highlight-count="1"] .CodeMirror-selection-high max-width: 50vw; position: fixed; display: none; - background-color: white; + background-color: var(--bg); box-shadow: 3px 3px 30px rgba(0, 0, 0, 0.5); padding: var(--pad-y) var(--pad-x) 0; z-index: 99; @@ -755,7 +754,7 @@ body:not(.find-open) [data-match-highlight-count="1"] .CodeMirror-selection-high } #help-popup .title { font-weight: bold; - background-color: rgba(0,0,0,0.05); + background-color: rgba(128, 128, 128, .15); margin: calc(-1 * var(--pad-y)) calc(-1 * var(--pad-x)) 0; padding: var(--pad-y2) var(--pad-x); } @@ -980,12 +979,12 @@ body:not(.find-open) [data-match-highlight-count="1"] .CodeMirror-selection-high } #footer a { - color: #333; + color: var(--c20); transition: color .5s; } #footer a:hover { - color: #666; + color: var(--c40); } /************ line widget *************/ @@ -1041,14 +1040,14 @@ body:not(.find-open) [data-match-highlight-count="1"] .CodeMirror-selection-high height: unset; width: 100%; overflow: visible; - background: #fff; + background: var(--bg); border-right: none; - border-bottom: 1px dashed #AAA; + border-bottom: 1px dashed var(--c65); padding: var(--pad05) var(--pad05) 0; } #header.sticky { flex-direction: row; - box-shadow: 0 0 3rem -.75rem black; + box-shadow: 0 0 3rem -.75rem; } #header.sticky #basic-info, #header.sticky #mozilla-format-buttons, @@ -1106,7 +1105,7 @@ body:not(.find-open) [data-match-highlight-count="1"] .CodeMirror-selection-high position: absolute; overflow: hidden auto; max-height: var(--max-height, 10vh); - background: #fff; + background: var(--bg); box-shadow: 0 6px 20px rgba(0, 0, 0, .3); padding: var(--pad); margin-top: var(--pad05); diff --git a/edit/edit.js b/edit/edit.js index 910ea6d1..ca514d92 100644 --- a/edit/edit.js +++ b/edit/edit.js @@ -140,7 +140,6 @@ async function handleExternalUpdate({style, reason}) { delete style.name; delete style.enabled; Object.assign(editor.style, style); - editor.updateLivePreview(); } else { await editor.replaceStyle(style); } diff --git a/edit/global-search.js b/edit/global-search.js index e4ebbaa8..359add49 100644 --- a/edit/global-search.js +++ b/edit/global-search.js @@ -607,10 +607,10 @@ } #search-replace-dialog[data-type="replace"] button:hover svg, #search-replace-dialog svg:hover { - fill: inherit; + fill: var(--cmin); } #search-replace-dialog [data-action="case"]:hover { - color: inherit; + color: var(--cmin); } #search-replace-dialog [data-action="clear"] { background-color: ${colors.input.bg.replace(/[^,]+$/, '') + '.75)'}; diff --git a/edit/moz-section-widget.js b/edit/moz-section-widget.js index 674d03b1..84ffb0a2 100644 --- a/edit/moz-section-widget.js +++ b/edit/moz-section-widget.js @@ -158,6 +158,7 @@ function MozSectionWidget(cm, finder = MozSectionFinder(cm)) { } if (msg.style || msg.styles || msg.prefs && 'disableAll' in msg.prefs || + msg.method === 'colorScheme' || msg.method === 'styleDeleted') { requestAnimationFrame(updateWidgetStyle); } diff --git a/edit/settings.css b/edit/settings.css index 3bf71cce..1cfd7789 100644 --- a/edit/settings.css +++ b/edit/settings.css @@ -21,7 +21,7 @@ margin-bottom: 0; } .style-settings input[type=radio] { - margin-left: -.5em; /* compensate for label's 16px margin in edit.css */ + margin: 0 .3em 0 0; } .style-settings input:disabled ~ label { opacity: .5; @@ -44,3 +44,12 @@ .style-settings textarea:not(:placeholder-shown) { min-width: 50vw; } +.ss-radio { + display: inline-flex; + align-items: center; + line-height: 2; + padding: 0 .8em 0 0; +} +a[data-cmd=note] { + vertical-align: text-bottom; +} diff --git a/edit/settings.html b/edit/settings.html index 725a1ba8..a83a958f 100644 --- a/edit/settings.html +++ b/edit/settings.html @@ -7,14 +7,16 @@
-
-
diff --git a/edit/settings.js b/edit/settings.js index 855bdb0a..b415c1bc 100644 --- a/edit/settings.js +++ b/edit/settings.js @@ -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, { diff --git a/global-dark.css b/global-dark.css new file mode 100644 index 00000000..124c4d6c --- /dev/null +++ b/global-dark.css @@ -0,0 +1,159 @@ +@media screen and (prefers-color-scheme: dark), dark { + :root { + /* Comfortable dark themes don't use absolutes so the range is compressed */ + --c00: hsl(0, 0%, 80%); + --c10: hsl(0, 0%, 73.5%); + --c20: hsl(0, 0%, 66%); + --c30: hsl(0, 0%, 59.5%); + --c40: hsl(0, 0%, 53%); + --c45: hsl(0, 0%, 49.75%); + --c50: hsl(0, 0%, 46.5%); + --c60: hsl(0, 0%, 40%); + --c65: hsl(0, 0%, 36.75%); + --c70: hsl(0, 0%, 33.5%); + --c75: hsl(0, 0%, 30.25%); + --c80: hsl(0, 0%, 27%); + --c85: hsl(0, 0%, 23.75%); + --c90: hsl(0, 0%, 20.5%); + --c95: hsl(0, 0%, 17.25%); + --c100: hsl(0, 0%, 14%); + /* min/max are exposed in case we want to use an overdrive color for emphasis */ + --cmin: hsl(0, 0%, 100%); + --cmax: hsl(0, 0%, 0%); + --accent-1: hsl(180, 100%, 95%); + --accent-3: hsl(180, 30%, 18%); + --input-bg: var(--c95); + } + textarea, + input[type=url], + input[type=time] { + background-color: var(--input-bg); + color: var(--fg); + } + input::-webkit-inner-spin-button { + filter: invert(.8); + } + input[type=radio]:checked:after { + background-color: var(--fg); + } + input[type=time]::-webkit-calendar-picker-indicator { + filter: invert(1); + } + select { + background-color: var(--bg); + } + .onoffswitch { + --knob: var(--c50); + } + .CodeMirror-scrollbar-filler, + .CodeMirror-gutter-filler { + background-color: var(--bg) !important; + border: 0; + } + ::-webkit-scrollbar { + width: 17px; + height: 17px; + background: var(--bg); + } + ::-webkit-scrollbar-corner { + background: var(--bg); + border: 0; + } + /* buttons */ + ::-webkit-scrollbar-button:single-button { + height: 17px; + width: 17px; + background-size: 9px; + background-position: 4px 7px; + background-repeat: no-repeat; + } + ::-webkit-scrollbar-button:horizontal:single-button { + background-position: 7px 4px; + } + /* up */ + ::-webkit-scrollbar-button:single-button:vertical:decrement { + background-image: url("data:image/svg+xml,"); + } + ::-webkit-scrollbar-button:single-button:vertical:decrement:hover { + background-image: url("data:image/svg+xml,"); + } + ::-webkit-scrollbar-button:single-button:vertical:decrement:active { + background-image: url("data:image/svg+xml,"); + } + /* down */ + ::-webkit-scrollbar-button:single-button:vertical:increment { + background-image: url("data:image/svg+xml,"); + } + ::-webkit-scrollbar-button:single-button:vertical:increment:hover { + background-image: url("data:image/svg+xml,"); + } + ::-webkit-scrollbar-button:single-button:vertical:increment:active { + background-image: url("data:image/svg+xml,"); + } + /* left */ + ::-webkit-scrollbar-button:single-button:horizontal:decrement { + background-image: url("data:image/svg+xml,"); + } + ::-webkit-scrollbar-button:single-button:horizontal:decrement:hover { + background-image: url("data:image/svg+xml,"); + } + ::-webkit-scrollbar-button:single-button:horizontal:decrement:active { + background-image: url("data:image/svg+xml,"); + } + /* right */ + ::-webkit-scrollbar-button:single-button:horizontal:increment { + background-image: url("data:image/svg+xml,"); + } + ::-webkit-scrollbar-button:single-button:horizontal:increment:hover { + background-image: url("data:image/svg+xml,"); + } + ::-webkit-scrollbar-button:single-button:horizontal:increment:active { + background-image: url("data:image/svg+xml,"); + } + ::-webkit-scrollbar-track-piece { + background: #333; + border: 1px solid var(--bg); + } + ::-webkit-scrollbar-track-piece:hover { + background: #444; + } + ::-webkit-scrollbar-track-piece:active { + background: #555; + } + ::-webkit-scrollbar-thumb { + background: url("data:image/svg+xml,") 2px 2px no-repeat; + } + ::-webkit-scrollbar-thumb:horizontal { + background-size: 100% 13px; + } + ::-webkit-scrollbar-thumb:vertical { + background-size: 13px 100%; + } + ::-webkit-scrollbar-thumb:hover { + background-image: url("data:image/svg+xml,"); + } + ::-webkit-scrollbar-thumb:active { + background-image: url("data:image/svg+xml,"); + } + ::-webkit-resizer { + background: var(--input-bg) linear-gradient(-45deg, + transparent 3px, #888 3px, + #888 4px, transparent 4px, + transparent 6px, #888 6px, + #888 7px, transparent 7px) no-repeat; + border: 2px solid transparent; + } + :-webkit-autofill { + box-shadow: 0 0 0 1000px var(--input-bg) inset; + -webkit-text-fill-color: #fff; + } + @supports (-moz-appearance: none) { + /* Workarounds for FF bugs/quirks */ + textarea { + border: 1px solid var(--c65); + } + * { + scrollbar-color: var(--c75) var(--bg); + } + } +} diff --git a/global.css b/global.css index 3d80529a..a16802ee 100644 --- a/global.css +++ b/global.css @@ -7,9 +7,35 @@ html#stylus #header *:not(#\1transition-suppressor) { :root { --family: Arial, "Helvetica Neue", Helvetica, system-ui, sans-serif; --input-height: 22px; + --cmin: hsl(0, 0%, 00%); + --c00: hsl(0, 0%, 00%); + --c10: hsl(0, 0%, 10%); + --c20: hsl(0, 0%, 20%); + --c30: hsl(0, 0%, 30%); + --c40: hsl(0, 0%, 40%); + --c45: hsl(0, 0%, 45%); + --c50: hsl(0, 0%, 50%); + --c60: hsl(0, 0%, 60%); + --c65: hsl(0, 0%, 65%); + --c70: hsl(0, 0%, 70%); + --c75: hsl(0, 0%, 75%); + --c80: hsl(0, 0%, 80%); + --c85: hsl(0, 0%, 85%); + --c90: hsl(0, 0%, 90%); + --c95: hsl(0, 0%, 95%); + --c100: hsl(0, 0%, 100%); + --cmax: hsl(0, 0%, 100%); + --bg: var(--c100); + --fg: var(--c00); + --accent-1: hsl(180, 100%, 15%); + --accent-2: hsl(180, 50%, 40%); + --accent-3: hsl(180, 40%, 69%); } body { font: normal 12px var(--family); + background-color: var(--bg); + color: var(--fg); + margin: 0; } body:lang(ja) { font-family: Arial, 'Meiryo UI', 'MS Gothic', system-ui, sans-serif; @@ -31,12 +57,12 @@ button { overflow: hidden; text-overflow: ellipsis; padding: 2px 7px; - border: 1px solid hsl(0, 0%, 62%); + border: 1px solid var(--c60); font: inherit; font-size: 13px; line-height: 1.2; - color: #000; - background-color: hsl(0, 0%, 100%); + color: var(--fg); + background-color: var(--bg); background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAAeCAYAAADtlXTHAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4QwGBBwIHvKt6QAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAAAL0lEQVQI12NoaGgQZ2JgYGBkYmBgYGZiYGBggrMY4VxsYsyoskQQCB2MWAxAMhkADVECDhlW9CoAAAAASUVORK5CYII='); background-repeat: repeat-x; background-size: 100% 100%; @@ -44,13 +70,13 @@ button { } button:not(:disabled):hover { - background-color: hsl(0, 0%, 95%); - border-color: hsl(0, 0%, 52%); + background-color: var(--c95); + border-color: var(--c50); } button:active { - background-color: hsl(0, 0%, 95%); - border-color: hsl(0, 0%, 52%); + background-color: var(--c95); + border-color: var(--c50); background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAAeCAYAAADtlXTHAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4QwJARIWJNZvuQAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAAAMElEQVQI12NoaGgIZmJgYPjLxMDA8I+JgYHhP5z1Dy7xH5X7jxQCzWQ0A9DEILYBABm5HtJk2jPHAAAAAElFTkSuQmCC'); background-repeat: repeat-x; background-size: 100% 100%; @@ -62,27 +88,28 @@ button .svg-icon { /* For some odd reason these hovers appear lighter than all other button hovers in every browser */ #message-box-buttons button:not(:disabled):hover { - background-color: hsl(0, 0%, 90%); - border-color: hsl(0, 0%, 50%); + background-color: var(--c90); + border-color: var(--c50); } input { font: inherit; - border: 1px solid hsl(0, 0%, 66%); + border: 1px solid var(--c65); transition: border-color .1s, box-shadow .1s; } input:not([type]), input[type=text], +input[type=number], input[type=search] { - background: #fff; - color: #000; + background: var(--bg); + color: var(--fg); height: var(--input-height); min-height: var(--input-height)!important; line-height: var(--input-height); box-sizing: border-box; padding: 0 3px; - border: 1px solid hsl(0, 0%, 66%); + border: 1px solid var(--c65); } .svg-icon { @@ -91,11 +118,11 @@ input[type=search] { transition: fill .5s; width: 20px; height: 20px; - fill: #666; + fill: var(--c40); } .svg-icon:hover { - fill: #000; + fill: var(--fg); } .svg-icon.info { @@ -114,7 +141,7 @@ input[type=search] { height: 8px; width: 8px; display: none; - fill: #000; + fill: var(--fg); margin: 2px 0 0 2px; } @@ -129,7 +156,7 @@ input[type="checkbox"]:not(.slider) { position: absolute; left: 0; top: 0; - border: 1px solid hsl(0, 0%, 46%); + border: 1px solid var(--c45); height: 12px; width: 12px; display: inline-flex; @@ -140,8 +167,8 @@ input[type="checkbox"]:not(.slider) { } input[type="checkbox"]:not(.slider):hover { - border-color: hsl(0, 0%, 32%); - background-color: hsl(0, 0%, 82%); + border-color: var(--c30); + background-color: var(--c80); } input[type="checkbox"]:not(.slider):checked + .svg-icon.checked { @@ -153,15 +180,15 @@ input[type="checkbox"]:not(.slider):checked + .svg-icon.checked { input[type="checkbox"]:not(.slider):disabled { background-color: transparent; - border-color: hsl(0, 0%, 50%); + border-color: var(--c50); } input[type="checkbox"]:not(.slider):disabled + .svg-icon.checked { - fill: hsl(0, 0%, 50%); + fill: var(--c50); } input[type="checkbox"]:not(.slider):disabled + .svg-icon.checked + span { - color: hsl(0, 0%, 50%); + color: var(--c50); } label { @@ -173,9 +200,9 @@ select { -webkit-appearance: none; height: var(--input-height); font: inherit; - color: #000; + color: var(--fg); background-color: transparent; - border: 1px solid hsl(0, 0%, 66%); + border: 1px solid var(--c65); padding: 0 20px 0 6px; transition: color .5s; } @@ -193,7 +220,7 @@ select { display: inline-flex; height: 14px; width: 14px; - fill: #000; + fill: var(--fg); position: absolute; top: 4px; right: 4px; @@ -203,9 +230,9 @@ select { input[type="radio"] { -webkit-appearance: none; -moz-appearance: none; - background: hsl(0, 0%, 88%); + background: var(--c90); border-radius: 50%; - border: 1px solid hsl(0, 0%, 60%); + border: 1px solid var(--c60); cursor: default; height: 13px; width: 13px; @@ -227,7 +254,7 @@ input[type="radio"]:after { } input[type="radio"]:checked:after { - background-color: hsl(0, 0%, 30%); + background-color: var(--c30); transform: scale(1); } @@ -241,7 +268,7 @@ select[disabled] > option { select:disabled + .select-arrow, select[disabled] + .select-arrow { - fill: hsl(0, 0%, 50%); + fill: var(--c50); } summary { @@ -289,12 +316,12 @@ input[type="number"][data-focused-via-click]:focus { cursor: e-resize; border-width: 0 1px; border-style: solid; - color: #8888; + color: hsla(0, 0%, 50%, .5); border-color: currentColor; pointer-events: auto; } #header-resizer:active { - border-color: #888; + border-color: var(--c50); } #header-resizer::after { content: ''; @@ -340,13 +367,14 @@ body.resizing-v > * { box-shadow: inset 0 0 100px rgba(0, 0, 0, .2); } .split-btn-menu { - background: #fff; + background: var(--bg); position: absolute; box-shadow: 2px 3px 7px rgba(0, 0, 0, .5); border: 1px solid hsl(180deg, 50%, 50%); white-space: nowrap; cursor: pointer; padding: .25em 0; + z-index: 1000; } .split-btn-menu > * { padding: .5em 1em; @@ -354,7 +382,7 @@ body.resizing-v > * { } .split-btn-menu > :hover { background-color: hsla(180deg, 50%, 50%, .25); - color: #000; + color: var(--fg); } @supports (-moz-appearance: none) { @@ -370,9 +398,9 @@ body.resizing-v > * { /* We can customize everything about number inputs except arrows. They're horrible in Linux FF, so we'll hide them unless hovered or focused. */ .firefox.non-windows input[type="number"] { -moz-appearance: textfield; - background: #fff; - color: #000; - border: 1px solid hsl(0, 0%, 66%); + background: var(--bg); + color: var(--fg); + border: 1px solid var(--c65); } .firefox.non-windows input[type="number"]:not(:disabled):hover, @@ -381,8 +409,8 @@ body.resizing-v > * { } .firefox.non-windows input[type="color"] { - background: #fff; - border: 1px solid hsl(0, 0%, 66%); + background: var(--bg); + border: 1px solid var(--c65); padding: 4px; } } diff --git a/injection-order/injection-order.css b/injection-order/injection-order.css index f864b3b6..3471369e 100644 --- a/injection-order/injection-order.css +++ b/injection-order/injection-order.css @@ -44,7 +44,7 @@ justify-content: space-between; position: relative; /* for incremental-search */ padding: 1px 1px 1px 1rem; /* keyboard focus outline */ - color: #000; + color: var(--fg); transition: transform .25s ease-in-out; z-index: 1; user-select: none; diff --git a/install-usercss.html b/install-usercss.html index 246720c7..1b84de1e 100644 --- a/install-usercss.html +++ b/install-usercss.html @@ -7,6 +7,7 @@ Loading... + @@ -20,8 +21,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/install-usercss/install-usercss.css b/install-usercss/install-usercss.css index b9c09576..7219de42 100644 --- a/install-usercss/install-usercss.css +++ b/install-usercss/install-usercss.css @@ -1,18 +1,16 @@ body { overflow: hidden; - margin: 0; - background: white; display: flex; height: 100vh; } a { - color: #000; + color: var(--fg); transition: color .5s; } a:hover { - color: #666; + color: var(--c40); } img.icon { @@ -21,7 +19,7 @@ img.icon { } input:disabled + span { - color: rgb(128, 128, 128); + color: var(--c50); } #header, @@ -54,7 +52,7 @@ input:disabled + span { flex-basis: auto; background: #ffe2e2; border-right: none; - border-bottom: 1px dashed #aaa; + border-bottom: 1px dashed var(--c65); } .has-warnings .warnings { @@ -143,7 +141,7 @@ h1 { .install:hover:not(:disabled) { background-color: hsl(0, 0%, 38%); - color: #fff; + color: var(--bg); text-shadow: none; } @@ -326,7 +324,7 @@ li { flex-direction: column; } #header { - border-bottom: 1px dashed #AAA; + border-bottom: 1px dashed var(--c65); min-height: 6rem; max-height: 40vh; resize: vertical; diff --git a/install-usercss/install-usercss.js b/install-usercss/install-usercss.js index a121b681..3202e4bb 100644 --- a/install-usercss/install-usercss.js +++ b/install-usercss/install-usercss.js @@ -1,9 +1,12 @@ /* global $$ $ $create $createLink $$remove showSpinner */// dom.js /* global API */// msg.js +/* global CodeMirror */ /* global URLS closeCurrentTab deepEqual */// toolbox.js +/* global compareVersion */// cmpver.js /* global messageBox */ /* global prefs */ /* global preinit */ +/* global styleCodeEmpty */// sections-util.js /* global t */// localization.js 'use strict'; @@ -40,34 +43,14 @@ setTimeout(() => !cm && showSpinner($('#header')), 200); if (theme !== 'default') { require([`/vendor/codemirror/theme/${theme}.css`]); // not awaiting as it may be absent } - const scriptsReady = require([ - '/vendor/codemirror/lib/codemirror', /* global CodeMirror */ - ]).then(() => require([ - '/vendor/codemirror/keymap/sublime', - '/vendor/codemirror/keymap/emacs', - '/vendor/codemirror/keymap/vim', // TODO: load conditionally - '/vendor/codemirror/mode/css/css', - '/vendor/codemirror/mode/stylus/stylus', - '/vendor/codemirror/addon/search/searchcursor', - '/vendor/codemirror/addon/fold/foldcode', - '/vendor/codemirror/addon/fold/foldgutter', - '/vendor/codemirror/addon/fold/brace-fold', - '/vendor/codemirror/addon/fold/indent-fold', - '/vendor/codemirror/addon/selection/active-line', - '/vendor/codemirror/lib/codemirror.css', - '/vendor/codemirror/addon/fold/foldgutter.css', - '/js/cmpver', /* global compareVersion */ - '/js/sections-util', /* global styleCodeEmpty */ - '/js/color/color-converter', - '/edit/codemirror-default.css', - ])).then(() => require([ - '/edit/codemirror-default', - '/js/color/color-view', - ])); - ({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}, @@ -80,7 +63,6 @@ setTimeout(() => !cm && showSpinner($('#header')), 200); messageBox.alert(isNaN(error) ? `${error}` : 'HTTP Error ' + error, 'pre'); return; } - await scriptsReady; cm = CodeMirror($('.main'), { value: sourceCode || style.sourceCode, readOnly: true, diff --git a/js/color/color-mimicry.js b/js/color/color-mimicry.js index c4152b3b..209c6792 100644 --- a/js/color/color-mimicry.js +++ b/js/color/color-mimicry.js @@ -18,7 +18,7 @@ function colorMimicry(el, targets, dummyContainer = document.body) { let numTotal = 0; const rootStyle = getStyle(document.documentElement); for (const k in targets) { - const base = {r: 255, g: 255, b: 255, a: 1}; + const base = {r: 0, g: 0, b: 0, a: 0}; blend(base, rootStyle[targets[k]]); colors[k] = base; numTotal++; @@ -45,6 +45,10 @@ function colorMimicry(el, targets, dummyContainer = document.body) { el.remove(); } for (const k in targets) { + const c = colors[k]; + if (!isOpaque(c)) { + blend(colors[k] = {r: 255, g: 255, b: 255, a: 1}, c); + } const {r, g, b, a} = colors[k]; colors[k] = `rgba(${r}, ${g}, ${b}, ${a})`; // https://www.w3.org/TR/AERT#color-contrast @@ -69,7 +73,7 @@ function colorMimicry(el, targets, dummyContainer = document.body) { base.b = Math.round(b * q1 + base.b * q2); base.a = mixedA; } - return Math.abs(base.a - 1) < 1e-3; + return isOpaque(base); } // speed-up for sequential invocations within the same event loop cycle @@ -86,4 +90,8 @@ function colorMimicry(el, targets, dummyContainer = document.body) { function clearCache() { styleCache.clear(); } + + function isOpaque({a}) { + return Math.abs(a - 1) < 1e-3; + } } diff --git a/js/dark-themer.js b/js/dark-themer.js new file mode 100644 index 00000000..8fc09846 --- /dev/null +++ b/js/dark-themer.js @@ -0,0 +1,33 @@ +/* global $ */// dom.js +/* global API msg */// msg.js +'use strict'; + +/** + * This file must be loaded in a + diff --git a/manage/manage.css b/manage/manage.css index ea4d930e..1561006e 100644 --- a/manage/manage.css +++ b/manage/manage.css @@ -3,9 +3,7 @@ --name-padding-right: 40px; --actions-width: 75px; } - body { - margin: 0; /* Fill the entire viewport to enable json import via drag'n'drop */ display: flex; height: 100vh; @@ -37,12 +35,12 @@ body.all-styles-hidden-by-filters::after { } a, .disabled a:hover { - color: #000; + color: var(--fg); transition: color .5s; } a:hover { - color: #666; + color: var(--c40); } #header { @@ -98,7 +96,7 @@ a:hover { } #add-style-as-usercss-wrapper:not(:hover) input:not(:checked) ~ a svg { - fill: #aaa; + fill: var(--c65); } #add-style-as-usercss-wrapper input { @@ -136,7 +134,7 @@ a:hover { .entry { margin: 0; padding: 1.25em 2em; - border-top: 1px solid #ddd; + border-top: 1px solid var(--c85); } .entry:first-child { @@ -225,7 +223,7 @@ a:hover { content: "UC"; background-color: hsla(180, 35%, 50%, .35); padding: 2px 3px; - color: #000; + color: var(--fg); } .oldUI .disabled h2::after { content: var(--genericDisabledLabel); @@ -244,8 +242,8 @@ a:hover { .disabled h2 .style-name-link, .disabled .applies-to, .newUI .disabled.entry .svg-icon { - color: #888; - fill: #c4c4c4; + color: var(--c50); + fill: var(--c80); font-weight: normal; transition: color .5s .1s, fill .5s .1s; } @@ -311,7 +309,7 @@ a:hover { margin-bottom: .1em; } #header summary:hover h2 { - border-color: #bbb; + border-color: var(--c75); } #header summary h2 [data-cmd="note"] { display: inline-flex; @@ -349,7 +347,7 @@ a:hover { } .style-info[data-type=version] { - color: #666; + color: var(--c40); padding-left: .5em; font-weight: normal; } @@ -359,7 +357,7 @@ a:hover { display: none; } .newUI .entry .style-info[data-type=age] { - color: #999; + color: var(--c60); text-align: right; padding-right: 1em; } @@ -457,11 +455,6 @@ a:hover { margin: 0 .5em; } -.newUI .entry .svg-icon.checked, -.newUI .entry:hover .svg-icon.checked { - fill: #000; -} - .newUI .entry input[type="checkbox"]:not(.slider) { pointer-events: all; } @@ -486,7 +479,7 @@ a:hover { } .newUI .entry.enabled .style-name:hover .style-name-link { - color: hsla(180, 100%, 15%, 1); + color: var(--accent-1); } .newUI .style-name:after { @@ -521,15 +514,18 @@ a:hover { } .newUI .entry .svg-icon { - fill: #999; + fill: var(--c60); } .newUI .entry:hover .svg-icon { - fill: #666; + fill: var(--c40); } +button .svg-icon, +.newUI .entry .svg-icon.checked, +.newUI .entry:hover .svg-icon.checked, .newUI .entry:hover .svg-icon:hover { - fill: #000; + fill: var(--fg); } .newUI .checking-update .check-update { @@ -823,7 +819,7 @@ a:hover { } #reset-filters svg { - fill: hsla(180, 50%, 27%, .5); + fill: var(--accent-2); width: 24px; /* widen the click area a bit */ height: 20px; padding: 2px; @@ -831,7 +827,7 @@ a:hover { } #reset-filters:hover svg { - fill: hsla(180, 50%, 27%, 1); + filter: brightness(1.2); } #filters summary:not(.active) #reset-filters, @@ -866,12 +862,12 @@ a:hover { #search, #manage\.newUI\.sort { min-width: 4em; /* reduces the big default width */ flex-grow: 1; - background: #fff; + background: var(--bg); height: 20px; box-sizing: border-box; padding: 3px 3px 3px 4px; - color: #000; - border: 1px solid hsl(0, 0%, 66%); + color: var(--fg); + border: 1px solid var(--c65); } #manage\.newUI\.sort { @@ -1086,7 +1082,7 @@ a:hover { width: 100%; position: static; border-right: none; - border-bottom: 1px dashed #AAA; + border-bottom: 1px dashed var(--c65); } #manage-settings { @@ -1177,3 +1173,8 @@ a:hover { } } +@media screen and (prefers-color-scheme: dark), dark { + .filter-selection select:not(:focus) { + background-color: transparent; + } +} diff --git a/options.html b/options.html index cf7445c9..92ab77ef 100644 --- a/options.html +++ b/options.html @@ -5,6 +5,7 @@ Stylus + @@ -18,6 +19,7 @@ + @@ -46,26 +48,67 @@ +
+

+
+ + + + + +
+
+

@@ -288,26 +331,6 @@ -
- - - - -
diff --git a/options/onoffswitch.css b/options/onoffswitch.css index 13c5119e..1e5d40b8 100644 --- a/options/onoffswitch.css +++ b/options/onoffswitch.css @@ -32,9 +32,9 @@ height: 12px; padding: 0; line-height: 12px; - border: 0 solid #E3E3E3; + border: 0 solid var(--c90); border-radius: 12px; - background-color: #E0E0E0; + background-color: var(--c85); box-shadow: inset 2px 2px 4px rgba(0,0,0,0.1); pointer-events: none; /* this is just a non-clickable decoration, only `input` is clickable */ } @@ -45,7 +45,7 @@ width: 18px; height: 18px; margin: -3px; - background: #efefef; + background: var(--knob, var(--c95)); position: absolute; top: 0; bottom: 0; @@ -55,7 +55,7 @@ } .onoffswitch input:checked + span { - background-color: #CAEBE3; + background-color: hsla(165, 45%, 50%, .3); } .onoffswitch input:checked + span, .onoffswitch input:checked + span::before { diff --git a/options/options.css b/options/options.css index 45e10486..e47034de 100644 --- a/options/options.css +++ b/options/options.css @@ -8,7 +8,6 @@ html { body { background: none; - margin: 0; font-family: "Helvetica Neue", Helvetica, sans-serif; font-size: 12px; display: flex; @@ -16,7 +15,7 @@ body { width: auto; max-width: 800px; max-height: calc(100vh - 32px); - border: 1px solid #999; + border: 1px solid var(--c60); box-shadow: 0px 5px 15px 3px hsla(0, 0%, 0%, .35); animation: scalein .25s ease-in-out; } @@ -26,7 +25,7 @@ body.scaleout { } #options { - background: #fff; + background: var(--bg); display: flex; flex-direction: column; overflow: hidden; @@ -37,17 +36,17 @@ body.scaleout { } a { - color: #000; + color: var(--fg); transition: color .5s; } a:hover { - color: #666; + color: var(--c40); } a:hover .svg-icon, .svg-icon:hover { - fill: #000; + fill: var(--fg); } .svg-inline-wrapper .svg-icon { @@ -55,12 +54,12 @@ a:hover .svg-icon, } #options-close-icon .svg-icon { - fill: #666; + fill: var(--c40); transition: fill .5s; } #options-close-icon:hover .svg-icon { - fill: #000; + fill: var(--fg); } #options-close-icon { @@ -78,14 +77,14 @@ a:hover .svg-icon, #options-title { font-weight: bold; - background-color: rgb(145, 208, 198); + background-color: var(--accent-3); padding: .75rem 26px .75rem calc(30% + 4px); font-size: 22px; letter-spacing: .5px; position: relative; min-height: 42px; box-sizing: border-box; - border-bottom: 1px solid #999; + border-bottom: 1px solid var(--c40); } #options-title::before { @@ -107,7 +106,7 @@ a:hover .svg-icon, } label.chromium-only > :first-child::after { content: '(Chrome)'; - color: #888; + color: var(--c50); margin-left: .5ex; } @@ -115,7 +114,7 @@ label.chromium-only > :first-child::after { display: flex; align-items: center; margin: 1em 0; - border-bottom: 1px dotted #ccc; + border-bottom: 1px dotted var(--c80); padding: 0 16px .75em; position: relative; } @@ -154,11 +153,12 @@ label, } label > :first-child { - margin-right: 8px; - flex-grow: 1; transition: text-shadow .1s; } - +.items:not(.no-stretch) label > :first-child { + margin-right: 8px; + flex-grow: 1; +} label:not([disabled]):hover > :first-child { text-shadow: 0 0 0.01px rgba(0, 0, 0, .25); } @@ -195,16 +195,14 @@ input[type="color"] { height: 2em; } -.iconset { - display: flex; +input[type=time] { + margin: 0 .5em; + max-width: 7em; /* TODO: remove when strict_min_version >= 57 */ } -.iconset input { - display: block; -} - -.iconset input[type="radio"] { - margin: 2px 4px 0 0; +input[type=radio] { + margin-top: 0; + vertical-align: text-top; } #actions { @@ -215,7 +213,7 @@ input[type="color"] { white-space: nowrap; background-color: rgba(0, 0, 0, .05); margin: 0; - border-top: 1px solid #999; + border-top: 1px solid var(--c60); border-bottom: none; min-height: min-content; /* workaround for old Chrome ~70 bug when the window height is small */ } @@ -275,12 +273,12 @@ html:not(.firefox):not(.opera) #updates { .svg-inline-wrapper .svg-icon { width: 16px; height: 16px; - fill: #666; + fill: var(--c40); vertical-align: sub; } .svg-inline-wrapper:hover .svg-icon { - fill: #000; + fill: var(--fg); } #message-box.note { @@ -296,57 +294,6 @@ html:not(.firefox):not(.opera) #updates { position: relative; } -/* radio group */ -.radio-group-item { - display: flex; - align-items: center; - min-height: 1.5em; -} -.radio-group-item > input { - margin: 0 8px 0 0; - flex-grow: 0; -} -.radio-group-label { - display: block; - margin: 0 0 .3em; -} - -.input-sm { - width: 3em; -} - -/* pixel perfect radio */ -input[type="radio"].radio::after { - position: absolute; - top: -1px; - right: -1px; - bottom: -1px; - left: -1px; - height: auto; - width: auto; - transform: scale(0); -} -input[type="radio"].radio:checked::after { - transform: scale(.65); -} - -@keyframes fadeinout { - 0% { opacity: 0 } - 10% { opacity: 1 } - 25% { opacity: 1 } - 100% { opacity: 0 } -} - -@media (hover: none) { - .expanded-note { - font-size: 90%; - white-space: normal; - color: #666; - margin-top: .5em; - hyphens: auto; - } -} - .sync-status { width: 0; /* together with flex-grow makes it reuse the current width */ flex-grow: 1; diff --git a/popup.html b/popup.html index 4ce7ccc0..05db4daa 100644 --- a/popup.html +++ b/popup.html @@ -5,6 +5,7 @@ +