mirror of https://github.com/mkrhere/pw2
1 changed files with 79 additions and 0 deletions
@ -0,0 +1,79 @@ |
|||||
|
import { css, cx } from "@emotion/css"; |
||||
|
import React, { useState, useRef } from "react"; |
||||
|
|
||||
|
export interface FlippableProps { |
||||
|
front: React.ReactNode; |
||||
|
back: React.ReactNode; |
||||
|
className?: string; |
||||
|
defaultSide?: "front" | "back"; |
||||
|
} |
||||
|
|
||||
|
export const Flippable: React.FC<FlippableProps> = ({ |
||||
|
front, |
||||
|
back, |
||||
|
className, |
||||
|
defaultSide, |
||||
|
}) => { |
||||
|
const ref = useRef<HTMLDivElement>(null); |
||||
|
const [isFlipped, setIsFlipped] = useState(defaultSide === "back"); |
||||
|
const mouseDownTime = useRef<number>(0); |
||||
|
const DRAG_THRESHOLD = 250; // milliseconds
|
||||
|
|
||||
|
const handleMouseDown = () => { |
||||
|
mouseDownTime.current = Date.now(); |
||||
|
}; |
||||
|
|
||||
|
const handleClick = () => { |
||||
|
if (Date.now() - mouseDownTime.current < DRAG_THRESHOLD) { |
||||
|
setIsFlipped(prev => !prev); |
||||
|
|
||||
|
ref.current?.animate( |
||||
|
[ |
||||
|
{ transform: "scale(1)" }, |
||||
|
{ transform: "scale(1.2)", offset: 0.4 }, |
||||
|
{ transform: "scale(1.2)", offset: 0.6 }, |
||||
|
{ transform: "scale(1)" }, |
||||
|
], |
||||
|
{ |
||||
|
duration: 600, |
||||
|
easing: "cubic-bezier(0.4, 0, 0.2, 1)", |
||||
|
}, |
||||
|
); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
return ( |
||||
|
<div |
||||
|
ref={ref} |
||||
|
onClick={handleClick} |
||||
|
onMouseDown={handleMouseDown} |
||||
|
onTouchStart={handleMouseDown} |
||||
|
className={cx( |
||||
|
css` |
||||
|
position: relative; |
||||
|
width: 100%; |
||||
|
height: 100%; |
||||
|
transform-style: preserve-3d; |
||||
|
cursor: pointer; |
||||
|
transition: rotate 0.6s cubic-bezier(0.4, 0, 0.2, 1); |
||||
|
rotate: ${isFlipped ? "y 180deg" : "y 0deg"}; |
||||
|
|
||||
|
.card-face { |
||||
|
position: absolute; |
||||
|
width: 100%; |
||||
|
height: 100%; |
||||
|
backface-visibility: hidden; |
||||
|
-webkit-backface-visibility: hidden; /* Safari */ |
||||
|
} |
||||
|
|
||||
|
.card-back { |
||||
|
rotate: y 180deg; |
||||
|
} |
||||
|
`,
|
||||
|
className, |
||||
|
)}> |
||||
|
<div className="card-face card-front">{front}</div> |
||||
|
<div className="card-face card-back">{back}</div> |
||||
|
</div> |
||||
|
); |
||||
|
}; |
Loading…
Reference in new issue