From e3db81d652f93ac3a0fec4142e5fb83c581ba4ce Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Fri, 22 Jul 2022 17:01:26 -0500 Subject: [PATCH 01/11] SoapboxMount: break SoapboxLoad into a separate component --- app/soapbox/containers/soapbox.tsx | 145 ++++++++++++++++------------- app/soapbox/hooks/index.ts | 1 + app/soapbox/hooks/useLocale.ts | 16 ++++ 3 files changed, 98 insertions(+), 64 deletions(-) create mode 100644 app/soapbox/hooks/useLocale.ts diff --git a/app/soapbox/containers/soapbox.tsx b/app/soapbox/containers/soapbox.tsx index 29cfd74fb..26bd02488 100644 --- a/app/soapbox/containers/soapbox.tsx +++ b/app/soapbox/containers/soapbox.tsx @@ -25,7 +25,16 @@ import { WaitlistPage, } from 'soapbox/features/ui/util/async-components'; import { createGlobals } from 'soapbox/globals'; -import { useAppSelector, useAppDispatch, useOwnAccount, useFeatures, useSoapboxConfig, useSettings, useSystemTheme } from 'soapbox/hooks'; +import { + useAppSelector, + useAppDispatch, + useOwnAccount, + useFeatures, + useSoapboxConfig, + useSettings, + useSystemTheme, + useLocale, +} from 'soapbox/hooks'; import MESSAGES from 'soapbox/locales/messages'; import { useCachedLocationHandler } from 'soapbox/utils/redirect'; import { generateThemeCss } from 'soapbox/utils/theme'; @@ -36,9 +45,6 @@ import ErrorBoundary from '../components/error_boundary'; import UI from '../features/ui'; import { store } from '../store'; -/** Ensure the given locale exists in our codebase */ -const validLocale = (locale: string): boolean => Object.keys(MESSAGES).includes(locale); - // Configure global functions for developers createGlobals(store); @@ -72,27 +78,19 @@ const loadInitial = () => { /** Highest level node with the Redux store. */ const SoapboxMount = () => { useCachedLocationHandler(); - const dispatch = useAppDispatch(); - const me = useAppSelector(state => state.me); const instance = useAppSelector(state => state.instance); const account = useOwnAccount(); const settings = useSettings(); const soapboxConfig = useSoapboxConfig(); const features = useFeatures(); - const swUpdating = useAppSelector(state => state.meta.swUpdating); - - const locale = validLocale(settings.get('locale')) ? settings.get('locale') : 'en'; + const locale = useLocale(); const waitlisted = account && !account.source.get('approved', true); const needsOnboarding = useAppSelector(state => state.onboarding.needsOnboarding); const showOnboarding = account && !waitlisted && needsOnboarding; const singleUserMode = soapboxConfig.singleUserMode && soapboxConfig.singleUserModeProfile; - const [messages, setMessages] = useState>({}); - const [localeLoading, setLocaleLoading] = useState(true); - const [isLoaded, setIsLoaded] = useState(false); - const systemTheme = useSystemTheme(); const userTheme = settings.get('themeMode'); const darkMode = userTheme === 'dark' || (userTheme === 'system' && systemTheme === 'dark'); @@ -100,37 +98,11 @@ const SoapboxMount = () => { const themeCss = generateThemeCss(soapboxConfig); - // Load the user's locale - useEffect(() => { - MESSAGES[locale]().then(messages => { - setMessages(messages); - setLocaleLoading(false); - }).catch(() => { }); - }, [locale]); - - // Load initial data from the API - useEffect(() => { - dispatch(loadInitial()).then(() => { - setIsLoaded(true); - }).catch(() => { - setIsLoaded(true); - }); - }, []); - // @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); }; - /** Whether to display a loading indicator. */ - const showLoading = [ - me === null, - me && !account, - !isLoaded, - localeLoading, - swUpdating, - ].some(Boolean); - const bodyClass = classNames('bg-white dark:bg-slate-900 text-base h-full', { 'no-reduce-motion': !settings.get('reduceMotion'), 'underline-links': settings.get('underlineLinks'), @@ -214,37 +186,80 @@ const SoapboxMount = () => { } }; + return ( + + + + <> + {helmet} + {renderBody()} + + + {(Component) => } + + + + {Component => } + + + + + + ); +}; + +interface ISoapboxLoad { + children: React.ReactNode, +} + +/** Initial data loader. */ +const SoapboxLoad: React.FC = ({ children }) => { + const dispatch = useAppDispatch(); + + const me = useAppSelector(state => state.me); + const account = useOwnAccount(); + const swUpdating = useAppSelector(state => state.meta.swUpdating); + const locale = useLocale(); + + const [messages, setMessages] = useState>({}); + const [localeLoading, setLocaleLoading] = useState(true); + const [isLoaded, setIsLoaded] = useState(false); + + /** Whether to display a loading indicator. */ + const showLoading = [ + me === null, + me && !account, + !isLoaded, + localeLoading, + swUpdating, + ].some(Boolean); + + // Load the user's locale + useEffect(() => { + MESSAGES[locale]().then(messages => { + setMessages(messages); + setLocaleLoading(false); + }).catch(() => { }); + }, [locale]); + + // Load initial data from the API + useEffect(() => { + dispatch(loadInitial()).then(() => { + setIsLoaded(true); + }).catch(() => { + setIsLoaded(true); + }); + }, []); + // intl is part of loading. // It's important nothing in here depends on intl. if (showLoading) { - return ( - <> - {helmet} - - - ); + return ; } return ( - {helmet} - - - - <> - {renderBody()} - - - {(Component) => } - - - - {Component => } - - - - - + {children} ); }; @@ -253,7 +268,9 @@ const SoapboxMount = () => { const Soapbox = () => { return ( - + + + ); }; diff --git a/app/soapbox/hooks/index.ts b/app/soapbox/hooks/index.ts index 2cd767c2d..a2489d6ef 100644 --- a/app/soapbox/hooks/index.ts +++ b/app/soapbox/hooks/index.ts @@ -3,6 +3,7 @@ export { useAppDispatch } from './useAppDispatch'; export { useAppSelector } from './useAppSelector'; export { useDimensions } from './useDimensions'; export { useFeatures } from './useFeatures'; +export { useLocale } from './useLocale'; export { useOnScreen } from './useOnScreen'; export { useOwnAccount } from './useOwnAccount'; export { useRefEventHandler } from './useRefEventHandler'; diff --git a/app/soapbox/hooks/useLocale.ts b/app/soapbox/hooks/useLocale.ts new file mode 100644 index 000000000..1be278002 --- /dev/null +++ b/app/soapbox/hooks/useLocale.ts @@ -0,0 +1,16 @@ +import MESSAGES from 'soapbox/locales/messages'; + +import { useSettings } from './useSettings'; + +/** Ensure the given locale exists in our codebase */ +const validLocale = (locale: string): boolean => Object.keys(MESSAGES).includes(locale); + +/** Get valid locale from settings. */ +const useLocale = (fallback = 'en') => { + const settings = useSettings(); + const locale = settings.get('locale'); + + return validLocale(locale) ? locale : fallback; +}; + +export { useLocale }; From dcd32e32a4128e2dcb8c16394531780d2f233d0a Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Fri, 22 Jul 2022 17:04:53 -0500 Subject: [PATCH 02/11] Add configurable GDPR alert --- app/soapbox/containers/soapbox.tsx | 2 + app/soapbox/hooks/index.ts | 1 + app/soapbox/hooks/useGdpr.ts | 47 +++++++++++++++++++ .../normalizers/soapbox/soapbox_config.ts | 1 + 4 files changed, 51 insertions(+) create mode 100644 app/soapbox/hooks/useGdpr.ts diff --git a/app/soapbox/containers/soapbox.tsx b/app/soapbox/containers/soapbox.tsx index 26bd02488..cbfb87d4a 100644 --- a/app/soapbox/containers/soapbox.tsx +++ b/app/soapbox/containers/soapbox.tsx @@ -34,6 +34,7 @@ import { useSettings, useSystemTheme, useLocale, + useGdpr, } from 'soapbox/hooks'; import MESSAGES from 'soapbox/locales/messages'; import { useCachedLocationHandler } from 'soapbox/utils/redirect'; @@ -77,6 +78,7 @@ const loadInitial = () => { /** Highest level node with the Redux store. */ const SoapboxMount = () => { + useGdpr(); useCachedLocationHandler(); const me = useAppSelector(state => state.me); const instance = useAppSelector(state => state.instance); diff --git a/app/soapbox/hooks/index.ts b/app/soapbox/hooks/index.ts index a2489d6ef..270f44c84 100644 --- a/app/soapbox/hooks/index.ts +++ b/app/soapbox/hooks/index.ts @@ -3,6 +3,7 @@ export { useAppDispatch } from './useAppDispatch'; export { useAppSelector } from './useAppSelector'; export { useDimensions } from './useDimensions'; export { useFeatures } from './useFeatures'; +export { useGdpr } from './useGdpr'; export { useLocale } from './useLocale'; export { useOnScreen } from './useOnScreen'; export { useOwnAccount } from './useOwnAccount'; diff --git a/app/soapbox/hooks/useGdpr.ts b/app/soapbox/hooks/useGdpr.ts new file mode 100644 index 000000000..ea0c5435f --- /dev/null +++ b/app/soapbox/hooks/useGdpr.ts @@ -0,0 +1,47 @@ +import { useEffect, useRef } from 'react'; +import { useIntl, defineMessages } from 'react-intl'; + +import snackbar from 'soapbox/actions/snackbar'; + +import { useAppDispatch } from './useAppDispatch'; +import { useAppSelector } from './useAppSelector'; +import { useSoapboxConfig } from './useSoapboxConfig'; + +const hasGdpr = !!localStorage.getItem('soapbox:gdpr'); + +const messages = defineMessages({ + accept: { id: 'gdpr.accept', defaultMessage: 'Accept' }, + body: { id: 'gdpr.message', defaultMessage: '{siteTitle} uses session cookies, which are essential to the website\'s functioning.' }, +}); + +/** Displays a GDPR popup unless it has already been accepted. */ +const useGdpr = () => { + const intl = useIntl(); + const dispatch = useAppDispatch(); + + /** Track whether the snackbar has already been displayed once. */ + const triggered = useRef(hasGdpr); + + const soapbox = useSoapboxConfig(); + const isLoggedIn = useAppSelector(state => !!state.me); + const siteTitle = useAppSelector(state => state.instance.title); + + const handleAccept = () => { + localStorage.setItem('soapbox:gdpr', 'true'); + triggered.current = true; + }; + + useEffect(() => { + if (soapbox.gdpr && !isLoggedIn && !triggered.current) { + const message = intl.formatMessage(messages.body, { siteTitle }); + + dispatch(snackbar.show('info', message, { + action: handleAccept, + actionLabel: intl.formatMessage(messages.accept), + dismissAfter: false, + })); + } + }, [soapbox.gdpr, isLoggedIn]); +}; + +export { useGdpr }; diff --git a/app/soapbox/normalizers/soapbox/soapbox_config.ts b/app/soapbox/normalizers/soapbox/soapbox_config.ts index efb3b0044..7ed814013 100644 --- a/app/soapbox/normalizers/soapbox/soapbox_config.ts +++ b/app/soapbox/normalizers/soapbox/soapbox_config.ts @@ -89,6 +89,7 @@ export const SoapboxConfigRecord = ImmutableRecord({ customCss: ImmutableList(), defaultSettings: ImmutableMap(), extensions: ImmutableMap(), + gdpr: false, greentext: false, promoPanel: PromoPanelRecord(), navlinks: ImmutableMap({ From 7bbb9839bab4ef095ebd9a5245dbdc14ba84c2f9 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Fri, 22 Jul 2022 17:13:57 -0500 Subject: [PATCH 03/11] SoapboxMount: break even more out into SoapboxHead --- app/soapbox/containers/soapbox.tsx | 72 ++++++++++++++++++------------ 1 file changed, 43 insertions(+), 29 deletions(-) diff --git a/app/soapbox/containers/soapbox.tsx b/app/soapbox/containers/soapbox.tsx index cbfb87d4a..21b80a503 100644 --- a/app/soapbox/containers/soapbox.tsx +++ b/app/soapbox/containers/soapbox.tsx @@ -83,45 +83,21 @@ const SoapboxMount = () => { const me = useAppSelector(state => state.me); const instance = useAppSelector(state => state.instance); const account = useOwnAccount(); - const settings = useSettings(); const soapboxConfig = useSoapboxConfig(); const features = useFeatures(); - const locale = useLocale(); const waitlisted = account && !account.source.get('approved', true); const needsOnboarding = useAppSelector(state => state.onboarding.needsOnboarding); const showOnboarding = account && !waitlisted && needsOnboarding; const singleUserMode = soapboxConfig.singleUserMode && soapboxConfig.singleUserModeProfile; - const systemTheme = useSystemTheme(); - const userTheme = settings.get('themeMode'); - const darkMode = userTheme === 'dark' || (userTheme === 'system' && systemTheme === 'dark'); const pepeEnabled = soapboxConfig.getIn(['extensions', 'pepe', 'enabled']) === true; - const themeCss = generateThemeCss(soapboxConfig); - // @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); }; - const bodyClass = classNames('bg-white dark:bg-slate-900 text-base h-full', { - 'no-reduce-motion': !settings.get('reduceMotion'), - 'underline-links': settings.get('underlineLinks'), - 'dyslexic': settings.get('dyslexicFont'), - 'demetricator': settings.get('demetricator'), - }); - - const helmet = ( - - - - {themeCss && } - {darkMode && } - - - ); - /** Render the onboarding flow. */ const renderOnboarding = () => ( @@ -193,7 +169,6 @@ const SoapboxMount = () => { <> - {helmet} {renderBody()} @@ -266,13 +241,52 @@ const SoapboxLoad: React.FC = ({ children }) => { ); }; +interface ISoapboxHead { + children: React.ReactNode, +} + +/** Injects metadata into site head with Helmet. */ +const SoapboxHead: React.FC = ({ children }) => { + const locale = useLocale(); + const settings = useSettings(); + const soapboxConfig = useSoapboxConfig(); + const systemTheme = useSystemTheme(); + + const userTheme = settings.get('themeMode'); + const darkMode = userTheme === 'dark' || (userTheme === 'system' && systemTheme === 'dark'); + const themeCss = generateThemeCss(soapboxConfig); + + const bodyClass = classNames('bg-white dark:bg-slate-900 text-base h-full', { + 'no-reduce-motion': !settings.get('reduceMotion'), + 'underline-links': settings.get('underlineLinks'), + 'dyslexic': settings.get('dyslexicFont'), + 'demetricator': settings.get('demetricator'), + }); + + return ( + <> + + + + {themeCss && } + {darkMode && } + + + + {children} + + ); +}; + /** The root React node of the application. */ -const Soapbox = () => { +const Soapbox: React.FC = () => { return ( - - - + + + + + ); }; From 5916041fecf9abceb623adf213fbb76a7bcd5450 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Fri, 22 Jul 2022 17:25:52 -0500 Subject: [PATCH 04/11] Add useTheme hook --- app/soapbox/components/site-logo.tsx | 9 ++------- app/soapbox/containers/soapbox.tsx | 6 ++---- app/soapbox/hooks/index.ts | 1 + app/soapbox/hooks/useTheme.ts | 20 ++++++++++++++++++++ 4 files changed, 25 insertions(+), 11 deletions(-) create mode 100644 app/soapbox/hooks/useTheme.ts diff --git a/app/soapbox/components/site-logo.tsx b/app/soapbox/components/site-logo.tsx index 01bfc54ed..1e8751ac5 100644 --- a/app/soapbox/components/site-logo.tsx +++ b/app/soapbox/components/site-logo.tsx @@ -1,7 +1,7 @@ import classNames from 'classnames'; import React from 'react'; -import { useSoapboxConfig, useSettings, useSystemTheme } from 'soapbox/hooks'; +import { useSoapboxConfig, useSettings, useTheme } from 'soapbox/hooks'; interface ISiteLogo extends React.ComponentProps<'img'> { /** Extra class names for the element. */ @@ -14,12 +14,7 @@ interface ISiteLogo extends React.ComponentProps<'img'> { const SiteLogo: React.FC = ({ className, theme, ...rest }) => { const { logo, logoDarkMode } = useSoapboxConfig(); const settings = useSettings(); - - const systemTheme = useSystemTheme(); - const userTheme = settings.get('themeMode'); - const darkMode = theme - ? theme === 'dark' - : (userTheme === 'dark' || (userTheme === 'system' && systemTheme === 'dark')); + const darkMode = useTheme() === 'dark'; /** Soapbox logo. */ const soapboxLogo = darkMode diff --git a/app/soapbox/containers/soapbox.tsx b/app/soapbox/containers/soapbox.tsx index 21b80a503..8be5b2814 100644 --- a/app/soapbox/containers/soapbox.tsx +++ b/app/soapbox/containers/soapbox.tsx @@ -32,7 +32,7 @@ import { useFeatures, useSoapboxConfig, useSettings, - useSystemTheme, + useTheme, useLocale, useGdpr, } from 'soapbox/hooks'; @@ -250,10 +250,8 @@ const SoapboxHead: React.FC = ({ children }) => { const locale = useLocale(); const settings = useSettings(); const soapboxConfig = useSoapboxConfig(); - const systemTheme = useSystemTheme(); - const userTheme = settings.get('themeMode'); - const darkMode = userTheme === 'dark' || (userTheme === 'system' && systemTheme === 'dark'); + const darkMode = useTheme() === 'dark'; const themeCss = generateThemeCss(soapboxConfig); const bodyClass = classNames('bg-white dark:bg-slate-900 text-base h-full', { diff --git a/app/soapbox/hooks/index.ts b/app/soapbox/hooks/index.ts index 270f44c84..49f4f6b8b 100644 --- a/app/soapbox/hooks/index.ts +++ b/app/soapbox/hooks/index.ts @@ -11,3 +11,4 @@ export { useRefEventHandler } from './useRefEventHandler'; export { useSettings } from './useSettings'; export { useSoapboxConfig } from './useSoapboxConfig'; export { useSystemTheme } from './useSystemTheme'; +export { useTheme } from './useTheme'; diff --git a/app/soapbox/hooks/useTheme.ts b/app/soapbox/hooks/useTheme.ts new file mode 100644 index 000000000..22ececd7a --- /dev/null +++ b/app/soapbox/hooks/useTheme.ts @@ -0,0 +1,20 @@ +import { useSettings } from './useSettings'; +import { useSystemTheme } from './useSystemTheme'; + +type Theme = 'light' | 'dark'; + +/** + * Returns the actual theme being displayed (eg "light" or "dark") + * regardless of whether that's by system theme or direct setting. + */ +const useTheme = (): Theme => { + const settings = useSettings(); + const systemTheme = useSystemTheme(); + + const userTheme = settings.get('themeMode'); + const darkMode = userTheme === 'dark' || (userTheme === 'system' && systemTheme === 'dark'); + + return darkMode ? 'dark' : 'light'; +}; + +export { useTheme }; From 83329d08871d1790b68a095a6777f718ce9d5008 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Mon, 25 Jul 2022 22:58:09 -0500 Subject: [PATCH 05/11] Copy react-notification's source code directly into the project --- app/soapbox/actions/alerts.ts | 2 +- .../ui/containers/notifications_container.tsx | 2 +- app/soapbox/hooks/useGdpr.ts | 1 + .../normalizers/soapbox/soapbox_config.ts | 1 + .../react-notification/defaultPropTypes.js | 31 ++++ app/soapbox/react-notification/index.d.ts | 88 +++++++++ app/soapbox/react-notification/index.js | 2 + .../react-notification/notification.js | 175 ++++++++++++++++++ .../react-notification/notificationStack.js | 95 ++++++++++ .../react-notification/stackedNotification.js | 69 +++++++ package.json | 1 - yarn.lock | 7 - 12 files changed, 464 insertions(+), 10 deletions(-) create mode 100644 app/soapbox/react-notification/defaultPropTypes.js create mode 100644 app/soapbox/react-notification/index.d.ts create mode 100644 app/soapbox/react-notification/index.js create mode 100644 app/soapbox/react-notification/notification.js create mode 100644 app/soapbox/react-notification/notificationStack.js create mode 100644 app/soapbox/react-notification/stackedNotification.js diff --git a/app/soapbox/actions/alerts.ts b/app/soapbox/actions/alerts.ts index 8f200563a..3e5aed4b3 100644 --- a/app/soapbox/actions/alerts.ts +++ b/app/soapbox/actions/alerts.ts @@ -5,7 +5,7 @@ import { httpErrorMessages } from 'soapbox/utils/errors'; import type { SnackbarActionSeverity } from './snackbar'; import type { AnyAction } from '@reduxjs/toolkit'; import type { AxiosError } from 'axios'; -import type { NotificationObject } from 'react-notification'; +import type { NotificationObject } from 'soapbox/react-notification'; const messages = defineMessages({ unexpectedTitle: { id: 'alert.unexpected.title', defaultMessage: 'Oops!' }, diff --git a/app/soapbox/features/ui/containers/notifications_container.tsx b/app/soapbox/features/ui/containers/notifications_container.tsx index eafd8efe4..b6d1748e5 100644 --- a/app/soapbox/features/ui/containers/notifications_container.tsx +++ b/app/soapbox/features/ui/containers/notifications_container.tsx @@ -1,11 +1,11 @@ import React from 'react'; import { useIntl, MessageDescriptor } from 'react-intl'; -import { NotificationStack, NotificationObject, StyleFactoryFn } from 'react-notification'; import { useHistory } from 'react-router-dom'; import { dismissAlert } from 'soapbox/actions/alerts'; import { Button } from 'soapbox/components/ui'; import { useAppSelector, useAppDispatch } from 'soapbox/hooks'; +import { NotificationStack, NotificationObject, StyleFactoryFn } from 'soapbox/react-notification'; import type { Alert } from 'soapbox/reducers/alerts'; diff --git a/app/soapbox/hooks/useGdpr.ts b/app/soapbox/hooks/useGdpr.ts index ea0c5435f..49e66bf0c 100644 --- a/app/soapbox/hooks/useGdpr.ts +++ b/app/soapbox/hooks/useGdpr.ts @@ -11,6 +11,7 @@ const hasGdpr = !!localStorage.getItem('soapbox:gdpr'); const messages = defineMessages({ accept: { id: 'gdpr.accept', defaultMessage: 'Accept' }, + learnMore: { id: 'gdpr.learn_more', defaultMessage: 'Learn more' }, body: { id: 'gdpr.message', defaultMessage: '{siteTitle} uses session cookies, which are essential to the website\'s functioning.' }, }); diff --git a/app/soapbox/normalizers/soapbox/soapbox_config.ts b/app/soapbox/normalizers/soapbox/soapbox_config.ts index 7ed814013..d90112810 100644 --- a/app/soapbox/normalizers/soapbox/soapbox_config.ts +++ b/app/soapbox/normalizers/soapbox/soapbox_config.ts @@ -90,6 +90,7 @@ export const SoapboxConfigRecord = ImmutableRecord({ defaultSettings: ImmutableMap(), extensions: ImmutableMap(), gdpr: false, + gdprUrl: '', greentext: false, promoPanel: PromoPanelRecord(), navlinks: ImmutableMap({ diff --git a/app/soapbox/react-notification/defaultPropTypes.js b/app/soapbox/react-notification/defaultPropTypes.js new file mode 100644 index 000000000..1a3dd9d4e --- /dev/null +++ b/app/soapbox/react-notification/defaultPropTypes.js @@ -0,0 +1,31 @@ +import PropTypes from 'prop-types'; + +export default { + message: PropTypes.oneOfType([ + PropTypes.string, + PropTypes.element, + ]).isRequired, + action: PropTypes.oneOfType([ + PropTypes.bool, + PropTypes.string, + PropTypes.node, + ]), + onClick: PropTypes.func, + style: PropTypes.bool, + actionStyle: PropTypes.object, + titleStyle: PropTypes.object, + barStyle: PropTypes.object, + activeBarStyle: PropTypes.object, + dismissAfter: PropTypes.oneOfType([ + PropTypes.bool, + PropTypes.number, + ]), + onDismiss: PropTypes.func, + className: PropTypes.string, + activeClassName: PropTypes.string, + isActive: PropTypes.bool, + title: PropTypes.oneOfType([ + PropTypes.string, + PropTypes.node, + ]), +}; diff --git a/app/soapbox/react-notification/index.d.ts b/app/soapbox/react-notification/index.d.ts new file mode 100644 index 000000000..7a1acd780 --- /dev/null +++ b/app/soapbox/react-notification/index.d.ts @@ -0,0 +1,88 @@ +declare module 'soapbox/react-notification' { + import { Component, ReactElement } from 'react'; + + interface StyleFactoryFn { + (index: number, style: object | void, notification: NotificationProps): object; + } + + interface OnClickNotificationProps { + /** + * Callback function to run when the action is clicked. + * @param notification Notification currently being clicked + * @param deactivate Function that can be called to set the notification to inactive. + * Used to activate notification exit animation on click. + */ + onClick?(notification: NotificationProps, deactivate: () => void): void; + } + + interface NotificationProps extends OnClickNotificationProps { + /** The name of the action, e.g., "close" or "undo". */ + action?: string; + /** Custom action styles. */ + actionStyle?: object; + /** Custom snackbar styles when the bar is active. */ + activeBarStyle?: object; + /** + * Custom class to apply to the top-level component when active. + * @default 'notification-bar-active' + */ + activeClassName?: string; + /** Custom snackbar styles. */ + barStyle?: object; + /** Custom class to apply to the top-level component. */ + className?: string; + /** + * Timeout for onDismiss event. + * @default 2000 + */ + dismissAfter?: boolean | number; + /** + * If true, the notification is visible. + * @default false + */ + isActive?: boolean; + /** The message or component for the notification. */ + message: string | ReactElement; + /** Setting this prop to `false` will disable all inline styles. */ + style?: boolean; + /** The title for the notification. */ + title?: string | ReactElement; + /** Custom title styles. */ + titleStyle?: object; + + /** + * Callback function to run when dismissAfter timer runs out + * @param notification Notification currently being dismissed. + */ + onDismiss?(notification: NotificationProps): void; + } + + interface NotificationStackProps extends OnClickNotificationProps { + /** Create the style of the actions. */ + actionStyleFactory?: StyleFactoryFn; + /** Create the style of the active notification. */ + activeBarStyleFactory?: StyleFactoryFn; + /** Create the style of the notification. */ + barStyleFactory?: StyleFactoryFn; + /** + * If false, notification dismiss timers start immediately. + * @default true + */ + dismissInOrder?: boolean; + /** Array of notifications to render. */ + notifications: NotificationObject[]; + /** + * Callback function to run when dismissAfter timer runs out + * @param notification Notification currently being dismissed. + */ + onDismiss?(notification: NotificationObject): void; + } + + export interface NotificationObject extends NotificationProps { + key: number | string; + } + + export class Notification extends Component {} + + export class NotificationStack extends Component {} +} diff --git a/app/soapbox/react-notification/index.js b/app/soapbox/react-notification/index.js new file mode 100644 index 000000000..3d7da7cee --- /dev/null +++ b/app/soapbox/react-notification/index.js @@ -0,0 +1,2 @@ +export { default as Notification } from './notification'; +export { default as NotificationStack } from './notificationStack'; diff --git a/app/soapbox/react-notification/notification.js b/app/soapbox/react-notification/notification.js new file mode 100644 index 000000000..ab1cddf9b --- /dev/null +++ b/app/soapbox/react-notification/notification.js @@ -0,0 +1,175 @@ +/* linting temp disabled while working on updates */ +/* eslint-disable */ +import React, { Component } from 'react'; +import defaultPropTypes from './defaultPropTypes'; + +class Notification extends Component { + constructor(props) { + super(props); + + this.getBarStyle = this.getBarStyle.bind(this); + this.getActionStyle = this.getActionStyle.bind(this); + this.getTitleStyle = this.getTitleStyle.bind(this); + this.handleClick = this.handleClick.bind(this); + + if (props.onDismiss && props.isActive) { + this.dismissTimeout = setTimeout( + props.onDismiss, + props.dismissAfter + ); + } + } + + componentWillReceiveProps(nextProps) { + if (nextProps.dismissAfter === false) return; + + // See http://eslint.org/docs/rules/no-prototype-builtins + if (!{}.hasOwnProperty.call(nextProps, 'isLast')) { + clearTimeout(this.dismissTimeout); + } + + if (nextProps.onDismiss) { + if ( + (nextProps.isActive && !this.props.isActive) || + (nextProps.dismissAfter && this.props.dismissAfter === false) + ) { + this.dismissTimeout = setTimeout( + nextProps.onDismiss, + nextProps.dismissAfter + ); + } + } + } + + componentWillUnmount() { + if (this.props.dismissAfter) clearTimeout(this.dismissTimeout); + } + + /* + * @description Dynamically get the styles for the bar. + * @returns {object} result The style. + */ + getBarStyle() { + if (this.props.style === false) return {}; + + const { isActive, barStyle, activeBarStyle } = this.props; + + const baseStyle = { + position: 'fixed', + bottom: '2rem', + left: '-100%', + width: 'auto', + padding: '1rem', + margin: 0, + color: '#fafafa', + font: '1rem normal Roboto, sans-serif', + borderRadius: '5px', + background: '#212121', + borderSizing: 'border-box', + boxShadow: '0 0 1px 1px rgba(10, 10, 11, .125)', + cursor: 'default', + WebKitTransition: '.5s cubic-bezier(0.89, 0.01, 0.5, 1.1)', + MozTransition: '.5s cubic-bezier(0.89, 0.01, 0.5, 1.1)', + msTransition: '.5s cubic-bezier(0.89, 0.01, 0.5, 1.1)', + OTransition: '.5s cubic-bezier(0.89, 0.01, 0.5, 1.1)', + transition: '.5s cubic-bezier(0.89, 0.01, 0.5, 1.1)', + WebkitTransform: 'translatez(0)', + MozTransform: 'translatez(0)', + msTransform: 'translatez(0)', + OTransform: 'translatez(0)', + transform: 'translatez(0)' + }; + + return isActive ? + Object.assign({}, baseStyle, { left: '1rem' }, barStyle, activeBarStyle) : + Object.assign({}, baseStyle, barStyle); + } + + /* + * @function getActionStyle + * @description Dynamically get the styles for the action text. + * @returns {object} result The style. + */ + getActionStyle() { + return this.props.style !== false ? Object.assign({}, { + padding: '0.125rem', + marginLeft: '1rem', + color: '#f44336', + font: '.75rem normal Roboto, sans-serif', + lineHeight: '1rem', + letterSpacing: '.125ex', + textTransform: 'uppercase', + borderRadius: '5px', + cursor: 'pointer' + }, this.props.actionStyle) : {}; + } + + /* + * @function getTitleStyle + * @description Dynamically get the styles for the title. + * @returns {object} result The style. + */ + getTitleStyle() { + return this.props.style !== false ? Object.assign({}, { + fontWeight: '700', + marginRight: '.5rem' + }, this.props.titleStyle) : {}; + } + + /* + * @function handleClick + * @description Handle click events on the action button. + */ + handleClick() { + if (this.props.onClick && typeof this.props.onClick === 'function') { + return this.props.onClick(); + } + } + + render() { + let className = 'notification-bar'; + + if (this.props.isActive) className += ` ${this.props.activeClassName}`; + if (this.props.className) className += ` ${this.props.className}`; + + return ( +
+
+ {this.props.title ? ( + + {this.props.title} + + ) : null} + + {/* eslint-disable */} + + {this.props.message} + + + {this.props.action ? ( + + {this.props.action} + + ) : null} +
+
+ ); + } +} + +Notification.propTypes = defaultPropTypes; + +Notification.defaultProps = { + isActive: false, + dismissAfter: 2000, + activeClassName: 'notification-bar-active' +}; + +export default Notification; diff --git a/app/soapbox/react-notification/notificationStack.js b/app/soapbox/react-notification/notificationStack.js new file mode 100644 index 000000000..dc9c2459b --- /dev/null +++ b/app/soapbox/react-notification/notificationStack.js @@ -0,0 +1,95 @@ +/* linting temp disabled while working on updates */ +/* eslint-disable */ +import React from 'react'; +import PropTypes from 'prop-types'; +import StackedNotification from './stackedNotification'; +import defaultPropTypes from './defaultPropTypes'; + +function defaultBarStyleFactory(index, style) { + return Object.assign( + {}, + style, + { bottom: `${2 + (index * 4)}rem` } + ); +} + +function defaultActionStyleFactory(index, style) { + return Object.assign( + {}, + style, + {} + ); +} + +/** +* The notification list does not have any state, so use a +* pure function here. It just needs to return the stacked array +* of notification components. +*/ +const NotificationStack = props => ( +
+ {props.notifications.map((notification, index) => { + const isLast = index === 0 && props.notifications.length === 1; + const dismissNow = isLast || !props.dismissInOrder; + + // Handle styles + const barStyle = props.barStyleFactory(index, notification.barStyle, notification); + const actionStyle = props.actionStyleFactory(index, notification.actionStyle, notification); + const activeBarStyle = props.activeBarStyleFactory( + index, + notification.activeBarStyle, + notification + ); + + // Allow onClick from notification stack or individual notifications + const onClick = notification.onClick || props.onClick; + const onDismiss = props.onDismiss; + + let { dismissAfter } = notification; + + if (dismissAfter !== false) { + if (dismissAfter == null) dismissAfter = props.dismissAfter; + if (!dismissNow) dismissAfter += index * 1000; + } + + return ( + + ); + })} +
+); + +/* eslint-disable react/no-unused-prop-types, react/forbid-prop-types */ +NotificationStack.propTypes = { + activeBarStyleFactory: PropTypes.func, + barStyleFactory: PropTypes.func, + actionStyleFactory: PropTypes.func, + dismissInOrder: PropTypes.bool, + notifications: PropTypes.array.isRequired, + onDismiss: PropTypes.func.isRequired, + onClick: PropTypes.func, + action: defaultPropTypes.action +}; + +NotificationStack.defaultProps = { + activeBarStyleFactory: defaultBarStyleFactory, + barStyleFactory: defaultBarStyleFactory, + actionStyleFactory: defaultActionStyleFactory, + dismissInOrder: true, + dismissAfter: 1000, + onClick: () => {} +}; +/* eslint-enable no-alert, no-console */ + +export default NotificationStack; diff --git a/app/soapbox/react-notification/stackedNotification.js b/app/soapbox/react-notification/stackedNotification.js new file mode 100644 index 000000000..c8d7200d4 --- /dev/null +++ b/app/soapbox/react-notification/stackedNotification.js @@ -0,0 +1,69 @@ +/* linting temp disabled while working on updates */ +/* eslint-disable */ +import React, { Component } from 'react'; +import defaultPropTypes from './defaultPropTypes'; +import Notification from './notification'; + +class StackedNotification extends Component { + constructor(props) { + super(props); + + this.state = { + isActive: false + }; + + this.handleClick = this.handleClick.bind(this); + } + + componentDidMount() { + this.activeTimeout = setTimeout(this.setState.bind(this, { + isActive: true + }), 1); + + this.dismiss(this.props.dismissAfter); + } + + componentWillReceiveProps(nextProps) { + if (nextProps.dismissAfter !== this.props.dismissAfter) { + this.dismiss(nextProps.dismissAfter); + } + } + + componentWillUnmount() { + clearTimeout(this.activeTimeout); + clearTimeout(this.dismissTimeout); + } + + dismiss(dismissAfter) { + if (dismissAfter === false) return; + + this.dismissTimeout = setTimeout(this.setState.bind(this, { + isActive: false + }), dismissAfter); + } + + /* + * @function handleClick + * @description Bind deactivate Notification function to Notification click handler + */ + handleClick() { + if (this.props.onClick && typeof this.props.onClick === 'function') { + return this.props.onClick(this.setState.bind(this, { isActive: false })); + } + } + + render() { + return ( + setTimeout(this.props.onDismiss, 300)} + isActive={this.state.isActive} + /> + ); + } +} + +StackedNotification.propTypes = defaultPropTypes; + +export default StackedNotification; diff --git a/package.json b/package.json index 0918b337b..a34f1b539 100644 --- a/package.json +++ b/package.json @@ -162,7 +162,6 @@ "react-inlinesvg": "^3.0.0", "react-intl": "^5.0.0", "react-motion": "^0.5.2", - "react-notification": "^6.8.5", "react-otp-input": "^2.4.0", "react-overlays": "^0.9.0", "react-popper": "^2.3.0", diff --git a/yarn.lock b/yarn.lock index b8d57fbff..4469a177a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9749,13 +9749,6 @@ react-motion@^0.5.2: prop-types "^15.5.8" raf "^3.1.0" -react-notification@^6.8.5: - version "6.8.5" - resolved "https://registry.yarnpkg.com/react-notification/-/react-notification-6.8.5.tgz#7ea90a633bb2a280d899e30c93cf372265cce4f0" - integrity sha512-3pJPhSsWNYizpyeMeWuC+jVthqE9WKqQ6rHq2naiiP4fLGN4irwL2Xp2Q8Qn7agW/e4BIDxarab6fJOUp1cKUw== - dependencies: - prop-types "^15.6.2" - react-onclickoutside@^6.12.0: version "6.12.1" resolved "https://registry.yarnpkg.com/react-onclickoutside/-/react-onclickoutside-6.12.1.tgz#92dddd28f55e483a1838c5c2930e051168c1e96b" From 0480bfab94f7b065e84ee88386a5828286cca027 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Tue, 26 Jul 2022 10:30:48 -0500 Subject: [PATCH 06/11] Add Banner UI component --- app/soapbox/components/ui/banner/banner.tsx | 28 ++++++++++++ app/soapbox/components/ui/index.ts | 1 + .../features/ui/components/cta-banner.tsx | 44 +++++++++---------- 3 files changed, 50 insertions(+), 23 deletions(-) create mode 100644 app/soapbox/components/ui/banner/banner.tsx diff --git a/app/soapbox/components/ui/banner/banner.tsx b/app/soapbox/components/ui/banner/banner.tsx new file mode 100644 index 000000000..3b2453a4a --- /dev/null +++ b/app/soapbox/components/ui/banner/banner.tsx @@ -0,0 +1,28 @@ +import classNames from 'classnames'; +import React from 'react'; + +interface IBanner { + theme: 'frosted' | 'opaque', + children: React.ReactNode, +} + +/** Displays a sticky full-width banner at the bottom of the screen. */ +const Banner: React.FC = ({ theme, children }) => { + return ( +
+
+
+ {children} +
+
+
+ ); +}; + +export default Banner; diff --git a/app/soapbox/components/ui/index.ts b/app/soapbox/components/ui/index.ts index 042b26838..5eff0a78f 100644 --- a/app/soapbox/components/ui/index.ts +++ b/app/soapbox/components/ui/index.ts @@ -1,4 +1,5 @@ export { default as Avatar } from './avatar/avatar'; +export { default as Banner } from './banner/banner'; export { default as Button } from './button/button'; export { Card, CardBody, CardHeader, CardTitle } from './card/card'; export { default as Checkbox } from './checkbox/checkbox'; diff --git a/app/soapbox/features/ui/components/cta-banner.tsx b/app/soapbox/features/ui/components/cta-banner.tsx index 9ecc9b6dc..339db9c95 100644 --- a/app/soapbox/features/ui/components/cta-banner.tsx +++ b/app/soapbox/features/ui/components/cta-banner.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { FormattedMessage } from 'react-intl'; -import { Button, HStack, Stack, Text } from 'soapbox/components/ui'; +import { Banner, Button, HStack, Stack, Text } from 'soapbox/components/ui'; import { useAppSelector, useSoapboxConfig } from 'soapbox/hooks'; const CtaBanner = () => { @@ -12,32 +12,30 @@ const CtaBanner = () => { if (me || singleUserMode) return null; return ( -
-
-
- - - - - +
+ + + + + + - - - - + + + + - - + + - - + -
-
+ +
); }; From d422bdf3d3eed0d74ccf5bd1acfcf06c73993418 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Tue, 26 Jul 2022 10:58:17 -0500 Subject: [PATCH 07/11] Add GdprBanner component, remove useGdpr hook --- app/soapbox/components/gdpr-banner.tsx | 60 ++++++++++++++++++++++++++ app/soapbox/containers/soapbox.tsx | 5 ++- app/soapbox/hooks/index.ts | 1 - app/soapbox/hooks/useGdpr.ts | 48 --------------------- 4 files changed, 63 insertions(+), 51 deletions(-) create mode 100644 app/soapbox/components/gdpr-banner.tsx delete mode 100644 app/soapbox/hooks/useGdpr.ts diff --git a/app/soapbox/components/gdpr-banner.tsx b/app/soapbox/components/gdpr-banner.tsx new file mode 100644 index 000000000..9095d7e03 --- /dev/null +++ b/app/soapbox/components/gdpr-banner.tsx @@ -0,0 +1,60 @@ +import React, { useState } from 'react'; +import { FormattedMessage } from 'react-intl'; + +import { Banner, Button, HStack, Stack, Text } from 'soapbox/components/ui'; +import { useAppSelector, useSoapboxConfig } from 'soapbox/hooks'; + +const acceptedGdpr = !!localStorage.getItem('soapbox:gdpr'); + +/** Displays a cookie consent banner. */ +const GdprBanner: React.FC = () => { + /** Track whether the banner has already been displayed once. */ + const [shown, setShown] = useState(acceptedGdpr); + + const soapbox = useSoapboxConfig(); + const isLoggedIn = useAppSelector(state => !!state.me); + const siteTitle = useAppSelector(state => state.instance.title); + + const handleAccept = () => { + localStorage.setItem('soapbox:gdpr', 'true'); + setShown(true); + }; + + const showBanner = soapbox.gdpr && !isLoggedIn && !shown; + + if (!showBanner) { + return null; + } + + return ( + + + + + + + + + + + + + + + + + + + + ); +}; + +export default GdprBanner; diff --git a/app/soapbox/containers/soapbox.tsx b/app/soapbox/containers/soapbox.tsx index 8be5b2814..603663aa7 100644 --- a/app/soapbox/containers/soapbox.tsx +++ b/app/soapbox/containers/soapbox.tsx @@ -13,6 +13,7 @@ import { fetchMe } from 'soapbox/actions/me'; import { loadSoapboxConfig, getSoapboxConfig } from 'soapbox/actions/soapbox'; import { fetchVerificationConfig } from 'soapbox/actions/verification'; import * as BuildConfig from 'soapbox/build_config'; +import GdprBanner from 'soapbox/components/gdpr-banner'; import Helmet from 'soapbox/components/helmet'; import LoadingScreen from 'soapbox/components/loading-screen'; import AuthLayout from 'soapbox/features/auth_layout'; @@ -34,7 +35,6 @@ import { useSettings, useTheme, useLocale, - useGdpr, } from 'soapbox/hooks'; import MESSAGES from 'soapbox/locales/messages'; import { useCachedLocationHandler } from 'soapbox/utils/redirect'; @@ -78,7 +78,6 @@ const loadInitial = () => { /** Highest level node with the Redux store. */ const SoapboxMount = () => { - useGdpr(); useCachedLocationHandler(); const me = useAppSelector(state => state.me); const instance = useAppSelector(state => state.instance); @@ -178,6 +177,8 @@ const SoapboxMount = () => { {Component => } + + diff --git a/app/soapbox/hooks/index.ts b/app/soapbox/hooks/index.ts index 49f4f6b8b..aad62b1f1 100644 --- a/app/soapbox/hooks/index.ts +++ b/app/soapbox/hooks/index.ts @@ -3,7 +3,6 @@ export { useAppDispatch } from './useAppDispatch'; export { useAppSelector } from './useAppSelector'; export { useDimensions } from './useDimensions'; export { useFeatures } from './useFeatures'; -export { useGdpr } from './useGdpr'; export { useLocale } from './useLocale'; export { useOnScreen } from './useOnScreen'; export { useOwnAccount } from './useOwnAccount'; diff --git a/app/soapbox/hooks/useGdpr.ts b/app/soapbox/hooks/useGdpr.ts deleted file mode 100644 index 49e66bf0c..000000000 --- a/app/soapbox/hooks/useGdpr.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { useEffect, useRef } from 'react'; -import { useIntl, defineMessages } from 'react-intl'; - -import snackbar from 'soapbox/actions/snackbar'; - -import { useAppDispatch } from './useAppDispatch'; -import { useAppSelector } from './useAppSelector'; -import { useSoapboxConfig } from './useSoapboxConfig'; - -const hasGdpr = !!localStorage.getItem('soapbox:gdpr'); - -const messages = defineMessages({ - accept: { id: 'gdpr.accept', defaultMessage: 'Accept' }, - learnMore: { id: 'gdpr.learn_more', defaultMessage: 'Learn more' }, - body: { id: 'gdpr.message', defaultMessage: '{siteTitle} uses session cookies, which are essential to the website\'s functioning.' }, -}); - -/** Displays a GDPR popup unless it has already been accepted. */ -const useGdpr = () => { - const intl = useIntl(); - const dispatch = useAppDispatch(); - - /** Track whether the snackbar has already been displayed once. */ - const triggered = useRef(hasGdpr); - - const soapbox = useSoapboxConfig(); - const isLoggedIn = useAppSelector(state => !!state.me); - const siteTitle = useAppSelector(state => state.instance.title); - - const handleAccept = () => { - localStorage.setItem('soapbox:gdpr', 'true'); - triggered.current = true; - }; - - useEffect(() => { - if (soapbox.gdpr && !isLoggedIn && !triggered.current) { - const message = intl.formatMessage(messages.body, { siteTitle }); - - dispatch(snackbar.show('info', message, { - action: handleAccept, - actionLabel: intl.formatMessage(messages.accept), - dismissAfter: false, - })); - } - }, [soapbox.gdpr, isLoggedIn]); -}; - -export { useGdpr }; From 4f0e104fc4dd5b3dcde225c69f54be575b8cab1d Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Tue, 26 Jul 2022 11:15:04 -0500 Subject: [PATCH 08/11] GdprBanner: conditionally show "Learn more" button --- app/soapbox/components/gdpr-banner.tsx | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/app/soapbox/components/gdpr-banner.tsx b/app/soapbox/components/gdpr-banner.tsx index 9095d7e03..14eed7b9c 100644 --- a/app/soapbox/components/gdpr-banner.tsx +++ b/app/soapbox/components/gdpr-banner.tsx @@ -44,9 +44,13 @@ const GdprBanner: React.FC = () => { - + {soapbox.gdprUrl && ( + + + + )} - +
); }; diff --git a/app/soapbox/components/ui/banner/banner.tsx b/app/soapbox/components/ui/banner/banner.tsx index 1816d0eb8..3acbbcf09 100644 --- a/app/soapbox/components/ui/banner/banner.tsx +++ b/app/soapbox/components/ui/banner/banner.tsx @@ -12,15 +12,13 @@ const Banner: React.FC = ({ theme, children, className }) => { return (
-
-
- {children} -
+
+ {children}
); diff --git a/app/soapbox/features/ui/components/cta-banner.tsx b/app/soapbox/features/ui/components/cta-banner.tsx index 339db9c95..9d83c6702 100644 --- a/app/soapbox/features/ui/components/cta-banner.tsx +++ b/app/soapbox/features/ui/components/cta-banner.tsx @@ -21,7 +21,7 @@ const CtaBanner = () => { - + diff --git a/app/soapbox/locales/ar.json b/app/soapbox/locales/ar.json index 029203691..c4ae9a7d1 100644 --- a/app/soapbox/locales/ar.json +++ b/app/soapbox/locales/ar.json @@ -918,7 +918,7 @@ "settings.save.success": "Your preferences have been saved!", "settings.security": "Security", "settings.settings": "Settings", - "signup_panel.subtitle": "Sign up now to discuss.", + "signup_panel.subtitle": "Sign up now to discuss what's happening.", "signup_panel.title": "New to {site_title}?", "snackbar.view": "View", "soapbox_config.authenticated_profile_hint": "Users must be logged-in to view replies and media on user profiles.", diff --git a/app/soapbox/locales/ast.json b/app/soapbox/locales/ast.json index f496179e4..fc823149b 100644 --- a/app/soapbox/locales/ast.json +++ b/app/soapbox/locales/ast.json @@ -918,7 +918,7 @@ "settings.save.success": "Your preferences have been saved!", "settings.security": "Security", "settings.settings": "Settings", - "signup_panel.subtitle": "Sign up now to discuss.", + "signup_panel.subtitle": "Sign up now to discuss what's happening.", "signup_panel.title": "New to {site_title}?", "snackbar.view": "View", "soapbox_config.authenticated_profile_hint": "Users must be logged-in to view replies and media on user profiles.", diff --git a/app/soapbox/locales/bg.json b/app/soapbox/locales/bg.json index 15926758e..ebbf986d8 100644 --- a/app/soapbox/locales/bg.json +++ b/app/soapbox/locales/bg.json @@ -918,7 +918,7 @@ "settings.save.success": "Your preferences have been saved!", "settings.security": "Security", "settings.settings": "Settings", - "signup_panel.subtitle": "Sign up now to discuss.", + "signup_panel.subtitle": "Sign up now to discuss what's happening.", "signup_panel.title": "New to {site_title}?", "snackbar.view": "View", "soapbox_config.authenticated_profile_hint": "Users must be logged-in to view replies and media on user profiles.", diff --git a/app/soapbox/locales/bn.json b/app/soapbox/locales/bn.json index 4303880d1..c49586886 100644 --- a/app/soapbox/locales/bn.json +++ b/app/soapbox/locales/bn.json @@ -918,7 +918,7 @@ "settings.save.success": "Your preferences have been saved!", "settings.security": "Security", "settings.settings": "Settings", - "signup_panel.subtitle": "Sign up now to discuss.", + "signup_panel.subtitle": "Sign up now to discuss what's happening.", "signup_panel.title": "New to {site_title}?", "snackbar.view": "View", "soapbox_config.authenticated_profile_hint": "Users must be logged-in to view replies and media on user profiles.", diff --git a/app/soapbox/locales/br.json b/app/soapbox/locales/br.json index 2e5c957db..e4515794e 100644 --- a/app/soapbox/locales/br.json +++ b/app/soapbox/locales/br.json @@ -918,7 +918,7 @@ "settings.save.success": "Your preferences have been saved!", "settings.security": "Security", "settings.settings": "Settings", - "signup_panel.subtitle": "Sign up now to discuss.", + "signup_panel.subtitle": "Sign up now to discuss what's happening.", "signup_panel.title": "New to {site_title}?", "snackbar.view": "View", "soapbox_config.authenticated_profile_hint": "Users must be logged-in to view replies and media on user profiles.", diff --git a/app/soapbox/locales/co.json b/app/soapbox/locales/co.json index b11952c0e..7ad438674 100644 --- a/app/soapbox/locales/co.json +++ b/app/soapbox/locales/co.json @@ -918,7 +918,7 @@ "settings.save.success": "Your preferences have been saved!", "settings.security": "Security", "settings.settings": "Settings", - "signup_panel.subtitle": "Sign up now to discuss.", + "signup_panel.subtitle": "Sign up now to discuss what's happening.", "signup_panel.title": "New to {site_title}?", "snackbar.view": "View", "soapbox_config.authenticated_profile_hint": "Users must be logged-in to view replies and media on user profiles.", diff --git a/app/soapbox/locales/cy.json b/app/soapbox/locales/cy.json index 33aafb510..d1d3363f6 100644 --- a/app/soapbox/locales/cy.json +++ b/app/soapbox/locales/cy.json @@ -918,7 +918,7 @@ "settings.save.success": "Your preferences have been saved!", "settings.security": "Security", "settings.settings": "Settings", - "signup_panel.subtitle": "Sign up now to discuss.", + "signup_panel.subtitle": "Sign up now to discuss what's happening.", "signup_panel.title": "New to {site_title}?", "snackbar.view": "View", "soapbox_config.authenticated_profile_hint": "Users must be logged-in to view replies and media on user profiles.", diff --git a/app/soapbox/locales/da.json b/app/soapbox/locales/da.json index d4ff52588..670347b7c 100644 --- a/app/soapbox/locales/da.json +++ b/app/soapbox/locales/da.json @@ -918,7 +918,7 @@ "settings.save.success": "Your preferences have been saved!", "settings.security": "Security", "settings.settings": "Settings", - "signup_panel.subtitle": "Sign up now to discuss.", + "signup_panel.subtitle": "Sign up now to discuss what's happening.", "signup_panel.title": "New to {site_title}?", "snackbar.view": "View", "soapbox_config.authenticated_profile_hint": "Users must be logged-in to view replies and media on user profiles.", diff --git a/app/soapbox/locales/el.json b/app/soapbox/locales/el.json index f01736748..f5f24bdf1 100644 --- a/app/soapbox/locales/el.json +++ b/app/soapbox/locales/el.json @@ -918,7 +918,7 @@ "settings.save.success": "Your preferences have been saved!", "settings.security": "Security", "settings.settings": "Settings", - "signup_panel.subtitle": "Sign up now to discuss.", + "signup_panel.subtitle": "Sign up now to discuss what's happening.", "signup_panel.title": "New to {site_title}?", "snackbar.view": "View", "soapbox_config.authenticated_profile_hint": "Users must be logged-in to view replies and media on user profiles.", diff --git a/app/soapbox/locales/en.json b/app/soapbox/locales/en.json index 5d6d5dadf..f4dae88b7 100644 --- a/app/soapbox/locales/en.json +++ b/app/soapbox/locales/en.json @@ -928,7 +928,7 @@ "settings.security": "Security", "settings.settings": "Settings", "shared.tos": "Terms of Service", - "signup_panel.subtitle": "Sign up now to discuss.", + "signup_panel.subtitle": "Sign up now to discuss what's happening.", "signup_panel.title": "New to {site_title}?", "snackbar.view": "View", "soapbox_config.authenticated_profile_hint": "Users must be logged-in to view replies and media on user profiles.", diff --git a/app/soapbox/locales/eo.json b/app/soapbox/locales/eo.json index 699589198..55329bfed 100644 --- a/app/soapbox/locales/eo.json +++ b/app/soapbox/locales/eo.json @@ -918,7 +918,7 @@ "settings.save.success": "Your preferences have been saved!", "settings.security": "Security", "settings.settings": "Settings", - "signup_panel.subtitle": "Sign up now to discuss.", + "signup_panel.subtitle": "Sign up now to discuss what's happening.", "signup_panel.title": "New to {site_title}?", "snackbar.view": "View", "soapbox_config.authenticated_profile_hint": "Users must be logged-in to view replies and media on user profiles.", diff --git a/app/soapbox/locales/es-AR.json b/app/soapbox/locales/es-AR.json index aea9c1c3e..f3486c046 100644 --- a/app/soapbox/locales/es-AR.json +++ b/app/soapbox/locales/es-AR.json @@ -918,7 +918,7 @@ "settings.save.success": "Your preferences have been saved!", "settings.security": "Security", "settings.settings": "Settings", - "signup_panel.subtitle": "Sign up now to discuss.", + "signup_panel.subtitle": "Sign up now to discuss what's happening.", "signup_panel.title": "New to {site_title}?", "snackbar.view": "View", "soapbox_config.authenticated_profile_hint": "Users must be logged-in to view replies and media on user profiles.", diff --git a/app/soapbox/locales/es.json b/app/soapbox/locales/es.json index 3bf0f4f68..1d737c682 100644 --- a/app/soapbox/locales/es.json +++ b/app/soapbox/locales/es.json @@ -918,7 +918,7 @@ "settings.save.success": "Your preferences have been saved!", "settings.security": "Security", "settings.settings": "Settings", - "signup_panel.subtitle": "Sign up now to discuss.", + "signup_panel.subtitle": "Sign up now to discuss what's happening.", "signup_panel.title": "New to {site_title}?", "snackbar.view": "View", "soapbox_config.authenticated_profile_hint": "Users must be logged-in to view replies and media on user profiles.", diff --git a/app/soapbox/locales/et.json b/app/soapbox/locales/et.json index d8833466b..2e1424fa0 100644 --- a/app/soapbox/locales/et.json +++ b/app/soapbox/locales/et.json @@ -918,7 +918,7 @@ "settings.save.success": "Your preferences have been saved!", "settings.security": "Security", "settings.settings": "Settings", - "signup_panel.subtitle": "Sign up now to discuss.", + "signup_panel.subtitle": "Sign up now to discuss what's happening.", "signup_panel.title": "New to {site_title}?", "snackbar.view": "View", "soapbox_config.authenticated_profile_hint": "Users must be logged-in to view replies and media on user profiles.", diff --git a/app/soapbox/locales/eu.json b/app/soapbox/locales/eu.json index e8a2a66da..601fa7c16 100644 --- a/app/soapbox/locales/eu.json +++ b/app/soapbox/locales/eu.json @@ -918,7 +918,7 @@ "settings.save.success": "Your preferences have been saved!", "settings.security": "Security", "settings.settings": "Settings", - "signup_panel.subtitle": "Sign up now to discuss.", + "signup_panel.subtitle": "Sign up now to discuss what's happening.", "signup_panel.title": "New to {site_title}?", "snackbar.view": "View", "soapbox_config.authenticated_profile_hint": "Users must be logged-in to view replies and media on user profiles.", diff --git a/app/soapbox/locales/fa.json b/app/soapbox/locales/fa.json index dd500285d..1ed7b974e 100644 --- a/app/soapbox/locales/fa.json +++ b/app/soapbox/locales/fa.json @@ -918,7 +918,7 @@ "settings.save.success": "Your preferences have been saved!", "settings.security": "Security", "settings.settings": "Settings", - "signup_panel.subtitle": "Sign up now to discuss.", + "signup_panel.subtitle": "Sign up now to discuss what's happening.", "signup_panel.title": "New to {site_title}?", "snackbar.view": "View", "soapbox_config.authenticated_profile_hint": "Users must be logged-in to view replies and media on user profiles.", diff --git a/app/soapbox/locales/fi.json b/app/soapbox/locales/fi.json index 676eecf01..762f07281 100644 --- a/app/soapbox/locales/fi.json +++ b/app/soapbox/locales/fi.json @@ -918,7 +918,7 @@ "settings.save.success": "Your preferences have been saved!", "settings.security": "Security", "settings.settings": "Settings", - "signup_panel.subtitle": "Sign up now to discuss.", + "signup_panel.subtitle": "Sign up now to discuss what's happening.", "signup_panel.title": "New to {site_title}?", "snackbar.view": "View", "soapbox_config.authenticated_profile_hint": "Users must be logged-in to view replies and media on user profiles.", diff --git a/app/soapbox/locales/fr.json b/app/soapbox/locales/fr.json index eb28628bb..d7892b75a 100644 --- a/app/soapbox/locales/fr.json +++ b/app/soapbox/locales/fr.json @@ -918,7 +918,7 @@ "settings.save.success": "Your preferences have been saved!", "settings.security": "Security", "settings.settings": "Settings", - "signup_panel.subtitle": "Sign up now to discuss.", + "signup_panel.subtitle": "Sign up now to discuss what's happening.", "signup_panel.title": "New to {site_title}?", "snackbar.view": "View", "soapbox_config.authenticated_profile_hint": "Users must be logged-in to view replies and media on user profiles.", diff --git a/app/soapbox/locales/ga.json b/app/soapbox/locales/ga.json index a3072440e..39a8e3fd1 100644 --- a/app/soapbox/locales/ga.json +++ b/app/soapbox/locales/ga.json @@ -918,7 +918,7 @@ "settings.save.success": "Your preferences have been saved!", "settings.security": "Security", "settings.settings": "Settings", - "signup_panel.subtitle": "Sign up now to discuss.", + "signup_panel.subtitle": "Sign up now to discuss what's happening.", "signup_panel.title": "New to {site_title}?", "snackbar.view": "View", "soapbox_config.authenticated_profile_hint": "Users must be logged-in to view replies and media on user profiles.", diff --git a/app/soapbox/locales/gl.json b/app/soapbox/locales/gl.json index 863f0e640..e97072195 100644 --- a/app/soapbox/locales/gl.json +++ b/app/soapbox/locales/gl.json @@ -918,7 +918,7 @@ "settings.save.success": "Your preferences have been saved!", "settings.security": "Security", "settings.settings": "Settings", - "signup_panel.subtitle": "Sign up now to discuss.", + "signup_panel.subtitle": "Sign up now to discuss what's happening.", "signup_panel.title": "New to {site_title}?", "snackbar.view": "View", "soapbox_config.authenticated_profile_hint": "Users must be logged-in to view replies and media on user profiles.", diff --git a/app/soapbox/locales/hi.json b/app/soapbox/locales/hi.json index 8368e57b0..defd85f26 100644 --- a/app/soapbox/locales/hi.json +++ b/app/soapbox/locales/hi.json @@ -918,7 +918,7 @@ "settings.save.success": "Your preferences have been saved!", "settings.security": "Security", "settings.settings": "Settings", - "signup_panel.subtitle": "Sign up now to discuss.", + "signup_panel.subtitle": "Sign up now to discuss what's happening.", "signup_panel.title": "New to {site_title}?", "snackbar.view": "View", "soapbox_config.authenticated_profile_hint": "Users must be logged-in to view replies and media on user profiles.", diff --git a/app/soapbox/locales/hr.json b/app/soapbox/locales/hr.json index 9993ab74b..f8b293893 100644 --- a/app/soapbox/locales/hr.json +++ b/app/soapbox/locales/hr.json @@ -918,7 +918,7 @@ "settings.save.success": "Your preferences have been saved!", "settings.security": "Security", "settings.settings": "Settings", - "signup_panel.subtitle": "Sign up now to discuss.", + "signup_panel.subtitle": "Sign up now to discuss what's happening.", "signup_panel.title": "New to {site_title}?", "snackbar.view": "View", "soapbox_config.authenticated_profile_hint": "Users must be logged-in to view replies and media on user profiles.", diff --git a/app/soapbox/locales/hu.json b/app/soapbox/locales/hu.json index 6e2902dfd..e43d58d81 100644 --- a/app/soapbox/locales/hu.json +++ b/app/soapbox/locales/hu.json @@ -918,7 +918,7 @@ "settings.save.success": "Your preferences have been saved!", "settings.security": "Security", "settings.settings": "Settings", - "signup_panel.subtitle": "Sign up now to discuss.", + "signup_panel.subtitle": "Sign up now to discuss what's happening.", "signup_panel.title": "New to {site_title}?", "snackbar.view": "View", "soapbox_config.authenticated_profile_hint": "Users must be logged-in to view replies and media on user profiles.", diff --git a/app/soapbox/locales/hy.json b/app/soapbox/locales/hy.json index 7bbb8208d..3ea2f4c45 100644 --- a/app/soapbox/locales/hy.json +++ b/app/soapbox/locales/hy.json @@ -918,7 +918,7 @@ "settings.save.success": "Your preferences have been saved!", "settings.security": "Security", "settings.settings": "Settings", - "signup_panel.subtitle": "Sign up now to discuss.", + "signup_panel.subtitle": "Sign up now to discuss what's happening.", "signup_panel.title": "New to {site_title}?", "snackbar.view": "View", "soapbox_config.authenticated_profile_hint": "Users must be logged-in to view replies and media on user profiles.", diff --git a/app/soapbox/locales/id.json b/app/soapbox/locales/id.json index 4ddf6659f..ce421deb2 100644 --- a/app/soapbox/locales/id.json +++ b/app/soapbox/locales/id.json @@ -918,7 +918,7 @@ "settings.save.success": "Your preferences have been saved!", "settings.security": "Security", "settings.settings": "Settings", - "signup_panel.subtitle": "Sign up now to discuss.", + "signup_panel.subtitle": "Sign up now to discuss what's happening.", "signup_panel.title": "New to {site_title}?", "snackbar.view": "View", "soapbox_config.authenticated_profile_hint": "Users must be logged-in to view replies and media on user profiles.", diff --git a/app/soapbox/locales/io.json b/app/soapbox/locales/io.json index dc96eae13..0366c18c4 100644 --- a/app/soapbox/locales/io.json +++ b/app/soapbox/locales/io.json @@ -918,7 +918,7 @@ "settings.save.success": "Your preferences have been saved!", "settings.security": "Security", "settings.settings": "Settings", - "signup_panel.subtitle": "Sign up now to discuss.", + "signup_panel.subtitle": "Sign up now to discuss what's happening.", "signup_panel.title": "New to {site_title}?", "snackbar.view": "View", "soapbox_config.authenticated_profile_hint": "Users must be logged-in to view replies and media on user profiles.", diff --git a/app/soapbox/locales/it.json b/app/soapbox/locales/it.json index 0804cef89..8b75a4530 100644 --- a/app/soapbox/locales/it.json +++ b/app/soapbox/locales/it.json @@ -920,7 +920,7 @@ "settings.save.success": "Preferenze salvate!", "settings.security": "Sicurezza", "settings.settings": "Impostazioni", - "signup_panel.subtitle": "Sign up now to discuss.", + "signup_panel.subtitle": "Sign up now to discuss what's happening.", "signup_panel.title": "New to {site_title}?", "snackbar.view": "Mostra", "soapbox_config.authenticated_profile_hint": "Users must be logged-in to view replies and media on user profiles.", diff --git a/app/soapbox/locales/ka.json b/app/soapbox/locales/ka.json index f270f1868..91a057060 100644 --- a/app/soapbox/locales/ka.json +++ b/app/soapbox/locales/ka.json @@ -918,7 +918,7 @@ "settings.save.success": "Your preferences have been saved!", "settings.security": "Security", "settings.settings": "Settings", - "signup_panel.subtitle": "Sign up now to discuss.", + "signup_panel.subtitle": "Sign up now to discuss what's happening.", "signup_panel.title": "New to {site_title}?", "snackbar.view": "View", "soapbox_config.authenticated_profile_hint": "Users must be logged-in to view replies and media on user profiles.", diff --git a/app/soapbox/locales/kk.json b/app/soapbox/locales/kk.json index 35fbabf38..090318b70 100644 --- a/app/soapbox/locales/kk.json +++ b/app/soapbox/locales/kk.json @@ -918,7 +918,7 @@ "settings.save.success": "Your preferences have been saved!", "settings.security": "Security", "settings.settings": "Settings", - "signup_panel.subtitle": "Sign up now to discuss.", + "signup_panel.subtitle": "Sign up now to discuss what's happening.", "signup_panel.title": "New to {site_title}?", "snackbar.view": "View", "soapbox_config.authenticated_profile_hint": "Users must be logged-in to view replies and media on user profiles.", diff --git a/app/soapbox/locales/ko.json b/app/soapbox/locales/ko.json index b20f71120..a9ab32183 100644 --- a/app/soapbox/locales/ko.json +++ b/app/soapbox/locales/ko.json @@ -918,7 +918,7 @@ "settings.save.success": "Your preferences have been saved!", "settings.security": "Security", "settings.settings": "Settings", - "signup_panel.subtitle": "Sign up now to discuss.", + "signup_panel.subtitle": "Sign up now to discuss what's happening.", "signup_panel.title": "New to {site_title}?", "snackbar.view": "View", "soapbox_config.authenticated_profile_hint": "Users must be logged-in to view replies and media on user profiles.", diff --git a/app/soapbox/locales/lt.json b/app/soapbox/locales/lt.json index 1d17a0217..254da01b0 100644 --- a/app/soapbox/locales/lt.json +++ b/app/soapbox/locales/lt.json @@ -918,7 +918,7 @@ "settings.save.success": "Your preferences have been saved!", "settings.security": "Security", "settings.settings": "Settings", - "signup_panel.subtitle": "Sign up now to discuss.", + "signup_panel.subtitle": "Sign up now to discuss what's happening.", "signup_panel.title": "New to {site_title}?", "snackbar.view": "View", "soapbox_config.authenticated_profile_hint": "Users must be logged-in to view replies and media on user profiles.", diff --git a/app/soapbox/locales/lv.json b/app/soapbox/locales/lv.json index 7ef074895..042c3f9b5 100644 --- a/app/soapbox/locales/lv.json +++ b/app/soapbox/locales/lv.json @@ -918,7 +918,7 @@ "settings.save.success": "Your preferences have been saved!", "settings.security": "Security", "settings.settings": "Settings", - "signup_panel.subtitle": "Sign up now to discuss.", + "signup_panel.subtitle": "Sign up now to discuss what's happening.", "signup_panel.title": "New to {site_title}?", "snackbar.view": "View", "soapbox_config.authenticated_profile_hint": "Users must be logged-in to view replies and media on user profiles.", diff --git a/app/soapbox/locales/mk.json b/app/soapbox/locales/mk.json index 47a85960b..b4c6191d7 100644 --- a/app/soapbox/locales/mk.json +++ b/app/soapbox/locales/mk.json @@ -918,7 +918,7 @@ "settings.save.success": "Your preferences have been saved!", "settings.security": "Security", "settings.settings": "Settings", - "signup_panel.subtitle": "Sign up now to discuss.", + "signup_panel.subtitle": "Sign up now to discuss what's happening.", "signup_panel.title": "New to {site_title}?", "snackbar.view": "View", "soapbox_config.authenticated_profile_hint": "Users must be logged-in to view replies and media on user profiles.", diff --git a/app/soapbox/locales/ms.json b/app/soapbox/locales/ms.json index 648e7ae64..769b67da5 100644 --- a/app/soapbox/locales/ms.json +++ b/app/soapbox/locales/ms.json @@ -918,7 +918,7 @@ "settings.save.success": "Your preferences have been saved!", "settings.security": "Security", "settings.settings": "Settings", - "signup_panel.subtitle": "Sign up now to discuss.", + "signup_panel.subtitle": "Sign up now to discuss what's happening.", "signup_panel.title": "New to {site_title}?", "snackbar.view": "View", "soapbox_config.authenticated_profile_hint": "Users must be logged-in to view replies and media on user profiles.", diff --git a/app/soapbox/locales/nl.json b/app/soapbox/locales/nl.json index 7a44a73a4..c09a9cd4c 100644 --- a/app/soapbox/locales/nl.json +++ b/app/soapbox/locales/nl.json @@ -918,7 +918,7 @@ "settings.save.success": "Your preferences have been saved!", "settings.security": "Security", "settings.settings": "Settings", - "signup_panel.subtitle": "Sign up now to discuss.", + "signup_panel.subtitle": "Sign up now to discuss what's happening.", "signup_panel.title": "New to {site_title}?", "snackbar.view": "View", "soapbox_config.authenticated_profile_hint": "Users must be logged-in to view replies and media on user profiles.", diff --git a/app/soapbox/locales/nn.json b/app/soapbox/locales/nn.json index 6741b663c..3cd6f8580 100644 --- a/app/soapbox/locales/nn.json +++ b/app/soapbox/locales/nn.json @@ -918,7 +918,7 @@ "settings.save.success": "Your preferences have been saved!", "settings.security": "Security", "settings.settings": "Settings", - "signup_panel.subtitle": "Sign up now to discuss.", + "signup_panel.subtitle": "Sign up now to discuss what's happening.", "signup_panel.title": "New to {site_title}?", "snackbar.view": "View", "soapbox_config.authenticated_profile_hint": "Users must be logged-in to view replies and media on user profiles.", diff --git a/app/soapbox/locales/no.json b/app/soapbox/locales/no.json index 7a8748c5d..510051138 100644 --- a/app/soapbox/locales/no.json +++ b/app/soapbox/locales/no.json @@ -918,7 +918,7 @@ "settings.save.success": "Your preferences have been saved!", "settings.security": "Security", "settings.settings": "Settings", - "signup_panel.subtitle": "Sign up now to discuss.", + "signup_panel.subtitle": "Sign up now to discuss what's happening.", "signup_panel.title": "New to {site_title}?", "snackbar.view": "View", "soapbox_config.authenticated_profile_hint": "Users must be logged-in to view replies and media on user profiles.", diff --git a/app/soapbox/locales/oc.json b/app/soapbox/locales/oc.json index 7112f8a69..196046eb8 100644 --- a/app/soapbox/locales/oc.json +++ b/app/soapbox/locales/oc.json @@ -918,7 +918,7 @@ "settings.save.success": "Your preferences have been saved!", "settings.security": "Security", "settings.settings": "Settings", - "signup_panel.subtitle": "Sign up now to discuss.", + "signup_panel.subtitle": "Sign up now to discuss what's happening.", "signup_panel.title": "New to {site_title}?", "snackbar.view": "View", "soapbox_config.authenticated_profile_hint": "Users must be logged-in to view replies and media on user profiles.", diff --git a/app/soapbox/locales/pt-BR.json b/app/soapbox/locales/pt-BR.json index 9774c4217..d90f83475 100644 --- a/app/soapbox/locales/pt-BR.json +++ b/app/soapbox/locales/pt-BR.json @@ -918,7 +918,7 @@ "settings.save.success": "Your preferences have been saved!", "settings.security": "Security", "settings.settings": "Settings", - "signup_panel.subtitle": "Sign up now to discuss.", + "signup_panel.subtitle": "Sign up now to discuss what's happening.", "signup_panel.title": "New to {site_title}?", "snackbar.view": "View", "soapbox_config.authenticated_profile_hint": "Users must be logged-in to view replies and media on user profiles.", diff --git a/app/soapbox/locales/ro.json b/app/soapbox/locales/ro.json index 55801dc32..3442a9604 100644 --- a/app/soapbox/locales/ro.json +++ b/app/soapbox/locales/ro.json @@ -918,7 +918,7 @@ "settings.save.success": "Your preferences have been saved!", "settings.security": "Security", "settings.settings": "Settings", - "signup_panel.subtitle": "Sign up now to discuss.", + "signup_panel.subtitle": "Sign up now to discuss what's happening.", "signup_panel.title": "New to {site_title}?", "snackbar.view": "View", "soapbox_config.authenticated_profile_hint": "Users must be logged-in to view replies and media on user profiles.", diff --git a/app/soapbox/locales/ru.json b/app/soapbox/locales/ru.json index e86952800..29b0ebaa8 100644 --- a/app/soapbox/locales/ru.json +++ b/app/soapbox/locales/ru.json @@ -918,7 +918,7 @@ "settings.save.success": "Your preferences have been saved!", "settings.security": "Security", "settings.settings": "Settings", - "signup_panel.subtitle": "Sign up now to discuss.", + "signup_panel.subtitle": "Sign up now to discuss what's happening.", "signup_panel.title": "New to {site_title}?", "snackbar.view": "View", "soapbox_config.authenticated_profile_hint": "Users must be logged-in to view replies and media on user profiles.", diff --git a/app/soapbox/locales/sk.json b/app/soapbox/locales/sk.json index 426190804..26beae73a 100644 --- a/app/soapbox/locales/sk.json +++ b/app/soapbox/locales/sk.json @@ -918,7 +918,7 @@ "settings.save.success": "Your preferences have been saved!", "settings.security": "Security", "settings.settings": "Settings", - "signup_panel.subtitle": "Sign up now to discuss.", + "signup_panel.subtitle": "Sign up now to discuss what's happening.", "signup_panel.title": "New to {site_title}?", "snackbar.view": "View", "soapbox_config.authenticated_profile_hint": "Users must be logged-in to view replies and media on user profiles.", diff --git a/app/soapbox/locales/sl.json b/app/soapbox/locales/sl.json index fe61bad97..6bfe49a5c 100644 --- a/app/soapbox/locales/sl.json +++ b/app/soapbox/locales/sl.json @@ -918,7 +918,7 @@ "settings.save.success": "Your preferences have been saved!", "settings.security": "Security", "settings.settings": "Settings", - "signup_panel.subtitle": "Sign up now to discuss.", + "signup_panel.subtitle": "Sign up now to discuss what's happening.", "signup_panel.title": "New to {site_title}?", "snackbar.view": "View", "soapbox_config.authenticated_profile_hint": "Users must be logged-in to view replies and media on user profiles.", diff --git a/app/soapbox/locales/sq.json b/app/soapbox/locales/sq.json index 16a2607e3..722aac280 100644 --- a/app/soapbox/locales/sq.json +++ b/app/soapbox/locales/sq.json @@ -918,7 +918,7 @@ "settings.save.success": "Your preferences have been saved!", "settings.security": "Security", "settings.settings": "Settings", - "signup_panel.subtitle": "Sign up now to discuss.", + "signup_panel.subtitle": "Sign up now to discuss what's happening.", "signup_panel.title": "New to {site_title}?", "snackbar.view": "View", "soapbox_config.authenticated_profile_hint": "Users must be logged-in to view replies and media on user profiles.", diff --git a/app/soapbox/locales/sr-Latn.json b/app/soapbox/locales/sr-Latn.json index 1d5f9fa2b..518eae7b7 100644 --- a/app/soapbox/locales/sr-Latn.json +++ b/app/soapbox/locales/sr-Latn.json @@ -918,7 +918,7 @@ "settings.save.success": "Your preferences have been saved!", "settings.security": "Security", "settings.settings": "Settings", - "signup_panel.subtitle": "Sign up now to discuss.", + "signup_panel.subtitle": "Sign up now to discuss what's happening.", "signup_panel.title": "New to {site_title}?", "snackbar.view": "View", "soapbox_config.authenticated_profile_hint": "Users must be logged-in to view replies and media on user profiles.", diff --git a/app/soapbox/locales/sr.json b/app/soapbox/locales/sr.json index c8a3e5e2f..8725a6fe1 100644 --- a/app/soapbox/locales/sr.json +++ b/app/soapbox/locales/sr.json @@ -918,7 +918,7 @@ "settings.save.success": "Your preferences have been saved!", "settings.security": "Security", "settings.settings": "Settings", - "signup_panel.subtitle": "Sign up now to discuss.", + "signup_panel.subtitle": "Sign up now to discuss what's happening.", "signup_panel.title": "New to {site_title}?", "snackbar.view": "View", "soapbox_config.authenticated_profile_hint": "Users must be logged-in to view replies and media on user profiles.", diff --git a/app/soapbox/locales/sv.json b/app/soapbox/locales/sv.json index 159e68c6d..ed28fcba4 100644 --- a/app/soapbox/locales/sv.json +++ b/app/soapbox/locales/sv.json @@ -918,7 +918,7 @@ "settings.save.success": "Your preferences have been saved!", "settings.security": "Security", "settings.settings": "Settings", - "signup_panel.subtitle": "Sign up now to discuss.", + "signup_panel.subtitle": "Sign up now to discuss what's happening.", "signup_panel.title": "New to {site_title}?", "snackbar.view": "View", "soapbox_config.authenticated_profile_hint": "Users must be logged-in to view replies and media on user profiles.", diff --git a/app/soapbox/locales/ta.json b/app/soapbox/locales/ta.json index 12d86c89c..90e58bd13 100644 --- a/app/soapbox/locales/ta.json +++ b/app/soapbox/locales/ta.json @@ -918,7 +918,7 @@ "settings.save.success": "Your preferences have been saved!", "settings.security": "Security", "settings.settings": "Settings", - "signup_panel.subtitle": "Sign up now to discuss.", + "signup_panel.subtitle": "Sign up now to discuss what's happening.", "signup_panel.title": "New to {site_title}?", "snackbar.view": "View", "soapbox_config.authenticated_profile_hint": "Users must be logged-in to view replies and media on user profiles.", diff --git a/app/soapbox/locales/te.json b/app/soapbox/locales/te.json index b9a80ad41..b4d372902 100644 --- a/app/soapbox/locales/te.json +++ b/app/soapbox/locales/te.json @@ -918,7 +918,7 @@ "settings.save.success": "Your preferences have been saved!", "settings.security": "Security", "settings.settings": "Settings", - "signup_panel.subtitle": "Sign up now to discuss.", + "signup_panel.subtitle": "Sign up now to discuss what's happening.", "signup_panel.title": "New to {site_title}?", "snackbar.view": "View", "soapbox_config.authenticated_profile_hint": "Users must be logged-in to view replies and media on user profiles.", diff --git a/app/soapbox/locales/th.json b/app/soapbox/locales/th.json index c00ee7627..2964c4d94 100644 --- a/app/soapbox/locales/th.json +++ b/app/soapbox/locales/th.json @@ -918,7 +918,7 @@ "settings.save.success": "Your preferences have been saved!", "settings.security": "Security", "settings.settings": "Settings", - "signup_panel.subtitle": "Sign up now to discuss.", + "signup_panel.subtitle": "Sign up now to discuss what's happening.", "signup_panel.title": "New to {site_title}?", "snackbar.view": "View", "soapbox_config.authenticated_profile_hint": "Users must be logged-in to view replies and media on user profiles.", diff --git a/app/soapbox/locales/tr.json b/app/soapbox/locales/tr.json index b624d629f..f124d7083 100644 --- a/app/soapbox/locales/tr.json +++ b/app/soapbox/locales/tr.json @@ -918,7 +918,7 @@ "settings.save.success": "Your preferences have been saved!", "settings.security": "Security", "settings.settings": "Settings", - "signup_panel.subtitle": "Sign up now to discuss.", + "signup_panel.subtitle": "Sign up now to discuss what's happening.", "signup_panel.title": "New to {site_title}?", "snackbar.view": "View", "soapbox_config.authenticated_profile_hint": "Users must be logged-in to view replies and media on user profiles.", diff --git a/app/soapbox/locales/uk.json b/app/soapbox/locales/uk.json index 8c4005ce3..a3bcffeea 100644 --- a/app/soapbox/locales/uk.json +++ b/app/soapbox/locales/uk.json @@ -918,7 +918,7 @@ "settings.save.success": "Your preferences have been saved!", "settings.security": "Security", "settings.settings": "Settings", - "signup_panel.subtitle": "Sign up now to discuss.", + "signup_panel.subtitle": "Sign up now to discuss what's happening.", "signup_panel.title": "New to {site_title}?", "snackbar.view": "View", "soapbox_config.authenticated_profile_hint": "Users must be logged-in to view replies and media on user profiles.", diff --git a/app/soapbox/locales/zh-HK.json b/app/soapbox/locales/zh-HK.json index 877ecfcff..4ca62018a 100644 --- a/app/soapbox/locales/zh-HK.json +++ b/app/soapbox/locales/zh-HK.json @@ -918,7 +918,7 @@ "settings.save.success": "Your preferences have been saved!", "settings.security": "Security", "settings.settings": "Settings", - "signup_panel.subtitle": "Sign up now to discuss.", + "signup_panel.subtitle": "Sign up now to discuss what's happening.", "signup_panel.title": "New to {site_title}?", "snackbar.view": "View", "soapbox_config.authenticated_profile_hint": "Users must be logged-in to view replies and media on user profiles.", diff --git a/app/soapbox/locales/zh-TW.json b/app/soapbox/locales/zh-TW.json index 414c297e3..de4a3b347 100644 --- a/app/soapbox/locales/zh-TW.json +++ b/app/soapbox/locales/zh-TW.json @@ -918,7 +918,7 @@ "settings.save.success": "Your preferences have been saved!", "settings.security": "Security", "settings.settings": "Settings", - "signup_panel.subtitle": "Sign up now to discuss.", + "signup_panel.subtitle": "Sign up now to discuss what's happening.", "signup_panel.title": "New to {site_title}?", "snackbar.view": "View", "soapbox_config.authenticated_profile_hint": "Users must be logged-in to view replies and media on user profiles.",