Optimize native tag input
This commit is contained in:
+160
-160
@@ -23,6 +23,16 @@ import {
|
|||||||
import {Loader} from '#/components/Loader'
|
import {Loader} from '#/components/Loader'
|
||||||
import {isInvalidHandle} from '#/lib/strings/handles'
|
import {isInvalidHandle} from '#/lib/strings/handles'
|
||||||
|
|
||||||
|
type TagMenuProps = {
|
||||||
|
control: Dialog.DialogOuterProps['control']
|
||||||
|
/**
|
||||||
|
* This should be the sanitized tag value from the facet itself, not the
|
||||||
|
* "display" value with a leading `#`.
|
||||||
|
*/
|
||||||
|
tag: string
|
||||||
|
authorHandle?: string
|
||||||
|
}
|
||||||
|
|
||||||
export function useTagMenuControl() {
|
export function useTagMenuControl() {
|
||||||
return Dialog.useDialogControl()
|
return Dialog.useDialogControl()
|
||||||
}
|
}
|
||||||
@@ -32,15 +42,20 @@ export function TagMenu({
|
|||||||
control,
|
control,
|
||||||
tag,
|
tag,
|
||||||
authorHandle,
|
authorHandle,
|
||||||
}: React.PropsWithChildren<{
|
}: React.PropsWithChildren<TagMenuProps>) {
|
||||||
control: Dialog.DialogOuterProps['control']
|
return (
|
||||||
/**
|
<>
|
||||||
* This should be the sanitized tag value from the facet itself, not the
|
{children}
|
||||||
* "display" value with a leading `#`.
|
|
||||||
*/
|
<Dialog.Outer control={control}>
|
||||||
tag: string
|
<Dialog.Handle />
|
||||||
authorHandle?: string
|
<TagMenuInner control={control} tag={tag} authorHandle={authorHandle} />
|
||||||
}>) {
|
</Dialog.Outer>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function TagMenuInner({control, tag, authorHandle}: TagMenuProps) {
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
const navigation = useNavigation<NavigationProp>()
|
const navigation = useNavigation<NavigationProp>()
|
||||||
@@ -69,36 +84,86 @@ export function TagMenu({
|
|||||||
)
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<Dialog.Inner label={_(msg`Tag menu: ${displayTag}`)}>
|
||||||
{children}
|
{isPreferencesLoading ? (
|
||||||
|
<View style={[a.w_full, a.align_center]}>
|
||||||
|
<Loader size="lg" />
|
||||||
|
</View>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<View
|
||||||
|
style={[
|
||||||
|
a.rounded_md,
|
||||||
|
a.border,
|
||||||
|
a.mb_md,
|
||||||
|
t.atoms.border_contrast_low,
|
||||||
|
t.atoms.bg_contrast_25,
|
||||||
|
]}>
|
||||||
|
<Link
|
||||||
|
label={_(msg`Search for all posts with tag ${displayTag}`)}
|
||||||
|
to={makeSearchLink({query: displayTag})}
|
||||||
|
onPress={e => {
|
||||||
|
e.preventDefault()
|
||||||
|
|
||||||
<Dialog.Outer control={control}>
|
control.close(() => {
|
||||||
<Dialog.Handle />
|
navigation.push('Hashtag', {
|
||||||
|
tag: tag.replaceAll('#', '%23'),
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
<Dialog.Inner label={_(msg`Tag menu: ${displayTag}`)}>
|
return false
|
||||||
{isPreferencesLoading ? (
|
}}>
|
||||||
<View style={[a.w_full, a.align_center]}>
|
|
||||||
<Loader size="lg" />
|
|
||||||
</View>
|
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
<View
|
<View
|
||||||
style={[
|
style={[
|
||||||
a.rounded_md,
|
a.w_full,
|
||||||
a.border,
|
a.flex_row,
|
||||||
a.mb_md,
|
a.align_center,
|
||||||
t.atoms.border_contrast_low,
|
a.justify_start,
|
||||||
t.atoms.bg_contrast_25,
|
a.gap_md,
|
||||||
|
a.px_lg,
|
||||||
|
a.py_md,
|
||||||
]}>
|
]}>
|
||||||
|
<Search size="lg" style={[t.atoms.text_contrast_medium]} />
|
||||||
|
<Text
|
||||||
|
numberOfLines={1}
|
||||||
|
ellipsizeMode="middle"
|
||||||
|
style={[
|
||||||
|
a.flex_1,
|
||||||
|
a.text_md,
|
||||||
|
a.font_bold,
|
||||||
|
native({top: 2}),
|
||||||
|
t.atoms.text_contrast_medium,
|
||||||
|
]}>
|
||||||
|
<Trans>
|
||||||
|
See{' '}
|
||||||
|
<Text style={[a.text_md, a.font_bold, t.atoms.text]}>
|
||||||
|
{displayTag}
|
||||||
|
</Text>{' '}
|
||||||
|
posts
|
||||||
|
</Trans>
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
</Link>
|
||||||
|
|
||||||
|
{authorHandle && !isInvalidHandle(authorHandle) && (
|
||||||
|
<>
|
||||||
|
<Divider />
|
||||||
|
|
||||||
<Link
|
<Link
|
||||||
label={_(msg`Search for all posts with tag ${displayTag}`)}
|
label={_(
|
||||||
to={makeSearchLink({query: displayTag})}
|
msg`Search for all posts by @${authorHandle} with tag ${displayTag}`,
|
||||||
|
)}
|
||||||
|
to={makeSearchLink({
|
||||||
|
query: displayTag,
|
||||||
|
from: authorHandle,
|
||||||
|
})}
|
||||||
onPress={e => {
|
onPress={e => {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
|
|
||||||
control.close(() => {
|
control.close(() => {
|
||||||
navigation.push('Hashtag', {
|
navigation.push('Hashtag', {
|
||||||
tag: tag.replaceAll('#', '%23'),
|
tag: tag.replaceAll('#', '%23'),
|
||||||
|
author: authorHandle,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -114,7 +179,7 @@ export function TagMenu({
|
|||||||
a.px_lg,
|
a.px_lg,
|
||||||
a.py_md,
|
a.py_md,
|
||||||
]}>
|
]}>
|
||||||
<Search size="lg" style={[t.atoms.text_contrast_medium]} />
|
<Person size="lg" style={[t.atoms.text_contrast_medium]} />
|
||||||
<Text
|
<Text
|
||||||
numberOfLines={1}
|
numberOfLines={1}
|
||||||
ellipsizeMode="middle"
|
ellipsizeMode="middle"
|
||||||
@@ -130,146 +195,81 @@ export function TagMenu({
|
|||||||
<Text style={[a.text_md, a.font_bold, t.atoms.text]}>
|
<Text style={[a.text_md, a.font_bold, t.atoms.text]}>
|
||||||
{displayTag}
|
{displayTag}
|
||||||
</Text>{' '}
|
</Text>{' '}
|
||||||
posts
|
posts by this user
|
||||||
</Trans>
|
</Trans>
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
</Link>
|
</Link>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
{authorHandle && !isInvalidHandle(authorHandle) && (
|
{preferences ? (
|
||||||
<>
|
<>
|
||||||
<Divider />
|
<Divider />
|
||||||
|
|
||||||
<Link
|
<Button
|
||||||
label={_(
|
label={
|
||||||
msg`Search for all posts by @${authorHandle} with tag ${displayTag}`,
|
isMuted
|
||||||
)}
|
? _(msg`Unmute all ${displayTag} posts`)
|
||||||
to={makeSearchLink({
|
: _(msg`Mute all ${displayTag} posts`)
|
||||||
query: displayTag,
|
}
|
||||||
from: authorHandle,
|
onPress={() => {
|
||||||
})}
|
control.close(() => {
|
||||||
onPress={e => {
|
if (isMuted) {
|
||||||
e.preventDefault()
|
resetUpsert()
|
||||||
|
removeMutedWord({
|
||||||
control.close(() => {
|
value: tag,
|
||||||
navigation.push('Hashtag', {
|
targets: ['tag'],
|
||||||
tag: tag.replaceAll('#', '%23'),
|
|
||||||
author: authorHandle,
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
} else {
|
||||||
return false
|
resetRemove()
|
||||||
}}>
|
upsertMutedWord([{value: tag, targets: ['tag']}])
|
||||||
<View
|
|
||||||
style={[
|
|
||||||
a.w_full,
|
|
||||||
a.flex_row,
|
|
||||||
a.align_center,
|
|
||||||
a.justify_start,
|
|
||||||
a.gap_md,
|
|
||||||
a.px_lg,
|
|
||||||
a.py_md,
|
|
||||||
]}>
|
|
||||||
<Person
|
|
||||||
size="lg"
|
|
||||||
style={[t.atoms.text_contrast_medium]}
|
|
||||||
/>
|
|
||||||
<Text
|
|
||||||
numberOfLines={1}
|
|
||||||
ellipsizeMode="middle"
|
|
||||||
style={[
|
|
||||||
a.flex_1,
|
|
||||||
a.text_md,
|
|
||||||
a.font_bold,
|
|
||||||
native({top: 2}),
|
|
||||||
t.atoms.text_contrast_medium,
|
|
||||||
]}>
|
|
||||||
<Trans>
|
|
||||||
See{' '}
|
|
||||||
<Text
|
|
||||||
style={[a.text_md, a.font_bold, t.atoms.text]}>
|
|
||||||
{displayTag}
|
|
||||||
</Text>{' '}
|
|
||||||
posts by this user
|
|
||||||
</Trans>
|
|
||||||
</Text>
|
|
||||||
</View>
|
|
||||||
</Link>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{preferences ? (
|
|
||||||
<>
|
|
||||||
<Divider />
|
|
||||||
|
|
||||||
<Button
|
|
||||||
label={
|
|
||||||
isMuted
|
|
||||||
? _(msg`Unmute all ${displayTag} posts`)
|
|
||||||
: _(msg`Mute all ${displayTag} posts`)
|
|
||||||
}
|
}
|
||||||
onPress={() => {
|
})
|
||||||
control.close(() => {
|
}}>
|
||||||
if (isMuted) {
|
<View
|
||||||
resetUpsert()
|
style={[
|
||||||
removeMutedWord({
|
a.w_full,
|
||||||
value: tag,
|
a.flex_row,
|
||||||
targets: ['tag'],
|
a.align_center,
|
||||||
})
|
a.justify_start,
|
||||||
} else {
|
a.gap_md,
|
||||||
resetRemove()
|
a.px_lg,
|
||||||
upsertMutedWord([{value: tag, targets: ['tag']}])
|
a.py_md,
|
||||||
}
|
]}>
|
||||||
})
|
<Mute size="lg" style={[t.atoms.text_contrast_medium]} />
|
||||||
}}>
|
<Text
|
||||||
<View
|
numberOfLines={1}
|
||||||
style={[
|
ellipsizeMode="middle"
|
||||||
a.w_full,
|
style={[
|
||||||
a.flex_row,
|
a.flex_1,
|
||||||
a.align_center,
|
a.text_md,
|
||||||
a.justify_start,
|
a.font_bold,
|
||||||
a.gap_md,
|
native({top: 2}),
|
||||||
a.px_lg,
|
t.atoms.text_contrast_medium,
|
||||||
a.py_md,
|
]}>
|
||||||
]}>
|
{isMuted ? _(msg`Unmute`) : _(msg`Mute`)}{' '}
|
||||||
<Mute
|
<Text style={[a.text_md, a.font_bold, t.atoms.text]}>
|
||||||
size="lg"
|
{displayTag}
|
||||||
style={[t.atoms.text_contrast_medium]}
|
</Text>{' '}
|
||||||
/>
|
<Trans>posts</Trans>
|
||||||
<Text
|
</Text>
|
||||||
numberOfLines={1}
|
</View>
|
||||||
ellipsizeMode="middle"
|
</Button>
|
||||||
style={[
|
</>
|
||||||
a.flex_1,
|
) : null}
|
||||||
a.text_md,
|
</View>
|
||||||
a.font_bold,
|
|
||||||
native({top: 2}),
|
|
||||||
t.atoms.text_contrast_medium,
|
|
||||||
]}>
|
|
||||||
{isMuted ? _(msg`Unmute`) : _(msg`Mute`)}{' '}
|
|
||||||
<Text style={[a.text_md, a.font_bold, t.atoms.text]}>
|
|
||||||
{displayTag}
|
|
||||||
</Text>{' '}
|
|
||||||
<Trans>posts</Trans>
|
|
||||||
</Text>
|
|
||||||
</View>
|
|
||||||
</Button>
|
|
||||||
</>
|
|
||||||
) : null}
|
|
||||||
</View>
|
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
label={_(msg`Close this dialog`)}
|
label={_(msg`Close this dialog`)}
|
||||||
size="small"
|
size="small"
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
color="secondary"
|
color="secondary"
|
||||||
onPress={() => control.close()}>
|
onPress={() => control.close()}>
|
||||||
<ButtonText>Cancel</ButtonText>
|
<ButtonText>Cancel</ButtonText>
|
||||||
</Button>
|
</Button>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</Dialog.Inner>
|
</Dialog.Inner>
|
||||||
</Dialog.Outer>
|
|
||||||
</>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user