Bluesky app fork with some witchin' additions 馃挮
at main 5.0 kB view raw
1import React from 'react' 2import {type StyleProp, Text as RNText, type TextStyle} from 'react-native' 3import {msg, Trans} from '@lingui/macro' 4import {useLingui} from '@lingui/react' 5import {useNavigation} from '@react-navigation/native' 6 7import {type NavigationProp} from '#/lib/routes/types' 8import {isInvalidHandle} from '#/lib/strings/handles' 9import {isNative, isWeb} from '#/platform/detection' 10import { 11 usePreferencesQuery, 12 useRemoveMutedWordsMutation, 13 useUpsertMutedWordsMutation, 14} from '#/state/queries/preferences' 15import {MagnifyingGlass_Stroke2_Corner0_Rounded as Search} from '#/components/icons/MagnifyingGlass' 16import {Mute_Stroke2_Corner0_Rounded as Mute} from '#/components/icons/Mute' 17import {Person_Stroke2_Corner0_Rounded as Person} from '#/components/icons/Person' 18import { 19 createStaticClick, 20 createStaticClickIfUnmodified, 21 InlineLinkText, 22} from '#/components/Link' 23import {Loader} from '#/components/Loader' 24import * as Menu from '#/components/Menu' 25 26export function RichTextTag({ 27 tag, 28 display, 29 authorHandle, 30 textStyle, 31}: { 32 tag: string 33 display: string 34 authorHandle?: string 35 textStyle: StyleProp<TextStyle> 36}) { 37 const {_} = useLingui() 38 const {isLoading: isPreferencesLoading, data: preferences} = 39 usePreferencesQuery() 40 const { 41 mutateAsync: upsertMutedWord, 42 variables: optimisticUpsert, 43 reset: resetUpsert, 44 } = useUpsertMutedWordsMutation() 45 const { 46 mutateAsync: removeMutedWords, 47 variables: optimisticRemove, 48 reset: resetRemove, 49 } = useRemoveMutedWordsMutation() 50 const navigation = useNavigation<NavigationProp>() 51 const label = _(msg`Hashtag ${tag}`) 52 const hint = isNative 53 ? _(msg`Long press to open tag menu for #${tag}`) 54 : _(msg`Click to open tag menu for ${tag}`) 55 56 const isMuted = Boolean( 57 (preferences?.moderationPrefs.mutedWords?.find( 58 m => m.value === tag && m.targets.includes('tag'), 59 ) ?? 60 optimisticUpsert?.find( 61 m => m.value === tag && m.targets.includes('tag'), 62 )) && 63 !optimisticRemove?.find(m => m?.value === tag), 64 ) 65 66 /* 67 * Mute word records that exactly match the tag in question. 68 */ 69 const removeableMuteWords = React.useMemo(() => { 70 return ( 71 preferences?.moderationPrefs.mutedWords?.filter(word => { 72 return word.value === tag 73 }) || [] 74 ) 75 }, [tag, preferences?.moderationPrefs?.mutedWords]) 76 77 return ( 78 <Menu.Root> 79 <Menu.Trigger label={label} hint={hint}> 80 {({props: menuProps}) => ( 81 <InlineLinkText 82 to={{ 83 screen: 'Hashtag', 84 params: {tag: encodeURIComponent(tag)}, 85 }} 86 {...menuProps} 87 onPress={e => { 88 if (isWeb) { 89 return createStaticClickIfUnmodified(() => { 90 if (!isNative) { 91 menuProps.onPress() 92 } 93 }).onPress(e) 94 } 95 }} 96 onLongPress={createStaticClick(menuProps.onPress).onPress} 97 accessibilityHint={hint} 98 label={label} 99 style={textStyle} 100 emoji> 101 {isNative ? ( 102 display 103 ) : ( 104 <RNText ref={menuProps.ref}>{display}</RNText> 105 )} 106 </InlineLinkText> 107 )} 108 </Menu.Trigger> 109 <Menu.Outer> 110 <Menu.Group> 111 <Menu.Item 112 label={_(msg`See ${tag} skeets`)} 113 onPress={() => { 114 navigation.push('Hashtag', { 115 tag: encodeURIComponent(tag), 116 }) 117 }}> 118 <Menu.ItemText> 119 <Trans>See #{tag} skeets</Trans> 120 </Menu.ItemText> 121 <Menu.ItemIcon icon={Search} /> 122 </Menu.Item> 123 {authorHandle && !isInvalidHandle(authorHandle) && ( 124 <Menu.Item 125 label={_(msg`See ${tag} skeets by user`)} 126 onPress={() => { 127 navigation.push('Hashtag', { 128 tag: encodeURIComponent(tag), 129 author: authorHandle, 130 }) 131 }}> 132 <Menu.ItemText> 133 <Trans>See #{tag} skeets by user</Trans> 134 </Menu.ItemText> 135 <Menu.ItemIcon icon={Person} /> 136 </Menu.Item> 137 )} 138 </Menu.Group> 139 <Menu.Divider /> 140 <Menu.Item 141 label={isMuted ? _(msg`Unmute ${tag}`) : _(msg`Mute ${tag}`)} 142 onPress={() => { 143 if (isMuted) { 144 resetUpsert() 145 removeMutedWords(removeableMuteWords) 146 } else { 147 resetRemove() 148 upsertMutedWord([ 149 {value: tag, targets: ['tag'], actorTarget: 'all'}, 150 ]) 151 } 152 }}> 153 <Menu.ItemText> 154 {isMuted ? _(msg`Unmute ${tag}`) : _(msg`Mute ${tag}`)} 155 </Menu.ItemText> 156 <Menu.ItemIcon icon={isPreferencesLoading ? Loader : Mute} /> 157 </Menu.Item> 158 </Menu.Outer> 159 </Menu.Root> 160 ) 161}