Skip to content

Commit bd4fecc

Browse files
committed
fix: default to current system theme if no theme set
1 parent 5232b60 commit bd4fecc

File tree

12 files changed

+117
-84
lines changed

12 files changed

+117
-84
lines changed

src/ambient.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ declare global {
154154
pathExists(path: string): boolean;
155155
platform: string;
156156
pushOutputEntry(entry: OutputEntry): void;
157-
readThemeFile(name?: string): Promise<LoadedFiddleTheme | null>;
157+
readThemeFile(name: string): Promise<LoadedFiddleTheme | null>;
158158
reloadWindows(): void;
159159
removeAllListeners(type: FiddleEvent): void;
160160
removeVersion(version: string): Promise<InstallState>;

src/main/themes.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import * as namor from 'namor';
77
import { ipcMainManager } from './ipc';
88
import { IpcEvents } from '../ipc-events';
99
import {
10-
DefaultThemes,
1110
FiddleTheme,
1211
LoadedFiddleTheme,
1312
defaultDark,
@@ -21,11 +20,8 @@ export const THEMES_PATH = path.join(CONFIG_PATH, 'themes');
2120
* Read in a theme file.
2221
*/
2322
export async function readThemeFile(
24-
name?: string,
23+
name: string,
2524
): Promise<LoadedFiddleTheme | null> {
26-
if (!name || name === DefaultThemes.DARK) return defaultDark;
27-
if (name === DefaultThemes.LIGHT) return defaultLight;
28-
2925
const file = name.endsWith('.json') ? name : `${name}.json`;
3026
const themePath = path.join(THEMES_PATH, file);
3127

@@ -117,7 +113,7 @@ export async function openThemeFolder() {
117113
export function setupThemes() {
118114
ipcMainManager.handle(
119115
IpcEvents.READ_THEME_FILE,
120-
(_: IpcMainEvent, name?: string) => readThemeFile(name),
116+
(_: IpcMainEvent, name: string) => readThemeFile(name),
121117
);
122118
ipcMainManager.handle(IpcEvents.GET_AVAILABLE_THEMES, (_: IpcMainEvent) =>
123119
getAvailableThemes(),

src/renderer/app.tsx

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
import { autorun, reaction, when } from 'mobx';
22

3+
import { PREFERS_DARK_MEDIA_QUERY } from './constants';
34
import { ElectronTypes } from './electron-types';
45
import { FileManager } from './file-manager';
56
import { RemoteLoader } from './remote-loader';
67
import { Runner } from './runner';
78
import { AppState } from './state';
89
import { TaskRunner } from './task-runner';
9-
import { activateTheme, getTheme } from './themes';
10+
import { activateTheme, getCurrentTheme, getTheme } from './themes';
1011
import { getPackageJson } from './utils/get-package';
1112
import { getElectronVersions } from './versions';
1213
import {
@@ -101,7 +102,11 @@ export class App {
101102
* render process.
102103
*/
103104
public async setup(): Promise<void | Element | React.Component> {
104-
await this.loadTheme(this.state.theme || '');
105+
if (this.state.isUsingSystemTheme) {
106+
await this.loadTheme(getCurrentTheme().file);
107+
} else {
108+
await this.loadTheme(this.state.theme);
109+
}
105110

106111
const [
107112
{ default: React },
@@ -158,33 +163,25 @@ export class App {
158163
}
159164

160165
public async setupThemeListeners() {
161-
const setSystemTheme = (prefersDark: boolean) => {
162-
if (prefersDark) {
163-
this.state.setTheme(defaultDark.file);
164-
} else {
165-
this.state.setTheme(defaultLight.file);
166-
}
167-
};
168-
169166
// match theme to system when box is ticked
170167
reaction(
171168
() => this.state.isUsingSystemTheme,
172169
() => {
173170
if (this.state.isUsingSystemTheme) {
174171
window.ElectronFiddle.setNativeTheme('system');
175-
176-
const { matches } = window.matchMedia('(prefers-color-scheme: dark)');
177-
setSystemTheme(matches);
172+
this.loadTheme(getCurrentTheme().file);
173+
} else {
174+
this.loadTheme(this.state.theme);
178175
}
179176
},
180177
);
181178

182179
// change theme when system theme changes
183180
window
184-
.matchMedia('(prefers-color-scheme: dark)')
185-
.addEventListener('change', ({ matches }) => {
181+
.matchMedia(PREFERS_DARK_MEDIA_QUERY)
182+
.addEventListener('change', ({ matches: prefersDark }) => {
186183
if (this.state.isUsingSystemTheme) {
187-
setSystemTheme(matches);
184+
this.loadTheme((prefersDark ? defaultDark : defaultLight).file);
188185
}
189186
});
190187
}
@@ -209,10 +206,10 @@ export class App {
209206
/**
210207
* Loads theme CSS into the HTML document.
211208
*/
212-
public async loadTheme(name: string): Promise<void> {
209+
public async loadTheme(name: string | null): Promise<void> {
213210
const tag: HTMLStyleElement | null =
214211
document.querySelector('style#fiddle-theme');
215-
const theme = await getTheme(name);
212+
const theme = await getTheme(this.state, name);
216213
activateTheme(theme);
217214

218215
if (tag && theme.css) {

src/renderer/components/dialog-add-theme.tsx

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { Button, Dialog, FileInput } from '@blueprintjs/core';
44
import { observer } from 'mobx-react';
55
import * as MonacoType from 'monaco-editor';
66

7-
import { FiddleTheme, defaultDark } from '../../themes-defaults';
7+
import { FiddleTheme } from '../../themes-defaults';
88
import { AppState } from '../state';
99
import { getTheme } from '../themes';
1010

@@ -52,9 +52,7 @@ export const AddThemeDialog = observer(
5252
const { file } = this.state;
5353
const { appState } = this.props;
5454

55-
const defaultTheme = !!appState.theme
56-
? await getTheme(appState.theme)
57-
: defaultDark;
55+
const defaultTheme = await getTheme(appState, appState.theme);
5856

5957
if (!file) return;
6058

src/renderer/components/settings-general-appearance.tsx

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import { observer } from 'mobx-react';
1313

1414
import { LoadedFiddleTheme } from '../../themes-defaults';
1515
import { AppState } from '../state';
16-
import { getTheme } from '../themes';
16+
import { getCurrentTheme, getTheme } from '../themes';
1717
import { highlightText } from '../utils/highlight-text';
1818

1919
const ThemeSelect = Select.ofType<LoadedFiddleTheme>();
@@ -86,15 +86,19 @@ export const AppearanceSettings = observer(
8686
window.ElectronFiddle.getAvailableThemes().then((themes) => {
8787
const { theme } = this.props.appState;
8888
const selectedTheme =
89-
(theme && themes.find(({ file }) => file === theme)) || themes[0];
89+
(theme && themes.find(({ file }) => file === theme)) ||
90+
getCurrentTheme();
9091

9192
this.setState({ themes, selectedTheme });
9293

9394
// set up mobx so that changes from system sync are reflected in picker
9495
reaction(
9596
() => this.props.appState.theme,
9697
async () => {
97-
const selectedTheme = await getTheme(this.props.appState.theme);
98+
const selectedTheme = await getTheme(
99+
this.props.appState,
100+
this.props.appState.theme,
101+
);
98102
this.setState({ selectedTheme });
99103
},
100104
);
@@ -119,7 +123,7 @@ export const AppearanceSettings = observer(
119123
*/
120124
public async createNewThemeFromCurrent(): Promise<boolean> {
121125
const { appState } = this.props;
122-
const theme = await getTheme(appState.theme);
126+
const theme = await getTheme(appState, appState.theme);
123127

124128
try {
125129
await window.ElectronFiddle.createThemeFile(theme);
@@ -172,8 +176,7 @@ export const AppearanceSettings = observer(
172176
public render() {
173177
const { selectedTheme } = this.state;
174178
const { isUsingSystemTheme } = this.props.appState;
175-
const selectedName =
176-
(selectedTheme && selectedTheme.name) || 'Select a theme';
179+
const selectedName = selectedTheme?.name || 'Select a theme';
177180

178181
return (
179182
<div className="settings-appearance">

src/renderer/constants.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,5 @@ export const ELECTRON_ORG = 'electron';
22
export const ELECTRON_REPO = 'electron';
33

44
export const FIDDLE_GIST_DESCRIPTION_PLACEHOLDER = 'Electron Fiddle Gist';
5+
6+
export const PREFERS_DARK_MEDIA_QUERY = '(prefers-color-scheme: dark)';

src/renderer/state.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -737,8 +737,8 @@ export class AppState {
737737
this.resetView({ isTourShowing: true });
738738
}
739739

740-
public setTheme(fileName?: string) {
741-
this.theme = fileName || '';
740+
public setTheme(fileName: string | null) {
741+
this.theme = fileName;
742742
window.app.loadTheme(this.theme);
743743
}
744744

src/renderer/themes.ts

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
1+
import { PREFERS_DARK_MEDIA_QUERY } from './constants';
2+
import { AppState } from './state';
13
import {
4+
DefaultThemes,
25
FiddleTheme,
36
LoadedFiddleTheme,
47
defaultDark,
8+
defaultLight,
59
} from '../themes-defaults';
610

711
/**
@@ -13,17 +17,37 @@ export function activateTheme(theme: LoadedFiddleTheme) {
1317
monaco.editor.setTheme('main');
1418
}
1519

20+
export function getCurrentTheme(): LoadedFiddleTheme {
21+
return window.matchMedia(PREFERS_DARK_MEDIA_QUERY).matches
22+
? defaultDark
23+
: defaultLight;
24+
}
25+
1626
/**
1727
* Returns a Fiddle theme, either a default one or by checking
1828
* the disk for a JSON file.
1929
*/
2030
export async function getTheme(
21-
name?: string | null,
31+
appState: AppState,
32+
name: string | null,
2233
): Promise<LoadedFiddleTheme> {
2334
console.log(`Themes: getTheme() loading ${name || 'default'}`);
24-
const theme =
25-
(await window.ElectronFiddle.readThemeFile(name || undefined)) ||
26-
defaultDark;
35+
36+
let theme: LoadedFiddleTheme | null = null;
37+
38+
if (name === DefaultThemes.LIGHT) {
39+
theme = defaultLight;
40+
} else if (name === DefaultThemes.DARK) {
41+
theme = defaultDark;
42+
} else if (name) {
43+
theme = await window.ElectronFiddle.readThemeFile(name);
44+
}
45+
46+
// If there is no theme, default to the current system theme
47+
// if the app is using system theme, otherwise default to dark
48+
if (!theme) {
49+
theme = appState.isUsingSystemTheme ? getCurrentTheme() : defaultDark;
50+
}
2751

2852
return { ...theme, css: await getCssStringForTheme(theme) };
2953
}

tests/main/themes-spec.ts

Lines changed: 2 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {
1111
openThemeFolder,
1212
readThemeFile,
1313
} from '../../src/main/themes';
14-
import { DefaultThemes, LoadedFiddleTheme } from '../../src/themes-defaults';
14+
import { LoadedFiddleTheme, defaultDark } from '../../src/themes-defaults';
1515

1616
jest.mock('fs-extra');
1717

@@ -82,21 +82,6 @@ describe('themes', () => {
8282
});
8383

8484
describe('readThemeFile()', () => {
85-
it('returns the default (light) theme', async () => {
86-
const theme = await readThemeFile(DefaultThemes.LIGHT);
87-
expect(theme!.name).toBe('Fiddle (Light)');
88-
});
89-
90-
it('returns the default (Dark) theme', async () => {
91-
const theme = await readThemeFile(DefaultThemes.DARK);
92-
expect(theme!.name).toBe('Fiddle (Dark)');
93-
});
94-
95-
it('returns the default (Dark) theme if no name provided', async () => {
96-
const theme = await readThemeFile();
97-
expect(theme!.name).toBe('Fiddle (Dark)');
98-
});
99-
10085
it('reads the right file if ends with .json', async () => {
10186
(fs.readJSON as jest.Mock).mockResolvedValueOnce({});
10287

@@ -122,12 +107,7 @@ describe('themes', () => {
122107
let defaultTheme: LoadedFiddleTheme;
123108

124109
beforeEach(async () => {
125-
const theme = await readThemeFile();
126-
if (theme) {
127-
defaultTheme = theme;
128-
} else {
129-
fail('Error loading default theme');
130-
}
110+
defaultTheme = defaultDark;
131111
});
132112

133113
it('filters out file and css keys', async () => {

0 commit comments

Comments
 (0)