Merge branch 'site-logo' into 'develop'

Replace logos with SiteLogo component, fixes #937

Closes #937

See merge request soapbox-pub/soapbox-fe!1356
This commit is contained in:
Alex Gleason 2022-05-12 19:22:46 +00:00
commit 80f5c75a1a
14 changed files with 86 additions and 124 deletions

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 95 95" width="100" height="100"><path d="M94.909 19.374C94.909 8.674 86.235 0 75.534 0c-10.647 0-19.28 8.591-19.365 19.217l-15.631 2.09c-1.961-6.007-7.598-10.35-14.258-10.35-8.284 0-15.002 6.716-15.002 15.002 0 6.642 4.321 12.267 10.303 14.24l-2.205 16.056c-10.66.049-19.285 8.7-19.285 19.37C.091 86.325 8.765 95 19.466 95c10.677 0 19.332-8.638 19.37-19.304l18.093-2.501c1.979 5.972 7.598 10.285 14.234 10.285 8.284 0 15.002-6.716 15.002-15.002 0-6.891-4.652-12.682-10.983-14.441l1.365-15.339c10.229-.53 18.363-8.966 18.363-19.324zM56.194 67.8l-18.116 2.505a19.39 19.39 0 0 0-13.312-13.3l2.205-16.077a14.98 14.98 0 0 0 14.27-14.222l15.655-2.094c1.894 6.757 7.351 12.009 14.225 13.612l-1.365 15.322c-7.4.688-13.224 6.753-13.562 14.254z" fill="#ffffff"/></svg>

After

Width:  |  Height:  |  Size: 812 B

View file

