feat(gallery): intro animation
This commit is contained in:
@@ -2,6 +2,7 @@
|
|||||||
import { LazyGalleryModal } from "#components";
|
import { LazyGalleryModal } from "#components";
|
||||||
import type { InternalApi } from "nitropack/types";
|
import type { InternalApi } from "nitropack/types";
|
||||||
import { useElementSize } from "@vueuse/core";
|
import { useElementSize } from "@vueuse/core";
|
||||||
|
import gsap from "gsap";
|
||||||
|
|
||||||
const { data: images } = await useAsyncData(
|
const { data: images } = await useAsyncData(
|
||||||
"gallery",
|
"gallery",
|
||||||
@@ -49,6 +50,44 @@ const openModal = async (index: number) => {
|
|||||||
const getAspectRatio = (image: InternalApi["/api/gallery"]["get"][number]) => {
|
const getAspectRatio = (image: InternalApi["/api/gallery"]["get"][number]) => {
|
||||||
return (image.height / image.width) * 100;
|
return (image.height / image.width) * 100;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const isAnimating = ref(true);
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
await nextTick();
|
||||||
|
|
||||||
|
const scrollEl = scrollArea.value?.$el;
|
||||||
|
if (!scrollEl) return;
|
||||||
|
|
||||||
|
const preventScroll = (e: Event) => {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
};
|
||||||
|
|
||||||
|
scrollEl.addEventListener("wheel", preventScroll, { passive: false });
|
||||||
|
scrollEl.addEventListener("touchmove", preventScroll, { passive: false });
|
||||||
|
|
||||||
|
const items = document.querySelectorAll(".gallery-item");
|
||||||
|
gsap.fromTo(
|
||||||
|
items,
|
||||||
|
{ opacity: 0 },
|
||||||
|
{
|
||||||
|
opacity: 1,
|
||||||
|
duration: 0.6,
|
||||||
|
stagger: (index) => {
|
||||||
|
const line = Math.floor(index / lanes.value);
|
||||||
|
const column = index % lanes.value;
|
||||||
|
return line * 0.1 + column * 0.05;
|
||||||
|
},
|
||||||
|
ease: "power2.out",
|
||||||
|
onComplete: () => {
|
||||||
|
isAnimating.value = false;
|
||||||
|
scrollEl.removeEventListener("wheel", preventScroll);
|
||||||
|
scrollEl.removeEventListener("touchmove", preventScroll);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -61,6 +100,7 @@ const getAspectRatio = (image: InternalApi["/api/gallery"]["get"][number]) => {
|
|||||||
estimateSize: 510,
|
estimateSize: 510,
|
||||||
}"
|
}"
|
||||||
class="p-6 lg:p-8 xl:p-10 2xl:p-12 h-screen bg-[#0a0a0a] text-white font-[JetBrains_Mono]"
|
class="p-6 lg:p-8 xl:p-10 2xl:p-12 h-screen bg-[#0a0a0a] text-white font-[JetBrains_Mono]"
|
||||||
|
:class="{ 'no-scroll': isAnimating }"
|
||||||
>
|
>
|
||||||
<template #default="{ item: image, index }">
|
<template #default="{ item: image, index }">
|
||||||
<header v-if="index === 0" class="pr-2 pb-6">
|
<header v-if="index === 0" class="pr-2 pb-6">
|
||||||
@@ -69,6 +109,7 @@ const getAspectRatio = (image: InternalApi["/api/gallery"]["get"][number]) => {
|
|||||||
size="md"
|
size="md"
|
||||||
color="neutral"
|
color="neutral"
|
||||||
variant="link"
|
variant="link"
|
||||||
|
to="/"
|
||||||
:ui="{
|
:ui="{
|
||||||
base: 'px-0 text-neutral-600 hover:text-neutral-400',
|
base: 'px-0 text-neutral-600 hover:text-neutral-400',
|
||||||
leadingIcon: 'size-4',
|
leadingIcon: 'size-4',
|
||||||
@@ -85,7 +126,7 @@ const getAspectRatio = (image: InternalApi["/api/gallery"]["get"][number]) => {
|
|||||||
|
|
||||||
<div
|
<div
|
||||||
v-else
|
v-else
|
||||||
class="relative overflow-hidden rounded-sm cursor-pointer"
|
class="gallery-item relative overflow-hidden rounded-sm cursor-pointer"
|
||||||
:style="{ paddingBottom: `${getAspectRatio(image)}%` }"
|
:style="{ paddingBottom: `${getAspectRatio(image)}%` }"
|
||||||
@click="openModal(index)"
|
@click="openModal(index)"
|
||||||
>
|
>
|
||||||
@@ -115,3 +156,9 @@ const getAspectRatio = (image: InternalApi["/api/gallery"]["get"][number]) => {
|
|||||||
</template>
|
</template>
|
||||||
</UScrollArea>
|
</UScrollArea>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.no-scroll :deep(*) {
|
||||||
|
pointer-events: none !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
Reference in New Issue
Block a user