Bluesky app fork with some witchin' additions 馃挮
at 5ee667f307bc459ba53cdaabdad00a0ea1ee6846 97 lines 2.9 kB view raw
1/* 2 * This is a reimplementation of what exists in our HTML template files 3 * already. Once the React tree mounts, this is what gets rendered first, until 4 * the app is ready to go. 5 */ 6 7import {useEffect, useRef, useState} from 'react' 8import Svg, {Path} from 'react-native-svg' 9 10import {atoms as a, flatten} from '#/alf' 11 12const size = 100 13const ratio = 57 / 64 14 15export function Splash({ 16 isReady, 17 children, 18}: React.PropsWithChildren<{ 19 isReady: boolean 20}>) { 21 const [isAnimationComplete, setIsAnimationComplete] = useState(false) 22 const splashRef = useRef<HTMLDivElement>(null) 23 24 // hide the static one that's baked into the HTML - gets replaced by our React version below 25 useEffect(() => { 26 // double rAF ensures that the React version gets painted first 27 requestAnimationFrame(() => { 28 requestAnimationFrame(() => { 29 const splash = document.getElementById('splash') 30 if (splash) { 31 splash.remove() 32 } 33 }) 34 }) 35 }, []) 36 37 // when ready, we fade/scale out 38 useEffect(() => { 39 if (!isReady) return 40 41 const reduceMotion = window.matchMedia( 42 '(prefers-reduced-motion: reduce)', 43 ).matches 44 const node = splashRef.current 45 if (!node || reduceMotion) { 46 setIsAnimationComplete(true) 47 return 48 } 49 50 const animation = node.animate( 51 [ 52 {opacity: 1, transform: 'scale(1)'}, 53 {opacity: 0, transform: 'scale(1.5)'}, 54 ], 55 { 56 duration: 300, 57 easing: 'cubic-bezier(0.25, 0.46, 0.45, 0.94)', 58 fill: 'forwards', 59 }, 60 ) 61 animation.onfinish = () => setIsAnimationComplete(true) 62 63 return () => { 64 animation.cancel() 65 } 66 }, [isReady]) 67 68 return ( 69 <> 70 {isReady && children} 71 72 {!isAnimationComplete && ( 73 <div 74 ref={splashRef} 75 style={flatten([ 76 a.fixed, 77 a.inset_0, 78 a.flex, 79 a.align_center, 80 a.justify_center, 81 // to compensate for the `top: -50px` below 82 {transformOrigin: 'center calc(50% - 50px)'}, 83 ])}> 84 <Svg 85 fill="none" 86 viewBox="0 0 64 57" 87 style={[a.relative, {width: size, height: size * ratio, top: -50}]}> 88 <Path 89 fill="#006AFF" 90 d="M13.873 3.805C21.21 9.332 29.103 20.537 32 26.55v15.882c0-.338-.13.044-.41.867-1.512 4.456-7.418 21.847-20.923 7.944-7.111-7.32-3.819-14.64 9.125-16.85-7.405 1.264-15.73-.825-18.014-9.015C1.12 23.022 0 8.51 0 6.55 0-3.268 8.579-.182 13.873 3.805ZM50.127 3.805C42.79 9.332 34.897 20.537 32 26.55v15.882c0-.338.13.044.41.867 1.512 4.456 7.418 21.847 20.923 7.944 7.111-7.32 3.819-14.64-9.125-16.85 7.405 1.264 15.73-.825 18.014-9.015C62.88 23.022 64 8.51 64 6.55c0-9.818-8.578-6.732-13.873-2.745Z" 91 /> 92 </Svg> 93 </div> 94 )} 95 </> 96 ) 97}