forked from
jollywhoppers.com/witchsky.app
Bluesky app fork with some witchin' additions 馃挮
1import {msg, Trans} from '@lingui/macro'
2import {useLingui} from '@lingui/react'
3
4import {LANG_DROPDOWN_HITSLOP} from '#/lib/constants'
5import {codeToLanguageName} from '#/locale/helpers'
6import {getTerminology, TERMINOLOGY} from '#/lib/strings/terminology'
7import {useTerminologyPreference} from '#/state/preferences'
8import {
9 toPostLanguages,
10 useLanguagePrefs,
11 useLanguagePrefsApi,
12} from '#/state/preferences/languages'
13import {atoms as a, useTheme} from '#/alf'
14import {Button, type ButtonProps} from '#/components/Button'
15import * as Dialog from '#/components/Dialog'
16import {ChevronRight_Stroke2_Corner0_Rounded as ChevronRightIcon} from '#/components/icons/Chevron'
17import {Globe_Stroke2_Corner0_Rounded as GlobeIcon} from '#/components/icons/Globe'
18import * as Menu from '#/components/Menu'
19import {Text} from '#/components/Typography'
20import {PostLanguageSelectDialog} from './PostLanguageSelectDialog'
21
22export function PostLanguageSelect({
23 currentLanguages: currentLanguagesProp,
24 onSelectLanguage,
25}: {
26 currentLanguages?: string[]
27 onSelectLanguage?: (language: string) => void
28}) {
29 const {_} = useLingui()
30 const terminologyPreference = useTerminologyPreference()
31 const langPrefs = useLanguagePrefs()
32 const setLangPrefs = useLanguagePrefsApi()
33 const languageDialogControl = Dialog.useDialogControl()
34
35 const dedupedHistory = Array.from(
36 new Set([...langPrefs.postLanguageHistory, langPrefs.postLanguage]),
37 )
38
39 const currentLanguages =
40 currentLanguagesProp ?? toPostLanguages(langPrefs.postLanguage)
41
42 if (
43 dedupedHistory.length === 1 &&
44 dedupedHistory[0] === langPrefs.postLanguage
45 ) {
46 return (
47 <>
48 <LanguageBtn onPress={languageDialogControl.open} />
49 <PostLanguageSelectDialog
50 control={languageDialogControl}
51 currentLanguages={currentLanguages}
52 />
53 </>
54 )
55 }
56
57 return (
58 <>
59 <Menu.Root>
60 <Menu.Trigger label={_(getTerminology(terminologyPreference, TERMINOLOGY.selectLanguage))}>
61 {({props}) => (
62 <LanguageBtn currentLanguages={currentLanguages} {...props} />
63 )}
64 </Menu.Trigger>
65 <Menu.Outer>
66 <Menu.Group>
67 {dedupedHistory.map(historyItem => {
68 const langCodes = historyItem.split(',')
69 const langName = langCodes
70 .map(code => codeToLanguageName(code, langPrefs.appLanguage))
71 .join(' + ')
72 return (
73 <Menu.Item
74 key={historyItem}
75 label={_(msg`Select ${langName}`)}
76 onPress={() => {
77 setLangPrefs.setPostLanguage(historyItem)
78 onSelectLanguage?.(historyItem)
79 }}>
80 <Menu.ItemText>{langName}</Menu.ItemText>
81 <Menu.ItemRadio
82 selected={currentLanguages.includes(historyItem)}
83 />
84 </Menu.Item>
85 )
86 })}
87 </Menu.Group>
88 <Menu.Divider />
89 <Menu.Item
90 label={_(msg`More languages...`)}
91 onPress={languageDialogControl.open}>
92 <Menu.ItemText>
93 <Trans>More languages...</Trans>
94 </Menu.ItemText>
95 <Menu.ItemIcon icon={ChevronRightIcon} />
96 </Menu.Item>
97 </Menu.Outer>
98 </Menu.Root>
99
100 <PostLanguageSelectDialog
101 control={languageDialogControl}
102 currentLanguages={currentLanguages}
103 onSelectLanguage={onSelectLanguage}
104 />
105 </>
106 )
107}
108
109function LanguageBtn(
110 props: Omit<ButtonProps, 'label' | 'children'> & {
111 currentLanguages?: string[]
112 },
113) {
114 const {_} = useLingui()
115 const terminologyPreference = useTerminologyPreference()
116 const langPrefs = useLanguagePrefs()
117 const t = useTheme()
118
119 const postLanguagesPref = toPostLanguages(langPrefs.postLanguage)
120 const currentLanguages = props.currentLanguages ?? postLanguagesPref
121
122 return (
123 <Button
124 testID="selectLangBtn"
125 size="small"
126 hitSlop={LANG_DROPDOWN_HITSLOP}
127 label={_(getTerminology(terminologyPreference, TERMINOLOGY.selectLanguage))}
128 accessibilityHint={_(msg`Opens post language settings`)}
129 style={[a.mr_xs]}
130 {...props}>
131 {({pressed, hovered}) => {
132 const color =
133 pressed || hovered ? t.palette.primary_300 : t.palette.primary_500
134 if (currentLanguages.length > 0) {
135 return (
136 <Text
137 style={[
138 {color},
139 a.font_semi_bold,
140 a.text_sm,
141 a.leading_snug,
142 {maxWidth: 100},
143 ]}
144 numberOfLines={1}>
145 {currentLanguages
146 .map(lang => codeToLanguageName(lang, langPrefs.appLanguage))
147 .join(', ')}
148 </Text>
149 )
150 } else {
151 return <GlobeIcon size="xs" style={{color}} />
152 }
153 }}
154 </Button>
155 )
156}