diff options
author | Eric Bailey <git@esb.lol> | 2024-02-26 22:33:48 -0600 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-02-26 20:33:48 -0800 |
commit | 58aaad704aa971c5ebbf5a5f330a2e2129b557f6 (patch) | |
tree | 74a448e61e83ca9292b0c6bf8d638bcfabd11eec /src/components/TagMenu/index.web.tsx | |
parent | c8582924e2421e5383050c4f60a80d2e74287c07 (diff) | |
download | voidsky-58aaad704aa971c5ebbf5a5f330a2e2129b557f6.tar.zst |
Add tags and mute words (#2968)
* Add bare minimum hashtags support (#2804) * Add bare minimum hashtags support As atproto/api already parses hashtags, this is as simple as hooking it up like link segments. This is "bare minimum" because: - Opening hashtag "#foo" is actually just a search for "foo" right now to work around #2491. - There is no integration in the composer. This hasn't stopped people from using hashtags already, and can be added later. - This change itself only had to hook things up - thank you for having already put the hashtag parsing in place. * Remove workaround for hash search not working now that it's fixed * Add RichTextTag and TagMenu * Sketch * Remove hackfix * Some cleanup * Sketch web * Mobile design * Mobile handling of tags search * Web only * Fix navigation woes * Use new callback * Hook it up * Integrate muted tags * Fix dropdown styles * Type error * Use close callback * Fix styles * Cleanup, install latest sdk * Quick muted words screen * Targets * Dir structure * Icons, list view * Move to dialog * Add removal confirmation * Swap copy * Improve checkboxees * Update matching, add tests * Moderate embeds * Create global dialogs concept again to prevent flashing * Add access from moderation screen * Highlight tags on native * Add web highlighting * Add close to web modal * Adjust close color * Rename toggles and adjust logic * Icon update * Load states * Improve regex * Improve regex * Improve regex * Revert link test * Hyphenated words * Improve matching * Enhance * Some tweaks * Muted words modal changes * Handle invalid handles, handle long tags * Remove main regex * Better test * Space/punct check drop to includes * Lowercase post text before comparison * Add better real world test case --------- Co-authored-by: Kisaragi Hiu <mail@kisaragi-hiu.com>
Diffstat (limited to 'src/components/TagMenu/index.web.tsx')
-rw-r--r-- | src/components/TagMenu/index.web.tsx | 127 |
1 files changed, 127 insertions, 0 deletions
diff --git a/src/components/TagMenu/index.web.tsx b/src/components/TagMenu/index.web.tsx new file mode 100644 index 000000000..930e47a1a --- /dev/null +++ b/src/components/TagMenu/index.web.tsx @@ -0,0 +1,127 @@ +import React from 'react' +import {msg} from '@lingui/macro' +import {useLingui} from '@lingui/react' +import {useNavigation} from '@react-navigation/native' + +import {isInvalidHandle} from '#/lib/strings/handles' +import {EventStopper} from '#/view/com/util/EventStopper' +import {NativeDropdown} from '#/view/com/util/forms/NativeDropdown' +import {NavigationProp} from '#/lib/routes/types' +import { + usePreferencesQuery, + useUpsertMutedWordsMutation, + useRemoveMutedWordMutation, +} from '#/state/queries/preferences' + +export function useTagMenuControl() {} + +export function TagMenu({ + children, + tag, + authorHandle, +}: React.PropsWithChildren<{ + tag: string + authorHandle?: string +}>) { + const sanitizedTag = tag.replace(/^#/, '') + const {_} = useLingui() + const navigation = useNavigation<NavigationProp>() + const {data: preferences} = usePreferencesQuery() + const {mutateAsync: upsertMutedWord, variables: optimisticUpsert} = + useUpsertMutedWordsMutation() + const {mutateAsync: removeMutedWord, variables: optimisticRemove} = + useRemoveMutedWordMutation() + const isMuted = Boolean( + (preferences?.mutedWords?.find( + m => m.value === sanitizedTag && m.targets.includes('tag'), + ) ?? + optimisticUpsert?.find( + m => m.value === sanitizedTag && m.targets.includes('tag'), + )) && + !(optimisticRemove?.value === sanitizedTag), + ) + + const dropdownItems = React.useMemo(() => { + return [ + { + label: _(msg`See ${tag} posts`), + onPress() { + navigation.navigate('Search', { + q: tag, + }) + }, + testID: 'tagMenuSearch', + icon: { + ios: { + name: 'magnifyingglass', + }, + android: '', + web: 'magnifying-glass', + }, + }, + authorHandle && + !isInvalidHandle(authorHandle) && { + label: _(msg`See ${tag} posts by this user`), + onPress() { + navigation.navigate({ + name: 'Search', + params: { + q: tag + (authorHandle ? ` from:${authorHandle}` : ''), + }, + }) + }, + testID: 'tagMenuSeachByUser', + icon: { + ios: { + name: 'magnifyingglass', + }, + android: '', + web: ['far', 'user'], + }, + }, + preferences && { + label: 'separator', + }, + preferences && { + label: isMuted ? _(msg`Unmute ${tag}`) : _(msg`Mute ${tag}`), + onPress() { + if (isMuted) { + removeMutedWord({value: sanitizedTag, targets: ['tag']}) + } else { + upsertMutedWord([{value: sanitizedTag, targets: ['tag']}]) + } + }, + testID: 'tagMenuMute', + icon: { + ios: { + name: 'speaker.slash', + }, + android: 'ic_menu_sort_alphabetically', + web: isMuted ? 'eye' : ['far', 'eye-slash'], + }, + }, + ].filter(Boolean) + }, [ + _, + authorHandle, + isMuted, + navigation, + preferences, + tag, + sanitizedTag, + upsertMutedWord, + removeMutedWord, + ]) + + return ( + <EventStopper> + <NativeDropdown + accessibilityLabel={_(msg`Click here to open tag menu for ${tag}`)} + accessibilityHint="" + // @ts-ignore + items={dropdownItems}> + {children} + </NativeDropdown> + </EventStopper> + ) +} |