Skip to content

Instantly share code, notes, and snippets.

@mlshv
Created August 23, 2024 00:02
Show Gist options
  • Save mlshv/4838be345580d916af4e5c32fc6f0d75 to your computer and use it in GitHub Desktop.
Save mlshv/4838be345580d916af4e5c32fc6f0d75 to your computer and use it in GitHub Desktop.
Framer splash screen code component
import { useEffect, useState } from "react"
import { addPropertyControls, ControlType } from "framer"
import { motion } from "framer-motion"
/**
* These annotations control how your component sizes
* Learn more: https://www.framer.com/developers/#code-components-auto-sizing
*
* @framerSupportedLayoutWidth auto
* @framerSupportedLayoutHeight auto
*/
export default function SplashScreen(props) {
const { children, preloadUrls } = props
const urls = preloadUrls.filter((url) => Boolean(url))
const total = urls.length
const [isContentLoaded, setIsContentLoaded] = useState(false)
const [loadedAssetsCount, setLoadedAssetsCount] = useState(0)
const loadedPercentage = (loadedAssetsCount / urls.length) * 100
useEffect(() => {
console.log("preloading assets:", urls)
const loadImages = async () => {
// toggle scroll off
document.body.style.overflow = "hidden"
const preloadMedia = async (src: string) => {
console.log("preloading", src)
try {
if (
src.endsWith(".jpg") ||
src.endsWith(".png") ||
src.endsWith(".jpeg")
) {
await new Promise((resolve, reject) => {
const img = new Image()
img.fetchpriority = "high"
img.onload = resolve
img.onerror = reject
img.src = src
})
} else {
await fetch(src, { priority: "high" })
.then((response) => {
if (!response.ok) {
throw new Error(
"Network response was not ok"
)
}
return response.blob()
})
.then((blob) => {
const url = URL.createObjectURL(blob)
return new Promise((resolve, reject) => {
if (blob.type.startsWith("video/")) {
const video =
document.createElement("video")
video.oncanplaythrough = () => {
URL.revokeObjectURL(url)
resolve(null)
}
video.onerror = reject
video.src = url
video.load() // Explicitly call load for video
} else {
reject(
new Error("Unsupported asset type")
)
}
})
})
}
} catch (error) {
console.error(`Couldn't preload asset ${src}`, error)
}
setLoadedAssetsCount((i) => {
console.log(
`Finished preloading ${i + 1}/${total} assets (${src})`
)
return i + 1
})
}
const mediaPromises = preloadUrls.map(preloadMedia)
try {
await Promise.all(mediaPromises)
} catch (error) {
console.error("Error loading media:", error)
}
console.log("finished preloading")
// toggle scroll back on
document.body.style.overflow = ""
setIsContentLoaded(true)
}
loadImages()
}, [])
return (
<motion.div
id="splash-screen"
style={{
position: "fixed",
inset: 0,
height: "100vh",
display: "flex",
justifyContent: "center",
alignItems: "center",
background: "white",
zIndex: 1000,
pointerEvents: isContentLoaded ? "none" : "all",
}}
animate={{ opacity: isContentLoaded ? 0 : 1 }}
transition={{ duration: 0.5 }}
>
<motion.div
style={{
width: "200px",
background: "#eee",
}}
transition={{
duration: 0.5,
}}
>
<motion.div
initial={{ width: "5%" }}
animate={{
width:
loadedPercentage < 5
? "5%"
: `${loadedPercentage}%`,
}}
transition={{ duration: 0.5 }}
style={{
backgroundColor: "black",
height: "4px",
borderRadius: "10px",
}}
/>
</motion.div>
</motion.div>
)
}
addPropertyControls(SplashScreen, {
preloadUrls: {
type: ControlType.Array,
title: "Assets' URLs",
control: {
type: ControlType.String,
},
},
})
SplashScreen.defaultProps = {
preloadUrls: [],
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment