mirror of
https://github.com/LaconicNetwork/laconic.com.git
synced 2026-10-10 09:54:07 +00:00
Initial Commit
This commit is contained in:
@@ -0,0 +1,122 @@
|
||||
import { useMedia } from 'hooks/use-media'
|
||||
import * as React from 'react'
|
||||
|
||||
import { DURATION, gsap } from '~/lib/gsap'
|
||||
|
||||
const AnimationContext = React.createContext<
|
||||
| {
|
||||
fontsLoaded: boolean
|
||||
minInteractionTimeComplete: boolean
|
||||
prefersReducedMotion: boolean | undefined
|
||||
shouldAnimate: boolean
|
||||
}
|
||||
| undefined
|
||||
>(undefined)
|
||||
|
||||
export const AnimationContextProvider: React.FC = ({ children }) => {
|
||||
const [fontsLoaded, setFontsLoaded] = React.useState(false)
|
||||
const [minInteractionTimeComplete, setMinInteractionTimeComplete] =
|
||||
React.useState(false)
|
||||
const prefersReducedMotion = useMedia('(prefers-reduced-motion: reduce)')
|
||||
|
||||
const shouldAnimate = React.useMemo(
|
||||
() => fontsLoaded && minInteractionTimeComplete && !prefersReducedMotion,
|
||||
[fontsLoaded, minInteractionTimeComplete, prefersReducedMotion]
|
||||
)
|
||||
|
||||
React.useEffect(() => {
|
||||
if (window.fontsReady) {
|
||||
setFontsLoaded(true)
|
||||
return
|
||||
}
|
||||
|
||||
const timeout = setTimeout(() => {
|
||||
setFontsLoaded(true)
|
||||
}, 500)
|
||||
|
||||
try {
|
||||
document.fonts.ready
|
||||
.then(() => {
|
||||
setFontsLoaded(true)
|
||||
})
|
||||
.catch((error: unknown) => {
|
||||
console.error(error)
|
||||
setFontsLoaded(true)
|
||||
})
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
setFontsLoaded(true)
|
||||
}
|
||||
|
||||
return () => {
|
||||
clearTimeout(timeout)
|
||||
}
|
||||
}, [])
|
||||
|
||||
React.useEffect(() => {
|
||||
const timeout = window.setTimeout(() => {
|
||||
setMinInteractionTimeComplete(true)
|
||||
}, DURATION * 1000)
|
||||
|
||||
return () => {
|
||||
window.clearTimeout(timeout)
|
||||
}
|
||||
}, [])
|
||||
|
||||
React.useEffect(() => {
|
||||
if (fontsLoaded) {
|
||||
window.fontsReady = true
|
||||
document.documentElement.classList.add('fonts-ready')
|
||||
}
|
||||
}, [fontsLoaded, minInteractionTimeComplete])
|
||||
|
||||
React.useEffect(() => {
|
||||
if (fontsLoaded && minInteractionTimeComplete) {
|
||||
const timeline = gsap.timeline({
|
||||
paused: true,
|
||||
smoothChildTiming: true
|
||||
})
|
||||
|
||||
timeline.to(document.body, {
|
||||
opacity: 1,
|
||||
duration: DURATION,
|
||||
ease: 'BodyFadeIn'
|
||||
})
|
||||
|
||||
timeline.play()
|
||||
|
||||
return () => {
|
||||
timeline.kill()
|
||||
}
|
||||
}
|
||||
}, [fontsLoaded, minInteractionTimeComplete])
|
||||
|
||||
return (
|
||||
<AnimationContext.Provider
|
||||
value={{
|
||||
fontsLoaded,
|
||||
minInteractionTimeComplete,
|
||||
prefersReducedMotion,
|
||||
shouldAnimate
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
<style jsx global>{`
|
||||
body {
|
||||
opacity: 0;
|
||||
will-change: opacity;
|
||||
}
|
||||
`}</style>
|
||||
</AnimationContext.Provider>
|
||||
)
|
||||
}
|
||||
|
||||
export const useAnimationContext = () => {
|
||||
const context = React.useContext(AnimationContext)
|
||||
if (context === undefined) {
|
||||
throw new Error(
|
||||
'useAnimationContext must be used within a AnimationContextProvider'
|
||||
)
|
||||
}
|
||||
return context
|
||||
}
|
||||
Reference in New Issue
Block a user