diff --git a/app/javascript/mastodon/features/ui/components/columns_area.jsx b/app/javascript/mastodon/features/ui/components/columns_area.jsx index 9737d31e31b..1b882a1c550 100644 --- a/app/javascript/mastodon/features/ui/components/columns_area.jsx +++ b/app/javascript/mastodon/features/ui/components/columns_area.jsx @@ -23,7 +23,7 @@ import { useColumnsContext } from '../util/columns_context'; import BundleColumnError from './bundle_column_error'; import { ColumnLoading } from './column_loading'; -import { ComposePanel } from './compose_panel'; +import { ComposePanel, RedirectToMobileComposeIfNeeded } from './compose_panel'; import DrawerLoading from './drawer_loading'; import { NavigationPanel } from 'mastodon/features/navigation_panel'; @@ -124,6 +124,7 @@ export default class ColumnsArea extends ImmutablePureComponent {
{renderComposePanel && } +
diff --git a/app/javascript/mastodon/features/ui/components/compose_panel.tsx b/app/javascript/mastodon/features/ui/components/compose_panel.tsx index aa155203095..cc55ff4cef6 100644 --- a/app/javascript/mastodon/features/ui/components/compose_panel.tsx +++ b/app/javascript/mastodon/features/ui/components/compose_panel.tsx @@ -1,4 +1,4 @@ -import { useCallback, useEffect } from 'react'; +import { useCallback, useEffect, useLayoutEffect } from 'react'; import { useLayout } from '@/mastodon/hooks/useLayout'; import { useAppDispatch, useAppSelector } from '@/mastodon/store'; @@ -7,6 +7,7 @@ import { mountCompose, unmountCompose, } from 'mastodon/actions/compose'; +import { useAppHistory } from 'mastodon/components/router'; import ServerBanner from 'mastodon/components/server_banner'; import { Search } from 'mastodon/features/compose/components/search'; import ComposeFormContainer from 'mastodon/features/compose/containers/compose_form_container'; @@ -54,3 +55,25 @@ export const ComposePanel: React.FC = () => { ); }; + +/** + * Redirect the user to the standalone compose page when the + * sidebar composer is hidden due to a change in viewport size + * while a post is being written. + */ + +export const RedirectToMobileComposeIfNeeded: React.FC = () => { + const history = useAppHistory(); + + const shouldRedirect = useAppSelector((state) => + state.compose.get('should_redirect_to_compose_page'), + ); + + useLayoutEffect(() => { + if (shouldRedirect) { + history.push('/publish'); + } + }, [history, shouldRedirect]); + + return null; +}; diff --git a/app/javascript/mastodon/reducers/compose.js b/app/javascript/mastodon/reducers/compose.js index 330dcd93d09..6b799a46e80 100644 --- a/app/javascript/mastodon/reducers/compose.js +++ b/app/javascript/mastodon/reducers/compose.js @@ -68,6 +68,7 @@ const initialState = ImmutableMap({ is_submitting: false, is_changing_upload: false, is_uploading: false, + should_redirect_to_compose_page: false, progress: 0, isUploadingThumbnail: false, thumbnailProgress: 0, @@ -322,11 +323,21 @@ export const composeReducer = (state = initialState, action) => { case STORE_HYDRATE: return hydrate(state, action.state.get('compose')); case COMPOSE_MOUNT: - return state.set('mounted', state.get('mounted') + 1); + return state + .set('mounted', state.get('mounted') + 1) + .set('should_redirect_to_compose_page', false); case COMPOSE_UNMOUNT: return state .set('mounted', Math.max(state.get('mounted') - 1, 0)) - .set('is_composing', false); + .set('is_composing', false) + .set( + 'should_redirect_to_compose_page', + (state.get('mounted') === 1 && + state.get('is_composing') === true && + (state.get('text').trim() !== '' || + state.get('media_attachments').size > 0) + ) + ); case COMPOSE_SENSITIVITY_CHANGE: return state.withMutations(map => { if (!state.get('spoiler')) {