Bluesky app fork with some witchin' additions 馃挮
at 5ee667f307bc459ba53cdaabdad00a0ea1ee6846 250 lines 8.3 kB view raw
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}