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