diff --git a/extension/src/browser/extension/devpanel/index.tsx b/extension/src/browser/extension/devpanel/index.tsx
index 658612b6..80ea8249 100644
--- a/extension/src/browser/extension/devpanel/index.tsx
+++ b/extension/src/browser/extension/devpanel/index.tsx
@@ -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';
@@ -33,9 +36,20 @@ function renderDevTools() {
unmountComponentAtNode(node!);
clearTimeout(naTimeout);
({ store, persistor } = configureStore(position, bgConnection));
+
+ const onBeforeLift = () => {
+ if (store) {
+ store.dispatch(applyMediaFeaturesPreferences());
+ }
+ };
+
render(
-
+
,
diff --git a/extension/src/browser/extension/window/index.tsx b/extension/src/browser/extension/window/index.tsx
index a49aa01a..bc527588 100644
--- a/extension/src/browser/extension/window/index.tsx
+++ b/extension/src/browser/extension/window/index.tsx
@@ -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;
@@ -25,9 +26,17 @@ chrome.runtime.getBackgroundPage((window) => {
bg.onMessage.addListener(update);
update();
+ const onBeforeLift = () => {
+ localStore.dispatch(applyMediaFeaturesPreferences());
+ };
+
render(
-
+
,
diff --git a/packages/redux-devtools-app/src/actions/index.ts b/packages/redux-devtools-app/src/actions/index.ts
index c66cb0fb..663f132e 100644
--- a/packages/redux-devtools-app/src/actions/index.ts
+++ b/packages/redux-devtools-app/src/actions/index.ts
@@ -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,
@@ -44,9 +45,9 @@ 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';
let monitorReducer: (
monitorProps: unknown,
@@ -77,10 +78,29 @@ export interface ChangeThemeAction {
readonly scheme: Scheme;
readonly dark: boolean;
}
+
+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 };
}
+/**
+ * @see https://developer.mozilla.org/en-US/docs/Web/CSS/Media_Queries/Using_media_queries#media_features
+ */
+export function applyMediaFeaturesPreferences(
+ payload?: Partial>
+): ApplyMediaFeaturesPreferencesAction {
+ return {
+ prefersDarkColorScheme: prefersDarkColorScheme(),
+ ...payload,
+ type: APPLY_MEDIA_FEATURES_PREFERENCES,
+ };
+}
+
export interface InitMonitorAction {
type: '@@INIT_MONITOR';
newMonitorState: unknown;
@@ -564,6 +584,7 @@ export interface ErrorAction {
export type StoreActionWithoutUpdateStateOrLiftedAction =
| ChangeSectionAction
| ChangeThemeAction
+ | ApplyMediaFeaturesPreferencesAction
| MonitorActionAction
| SelectInstanceAction
| SelectMonitorAction
diff --git a/packages/redux-devtools-app/src/constants/actionTypes.ts b/packages/redux-devtools-app/src/constants/actionTypes.ts
index 98b1aa38..fa9e0ee7 100644
--- a/packages/redux-devtools-app/src/constants/actionTypes.ts
+++ b/packages/redux-devtools-app/src/constants/actionTypes.ts
@@ -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';
diff --git a/packages/redux-devtools-app/src/index.tsx b/packages/redux-devtools-app/src/index.tsx
index abb0fc56..6d2d8b81 100644
--- a/packages/redux-devtools-app/src/index.tsx
+++ b/packages/redux-devtools-app/src/index.tsx
@@ -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;
@@ -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 (
-
+
diff --git a/packages/redux-devtools-app/src/reducers/theme.ts b/packages/redux-devtools-app/src/reducers/theme.ts
index 293e9992..55d6d405 100644
--- a/packages/redux-devtools-app/src/reducers/theme.ts
+++ b/packages/redux-devtools-app/src/reducers/theme.ts
@@ -1,11 +1,12 @@
import { Scheme, Theme } from '@redux-devtools/ui';
-import { CHANGE_THEME } from '../constants/actionTypes';
+import { CHANGE_THEME, APPLY_MEDIA_FEATURES_PREFERENCES, } from '../constants/actionTypes';
import { StoreAction } from '../actions';
export interface ThemeState {
readonly theme: Theme;
readonly scheme: Scheme;
readonly light: boolean;
+ readonly latestChangeBy?: string;
}
export default function theme(
@@ -21,7 +22,20 @@ export default function theme(
theme: action.theme,
scheme: action.scheme,
light: !action.dark,
+ latestChangeBy: CHANGE_THEME,
};
}
+
+ if (
+ action.type === APPLY_MEDIA_FEATURES_PREFERENCES &&
+ state.latestChangeBy !== CHANGE_THEME
+ ) {
+ return {
+ ...state,
+ light: !action.prefersDarkColorScheme,
+ latestChangeBy: APPLY_MEDIA_FEATURES_PREFERENCES,
+ };
+ }
+
return state;
}
diff --git a/packages/redux-devtools-app/src/utils/media-queries.ts b/packages/redux-devtools-app/src/utils/media-queries.ts
new file mode 100644
index 00000000..a965492c
--- /dev/null
+++ b/packages/redux-devtools-app/src/utils/media-queries.ts
@@ -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;
+}