diff --git a/res/css/categories.css b/res/css/categories.css index 8d1d533854..6ec2b8e2e4 100644 --- a/res/css/categories.css +++ b/res/css/categories.css @@ -20,6 +20,22 @@ --category-color-darkgrey: var(--grey-50); } +@supports (color-scheme: dark) { + @media (prefers-color-scheme: dark) { + :root { + --category-color-purple: var(--purple-60); + --category-color-green: var(--green-80); + --category-color-orange: var(--orange-60); + --category-color-yellow: var(--yellow-70); + --category-color-magenta: var(--magenta-70); + --category-color-gray: var(--grey-50); + --category-color-grey: var(--grey-50); + --category-color-darkgray: var(--grey-60); + --category-color-darkgrey: var(--grey-60); + } + } +} + /** * These classes should be used to create a small color swatch to describe a * category. They should be used with the class `colored-square` that's defined diff --git a/res/css/focus.css b/res/css/focus.css index a6291dcff1..3925aa3858 100644 --- a/res/css/focus.css +++ b/res/css/focus.css @@ -18,15 +18,15 @@ input[type='range']:focus-visible, select:focus-visible, button:focus-visible { box-shadow: - 0 0 0 1px var(--blue-50) inset, - 0 0 0 1px var(--blue-50), - 0 0 0 4px var(--blue-50-a30); + 0 0 0 1px var(--focus-border-color) inset, + 0 0 0 1px var(--focus-border-color), + 0 0 0 4px var(--focus-shadow-color); outline: 0; } a:focus-visible { box-shadow: - 0 0 0 2px var(--blue-50), - 0 0 0 6px var(--blue-50-a30); + 0 0 0 2px var(--focus-border-color), + 0 0 0 6px var(--focus-shadow-color); outline: 0; } diff --git a/res/css/global.css b/res/css/global.css index 72c99c9064..8d4b99bc3a 100644 --- a/res/css/global.css +++ b/res/css/global.css @@ -2,6 +2,102 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +:root { + --base-foreground-color: #000; + --base-background-color: #fff; + --base-border-color: var(--grey-30); + --base-shadow-color: rgb(0 0 0 / 0.2); + --link-foreground-color: var(--blue-60); + --link-visited-foreground-color: var(--purple-70); + --link-active-foreground-color: var(--red-50); + --clickable-foreground-color: var(--grey-90); + --clickable-background-color: var(--grey-90-a10); + --clickable-border-color: var(--grey-90-a30); + --clickable-hover-background-color: var(--grey-90-a20); + --clickable-active-background-color: var(--grey-90-a30); + --clickable-ghost-hover-background-color: var(--grey-90-a10); + --clickable-ghost-active-background-color: var(--grey-90-a20); + --clickable-checked-background-color: var(--blue-60); + --clickable-checked-hover-background-color: var(--blue-70); + --clickable-checked-active-background-color: var(--blue-80); + --focus-border-color: var(--blue-50); + --focus-shadow-color: var(--blue-50-a30); + --kbd-foreground-color: var(--base-foreground-color); + --kbd-background-color: #f6f6f6; + --kbd-border-color: #ccc; + --kbd-shadow-color: #bbb; + --home-border-color: #ccc; + --home-shadow-color: #0b1f50; + --row-odd-background-color: #f5f5f5; + --panel-foreground-color: var(--ink-70); + --panel-background-color: var(--grey-10); + --panel-border-color: var(--grey-30); + --track-selected-background-color: #edf6ff; + --tooltip-number-foreground-color: var(--grey-60); + --colored-border-color: rgb(0 0 0 / 0.1); + + background-color: var(--base-background-color); + color: var(--base-foreground-color); +} + +@supports (color-scheme: dark) { + @media (prefers-color-scheme: dark) { + :root { + --base-foreground-color: var(--grey-20); + --base-background-color: var(--ink-90); + --base-border-color: var(--grey-50); + --base-shadow-color: rgb(0 0 0 / 0.4); + --link-foreground-color: var(--blue-40); + --link-visited-foreground-color: var(--purple-40); + --link-active-foreground-color: var(--red-50); + --clickable-foreground-color: var(--grey-20); + --clickable-background-color: var(--grey-10-a10); + --clickable-border-color: var(--grey-10-a40); + --clickable-hover-background-color: var(--grey-10-a20); + --clickable-active-background-color: var(--grey-10-a40); + --clickable-ghost-hover-background-color: var(--grey-10-a10); + --clickable-ghost-active-background-color: var(--grey-10-a20); + --clickable-checked-background-color: var(--blue-50); + --clickable-checked-hover-background-color: var(--blue-60); + --clickable-checked-active-background-color: var(--blue-70); + --focus-border-color: var(--blue-40); + --focus-shadow-color: var(--blue-50-a30); + --kbd-background-color: var(--ink-70); + --kbd-border-color: var(--ink-60); + --kbd-shadow-color: var(--ink-50); + --home-border-color: var(--ink-70); + --home-shadow-color: var(--ink-90); + --row-odd-background-color: color-mix( + in hsl, + var(--ink-80) 50%, + var(--ink-90) 50% + ); + --panel-foreground-color: var(--grey-20); + --panel-background-color: var(--ink-80); + --panel-border-color: var(--ink-60); + --selected-track-background-color: color-mix( + in hsl, + var(--ink-90) 80%, + var(--teal-50) 20% + ); + --tooltip-number-foreground-color: var(--grey-40); + --colored-border-color: rgb(237 237 240 / 0.1); + } + } +} + +a { + color: var(--link-foreground-color); +} + +a:visited { + color: var(--link-visited-foreground-color); +} + +a:active { + color: var(--link-active-foreground-color); +} + /** * This class should be used to create a small colored square. It's used * especially for categories and network mime types. @@ -11,7 +107,7 @@ width: 9px; height: 9px; box-sizing: border-box; - border: 0.5px solid rgb(0 0 0 / 0.1); + border: 0.5px solid var(--colored-border-color); margin-right: 3px; /* Opt-out of forced colors so the color is applied */ @@ -19,7 +115,7 @@ } .colored-border { - border: 2px solid rgb(0 0 0 / 0.1); + border: 2px solid var(--colored-border-color); margin-right: 3px; /* Opt-out of forced colors so the color is applied */ diff --git a/res/css/photon/button.css b/res/css/photon/button.css index aeff4be412..14eccf58ea 100644 --- a/res/css/photon/button.css +++ b/res/css/photon/button.css @@ -4,6 +4,15 @@ /* See https://design.firefox.com/photon/components/buttons.html for the spec */ .photon-button { + --internal-primary-foreground-color: #fff; + --internal-primary-background-color: var(--blue-60); + --internal-primary-hover-background-color: var(--blue-70); + --internal-primary-active-background-color: var(--blue-80); + --internal-destructive-foreground-color: #fff; + --internal-destructive-background-color: var(--red-60); + --internal-destructive-hover-background-color: var(--red-70); + --internal-destructive-active-background-color: var(--red-80); + /* These flex and sizing properties aren't necessary when a real string; + readonly getUnselectedFillStyle: () => string; + readonly getSelectedTextColor: () => string; readonly gravity: number; }; -const GRAY_STYLE = { - selectedFillStyle: GREY_40, - unselectedFillStyle: GREY_40 + '60', - selectedTextColor: '#000', +const DEFAULT_STYLE: ColorStyles = { + _selectedFillStyle: ['#ffffff', '#0f1126'], + _unselectedFillStyle: ['#ffffff60', '#0f112660'], + _selectedTextColor: ['#000000', GREY_20], + getSelectedFillStyle: function () { + return maybeLightDark(this._selectedFillStyle); + }, + getUnselectedFillStyle: function () { + return maybeLightDark(this._unselectedFillStyle); + }, + getSelectedTextColor: function () { + return maybeLightDark(this._selectedTextColor); + }, + gravity: 0, +}; + +const PSEUDO_TRANSPARENT_STYLE: ColorStyles = { + ...DEFAULT_STYLE, + _selectedFillStyle: [GREY_30, GREY_70], + _unselectedFillStyle: [GREY_30 + '60', GREY_70 + '60'], + _selectedTextColor: ['#000', GREY_20], + gravity: 8, +}; + +const GRAY_STYLE: ColorStyles = { + ...DEFAULT_STYLE, + _selectedFillStyle: [GREY_40, GREY_50], + _unselectedFillStyle: [GREY_40 + '60', GREY_50 + '60'], + _selectedTextColor: ['#000', GREY_20], gravity: 10, }; -const DARK_GRAY_STYLE = { - selectedFillStyle: GREY_50, - unselectedFillStyle: GREY_50 + '60', - selectedTextColor: '#fff', +const DARK_GRAY_STYLE: ColorStyles = { + ...DEFAULT_STYLE, + _selectedFillStyle: [GREY_50, GREY_60], + _unselectedFillStyle: [GREY_50 + '60', GREY_60 + '60'], + _selectedTextColor: '#fff', gravity: 11, }; const STYLE_MAP: { [key: string]: ColorStyles } = { transparent: { - selectedFillStyle: 'transparent', - unselectedFillStyle: 'transparent', - selectedTextColor: '#000', + ...DEFAULT_STYLE, + _selectedFillStyle: 'transparent', + _unselectedFillStyle: 'transparent', + _selectedTextColor: ['#000', GREY_20], gravity: 0, }, lightblue: { - selectedFillStyle: BLUE_40, + ...DEFAULT_STYLE, + _selectedFillStyle: BLUE_40, // Colors are assumed to have the form #RRGGBB, so concatenating 2 more digits to // the end defines the transparency #RRGGBBAA. - unselectedFillStyle: BLUE_40 + '60', - selectedTextColor: '#000', + _unselectedFillStyle: BLUE_40 + '60', + _selectedTextColor: ['#000', GREY_20], gravity: 1, }, red: { - selectedFillStyle: RED_60, - unselectedFillStyle: RED_60 + '60', - selectedTextColor: '#fff', + ...DEFAULT_STYLE, + _selectedFillStyle: RED_60, + _unselectedFillStyle: RED_60 + '60', + _selectedTextColor: '#fff', gravity: 1, }, lightred: { - selectedFillStyle: RED_70 + '60', - unselectedFillStyle: RED_70 + '30', - selectedTextColor: '#000', + ...DEFAULT_STYLE, + _selectedFillStyle: RED_70 + '60', + _unselectedFillStyle: RED_70 + '30', + _selectedTextColor: ['#000', GREY_20], gravity: 1, }, orange: { - selectedFillStyle: ORANGE_50, - unselectedFillStyle: ORANGE_50 + '60', - selectedTextColor: '#fff', + ...DEFAULT_STYLE, + _selectedFillStyle: [ORANGE_50, ORANGE_60], + _unselectedFillStyle: [ORANGE_50 + '60', ORANGE_60 + '60'], + _selectedTextColor: '#fff', gravity: 2, }, blue: { - selectedFillStyle: BLUE_60, - unselectedFillStyle: BLUE_60 + '60', - selectedTextColor: '#fff', + ...DEFAULT_STYLE, + _selectedFillStyle: BLUE_60, + _unselectedFillStyle: BLUE_60 + '60', + _selectedTextColor: '#fff', gravity: 3, }, green: { - selectedFillStyle: GREEN_60, - unselectedFillStyle: GREEN_60 + '60', - selectedTextColor: '#fff', + ...DEFAULT_STYLE, + _selectedFillStyle: [GREEN_60, GREEN_80], + _unselectedFillStyle: [GREEN_60 + '60', GREEN_80 + '60'], + _selectedTextColor: '#fff', gravity: 4, }, purple: { - selectedFillStyle: PURPLE_70, - unselectedFillStyle: PURPLE_70 + '60', - selectedTextColor: '#fff', + ...DEFAULT_STYLE, + _selectedFillStyle: [PURPLE_70, PURPLE_60], + _unselectedFillStyle: [PURPLE_70 + '60', PURPLE_60 + '60'], + _selectedTextColor: '#fff', gravity: 5, }, yellow: { - selectedFillStyle: '#ffe129', // This yellow has more contrast than YELLOW_50. - unselectedFillStyle: YELLOW_50 + '70', - selectedTextColor: '#000', + ...DEFAULT_STYLE, + _selectedFillStyle: [ + // This yellow has more contrast than YELLOW_50. + '#ffe129', + YELLOW_70, + ], + _unselectedFillStyle: [YELLOW_50 + '70', YELLOW_60 + '70'], + _selectedTextColor: ['#000', GREY_20], gravity: 6, }, brown: { - selectedFillStyle: ORANGE_70, - unselectedFillStyle: ORANGE_70 + '60', - selectedTextColor: '#fff', + ...DEFAULT_STYLE, + _selectedFillStyle: ORANGE_70, + _unselectedFillStyle: ORANGE_70 + '60', + _selectedTextColor: '#fff', gravity: 7, }, magenta: { - selectedFillStyle: MAGENTA_60, - unselectedFillStyle: MAGENTA_60 + '60', - selectedTextColor: '#fff', + ...DEFAULT_STYLE, + _selectedFillStyle: [MAGENTA_60, MAGENTA_70], + _unselectedFillStyle: [MAGENTA_60 + '60', MAGENTA_70 + '60'], + _selectedTextColor: '#fff', gravity: 8, }, lightgreen: { - selectedFillStyle: GREEN_50, - unselectedFillStyle: GREEN_50 + '60', - selectedTextColor: '#fff', + ...DEFAULT_STYLE, + _selectedFillStyle: [GREEN_50, GREEN_70], + _unselectedFillStyle: [GREEN_50 + '60', GREEN_70 + '60'], + _selectedTextColor: '#fff', gravity: 9, }, gray: GRAY_STYLE, @@ -200,12 +247,15 @@ export function mapCategoryColorNameToStackChartStyles( colorName: string ): ColorStyles { if (colorName === 'transparent') { - return { - selectedFillStyle: GREY_30, - unselectedFillStyle: GREY_30 + '60', - selectedTextColor: '#000', - gravity: 8, - }; + return PSEUDO_TRANSPARENT_STYLE; } return mapCategoryColorNameToStyles(colorName); } + +export function getForegroundColor(): string { + return lightDark('#000000', GREY_20); +} + +export function getBackgroundColor(): string { + return lightDark('#ffffff', INK_90); +} diff --git a/src/utils/dark-mode.ts b/src/utils/dark-mode.ts new file mode 100644 index 0000000000..e63131c46a --- /dev/null +++ b/src/utils/dark-mode.ts @@ -0,0 +1,28 @@ +let _isDarkModeSetup = false; +let _isDarkMode = false; + +export function isDarkMode() { + if (!_isDarkModeSetup) { + if (window.matchMedia) { + const result = window.matchMedia('(prefers-color-scheme: dark)'); + _isDarkMode = result.matches; + result.addEventListener('change', (event) => { + _isDarkMode = event.matches; + }); + } + _isDarkModeSetup = true; + } + + return _isDarkMode; +} + +export function lightDark(light: string, dark: string): string { + return isDarkMode() ? dark : light; +} + +export function maybeLightDark(value: string | [string, string]): string { + if (typeof value === 'string') { + return value; + } + return lightDark(value[0], value[1]); +}