forked from
jollywhoppers.com/witchsky.app
Bluesky app fork with some witchin' additions 馃挮
1import {useEffect, useState} from 'react'
2import {Pressable, View} from 'react-native'
3import {ImageBackground} from 'expo-image'
4import {msg} from '@lingui/core/macro'
5import {useLingui} from '@lingui/react'
6import {Trans} from '@lingui/react/macro'
7import {FocusGuards, FocusScope} from 'radix-ui/internal'
8
9import {useLoggedOutViewControls} from '#/state/shell/logged-out'
10import {Logo} from '#/view/icons/Logo'
11import {atoms as a, flatten, useBreakpoints, web} from '#/alf'
12import {Button, ButtonText} from '#/components/Button'
13import {TimesLarge_Stroke2_Corner0_Rounded as XIcon} from '#/components/icons/Times'
14import {Text} from '#/components/Typography'
15import {useAnalytics} from '#/analytics'
16
17const welcomeModalBg = require('../../assets/images/welcome-modal-bg.jpg')
18
19interface WelcomeModalProps {
20 control: {
21 isOpen: boolean
22 open: () => void
23 close: () => void
24 }
25}
26
27export function WelcomeModal({control}: WelcomeModalProps) {
28 const {_} = useLingui()
29 const ax = useAnalytics()
30 const {requestSwitchToAccount} = useLoggedOutViewControls()
31 const {gtMobile} = useBreakpoints()
32 const [isExiting, setIsExiting] = useState(false)
33 const [signInLinkHovered, setSignInLinkHovered] = useState(false)
34
35 const fadeOutAndClose = (callback?: () => void) => {
36 setIsExiting(true)
37 setTimeout(() => {
38 control.close()
39 if (callback) callback()
40 }, 150)
41 }
42
43 useEffect(() => {
44 if (control.isOpen) {
45 ax.metric('welcomeModal:presented', {})
46 }
47 // eslint-disable-next-line react-hooks/exhaustive-deps
48 }, [control.isOpen])
49
50 const onPressCreateAccount = () => {
51 ax.metric('welcomeModal:signupClicked', {})
52 control.close()
53 requestSwitchToAccount({requestedAccount: 'new'})
54 }
55
56 const onPressExplore = () => {
57 ax.metric('welcomeModal:exploreClicked', {})
58 fadeOutAndClose()
59 }
60
61 const onPressSignIn = () => {
62 ax.metric('welcomeModal:signinClicked', {})
63 control.close()
64 requestSwitchToAccount({requestedAccount: 'existing'})
65 }
66
67 FocusGuards.useFocusGuards()
68
69 return (
70 <View
71 role="dialog"
72 aria-modal
73 style={[
74 a.fixed,
75 a.inset_0,
76 a.justify_center,
77 a.align_center,
78 {zIndex: 9999, backgroundColor: 'rgba(0,0,0,0.2)'},
79 web({backdropFilter: 'blur(15px)'}),
80 isExiting ? a.fade_out : a.fade_in,
81 ]}>
82 <FocusScope.FocusScope asChild loop trapped>
83 <View
84 style={flatten([
85 {
86 maxWidth: 800,
87 maxHeight: 600,
88 width: '90%',
89 height: '90%',
90 backgroundColor: '#C0DCF0',
91 },
92 a.rounded_lg,
93 a.overflow_hidden,
94 a.zoom_in,
95 ])}>
96 <ImageBackground
97 source={welcomeModalBg}
98 style={[a.flex_1, a.justify_center]}
99 contentFit="cover">
100 <View style={[a.gap_2xl, a.align_center, a.p_4xl]}>
101 <View
102 style={[
103 a.flex_row,
104 a.align_center,
105 a.justify_center,
106 a.w_full,
107 a.p_0,
108 ]}>
109 <View style={[a.flex_row, a.align_center, a.gap_xs]}>
110 <Logo width={26} />
111 <Text
112 style={[
113 a.text_2xl,
114 a.font_semi_bold,
115 a.user_select_none,
116 {color: '#354358', letterSpacing: -0.5},
117 ]}>
118 Bluesky
119 </Text>
120 </View>
121 </View>
122 <View
123 style={[
124 a.gap_sm,
125 a.align_center,
126 a.pt_5xl,
127 a.pb_3xl,
128 a.mt_2xl,
129 ]}>
130 <Text
131 style={[
132 gtMobile ? a.text_4xl : a.text_3xl,
133 a.font_semi_bold,
134 a.text_center,
135 {color: '#354358'},
136 web({
137 backgroundImage:
138 'linear-gradient(180deg, #313F54 0%, #667B99 83.65%, rgba(102, 123, 153, 0.50) 100%)',
139 backgroundClip: 'text',
140 WebkitBackgroundClip: 'text',
141 WebkitTextFillColor: 'transparent',
142 color: 'transparent',
143 lineHeight: 1.2,
144 letterSpacing: -0.5,
145 }),
146 ]}>
147 <Trans>Real people.</Trans>
148 {'\n'}
149 <Trans>Real conversations.</Trans>
150 {'\n'}
151 <Trans>Social media you control.</Trans>
152 </Text>
153 </View>
154 <View style={[a.gap_md, a.align_center]}>
155 <View>
156 <Button
157 onPress={onPressCreateAccount}
158 label={_(msg`Create account`)}
159 size="large"
160 color="primary"
161 style={{
162 width: 200,
163 backgroundColor: '#006AFF',
164 }}>
165 <ButtonText>
166 <Trans>Create account</Trans>
167 </ButtonText>
168 </Button>
169 <Button
170 onPress={onPressExplore}
171 label={_(msg`Explore the app`)}
172 size="large"
173 color="primary"
174 variant="ghost"
175 style={[a.bg_transparent, {width: 200}]}
176 hoverStyle={[a.bg_transparent]}>
177 {({hovered}) => (
178 <ButtonText
179 style={[hovered && [a.underline], {color: '#006AFF'}]}>
180 <Trans>Explore the app</Trans>
181 </ButtonText>
182 )}
183 </Button>
184 </View>
185 <View style={[a.align_center, {minWidth: 200}]}>
186 <Text
187 style={[
188 a.text_md,
189 a.text_center,
190 {color: '#405168', lineHeight: 24},
191 ]}>
192 <Trans>Already have an account?</Trans>{' '}
193 <Pressable
194 onPointerEnter={() => setSignInLinkHovered(true)}
195 onPointerLeave={() => setSignInLinkHovered(false)}
196 accessibilityRole="button"
197 accessibilityLabel={_(msg`Sign in`)}
198 accessibilityHint="">
199 <Text
200 style={[
201 a.font_medium,
202 {
203 color: '#006AFF',
204 fontSize: undefined,
205 },
206 signInLinkHovered && a.underline,
207 ]}
208 onPress={onPressSignIn}>
209 <Trans>Sign in</Trans>
210 </Text>
211 </Pressable>
212 </Text>
213 </View>
214 </View>
215 </View>
216 <Button
217 label={_(msg`Close welcome modal`)}
218 style={[
219 a.absolute,
220 {
221 top: 8,
222 right: 8,
223 },
224 a.bg_transparent,
225 ]}
226 hoverStyle={[a.bg_transparent]}
227 onPress={() => {
228 ax.metric('welcomeModal:dismissed', {})
229 fadeOutAndClose()
230 }}
231 color="secondary"
232 size="small"
233 variant="ghost"
234 shape="round">
235 {({hovered, pressed, focused}) => (
236 <XIcon
237 size="md"
238 style={{
239 color: '#354358',
240 opacity: hovered || pressed || focused ? 1 : 0.7,
241 }}
242 />
243 )}
244 </Button>
245 </ImageBackground>
246 </View>
247 </FocusScope.FocusScope>
248 </View>
249 )
250}