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 <therealdoctorgonzo@gmail.com>
This commit is contained in:
tophf 2022-02-17 03:10:59 +03:00 committed by GitHub
parent dd38856eda
commit b7cfbe6e66
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
35 changed files with 739 additions and 418 deletions

View File

@ -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."

View File

@ -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);
}
}
}
})();

View File

@ -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) {

View File

@ -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'});
},
};

View File

@ -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);

View File

@ -5,6 +5,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="global.css" rel="stylesheet">
<link href="global-dark.css" rel="stylesheet">
<link id="cm-theme" rel="stylesheet">
<script src="js/polyfill.js"></script>
@ -239,6 +240,7 @@
<link href="js/color/color-picker.css" rel="stylesheet">
<link href="edit/codemirror-default.css" rel="stylesheet">
<link href="edit/edit.css" rel="stylesheet">
<script src="js/dark-themer.js"></script> <!-- must be last in HEAD to avoid FOUC -->
</head>
<body id="stylus-edit">

View File

@ -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;
}
}
}

View File

@ -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);

View File

@ -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);
}

View File

@ -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)'};

View File

@ -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);
}

View File

@ -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;
}

View File

@ -7,14 +7,16 @@
<input id="ss-update-url" type="url" class="w100" i18n-placeholder="styleUpdateUrlLabel">
</div>
<div id="ss-scheme">
<div i18n-text="installPreferSchemeLabel"></div>
<label i18n-text-append="installPreferSchemeNone">
<div i18n-text="preferScheme">
<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">
</label>
<label i18n-text-append="installPreferSchemeDark">
<label i18n-text-append="preferSchemeDark" class="ss-radio">
<input name="ss-scheme" type="radio" value="dark">
</label>
<label i18n-text-append="installPreferSchemeLight">
<label i18n-text-append="preferSchemeLight" class="ss-radio">
<input name="ss-scheme" type="radio" value="light">
</label>
</div>

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, {

159
global-dark.css Normal file
View File

@ -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,<svg xmlns='http://www.w3.org/2000/svg' width='2' height='2' fill='hsl(0, 0%, 35%)'><polygon points='1,0 0,1 2,1'/></svg>");
}
::-webkit-scrollbar-button:single-button:vertical:decrement:hover {
background-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='2' height='2' fill='hsl(0, 0%, 45%)'><polygon points='1,0 0,1 2,1'/></svg>");
}
::-webkit-scrollbar-button:single-button:vertical:decrement:active {
background-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='2' height='2' fill='hsl(0, 0%, 55%)'><polygon points='1,0 0,1 2,1'/></svg>");
}
/* down */
::-webkit-scrollbar-button:single-button:vertical:increment {
background-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='2' height='2' fill='hsl(0, 0%, 35%)'><polygon points='0,0 2,0 1,1'/></svg>");
}
::-webkit-scrollbar-button:single-button:vertical:increment:hover {
background-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='2' height='2' fill='hsl(0, 0%, 45%)'><polygon points='0,0 2,0 1,1'/></svg>");
}
::-webkit-scrollbar-button:single-button:vertical:increment:active {
background-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='2' height='2' fill='hsl(0, 0%, 55%)'><polygon points='0,0 2,0 1,1'/></svg>");
}
/* left */
::-webkit-scrollbar-button:single-button:horizontal:decrement {
background-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='2' height='2' fill='hsl(0, 0%, 35%)'><polygon points='0,1 1,2 1,0'/></svg>");
}
::-webkit-scrollbar-button:single-button:horizontal:decrement:hover {
background-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='2' height='2' fill='hsl(0, 0%, 45%)'><polygon points='0,1 1,2 1,0'/></svg>");
}
::-webkit-scrollbar-button:single-button:horizontal:decrement:active {
background-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='2' height='2' fill='hsl(0, 0%, 55%)'><polygon points='0,1 1,2 1,0'/></svg>");
}
/* right */
::-webkit-scrollbar-button:single-button:horizontal:increment {
background-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='2' height='2' fill='hsl(0, 0%, 35%)'><polygon points='0,0 0,2 1,1'/></svg>");
}
::-webkit-scrollbar-button:single-button:horizontal:increment:hover {
background-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='2' height='2' fill='hsl(0, 0%, 45%)'><polygon points='0,0 0,2 1,1'/></svg>");
}
::-webkit-scrollbar-button:single-button:horizontal:increment:active {
background-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='2' height='2' fill='hsl(0, 0%, 55%)'><polygon points='0,0 0,2 1,1'/></svg>");
}
::-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,<svg xmlns='http://www.w3.org/2000/svg' width='1' height='1' fill='%23505050'><rect width='1' height='1'/></svg>") 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,<svg xmlns='http://www.w3.org/2000/svg' width='1' height='1' fill='%23585858'><rect width='1' height='1'/></svg>");
}
::-webkit-scrollbar-thumb:active {
background-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='1' height='1' fill='%23666'><rect width='1' height='1'/></svg>");
}
::-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);
}
}
}

