Skip to content

Commit 504213c

Browse files
authored
Merge pull request #92 from Bleuzen/add-auto-theme
Add automatic theme (syncs with system settings)
2 parents 9e0d3e8 + 7e947a1 commit 504213c

File tree

3 files changed

+44
-12
lines changed

3 files changed

+44
-12
lines changed

src/components/settings/settings-page.tsx

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ const ThemeColors = styled.div`
9090
display: grid;
9191
grid-template-columns: 1fr 1fr;
9292
border: 3px solid #999;
93-
margin: 0 20px;
93+
margin: auto 20px;
9494
`;
9595

9696
const ThemeColorBlock = styled.div<{ themeColor: keyof Theme }>`
@@ -103,6 +103,7 @@ const EditorContainer = styled.div`
103103
border: 3px solid #999;
104104
height: 300px;
105105
flex-grow: 1;
106+
margin: auto 0;
106107
`;
107108

108109
const AccountUpdateSpinner = styled(Icon).attrs(() => ({
@@ -288,15 +289,21 @@ class SettingsPage extends React.Component<SettingsPageProps> {
288289
</header>
289290
<TabbedOptionsContainer>
290291
<TabsContainer
291-
onClick={(value: ThemeName | Theme) => uiStore.setTheme(value)}
292-
isSelected={(value: ThemeName | Theme) => {
292+
onClick={(value: ThemeName | 'automatic' | Theme) => uiStore.setTheme(value)}
293+
isSelected={(value: ThemeName | 'automatic' | Theme) => {
293294
if (typeof value === 'string') {
294-
return uiStore.themeName === value
295+
return uiStore.themeName === value;
295296
} else {
296297
return _.isEqual(value, uiStore.theme);
297298
}
298299
}}
299300
>
301+
<Tab
302+
icon={['fas', 'magic']}
303+
value='automatic'
304+
>
305+
Automatic
306+
</Tab>
300307
<Tab
301308
icon={['fas', 'sun']}
302309
value='light'
@@ -311,7 +318,7 @@ class SettingsPage extends React.Component<SettingsPageProps> {
311318
</Tab>
312319
<Tab
313320
icon={['fas', 'adjust']}
314-
value={'high-contrast'}
321+
value='high-contrast'
315322
>
316323
High Contrast
317324
</Tab>

src/icons.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import { faExclamationTriangle } from '@fortawesome/free-solid-svg-icons/faExcla
3737
import { faLightbulb } from '@fortawesome/free-solid-svg-icons/faLightbulb';
3838
import { faCog } from '@fortawesome/free-solid-svg-icons/faCog';
3939
import { faStar } from '@fortawesome/free-regular-svg-icons/faStar';
40+
import { faMagic } from '@fortawesome/free-solid-svg-icons/faMagic';
4041
import { faSun } from '@fortawesome/free-solid-svg-icons/faSun';
4142
import { faMoon } from '@fortawesome/free-solid-svg-icons/faMoon';
4243
import { faAdjust } from '@fortawesome/free-solid-svg-icons/faAdjust';
@@ -114,6 +115,7 @@ library.add(
114115
faLightbulb,
115116
faCog,
116117
faStar,
118+
faMagic,
117119
faSun,
118120
faMoon,
119121
faAdjust,

src/model/ui/ui-store.ts

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -111,19 +111,27 @@ export class UiStore {
111111
// logout & subscription expiration (even if that happened while the app was
112112
// closed), but don't get reset when the app starts with stale account data.
113113
observe(this.accountStore, 'accountDataLastUpdated', () => {
114-
if (!this.accountStore.isPaidUser) this.setTheme('light');
114+
if (!this.accountStore.isPaidUser) {
115+
this.setTheme('light');
116+
}
115117
});
116118

117119
await hydrate({
118120
key: 'ui-store',
119121
store: this
120122
});
121123

124+
const darkThemeMq = window.matchMedia("(prefers-color-scheme: dark)");
125+
this._setPrefersDarkTheme(darkThemeMq.matches);
126+
darkThemeMq.addEventListener('change', e => {
127+
this._setPrefersDarkTheme(e.matches);
128+
});
129+
122130
console.log('UI store initialized');
123131
});
124132

125133
@action.bound
126-
setTheme(themeNameOrObject: Theme | ThemeName) {
134+
setTheme(themeNameOrObject: Theme | ThemeName | 'automatic') {
127135
if (typeof themeNameOrObject === 'string') {
128136
this._themeName = themeNameOrObject;
129137
this.customTheme = undefined;
@@ -134,21 +142,36 @@ export class UiStore {
134142
}
135143

136144
@persist @observable
137-
private _themeName: ThemeName | 'custom' = 'light';
145+
private _themeName: ThemeName | 'automatic' | 'custom' = 'light';
138146

139147
get themeName() {
140148
return this._themeName;
141149
}
142150

151+
/**
152+
* Stores if user prefers a dark color theme (for example when set in system settings).
153+
* Used if automatic theme is enabled.
154+
*/
155+
@observable
156+
private _prefersDarkTheme: boolean = false;
157+
158+
@action.bound
159+
private _setPrefersDarkTheme(value: boolean) {
160+
this._prefersDarkTheme = value;
161+
}
162+
143163
@persist('object') @observable
144164
private customTheme: Theme | undefined = undefined;
145165

146166
@computed
147167
get theme(): Theme {
148-
if (this.themeName === 'custom') {
149-
return this.customTheme!;
150-
} else {
151-
return Themes[this.themeName];
168+
switch(this.themeName) {
169+
case 'automatic':
170+
return {...Themes[this._prefersDarkTheme ? 'dark' : 'light']}
171+
case 'custom':
172+
return this.customTheme!;
173+
default:
174+
return Themes[this.themeName];
152175
}
153176
}
154177

0 commit comments

Comments
 (0)