Skip to content

Instantly share code, notes, and snippets.

@realvjy
Last active June 8, 2024 14:18
Show Gist options
  • Save realvjy/4f60930d34ea37212ecf10e4fb91d038 to your computer and use it in GitHub Desktop.
Save realvjy/4f60930d34ea37212ecf10e4fb91d038 to your computer and use it in GitHub Desktop.
Framer Component Override to create 3D Book Flip Effect same as vjy.me
//
// BookFlip3D - Framer Component
// Date - 6 Jan, 2024
// Credits -
// Author: [realvjy](https://vjy.me),
// Twitter: [@realvjy](https://x.com/realvjy)
import { addPropertyControls, ControlType } from "framer"
import React, { CSSProperties, useEffect, useState } from "react"
export default function BookFlip3D(props) {
const [isHovered, setIsHovered] = useState(false)
const img = props.image
const [bookIsOpen, setBookIsOpen] = useState(props.open)
const handleMouseOver = () => {
setIsHovered(true)
}
const handleMouseOut = () => {
setIsHovered(false)
}
useEffect(() => {
if (isHovered) {
setBookIsOpen(!bookIsOpen)
return
}
setBookIsOpen(!bookIsOpen)
}, [isHovered])
useEffect(() => {
setBookIsOpen(!props.open)
}, [props.open])
const bookWrapper: CSSProperties = {
position: "relative",
cursor: "default",
padding: "16px",
margin: "0",
minWidth: "120px",
maxWidth: "300px",
}
const bookCover: CSSProperties = {
position: "relative",
height: "100%",
width: "100%",
}
const bookInside: CSSProperties = {
position: "absolute",
width: "90%",
height: "96%",
top: "1%",
left: "8%",
border: "1px solid grey",
borderRadius: "2px 6px 6px 2px",
background: "white",
boxShadow:
"10px 40px 40px -10px #00000030, inset -2px 0 0 grey, inset -3px 0 0 #dbdbdb, inset -4px 0 0 white, inset -5px 0 0 #dbdbdb, inset -6px 0 0 white, inset -7px 0 0 #dbdbdb, inset -8px 0 0 white, inset -9px 0 0 #dbdbdb, inset -10px 0 0 white, inset -11px 0 0 #dbdbdb",
}
const bookImage: CSSProperties = {
width: "100%",
lineHeight: "0",
position: "relative",
borderRadius: "2px 6px 6px 2px",
boxShadow: bookIsOpen
? "6px 6px 12px -1px rgba(0, 0, 0, 0.1), 20px 14px 16px -6px rgba(0, 0, 0, 0.1)"
: "6px 6px 18px -2px rgba(0, 0, 0, 0.2), 24px 28px 40px -6px rgba(0, 0, 0, 0.1)",
transition: "all 0.3s ease-in-out",
transform: bookIsOpen
? "perspective(2000px) rotateY(0deg) translateX(0px) scaleX(1)"
: "perspective(2000px) rotateY(-15deg) translateX(-10px) scaleX(0.94)",
cursor: "pointer",
}
const imageStyle = {
width: "100%",
height: "auto",
borderRadius: "2px 6px 6px 2px",
transition: "transform 0.3s ease-in-out",
}
const effectStyle: CSSProperties = {
position: "absolute",
width: "10px",
height: "100%",
marginLeft: "10px",
top: "0",
borderLeft: "2px solid #00000010",
backgroundImage:
"linear-gradient(90deg, rgba(255, 255, 255, 0.2) 0%, rgba(255, 255, 255, 0) 100%)",
transition: "all 0.5s ease",
zIndex: "5",
}
const lightStyle: CSSProperties = {
width: "90%",
height: "100%",
position: "absolute",
borderRadius: "3px",
backgroundImage:
"linear-gradient(90deg, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.2) 100%)",
top: "0",
right: "0",
opacity: "0.1",
transition: "all 0.5s ease",
zIndex: "4",
}
const hoverImageStyle = {
transform: "scale(1.2)", // Scale factor when hovered
}
return (
<div
style={bookWrapper}
onMouseOver={handleMouseOver}
onMouseOut={handleMouseOut}
>
<div style={bookCover}>
<div style={bookInside} />
<div style={bookImage}>
<img
src={
img
? props.image
: "https://i.imgur.com/SPv9Rg7.png"
}
style={imageStyle}
/>
<div style={effectStyle} />
<div style={lightStyle} />
</div>
</div>
</div>
)
}
addPropertyControls(BookFlip3D, {
image: {
type: ControlType.Image,
},
open: {
title: "open",
type: ControlType.Boolean,
},
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment