Files
bsky-social-app/src/screens/Search/components/SearchLanguageDropdown.tsx
T

113 lines
3.8 KiB
TypeScript

import {useMemo} from 'react'
import {Trans, useLingui} from '@lingui/react/macro'
import {languageName} from '#/locale/helpers'
import {APP_LANGUAGES, LANGUAGES} from '#/locale/languages'
import {useLanguagePrefs} from '#/state/preferences'
import {atoms as a, native, platform} from '#/alf'
import {Button, ButtonIcon, ButtonText} from '#/components/Button'
import {
ChevronBottom_Stroke2_Corner0_Rounded as ChevronDownIcon,
ChevronTopBottom_Stroke2_Corner0_Rounded as ChevronUpDownIcon,
} from '#/components/icons/Chevron'
import {Earth_Stroke2_Corner0_Rounded as EarthIcon} from '#/components/icons/Globe'
import * as Menu from '#/components/Menu'
export function SearchLanguageDropdown({
showIcon = true,
value,
onChange,
}: {
showIcon?: boolean
value: string
onChange(value: string): void
}) {
const {t: l} = useLingui()
const {appLanguage, contentLanguages, primaryLanguage} = useLanguagePrefs()
const languages = useMemo(() => {
return LANGUAGES.filter(
(lang, index, self) =>
Boolean(lang.code2) && // reduce to the code2 varieties
index === self.findIndex(t => t.code2 === lang.code2), // remove dupes (which will happen)
)
.map(l => ({
label: languageName(l, appLanguage),
value: l.code2,
key: l.code2 + l.code3,
}))
.sort((a, b) => {
// prioritize user's languages
const aIsUser = contentLanguages.includes(a.value)
const bIsUser = contentLanguages.includes(b.value)
if (aIsUser && !bIsUser) return -1
if (bIsUser && !aIsUser) return 1
// prioritize "common" langs in the network
const aIsCommon = !!APP_LANGUAGES.find(
al =>
// skip `ast`, because it uses a 3-letter code which conflicts with `as`
// it begins with `a` anyway so still is top of the list
(al.code2 as string) !== 'ast' && al.code2.startsWith(a.value),
)
const bIsCommon = !!APP_LANGUAGES.find(
al =>
// ditto
(al.code2 as string) !== 'ast' && al.code2.startsWith(b.value),
)
if (aIsCommon && !bIsCommon) return -1
if (bIsCommon && !aIsCommon) return 1
// fall back to alphabetical
return a.label.localeCompare(b.label, primaryLanguage)
})
}, [appLanguage, contentLanguages, primaryLanguage])
const currentLanguageLabel =
languages.find(lang => lang.value === value)?.label ?? l`No language filter`
return (
<Menu.Root>
<Menu.Trigger
label={l`Filter search by language (currently: ${currentLanguageLabel})`}>
{({props}) => (
<Button
{...props}
label={props.accessibilityLabel}
size="small"
color="secondary"
variant="solid"
style={showIcon ? native([a.py_sm, a.px_sm]) : null}>
{showIcon ? <ButtonIcon icon={EarthIcon} /> : null}
<ButtonText>{currentLanguageLabel}</ButtonText>
<ButtonIcon
icon={platform({
native: ChevronUpDownIcon,
default: ChevronDownIcon,
})}
/>
</Button>
)}
</Menu.Trigger>
<Menu.Outer>
<Menu.Item label={l`No language filter`} onPress={() => onChange('')}>
<Menu.ItemText>
<Trans>No language filter</Trans>
</Menu.ItemText>
<Menu.ItemRadio selected={value === ''} />
</Menu.Item>
<Menu.Divider />
<Menu.Group>
{languages.map(lang => (
<Menu.Item
key={lang.key}
label={lang.label}
onPress={() => onChange(lang.value)}>
<Menu.ItemText>{lang.label}</Menu.ItemText>
<Menu.ItemRadio selected={value === lang.value} />
</Menu.Item>
))}
</Menu.Group>
</Menu.Outer>
</Menu.Root>
)
}