diff options
author | Jan-Olof Eriksson <jan-olof.eriksson@iki.fi> | 2024-02-29 11:55:03 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-02-29 11:55:03 +0200 |
commit | 963a44ab872a1044d6997a8fcf7b2fc754ac618a (patch) | |
tree | bbd64f464a8f14e55cbb06e28811cdc43f059d29 /src/components/TagMenu/index.web.tsx | |
parent | 1f9562847512bb41cd8bb381b735a388be4db59b (diff) | |
parent | a35976cdc9b6467ad8b6e0c4ff46ba684fee9064 (diff) | |
download | voidsky-963a44ab872a1044d6997a8fcf7b2fc754ac618a.tar.zst |
Merge branch 'bluesky-social:main' into main
Diffstat (limited to 'src/components/TagMenu/index.web.tsx')
-rw-r--r-- | src/components/TagMenu/index.web.tsx | 136 |
1 files changed, 136 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..31187112f --- /dev/null +++ b/src/components/TagMenu/index.web.tsx @@ -0,0 +1,136 @@ +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' +import {enforceLen} from '#/lib/strings/helpers' +import {web} from '#/alf' + +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 truncatedTag = enforceLen(tag, 15, true, 'middle') + + const dropdownItems = React.useMemo(() => { + return [ + { + label: _(msg`See ${truncatedTag} posts`), + onPress() { + navigation.navigate('Search', { + q: tag, + }) + }, + testID: 'tagMenuSearch', + icon: { + ios: { + name: 'magnifyingglass', + }, + android: '', + web: 'magnifying-glass', + }, + }, + authorHandle && + !isInvalidHandle(authorHandle) && { + label: _(msg`See ${truncatedTag} posts by 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 ${truncatedTag}`) + : _(msg`Mute ${truncatedTag}`), + 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, + truncatedTag, + sanitizedTag, + upsertMutedWord, + removeMutedWord, + ]) + + return ( + <EventStopper> + <NativeDropdown + accessibilityLabel={_(msg`Click here to open tag menu for ${tag}`)} + accessibilityHint="" + // @ts-ignore + items={dropdownItems} + triggerStyle={web({ + textAlign: 'left', + })}> + {children} + </NativeDropdown> + </EventStopper> + ) +} |