diff --git a/app/javascript/mastodon/features/compose/redesign/header.tsx b/app/javascript/mastodon/features/compose/redesign/header.tsx
index aab54ebd41d..5eb27639973 100644
--- a/app/javascript/mastodon/features/compose/redesign/header.tsx
+++ b/app/javascript/mastodon/features/compose/redesign/header.tsx
@@ -3,7 +3,6 @@ import { useCallback } from 'react';
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
import { ArrowsOutSimpleIcon, MinusIcon, XIcon } from '@phosphor-icons/react';
-import { ReadCvLogoIcon } from '@phosphor-icons/react/dist/ssr';
import { IconButton } from '@/mastodon/components/button/redesign';
import {
@@ -17,8 +16,6 @@ import {
useAppSelector,
} from '@/mastodon/store';
-import { useBreakpoint } from '../../ui/hooks/useBreakpoint';
-
import { selectComposeType } from './selectors';
import classes from './styles.module.scss';
@@ -73,27 +70,18 @@ export const ComposeFormHeader: React.FC<{
noMinimize?: boolean;
}> = ({ id, noMinimize }) => {
const intl = useIntl();
+ const dispatch = useAppDispatch();
const titleMessage = useAppSelector(selectComposeFormTitle);
const isMinimized = useAppSelector(selectIsMinimized);
- const dispatch = useAppDispatch();
const onClose = useCallback(() => {
dispatch(closeComposer());
}, [dispatch]);
+
const onMinimize = useCallback(() => {
dispatch(minimizeComposerToggle());
}, [dispatch]);
- const isMobile = useBreakpoint('openable');
-
- if (isMobile && isMinimized && !noMinimize) {
- return (
-
-
-
- );
- }
-
return (
{intl.formatMessage(titleMessage)}
diff --git a/app/javascript/mastodon/features/compose/redesign/trigger.module.scss b/app/javascript/mastodon/features/compose/redesign/trigger.module.scss
index 2ed05078571..61045f66ab2 100644
--- a/app/javascript/mastodon/features/compose/redesign/trigger.module.scss
+++ b/app/javascript/mastodon/features/compose/redesign/trigger.module.scss
@@ -1,7 +1,13 @@
@use '@/styles/mastodon/variables';
-.button {
- &:not(.buttonInline) {
+.buttonWrapper {
+ position: relative;
+
+ @media (prefers-reduced-motion: no-preference) {
+ transition: all 200ms ease-out;
+ }
+
+ &:not(.buttonWrapperInline) {
position: fixed;
bottom: var(--space-4);
right: var(--space-4);
@@ -9,6 +15,12 @@
}
}
+.buttonWrapperHidden {
+ transform: translateX(calc(100% + var(--space-4)));
+ opacity: 0;
+ transition-timing-function: ease-in;
+}
+
.composer,
.composerMinimized {
position: fixed;
diff --git a/app/javascript/mastodon/features/compose/redesign/trigger.tsx b/app/javascript/mastodon/features/compose/redesign/trigger.tsx
index 4764093a48e..0e99a16b7fc 100644
--- a/app/javascript/mastodon/features/compose/redesign/trigger.tsx
+++ b/app/javascript/mastodon/features/compose/redesign/trigger.tsx
@@ -4,13 +4,16 @@ import { lazy, Suspense, useCallback, useEffect, useState } from 'react';
import { FormattedMessage } from 'react-intl';
import classNames from 'classnames';
+import { useRouteMatch } from 'react-router';
import {
ChatCircleDotsIcon,
NewspaperIcon,
PenNibIcon,
+ ReadCvLogoIcon,
} from '@phosphor-icons/react';
+import type { IconButtonProps } from '@/mastodon/components/button/redesign';
import { IconButton } from '@/mastodon/components/button/redesign';
import {
Menu,
@@ -20,10 +23,15 @@ import {
} from '@/mastodon/components/menu';
import { MenuCard } from '@/mastodon/components/menu/card';
import { useIdentity } from '@/mastodon/identity_context';
-import { openNewComposer } from '@/mastodon/reducers/slices/composer';
+import {
+ minimizeComposerToggle,
+ openNewComposer,
+} from '@/mastodon/reducers/slices/composer';
import { useAppDispatch, useAppSelector } from '@/mastodon/store';
import { isRedesignEnabled } from '@/mastodon/utils/environment';
+import { useBreakpoint } from '../../ui/hooks/useBreakpoint';
+
import { ComposeFormHeader } from './header';
import classes from './trigger.module.scss';
@@ -38,8 +46,13 @@ export const ComposeRedesignButton: React.FC<{
* Render the button in regular document flow instead of fixed positioning for mobile layout
*/
inline?: boolean;
-}> = ({ inline }) => {
+}> = ({ inline = false }) => {
const displayState = useAppSelector((state) => state.composer.displayState);
+ const isMobile = useBreakpoint('openable');
+
+ const hasMobileFloatingActionButton = useHasMobileFloatingActionButton({
+ isMobile,
+ });
// Update viewport based on visual size in order to account for the virtual keyboard.
const [viewportHeight, setViewportHeight] = useState(null);
@@ -69,14 +82,32 @@ export const ComposeRedesignButton: React.FC<{
[dispatch],
);
+ const toggleMinimize = useCallback(() => {
+ dispatch(minimizeComposerToggle());
+ }, [dispatch]);
+
const { signedIn } = useIdentity();
if (!isRedesignEnabled() || !signedIn) {
return null;
}
+ const floatingButtonProps = {
+ inline,
+ hidden: !hasMobileFloatingActionButton,
+ } as const;
+
if (displayState === 'minimized') {
- return (
+ return isMobile ? (
+
+
+
+ ) : (
@@ -91,21 +122,16 @@ export const ComposeRedesignButton: React.FC<{
return (
-
+
}
>
@@ -116,11 +142,9 @@ export const ComposeRedesignButton: React.FC<{
return (