From 28b3695b6bcc8eb53e7b7bd443dfc3383d91dade Mon Sep 17 00:00:00 2001 From: Echo Date: Wed, 9 Sep 2026 11:23:44 +0000 Subject: [PATCH] Composer redesign: Private replies (#40435) --- .../features/compose/redesign/header.tsx | 10 ++++- .../features/compose/redesign/index.tsx | 4 +- .../features/compose/redesign/selectors.ts | 19 ++++++---- .../features/compose/redesign/visibility.tsx | 37 ++++++++++++++----- app/javascript/mastodon/locales/en.json | 6 ++- .../mastodon/reducers/slices/composer.ts | 2 +- 6 files changed, 58 insertions(+), 20 deletions(-) diff --git a/app/javascript/mastodon/features/compose/redesign/header.tsx b/app/javascript/mastodon/features/compose/redesign/header.tsx index 3ea207d2b6b..aab54ebd41d 100644 --- a/app/javascript/mastodon/features/compose/redesign/header.tsx +++ b/app/javascript/mastodon/features/compose/redesign/header.tsx @@ -36,9 +36,17 @@ const messages = defineMessages({ defaultMessage: 'New reply', }, replyEdit: { - id: 'compose_form.reply.title.edit', + id: 'compose.reply.title.edit', defaultMessage: 'Edit reply', }, + replyPrivateNew: { + id: 'compose.reply_private.title.new', + defaultMessage: 'New private reply', + }, + replyPrivateEdit: { + id: 'compose.reply_private.title.edit', + defaultMessage: 'Edit private reply', + }, messageNew: { id: 'compose_form.message.title.new', defaultMessage: 'New message', diff --git a/app/javascript/mastodon/features/compose/redesign/index.tsx b/app/javascript/mastodon/features/compose/redesign/index.tsx index 2ea9bac3ca6..8220a3f1263 100644 --- a/app/javascript/mastodon/features/compose/redesign/index.tsx +++ b/app/javascript/mastodon/features/compose/redesign/index.tsx @@ -72,7 +72,9 @@ export const RedesignComposeForm: React.FC< aria-labelledby={titleId} className={classNames(className, classes.root)} > - {type === 'message' &&
} + {(type === 'message' || type === 'replyPrivate') && ( +
+ )} diff --git a/app/javascript/mastodon/features/compose/redesign/selectors.ts b/app/javascript/mastodon/features/compose/redesign/selectors.ts index 0b9f6da112f..7fd2a47062b 100644 --- a/app/javascript/mastodon/features/compose/redesign/selectors.ts +++ b/app/javascript/mastodon/features/compose/redesign/selectors.ts @@ -22,15 +22,20 @@ export const selectComposeType = createAppSelector( (state) => state.compose.get('in_reply_to') as string | null, selectComposePrivacy, ], - (inReplyToId, privacy) => { - let type: ComposeType = 'post'; - if (inReplyToId) { - type = 'reply'; - } else if (privacy === 'direct') { - type = 'message'; + (inReplyToId, privacy): ComposeType => { + if (inReplyToId && privacy === 'direct') { + return 'replyPrivate'; } - return type; + if (privacy === 'direct') { + return 'message'; + } + + if (inReplyToId) { + return 'reply'; + } + + return 'post'; }, ); diff --git a/app/javascript/mastodon/features/compose/redesign/visibility.tsx b/app/javascript/mastodon/features/compose/redesign/visibility.tsx index 6217ede6a13..9034927a0fb 100644 --- a/app/javascript/mastodon/features/compose/redesign/visibility.tsx +++ b/app/javascript/mastodon/features/compose/redesign/visibility.tsx @@ -112,6 +112,8 @@ const ComposeVisibilityMenu: React.FC = () => { ); const quotePolicy = currentQuotePolicy ?? defaultQuotePolicy; + const isReply = useAppSelector((state) => !!state.compose.get('in_reply_to')); + const dispatch = useAppDispatch(); const handlePrivacyChange = useCallback( ({ value }: { value: string }) => { @@ -131,6 +133,7 @@ const ComposeVisibilityMenu: React.FC = () => { }, [defaultPrivacy, dispatch, privacy], ); + const handleQuotePolicyChange = useCallback( ({ value, checked }: { value: string; checked?: boolean }) => { let newQuotePolicy: ApiQuotePolicy = 'nobody'; @@ -264,11 +267,18 @@ const ComposeVisibilityMenu: React.FC = () => { - + {isReply ? ( + + ) : ( + + )} ); @@ -283,6 +293,8 @@ const ComposeDirectMenu: React.FC = () => { ); }, [dispatch]); + const isReply = useAppSelector((state) => !!state.compose.get('in_reply_to')); + return ( { - + {isReply ? ( + + ) : ( + + )} ); diff --git a/app/javascript/mastodon/locales/en.json b/app/javascript/mastodon/locales/en.json index eafe7d98635..9c4c4990a3e 100644 --- a/app/javascript/mastodon/locales/en.json +++ b/app/javascript/mastodon/locales/en.json @@ -537,6 +537,7 @@ "compose.post.title.new": "New post", "compose.post.to": "To:", "compose.post.to_message": "Compose a message instead", + "compose.post.to_private_reply": "Reply privately instead", "compose.publish": "Publish", "compose.published.body": "Post published.", "compose.published.open": "Open", @@ -554,7 +555,10 @@ "compose.rearrange_modal.handle": "Drag attachment at position {index, number}", "compose.rearrange_modal.save": "Save", "compose.rearrange_modal.title": "Rearrange media", + "compose.reply.title.edit": "Edit reply", "compose.reply.title.new": "New reply", + "compose.reply_private.title.edit": "Edit private reply", + "compose.reply_private.title.new": "New private reply", "compose.saved.body": "Post saved.", "compose.sensitive": "Sensitive", "compose.sensitive.text": "Sensitive content description", @@ -575,6 +579,7 @@ "compose.visibility.quote_policy.followers": "Followers", "compose.visibility.title": "Visibility", "compose.visibility.to_post": "Compose a post instead", + "compose.visibility.to_reply": "Reply publicly instead", "compose_form.direct_message_warning_learn_more": "Learn more", "compose_form.encryption_warning": "Posts on Mastodon are not end-to-end encrypted. Do not share any sensitive information over Mastodon.", "compose_form.hashtag_warning": "This post won't be listed under any hashtag as it is not public. Only public posts can be searched by hashtag.", @@ -592,7 +597,6 @@ "compose_form.poll.type": "Style", "compose_form.publish": "Post", "compose_form.reply": "Reply", - "compose_form.reply.title.edit": "Edit reply", "compose_form.save_changes": "Update", "compose_form.spoiler.marked": "Remove content warning", "compose_form.spoiler.unmarked": "Add content warning", diff --git a/app/javascript/mastodon/reducers/slices/composer.ts b/app/javascript/mastodon/reducers/slices/composer.ts index 04d180844b4..8bbf318996f 100644 --- a/app/javascript/mastodon/reducers/slices/composer.ts +++ b/app/javascript/mastodon/reducers/slices/composer.ts @@ -52,7 +52,7 @@ export function focusComposerTextarea(defer = false) { type DisplayState = 'hidden' | 'showing' | 'minimized'; -export type ComposeType = 'post' | 'message' | 'reply'; +export type ComposeType = 'post' | 'message' | 'reply' | 'replyPrivate'; interface ComposerState { displayState: DisplayState;