View File

@ -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;
}
}

View File

@ -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;

View File

@ -7,6 +7,7 @@
<title>Loading...</title>
<link href="global.css" rel="stylesheet">
<link href="global-dark.css" rel="stylesheet">
<script src="js/polyfill.js"></script>
<script src="js/msg.js"></script>
@ -20,8 +21,47 @@
<script src="content/style-injector.js"></script>
<script src="content/apply.js"></script>
<template data-id="jumpToLine">
<span i18n-text="editGotoLine">: <input class="CodeMirror-jump-field" type="text"></span>
</template>
<script src="vendor/codemirror/lib/codemirror.js"></script>
<script src="vendor/codemirror/mode/css/css.js"></script>
<script src="vendor/codemirror/mode/stylus/stylus.js"></script>
<script src="vendor/codemirror/addon/dialog/dialog.js"></script>
<script src="vendor/codemirror/addon/edit/closebrackets.js"></script>
<script src="vendor/codemirror/addon/scroll/annotatescrollbar.js"></script>
<script src="vendor/codemirror/addon/search/searchcursor.js"></script>
<script src="vendor/codemirror/addon/search/matchesonscrollbar.js"></script>
<script src="vendor/codemirror/addon/comment/comment.js"></script>
<script src="vendor/codemirror/addon/selection/active-line.js"></script>
<script src="vendor/codemirror/addon/edit/matchbrackets.js"></script>
<script src="vendor/codemirror/addon/fold/foldcode.js"></script>
<script src="vendor/codemirror/addon/fold/foldgutter.js"></script>
<script src="vendor/codemirror/addon/fold/brace-fold.js"></script>
<script src="vendor/codemirror/addon/fold/indent-fold.js"></script>
<script src="vendor/codemirror/addon/fold/comment-fold.js"></script>
<script src="vendor/codemirror/addon/lint/lint.js"></script>
<script src="vendor/codemirror/addon/hint/show-hint.js"></script>
<script src="vendor/codemirror/addon/hint/css-hint.js"></script>
<script src="vendor/codemirror/keymap/sublime.js"></script>
<script src="vendor/codemirror/keymap/emacs.js"></script>
<script src="vendor/codemirror/keymap/vim.js"></script>
<script src="vendor-overwrites/codemirror-addon/match-highlighter.js"></script>
<script src="edit/codemirror-default.js"></script>
<script src="js/color/color-converter.js"></script>
<script src="js/color/color-view.js"></script>
<script src="js/sections-util.js"></script>
<script src="js/cmpver.js"></script>
<link href="vendor/codemirror/lib/codemirror.css" rel="stylesheet">
<link href="vendor/codemirror/addon/dialog/dialog.css" rel="stylesheet">
<link href="vendor/codemirror/addon/fold/foldgutter.css" rel="stylesheet">
<link href="vendor/codemirror/addon/search/matchesonscrollbar.css" rel="stylesheet">
<link href="edit/codemirror-default.css" rel="stylesheet">
<link href="spinner.css" rel="stylesheet">
<link href="install-usercss/install-usercss.css" rel="stylesheet">
<script src="js/dark-themer.js"></script> <!-- must be last in HEAD to avoid FOUC -->
</head>
<body id="stylus-install-usercss">
<div id="header">
@ -80,6 +120,11 @@
</div>
<svg xmlns="http://www.w3.org/2000/svg" style="display: none !important;">
<symbol id="svg-icon-help" viewBox="0 0 14 16" i18n-alt="helpAlt">
<circle cx="7" cy="5" r="1"/>
<path d="M8,8c0-0.5-0.5-1-1-1H6C5.5,7,5,7.4,5,8h1v3c0,0.5,0.5,1,1,1h1c0.5,0,1-0.4,1-1H8V8z"/>
<path d="M7,1c3.9,0,7,3.1,7,7s-3.1,7-7,7s-7-3.1-7-7S3.1,1,7,1z M7,2.3C3.9,2.3,1.3,4.9,1.3,8s2.6,5.7,5.7,5.7s5.7-2.6,5.7-5.7S10.1,2.3,7,2.3C7,2.3,7,2.3,7,2.3z"/>
</symbol>
<symbol id="svg-icon-checked" viewBox="0 0 1000 1000">
<path fill-rule="evenodd" d="M983.2,184.3L853,69.8c-4-3.5-9.3-5.3-14.5-5c-5.3,0.4-10.3,2.8-13.8,6.8L352.3,609.2L184.4,386.9c-3.2-4.2-8-7-13.2-7.8c-5.3-0.8-10.6,0.6-14.9,3.9L18,487.5c-8.8,6.7-10.6,19.3-3.9,28.1L325,927.2c3.6,4.8,9.3,7.7,15.3,8c0.2,0,0.5,0,0.7,0c5.8,0,11.3-2.5,15.1-6.8L985,212.6C992.3,204.3,991.5,191.6,983.2,184.3z"/>
</symbol>

