forked from
jollywhoppers.com/witchsky.app
Bluesky app fork with some witchin' additions 馃挮
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}