From 6166e616389b051039dc76635048e2519271832a Mon Sep 17 00:00:00 2001 From: diondiondion Date: Mon, 23 Jun 2025 11:53:21 +0200 Subject: [PATCH] fix: Keep user on Compose page when changing screen size, #34937 (#35105) --- .../features/ui/components/columns_area.jsx | 3 ++- .../features/ui/components/compose_panel.tsx | 25 ++++++++++++++++++- app/javascript/mastodon/reducers/compose.js | 15 +++++++++-- 3 files changed, 39 insertions(+), 4 deletions(-) diff --git a/app/javascript/mastodon/features/ui/components/columns_area.jsx b/app/javascript/mastodon/features/ui/components/columns_area.jsx index 9737d31e3..1b882a1c5 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 aa1552030..cc55ff4ce 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 330dcd93d..6b799a46e 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')) {