Files
hossein-por-shop/frontend/components/global/SideModal.vue
T
2025-01-07 18:13:27 +03:30

91 lines
2.1 KiB
Vue

<script setup lang="ts">
// types
type Props = {
title: string;
};
defineProps<Props>();
// state
const { $gsap: gsap } = useNuxtApp();
const isSideShow = ref(false);
const tl = gsap.timeline();
// methods
const enterAnimation = () => {
tl.to("#side-overlay", { opacity: 1 }).fromTo(
"#side-content",
{
right: "-100%",
opacity: 0,
},
{
right: 0,
opacity: 1,
},
"<"
);
};
const closeAnimation = () => {
tl.reverse().then(() => (isSideShow.value = false));
};
// watch
watch(
() => isSideShow.value,
(newValue) => {
newValue ? enterAnimation() : null;
}
);
</script>
<template>
<div class="relative z-[90]">
<div @click="isSideShow = true">
<slot name="button" />
</div>
<div v-show="isSideShow" class="fixed inset-0">
<div
id="side-overlay"
class="size-full bg-black/20"
@click="closeAnimation"
></div>
<div
id="side-content"
class="hidden md:flex w-1/3 lg:w-2/5 bg-white h-full rounded-e-[1.5rem] overflow-hidden absolute top-0 min-md:flex-col"
>
<div
class="w-full flex justify-between items-center py-[2.5rem] px-[3rem]"
>
<span class="typo-h-5">
{{ title }}
</span>
<button
@click="closeAnimation"
class="size-[3.5rem] flex-center rounded-full border border-transparent hover:border-slate-200 transition-all"
>
<Icon
name="ci:close"
size="24"
class="**:stroke-black"
/>
</button>
</div>
<div class="size-full flex flex-col grow bg-red-400">
<slot />
</div>
</div>
</div>
</div>
</template>
<style scoped></style>