-
Notifications
You must be signed in to change notification settings - Fork 1.5k
/
Copy paththemeLogic.ts
110 lines (107 loc) · 4.33 KB
/
themeLogic.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
import { actions, connect, events, kea, listeners, path, reducers, selectors } from 'kea'
import { FEATURE_FLAGS } from 'lib/constants'
import { featureFlagLogic } from 'lib/logic/featureFlagLogic'
import { sceneLogic } from 'scenes/sceneLogic'
import { userLogic } from 'scenes/userLogic'
import type { themeLogicType } from './themeLogicType'
import { Theme, themes } from './themes'
export const themeLogic = kea<themeLogicType>([
path(['layout', 'navigation-3000', 'themeLogic']),
connect({
values: [userLogic, ['themeMode'], featureFlagLogic, ['featureFlags']],
}),
actions({
syncDarkModePreference: (darkModePreference: boolean) => ({ darkModePreference }),
setTheme: (theme: string | null) => ({ theme }),
saveCustomCss: true,
setPersistedCustomCss: (css: string | null) => ({ css }),
setPreviewingCustomCss: (css: string | null) => ({ css }),
}),
reducers({
darkModeSystemPreference: [
window.matchMedia('(prefers-color-scheme: dark)').matches,
{
syncDarkModePreference: (_, { darkModePreference }) => darkModePreference,
},
],
selectedTheme: [
null as string | null,
{ persist: true },
{
setTheme: (_, { theme }) => theme,
},
],
persistedCustomCss: [
null as string | null,
{ persist: true },
{
setPersistedCustomCss: (_, { css }) => css,
},
],
previewingCustomCss: [
null as string | null,
{ persist: true },
{
setPreviewingCustomCss: (_, { css }) => css,
},
],
}),
selectors({
theme: [
(s) => [s.selectedTheme, s.featureFlags],
(selectedTheme, featureFlags): Theme | null => {
const flagVariant = featureFlags[FEATURE_FLAGS.THEME]
return (
(selectedTheme ? themes.find((theme) => theme.id === selectedTheme) : null) ??
(typeof flagVariant === 'string' ? themes.find((theme) => theme.id === flagVariant) : null) ??
null
)
},
],
customCssEnabled: [
(s) => [s.featureFlags],
(featureFlags): boolean => !!featureFlags[FEATURE_FLAGS.CUSTOM_CSS_THEMES],
],
customCss: [
(s) => [s.persistedCustomCss, s.previewingCustomCss],
(persistedCustomCss, previewingCustomCss): string | null => previewingCustomCss || persistedCustomCss,
],
isDarkModeOn: [
(s) => [s.themeMode, s.darkModeSystemPreference, sceneLogic.selectors.sceneConfig, s.theme],
(themeMode, darkModeSystemPreference, sceneConfig, theme) => {
if (
typeof window !== 'undefined' &&
window.document &&
document.body.classList.contains('storybook-test-runner') &&
document.body.getAttribute('theme') == 'dark'
) {
return true
}
if (theme) {
return !!theme?.dark
}
// NOTE: Unauthenticated users always get the light mode until we have full support for dark mode there
if (sceneConfig?.allowUnauthenticated || sceneConfig?.onlyUnauthenticated) {
return false
}
return themeMode === 'system' ? darkModeSystemPreference : themeMode === 'dark'
},
],
}),
listeners(({ values, actions }) => ({
saveCustomCss() {
actions.setPersistedCustomCss(values.previewingCustomCss)
actions.setPreviewingCustomCss(null)
},
})),
events(({ cache, actions }) => ({
afterMount() {
cache.prefersColorSchemeMedia = window.matchMedia('(prefers-color-scheme: dark)')
cache.onPrefersColorSchemeChange = (e: MediaQueryListEvent) => actions.syncDarkModePreference(e.matches)
cache.prefersColorSchemeMedia.addEventListener('change', cache.onPrefersColorSchemeChange)
},
beforeUnmount() {
cache.prefersColorSchemeMedia.removeEventListener('change', cache.onPrefersColorSchemeChange)
},
})),
])