Add toggle to use browser's preferred theme (#224)

* Add Auto theme that uses browser's preferred color scheme

This will use dark mode automatically if the browser requests it.

* fixup! Add Auto theme that uses browser's preferred color scheme

* Use a toggle to use system theme
This commit is contained in:
Gregory Anders 2022-01-03 06:16:43 -07:00 committed by GitHub
parent 63a0adaa6e
commit 11f395f65f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 74 additions and 14 deletions

View file

@ -5,7 +5,7 @@ import './Settings.scss';
import initMatrix from '../../../client/initMatrix'; import initMatrix from '../../../client/initMatrix';
import cons from '../../../client/state/cons'; import cons from '../../../client/state/cons';
import settings from '../../../client/state/settings'; import settings from '../../../client/state/settings';
import { toggleMarkdown, toggleMembershipEvents, toggleNickAvatarEvents } from '../../../client/action/settings'; import { toggleSystemTheme, toggleMarkdown, toggleMembershipEvents, toggleNickAvatarEvents } from '../../../client/action/settings';
import logout from '../../../client/action/logout'; import logout from '../../../client/action/logout';
import Text from '../../atoms/text/Text'; import Text from '../../atoms/text/Text';
@ -49,20 +49,34 @@ function AppearanceSection() {
return ( return (
<div className="settings-content"> <div className="settings-content">
<SettingTile <SettingTile
title="Theme" title="Follow system theme"
content={( options={(
<SegmentedControls <Toggle
selected={settings.getThemeIndex()} isActive={settings.useSystemTheme}
segments={[ onToggle={() => { toggleSystemTheme(); updateState({}); }}
{ text: 'Light' },
{ text: 'Silver' },
{ text: 'Dark' },
{ text: 'Butter' },
]}
onSelect={(index) => settings.setTheme(index)}
/> />
)} )}
content={<Text variant="b3">Use light or dark mode based on the system's settings.</Text>}
/> />
{(() => {
if (!settings.useSystemTheme) {
return <SettingTile
title="Theme"
content={(
<SegmentedControls
selected={settings.getThemeIndex()}
segments={[
{ text: 'Light' },
{ text: 'Silver' },
{ text: 'Dark' },
{ text: 'Butter' },
]}
onSelect={(index) => settings.setTheme(index)}
/>
)}
/>
}
})()}
<SettingTile <SettingTile
title="Markdown formatting" title="Markdown formatting"
options={( options={(

View file

@ -1,6 +1,12 @@
import appDispatcher from '../dispatcher'; import appDispatcher from '../dispatcher';
import cons from '../state/cons'; import cons from '../state/cons';
export function toggleSystemTheme() {
appDispatcher.dispatch({
type: cons.actions.settings.TOGGLE_SYSTEM_THEME,
});
}
export function toggleMarkdown() { export function toggleMarkdown() {
appDispatcher.dispatch({ appDispatcher.dispatch({
type: cons.actions.settings.TOGGLE_MARKDOWN, type: cons.actions.settings.TOGGLE_MARKDOWN,

View file

@ -54,6 +54,7 @@ const cons = {
}, },
}, },
settings: { settings: {
TOGGLE_SYSTEM_THEME: 'TOGGLE_SYSTEM_THEME',
TOGGLE_MARKDOWN: 'TOGGLE_MARKDOWN', TOGGLE_MARKDOWN: 'TOGGLE_MARKDOWN',
TOGGLE_PEOPLE_DRAWER: 'TOGGLE_PEOPLE_DRAWER', TOGGLE_PEOPLE_DRAWER: 'TOGGLE_PEOPLE_DRAWER',
TOGGLE_MEMBERSHIP_EVENT: 'TOGGLE_MEMBERSHIP_EVENT', TOGGLE_MEMBERSHIP_EVENT: 'TOGGLE_MEMBERSHIP_EVENT',
@ -110,6 +111,7 @@ const cons = {
ATTACHMENT_CANCELED: 'ATTACHMENT_CANCELED', ATTACHMENT_CANCELED: 'ATTACHMENT_CANCELED',
}, },
settings: { settings: {
SYSTEM_THEME_TOGGLED: 'SYSTEM_THEME_TOGGLED',
MARKDOWN_TOGGLED: 'MARKDOWN_TOGGLED', MARKDOWN_TOGGLED: 'MARKDOWN_TOGGLED',
PEOPLE_DRAWER_TOGGLED: 'PEOPLE_DRAWER_TOGGLED', PEOPLE_DRAWER_TOGGLED: 'PEOPLE_DRAWER_TOGGLED',
MEMBERSHIP_EVENTS_TOGGLED: 'MEMBERSHIP_EVENTS_TOGGLED', MEMBERSHIP_EVENTS_TOGGLED: 'MEMBERSHIP_EVENTS_TOGGLED',

View file

@ -23,6 +23,7 @@ class Settings extends EventEmitter {
this.themes = ['', 'silver-theme', 'dark-theme', 'butter-theme']; this.themes = ['', 'silver-theme', 'dark-theme', 'butter-theme'];
this.themeIndex = this.getThemeIndex(); this.themeIndex = this.getThemeIndex();
this.useSystemTheme = this.getUseSystemTheme();
this.isMarkdown = this.getIsMarkdown(); this.isMarkdown = this.getIsMarkdown();
this.isPeopleDrawer = this.getIsPeopleDrawer(); this.isPeopleDrawer = this.getIsPeopleDrawer();
this.hideMembershipEvents = this.getHideMembershipEvents(); this.hideMembershipEvents = this.getHideMembershipEvents();
@ -56,6 +57,15 @@ class Settings extends EventEmitter {
this.themeIndex = themeIndex; this.themeIndex = themeIndex;
} }
getUseSystemTheme() {
if (typeof this.useSystemTheme === 'boolean') return this.useSystemTheme;
const settings = getSettings();
if (settings === null) return false;
if (typeof settings.useSystemTheme === 'undefined') return false;
return settings.useSystemTheme;
}
getIsMarkdown() { getIsMarkdown() {
if (typeof this.isMarkdown === 'boolean') return this.isMarkdown; if (typeof this.isMarkdown === 'boolean') return this.isMarkdown;
@ -94,6 +104,24 @@ class Settings extends EventEmitter {
setter(action) { setter(action) {
const actions = { const actions = {
[cons.actions.settings.TOGGLE_SYSTEM_THEME]: () => {
this.useSystemTheme = !this.useSystemTheme;
setSettings('useSystemTheme', this.useSystemTheme);
const appBody = document.getElementById('appBody');
if (this.useSystemTheme) {
appBody.classList.add('system-theme');
this.themes.forEach((themeName) => {
if (themeName === '') return;
appBody.classList.remove(themeName);
});
} else {
appBody.classList.remove('system-theme');
this.setTheme(this.themeIndex);
}
this.emit(cons.events.settings.SYSTEM_THEME_TOGGLED, this.useSystemTheme);
},
[cons.actions.settings.TOGGLE_MARKDOWN]: () => { [cons.actions.settings.TOGGLE_MARKDOWN]: () => {
this.isMarkdown = !this.isMarkdown; this.isMarkdown = !this.isMarkdown;
setSettings('isMarkdown', this.isMarkdown); setSettings('isMarkdown', this.isMarkdown);

View file

@ -202,8 +202,7 @@
--bg-surface-extra-low-transparent: hsla(0, 0%, 91%, 0); --bg-surface-extra-low-transparent: hsla(0, 0%, 91%, 0);
} }
.dark-theme, @mixin dark-mode() {
.butter-theme {
/* background color | --bg-[background type]: value */ /* background color | --bg-[background type]: value */
--bg-surface: hsl(208, 8%, 20%); --bg-surface: hsl(208, 8%, 20%);
--bg-surface-transparent: hsla(208, 8%, 20%, 0); --bg-surface-transparent: hsla(208, 8%, 20%, 0);
@ -290,6 +289,17 @@
--font-secondary: 'Inter', 'Roboto', sans-serif; --font-secondary: 'Inter', 'Roboto', sans-serif;
} }
.dark-theme,
.butter-theme {
@include dark-mode();
}
@media (prefers-color-scheme: dark) {
.system-theme {
@include dark-mode();
}
}
.butter-theme { .butter-theme {
/* background color | --bg-[background type]: value */ /* background color | --bg-[background type]: value */
--bg-surface: hsl(64, 6%, 14%); --bg-surface: hsl(64, 6%, 14%);