This commit is contained in:
Justin Edmund 2025-05-26 13:50:49 -07:00
parent 6ebe2d59dc
commit 4d8e23ae5b
3 changed files with 127 additions and 12 deletions

View file

@ -1,5 +1,6 @@
<script lang="ts">
import Lightbox from './Lightbox.svelte'
import TiltCard from './TiltCard.svelte'
let {
images = [],
@ -46,15 +47,19 @@
{#if images.length === 1}
<!-- Single image -->
<button class="single-image image-button" onclick={() => openLightbox()}>
<img src={images[0]} {alt} />
</button>
<TiltCard>
<button class="single-image image-button" onclick={() => openLightbox()}>
<img src={images[0]} {alt} />
</button>
</TiltCard>
{:else if images.length > 1}
<!-- Slideshow -->
<div class="slideshow">
<button class="main-image image-button" onclick={() => openLightbox()}>
<img src={images[selectedIndex]} alt="{alt} {selectedIndex + 1}" />
</button>
<TiltCard>
<button class="main-image image-button" onclick={() => openLightbox()}>
<img src={images[selectedIndex]} alt="{alt} {selectedIndex + 1}" />
</button>
</TiltCard>
<div class="thumbnails">
{#each Array(totalSlots) as _, index}
{#if index < images.length}
@ -84,11 +89,6 @@
cursor: pointer;
display: block;
width: 100%;
transition: transform 0.2s ease;
&:hover {
transform: scale(0.98);
}
&:focus {
outline: 2px solid $red-60;
@ -101,6 +101,10 @@
aspect-ratio: 4 / 3;
border-radius: $image-corner-radius;
overflow: hidden;
// Force GPU acceleration and proper clipping
transform: translateZ(0);
-webkit-backface-visibility: hidden;
backface-visibility: hidden;
img {
width: 100%;

View file

@ -16,9 +16,46 @@
new RegExp(`(${name})`, 'gi'),
`<span style="color: ${highlightColor};">$1</span>`
)
// 3D tilt effect
let cardElement: HTMLDivElement
let isHovering = false
let transform = ''
function handleMouseMove(e: MouseEvent) {
if (!cardElement || !isHovering) return
const rect = cardElement.getBoundingClientRect()
const x = e.clientX - rect.left
const y = e.clientY - rect.top
const centerX = rect.width / 2
const centerY = rect.height / 2
const rotateX = ((y - centerY) / centerY) * -4 // -4 to 4 degrees
const rotateY = ((x - centerX) / centerX) * 4 // -4 to 4 degrees
transform = `perspective(1000px) rotateX(${rotateX}deg) rotateY(${rotateY}deg) scale3d(1.014, 1.014, 1.014)`
}
function handleMouseEnter() {
isHovering = true
}
function handleMouseLeave() {
isHovering = false
transform = 'perspective(1000px) rotateX(0) rotateY(0) scale3d(1, 1, 1)'
}
</script>
<div class="project-item {isEven ? 'even' : 'odd'}">
<div
class="project-item {isEven ? 'even' : 'odd'}"
bind:this={cardElement}
on:mousemove={handleMouseMove}
on:mouseenter={handleMouseEnter}
on:mouseleave={handleMouseLeave}
style="transform: {transform};"
>
<div class="project-logo">
<SVGHoverEffect
{SVGComponent}
@ -42,6 +79,16 @@
padding: $unit-3x;
background: $grey-100;
border-radius: $card-corner-radius;
transition: transform 0.15s ease-out, box-shadow 0.15s ease-out;
transform-style: preserve-3d;
will-change: transform;
cursor: pointer;
&:hover {
box-shadow:
0 10px 30px rgba(0, 0, 0, 0.1),
0 1px 8px rgba(0, 0, 0, 0.06);
}
&.odd {
flex-direction: row-reverse;

View file

@ -0,0 +1,64 @@
<script lang="ts">
let cardElement: HTMLDivElement
let isHovering = false
let transform = ''
function handleMouseMove(e: MouseEvent) {
if (!cardElement || !isHovering) return
const rect = cardElement.getBoundingClientRect()
const x = e.clientX - rect.left
const y = e.clientY - rect.top
const centerX = rect.width / 2
const centerY = rect.height / 2
const rotateX = ((y - centerY) / centerY) * -5 // -4 to 4 degrees
const rotateY = ((x - centerX) / centerX) * 5 // -4 to 4 degrees
transform = `perspective(1000px) rotateX(${rotateX}deg) rotateY(${rotateY}deg) scale3d(1.014, 1.014, 1.014)`
}
function handleMouseEnter() {
isHovering = true
}
function handleMouseLeave() {
isHovering = false
transform = 'perspective(1000px) rotateX(0) rotateY(0) scale3d(1, 1, 1)'
}
</script>
<div
class="tilt-card"
bind:this={cardElement}
on:mousemove={handleMouseMove}
on:mouseenter={handleMouseEnter}
on:mouseleave={handleMouseLeave}
style="transform: {transform};"
>
<slot />
</div>
<style lang="scss">
.tilt-card {
transition:
transform 0.15s ease-out,
box-shadow 0.15s ease-out;
transform-style: preserve-3d;
will-change: transform;
cursor: pointer;
border-radius: $image-corner-radius;
overflow: hidden;
// Use mask as a fallback for better clipping
-webkit-mask-image: -webkit-radial-gradient(white, black);
mask-image: radial-gradient(white, black);
&:hover {
box-shadow:
0 6px 20px rgba(0, 0, 0, 0.1),
0 1px 8px rgba(0, 0, 0, 0.06);
}
}
</style>