View File

@ -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;

View File

@ -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,

View File

@ -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;
}
}

33
js/dark-themer.js Normal file
View File

@ -0,0 +1,33 @@
/* global $ */// dom.js
/* global API msg */// msg.js
'use strict';
/**
* 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 by the time this script runs.
* The CSS must use `@media screen and (prefers-color-scheme: dark), dark {}` that also works
* in old browsers and ensures CSS loads before the first paint, then we toggle the media 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('darkUI').then(val => {
let isDark = val;
toggleDarkStyles();
msg.onExtension(e => {
if (e.method === 'colorScheme') {
isDark = e.value;
toggleDarkStyles();
}
});
function toggleDarkStyles() {
$.root.dataset.uiTheme = isDark ? 'dark' : 'light';
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 ? 'screen,dark' : 'not all,dark';
}
}
}
}
});

View File

@ -49,7 +49,7 @@
}
.config-body label:not(:first-child) {
border-top: 1px dotted #ccc;
border-top: 1px dotted var(--c80);
}
.config-body .dirty {
@ -125,7 +125,7 @@
.config-reset-icon .svg-icon {
cursor: pointer;
fill: #aaa;
fill: var(--c65);
width: var(--pad);
height: var(--pad);
padding: 0 1px;
@ -134,7 +134,7 @@
}
.config-reset-icon:hover .svg-icon {
fill: #666;
fill: var(--c40);
}
#config-autosave-wrapper {
@ -188,7 +188,7 @@
position: absolute;
top: 0;
left: 0;
border: 1px solid gray;
border: 1px solid var(--c50);
cursor: pointer;
opacity: 1;
z-index: 2;

View File

@ -26,7 +26,7 @@
position: fixed;
display: flex;
flex-direction: column;
background-color: white;
background-color: var(--bg);
box-shadow: 5px 5px 50px rgba(0, 0, 0, 0.225);
z-index: 9999991;
-moz-user-select: text;
@ -68,7 +68,7 @@
#message-box-title {
font-weight: bold;
background-color: rgb(145, 208, 198);
background-color: var(--accent-3);
padding: .75rem 24px .75rem 52px;
font-size: 1rem;
position: relative;
@ -143,7 +143,7 @@
#message-box-buttons {
padding: .75rem .375rem;
background-color: #f0f0f0;
background-color: var(--c95);
text-align: center;
}

View File

@ -278,7 +278,7 @@ function moveFocus(rootElement, step) {
function onDOMready() {
return document.readyState !== 'loading'
? Promise.resolve()
: new Promise(resolve => document.on('DOMContentLoaded', resolve, {once: true}));
: new Promise(resolve => document.on('DOMContentLoaded', () => resolve(), {once: true}));
}
/**
@ -500,11 +500,10 @@ const dom = {};
}
// add favicon in FF
if (FIREFOX) {
const iconset = ['', 'light/'][prefs.get('iconset')] || '';
for (const size of [38, 32, 19, 16]) {
document.head.appendChild($create('link', {
rel: 'icon',
href: `/images/icon/${iconset}${size}.png`,
href: `/images/icon/${size}.png`,
sizes: size + 'x' + size,
}));
}

View File

@ -32,7 +32,7 @@
// checkbox in style config dialog
'config.autosave': true,
'schemeSwitcher.enabled': 'never',
'schemeSwitcher.enabled': 'system',
'schemeSwitcher.nightStart': '18:00',
'schemeSwitcher.nightEnd': '06:00',
@ -120,9 +120,9 @@
'sync.enabled': 'none',
'iconset': 0, // 0 = dark-themed icon
'iconset': -1, // 0 = dark-themed icon
// 1 = light-themed icon
// -1 = match dark/light mode
'badgeDisabled': '#8B0000', // badge background color when disabled
'badgeNormal': '#006666', // badge background color

View File

@ -6,6 +6,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title i18n-text="manageTitle"></title>
<link rel="stylesheet" href="global.css">
<link href="global-dark.css" rel="stylesheet">
<!-- Notes:
* Chrome doesn't garbage-collect (or even leaks) SVG <symbol> referenced via <use> so we'll embed the code directly
@ -155,6 +156,7 @@
<script src="manage/manage.js"></script>
<link rel="stylesheet" href="manage/manage.css">
<script src="js/dark-themer.js"></script> <!-- must be last in HEAD to avoid FOUC -->
</head>
<body id="stylus-manage" i18n-dragndrop-hint="dragDropMessage">

View File

@ -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;
}
}

View File

@ -5,6 +5,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title i18n-text-append="optionsHeading">Stylus </title>
<link rel="stylesheet" href="global.css">
<link href="global-dark.css" rel="stylesheet">
<script src="js/polyfill.js"></script>
<script src="js/toolbox.js"></script>
@ -18,6 +19,7 @@
<link rel="stylesheet" href="options/onoffswitch.css">
<link rel="stylesheet" href="options/options.css">
<script src="js/dark-themer.js"></script> <!-- must be last in HEAD to avoid FOUC -->
</head>
<body id="stylus-options">
@ -46,26 +48,67 @@
</div>
</div>
<div class="block">
<h1 i18n-text="stylePreferSchemeLabel"></h1>
<div class="items no-stretch">
<label>
<span i18n-text-append="preferSchemeDark">
<input type="radio" value="dark" name="schemeSwitcher.enabled">
</span>
</label>
<label>
<span i18n-text-append="preferSchemeLight">
<input type="radio" value="light" name="schemeSwitcher.enabled">
</span>
</label>
<label>
<span i18n-text-append="optionsAdvancedAutoSwitchSchemeBySystem">
<input type="radio" value="system" name="schemeSwitcher.enabled">
</span>
</label>
<label>
<span i18n-text-append="optionsAdvancedAutoSwitchSchemeByTime">
<input type="radio" value="time" name="schemeSwitcher.enabled">
</span>
<input type="time" required id="schemeSwitcher.nightStart">
~
<input type="time" required id="schemeSwitcher.nightEnd">
</label>
<label>
<span i18n-text-append="optionsAdvancedAutoSwitchSchemeNever">
<input type="radio" value="never" name="schemeSwitcher.enabled">
</span>
</label>
</div>
</div>
<div class="block">
<h1 i18n-text="optionsCustomizeIcon"></h1>
<div class="items">
<label>
<span i18n-text="optionsIconDark"></span>
<div class="iconset">
<span i18n-text-append="optionsIconAuto">
<input type="radio" name="iconset" value="-1" data-value-type="number">
</span>
</label>
<label>
<span i18n-text-append="optionsIconDark">
<input type="radio" name="iconset" value="0" data-value-type="number">
</span>
<span>
<img src="/images/icon/16.png">
<img src="/images/icon/16w.png">
<img src="/images/icon/16x.png">
</div>
</span>
</label>
<label>
<span i18n-text="optionsIconLight"></span>
<div class="iconset">
<span i18n-text-append="optionsIconLight">
<input type="radio" name="iconset" value="1" data-value-type="number">
</span>
<span>
<img src="/images/icon/light/16.png">
<img src="/images/icon/light/16w.png">
<img src="/images/icon/light/16x.png">
</div>
</span>
</label>
</div>
</div>
@ -288,26 +331,6 @@
<span></span>
</span>
</label>
<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>
<label class="radio-group-item">
<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">
<span>
<span i18n-text="optionsAdvancedAutoSwitchSchemeByTime"></span>
<input type="text" pattern="\d{2}:\d{2}" required id="schemeSwitcher.nightStart" class="input-sm">
~
<input type="text" pattern="\d{2}:\d{2}" required id="schemeSwitcher.nightEnd" class="input-sm">
</span>
</label>
</div>
</div>
</div>

View File

@ -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 {

View File

@ -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;

View File

@ -5,6 +5,7 @@
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="global.css">
<link href="global-dark.css" rel="stylesheet">
<template data-id="style">
<div class="entry">
@ -171,6 +172,7 @@
<script src="content/apply.js"></script>
<link rel="stylesheet" href="popup/popup.css">
<script src="js/dark-themer.js"></script> <!-- must be last in HEAD to avoid FOUC -->
</head>
<body id="stylus-popup">

View File

@ -11,12 +11,7 @@ html, body {
body {
width: 252px;
margin: 0;
}
.firefox body {
color: #000;
background-color: #fff;
overflow: hidden;
}
.firefox button {
@ -33,14 +28,10 @@ body > div:not(#installed):not(#message-box):not(.colorpicker-popup) {
}
/************ checkbox ************/
.style-name:hover .checker:checked {
border-color: hsl(0, 0%, 32%);
background-color: hsl(0, 0%, 82%);
}
.style-name:hover .checker:checked,
.style-name:hover .checker {
border-color: hsl(0, 0%, 32%);
background-color: hsl(0, 0%, 82%);
border-color: var(--c30);
background-color: var(--c80);
}
#disable-all-wrapper input[type="checkbox"]:not(.slider):checked + .svg-icon.checked {
@ -59,7 +50,7 @@ body > div:not(#installed):not(#message-box):not(.colorpicker-popup) {
}
#installed.disabled + .actions #disableAll:checked:hover + .svg-icon.checked {
fill: #fff;
fill: var(--bg);
}
#disableAll:hover {
@ -119,12 +110,12 @@ body > div:not(#installed):not(#message-box):not(.colorpicker-popup) {
}
a {
color: #000;
color: var(--fg);
transition: color .5s;
}
a:hover {
color: #666;
color: var(--c40);
}
.actions > .main-controls {
@ -141,7 +132,7 @@ body.blocked > DIV {
}
#installed {
border-bottom: 1px solid black;
border-bottom: 1px solid var(--c85);
max-height: 445px;
overflow-y: auto;
counter-reset: style-number;
@ -181,10 +172,6 @@ html[style] .entry-content {
padding: 0 var(--hotkey-margin) 0 0;
}
#no-styles.entry {
padding: 0 14px;
}
.entry .actions {
display: inline-flex;
align-items: center;
@ -224,14 +211,14 @@ html[style] .entry-content {
.entry.disabled .style-name,
.entry.disabled .svg-icon {
font-weight: normal;
color: #888;
fill: #aaa;
color: var(--c50);
fill: var(--c65);
}
.entry.disabled:hover .svg-icon {
fill: #666;
fill: var(--c40);
}
.entry.disabled:hover a:hover .svg-icon {
fill: #000;
fill: var(--fg);
}
.entry .main-controls {
@ -243,8 +230,14 @@ html[style] .entry-content {
padding-right: 5px;
}
.entry:nth-child(even) {
background-color: rgba(0, 0, 0, 0.05);
[data-ui-theme="light"] .zebra .entry:nth-child(even),
[data-ui-theme="light"] .reverse-zebra .entry:nth-child(odd) {
background-color: hsla(0, 0%, 50%, 0.1);
}
[data-ui-theme="dark"] .zebra .entry:nth-child(even),
[data-ui-theme="dark"] .reverse-zebra .entry:nth-child(odd) {
background-color: hsla(0, 0%, 50%, 0.05);
}
.entry:nth-child(-n+10):before,
@ -254,7 +247,7 @@ html[style] .entry-content {
position: absolute;
top: .9ex;
right: 5px;
color: #aaa;
color: var(--c65);
}
.entry:nth-child(11):before {
@ -367,7 +360,7 @@ a.configure[target="_blank"] .svg-icon.config {
display: flex;
position: relative;
flex-direction: column;
background-color: #fff;
background-color: var(--bg);
border: solid 2px rgba(0, 0, 0, 0.5);
}
.menu-buttons-wrapper {
@ -393,7 +386,7 @@ a.configure[target="_blank"] .svg-icon.config {
}
.entry .menu-item:hover,
.entry .menu-item:active {
background-color: rgba(0, 0, 0, 0.1);
background-color: var(--c95);
transition: background-color .25s;
}
.entry .menu-icon {
@ -445,16 +438,16 @@ a.configure[target="_blank"] .svg-icon.config {
#regexp-explanation {
position: fixed;
background-color: white;
background-color: var(--bg);
top: 50%;
transform: translateY(-50%);
left: 0;
right: 0;
padding: .5rem;
font-size: 90%;
border-top: 2px solid black;
border-bottom: 2px solid black;
box-shadow: 0 0 100px black;
border-top: 2px solid var(--fg);
border-bottom: 2px solid var(--fg);
box-shadow: 0 0 100px var(--fg);
display: flex;
flex-direction: column;
z-index: 999999;
@ -483,7 +476,7 @@ a.configure[target="_blank"] .svg-icon.config {
}
a:hover .svg-icon {
fill: #000;
fill: var(--fg);
}
body > .actions {
@ -620,7 +613,7 @@ body.blocked .actions > .main-controls {
}
.breadcrumbs:hover a {
color: #bbb;
color: var(--c75);
text-decoration: none
}
@ -714,7 +707,7 @@ html:not(.styles-last) .split-btn-pedal::after {
order: 2;
}
.styles-last #installed {
border-top: 1px solid black;
border-top: 1px solid var(--fg);
}
/* confirm */
@ -756,7 +749,7 @@ html:not(.styles-last) .split-btn-pedal::after {
max-height: 80%;
min-height: 6em;
padding: 1em;
background-color: #fff;
background-color: var(--bg);
display: flex;
flex-direction: column;
border: solid 2px rgba(0, 0, 0, 0.5);
@ -780,7 +773,7 @@ html:not(.styles-last) .split-btn-pedal::after {
max-height: 80%;
min-height: 6em;
padding: 1em;
background-color: #fff;
background-color: var(--bg);
display: flex;
flex-direction: column;
border: solid 2px rgba(0, 0, 0, 0.5);
@ -810,7 +803,7 @@ html:not(.styles-last) .split-btn-pedal::after {
}
.unreachable .blocked-info {
border-bottom: 1px solid black;
border-bottom: 1px solid var(--fg);
}
.blocked-info {
@ -843,12 +836,12 @@ html:not(.styles-last) .split-btn-pedal::after {
}
.blocked-info .copy:hover {
color: #000;
color: var(--fg);
}
.blocked-info .copy.copied {
background: hsl(170, 40%, 80%);
color: #000;
color: var(--fg);
}
.copy-message {
@ -863,7 +856,7 @@ html:not(.styles-last) .split-btn-pedal::after {
text-align: center;
padding: 4px 0;
background: hsl(170, 40%, 80%);
color: #000;
color: var(--fg);
z-index: 10;
}
@ -907,7 +900,7 @@ html:not(.styles-last) .split-btn-pedal::after {
cursor: auto;
display: flex;
flex-direction: column;
border-left: 2px solid white;
border-left: 2px solid var(--bg);
box-shadow: 0 0 90px rgba(0, 0, 0, .5);
z-index: 5;
}
@ -921,8 +914,8 @@ html:not(.styles-last) .split-btn-pedal::after {
#hotkey-info div {
padding: 1em;
border-top: 1px solid #ddd;
background-color: white;
border-top: 1px solid var(--c85);
background-color: var(--bg);
}
#hotkey-info div:last-child {
@ -940,10 +933,10 @@ html:not(.styles-last) .split-btn-pedal::after {
#hotkey-info mark {
display: inline-block;
background: linear-gradient(#ccc, #fff);
background: linear-gradient(var(--c80), var(--bg));
padding: 1px 6px 0;
margin: 2px;
border: 1px solid white;
border: 1px solid var(--bg);
border-radius: 4px;
box-shadow: 1px 1px 4px rgba(0, 0, 0, .3);
font-weight: bold;

View File

@ -293,6 +293,9 @@ function showStyles(frameResults) {
} else {
installed.appendChild(t.template.noStyles);
}
const zebra = $('.entry:last-child:nth-child(odd)') &&
!$('.styles-last') ? 'reverse-zebra' : 'zebra';
$('#installed').classList.add(`${zebra}`);
require(['/popup/hotkeys']);
}

View File

@ -49,19 +49,19 @@ body.search-results-shown {
.search-result {
box-shadow: 1px 1px 10px rgba(0, 0, 0, .75);
border-radius: 4px;
border: 1px solid #555;
border: 1px solid var(--c50);
margin-bottom: 24px;
background-color: #eee;
background-color: var(--c95);
}
.search-result:hover {
border-color: #000;
background-color: #fff;
border-color: var(--fg);
background-color: var(--c90);
}
#search-results .lds-spinner {
transform: scale(.5);
filter: invert(1) drop-shadow(1px 1px 3px #000);
filter: invert(1) drop-shadow(1px 1px 3px var(--fg));
}
#search-results .search-result-empty .lds-spinner {
@ -79,7 +79,7 @@ body.search-results-shown {
display: flex;
align-items: center;
margin-bottom: .5em;
color: #555;
color: var(--c30);
overflow-wrap: break-word;
}
@ -95,7 +95,7 @@ body.search-results-shown {
}
.search-result:hover .search-result-title {
color: initial;
color: var(--fg);
}
.search-result-info {
@ -110,7 +110,7 @@ body.search-results-shown {
text-align: center;
position: absolute;
background-color: hsla(180, 100%, 27%, .75);
color: #fff;
color: var(--bg);
transition: background-color .5s;
pointer-events: none;
}
@ -123,7 +123,7 @@ body.search-results-shown {
}
.search-result-screenshot:hover ~ .search-result-status {
background-color: hsla(180, 100%, 27%, 1);
color: #fff;
color: var(--bg);
}
.search-result-actions {
@ -142,7 +142,7 @@ body.search-results-shown {
opacity: 1;
}
.search-result-actions button {
box-shadow: 2px 2px 20px #000;
box-shadow: 2px 2px 20px var(--fg);
white-space: nowrap;
margin: 3px;
}
@ -160,7 +160,6 @@ body.search-results-shown {
}
.search-result-meta {
background-color: hsla(0, 0%, 93%, 0.75);
display: flex;
justify-content: space-between;
flex-wrap: wrap;
@ -171,9 +170,25 @@ body.search-results-shown {
margin: 0;
padding-bottom: 3px;
}
.search-result-meta::before {
transition: .25s;
background-color: var(--c95);
opacity: .65;
content: '';
position: absolute;
left: 0;
right: 0;
bottom: 0;
height: 22px;
z-index: 1;
}
.search-result-meta > * {
z-index: 2;
}
.search-result:hover .search-result-meta {
background-color: hsla(0, 0%, 100%, 0.75);
.search-result:hover .search-result-meta::before {
background-color: var(--c90);
opacity: 1;
}
.search-result-meta dt {