diff options
author | dan <dan.abramov@gmail.com> | 2024-11-17 03:15:03 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-11-17 03:15:03 +0000 |
commit | e9fe8d90ef5e9ca2ed4bc9649794c5288fb1232d (patch) | |
tree | d82ee539096112cfdaa4602719a208f2715c1998 /src | |
parent | ddf2a64a7287ee737099844b6885f9ceb8f65f75 (diff) | |
download | voidsky-e9fe8d90ef5e9ca2ed4bc9649794c5288fb1232d.tar.zst |
Render dropdown menu items lazily (#6437)
Diffstat (limited to 'src')
-rw-r--r-- | src/view/com/util/forms/PostDropdownBtn.tsx | 587 |
1 files changed, 309 insertions, 278 deletions
diff --git a/src/view/com/util/forms/PostDropdownBtn.tsx b/src/view/com/util/forms/PostDropdownBtn.tsx index 1cd4841a5..e71332279 100644 --- a/src/view/com/util/forms/PostDropdownBtn.tsx +++ b/src/view/com/util/forms/PostDropdownBtn.tsx @@ -102,12 +102,77 @@ let PostDropdownBtn = ({ timestamp: string threadgateRecord?: AppBskyFeedThreadgate.Record }): React.ReactNode => { - const {hasSession, currentAccount} = useSession() const theme = useTheme() const alf = useAlf() - const {gtMobile} = useBreakpoints() const {_} = useLingui() const defaultCtrlColor = theme.palette.default.postCtrl + return ( + <EventStopper onKeyDown={false}> + <Menu.Root> + <Menu.Trigger label={_(msg`Open post options menu`)}> + {({props, state}) => { + return ( + <Pressable + {...props} + hitSlop={hitSlop} + testID={testID} + style={[ + style, + a.rounded_full, + (state.hovered || state.pressed) && [ + alf.atoms.bg_contrast_25, + ], + ]}> + <DotsHorizontal + fill={defaultCtrlColor} + style={{pointerEvents: 'none'}} + size={size} + /> + </Pressable> + ) + }} + </Menu.Trigger> + <Menu.Outer> + <PostDropdownMenuItems + testID={testID} + post={post} + postFeedContext={postFeedContext} + record={record} + richText={richText} + timestamp={timestamp} + threadgateRecord={threadgateRecord} + /> + </Menu.Outer> + </Menu.Root> + </EventStopper> + ) +} + +PostDropdownBtn = memo(PostDropdownBtn) +export {PostDropdownBtn} + +let PostDropdownMenuItems = ({ + post, + postFeedContext, + record, + richText, + timestamp, + threadgateRecord, +}: { + testID: string + post: Shadow<AppBskyFeedDefs.PostView> + postFeedContext: string | undefined + record: AppBskyFeedPost.Record + richText: RichTextAPI + style?: StyleProp<ViewStyle> + hitSlop?: PressableProps['hitSlop'] + size?: 'lg' | 'md' | 'sm' + timestamp: string + threadgateRecord?: AppBskyFeedThreadgate.Record +}): React.ReactNode => { + const {hasSession, currentAccount} = useSession() + const {gtMobile} = useBreakpoints() + const {_} = useLingui() const langPrefs = useLanguagePrefs() const {mutateAsync: deletePostMutate} = usePostDeleteMutation() const {mutateAsync: pinPostMutate, isPending: isPinPending} = @@ -360,308 +425,276 @@ let PostDropdownBtn = ({ }, [isPinned, pinPostMutate, postCid, postUri]) return ( - <EventStopper onKeyDown={false}> - <Menu.Root> - <Menu.Trigger label={_(msg`Open post options menu`)}> - {({props, state}) => { - return ( - <Pressable - {...props} - hitSlop={hitSlop} - testID={testID} - style={[ - style, - a.rounded_full, - (state.hovered || state.pressed) && [ - alf.atoms.bg_contrast_25, - ], - ]}> - <DotsHorizontal - fill={defaultCtrlColor} - style={{pointerEvents: 'none'}} - size={size} - /> - </Pressable> - ) - }} - </Menu.Trigger> + <> + {isAuthor && ( + <> + <Menu.Group> + <Menu.Item + testID="pinPostBtn" + label={ + isPinned + ? _(msg`Unpin from profile`) + : _(msg`Pin to your profile`) + } + disabled={isPinPending} + onPress={onPressPin}> + <Menu.ItemText> + {isPinned + ? _(msg`Unpin from profile`) + : _(msg`Pin to your profile`)} + </Menu.ItemText> + <Menu.ItemIcon + icon={isPinPending ? Loader : PinIcon} + position="right" + /> + </Menu.Item> + </Menu.Group> + <Menu.Divider /> + </> + )} - <Menu.Outer> - {isAuthor && ( - <> - <Menu.Group> - <Menu.Item - testID="pinPostBtn" - label={ - isPinned - ? _(msg`Unpin from profile`) - : _(msg`Pin to your profile`) - } - disabled={isPinPending} - onPress={onPressPin}> - <Menu.ItemText> - {isPinned - ? _(msg`Unpin from profile`) - : _(msg`Pin to your profile`)} - </Menu.ItemText> - <Menu.ItemIcon - icon={isPinPending ? Loader : PinIcon} - position="right" - /> - </Menu.Item> - </Menu.Group> - <Menu.Divider /> - </> - )} + <Menu.Group> + {(!hideInPWI || hasSession) && ( + <> + <Menu.Item + testID="postDropdownTranslateBtn" + label={_(msg`Translate`)} + onPress={onPressTranslate}> + <Menu.ItemText>{_(msg`Translate`)}</Menu.ItemText> + <Menu.ItemIcon icon={Translate} position="right" /> + </Menu.Item> - <Menu.Group> - {(!hideInPWI || hasSession) && ( - <> - <Menu.Item - testID="postDropdownTranslateBtn" - label={_(msg`Translate`)} - onPress={onPressTranslate}> - <Menu.ItemText>{_(msg`Translate`)}</Menu.ItemText> - <Menu.ItemIcon icon={Translate} position="right" /> - </Menu.Item> + <Menu.Item + testID="postDropdownCopyTextBtn" + label={_(msg`Copy post text`)} + onPress={onCopyPostText}> + <Menu.ItemText>{_(msg`Copy post text`)}</Menu.ItemText> + <Menu.ItemIcon icon={ClipboardIcon} position="right" /> + </Menu.Item> + </> + )} - <Menu.Item - testID="postDropdownCopyTextBtn" - label={_(msg`Copy post text`)} - onPress={onCopyPostText}> - <Menu.ItemText>{_(msg`Copy post text`)}</Menu.ItemText> - <Menu.ItemIcon icon={ClipboardIcon} position="right" /> - </Menu.Item> - </> - )} + {hasSession && ( + <Menu.Item + testID="postDropdownSendViaDMBtn" + label={_(msg`Send via direct message`)} + onPress={() => sendViaChatControl.open()}> + <Menu.ItemText> + <Trans>Send via direct message</Trans> + </Menu.ItemText> + <Menu.ItemIcon icon={Send} position="right" /> + </Menu.Item> + )} - {hasSession && ( - <Menu.Item - testID="postDropdownSendViaDMBtn" - label={_(msg`Send via direct message`)} - onPress={() => sendViaChatControl.open()}> - <Menu.ItemText> - <Trans>Send via direct message</Trans> - </Menu.ItemText> - <Menu.ItemIcon icon={Send} position="right" /> - </Menu.Item> - )} + <Menu.Item + testID="postDropdownShareBtn" + label={isWeb ? _(msg`Copy link to post`) : _(msg`Share`)} + onPress={() => { + if (showLoggedOutWarning) { + loggedOutWarningPromptControl.open() + } else { + onSharePost() + } + }}> + <Menu.ItemText> + {isWeb ? _(msg`Copy link to post`) : _(msg`Share`)} + </Menu.ItemText> + <Menu.ItemIcon icon={Share} position="right" /> + </Menu.Item> + + {canEmbed && ( + <Menu.Item + testID="postDropdownEmbedBtn" + label={_(msg`Embed post`)} + onPress={() => embedPostControl.open()}> + <Menu.ItemText>{_(msg`Embed post`)}</Menu.ItemText> + <Menu.ItemIcon icon={CodeBrackets} position="right" /> + </Menu.Item> + )} + </Menu.Group> + + {hasSession && feedFeedback.enabled && ( + <> + <Menu.Divider /> + <Menu.Group> + <Menu.Item + testID="postDropdownShowMoreBtn" + label={_(msg`Show more like this`)} + onPress={onPressShowMore}> + <Menu.ItemText>{_(msg`Show more like this`)}</Menu.ItemText> + <Menu.ItemIcon icon={EmojiSmile} position="right" /> + </Menu.Item> <Menu.Item - testID="postDropdownShareBtn" - label={isWeb ? _(msg`Copy link to post`) : _(msg`Share`)} - onPress={() => { - if (showLoggedOutWarning) { - loggedOutWarningPromptControl.open() - } else { - onSharePost() - } - }}> + testID="postDropdownShowLessBtn" + label={_(msg`Show less like this`)} + onPress={onPressShowLess}> + <Menu.ItemText>{_(msg`Show less like this`)}</Menu.ItemText> + <Menu.ItemIcon icon={EmojiSad} position="right" /> + </Menu.Item> + </Menu.Group> + </> + )} + + {hasSession && ( + <> + <Menu.Divider /> + <Menu.Group> + <Menu.Item + testID="postDropdownMuteThreadBtn" + label={ + isThreadMuted ? _(msg`Unmute thread`) : _(msg`Mute thread`) + } + onPress={onToggleThreadMute}> <Menu.ItemText> - {isWeb ? _(msg`Copy link to post`) : _(msg`Share`)} + {isThreadMuted ? _(msg`Unmute thread`) : _(msg`Mute thread`)} </Menu.ItemText> - <Menu.ItemIcon icon={Share} position="right" /> + <Menu.ItemIcon + icon={isThreadMuted ? Unmute : Mute} + position="right" + /> </Menu.Item> - {canEmbed && ( - <Menu.Item - testID="postDropdownEmbedBtn" - label={_(msg`Embed post`)} - onPress={() => embedPostControl.open()}> - <Menu.ItemText>{_(msg`Embed post`)}</Menu.ItemText> - <Menu.ItemIcon icon={CodeBrackets} position="right" /> - </Menu.Item> - )} + <Menu.Item + testID="postDropdownMuteWordsBtn" + label={_(msg`Mute words & tags`)} + onPress={() => mutedWordsDialogControl.open()}> + <Menu.ItemText>{_(msg`Mute words & tags`)}</Menu.ItemText> + <Menu.ItemIcon icon={Filter} position="right" /> + </Menu.Item> </Menu.Group> + </> + )} - {hasSession && feedFeedback.enabled && ( - <> - <Menu.Divider /> - <Menu.Group> - <Menu.Item - testID="postDropdownShowMoreBtn" - label={_(msg`Show more like this`)} - onPress={onPressShowMore}> - <Menu.ItemText>{_(msg`Show more like this`)}</Menu.ItemText> - <Menu.ItemIcon icon={EmojiSmile} position="right" /> - </Menu.Item> - + {hasSession && + (canHideReplyForEveryone || canDetachQuote || canHidePostForMe) && ( + <> + <Menu.Divider /> + <Menu.Group> + {canHidePostForMe && ( <Menu.Item - testID="postDropdownShowLessBtn" - label={_(msg`Show less like this`)} - onPress={onPressShowLess}> - <Menu.ItemText>{_(msg`Show less like this`)}</Menu.ItemText> - <Menu.ItemIcon icon={EmojiSad} position="right" /> + testID="postDropdownHideBtn" + label={ + isReply + ? _(msg`Hide reply for me`) + : _(msg`Hide post for me`) + } + onPress={() => hidePromptControl.open()}> + <Menu.ItemText> + {isReply + ? _(msg`Hide reply for me`) + : _(msg`Hide post for me`)} + </Menu.ItemText> + <Menu.ItemIcon icon={EyeSlash} position="right" /> </Menu.Item> - </Menu.Group> - </> - )} - - {hasSession && ( - <> - <Menu.Divider /> - <Menu.Group> + )} + {canHideReplyForEveryone && ( <Menu.Item - testID="postDropdownMuteThreadBtn" + testID="postDropdownHideBtn" label={ - isThreadMuted ? _(msg`Unmute thread`) : _(msg`Mute thread`) + isReplyHiddenByThreadgate + ? _(msg`Show reply for everyone`) + : _(msg`Hide reply for everyone`) } - onPress={onToggleThreadMute}> + onPress={ + isReplyHiddenByThreadgate + ? onToggleReplyVisibility + : () => hideReplyConfirmControl.open() + }> <Menu.ItemText> - {isThreadMuted - ? _(msg`Unmute thread`) - : _(msg`Mute thread`)} + {isReplyHiddenByThreadgate + ? _(msg`Show reply for everyone`) + : _(msg`Hide reply for everyone`)} </Menu.ItemText> <Menu.ItemIcon - icon={isThreadMuted ? Unmute : Mute} + icon={isReplyHiddenByThreadgate ? Eye : EyeSlash} position="right" /> </Menu.Item> + )} + {canDetachQuote && ( <Menu.Item - testID="postDropdownMuteWordsBtn" - label={_(msg`Mute words & tags`)} - onPress={() => mutedWordsDialogControl.open()}> - <Menu.ItemText>{_(msg`Mute words & tags`)}</Menu.ItemText> - <Menu.ItemIcon icon={Filter} position="right" /> + disabled={isDetachPending} + testID="postDropdownHideBtn" + label={ + quoteEmbed.isDetached + ? _(msg`Re-attach quote`) + : _(msg`Detach quote`) + } + onPress={ + quoteEmbed.isDetached + ? onToggleQuotePostAttachment + : () => quotePostDetachConfirmControl.open() + }> + <Menu.ItemText> + {quoteEmbed.isDetached + ? _(msg`Re-attach quote`) + : _(msg`Detach quote`)} + </Menu.ItemText> + <Menu.ItemIcon + icon={ + isDetachPending + ? Loader + : quoteEmbed.isDetached + ? Eye + : EyeSlash + } + position="right" + /> </Menu.Item> - </Menu.Group> - </> - )} + )} + </Menu.Group> + </> + )} + + {hasSession && ( + <> + <Menu.Divider /> + <Menu.Group> + {!isAuthor && ( + <Menu.Item + testID="postDropdownReportBtn" + label={_(msg`Report post`)} + onPress={() => reportDialogControl.open()}> + <Menu.ItemText>{_(msg`Report post`)}</Menu.ItemText> + <Menu.ItemIcon icon={Warning} position="right" /> + </Menu.Item> + )} - {hasSession && - (canHideReplyForEveryone || canDetachQuote || canHidePostForMe) && ( + {isAuthor && ( <> - <Menu.Divider /> - <Menu.Group> - {canHidePostForMe && ( - <Menu.Item - testID="postDropdownHideBtn" - label={ - isReply - ? _(msg`Hide reply for me`) - : _(msg`Hide post for me`) - } - onPress={() => hidePromptControl.open()}> - <Menu.ItemText> - {isReply - ? _(msg`Hide reply for me`) - : _(msg`Hide post for me`)} - </Menu.ItemText> - <Menu.ItemIcon icon={EyeSlash} position="right" /> - </Menu.Item> - )} - {canHideReplyForEveryone && ( - <Menu.Item - testID="postDropdownHideBtn" - label={ - isReplyHiddenByThreadgate - ? _(msg`Show reply for everyone`) - : _(msg`Hide reply for everyone`) - } - onPress={ - isReplyHiddenByThreadgate - ? onToggleReplyVisibility - : () => hideReplyConfirmControl.open() - }> - <Menu.ItemText> - {isReplyHiddenByThreadgate - ? _(msg`Show reply for everyone`) - : _(msg`Hide reply for everyone`)} - </Menu.ItemText> - <Menu.ItemIcon - icon={isReplyHiddenByThreadgate ? Eye : EyeSlash} - position="right" - /> - </Menu.Item> - )} - - {canDetachQuote && ( - <Menu.Item - disabled={isDetachPending} - testID="postDropdownHideBtn" - label={ - quoteEmbed.isDetached - ? _(msg`Re-attach quote`) - : _(msg`Detach quote`) - } - onPress={ - quoteEmbed.isDetached - ? onToggleQuotePostAttachment - : () => quotePostDetachConfirmControl.open() - }> - <Menu.ItemText> - {quoteEmbed.isDetached - ? _(msg`Re-attach quote`) - : _(msg`Detach quote`)} - </Menu.ItemText> - <Menu.ItemIcon - icon={ - isDetachPending - ? Loader - : quoteEmbed.isDetached - ? Eye - : EyeSlash - } - position="right" - /> - </Menu.Item> - )} - </Menu.Group> + <Menu.Item + testID="postDropdownEditPostInteractions" + label={_(msg`Edit interaction settings`)} + onPress={() => postInteractionSettingsDialogControl.open()} + {...(isAuthor + ? Platform.select({ + web: { + onHoverIn: prefetchPostInteractionSettings, + }, + native: { + onPressIn: prefetchPostInteractionSettings, + }, + }) + : {})}> + <Menu.ItemText> + {_(msg`Edit interaction settings`)} + </Menu.ItemText> + <Menu.ItemIcon icon={Gear} position="right" /> + </Menu.Item> + <Menu.Item + testID="postDropdownDeleteBtn" + label={_(msg`Delete post`)} + onPress={() => deletePromptControl.open()}> + <Menu.ItemText>{_(msg`Delete post`)}</Menu.ItemText> + <Menu.ItemIcon icon={Trash} position="right" /> + </Menu.Item> </> )} - - {hasSession && ( - <> - <Menu.Divider /> - <Menu.Group> - {!isAuthor && ( - <Menu.Item - testID="postDropdownReportBtn" - label={_(msg`Report post`)} - onPress={() => reportDialogControl.open()}> - <Menu.ItemText>{_(msg`Report post`)}</Menu.ItemText> - <Menu.ItemIcon icon={Warning} position="right" /> - </Menu.Item> - )} - - {isAuthor && ( - <> - <Menu.Item - testID="postDropdownEditPostInteractions" - label={_(msg`Edit interaction settings`)} - onPress={() => - postInteractionSettingsDialogControl.open() - } - {...(isAuthor - ? Platform.select({ - web: { - onHoverIn: prefetchPostInteractionSettings, - }, - native: { - onPressIn: prefetchPostInteractionSettings, - }, - }) - : {})}> - <Menu.ItemText> - {_(msg`Edit interaction settings`)} - </Menu.ItemText> - <Menu.ItemIcon icon={Gear} position="right" /> - </Menu.Item> - <Menu.Item - testID="postDropdownDeleteBtn" - label={_(msg`Delete post`)} - onPress={() => deletePromptControl.open()}> - <Menu.ItemText>{_(msg`Delete post`)}</Menu.ItemText> - <Menu.ItemIcon icon={Trash} position="right" /> - </Menu.Item> - </> - )} - </Menu.Group> - </> - )} - </Menu.Outer> - </Menu.Root> + </Menu.Group> + </> + )} <Prompt.Basic control={deletePromptControl} @@ -745,9 +778,7 @@ let PostDropdownBtn = ({ onConfirm={onToggleReplyVisibility} confirmButtonCta={_(msg`Yes, hide`)} /> - </EventStopper> + </> ) } - -PostDropdownBtn = memo(PostDropdownBtn) -export {PostDropdownBtn} +PostDropdownMenuItems = memo(PostDropdownMenuItems) |