Last active
June 8, 2024 14:18
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// 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