color hover animation

This commit is contained in:
nicwands 2026-06-25 13:55:47 -04:00
parent 2464e7661c
commit cb1d65e0b8
4 changed files with 51 additions and 6 deletions

View file

@ -84,19 +84,19 @@ onMounted(() => {
clipPath: 'inset(0% 0% 0% 0%)', clipPath: 'inset(0% 0% 0% 0%)',
...ANIMATION_SETTINGS, ...ANIMATION_SETTINGS,
}, },
'<+0.1', 0,
) )
tl.value.fromTo( tl.value.fromTo(
contentWindow.value, contentWindow.value,
{ opacity: 0, clipPath: 'inset(0% 0% 100% 0%)' }, { opacity: 0, clipPath: 'inset(0% 0% 100% 0%)' },
{ opacity: 1, clipPath: 'inset(0% 0% 0% 0%)', ...ANIMATION_SETTINGS }, { opacity: 1, clipPath: 'inset(0% 0% 0% 0%)', ...ANIMATION_SETTINGS },
'<+0.1', 0,
) )
tl.value.fromTo( tl.value.fromTo(
closeWindow.value, closeWindow.value,
{ opacity: 0 }, { opacity: 0 },
{ opacity: 1, ...ANIMATION_SETTINGS }, { opacity: 1, ...ANIMATION_SETTINGS },
'<+0.1', 0,
) )
tl.value.pause(0) tl.value.pause(0)

View file

@ -8,7 +8,7 @@
> >
<div class="mosaic-container"> <div class="mosaic-container">
<router-link <router-link
v-for="cell in content.cells" v-for="(cell, i) in content.cells"
:class="[ :class="[
'mosaic-cell', 'mosaic-cell',
`layout-${cell.width >= cell.height ? 'landscape' : 'portrait'}`, `layout-${cell.width >= cell.height ? 'landscape' : 'portrait'}`,
@ -24,8 +24,10 @@
params: { id: cell.content.slug }, params: { id: cell.content.slug },
}" }"
:key="`${viewport.index}-${cell.id}`" :key="`${viewport.index}-${cell.id}`"
@mouseenter="onMouseEnter(i)"
ref="cells" ref="cells"
> >
<div class="hover-bg" :style="{ background: hoverColors[i] }" />
<strapi-media <strapi-media
:image="cell.content.image" :image="cell.content.image"
:aspect="100" :aspect="100"
@ -40,6 +42,9 @@
import { ref } from 'vue' import { ref } from 'vue'
import gsap from 'gsap' import gsap from 'gsap'
const THEME_S = 90
const THEME_L = 50
const props = defineProps({ const props = defineProps({
viewport: { viewport: {
type: Object, type: Object,
@ -52,13 +57,23 @@ const props = defineProps({
}) })
const cells = ref([]) const cells = ref([])
const hoverColors = ref(
cells.value.map(
() => `hsl(${Math.random() * 360}deg ${THEME_S}% ${THEME_L}%)`,
),
)
const onMouseEnter = (i) => {
hoverColors.value[i] =
`hsl(${Math.random() * 360}deg ${THEME_S}% ${THEME_L}%)`
}
const onIntersect = (isIntersecting) => { const onIntersect = (isIntersecting) => {
if (isIntersecting) { if (isIntersecting) {
if (!cells.value) return if (!cells.value) return
const cellGifs = cells.value const cellGifs = cells.value
.map((cell) => cell.$el?.children?.[0]) .map((cell) => cell.$el?.children?.[1])
.filter(Boolean) .filter(Boolean)
gsap.to(cellGifs, { opacity: 1, duration: 0, stagger: 0.1 }) gsap.to(cellGifs, { opacity: 1, duration: 0, stagger: 0.1 })
@ -98,9 +113,25 @@ const onIntersect = (isIntersecting) => {
aspect-ratio: 1; aspect-ratio: 1;
} }
} }
.hover-bg {
position: absolute;
inset: 0;
clip-path: circle(0% at 50% 50%);
transition: clip-path 0.3s ease-in-out;
}
.strapi-media { .strapi-media {
mix-blend-mode: darken;
opacity: 0; opacity: 0;
position: relative;
z-index: 5;
}
&:hover {
.strapi-media {
@include bonk-animation(0s, 1s, 10deg);
}
.hover-bg {
clip-path: circle(100% at 50% 50%);
}
} }
} }
} }

View file

@ -185,3 +185,8 @@ $mobile-height: get('viewports.mobile.height');
} }
} }
} }
@mixin bonk-animation($delay: 0s, $duration: 1s, $angle: 25deg) {
--bonk-angle: #{$angle};
animation: bonk $duration $delay infinite step-end;
}

View file

@ -59,3 +59,12 @@ dt {
code { code {
@include code; @include code;
} }
@keyframes bonk {
0% {
transform: rotate(calc(var(--bonk-angle) * -1));
}
50% {
transform: rotate(var(--bonk-angle));
}
}