Bluesky app fork with some witchin' additions 💫
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Options for selecting dark theme, fix some white flashes when in dark mode (#2722)

* add dark theme selection to settings/schema

* use `useThemePrefs` where needed

* adjust theme providers to support various themes

* update storybook

* handle web themes

* better themeing for web

* dont show dark theme prefs when color mode is light

* drop the inverted text change on oled theme

* get the color mode inside of `useColorModeTheme`

* use `ThemeName` type everywhere

* typo

* use dim/dark instead of dark/oled

* prevent any fickers on web

* fix styles

* use `dim` for dark default

* more cleanup

* 🤔

* set system background color

* ts

authored by

Hailey and committed by
GitHub
ec862824 856f80fc

+249 -170
+26 -18
bskyweb/templates/base.html
··· 1 - <!DOCTYPE html> 1 + <!DOCTYPE html> 2 2 <html lang="en"> 3 - <head> 3 + <head> 4 4 <meta charset="UTF-8"> 5 5 <meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1, viewport-fit=cover"> 6 6 <meta name="referrer" content="origin-when-cross-origin"> 7 7 <title>{%- block head_title -%}Bluesky{%- endblock -%}</title> 8 8 9 9 <!-- Hello Humans! API docs at https://atproto.com --> 10 - 10 + 11 11 <style> 12 12 /** 13 13 * Extend the react-native-web reset: ··· 40 40 } 41 41 42 42 /* Color theming */ 43 + /* Default will always be white */ 43 44 :root { 44 - --text: black; 45 - --background: white; 46 - --backgroundLight: hsl(211, 20%, 95%); 45 + --text: black; 46 + --background: white; 47 + --backgroundLight: hsl(211, 20%, 95%); 47 48 } 48 - html.colorMode--dark { 49 - --text: white; 50 - --background: hsl(211, 20%, 4%); 51 - --backgroundLight: hsl(211, 20%, 20%); 52 - color-scheme: dark; 49 + /* This gives us a black background when system is dark and we have not loaded the theme/color scheme values in JS */ 50 + @media (prefers-color-scheme: dark) { 51 + :root { 52 + --text: white; 53 + --background: black; 54 + --backgroundLight: hsl(211, 20%, 20%); 55 + color-scheme: dark; 56 + } 53 57 } 54 - @media (prefers-color-scheme: light) { 55 - html.colorMode--system { 58 + 59 + /* Overwrite those preferences with the selected theme */ 60 + html.theme--light { 56 61 --text: black; 57 62 --background: white; 58 63 --backgroundLight: hsl(211, 20%, 95%); 59 - } 60 64 } 61 - @media (prefers-color-scheme: dark) { 62 - html.colorMode--system { 65 + html.theme--dark { 66 + --text: white; 67 + --background: black; 68 + --backgroundLight: hsl(211, 20%, 20%); 69 + color-scheme: dark; 70 + } 71 + html.theme--dim { 63 72 --text: white; 64 73 --background: hsl(211, 20%, 4%); 65 - --backgroundLight: hsl(211, 20%, 20%); 74 + --backgroundLight: hsl(211, 20%, 10%); 66 75 color-scheme: dark; 67 - } 68 76 } 69 77 70 78 /* Remove autofill styles on Webkit */
+2 -4
src/App.native.tsx
··· 17 17 import {useColorModeTheme} from '#/alf/util/useColorModeTheme' 18 18 import {init as initPersistedState} from '#/state/persisted' 19 19 import {listenSessionDropped} from './state/events' 20 - import {useColorMode} from 'state/shell' 21 20 import {ThemeProvider} from 'lib/ThemeContext' 22 21 import {s} from 'lib/styles' 23 22 import {Shell} from 'view/shell' ··· 49 48 SplashScreen.preventAutoHideAsync() 50 49 51 50 function InnerApp() { 52 - const colorMode = useColorMode() 53 51 const {isInitialLoad, currentAccount} = useSession() 54 52 const {resumeSession} = useSessionApi() 55 - const theme = useColorModeTheme(colorMode) 53 + const theme = useColorModeTheme() 56 54 const {_} = useLingui() 57 55 58 56 // init ··· 75 73 key={currentAccount?.did}> 76 74 <LoggedOutViewProvider> 77 75 <UnreadNotifsProvider> 78 - <ThemeProvider theme={colorMode}> 76 + <ThemeProvider theme={theme}> 79 77 {/* All components should be within this provider */} 80 78 <RootSiblingParent> 81 79 <GestureHandlerRootView style={s.h100pct}>
+2 -4
src/App.web.tsx
··· 10 10 import {ThemeProvider as Alf} from '#/alf' 11 11 import {useColorModeTheme} from '#/alf/util/useColorModeTheme' 12 12 import {init as initPersistedState} from '#/state/persisted' 13 - import {useColorMode} from 'state/shell' 14 13 import {Shell} from 'view/shell/index' 15 14 import {ToastContainer} from 'view/com/util/Toast.web' 16 15 import {ThemeProvider} from 'lib/ThemeContext' ··· 36 35 function InnerApp() { 37 36 const {isInitialLoad, currentAccount} = useSession() 38 37 const {resumeSession} = useSessionApi() 39 - const colorMode = useColorMode() 40 - const theme = useColorModeTheme(colorMode) 38 + const theme = useColorModeTheme() 41 39 42 40 // init 43 41 useEffect(() => { ··· 55 53 key={currentAccount?.did}> 56 54 <LoggedOutViewProvider> 57 55 <UnreadNotifsProvider> 58 - <ThemeProvider theme={colorMode}> 56 + <ThemeProvider theme={theme}> 59 57 {/* All components should be within this provider */} 60 58 <RootSiblingParent> 61 59 <SafeAreaProvider>
+2 -2
src/Splash.tsx
··· 21 21 import Svg, {Path, SvgProps} from 'react-native-svg' 22 22 23 23 import {isAndroid} from '#/platform/detection' 24 - import {useColorMode} from '#/state/shell' 24 + import {useThemePrefs} from 'state/shell' 25 25 import {Logotype} from '#/view/icons/Logotype' 26 26 27 27 // @ts-ignore ··· 75 75 isLayoutReady && 76 76 reduceMotion !== undefined 77 77 78 - const colorMode = useColorMode() 78 + const {colorMode} = useThemePrefs() 79 79 const colorScheme = useColorScheme() 80 80 const themeName = colorMode === 'system' ? colorScheme : colorMode 81 81 const isDarkMode = themeName === 'dark'
+20 -65
src/alf/themes.ts
··· 71 71 72 72 export const darkPalette: Palette = { 73 73 white: tokens.color.gray_0, 74 - black: tokens.color.gray_1000, 74 + black: tokens.color.trueBlack, 75 75 76 76 contrast_25: tokens.color.gray_975, 77 77 contrast_50: tokens.color.gray_950, ··· 128 128 negative_900: tokens.color.red_900, 129 129 negative_950: tokens.color.red_950, 130 130 negative_975: tokens.color.red_975, 131 + } as const 132 + 133 + export const dimPalette: Palette = { 134 + ...darkPalette, 135 + black: tokens.color.gray_1000, 131 136 } as const 132 137 133 138 export const light = { ··· 191 196 }, 192 197 } 193 198 194 - export const dim: Theme = { 195 - name: 'dim', 196 - palette: darkPalette, 197 - atoms: { 198 - text: { 199 - color: darkPalette.white, 200 - }, 201 - text_contrast_700: { 202 - color: darkPalette.contrast_800, 203 - }, 204 - text_contrast_600: { 205 - color: darkPalette.contrast_700, 206 - }, 207 - text_contrast_500: { 208 - color: darkPalette.contrast_600, 209 - }, 210 - text_contrast_400: { 211 - color: darkPalette.contrast_500, 212 - }, 213 - text_inverted: { 214 - color: darkPalette.black, 215 - }, 216 - bg: { 217 - backgroundColor: darkPalette.contrast_50, 218 - }, 219 - bg_contrast_25: { 220 - backgroundColor: darkPalette.contrast_100, 221 - }, 222 - bg_contrast_50: { 223 - backgroundColor: darkPalette.contrast_200, 224 - }, 225 - bg_contrast_100: { 226 - backgroundColor: darkPalette.contrast_300, 227 - }, 228 - bg_contrast_200: { 229 - backgroundColor: darkPalette.contrast_400, 230 - }, 231 - bg_contrast_300: { 232 - backgroundColor: darkPalette.contrast_500, 233 - }, 234 - border: { 235 - borderColor: darkPalette.contrast_200, 236 - }, 237 - border_contrast: { 238 - borderColor: darkPalette.contrast_400, 239 - }, 240 - shadow_sm: { 241 - ...atoms.shadow_sm, 242 - shadowOpacity: 0.7, 243 - shadowColor: tokens.color.trueBlack, 244 - }, 245 - shadow_md: { 246 - ...atoms.shadow_md, 247 - shadowOpacity: 0.7, 248 - shadowColor: tokens.color.trueBlack, 249 - }, 250 - shadow_lg: { 251 - ...atoms.shadow_lg, 252 - shadowOpacity: 0.7, 253 - shadowColor: tokens.color.trueBlack, 254 - }, 255 - }, 256 - } 257 - 258 199 export const dark: Theme = { 259 200 name: 'dark', 260 201 palette: darkPalette, ··· 318 259 }, 319 260 }, 320 261 } 262 + 263 + export const dim: Theme = { 264 + ...dark, 265 + name: 'dim', 266 + atoms: { 267 + ...dark.atoms, 268 + text_inverted: { 269 + color: dimPalette.black, 270 + }, 271 + bg: { 272 + backgroundColor: dimPalette.black, 273 + }, 274 + }, 275 + }
+49 -5
src/alf/util/useColorModeTheme.ts
··· 1 + import React from 'react' 1 2 import {useColorScheme} from 'react-native' 2 3 3 - import * as persisted from '#/state/persisted' 4 + import {useThemePrefs} from 'state/shell' 5 + import {isWeb} from 'platform/detection' 6 + import {ThemeName, light, dark, dim} from '#/alf/themes' 7 + import * as SystemUI from 'expo-system-ui' 4 8 5 - export function useColorModeTheme( 6 - theme: persisted.Schema['colorMode'], 7 - ): 'light' | 'dark' { 9 + export function useColorModeTheme(): ThemeName { 8 10 const colorScheme = useColorScheme() 9 - return (theme === 'system' ? colorScheme : theme) || 'light' 11 + const {colorMode, darkTheme} = useThemePrefs() 12 + 13 + return React.useMemo(() => { 14 + if ( 15 + (colorMode === 'system' && colorScheme === 'light') || 16 + colorMode === 'light' 17 + ) { 18 + updateDocument('light') 19 + updateSystemBackground('light') 20 + return 'light' 21 + } else { 22 + const themeName = darkTheme ?? 'dim' 23 + updateDocument(themeName) 24 + updateSystemBackground(themeName) 25 + return themeName 26 + } 27 + }, [colorMode, darkTheme, colorScheme]) 28 + } 29 + 30 + function updateDocument(theme: ThemeName) { 31 + // @ts-ignore web only 32 + if (isWeb && typeof window !== 'undefined') { 33 + // @ts-ignore web only 34 + const html = window.document.documentElement 35 + // remove any other color mode classes 36 + html.className = html.className.replace(/(theme)--\w+/g, '') 37 + 38 + html.classList.add(`theme--${theme}`) 39 + } 40 + } 41 + 42 + function updateSystemBackground(theme: ThemeName) { 43 + switch (theme) { 44 + case 'light': 45 + SystemUI.setBackgroundColorAsync(light.atoms.bg.backgroundColor) 46 + break 47 + case 'dark': 48 + SystemUI.setBackgroundColorAsync(dark.atoms.bg.backgroundColor) 49 + break 50 + case 'dim': 51 + SystemUI.setBackgroundColorAsync(dim.atoms.bg.backgroundColor) 52 + break 53 + } 10 54 }
+16 -12
src/lib/ThemeContext.tsx
··· 1 1 import React, {ReactNode, createContext, useContext} from 'react' 2 - import { 3 - TextStyle, 4 - useColorScheme, 5 - ViewStyle, 6 - ColorSchemeName, 7 - } from 'react-native' 8 - import {darkTheme, defaultTheme} from './themes' 2 + import {TextStyle, ViewStyle} from 'react-native' 3 + import {darkTheme, defaultTheme, dimTheme} from './themes' 4 + import {ThemeName} from '#/alf/themes' 9 5 10 6 export type ColorScheme = 'light' | 'dark' 11 7 ··· 84 80 85 81 export interface ThemeProviderProps { 86 82 children?: ReactNode 87 - theme?: 'light' | 'dark' | 'system' 83 + theme: ThemeName 88 84 } 89 85 90 86 export const ThemeContext = createContext<Theme>(defaultTheme) 91 87 92 88 export const useTheme = () => useContext(ThemeContext) 93 89 94 - function getTheme(theme: ColorSchemeName) { 95 - return theme === 'dark' ? darkTheme : defaultTheme 90 + function getTheme(theme: ThemeName) { 91 + switch (theme) { 92 + case 'light': 93 + return defaultTheme 94 + case 'dim': 95 + return dimTheme 96 + case 'dark': 97 + return darkTheme 98 + default: 99 + return defaultTheme 100 + } 96 101 } 97 102 98 103 export const ThemeProvider: React.FC<ThemeProviderProps> = ({ 99 104 theme, 100 105 children, 101 106 }) => { 102 - const colorScheme = useColorScheme() 103 - const themeValue = getTheme(theme === 'system' ? colorScheme : theme) 107 + const themeValue = getTheme(theme) 104 108 105 109 return ( 106 110 <ThemeContext.Provider value={themeValue}>{children}</ThemeContext.Provider>
+12 -1
src/lib/themes.ts
··· 2 2 import type {Theme} from './ThemeContext' 3 3 import {colors} from './styles' 4 4 5 - import {darkPalette, lightPalette} from '#/alf/themes' 5 + import {darkPalette, lightPalette, dimPalette} from '#/alf/themes' 6 6 7 7 export const defaultTheme: Theme = { 8 8 colorScheme: 'light', ··· 336 336 }, 337 337 }, 338 338 } 339 + 340 + export const dimTheme: Theme = { 341 + ...darkTheme, 342 + palette: { 343 + ...darkTheme.palette, 344 + default: { 345 + ...darkTheme.palette.default, 346 + background: dimPalette.black, 347 + }, 348 + }, 349 + }
+1
src/state/persisted/legacy.ts
··· 69 69 export function transform(legacy: Partial<LegacySchema>): Schema { 70 70 return { 71 71 colorMode: legacy.shell?.colorMode || defaults.colorMode, 72 + darkTheme: defaults.darkTheme, 72 73 session: { 73 74 accounts: legacy.session?.accounts || defaults.session.accounts, 74 75 currentAccount:
+2
src/state/persisted/schema.ts
··· 18 18 19 19 export const schema = z.object({ 20 20 colorMode: z.enum(['system', 'light', 'dark']), 21 + darkTheme: z.enum(['dim', 'dark']).optional(), 21 22 session: z.object({ 22 23 accounts: z.array(accountSchema), 23 24 currentAccount: accountSchema.optional(), ··· 60 61 61 62 export const defaults: Schema = { 62 63 colorMode: 'system', 64 + darkTheme: 'dim', 63 65 session: { 64 66 accounts: [], 65 67 currentAccount: undefined,
+39 -31
src/state/shell/color-mode.tsx
··· 1 1 import React from 'react' 2 - import {isWeb} from '#/platform/detection' 3 2 import * as persisted from '#/state/persisted' 4 3 5 - type StateContext = persisted.Schema['colorMode'] 6 - type SetContext = (v: persisted.Schema['colorMode']) => void 4 + type StateContext = { 5 + colorMode: persisted.Schema['colorMode'] 6 + darkTheme: persisted.Schema['darkTheme'] 7 + } 8 + type SetContext = { 9 + setColorMode: (v: persisted.Schema['colorMode']) => void 10 + setDarkTheme: (v: persisted.Schema['darkTheme']) => void 11 + } 7 12 8 - const stateContext = React.createContext<StateContext>('system') 9 - const setContext = React.createContext<SetContext>( 10 - (_: persisted.Schema['colorMode']) => {}, 11 - ) 13 + const stateContext = React.createContext<StateContext>({ 14 + colorMode: 'system', 15 + darkTheme: 'dark', 16 + }) 17 + const setContext = React.createContext<SetContext>({} as SetContext) 12 18 13 19 export function Provider({children}: React.PropsWithChildren<{}>) { 14 - const [state, setState] = React.useState(persisted.get('colorMode')) 20 + const [colorMode, setColorMode] = React.useState(persisted.get('colorMode')) 21 + const [darkTheme, setDarkTheme] = React.useState(persisted.get('darkTheme')) 15 22 16 - const setStateWrapped = React.useCallback( 17 - (colorMode: persisted.Schema['colorMode']) => { 18 - setState(colorMode) 19 - persisted.write('colorMode', colorMode) 20 - updateDocument(colorMode) 23 + const setColorModeWrapped = React.useCallback( 24 + (_colorMode: persisted.Schema['colorMode']) => { 25 + setColorMode(_colorMode) 26 + persisted.write('colorMode', _colorMode) 21 27 }, 22 - [setState], 28 + [setColorMode], 29 + ) 30 + 31 + const setDarkThemeWrapped = React.useCallback( 32 + (_darkTheme: persisted.Schema['darkTheme']) => { 33 + setDarkTheme(_darkTheme) 34 + persisted.write('darkTheme', _darkTheme) 35 + }, 36 + [setDarkTheme], 23 37 ) 24 38 25 39 React.useEffect(() => { 26 - updateDocument(persisted.get('colorMode')) // set on load 27 40 return persisted.onUpdate(() => { 28 - setState(persisted.get('colorMode')) 29 - updateDocument(persisted.get('colorMode')) 41 + setColorModeWrapped(persisted.get('colorMode')) 42 + setDarkThemeWrapped(persisted.get('darkTheme')) 30 43 }) 31 - }, [setState]) 44 + }, [setColorModeWrapped, setDarkThemeWrapped]) 32 45 33 46 return ( 34 - <stateContext.Provider value={state}> 35 - <setContext.Provider value={setStateWrapped}> 47 + <stateContext.Provider value={{colorMode, darkTheme}}> 48 + <setContext.Provider 49 + value={{ 50 + setDarkTheme: setDarkThemeWrapped, 51 + setColorMode: setColorModeWrapped, 52 + }}> 36 53 {children} 37 54 </setContext.Provider> 38 55 </stateContext.Provider> 39 56 ) 40 57 } 41 58 42 - export function useColorMode() { 59 + export function useThemePrefs() { 43 60 return React.useContext(stateContext) 44 61 } 45 62 46 - export function useSetColorMode() { 63 + export function useSetThemePrefs() { 47 64 return React.useContext(setContext) 48 65 } 49 - 50 - function updateDocument(colorMode: string) { 51 - if (isWeb && typeof window !== 'undefined') { 52 - const html = window.document.documentElement 53 - // remove any other color mode classes 54 - html.className = html.className.replace(/colorMode--\w+/g, '') 55 - html.classList.add(`colorMode--${colorMode}`) 56 - } 57 - }
+1 -1
src/state/shell/index.tsx
··· 14 14 useSetDrawerSwipeDisabled, 15 15 } from './drawer-swipe-disabled' 16 16 export {useMinimalShellMode, useSetMinimalShellMode} from './minimal-mode' 17 - export {useColorMode, useSetColorMode} from './color-mode' 17 + export {useThemePrefs, useSetThemePrefs} from './color-mode' 18 18 export {useOnboardingState, useOnboardingDispatch} from './onboarding' 19 19 export {useComposerState, useComposerControls} from './composer' 20 20 export {useTickEveryMinute} from './tick-every-minute'
+32 -4
src/view/screens/Settings.tsx
··· 40 40 import {useModalControls} from '#/state/modals' 41 41 import { 42 42 useSetMinimalShellMode, 43 - useColorMode, 44 - useSetColorMode, 43 + useThemePrefs, 44 + useSetThemePrefs, 45 45 useOnboardingDispatch, 46 46 } from '#/state/shell' 47 47 import { ··· 144 144 type Props = NativeStackScreenProps<CommonNavigatorParams, 'Settings'> 145 145 export function SettingsScreen({}: Props) { 146 146 const queryClient = useQueryClient() 147 - const colorMode = useColorMode() 148 - const setColorMode = useSetColorMode() 147 + const {colorMode, darkTheme} = useThemePrefs() 148 + const {setColorMode, setDarkTheme} = useSetThemePrefs() 149 149 const pal = usePalette('default') 150 150 const {_} = useLingui() 151 151 const setMinimalShellMode = useSetMinimalShellMode() ··· 483 483 /> 484 484 </View> 485 485 </View> 486 + 486 487 <View style={styles.spacer20} /> 488 + 489 + {colorMode !== 'light' && ( 490 + <> 491 + <Text type="xl-bold" style={[pal.text, styles.heading]}> 492 + <Trans>Dark Theme</Trans> 493 + </Text> 494 + <View> 495 + <View style={[styles.linkCard, pal.view, styles.selectableBtns]}> 496 + <SelectableBtn 497 + selected={!darkTheme || darkTheme === 'dim'} 498 + label={_(msg`Dim`)} 499 + left 500 + onSelect={() => setDarkTheme('dim')} 501 + accessibilityHint={_(msg`Set dark theme to the dim theme`)} 502 + /> 503 + <SelectableBtn 504 + selected={darkTheme === 'dark'} 505 + label={_(msg`Dark`)} 506 + right 507 + onSelect={() => setDarkTheme('dark')} 508 + accessibilityHint={_(msg`Set dark theme to the dark theme`)} 509 + /> 510 + </View> 511 + </View> 512 + <View style={styles.spacer20} /> 513 + </> 514 + )} 487 515 488 516 <Text type="xl-bold" style={[pal.text, styles.heading]}> 489 517 <Trans>Basics</Trans>
+19 -5
src/view/screens/Storybook/index.tsx
··· 3 3 import {CenteredView, ScrollView} from '#/view/com/util/Views' 4 4 5 5 import {atoms as a, useTheme, ThemeProvider} from '#/alf' 6 - import {useSetColorMode} from '#/state/shell' 6 + import {useSetThemePrefs} from '#/state/shell' 7 7 import {Button} from '#/components/Button' 8 8 9 9 import {Theming} from './Theming' ··· 19 19 20 20 export function Storybook() { 21 21 const t = useTheme() 22 - const setColorMode = useSetColorMode() 22 + const {setColorMode, setDarkTheme} = useSetThemePrefs() 23 23 24 24 return ( 25 25 <ScrollView> ··· 38 38 variant="solid" 39 39 color="secondary" 40 40 size="small" 41 - label='Set theme to "system"' 41 + label='Set theme to "light"' 42 42 onPress={() => setColorMode('light')}> 43 43 Light 44 44 </Button> ··· 46 46 variant="solid" 47 47 color="secondary" 48 48 size="small" 49 - label='Set theme to "system"' 50 - onPress={() => setColorMode('dark')}> 49 + label='Set theme to "dim"' 50 + onPress={() => { 51 + setColorMode('dark') 52 + setDarkTheme('dim') 53 + }}> 54 + Dim 55 + </Button> 56 + <Button 57 + variant="solid" 58 + color="secondary" 59 + size="small" 60 + label='Set theme to "dark"' 61 + onPress={() => { 62 + setColorMode('dark') 63 + setDarkTheme('dark') 64 + }}> 51 65 Dark 52 66 </Button> 53 67 </View>
+26 -18
web/index.html
··· 3 3 <head> 4 4 <meta charset="utf-8" /> 5 5 <meta httpEquiv="X-UA-Compatible" content="IE=edge" /> 6 - <!-- 6 + <!-- 7 7 This viewport works for phones with notches. 8 8 It's optimized for gestures by disabling global zoom. 9 9 --> ··· 44 44 } 45 45 46 46 /* Color theming */ 47 + /* Default will always be white */ 47 48 :root { 48 - --text: black; 49 - --background: white; 50 - --backgroundLight: hsl(211, 20%, 95%); 49 + --text: black; 50 + --background: white; 51 + --backgroundLight: hsl(211, 20%, 95%); 51 52 } 52 - html.colorMode--dark { 53 - --text: white; 54 - --background: hsl(211, 20%, 4%); 55 - --backgroundLight: hsl(211, 20%, 20%); 56 - color-scheme: dark; 53 + /* This gives us a black background when system is dark and we have not loaded the theme/color scheme values in JS */ 54 + @media (prefers-color-scheme: dark) { 55 + :root { 56 + --text: white; 57 + --background: black; 58 + --backgroundLight: hsl(211, 20%, 20%); 59 + color-scheme: dark; 60 + } 57 61 } 58 - @media (prefers-color-scheme: light) { 59 - html.colorMode--system { 62 + 63 + /* Overwrite those preferences with the selected theme */ 64 + html.theme--light { 60 65 --text: black; 61 66 --background: white; 62 67 --backgroundLight: hsl(211, 20%, 95%); 63 - } 64 68 } 65 - @media (prefers-color-scheme: dark) { 66 - html.colorMode--system { 69 + html.theme--dark { 67 70 --text: white; 68 - --background: hsl(211, 20%, 4%); 71 + --background: black; 69 72 --backgroundLight: hsl(211, 20%, 20%); 70 73 color-scheme: dark; 71 - } 74 + } 75 + html.theme--dim { 76 + --text: white; 77 + --background: hsl(211, 20%, 4%); 78 + --backgroundLight: hsl(211, 20%, 10%); 79 + color-scheme: dark; 72 80 } 73 81 74 82 /* Remove autofill styles on Webkit */ ··· 142 150 .ProseMirror .mention { 143 151 color: #0085ff; 144 152 } 145 - .ProseMirror a, 153 + .ProseMirror a, 146 154 .ProseMirror .autolink { 147 155 color: #0085ff; 148 156 } ··· 200 208 </head> 201 209 202 210 <body> 203 - <!-- 211 + <!-- 204 212 A generic no script element with a reload button and a message. 205 213 Feel free to customize this however you'd like. 206 214 -->