From 9df5caf3c545a7a1c559c6561625d99154aa0603 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Tue, 21 Jan 2025 15:56:01 -0600 Subject: Update hashtag menu to use `Menu`, convert to native link for additional a11y and click handling (#7529) * Make tag a normal link on web * Replace old TagMenu with new RichTextTag component, expand and improve click utils * Clarify intents * Ensure we're passing down hint * ope * DRY --- src/components/RichTextTag.tsx | 160 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 160 insertions(+) create mode 100644 src/components/RichTextTag.tsx (limited to 'src/components/RichTextTag.tsx') diff --git a/src/components/RichTextTag.tsx b/src/components/RichTextTag.tsx new file mode 100644 index 000000000..562d44aa6 --- /dev/null +++ b/src/components/RichTextTag.tsx @@ -0,0 +1,160 @@ +import React from 'react' +import {StyleProp, Text as RNText, TextStyle} from 'react-native' +import {msg, Trans} from '@lingui/macro' +import {useLingui} from '@lingui/react' +import {useNavigation} from '@react-navigation/native' + +import {NavigationProp} from '#/lib/routes/types' +import {isInvalidHandle} from '#/lib/strings/handles' +import {isNative, isWeb} from '#/platform/detection' +import { + usePreferencesQuery, + useRemoveMutedWordsMutation, + useUpsertMutedWordsMutation, +} from '#/state/queries/preferences' +import {MagnifyingGlass2_Stroke2_Corner0_Rounded as Search} from '#/components/icons/MagnifyingGlass2' +import {Mute_Stroke2_Corner0_Rounded as Mute} from '#/components/icons/Mute' +import {Person_Stroke2_Corner0_Rounded as Person} from '#/components/icons/Person' +import { + createStaticClick, + createStaticClickIfUnmodified, + InlineLinkText, +} from '#/components/Link' +import {Loader} from '#/components/Loader' +import * as Menu from '#/components/Menu' + +export function RichTextTag({ + tag, + display, + authorHandle, + textStyle, +}: { + tag: string + display: string + authorHandle?: string + textStyle: StyleProp +}) { + const {_} = useLingui() + const {isLoading: isPreferencesLoading, data: preferences} = + usePreferencesQuery() + const { + mutateAsync: upsertMutedWord, + variables: optimisticUpsert, + reset: resetUpsert, + } = useUpsertMutedWordsMutation() + const { + mutateAsync: removeMutedWords, + variables: optimisticRemove, + reset: resetRemove, + } = useRemoveMutedWordsMutation() + const navigation = useNavigation() + const label = _(msg`Hashtag ${tag}`) + const hint = isNative + ? _(msg`Long press to open tag menu for #${tag}`) + : _(msg`Click to open tag menu for ${tag}`) + + const isMuted = Boolean( + (preferences?.moderationPrefs.mutedWords?.find( + m => m.value === tag && m.targets.includes('tag'), + ) ?? + optimisticUpsert?.find( + m => m.value === tag && m.targets.includes('tag'), + )) && + !optimisticRemove?.find(m => m?.value === tag), + ) + + /* + * Mute word records that exactly match the tag in question. + */ + const removeableMuteWords = React.useMemo(() => { + return ( + preferences?.moderationPrefs.mutedWords?.filter(word => { + return word.value === tag + }) || [] + ) + }, [tag, preferences?.moderationPrefs?.mutedWords]) + + return ( + + + {({props: menuProps}) => ( + { + if (isWeb) { + return createStaticClickIfUnmodified(() => { + if (!isNative) { + menuProps.onPress() + } + }).onPress(e) + } + }} + onLongPress={createStaticClick(menuProps.onPress).onPress} + accessibilityHint={hint} + label={label} + style={textStyle}> + {isNative ? ( + display + ) : ( + {display} + )} + + )} + + + + { + navigation.push('Hashtag', { + tag: encodeURIComponent(tag), + }) + }}> + + See #{tag} posts + + + + {authorHandle && !isInvalidHandle(authorHandle) && ( + { + navigation.push('Hashtag', { + tag: encodeURIComponent(tag), + author: authorHandle, + }) + }}> + + See #{tag} posts by user + + + + )} + + + { + if (isMuted) { + resetUpsert() + removeMutedWords(removeableMuteWords) + } else { + resetRemove() + upsertMutedWord([ + {value: tag, targets: ['tag'], actorTarget: 'all'}, + ]) + } + }}> + + {isMuted ? _(msg`Unmute ${tag}`) : _(msg`Mute ${tag}`)} + + + + + + ) +} -- cgit 1.4.1