@ -9,9 +9,10 @@ import { fetchOwnAccounts } from 'soapbox/actions/auth';
import { getSettings } from 'soapbox/actions/settings';
import { closeSidebar } from 'soapbox/actions/sidebar';
import Account from 'soapbox/components/account';
import SiteLogo from 'soapbox/components/site-logo';
import { Stack } from 'soapbox/components/ui';
import ProfileStats from 'soapbox/features/ui/components/profile_stats';
import { useAppSelector, useSoapboxConfig, useFeatures } from 'soapbox/hooks';
import { useAppSelector, useFeatures } from 'soapbox/hooks';
import { makeGetAccount, makeGetOtherAccounts } from 'soapbox/selectors';
import { getBaseURL } from 'soapbox/utils/accounts';
@ -66,7 +67,6 @@ const SidebarMenu: React.FC = (): JSX.Element | null => {
const intl = useIntl();
const dispatch = useDispatch();
const { logo } = useSoapboxConfig();
const features = useFeatures();
const getAccount = makeGetAccount();
const instance = useAppSelector((state) => state.instance);
@ -141,15 +141,7 @@ const SidebarMenu: React.FC = (): JSX.Element | null => {
<Stack space={4}>
<HStack alignItems='center' justifyContent='between'>
<Link to='/' onClick={onClose}>
{logo ? (
<img alt='Logo' src={logo} className='h-5 w-auto cursor-pointer' />
) : (
<Icon
alt='Logo'
src={require('@tabler/icons/icons/home.svg')}
className='h-6 w-6 text-gray-400 hover:text-gray-600 dark:text-gray-200 cursor-pointer'
/>
)}
<SiteLogo alt='Logo' className='h-5 w-auto cursor-pointer' />
</Link>
<IconButton

View file

@ -0,0 +1,35 @@
import React from 'react';
import { useSoapboxConfig, useSettings, useSystemTheme } from 'soapbox/hooks';
/** Display the most appropriate site logo based on the theme and configuration. */
const SiteLogo: React.FC<React.ComponentProps<'img'>> = (props) => {
const { logo, logoDarkMode } = useSoapboxConfig();
const settings = useSettings();
const systemTheme = useSystemTheme();
const userTheme = settings.get('themeMode');
const darkMode = userTheme === 'dark' || (userTheme === 'system' && systemTheme === 'dark');
/** Soapbox logo. */
const soapboxLogo = darkMode
? require('images/soapbox-logo-white.svg')
: require('images/soapbox-logo.svg');
// Use the right logo if provided, then use fallbacks.
const getSrc = () => {
// In demo mode, use the Soapbox logo.
if (settings.get('demo')) return soapboxLogo;
return (darkMode && logoDarkMode)
? logoDarkMode
: logo || logoDarkMode || soapboxLogo;
};
return (
// eslint-disable-next-line jsx-a11y/alt-text
<img src={getSrc()} {...props} />
);
};
export default SiteLogo;

View file

@ -20,7 +20,7 @@ import PublicLayout from 'soapbox/features/public_layout';
import NotificationsContainer from 'soapbox/features/ui/containers/notifications_container';
import WaitlistPage from 'soapbox/features/verification/waitlist_page';
import { createGlobals } from 'soapbox/globals';
import { useAppSelector, useAppDispatch, useOwnAccount, useFeatures, useSoapboxConfig, useSettings } from 'soapbox/hooks';
import { useAppSelector, useAppDispatch, useOwnAccount, useFeatures, useSoapboxConfig, useSettings, useSystemTheme } from 'soapbox/hooks';
import MESSAGES from 'soapbox/locales/messages';
import { generateThemeCss } from 'soapbox/utils/theme';
@ -82,17 +82,12 @@ const SoapboxMount = () => {
const [localeLoading, setLocaleLoading] = useState(true);
const [isLoaded, setIsLoaded] = useState(false);
const colorSchemeQueryList = window.matchMedia('(prefers-color-scheme: dark)');
const [isSystemDarkMode, setSystemDarkMode] = useState(colorSchemeQueryList.matches);
const systemTheme = useSystemTheme();
const userTheme = settings.get('themeMode');
const darkMode = userTheme === 'dark' || (userTheme === 'system' && isSystemDarkMode);
const darkMode = userTheme === 'dark' || (userTheme === 'system' && systemTheme === 'dark');
const themeCss = generateThemeCss(soapboxConfig);
const handleSystemModeChange = (event: MediaQueryListEvent) => {
setSystemDarkMode(event.matches);
};
// Load the user's locale
useEffect(() => {
MESSAGES[locale]().then(messages => {
@ -110,12 +105,6 @@ const SoapboxMount = () => {
});
}, []);
useEffect(() => {
colorSchemeQueryList.addEventListener('change', handleSystemModeChange);
return () => colorSchemeQueryList.removeEventListener('change', handleSystemModeChange);
}, []);
// @ts-ignore: I don't actually know what these should be, lol
const shouldUpdateScroll = (prevRouterProps, { location }) => {
return !(location.state?.soapboxModalKey && location.state?.soapboxModalKey !== prevRouterProps?.location?.state?.soapboxModalKey);

View file

@ -2,10 +2,10 @@ import React from 'react';
import { Link, Redirect, Route, Switch } from 'react-router-dom';
import LandingGradient from 'soapbox/components/landing-gradient';
import SvgIcon from 'soapbox/components/ui/icon/svg-icon';
import SiteLogo from 'soapbox/components/site-logo';
import BundleContainer from 'soapbox/features/ui/containers/bundle_container';
import { NotificationsContainer } from 'soapbox/features/ui/util/async-components';
import { useAppSelector, useSoapboxConfig } from 'soapbox/hooks';
import { useAppSelector } from 'soapbox/hooks';
import { Card, CardBody } from '../../components/ui';
import LoginPage from '../auth_login/components/login_page';
@ -18,7 +18,6 @@ import Verification from '../verification';
import EmailPassthru from '../verification/email_passthru';
const AuthLayout = () => {
const { logo } = useSoapboxConfig();
const siteTitle = useAppSelector(state => state.instance.title);
return (
@ -29,15 +28,7 @@ const AuthLayout = () => {
<div className='w-full sm:max-w-lg md:max-w-2xl space-y-8'>
<header className='flex justify-center relative'>
<Link to='/' className='cursor-pointer'>
{logo ? (
<img src={logo} alt={siteTitle} className='h-7' />
) : (
<SvgIcon
className='w-7 h-7 dark:text-white'
alt={siteTitle}
src={require('@tabler/icons/icons/home.svg')}
/>
)}
<SiteLogo alt={siteTitle} className='h-7' />
</Link>
</header>

View file

@ -1,4 +1,3 @@
import classNames from 'classnames';
import React from 'react';
import { defineMessages, useIntl } from 'react-intl';
import { useDispatch } from 'react-redux';
@ -6,6 +5,7 @@ import { Link, Redirect } from 'react-router-dom';
import { logIn, verifyCredentials } from 'soapbox/actions/auth';
import { fetchInstance } from 'soapbox/actions/instance';
import SiteLogo from 'soapbox/components/site-logo';
import { useAppSelector, useFeatures, useSoapboxConfig } from 'soapbox/hooks';
import { openModal } from '../../../actions/modals';
@ -31,7 +31,6 @@ const Header = () => {
const soapboxConfig = useSoapboxConfig();
const pepeEnabled = soapboxConfig.getIn(['extensions', 'pepe', 'enabled']) === true;
const { logo, logoDarkMode } = soapboxConfig;
const features = useFeatures();
const instance = useAppSelector((state) => state.instance);
const isOpen = features.accountCreation && instance.registrations;
@ -80,11 +79,7 @@ const Header = () => {
<Sonar />
</div>
<Link to='/' className='z-10'>
<img alt='Logo' src={logo} className={classNames('h-6 w-auto cursor-pointer', { 'dark:hidden': logoDarkMode })} />
{logoDarkMode && (
<img alt='Logo' src={logoDarkMode} className='h-6 w-auto cursor-pointer hidden dark:block' />
)}
<SiteLogo alt='Logo' className='h-6 w-auto cursor-pointer' />
<span className='hidden'>{intl.formatMessage(messages.home)}</span>
</Link>
</div>

View file

@ -1,25 +0,0 @@
import React from 'react';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { connect } from 'react-redux';
import { getSoapboxConfig } from 'soapbox/actions/soapbox';
const mapStateToProps = (state, props) => ({
instance: state.get('instance'),
soapbox: getSoapboxConfig(state),
});
class SiteBanner extends ImmutablePureComponent {
render() {
const { instance, soapbox } = this.props;
const logos = {
imgLogo: (<img alt={instance.get('title')} src={soapbox.get('banner')} />),
textLogo: (<h1>{instance.get('title')}</h1>),
};
return soapbox.getIn(['banner']) ? logos.imgLogo : logos.textLogo;
}
}
export default connect(mapStateToProps)(SiteBanner);

View file

@ -1,25 +0,0 @@
import React from 'react';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { connect } from 'react-redux';
import { getSoapboxConfig } from 'soapbox/actions/soapbox';
const mapStateToProps = (state, props) => ({
instance: state.get('instance'),
soapbox: getSoapboxConfig(state),
});
class SiteLogo extends ImmutablePureComponent {
render() {
const { instance, soapbox } = this.props;
const logos = {
imgLogo: (<img alt={instance.get('title')} src={soapbox.get('logo')} />),
textLogo: (<h1>{instance.get('title')}</h1>),
};
return soapbox.getIn(['logo']) ? logos.imgLogo : logos.textLogo;
}
}
export default connect(mapStateToProps)(SiteLogo);

View file

@ -4,6 +4,7 @@ import { FormattedMessage } from 'react-intl';
import { defaultSettings } from 'soapbox/actions/settings';
import BackgroundShapes from 'soapbox/features/ui/components/background_shapes';
import { useSystemTheme } from 'soapbox/hooks';
import { normalizeSoapboxConfig } from 'soapbox/normalizers';
import { generateThemeCss } from 'soapbox/utils/theme';
@ -17,7 +18,10 @@ const SitePreview: React.FC<ISitePreview> = ({ soapbox }) => {
const soapboxConfig = useMemo(() => normalizeSoapboxConfig(soapbox), [soapbox]);
const settings = defaultSettings.mergeDeep(soapboxConfig.defaultSettings);
const dark = settings.get('themeMode') === 'dark';
const userTheme = settings.get('themeMode');
const systemTheme = useSystemTheme();
const dark = userTheme === 'dark' || (userTheme === 'system' && systemTheme === 'dark');
const bodyClass = classNames(
'site-preview',

View file

@ -2,6 +2,7 @@ import classNames from 'classnames';
import React from 'react';
import { defineMessages, useIntl } from 'react-intl';
import SiteLogo from 'soapbox/components/site-logo';
import { Button } from 'soapbox/components/ui';
import { Modal } from 'soapbox/components/ui';
import { useAppSelector, useFeatures, useSoapboxConfig } from 'soapbox/hooks';
@ -23,7 +24,6 @@ const LandingPageModal: React.FC<ILandingPageModal> = ({ onClose }) => {
const soapboxConfig = useSoapboxConfig();
const pepeEnabled = soapboxConfig.getIn(['extensions', 'pepe', 'enabled']) === true;
const { logo } = soapboxConfig;
const instance = useAppSelector((state) => state.instance);
const features = useFeatures();
@ -32,7 +32,7 @@ const LandingPageModal: React.FC<ILandingPageModal> = ({ onClose }) => {
return (
<Modal
title={<img alt='Logo' src={logo} className='h-4 w-auto' />}
title={<SiteLogo alt='Logo' className='h-4 w-auto' />}
onClose={() => onClose('LANDING_PAGE')}
>
<div className='mt-4 divide-y divide-solid divide-gray-200 dark:divide-slate-700'>

View file

@ -4,9 +4,10 @@ import { FormattedMessage } from 'react-intl';
import { useDispatch } from 'react-redux';
import { Link } from 'react-router-dom';
import { Avatar, Button, Icon } from 'soapbox/components/ui';
import SiteLogo from 'soapbox/components/site-logo';
import { Avatar, Button } from 'soapbox/components/ui';
import Search from 'soapbox/features/compose/components/search';
import { useOwnAccount, useSoapboxConfig, useSettings } from 'soapbox/hooks';
import { useOwnAccount, useSoapboxConfig } from 'soapbox/hooks';
import { openSidebar } from '../../../actions/sidebar';
@ -17,14 +18,9 @@ const Navbar = () => {
const node = React.useRef(null);
const account = useOwnAccount();
const settings = useSettings();
const soapboxConfig = useSoapboxConfig();
const singleUserMode = soapboxConfig.get('singleUserMode');
// In demo mode, use the Soapbox logo
const logo = settings.get('demo') ? require('images/soapbox-logo.svg') : soapboxConfig.logo;
const logoDarkMode = soapboxConfig.logoDarkMode;
const onOpenSidebar = () => dispatch(openSidebar());
return (
@ -46,21 +42,10 @@ const Navbar = () => {
'justify-start': !account,
})}
>
{logo ? (
<Link key='logo' to='/' data-preview-title-id='column.home' className='flex-shrink-0 flex items-center'>
<img alt='Logo' src={logo} className={classNames('h-5 lg:h-6 w-auto cursor-pointer', { 'dark:hidden': logoDarkMode })} />
{logoDarkMode && (
<img alt='Logo' src={logoDarkMode} className='h-5 lg:h-6 w-auto cursor-pointer hidden dark:block' />
)}
<span className='hidden'><FormattedMessage id='tabs_bar.home' defaultMessage='Home' /></span>
</Link>
) : (
<Link key='logo' to='/' data-preview-title-id='column.home' className='flex-shrink-0 flex items-center'>
<Icon alt='Logo' src={require('@tabler/icons/icons/home.svg')} className='h-5 lg:h-6 w-auto text-primary-700' />
<span className='hidden'><FormattedMessage id='tabs_bar.home' defaultMessage='Home' /></span>
</Link>
)}
<Link key='logo' to='/' data-preview-title-id='column.home' className='flex-shrink-0 flex items-center'>
<SiteLogo alt='Logo' className='h-5 lg:h-6 w-auto cursor-pointer' />
<span className='hidden'><FormattedMessage id='tabs_bar.home' defaultMessage='Home' /></span>
</Link>
{account && (
<div className='flex-1 hidden lg:flex justify-center px-2 lg:ml-6 lg:justify-start items-center'>

View file

@ -1,11 +1,11 @@
import PropTypes from 'prop-types';
import React from 'react';
import { useIntl } from 'react-intl';
import { useDispatch, useSelector } from 'react-redux';
import { useDispatch } from 'react-redux';
import { Link } from 'react-router-dom';
import { getSoapboxConfig } from 'soapbox/actions/soapbox';
import LandingGradient from 'soapbox/components/landing-gradient';
import SiteLogo from 'soapbox/components/site-logo';
import BundleContainer from 'soapbox/features/ui/containers/bundle_container';
import { NotificationsContainer } from 'soapbox/features/ui/util/async-components';
@ -16,8 +16,6 @@ const WaitlistPage = ({ account }) => {
const dispatch = useDispatch();
const intl = useIntl();
const logo = useSelector((state) => getSoapboxConfig(state).get('logo'));
const onClickLogOut = (event) => {
event.preventDefault();
dispatch(logOut(intl));
@ -31,7 +29,7 @@ const WaitlistPage = ({ account }) => {
<header className='relative flex justify-between h-16'>
<div className='flex-1 flex items-stretch justify-center relative'>
<Link to='/' className='cursor-pointer flex-shrink-0 flex items-center'>
<img alt='Logo' src={logo} className='h-7' />
<SiteLogo alt='Logo' className='h-7' />
</Link>
<div className='absolute inset-y-0 right-0 flex items-center pr-2 space-x-3'>

View file

@ -6,3 +6,4 @@ export { useOnScreen } from './useOnScreen';
export { useOwnAccount } from './useOwnAccount';
export { useSettings } from './useSettings';
export { useSoapboxConfig } from './useSoapboxConfig';
export { useSystemTheme } from './useSystemTheme';

View file

@ -0,0 +1,21 @@
import { useState, useEffect } from 'react';
type SystemTheme = 'light' | 'dark';
/** Get the system color scheme of the system. */
export const useSystemTheme = (): SystemTheme => {
const query = window.matchMedia('(prefers-color-scheme: dark)');
const [dark, setDark] = useState(query.matches);
const handleChange = (event: MediaQueryListEvent) => {
setDark(event.matches);
};
useEffect(() => {
query.addEventListener('change', handleChange);
return () => query.removeEventListener('change', handleChange);
}, []);
return dark ? 'dark' : 'light';
};