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