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
zio/stable
Hailey 2024-02-06 11:43:51 -08:00 committed by GitHub
parent 856f80fc6d
commit ec86282403
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 251 additions and 172 deletions

View File

@ -1,13 +1,13 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1, viewport-fit=cover"> <meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1, viewport-fit=cover">
<meta name="referrer" content="origin-when-cross-origin"> <meta name="referrer" content="origin-when-cross-origin">
<title>{%- block head_title -%}Bluesky{%- endblock -%}</title> <title>{%- block head_title -%}Bluesky{%- endblock -%}</title>
<!-- Hello Humans! API docs at https://atproto.com --> <!-- Hello Humans! API docs at https://atproto.com -->
<style> <style>
/** /**
* Extend the react-native-web reset: * Extend the react-native-web reset:
@ -40,31 +40,39 @@
} }
/* Color theming */ /* Color theming */
/* Default will always be white */
:root { :root {
--text: black;
--background: white;
--backgroundLight: hsl(211, 20%, 95%);
}
html.colorMode--dark {
--text: white;
--background: hsl(211, 20%, 4%);
--backgroundLight: hsl(211, 20%, 20%);
color-scheme: dark;
}
@media (prefers-color-scheme: light) {
html.colorMode--system {
--text: black; --text: black;
--background: white; --background: white;
--backgroundLight: hsl(211, 20%, 95%); --backgroundLight: hsl(211, 20%, 95%);
}
} }
/* This gives us a black background when system is dark and we have not loaded the theme/color scheme values in JS */
@media (prefers-color-scheme: dark) { @media (prefers-color-scheme: dark) {
html.colorMode--system { :root {
--text: white;
--background: black;
--backgroundLight: hsl(211, 20%, 20%);
color-scheme: dark;
}
}
/* Overwrite those preferences with the selected theme */
html.theme--light {
--text: black;
--background: white;
--backgroundLight: hsl(211, 20%, 95%);
}
html.theme--dark {
--text: white; --text: white;
--background: hsl(211, 20%, 4%); --background: black;
--backgroundLight: hsl(211, 20%, 20%); --backgroundLight: hsl(211, 20%, 20%);
color-scheme: dark; color-scheme: dark;
} }
html.theme--dim {
--text: white;
--background: hsl(211, 20%, 4%);
--backgroundLight: hsl(211, 20%, 10%);
color-scheme: dark;
} }
/* Remove autofill styles on Webkit */ /* Remove autofill styles on Webkit */

View File

