diff --git a/app/soapbox/features/soapbox_config/index.js b/app/soapbox/features/soapbox_config/index.js
index 8c5a8816c..44317a1b7 100644
--- a/app/soapbox/features/soapbox_config/index.js
+++ b/app/soapbox/features/soapbox_config/index.js
@@ -23,7 +23,7 @@ import {
FileChooserLogo,
Checkbox,
} from 'soapbox/features/forms';
-import ThemeToggle from 'soapbox/features/ui/components/theme_toggle';
+import ThemeToggle from 'soapbox/features/ui/components/theme-toggle';
import { isMobile } from 'soapbox/is_mobile';
import { normalizeSoapboxConfig } from 'soapbox/normalizers';
diff --git a/app/soapbox/features/ui/components/navbar.tsx b/app/soapbox/features/ui/components/navbar.tsx
index 5a075eead..c6d810f0c 100644
--- a/app/soapbox/features/ui/components/navbar.tsx
+++ b/app/soapbox/features/ui/components/navbar.tsx
@@ -6,8 +6,7 @@ import { Link } from 'react-router-dom';
import { Avatar, Button, Icon } from 'soapbox/components/ui';
import Search from 'soapbox/features/compose/components/search';
-import ThemeToggle from 'soapbox/features/ui/components/theme_toggle';
-import { useOwnAccount, useSoapboxConfig, useSettings, useFeatures } from 'soapbox/hooks';
+import { useOwnAccount, useSoapboxConfig, useSettings } from 'soapbox/hooks';
import { openSidebar } from '../../../actions/sidebar';
@@ -19,7 +18,6 @@ const Navbar = () => {
const account = useOwnAccount();
const settings = useSettings();
- const features = useFeatures();
const soapboxConfig = useSoapboxConfig();
const singleUserMode = soapboxConfig.get('singleUserMode');
@@ -69,11 +67,6 @@ const Navbar = () => {
- {/* TODO: make this available for everyone when it's ready (possibly in a different place) */}
- {(features.darkMode || settings.get('isDeveloper')) && (
-
- )}
-
{account ? (
diff --git a/app/soapbox/features/ui/components/profile-dropdown.tsx b/app/soapbox/features/ui/components/profile-dropdown.tsx
index 034a6d099..7253b7ba6 100644
--- a/app/soapbox/features/ui/components/profile-dropdown.tsx
+++ b/app/soapbox/features/ui/components/profile-dropdown.tsx
@@ -7,11 +7,13 @@ import { Link } from 'react-router-dom';
import { logOut, switchAccount } from 'soapbox/actions/auth';
import { fetchOwnAccounts } from 'soapbox/actions/auth';
import { Menu, MenuButton, MenuDivider, MenuItem, MenuLink, MenuList } from 'soapbox/components/ui';
-import { useAppSelector } from 'soapbox/hooks';
+import { useAppSelector, useFeatures, useSettings } from 'soapbox/hooks';
import { makeGetAccount } from 'soapbox/selectors';
import Account from '../../../components/account';
+import ThemeToggle from './theme-toggle';
+
import type { Account as AccountEntity } from 'soapbox/types/entities';
const messages = defineMessages({
@@ -24,9 +26,10 @@ interface IProfileDropdown {
}
type IMenuItem = {
- text: string | React.ReactElement | null,
- to?: string,
- icon?: string,
+ text: string | React.ReactElement | null
+ to?: string
+ toggle?: JSX.Element
+ icon?: string
action?: (event: React.MouseEvent) => void
}
@@ -34,6 +37,8 @@ const getAccount = makeGetAccount();
const ProfileDropdown: React.FC = ({ account, children }) => {
const dispatch = useDispatch();
+ const features = useFeatures();
+ const settings = useSettings();
const intl = useIntl();
const authUsers = useAppSelector((state) => state.auth.get('users'));
@@ -73,6 +78,12 @@ const ProfileDropdown: React.FC = ({ account, children }) => {
}
});
+ if (features.darkMode || settings.get('isDeveloper')) {
+ menu.push({ text: null });
+
+ menu.push({ text: 'Theme', toggle: });
+ }
+
menu.push({ text: null });
menu.push({
@@ -89,7 +100,7 @@ const ProfileDropdown: React.FC = ({ account, children }) => {
});
return menu;
- }, [account, authUsers]);
+ }, [account, authUsers, features]);
React.useEffect(() => {
fetchOwnAccountThrottled();
@@ -103,7 +114,15 @@ const ProfileDropdown: React.FC = ({ account, children }) => {
{menu.map((menuItem, idx) => {
- if (!menuItem.text) {
+ if (menuItem.toggle) {
+ return (
+
+ {menuItem.text}
+
+ {menuItem.toggle}
+
+ );
+ } else if (!menuItem.text) {
return ;
} else {
const Comp: any = menuItem.action ? MenuItem : MenuLink;
diff --git a/app/soapbox/features/ui/components/theme-toggle.tsx b/app/soapbox/features/ui/components/theme-toggle.tsx
new file mode 100644
index 000000000..60fc2bbf3
--- /dev/null
+++ b/app/soapbox/features/ui/components/theme-toggle.tsx
@@ -0,0 +1,67 @@
+import React, { useMemo } from 'react';
+import { defineMessages, useIntl } from 'react-intl';
+import { useDispatch } from 'react-redux';
+
+import { changeSetting } from 'soapbox/actions/settings';
+import { Icon } from 'soapbox/components/ui';
+import { useSettings } from 'soapbox/hooks';
+
+const messages = defineMessages({
+ switchToLight: { id: 'tabs_bar.theme_toggle_light', defaultMessage: 'Switch to light theme' },
+ switchToDark: { id: 'tabs_bar.theme_toggle_dark', defaultMessage: 'Switch to dark theme' },
+});
+
+interface IThemeToggle {
+ showLabel?: boolean,
+}
+
+const ThemeToggle = ({ showLabel }: IThemeToggle) => {
+ const intl = useIntl();
+ const dispatch = useDispatch();
+ const themeMode = useSettings().get('themeMode');
+
+ const label = intl.formatMessage(themeMode === 'light' ? messages.switchToDark : messages.switchToLight);
+
+ const onToggle = (event: React.ChangeEvent) => {
+ dispatch(changeSetting(['themeMode'], event.target.value));
+ };
+
+ const themeIconSrc = useMemo(() => {
+ switch (themeMode) {
+ case 'system':
+ return require('@tabler/icons/icons/device-desktop.svg');
+ case 'light':
+ return require('@tabler/icons/icons/sun.svg');
+ case 'dark':
+ return require('@tabler/icons/icons/moon.svg');
+ default:
+ return null;
+ }
+ }, [themeMode]);
+
+ return (
+
+
+
+
+
+
+
+ System
+ Light
+ Dark
+
+
+
+
+
+
+
+ );
+};
+
+export default ThemeToggle;
diff --git a/app/soapbox/features/ui/components/theme_toggle.tsx b/app/soapbox/features/ui/components/theme_toggle.tsx
deleted file mode 100644
index e8c63c60f..000000000
--- a/app/soapbox/features/ui/components/theme_toggle.tsx
+++ /dev/null
@@ -1,51 +0,0 @@
-import React from 'react';
-import { defineMessages, useIntl } from 'react-intl';
-import { useDispatch } from 'react-redux';
-import Toggle from 'react-toggle';
-import { v4 as uuidv4 } from 'uuid';
-
-import { changeSetting } from 'soapbox/actions/settings';
-import { Icon } from 'soapbox/components/ui';
-import { useSettings } from 'soapbox/hooks';
-
-const messages = defineMessages({
- switchToLight: { id: 'tabs_bar.theme_toggle_light', defaultMessage: 'Switch to light theme' },
- switchToDark: { id: 'tabs_bar.theme_toggle_dark', defaultMessage: 'Switch to dark theme' },
-});
-
-interface IThemeToggle {
- showLabel?: boolean,
-}
-
-function ThemeToggle({ showLabel }: IThemeToggle) {
- const intl = useIntl();
- const dispatch = useDispatch();
- const themeMode = useSettings().get('themeMode');
-
- const id = uuidv4();
- const label = intl.formatMessage(themeMode === 'light' ? messages.switchToDark : messages.switchToLight);
-
- const onToggle = () => {
- const setting = themeMode === 'light' ? 'dark' : 'light';
- dispatch(changeSetting(['themeMode'], setting));
- };
-
- return (
-
-
- ,
- unchecked: ,
- }}
- onChange={onToggle}
- />
- {showLabel && ({label} )}
-
-
- );
-}
-
-export default ThemeToggle;