Bluesky app fork with some witchin' additions 💫 witchsky.app
bluesky fork client

Refactor `PostDropdownBtn` to use new `Menu` (#3112)

* Refactor PostDropdownBtn

(cherry picked from commit 0adf6cb75e3d4b7c1630cf6153c0d7e289e1b859)

* Update icons

(cherry picked from commit ac89ef9b28721c00736b1388455f3f5f092de0ad)

* Port over fixes

* fix scrollbar disappearing

* Try CSS solution

* Disable arrow for now

---------

Co-authored-by: Hailey <me@haileyok.com>

authored by

Eric Bailey
Hailey
and committed by
GitHub
8f623c3b dd86d096

+249 -177
+1
assets/icons/bubbleQuestion_stroke2_corner0_rounded.svg
··· 1 + <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><path fill="#000" fill-rule="evenodd" d="M5.002 17.036V5h14v12.036h-3.986a1 1 0 0 0-.639.23l-2.375 1.968-2.344-1.965a1 1 0 0 0-.643-.233H5.002ZM20.002 3h-16a1 1 0 0 0-1 1v14.036a1 1 0 0 0 1 1h4.65l2.704 2.266a1 1 0 0 0 1.28.004l2.74-2.27h4.626a1 1 0 0 0 1-1V4a1 1 0 0 0-1-1Zm-7.878 3.663c-1.39 0-2.5 1.135-2.5 2.515a1 1 0 0 0 2 0c0-.294.232-.515.5-.515a.507.507 0 0 1 .489.6.174.174 0 0 1-.027.048 1.1 1.1 0 0 1-.267.226c-.508.345-1.128.923-1.286 1.978a1 1 0 1 0 1.978.297.762.762 0 0 1 .14-.359c.063-.086.155-.169.293-.262.436-.297 1.18-.885 1.18-2.013 0-1.38-1.11-2.515-2.5-2.515ZM12 15.75a1.25 1.25 0 1 1 0-2.5 1.25 1.25 0 0 1 0 2.5Z" clip-rule="evenodd"/></svg>
+1
assets/icons/filter_stroke2_corner0_rounded.svg
··· 1 + <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><path fill="#000" fill-rule="evenodd" d="M3 4a1 1 0 0 1 1-1h16a1 1 0 0 1 1 1v4a1 1 0 0 1-.293.707L15 14.414V20a1 1 0 0 1-.758.97l-4 1A1 1 0 0 1 9 21v-6.586L3.293 8.707A1 1 0 0 1 3 8V4Zm2 1v2.586l5.707 5.707A1 1 0 0 1 11 14v5.72l2-.5V14a1 1 0 0 1 .293-.707L19 7.586V5H5Z" clip-rule="evenodd"/></svg>
+1
assets/icons/speakerVolumeFull_stroke2_corner0_rounded.svg
··· 1 + <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><path fill="#000" fill-rule="evenodd" d="M12.472 3.118A1 1 0 0 1 13 4v16a1 1 0 0 1-1.555.832L5.697 17H2a1 1 0 0 1-1-1V8a1 1 0 0 1 1-1h3.697l5.748-3.832a1 1 0 0 1 1.027-.05ZM11 5.868 6.555 8.833A1 1 0 0 1 6 9H3v6h3a1 1 0 0 1 .555.168L11 18.131V5.87Zm7.364-1.645a1 1 0 0 1 1.414 0A10.969 10.969 0 0 1 23 12c0 3.037-1.232 5.788-3.222 7.778a1 1 0 1 1-1.414-1.414A8.969 8.969 0 0 0 21 12a8.969 8.969 0 0 0-2.636-6.364 1 1 0 0 1 0-1.414Zm-3.182 3.181a1 1 0 0 1 1.414 0A6.483 6.483 0 0 1 18.5 12a6.483 6.483 0 0 1-1.904 4.597 1 1 0 0 1-1.414-1.415A4.483 4.483 0 0 0 16.5 12a4.483 4.483 0 0 0-1.318-3.182 1 1 0 0 1 0-1.414Z" clip-rule="evenodd"/></svg>
+1
assets/icons/trash_stroke2_corner0_rounded.svg
··· 1 + <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><path fill="#000" fill-rule="evenodd" d="M7.416 5H3a1 1 0 0 0 0 2h1.064l.938 14.067A1 1 0 0 0 6 22h12a1 1 0 0 0 .998-.933L19.936 7H21a1 1 0 1 0 0-2h-4.416a5 5 0 0 0-9.168 0Zm2.348 0h4.472c-.55-.614-1.348-1-2.236-1-.888 0-1.687.386-2.236 1Zm6.087 2H6.07l.867 13h10.128l.867-13h-2.036a1 1 0 0 1-.044 0ZM10 10a1 1 0 0 1 1 1v5a1 1 0 1 1-2 0v-5a1 1 0 0 1 1-1Zm4 0a1 1 0 0 1 1 1v5a1 1 0 1 1-2 0v-5a1 1 0 0 1 1-1Z" clip-rule="evenodd"/></svg>
+1
assets/icons/warning_stroke2_corner0_rounded.svg
··· 1 + <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><path fill="#000" fill-rule="evenodd" d="M11.14 4.494a.995.995 0 0 1 1.72 0l7.001 12.008a.996.996 0 0 1-.86 1.498H4.999a.996.996 0 0 1-.86-1.498L11.14 4.494Zm3.447-1.007c-1.155-1.983-4.019-1.983-5.174 0L2.41 15.494C1.247 17.491 2.686 20 4.998 20h14.004c2.312 0 3.751-2.509 2.587-4.506L14.587 3.487ZM13 9.019a1 1 0 1 0-2 0v2.994a1 1 0 1 0 2 0V9.02Zm-1 4.731a1.25 1.25 0 1 0 0 2.5 1.25 1.25 0 0 0 0-2.5Z" clip-rule="evenodd"/></svg>
+4 -4
src/components/Menu/index.web.tsx
··· 92 92 accessibilityLabel={label} 93 93 onFocus={onFocus} 94 94 onBlur={onBlur} 95 - style={flatten([style, web({outline: 0})])} 96 - onPointerDown={() => { 97 - control.open() 98 - }} 95 + style={flatten([style, focused && web({outline: 0})])} 96 + onPointerDown={() => control.open()} 99 97 {...web({ 100 98 onMouseEnter, 101 99 onMouseLeave, ··· 131 129 {children} 132 130 </View> 133 131 132 + {/* Disabled until we can fix positioning 134 133 <DropdownMenu.Arrow 135 134 className="DropdownMenuArrow" 136 135 fill={ ··· 138 137 .backgroundColor 139 138 } 140 139 /> 140 + */} 141 141 </DropdownMenu.Content> 142 142 </DropdownMenu.Portal> 143 143 )
+5
src/components/icons/Bubble.tsx
··· 1 + import {createSinglePathSVG} from './TEMPLATE' 2 + 3 + export const BubbleQuestion_Stroke2_Corner0_Rounded = createSinglePathSVG({ 4 + path: 'M5.002 17.036V5h14v12.036h-3.986a1 1 0 0 0-.639.23l-2.375 1.968-2.344-1.965a1 1 0 0 0-.643-.233H5.002ZM20.002 3h-16a1 1 0 0 0-1 1v14.036a1 1 0 0 0 1 1h4.65l2.704 2.266a1 1 0 0 0 1.28.004l2.74-2.27h4.626a1 1 0 0 0 1-1V4a1 1 0 0 0-1-1Zm-7.878 3.663c-1.39 0-2.5 1.135-2.5 2.515a1 1 0 0 0 2 0c0-.294.232-.515.5-.515a.507.507 0 0 1 .489.6.174.174 0 0 1-.027.048 1.1 1.1 0 0 1-.267.226c-.508.345-1.128.923-1.286 1.978a1 1 0 1 0 1.978.297.762.762 0 0 1 .14-.359c.063-.086.155-.169.293-.262.436-.297 1.18-.885 1.18-2.013 0-1.38-1.11-2.515-2.5-2.515ZM12 15.75a1.25 1.25 0 1 1 0-2.5 1.25 1.25 0 0 1 0 2.5Z', 5 + })
+5
src/components/icons/Filter.tsx
··· 1 + import {createSinglePathSVG} from './TEMPLATE' 2 + 3 + export const Filter_Stroke2_Corner0_Rounded = createSinglePathSVG({ 4 + path: 'M3 4a1 1 0 0 1 1-1h16a1 1 0 0 1 1 1v4a1 1 0 0 1-.293.707L15 14.414V20a1 1 0 0 1-.758.97l-4 1A1 1 0 0 1 9 21v-6.586L3.293 8.707A1 1 0 0 1 3 8V4Zm2 1v2.586l5.707 5.707A1 1 0 0 1 11 14v5.72l2-.5V14a1 1 0 0 1 .293-.707L19 7.586V5H5Z', 5 + })
+5
src/components/icons/Speaker.tsx
··· 1 + import {createSinglePathSVG} from './TEMPLATE' 2 + 3 + export const SpeakerVolumeFull_Stroke2_Corner0_Rounded = createSinglePathSVG({ 4 + path: 'M12.472 3.118A1 1 0 0 1 13 4v16a1 1 0 0 1-1.555.832L5.697 17H2a1 1 0 0 1-1-1V8a1 1 0 0 1 1-1h3.697l5.748-3.832a1 1 0 0 1 1.027-.05ZM11 5.868 6.555 8.833A1 1 0 0 1 6 9H3v6h3a1 1 0 0 1 .555.168L11 18.131V5.87Zm7.364-1.645a1 1 0 0 1 1.414 0A10.969 10.969 0 0 1 23 12c0 3.037-1.232 5.788-3.222 7.778a1 1 0 1 1-1.414-1.414A8.969 8.969 0 0 0 21 12a8.969 8.969 0 0 0-2.636-6.364 1 1 0 0 1 0-1.414Zm-3.182 3.181a1 1 0 0 1 1.414 0A6.483 6.483 0 0 1 18.5 12a6.483 6.483 0 0 1-1.904 4.597 1 1 0 0 1-1.414-1.415A4.483 4.483 0 0 0 16.5 12a4.483 4.483 0 0 0-1.318-3.182 1 1 0 0 1 0-1.414Z', 5 + })
+5
src/components/icons/Trash.tsx
··· 1 + import {createSinglePathSVG} from './TEMPLATE' 2 + 3 + export const Trash_Stroke2_Corner0_Rounded = createSinglePathSVG({ 4 + path: 'M7.416 5H3a1 1 0 0 0 0 2h1.064l.938 14.067A1 1 0 0 0 6 22h12a1 1 0 0 0 .998-.933L19.936 7H21a1 1 0 1 0 0-2h-4.416a5 5 0 0 0-9.168 0Zm2.348 0h4.472c-.55-.614-1.348-1-2.236-1-.888 0-1.687.386-2.236 1Zm6.087 2H6.07l.867 13h10.128l.867-13h-2.036a1 1 0 0 1-.044 0ZM10 10a1 1 0 0 1 1 1v5a1 1 0 1 1-2 0v-5a1 1 0 0 1 1-1Zm4 0a1 1 0 0 1 1 1v5a1 1 0 1 1-2 0v-5a1 1 0 0 1 1-1Z', 5 + })
+5
src/components/icons/Warning.tsx
··· 1 + import {createSinglePathSVG} from './TEMPLATE' 2 + 3 + export const Warning_Stroke2_Corner0_Rounded = createSinglePathSVG({ 4 + path: 'M11.14 4.494a.995.995 0 0 1 1.72 0l7.001 12.008a.996.996 0 0 1-.86 1.498H4.999a.996.996 0 0 1-.86-1.498L11.14 4.494Zm3.447-1.007c-1.155-1.983-4.019-1.983-5.174 0L2.41 15.494C1.247 17.491 2.686 20 4.998 20h14.004c2.312 0 3.751-2.509 2.587-4.506L14.587 3.487ZM13 9.019a1 1 0 1 0-2 0v2.994a1 1 0 1 0 2 0V9.02Zm-1 4.731a1.25 1.25 0 1 0 0 2.5 1.25 1.25 0 0 0 0-2.5Z', 5 + })
+9 -2
src/view/com/util/EventStopper.tsx
··· 8 8 export function EventStopper({ 9 9 children, 10 10 style, 11 - }: React.PropsWithChildren<{style?: ViewStyle | ViewStyle[]}>) { 11 + onKeyDown = true, 12 + }: React.PropsWithChildren<{ 13 + style?: ViewStyle | ViewStyle[] 14 + /** 15 + * Default `true`. Set to `false` to allow onKeyDown to propagate 16 + */ 17 + onKeyDown?: boolean 18 + }>) { 12 19 const stop = (e: any) => { 13 20 e.stopPropagation() 14 21 } ··· 18 25 onTouchEnd={stop} 19 26 // @ts-ignore web only -prf 20 27 onClick={stop} 21 - onKeyDown={stop} 28 + onKeyDown={onKeyDown ? stop : undefined} 22 29 style={style}> 23 30 {children} 24 31 </View>
+205 -171
src/view/com/util/forms/PostDropdownBtn.tsx
··· 1 1 import React, {memo} from 'react' 2 - import {StyleProp, View, ViewStyle} from 'react-native' 2 + import { 3 + StyleProp, 4 + ViewStyle, 5 + Pressable, 6 + View, 7 + PressableProps, 8 + } from 'react-native' 3 9 import Clipboard from '@react-native-clipboard/clipboard' 4 10 import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' 5 11 import {useNavigation} from '@react-navigation/native' ··· 12 18 import {toShareUrl} from 'lib/strings/url-helpers' 13 19 import {useTheme} from 'lib/ThemeContext' 14 20 import {shareUrl} from 'lib/sharing' 15 - import { 16 - NativeDropdown, 17 - DropdownItem as NativeDropdownItem, 18 - } from './NativeDropdown' 19 21 import * as Toast from '../Toast' 20 22 import {EventStopper} from '../EventStopper' 21 23 import {useModalControls} from '#/state/modals' ··· 36 38 import {richTextToString} from '#/lib/strings/rich-text-helpers' 37 39 import {useGlobalDialogsControlContext} from '#/components/dialogs/Context' 38 40 41 + import {atoms as a, useTheme as useAlf, web} from '#/alf' 42 + import * as Menu from '#/components/Menu' 43 + import {Clipboard_Stroke2_Corner2_Rounded as ClipboardIcon} from '#/components/icons/Clipboard' 44 + import {Filter_Stroke2_Corner0_Rounded as Filter} from '#/components/icons/Filter' 45 + import {ArrowOutOfBox_Stroke2_Corner0_Rounded as Share} from '#/components/icons/ArrowOutOfBox' 46 + import {EyeSlash_Stroke2_Corner0_Rounded as EyeSlash} from '#/components/icons/EyeSlash' 47 + import {Mute_Stroke2_Corner0_Rounded as Mute} from '#/components/icons/Mute' 48 + import {SpeakerVolumeFull_Stroke2_Corner0_Rounded as Unmute} from '#/components/icons/Speaker' 49 + import {BubbleQuestion_Stroke2_Corner0_Rounded as Translate} from '#/components/icons/Bubble' 50 + import {Warning_Stroke2_Corner0_Rounded as Warning} from '#/components/icons/Warning' 51 + import {Trash_Stroke2_Corner0_Rounded as Trash} from '#/components/icons/Trash' 52 + import {CircleInfo_Stroke2_Corner0_Rounded as CircleInfo} from '#/components/icons/CircleInfo' 53 + 39 54 let PostDropdownBtn = ({ 40 55 testID, 41 56 postAuthor, ··· 45 60 richText, 46 61 style, 47 62 showAppealLabelItem, 63 + hitSlop, 48 64 }: { 49 65 testID: string 50 66 postAuthor: AppBskyActorDefs.ProfileViewBasic ··· 54 70 richText: RichTextAPI 55 71 style?: StyleProp<ViewStyle> 56 72 showAppealLabelItem?: boolean 73 + hitSlop?: PressableProps['hitSlop'] 57 74 }): React.ReactNode => { 58 75 const {hasSession, currentAccount} = useSession() 59 76 const theme = useTheme() 77 + const alf = useAlf() 60 78 const {_} = useLingui() 61 79 const defaultCtrlColor = theme.palette.default.postCtrl 62 80 const {openModal} = useModalControls() ··· 151 169 hidePost({uri: postUri}) 152 170 }, [postUri, hidePost]) 153 171 154 - const dropdownItems: NativeDropdownItem[] = [ 155 - { 156 - label: _(msg`Translate`), 157 - onPress() { 158 - onOpenTranslate() 159 - }, 160 - testID: 'postDropdownTranslateBtn', 161 - icon: { 162 - ios: { 163 - name: 'character.book.closed', 164 - }, 165 - android: 'ic_menu_sort_alphabetically', 166 - web: 'language', 167 - }, 168 - }, 169 - { 170 - label: _(msg`Copy post text`), 171 - onPress() { 172 - onCopyPostText() 173 - }, 174 - testID: 'postDropdownCopyTextBtn', 175 - icon: { 176 - ios: { 177 - name: 'doc.on.doc', 178 - }, 179 - android: 'ic_menu_edit', 180 - web: ['far', 'paste'], 181 - }, 182 - }, 183 - { 184 - label: isWeb ? _(msg`Copy link to post`) : _(msg`Share`), 185 - onPress() { 186 - const url = toShareUrl(href) 187 - shareUrl(url) 188 - }, 189 - testID: 'postDropdownShareBtn', 190 - icon: { 191 - ios: { 192 - name: 'square.and.arrow.up', 193 - }, 194 - android: 'ic_menu_share', 195 - web: 'share', 196 - }, 197 - }, 198 - hasSession && { 199 - label: 'separator', 200 - }, 201 - hasSession && { 202 - label: isThreadMuted ? _(msg`Unmute thread`) : _(msg`Mute thread`), 203 - onPress() { 204 - onToggleThreadMute() 205 - }, 206 - testID: 'postDropdownMuteThreadBtn', 207 - icon: { 208 - ios: { 209 - name: 'speaker.slash', 210 - }, 211 - android: 'ic_lock_silent_mode', 212 - web: 'comment-slash', 213 - }, 214 - }, 215 - hasSession && { 216 - label: _(msg`Mute words & tags`), 217 - onPress() { 218 - mutedWordsDialogControl.open() 219 - }, 220 - testID: 'postDropdownMuteWordsBtn', 221 - icon: { 222 - ios: { 223 - name: 'speaker.slash', 224 - }, 225 - android: 'ic_lock_silent_mode', 226 - web: 'filter', 227 - }, 228 - }, 229 - hasSession && 230 - !isAuthor && 231 - !isPostHidden && { 232 - label: _(msg`Hide post`), 233 - onPress() { 234 - openModal({ 235 - name: 'confirm', 236 - title: _(msg`Hide this post?`), 237 - message: _(msg`This will hide this post from your feeds.`), 238 - onPressConfirm: onHidePost, 239 - }) 240 - }, 241 - testID: 'postDropdownHideBtn', 242 - icon: { 243 - ios: { 244 - name: 'eye.slash', 245 - }, 246 - android: 'ic_menu_delete', 247 - web: ['far', 'eye-slash'], 248 - }, 249 - }, 250 - { 251 - label: 'separator', 252 - }, 253 - !isAuthor && 254 - hasSession && { 255 - label: _(msg`Report post`), 256 - onPress() { 257 - openModal({ 258 - name: 'report', 259 - uri: postUri, 260 - cid: postCid, 261 - }) 262 - }, 263 - testID: 'postDropdownReportBtn', 264 - icon: { 265 - ios: { 266 - name: 'exclamationmark.triangle', 267 - }, 268 - android: 'ic_menu_report_image', 269 - web: 'circle-exclamation', 270 - }, 271 - }, 272 - isAuthor && { 273 - label: _(msg`Delete post`), 274 - onPress() { 275 - openModal({ 276 - name: 'confirm', 277 - title: _(msg`Delete this post?`), 278 - message: _(msg`Are you sure? This cannot be undone.`), 279 - onPressConfirm: onDeletePost, 280 - }) 281 - }, 282 - testID: 'postDropdownDeleteBtn', 283 - icon: { 284 - ios: { 285 - name: 'trash', 286 - }, 287 - android: 'ic_menu_delete', 288 - web: ['far', 'trash-can'], 289 - }, 290 - }, 291 - showAppealLabelItem && { 292 - label: 'separator', 293 - }, 294 - showAppealLabelItem && { 295 - label: _(msg`Appeal content warning`), 296 - onPress() { 297 - openModal({name: 'appeal-label', uri: postUri, cid: postCid}) 298 - }, 299 - testID: 'postDropdownAppealBtn', 300 - icon: { 301 - ios: { 302 - name: 'exclamationmark.triangle', 303 - }, 304 - android: 'ic_menu_report_image', 305 - web: 'circle-exclamation', 306 - }, 307 - }, 308 - ].filter(Boolean) as NativeDropdownItem[] 309 - 310 172 return ( 311 - <EventStopper> 312 - <NativeDropdown 313 - testID={testID} 314 - items={dropdownItems} 315 - accessibilityLabel={_(msg`More post options`)} 316 - accessibilityHint=""> 317 - <View style={style}> 318 - <FontAwesomeIcon icon="ellipsis" size={20} color={defaultCtrlColor} /> 319 - </View> 320 - </NativeDropdown> 173 + <EventStopper onKeyDown={false}> 174 + <Menu.Root> 175 + <Menu.Trigger label={_(msg`Open post options menu`)}> 176 + {({props, state}) => { 177 + const styles = [ 178 + style, 179 + a.rounded_full, 180 + (state.hovered || state.focused || state.pressed) && [ 181 + web({outline: 0}), 182 + alf.atoms.bg_contrast_25, 183 + ], 184 + ] 185 + return isWeb ? ( 186 + <View {...props} testID={testID} style={styles}> 187 + <FontAwesomeIcon 188 + icon="ellipsis" 189 + size={20} 190 + color={defaultCtrlColor} 191 + style={{pointerEvents: 'none'}} 192 + /> 193 + </View> 194 + ) : ( 195 + <Pressable 196 + {...props} 197 + hitSlop={hitSlop} 198 + testID={testID} 199 + style={styles}> 200 + <FontAwesomeIcon 201 + icon="ellipsis" 202 + size={20} 203 + color={defaultCtrlColor} 204 + style={{pointerEvents: 'none'}} 205 + /> 206 + </Pressable> 207 + ) 208 + }} 209 + </Menu.Trigger> 210 + 211 + <Menu.Outer> 212 + <Menu.Group> 213 + <Menu.Item 214 + testID="postDropdownTranslateBtn" 215 + label={_(msg`Translate`)} 216 + onPress={onOpenTranslate}> 217 + <Menu.ItemText>{_(msg`Translate`)}</Menu.ItemText> 218 + <Menu.ItemIcon icon={Translate} position="right" /> 219 + </Menu.Item> 220 + 221 + <Menu.Item 222 + testID="postDropdownCopyTextBtn" 223 + label={_(msg`Copy post text`)} 224 + onPress={onCopyPostText}> 225 + <Menu.ItemText>{_(msg`Copy post text`)}</Menu.ItemText> 226 + <Menu.ItemIcon icon={ClipboardIcon} position="right" /> 227 + </Menu.Item> 228 + 229 + <Menu.Item 230 + testID="postDropdownShareBtn" 231 + label={isWeb ? _(msg`Copy link to post`) : _(msg`Share`)} 232 + onPress={() => { 233 + const url = toShareUrl(href) 234 + shareUrl(url) 235 + }}> 236 + <Menu.ItemText> 237 + {isWeb ? _(msg`Copy link to post`) : _(msg`Share`)} 238 + </Menu.ItemText> 239 + <Menu.ItemIcon icon={Share} position="right" /> 240 + </Menu.Item> 241 + </Menu.Group> 242 + 243 + {hasSession && ( 244 + <> 245 + <Menu.Divider /> 246 + 247 + <Menu.Group> 248 + <Menu.Item 249 + testID="postDropdownMuteThreadBtn" 250 + label={ 251 + isThreadMuted ? _(msg`Unmute thread`) : _(msg`Mute thread`) 252 + } 253 + onPress={onToggleThreadMute}> 254 + <Menu.ItemText> 255 + {isThreadMuted 256 + ? _(msg`Unmute thread`) 257 + : _(msg`Mute thread`)} 258 + </Menu.ItemText> 259 + <Menu.ItemIcon 260 + icon={isThreadMuted ? Unmute : Mute} 261 + position="right" 262 + /> 263 + </Menu.Item> 264 + 265 + <Menu.Item 266 + testID="postDropdownMuteWordsBtn" 267 + label={_(msg`Mute words & tags`)} 268 + onPress={() => mutedWordsDialogControl.open()}> 269 + <Menu.ItemText>{_(msg`Mute words & tags`)}</Menu.ItemText> 270 + <Menu.ItemIcon icon={Filter} position="right" /> 271 + </Menu.Item> 272 + 273 + {!isAuthor && !isPostHidden && ( 274 + <Menu.Item 275 + testID="postDropdownHideBtn" 276 + label={_(msg`Hide post`)} 277 + onPress={() => { 278 + openModal({ 279 + name: 'confirm', 280 + title: _(msg`Hide this post?`), 281 + message: _( 282 + msg`This will hide this post from your feeds.`, 283 + ), 284 + onPressConfirm: onHidePost, 285 + }) 286 + }}> 287 + <Menu.ItemText>{_(msg`Hide post`)}</Menu.ItemText> 288 + <Menu.ItemIcon icon={EyeSlash} position="right" /> 289 + </Menu.Item> 290 + )} 291 + </Menu.Group> 292 + </> 293 + )} 294 + 295 + <Menu.Divider /> 296 + 297 + <Menu.Group> 298 + {!isAuthor && ( 299 + <Menu.Item 300 + testID="postDropdownReportBtn" 301 + label={_(msg`Report post`)} 302 + onPress={() => { 303 + openModal({ 304 + name: 'report', 305 + uri: postUri, 306 + cid: postCid, 307 + }) 308 + }}> 309 + <Menu.ItemText>{_(msg`Report post`)}</Menu.ItemText> 310 + <Menu.ItemIcon icon={Warning} position="right" /> 311 + </Menu.Item> 312 + )} 313 + 314 + {isAuthor && ( 315 + <Menu.Item 316 + testID="postDropdownDeleteBtn" 317 + label={_(msg`Delete post`)} 318 + onPress={() => { 319 + openModal({ 320 + name: 'confirm', 321 + title: _(msg`Delete this post?`), 322 + message: _(msg`Are you sure? This cannot be undone.`), 323 + onPressConfirm: onDeletePost, 324 + }) 325 + }}> 326 + <Menu.ItemText>{_(msg`Delete post`)}</Menu.ItemText> 327 + <Menu.ItemIcon icon={Trash} position="right" /> 328 + </Menu.Item> 329 + )} 330 + 331 + {showAppealLabelItem && ( 332 + <> 333 + <Menu.Divider /> 334 + 335 + <Menu.Item 336 + testID="postDropdownAppealBtn" 337 + label={_(msg`Appeal content warning`)} 338 + onPress={() => { 339 + openModal({ 340 + name: 'appeal-label', 341 + uri: postUri, 342 + cid: postCid, 343 + }) 344 + }}> 345 + <Menu.ItemText> 346 + {_(msg`Appeal content warning`)} 347 + </Menu.ItemText> 348 + <Menu.ItemIcon icon={CircleInfo} position="right" /> 349 + </Menu.Item> 350 + </> 351 + )} 352 + </Menu.Group> 353 + </Menu.Outer> 354 + </Menu.Root> 321 355 </EventStopper> 322 356 ) 323 357 }
+1
src/view/com/util/post-ctrls/PostCtrls.tsx
··· 231 231 richText={richText} 232 232 showAppealLabelItem={showAppealLabelItem} 233 233 style={styles.btnPad} 234 + hitSlop={big ? HITSLOP_20 : HITSLOP_10} 234 235 /> 235 236 </View> 236 237 </View>