@ -17,7 +17,6 @@ import {ThemeProvider as Alf} from '#/alf'
import {useColorModeTheme} from '#/alf/util/useColorModeTheme' import {useColorModeTheme} from '#/alf/util/useColorModeTheme'
import {init as initPersistedState} from '#/state/persisted' import {init as initPersistedState} from '#/state/persisted'
import {listenSessionDropped} from './state/events' import {listenSessionDropped} from './state/events'
import {useColorMode} from 'state/shell'
import {ThemeProvider} from 'lib/ThemeContext' import {ThemeProvider} from 'lib/ThemeContext'
import {s} from 'lib/styles' import {s} from 'lib/styles'
import {Shell} from 'view/shell' import {Shell} from 'view/shell'
@ -49,10 +48,9 @@ import {useLingui} from '@lingui/react'
SplashScreen.preventAutoHideAsync() SplashScreen.preventAutoHideAsync()
function InnerApp() { function InnerApp() {
const colorMode = useColorMode()
const {isInitialLoad, currentAccount} = useSession() const {isInitialLoad, currentAccount} = useSession()
const {resumeSession} = useSessionApi() const {resumeSession} = useSessionApi()
const theme = useColorModeTheme(colorMode) const theme = useColorModeTheme()
const {_} = useLingui() const {_} = useLingui()
// init // init
@ -75,7 +73,7 @@ function InnerApp() {
key={currentAccount?.did}> key={currentAccount?.did}>
<LoggedOutViewProvider> <LoggedOutViewProvider>
<UnreadNotifsProvider> <UnreadNotifsProvider>
<ThemeProvider theme={colorMode}> <ThemeProvider theme={theme}>
{/* All components should be within this provider */} {/* All components should be within this provider */}
<RootSiblingParent> <RootSiblingParent>
<GestureHandlerRootView style={s.h100pct}> <GestureHandlerRootView style={s.h100pct}>

View File

@ -10,7 +10,6 @@ import 'view/icons'
import {ThemeProvider as Alf} from '#/alf' import {ThemeProvider as Alf} from '#/alf'
import {useColorModeTheme} from '#/alf/util/useColorModeTheme' import {useColorModeTheme} from '#/alf/util/useColorModeTheme'
import {init as initPersistedState} from '#/state/persisted' import {init as initPersistedState} from '#/state/persisted'
import {useColorMode} from 'state/shell'
import {Shell} from 'view/shell/index' import {Shell} from 'view/shell/index'
import {ToastContainer} from 'view/com/util/Toast.web' import {ToastContainer} from 'view/com/util/Toast.web'
import {ThemeProvider} from 'lib/ThemeContext' import {ThemeProvider} from 'lib/ThemeContext'
@ -36,8 +35,7 @@ import {Provider as PortalProvider} from '#/components/Portal'
function InnerApp() { function InnerApp() {
const {isInitialLoad, currentAccount} = useSession() const {isInitialLoad, currentAccount} = useSession()
const {resumeSession} = useSessionApi() const {resumeSession} = useSessionApi()
const colorMode = useColorMode() const theme = useColorModeTheme()
const theme = useColorModeTheme(colorMode)
// init // init
useEffect(() => { useEffect(() => {
@ -55,7 +53,7 @@ function InnerApp() {
key={currentAccount?.did}> key={currentAccount?.did}>
<LoggedOutViewProvider> <LoggedOutViewProvider>
<UnreadNotifsProvider> <UnreadNotifsProvider>
<ThemeProvider theme={colorMode}> <ThemeProvider theme={theme}>
{/* All components should be within this provider */} {/* All components should be within this provider */}
<RootSiblingParent> <RootSiblingParent>
<SafeAreaProvider> <SafeAreaProvider>

View File

@ -21,7 +21,7 @@ import {useSafeAreaInsets} from 'react-native-safe-area-context'
import Svg, {Path, SvgProps} from 'react-native-svg' import Svg, {Path, SvgProps} from 'react-native-svg'
import {isAndroid} from '#/platform/detection' import {isAndroid} from '#/platform/detection'
import {useColorMode} from '#/state/shell' import {useThemePrefs} from 'state/shell'
import {Logotype} from '#/view/icons/Logotype' import {Logotype} from '#/view/icons/Logotype'
// @ts-ignore // @ts-ignore
@ -75,7 +75,7 @@ export function Splash(props: React.PropsWithChildren<Props>) {
isLayoutReady && isLayoutReady &&
reduceMotion !== undefined reduceMotion !== undefined
const colorMode = useColorMode() const {colorMode} = useThemePrefs()
const colorScheme = useColorScheme() const colorScheme = useColorScheme()
const themeName = colorMode === 'system' ? colorScheme : colorMode const themeName = colorMode === 'system' ? colorScheme : colorMode
const isDarkMode = themeName === 'dark' const isDarkMode = themeName === 'dark'

View File

@ -71,7 +71,7 @@ export const lightPalette = {
export const darkPalette: Palette = { export const darkPalette: Palette = {
white: tokens.color.gray_0, white: tokens.color.gray_0,
black: tokens.color.gray_1000, black: tokens.color.trueBlack,
contrast_25: tokens.color.gray_975, contrast_25: tokens.color.gray_975,
contrast_50: tokens.color.gray_950, contrast_50: tokens.color.gray_950,
@ -130,6 +130,11 @@ export const darkPalette: Palette = {
negative_975: tokens.color.red_975, negative_975: tokens.color.red_975,
} as const } as const
export const dimPalette: Palette = {
...darkPalette,
black: tokens.color.gray_1000,
} as const
export const light = { export const light = {
name: 'light', name: 'light',
palette: lightPalette, palette: lightPalette,
@ -191,70 +196,6 @@ export const light = {
}, },
} }
export const dim: Theme = {
name: 'dim',
palette: darkPalette,
atoms: {
text: {
color: darkPalette.white,
},
text_contrast_700: {
color: darkPalette.contrast_800,
},
text_contrast_600: {
color: darkPalette.contrast_700,
},
text_contrast_500: {
color: darkPalette.contrast_600,
},
text_contrast_400: {
color: darkPalette.contrast_500,
},
text_inverted: {
color: darkPalette.black,
},
bg: {
backgroundColor: darkPalette.contrast_50,
},
bg_contrast_25: {
backgroundColor: darkPalette.contrast_100,
},
bg_contrast_50: {
backgroundColor: darkPalette.contrast_200,
},
bg_contrast_100: {
backgroundColor: darkPalette.contrast_300,
},
bg_contrast_200: {
backgroundColor: darkPalette.contrast_400,
},
bg_contrast_300: {
backgroundColor: darkPalette.contrast_500,
},
border: {
borderColor: darkPalette.contrast_200,
},
border_contrast: {
borderColor: darkPalette.contrast_400,
},
shadow_sm: {
...atoms.shadow_sm,
shadowOpacity: 0.7,
shadowColor: tokens.color.trueBlack,
},
shadow_md: {
...atoms.shadow_md,
shadowOpacity: 0.7,
shadowColor: tokens.color.trueBlack,
},
shadow_lg: {
...atoms.shadow_lg,
shadowOpacity: 0.7,
shadowColor: tokens.color.trueBlack,
},
},
}
export const dark: Theme = { export const dark: Theme = {
name: 'dark', name: 'dark',
palette: darkPalette, palette: darkPalette,
@ -318,3 +259,17 @@ export const dark: Theme = {
}, },
}, },
} }
export const dim: Theme = {
...dark,
name: 'dim',
atoms: {
...dark.atoms,
text_inverted: {
color: dimPalette.black,
},
bg: {
backgroundColor: dimPalette.black,
},
},
}

View File

@ -1,10 +1,54 @@
import React from 'react'
import {useColorScheme} from 'react-native' import {useColorScheme} from 'react-native'
import * as persisted from '#/state/persisted' import {useThemePrefs} from 'state/shell'
import {isWeb} from 'platform/detection'
import {ThemeName, light, dark, dim} from '#/alf/themes'
import * as SystemUI from 'expo-system-ui'
export function useColorModeTheme( export function useColorModeTheme(): ThemeName {
theme: persisted.Schema['colorMode'],
): 'light' | 'dark' {
const colorScheme = useColorScheme() const colorScheme = useColorScheme()
return (theme === 'system' ? colorScheme : theme) || 'light' const {colorMode, darkTheme} = useThemePrefs()
return React.useMemo(() => {
if (
(colorMode === 'system' && colorScheme === 'light') ||
colorMode === 'light'
) {
updateDocument('light')
updateSystemBackground('light')
return 'light'
} else {
const themeName = darkTheme ?? 'dim'
updateDocument(themeName)
updateSystemBackground(themeName)
return themeName
}
}, [colorMode, darkTheme, colorScheme])
}
function updateDocument(theme: ThemeName) {
// @ts-ignore web only
if (isWeb && typeof window !== 'undefined') {
// @ts-ignore web only
const html = window.document.documentElement
// remove any other color mode classes
html.className = html.className.replace(/(theme)--\w+/g, '')
html.classList.add(`theme--${theme}`)
}
}
function updateSystemBackground(theme: ThemeName) {
switch (theme) {
case 'light':
SystemUI.setBackgroundColorAsync(light.atoms.bg.backgroundColor)
break
case 'dark':
SystemUI.setBackgroundColorAsync(dark.atoms.bg.backgroundColor)
break
case 'dim':
SystemUI.setBackgroundColorAsync(dim.atoms.bg.backgroundColor)
break
}
} }

View File

@ -1,11 +1,7 @@
import React, {ReactNode, createContext, useContext} from 'react' import React, {ReactNode, createContext, useContext} from 'react'
import { import {TextStyle, ViewStyle} from 'react-native'
TextStyle, import {darkTheme, defaultTheme, dimTheme} from './themes'
useColorScheme, import {ThemeName} from '#/alf/themes'
ViewStyle,
ColorSchemeName,
} from 'react-native'
import {darkTheme, defaultTheme} from './themes'
export type ColorScheme = 'light' | 'dark' export type ColorScheme = 'light' | 'dark'
@ -84,23 +80,31 @@ export interface Theme {
export interface ThemeProviderProps { export interface ThemeProviderProps {
children?: ReactNode children?: ReactNode
theme?: 'light' | 'dark' | 'system' theme: ThemeName
} }
export const ThemeContext = createContext<Theme>(defaultTheme) export const ThemeContext = createContext<Theme>(defaultTheme)
export const useTheme = () => useContext(ThemeContext) export const useTheme = () => useContext(ThemeContext)
function getTheme(theme: ColorSchemeName) { function getTheme(theme: ThemeName) {
return theme === 'dark' ? darkTheme : defaultTheme switch (theme) {
case 'light':
return defaultTheme
case 'dim':
return dimTheme
case 'dark':
return darkTheme
default:
return defaultTheme
}
} }
export const ThemeProvider: React.FC<ThemeProviderProps> = ({ export const ThemeProvider: React.FC<ThemeProviderProps> = ({
theme, theme,
children, children,
}) => { }) => {
const colorScheme = useColorScheme() const themeValue = getTheme(theme)
const themeValue = getTheme(theme === 'system' ? colorScheme : theme)
return ( return (
<ThemeContext.Provider value={themeValue}>{children}</ThemeContext.Provider> <ThemeContext.Provider value={themeValue}>{children}</ThemeContext.Provider>

View File

@ -2,7 +2,7 @@ import {Platform} from 'react-native'
import type {Theme} from './ThemeContext' import type {Theme} from './ThemeContext'
import {colors} from './styles' import {colors} from './styles'
import {darkPalette, lightPalette} from '#/alf/themes' import {darkPalette, lightPalette, dimPalette} from '#/alf/themes'
export const defaultTheme: Theme = { export const defaultTheme: Theme = {
colorScheme: 'light', colorScheme: 'light',
@ -336,3 +336,14 @@ export const darkTheme: Theme = {
}, },
}, },
} }
export const dimTheme: Theme = {
...darkTheme,
palette: {
...darkTheme.palette,
default: {
...darkTheme.palette.default,
background: dimPalette.black,
},
},
}

View File

@ -69,6 +69,7 @@ const DEPRECATED_ROOT_STATE_STORAGE_KEY = 'root'
export function transform(legacy: Partial<LegacySchema>): Schema { export function transform(legacy: Partial<LegacySchema>): Schema {
return { return {
colorMode: legacy.shell?.colorMode || defaults.colorMode, colorMode: legacy.shell?.colorMode || defaults.colorMode,
darkTheme: defaults.darkTheme,
session: { session: {
accounts: legacy.session?.accounts || defaults.session.accounts, accounts: legacy.session?.accounts || defaults.session.accounts,
currentAccount: currentAccount:

View File

@ -18,6 +18,7 @@ export type PersistedAccount = z.infer<typeof accountSchema>
export const schema = z.object({ export const schema = z.object({
colorMode: z.enum(['system', 'light', 'dark']), colorMode: z.enum(['system', 'light', 'dark']),
darkTheme: z.enum(['dim', 'dark']).optional(),
session: z.object({ session: z.object({
accounts: z.array(accountSchema), accounts: z.array(accountSchema),
currentAccount: accountSchema.optional(), currentAccount: accountSchema.optional(),
@ -60,6 +61,7 @@ export type Schema = z.infer<typeof schema>
export const defaults: Schema = { export const defaults: Schema = {
colorMode: 'system', colorMode: 'system',
darkTheme: 'dim',
session: { session: {
accounts: [], accounts: [],
currentAccount: undefined, currentAccount: undefined,

View File

@ -1,57 +1,65 @@
import React from 'react' import React from 'react'
import {isWeb} from '#/platform/detection'
import * as persisted from '#/state/persisted' import * as persisted from '#/state/persisted'
type StateContext = persisted.Schema['colorMode'] type StateContext = {
type SetContext = (v: persisted.Schema['colorMode']) => void colorMode: persisted.Schema['colorMode']
darkTheme: persisted.Schema['darkTheme']
}
type SetContext = {
setColorMode: (v: persisted.Schema['colorMode']) => void
setDarkTheme: (v: persisted.Schema['darkTheme']) => void
}
const stateContext = React.createContext<StateContext>('system') const stateContext = React.createContext<StateContext>({
const setContext = React.createContext<SetContext>( colorMode: 'system',
(_: persisted.Schema['colorMode']) => {}, darkTheme: 'dark',
) })
const setContext = React.createContext<SetContext>({} as SetContext)
export function Provider({children}: React.PropsWithChildren<{}>) { export function Provider({children}: React.PropsWithChildren<{}>) {
const [state, setState] = React.useState(persisted.get('colorMode')) const [colorMode, setColorMode] = React.useState(persisted.get('colorMode'))
const [darkTheme, setDarkTheme] = React.useState(persisted.get('darkTheme'))
const setStateWrapped = React.useCallback( const setColorModeWrapped = React.useCallback(
(colorMode: persisted.Schema['colorMode']) => { (_colorMode: persisted.Schema['colorMode']) => {
setState(colorMode) setColorMode(_colorMode)
persisted.write('colorMode', colorMode) persisted.write('colorMode', _colorMode)
updateDocument(colorMode)
}, },
[setState], [setColorMode],
)
const setDarkThemeWrapped = React.useCallback(
(_darkTheme: persisted.Schema['darkTheme']) => {
setDarkTheme(_darkTheme)
persisted.write('darkTheme', _darkTheme)
},
[setDarkTheme],
) )
React.useEffect(() => { React.useEffect(() => {
updateDocument(persisted.get('colorMode')) // set on load
return persisted.onUpdate(() => { return persisted.onUpdate(() => {
setState(persisted.get('colorMode')) setColorModeWrapped(persisted.get('colorMode'))
updateDocument(persisted.get('colorMode')) setDarkThemeWrapped(persisted.get('darkTheme'))
}) })
}, [setState]) }, [setColorModeWrapped, setDarkThemeWrapped])
return ( return (
<stateContext.Provider value={state}> <stateContext.Provider value={{colorMode, darkTheme}}>
<setContext.Provider value={setStateWrapped}> <setContext.Provider
value={{
setDarkTheme: setDarkThemeWrapped,
setColorMode: setColorModeWrapped,
}}>
{children} {children}
</setContext.Provider> </setContext.Provider>
</stateContext.Provider> </stateContext.Provider>
) )
} }
export function useColorMode() { export function useThemePrefs() {
return React.useContext(stateContext) return React.useContext(stateContext)
} }
export function useSetColorMode() { export function useSetThemePrefs() {
return React.useContext(setContext) return React.useContext(setContext)
} }
function updateDocument(colorMode: string) {
if (isWeb && typeof window !== 'undefined') {
const html = window.document.documentElement
// remove any other color mode classes
html.className = html.className.replace(/colorMode--\w+/g, '')
html.classList.add(`colorMode--${colorMode}`)
}
}

View File

@ -14,7 +14,7 @@ export {
useSetDrawerSwipeDisabled, useSetDrawerSwipeDisabled,
} from './drawer-swipe-disabled' } from './drawer-swipe-disabled'
export {useMinimalShellMode, useSetMinimalShellMode} from './minimal-mode' export {useMinimalShellMode, useSetMinimalShellMode} from './minimal-mode'
export {useColorMode, useSetColorMode} from './color-mode' export {useThemePrefs, useSetThemePrefs} from './color-mode'
export {useOnboardingState, useOnboardingDispatch} from './onboarding' export {useOnboardingState, useOnboardingDispatch} from './onboarding'
export {useComposerState, useComposerControls} from './composer' export {useComposerState, useComposerControls} from './composer'
export {useTickEveryMinute} from './tick-every-minute' export {useTickEveryMinute} from './tick-every-minute'

View File

@ -40,8 +40,8 @@ import {RQKEY as RQKEY_PROFILE} from '#/state/queries/profile'
import {useModalControls} from '#/state/modals' import {useModalControls} from '#/state/modals'
import { import {
useSetMinimalShellMode, useSetMinimalShellMode,
useColorMode, useThemePrefs,
useSetColorMode, useSetThemePrefs,
useOnboardingDispatch, useOnboardingDispatch,
} from '#/state/shell' } from '#/state/shell'
import { import {
@ -144,8 +144,8 @@ function SettingsAccountCard({account}: {account: SessionAccount}) {
type Props = NativeStackScreenProps<CommonNavigatorParams, 'Settings'> type Props = NativeStackScreenProps<CommonNavigatorParams, 'Settings'>
export function SettingsScreen({}: Props) { export function SettingsScreen({}: Props) {
const queryClient = useQueryClient() const queryClient = useQueryClient()
const colorMode = useColorMode() const {colorMode, darkTheme} = useThemePrefs()
const setColorMode = useSetColorMode() const {setColorMode, setDarkTheme} = useSetThemePrefs()
const pal = usePalette('default') const pal = usePalette('default')
const {_} = useLingui() const {_} = useLingui()
const setMinimalShellMode = useSetMinimalShellMode() const setMinimalShellMode = useSetMinimalShellMode()
@ -483,8 +483,36 @@ export function SettingsScreen({}: Props) {
/> />
</View> </View>
</View> </View>
<View style={styles.spacer20} /> <View style={styles.spacer20} />
{colorMode !== 'light' && (
<>
<Text type="xl-bold" style={[pal.text, styles.heading]}>
<Trans>Dark Theme</Trans>
</Text>
<View>
<View style={[styles.linkCard, pal.view, styles.selectableBtns]}>
<SelectableBtn
selected={!darkTheme || darkTheme === 'dim'}
label={_(msg`Dim`)}
left
onSelect={() => setDarkTheme('dim')}
accessibilityHint={_(msg`Set dark theme to the dim theme`)}
/>
<SelectableBtn
selected={darkTheme === 'dark'}
label={_(msg`Dark`)}
right
onSelect={() => setDarkTheme('dark')}
accessibilityHint={_(msg`Set dark theme to the dark theme`)}
/>
</View>
</View>
<View style={styles.spacer20} />
</>
)}
<Text type="xl-bold" style={[pal.text, styles.heading]}> <Text type="xl-bold" style={[pal.text, styles.heading]}>
<Trans>Basics</Trans> <Trans>Basics</Trans>
</Text> </Text>

View File

@ -3,7 +3,7 @@ import {View} from 'react-native'
import {CenteredView, ScrollView} from '#/view/com/util/Views' import {CenteredView, ScrollView} from '#/view/com/util/Views'
import {atoms as a, useTheme, ThemeProvider} from '#/alf' import {atoms as a, useTheme, ThemeProvider} from '#/alf'
import {useSetColorMode} from '#/state/shell' import {useSetThemePrefs} from '#/state/shell'
import {Button} from '#/components/Button' import {Button} from '#/components/Button'
import {Theming} from './Theming' import {Theming} from './Theming'
@ -19,7 +19,7 @@ import {Icons} from './Icons'
export function Storybook() { export function Storybook() {
const t = useTheme() const t = useTheme()
const setColorMode = useSetColorMode() const {setColorMode, setDarkTheme} = useSetThemePrefs()
return ( return (
<ScrollView> <ScrollView>
@ -38,7 +38,7 @@ export function Storybook() {
variant="solid" variant="solid"
color="secondary" color="secondary"
size="small" size="small"
label='Set theme to "system"' label='Set theme to "light"'
onPress={() => setColorMode('light')}> onPress={() => setColorMode('light')}>
Light Light
</Button> </Button>
@ -46,8 +46,22 @@ export function Storybook() {
variant="solid" variant="solid"
color="secondary" color="secondary"
size="small" size="small"
label='Set theme to "system"' label='Set theme to "dim"'
onPress={() => setColorMode('dark')}> onPress={() => {
setColorMode('dark')
setDarkTheme('dim')
}}>
Dim
</Button>
<Button
variant="solid"
color="secondary"
size="small"
label='Set theme to "dark"'
onPress={() => {
setColorMode('dark')
setDarkTheme('dark')
}}>
Dark Dark
</Button> </Button>
</View> </View>

View File

@ -3,7 +3,7 @@
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<meta httpEquiv="X-UA-Compatible" content="IE=edge" /> <meta httpEquiv="X-UA-Compatible" content="IE=edge" />
<!-- <!--
This viewport works for phones with notches. This viewport works for phones with notches.
It's optimized for gestures by disabling global zoom. It's optimized for gestures by disabling global zoom.
--> -->
@ -44,31 +44,39 @@
} }
/* Color theming */ /* Color theming */
/* Default will always be white */
:root { :root {
--text: black;
--background: white;
--backgroundLight: hsl(211, 20%, 95%);
}
html.colorMode--dark {
--text: white;
--background: hsl(211, 20%, 4%);
--backgroundLight: hsl(211, 20%, 20%);
color-scheme: dark;
}
@media (prefers-color-scheme: light) {
html.colorMode--system {
--text: black; --text: black;
--background: white; --background: white;
--backgroundLight: hsl(211, 20%, 95%); --backgroundLight: hsl(211, 20%, 95%);
}
} }
/* This gives us a black background when system is dark and we have not loaded the theme/color scheme values in JS */
@media (prefers-color-scheme: dark) { @media (prefers-color-scheme: dark) {
html.colorMode--system { :root {
--text: white;
--background: black;
--backgroundLight: hsl(211, 20%, 20%);
color-scheme: dark;
}
}
/* Overwrite those preferences with the selected theme */
html.theme--light {
--text: black;
--background: white;
--backgroundLight: hsl(211, 20%, 95%);
}
html.theme--dark {
--text: white; --text: white;
--background: hsl(211, 20%, 4%); --background: black;
--backgroundLight: hsl(211, 20%, 20%); --backgroundLight: hsl(211, 20%, 20%);
color-scheme: dark; color-scheme: dark;
} }
html.theme--dim {
--text: white;
--background: hsl(211, 20%, 4%);
--backgroundLight: hsl(211, 20%, 10%);
color-scheme: dark;
} }
/* Remove autofill styles on Webkit */ /* Remove autofill styles on Webkit */
@ -142,7 +150,7 @@
.ProseMirror .mention { .ProseMirror .mention {
color: #0085ff; color: #0085ff;
} }
.ProseMirror a, .ProseMirror a,
.ProseMirror .autolink { .ProseMirror .autolink {
color: #0085ff; color: #0085ff;
} }
@ -200,7 +208,7 @@
</head> </head>
<body> <body>
<!-- <!--
A generic no script element with a reload button and a message. A generic no script element with a reload button and a message.
Feel free to customize this however you'd like. Feel free to customize this however you'd like.
--> -->