Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/use dark mode preference to set initial theme.light #861

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion extension/src/app/containers/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,12 @@ class App extends Component<Props> {
function mapStateToProps(state: StoreState) {
const instances = state.instances;
const id = getActiveInstance(instances);
const { themeColorPreference, ...themeData } = state.theme;

return {
options: instances.options[id],
section: state.section,
theme: state.theme,
theme: themeData,
notification: state.notification,
};
}
Expand Down
18 changes: 16 additions & 2 deletions extension/src/browser/extension/devpanel/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ import configureStore from '../../../app/stores/panelStore';

import '../../views/devpanel.pug';
import { Action, Store } from 'redux';
import { StoreAction } from '@redux-devtools/app/lib/actions';
import {
applyMediaFeaturesPreferences,
StoreAction,
} from '@redux-devtools/app/lib/actions';
import { PanelMessage } from '../../../app/middlewares/api';
import { StoreStateWithoutSocket } from '../../../app/reducers/panel';
import { PersistGate } from 'redux-persist/integration/react';
Expand All @@ -33,9 +36,20 @@ function renderDevTools() {
unmountComponentAtNode(node!);
clearTimeout(naTimeout);
({ store, persistor } = configureStore(position, bgConnection));

const onBeforeLift = () => {
if (store) {
store.dispatch(applyMediaFeaturesPreferences());
}
};

render(
<Provider store={store}>
<PersistGate loading={null} persistor={persistor}>
<PersistGate
loading={null}
persistor={persistor}
onBeforeLift={onBeforeLift}
>
<App position={position} />
</PersistGate>
</Provider>,
Expand Down
11 changes: 10 additions & 1 deletion extension/src/browser/extension/window/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import configureStore from '../../../app/stores/windowStore';
import { MonitorMessage } from '../../../app/middlewares/api';

import '../../views/window.pug';
import { applyMediaFeaturesPreferences } from '@redux-devtools/app/lib/actions';

const position = location.hash;

Expand All @@ -25,9 +26,17 @@ chrome.runtime.getBackgroundPage((window) => {
bg.onMessage.addListener(update);
update();

const onBeforeLift = () => {
localStore.dispatch(applyMediaFeaturesPreferences());
};

render(
<Provider store={localStore}>
<PersistGate loading={null} persistor={persistor}>
<PersistGate
loading={null}
persistor={persistor}
onBeforeLift={onBeforeLift}
>
<App position={position} />
</PersistGate>
</Provider>,
Expand Down
2 changes: 1 addition & 1 deletion packages/redux-devtools-app/jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@ module.exports = {
setupFilesAfterEnv: ['<rootDir>/test/setup.ts'],
testEnvironment: 'jsdom',
moduleNameMapper: {
'\\.css$': '<rootDir>/test/__mocks__/styleMock.ts',
'\\.css$': '<rootDir>/test/__mocks__/styleMock.js',
Copy link
Member

@Methuselah96 Methuselah96 Nov 6, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was it causing problems for this to be ts?

Copy link
Contributor Author

@FaberVitale FaberVitale Nov 6, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not recall exactly, luckily I wrote a detailed commit message.

chore(@redux-devtools/app): fix lint error

Error message:

0:0  error  Parsing error: "parserOptions.project" has been set for @typescript-eslint/parser.
The file does not match your project config: test/__mocks__/styleMock.ts.
The file must be included in at least one of the projects provided

Copy link
Member

@Methuselah96 Methuselah96 Nov 6, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice commit message! I wonder if this was fixed by #867.

},
};
47 changes: 42 additions & 5 deletions packages/redux-devtools-app/src/actions/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { AuthStates, States } from 'socketcluster-client/lib/scclientsocket';
import {
CHANGE_SECTION,
CHANGE_THEME,
APPLY_MEDIA_FEATURES_PREFERENCES,
SELECT_INSTANCE,
SELECT_MONITOR,
UPDATE_MONITOR_STATE,
Expand Down Expand Up @@ -44,9 +45,10 @@ import {
import { Action } from 'redux';
import { Features, State } from '../reducers/instances';
import { MonitorStateMonitorState } from '../reducers/monitor';
import { LiftedAction } from '@redux-devtools/core';
import { LiftedAction, LiftedState } from '@redux-devtools/core';
import { Data } from '../reducers/reports';
import { LiftedState } from '@redux-devtools/core';
import { prefersDarkColorScheme } from '../utils/media-queries';
import { ThemeColorPreference } from '../reducers/theme';

let monitorReducer: (
monitorProps: unknown,
Expand All @@ -66,19 +68,53 @@ export function changeSection(section: string): ChangeSectionAction {
interface ChangeThemeFormData {
readonly theme: Theme;
readonly scheme: Scheme;
readonly dark: boolean;
readonly themeColorPreference: ThemeColorPreference;
}
interface ChangeThemeData {
export interface ChangeThemeData {
readonly formData: ChangeThemeFormData;
}
export interface ChangeThemeAction {
readonly type: typeof CHANGE_THEME;
readonly theme: Theme;
readonly scheme: Scheme;
readonly dark: boolean;
readonly themeColorPreference: ThemeColorPreference;
}

export interface ApplyMediaFeaturesPreferencesAction {
readonly type: typeof APPLY_MEDIA_FEATURES_PREFERENCES;
readonly prefersDarkColorScheme: boolean;
}

export function changeTheme(data: ChangeThemeData): ChangeThemeAction {
return { type: CHANGE_THEME, ...data.formData };
const { themeColorPreference } = data.formData;
let dark: boolean;

switch (themeColorPreference) {
case 'light':
dark = false;
break;
case 'dark':
dark = true;
break;
default:
dark = prefersDarkColorScheme();
}

return { type: CHANGE_THEME, ...data.formData, dark };
}

/**
* @see https://developer.mozilla.org/en-US/docs/Web/CSS/Media_Queries/Using_media_queries#media_features
*/
export function applyMediaFeaturesPreferences(
payload?: Partial<Omit<ApplyMediaFeaturesPreferencesAction, 'type'>>
): ApplyMediaFeaturesPreferencesAction {
return {
prefersDarkColorScheme: prefersDarkColorScheme(),
...payload,
type: APPLY_MEDIA_FEATURES_PREFERENCES,
};
}

export interface InitMonitorAction {
Expand Down Expand Up @@ -564,6 +600,7 @@ export interface ErrorAction {
export type StoreActionWithoutUpdateStateOrLiftedAction =
| ChangeSectionAction
| ChangeThemeAction
| ApplyMediaFeaturesPreferencesAction
| MonitorActionAction
| SelectInstanceAction
| SelectMonitorAction
Expand Down
13 changes: 10 additions & 3 deletions packages/redux-devtools-app/src/components/Settings/Themes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ import { Container, Form } from '@redux-devtools/ui';
import { listSchemes, listThemes } from '@redux-devtools/ui/lib/utils/theme';
import { changeTheme } from '../../actions';
import { StoreState } from '../../reducers';
import {
defaultThemeColorPreference,
themeColorPreferences,
} from '../../reducers/theme';

type StateProps = ReturnType<typeof mapStateToProps>;
type DispatchProps = ResolveThunks<typeof actionCreators>;
Expand All @@ -15,7 +19,8 @@ export class Themes extends Component<Props> {
const formData = {
theme: theme.theme,
scheme: theme.scheme,
dark: !theme.light,
themeColorPreference:
theme.themeColorPreference ?? defaultThemeColorPreference,
};

return (
Expand All @@ -33,8 +38,10 @@ export class Themes extends Component<Props> {
type: 'string',
enum: listSchemes(),
},
dark: {
type: 'boolean',
themeColorPreference: {
title: 'theme color',
type: 'string',
enum: themeColorPreferences as unknown as string[],
},
},
}}
Expand Down
2 changes: 2 additions & 0 deletions packages/redux-devtools-app/src/constants/actionTypes.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
export const CHANGE_SECTION = 'main/CHANGE_SECTION';
export const CHANGE_THEME = 'main/CHANGE_THEME';
export const APPLY_MEDIA_FEATURES_PREFERENCES =
'main/APPLY_MEDIA_FEATURES_PREFERENCES';

export const UPDATE_STATE = 'devTools/UPDATE_STATE';
export const SET_STATE = 'devTools/SET_STATE';
Expand Down
19 changes: 17 additions & 2 deletions packages/redux-devtools-app/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import configureStore from './store/configureStore';
import { CONNECT_REQUEST } from './constants/socketActionTypes';
import App from './containers/App';
import { StoreState } from './reducers';
import { StoreAction } from './actions';
import { StoreAction, applyMediaFeaturesPreferences } from './actions';

class Root extends Component {
store?: Store<StoreState, StoreAction>;
Expand All @@ -27,11 +27,26 @@ class Root extends Component {
this.persistor = persistor;
}

/**
* @hidden
* @private
*/
private _checkMediaFeaturesPreferences = () => {
if (this.store) {
this.store.dispatch(applyMediaFeaturesPreferences());
}
};

render() {
if (!this.store) return null;

return (
<Provider store={this.store}>
<PersistGate loading={null} persistor={this.persistor!}>
<PersistGate
loading={null}
persistor={this.persistor!}
onBeforeLift={this._checkMediaFeaturesPreferences}
>
<App />
</PersistGate>
</Provider>
Expand Down
34 changes: 32 additions & 2 deletions packages/redux-devtools-app/src/reducers/theme.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,33 @@
import { Scheme, Theme } from '@redux-devtools/ui';
import { CHANGE_THEME } from '../constants/actionTypes';
import { Theme, Scheme } from '@redux-devtools/ui';
import {
CHANGE_THEME,
APPLY_MEDIA_FEATURES_PREFERENCES,
} from '../constants/actionTypes';
import { StoreAction } from '../actions';

export const defaultThemeColorPreference = 'auto';

export const themeColorPreferences = [
defaultThemeColorPreference,
'light',
'dark',
] as const;

export type ThemeColorPreference = typeof themeColorPreferences[number];

export interface ThemeState {
readonly theme: Theme;
readonly scheme: Scheme;
readonly light: boolean;
readonly themeColorPreference?: ThemeColorPreference;
}

export default function theme(
state: ThemeState = {
theme: 'default' as const,
scheme: 'default' as const,
light: true,
themeColorPreference: defaultThemeColorPreference,
},
action: StoreAction
) {
Expand All @@ -21,7 +36,22 @@ export default function theme(
theme: action.theme,
scheme: action.scheme,
light: !action.dark,
themeColorPreference: action.themeColorPreference,
};
}

if (
action.type === APPLY_MEDIA_FEATURES_PREFERENCES &&
(!state.themeColorPreference ||
state.themeColorPreference === defaultThemeColorPreference)
) {
return {
...state,
themeColorPreference:
state.themeColorPreference ?? defaultThemeColorPreference,
light: !action.prefersDarkColorScheme,
};
}

return state;
}
13 changes: 13 additions & 0 deletions packages/redux-devtools-app/src/utils/media-queries.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/**
* @see https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme
*/
export function prefersDarkColorScheme(): boolean {
if (
typeof window !== 'undefined' &&
typeof window.matchMedia === 'function'
) {
return window.matchMedia('(prefers-color-scheme: dark)').matches;
}

return false;
}
1 change: 1 addition & 0 deletions packages/redux-devtools-app/test/__mocks__/styleMock.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = {};
1 change: 0 additions & 1 deletion packages/redux-devtools-app/test/__mocks__/styleMock.ts

This file was deleted.