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 ( + + ); +}; + +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 && ()} -
-
- ); -} - -export default ThemeToggle;