Skip to content

Commit 91776ac

Browse files
authored
Merge pull request #2599 from RedisInsight/feature/RI-4893
RI-4893: Add system theme option
2 parents 1931e31 + 1a89a50 commit 91776ac

File tree

11 files changed

+84
-12
lines changed

11 files changed

+84
-12
lines changed

redisinsight/desktop/app.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,6 @@ const init = async () => {
3333
initTray()
3434
initCloudHandlers()
3535

36-
nativeTheme.themeSource = config.themeSource
37-
3836
checkForUpdate(process.env.MANUAL_UPGRADES_LINK || process.env.UPGRADES_LINK)
3937

4038
app.setName(config.name)

redisinsight/desktop/config.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
"defaultPort": 5530,
44
"host": "localhost",
55
"debug": false,
6-
"themeSource": "dark",
76
"appName": "RedisInsight",
87
"schema": "redisinsight",
98
"mainWindow": {

redisinsight/desktop/src/lib/app/ipc.handlers.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { app, ipcMain } from 'electron'
1+
import { app, ipcMain, nativeTheme } from 'electron'
22
import { electronStore } from 'desktopSrc/lib'
33
import { IpcInvokeEvent } from 'uiSrc/electron/constants'
44

@@ -8,4 +8,8 @@ export const initIPCHandlers = () => {
88
ipcMain.handle(IpcInvokeEvent.getStoreValue, (_event, key) => electronStore?.get(key))
99

1010
ipcMain.handle(IpcInvokeEvent.deleteStoreValue, (_event, key) => electronStore?.delete(key))
11+
12+
ipcMain.handle(IpcInvokeEvent.themeChange, (_event, theme: string) => {
13+
nativeTheme.themeSource = theme.toLowerCase()
14+
})
1115
}

redisinsight/ui/src/App.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { themeService } from './services'
1212
import { Config, GlobalSubscriptions, NavigationMenu, Notifications, ShortcutsFlyout } from './components'
1313
import { ThemeProvider } from './contexts/themeContext'
1414
import MainComponent from './components/main/MainComponent'
15+
import ThemeComponent from './components/theme/ThemeComponent'
1516
import GlobalDialogs from './components/global-dialogs'
1617
import GlobalActionBar from './components/global-action-bar'
1718

@@ -38,6 +39,7 @@ const App = ({ children }: { children?: ReactElement[] }) => {
3839
const { loading: serverLoading } = useSelector(appInfoSelector)
3940
return (
4041
<div className="main-container">
42+
<ThemeComponent />
4143
{ serverLoading
4244
? <PagePlaceholder />
4345
: (
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import React from 'react'
2+
import { render } from 'uiSrc/utils/test-utils'
3+
4+
import ThemeComponent from './ThemeComponent'
5+
6+
describe('ThemeComponent', () => {
7+
it('should render', () => {
8+
expect(render(<ThemeComponent />)).toBeTruthy()
9+
})
10+
})
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import React, { useContext, useEffect } from 'react'
2+
import { BrowserStorageItem, Theme, THEME_MATCH_MEDIA_DARK } from 'uiSrc/constants'
3+
import { localStorageService } from 'uiSrc/services'
4+
import { ThemeContext } from 'uiSrc/contexts/themeContext'
5+
6+
const ThemeComponent = () => {
7+
const themeContext = useContext(ThemeContext)
8+
useEffect(() => {
9+
const handler = event => {
10+
let theme = localStorageService.get(BrowserStorageItem.theme)
11+
if (theme === Theme.System) {
12+
themeContext.changeTheme(theme)
13+
}
14+
}
15+
16+
window.matchMedia(THEME_MATCH_MEDIA_DARK).addEventListener('change', handler)
17+
18+
return () => {
19+
window.matchMedia(THEME_MATCH_MEDIA_DARK).removeEventListener('change', handler)
20+
}
21+
}, [])
22+
23+
return <></>
24+
}
25+
26+
export default ThemeComponent

redisinsight/ui/src/constants/themes.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,14 @@ import { EuiSuperSelectOption } from '@elastic/eui'
33
export enum Theme {
44
Dark = 'DARK',
55
Light = 'LIGHT',
6+
System = 'SYSTEM',
67
}
78

89
export const THEMES: EuiSuperSelectOption<string>[] = [
10+
{
11+
inputDisplay: 'Match System',
12+
value: Theme.System,
13+
},
914
{
1015
inputDisplay: 'Dark Theme',
1116
value: Theme.Dark,
@@ -16,4 +21,6 @@ export const THEMES: EuiSuperSelectOption<string>[] = [
1621
},
1722
]
1823

24+
export const THEME_MATCH_MEDIA_DARK = '(prefers-color-scheme: dark)'
25+
1926
export default THEMES

redisinsight/ui/src/contexts/themeContext.tsx

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import React from 'react'
2-
import { BrowserStorageItem, THEMES } from '../constants'
2+
import { BrowserStorageItem, Theme, THEMES, THEME_MATCH_MEDIA_DARK } from '../constants'
33
import { localStorageService, themeService } from '../services'
44

55
interface Props {
@@ -10,6 +10,7 @@ const THEME_NAMES = THEMES.map(({ value }) => value)
1010

1111
export const defaultState = {
1212
theme: THEME_NAMES[0],
13+
usingSystemTheme: localStorageService.get(BrowserStorageItem.theme) === Theme.System,
1314
changeTheme: (themeValue: any) => {
1415
themeService.applyTheme(themeValue)
1516
},
@@ -25,28 +26,39 @@ export class ThemeProvider extends React.Component<Props> {
2526
const theme = !storedThemeValue || !THEME_NAMES.includes(storedThemeValue)
2627
? defaultState.theme
2728
: storedThemeValue
29+
const usingSystemTheme = theme === Theme.System
2830

2931
themeService.applyTheme(theme)
3032

3133
this.state = {
32-
theme,
34+
theme: theme === Theme.System ? this.getSystemTheme() : theme,
35+
usingSystemTheme,
3336
}
3437
}
3538

39+
getSystemTheme = () => window.matchMedia && window.matchMedia(THEME_MATCH_MEDIA_DARK).matches ? Theme.Dark : Theme.Light
40+
3641
changeTheme = (themeValue: any) => {
37-
this.setState({ theme: themeValue }, () => {
42+
let actualTheme = themeValue
43+
if (themeValue === Theme.System) {
44+
actualTheme = this.getSystemTheme()
45+
}
46+
window.app?.ipc?.invoke?.('theme:change', themeValue)
47+
48+
this.setState({ theme: actualTheme, usingSystemTheme: themeValue === Theme.System }, () => {
3849
themeService.applyTheme(themeValue)
3950
})
4051
}
4152

4253
render() {
4354
const { children } = this.props
44-
const { theme }: any = this.state
55+
const { theme, usingSystemTheme }: any = this.state
4556

4657
return (
4758
<ThemeContext.Provider
4859
value={{
4960
theme,
61+
usingSystemTheme,
5062
changeTheme: this.changeTheme,
5163
}}
5264
>

redisinsight/ui/src/electron/constants/ipcEvent.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ enum IpcInvokeEvent {
44
getAppVersion = 'app:get:version',
55
cloudOauth = 'cloud:oauth',
66
windowOpen = 'window:open',
7+
themeChange = 'theme:change',
78
}
89

910
enum IpcOnEvent {

redisinsight/ui/src/pages/settings/SettingsPage.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import {
1818
import { useDispatch, useSelector } from 'react-redux'
1919

2020
import { setTitle } from 'uiSrc/utils'
21-
import { FeatureFlags, THEMES } from 'uiSrc/constants'
21+
import { FeatureFlags, Theme, THEMES } from 'uiSrc/constants'
2222
import { useDebouncedEffect } from 'uiSrc/services'
2323
import { ConsentsNotifications, ConsentsPrivacy, FeatureFlagComponent } from 'uiSrc/components'
2424
import { sendEventTelemetry, sendPageViewTelemetry, TelemetryEvent, TelemetryPageView } from 'uiSrc/telemetry'
@@ -43,7 +43,11 @@ const SettingsPage = () => {
4343

4444
const options = THEMES
4545
const themeContext = useContext(ThemeContext)
46-
const { theme, changeTheme } = themeContext
46+
let { theme, changeTheme, usingSystemTheme } = themeContext
47+
48+
if (usingSystemTheme) {
49+
theme = Theme.System
50+
}
4751

4852
useEffect(() => {
4953
// componentDidMount

0 commit comments

Comments
 (0)