feat: tiltcard component
This commit is contained in:
parent
b7f951b9c7
commit
2e7009fef2
1 changed files with 74 additions and 0 deletions
74
src/routes/tiltcard.svelte
Normal file
74
src/routes/tiltcard.svelte
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
<script lang="ts">
|
||||||
|
export let imageSrc: string;
|
||||||
|
export let imageAlt: string = 'Card image';
|
||||||
|
export let width: string = '300px';
|
||||||
|
export let height: string = '400px';
|
||||||
|
|
||||||
|
let cardElement: HTMLDivElement;
|
||||||
|
let rotateX = 0;
|
||||||
|
let rotateY = 0;
|
||||||
|
let isHovered = false;
|
||||||
|
|
||||||
|
// Derived shadow offsets
|
||||||
|
let shadowX = 0;
|
||||||
|
let shadowY = 0;
|
||||||
|
let shadowBlur = 20;
|
||||||
|
|
||||||
|
function handleMouseMove(event: MouseEvent) {
|
||||||
|
if (!cardElement) return;
|
||||||
|
|
||||||
|
const rect = cardElement.getBoundingClientRect();
|
||||||
|
const x = event.clientX - rect.left;
|
||||||
|
const y = event.clientY - rect.top;
|
||||||
|
|
||||||
|
const centerX = rect.width / 2;
|
||||||
|
const centerY = rect.height / 2;
|
||||||
|
|
||||||
|
// Calculate rotation based on cursor position (max tilt of 10 degrees)
|
||||||
|
rotateY = ((x - centerX) / centerX) * 10 * 2;
|
||||||
|
rotateX = ((centerY - y) / centerY) * 10 * 2;
|
||||||
|
|
||||||
|
// Make shadow move opposite to tilt for a realistic lighting effect
|
||||||
|
shadowX = -rotateY * 0.7; // exaggerate slightly
|
||||||
|
shadowY = rotateX * 0.7;
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleMouseEnter() {
|
||||||
|
isHovered = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleMouseLeave() {
|
||||||
|
isHovered = false;
|
||||||
|
rotateX = 0;
|
||||||
|
rotateY = 0;
|
||||||
|
shadowX = 0;
|
||||||
|
shadowY = 0;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div
|
||||||
|
bind:this={cardElement}
|
||||||
|
class="cursor-pointer"
|
||||||
|
class:scale-[1.03]={isHovered}
|
||||||
|
style="
|
||||||
|
width: {width};
|
||||||
|
height: {height};
|
||||||
|
perspective: 1000px;
|
||||||
|
filter: drop-shadow({shadowX}px {shadowY}px 0px rgba(0, 0, 0, 0.5));
|
||||||
|
"
|
||||||
|
on:mousemove={handleMouseMove}
|
||||||
|
on:mouseenter={handleMouseEnter}
|
||||||
|
on:mouseleave={handleMouseLeave}
|
||||||
|
role="img"
|
||||||
|
aria-label={imageAlt}
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
src={imageSrc}
|
||||||
|
alt={imageAlt}
|
||||||
|
class="h-full w-full rounded-xl object-cover transition-transform duration-100 ease-out"
|
||||||
|
style="
|
||||||
|
transform: rotateX({rotateX}deg) rotateY({rotateY}deg);
|
||||||
|
transform-style: preserve-3d;
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</div>
|
Loading…
Add table
Reference in a new issue