2.0 KB60 lines
Blame
1/**
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 */
7
8import {atom} from 'jotai';
9import {useCommand} from './ISLShortcuts';
10import {localStorageBackedAtom, writeAtom} from './jotaiUtils';
11import platform from './platform';
12import {registerDisposable} from './utils';
13
14import 'isl-components/theme/themeDark.css';
15import 'isl-components/theme/themeLight.css';
16
17const THEME_LOCAL_STORAGE_KEY = 'isl-color-theme';
18
19export type ThemeColor = 'dark' | 'light';
20
21// local override. `null` means prefer platform theme.
22const localThemeState = localStorageBackedAtom<ThemeColor | null>(THEME_LOCAL_STORAGE_KEY, null);
23
24// platform theme. `null` means not supported.
25const theme = platform.theme;
26const platformThemeState = atom<ThemeColor | undefined>(theme?.getTheme());
27registerDisposable(
28 platform,
29 theme?.onDidChangeTheme(themeColor => {
30 writeAtom(platformThemeState, themeColor);
31 // reset local theme state so the user can notice the theme change
32 writeAtom(localThemeState, null);
33 theme.getThemeName && writeAtom(themeNameState, theme.getThemeName());
34 }) ?? {dispose: () => null},
35 import.meta.hot,
36);
37
38// combined state
39// - read: nullable local theme -> platform theme -> 'dark'
40// - write: update local theme
41export const themeState = atom<ThemeColor, [ThemeColor], void>(
42 get => get(localThemeState) ?? get(platformThemeState) ?? 'dark',
43 (_get, set, themeColor) => set(localThemeState, themeColor),
44);
45
46/**
47 * The specific theme name, like "Default Light Modern".
48 * Typically, you'd rather use `themeState` to get simply "light" / "dark".
49 * Theme name is useful for dynamically updating stylex styles for specific themes.
50 */
51export const themeNameState = atom<string | undefined>(theme?.getThemeName?.());
52
53export function useThemeShortcut() {
54 useCommand('ToggleTheme', () => {
55 if (platform.theme == null) {
56 writeAtom(localThemeState, theme => (theme === 'dark' ? 'light' : 'dark'));
57 }
58 });
59}
60