Merge branch 'main' of https://github.com/Byeto-Company/hossein_por_shop
This commit is contained in:
@@ -0,0 +1 @@
|
||||
.idea
|
||||
@@ -1,6 +1,6 @@
|
||||
@utility input-outlined-error {
|
||||
@apply text-danger-600 border-danger-600;
|
||||
svg[class~=iconify] path {
|
||||
svg[class~=iconify]:not(.static-icon) path {
|
||||
@apply stroke-danger-600;
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
@utility input-outlined-disabled {
|
||||
@apply text-slate-300 border-slate-200;
|
||||
svg[class~=iconify] path {
|
||||
svg[class~=iconify]:not(.static-icon) path {
|
||||
@apply stroke-slate-300;
|
||||
}
|
||||
}
|
||||
@@ -28,7 +28,7 @@
|
||||
&:focus-within {
|
||||
@apply border-black text-black;
|
||||
|
||||
svg[class~=iconify] path {
|
||||
svg[class~=iconify]:not(.static-icon) path {
|
||||
@apply stroke-black;
|
||||
}
|
||||
}
|
||||
@@ -37,7 +37,7 @@
|
||||
@utility input-outlined {
|
||||
@apply text-slate-500 border-slate-200;
|
||||
|
||||
svg[class~=iconify] path {
|
||||
svg[class~=iconify]:not(.static-icon) path {
|
||||
@apply stroke-slate-500;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,11 @@
|
||||
@import "./fonts/yekan-bakh.css";
|
||||
|
||||
@theme {
|
||||
|
||||
/* CONTAINER */
|
||||
|
||||
--app-container-padding: 20px;
|
||||
|
||||
/* COLORS */
|
||||
--color-slate-50: hsl(210, 40%, 98%);
|
||||
--color-slate-100: hsl(210, 40%, 96%);
|
||||
@@ -128,6 +133,8 @@
|
||||
/* ANIMATIONS */
|
||||
--animate-marquee: marquee 20s linear infinite;
|
||||
--animate-marquee-reverse: marquee 20s linear infinite reverse;
|
||||
--animate-fade-in: fadeIn 350ms ease-in-out;
|
||||
|
||||
--animate-slide-down: slideDown 300ms ease-out;
|
||||
--animate-slide-up: slideUp 300ms ease-out;
|
||||
--animate-overlay-show: overlayShow 150ms ease-in;
|
||||
@@ -148,6 +155,16 @@
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes slideDown {
|
||||
from {
|
||||
height: 0;
|
||||
@@ -265,31 +282,7 @@
|
||||
/* CONTAINER */
|
||||
|
||||
@utility container {
|
||||
@apply mx-auto px-6;
|
||||
|
||||
@screen 2xs {
|
||||
@apply px-4;
|
||||
}
|
||||
|
||||
@screen xs {
|
||||
@apply px-4;
|
||||
}
|
||||
|
||||
@screen sm {
|
||||
@apply px-4;
|
||||
}
|
||||
|
||||
@screen md {
|
||||
@apply px-8;
|
||||
}
|
||||
|
||||
@screen lg {
|
||||
@apply px-12;
|
||||
}
|
||||
|
||||
@screen xl {
|
||||
@apply px-20;
|
||||
}
|
||||
@apply mx-auto px-[var(--app-container-padding)];
|
||||
}
|
||||
|
||||
@layer {
|
||||
|
||||
@@ -15,7 +15,7 @@ const props = withDefaults(defineProps<Props>(), {
|
||||
disabled: false,
|
||||
placeholder: "وارد نشده",
|
||||
});
|
||||
const { variant, message, error, disabled, modelValue } = toRefs(props);
|
||||
const { variant, error, modelValue } = toRefs(props);
|
||||
|
||||
// emits
|
||||
|
||||
@@ -29,7 +29,7 @@ const inputRef = ref<HTMLInputElement | null>(null);
|
||||
|
||||
const value = computed({
|
||||
get: () => modelValue.value ?? "",
|
||||
set: (value) => emit("update:modelValue", value),
|
||||
set: (value) => emit("update:modelValue", value)
|
||||
});
|
||||
|
||||
const classes = computed(() => {
|
||||
@@ -41,8 +41,8 @@ const classes = computed(() => {
|
||||
"input-effects": !error.value,
|
||||
[variant.value === "solid"
|
||||
? "input-solid-error"
|
||||
: "input-outlined-error"]: error.value,
|
||||
},
|
||||
: "input-outlined-error"]: error.value
|
||||
}
|
||||
];
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
<script lang="ts" setup>
|
||||
|
||||
// types
|
||||
|
||||
type Props = {
|
||||
title: string,
|
||||
products: ProductListItem[]
|
||||
}
|
||||
|
||||
// props
|
||||
|
||||
defineProps<Props>();
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section class="w-full flex flex-col gap-10 md:gap-[4rem] py-[5rem] container">
|
||||
<div class="w-full flex justify-between items-center">
|
||||
<span class="text-black typo-h-6 max-sm:text-xl md:typo-h-5 lg:typo-h-4">
|
||||
{{ title }}
|
||||
</span>
|
||||
<NuxtLink to="/products">
|
||||
<Button variant="outlined" class="rounded-full max-sm:typo-label-sm max-sm:py-2" end-icon="ci:arrow-left">
|
||||
نمایش همه
|
||||
</Button>
|
||||
</NuxtLink>
|
||||
</div>
|
||||
<div class="grid grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-y-8 gap-5 sm:gap-8">
|
||||
<ProductCard
|
||||
v-for="product in products"
|
||||
:key="product.id"
|
||||
:id="product.id"
|
||||
:title="product.name"
|
||||
:picture="product.variants[0].images[0].image"
|
||||
:colors="product.colors"
|
||||
:price="product.variants[0].price"
|
||||
:rate="product.rating"
|
||||
:dark-layer="true"
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
@@ -35,11 +35,11 @@ const highlights = ref<Highlight[]>([
|
||||
|
||||
<template>
|
||||
<section class="w-full border-t-[0.5px] border-slate-200">
|
||||
<div class="w-full flex-center py-[5rem] gap-[1.25rem] container">
|
||||
<div class="w-full py-[5rem] gap-12 xs:gap-8 sm:gap-12 xl:gap-0 container grid grid-cols-1 xs:grid-cols-2 lg:grid-cols-4">
|
||||
<template v-for="(highlight, index) in highlights" :key="index">
|
||||
<div class="flex flex-col-center gap-[.75rem] w-1/4 px-5">
|
||||
<div class="flex flex-col-center gap-[.75rem] px-5">
|
||||
|
||||
<img :src="highlight.icon" class="size-[90px]" alt="" />
|
||||
<img :src="highlight.icon" class="size-[70px] md:size-[90px]" alt="" />
|
||||
|
||||
<div class="w-full flex-col-center gap-[.25rem]">
|
||||
<span class="typo-sub-h-md text-black text-center">
|
||||
@@ -51,10 +51,10 @@ const highlights = ref<Highlight[]>([
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="w-[1px] h-[5rem] bg-slate-200"
|
||||
v-if="index + 1 != highlights.length"
|
||||
/>
|
||||
<!-- <div-->
|
||||
<!-- class="w-[1px] h-[5rem] bg-slate-200"-->
|
||||
<!-- v-if="index + 1 != highlights.length"-->
|
||||
<!-- />-->
|
||||
</template>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -33,60 +33,72 @@ const { colorObject } = useImageColor(`#product-image-${id.value}`);
|
||||
|
||||
<template>
|
||||
<NuxtLink :to="'/product/' + id">
|
||||
<div
|
||||
class="group relative size-full aspect-square rounded-2xl bg-white brightness-[98%] overflow-hidden p-6"
|
||||
>
|
||||
<img
|
||||
:id="`product-image-${id}`"
|
||||
:src="picture"
|
||||
class="group-hover:scale-105 transition-transform duration-200 size-full object-contain absolute inset-0"
|
||||
alt="product-background"
|
||||
/>
|
||||
|
||||
<div class="@container">
|
||||
<div
|
||||
v-if="darkLayer"
|
||||
class="bg-linear-to-t inset-0 from-black/50 to-transparent to-55% absolute z-10 size-full"
|
||||
/>
|
||||
|
||||
<div
|
||||
class="flex justify-between items-center absolute px-6 pt-6 top-0 w-full inset-x-0"
|
||||
>
|
||||
<Rate v-if="rate" :rate="rate"/>
|
||||
<Tag v-if="tag">
|
||||
{{ tag }}
|
||||
</Tag>
|
||||
</div>
|
||||
<div
|
||||
:class="
|
||||
colorObject?.isLight && !darkLayer
|
||||
? 'text-black'
|
||||
: 'text-white'
|
||||
"
|
||||
class="absolute inset-x-0 bottom-0 pb-4 md:pb-6 px-4 md:px-6 flex flex-row-reverse justify-between items-end z-10"
|
||||
class="group relative size-full aspect-square rounded-xl @[280px]:rounded-2xl bg-white brightness-[98%] overflow-hidden p-6"
|
||||
>
|
||||
|
||||
<div class="flex flex-col gap-2 items-start w-full">
|
||||
<!-- <span class="typo-p-sm md:typo-p-md !font-medium">-->
|
||||
<!-- {{ brand }}-->
|
||||
<!-- </span>-->
|
||||
<span class="typo-sub-h-md md:typo-sub-h-lg">
|
||||
{{ title }}
|
||||
</span>
|
||||
<div class="flex items-center justify-between w-full mt-1">
|
||||
<div class="flex items-center gap-2 md:mt-1">
|
||||
<ColorCircle
|
||||
v-for="color in colors"
|
||||
:key="color"
|
||||
:style="{ backgroundColor: color }"
|
||||
class="!size-5 md:!size-6"
|
||||
/>
|
||||
<img
|
||||
:id="`product-image-${id}`"
|
||||
:src="picture"
|
||||
class="group-hover:scale-105 transition-transform duration-200 size-full object-contain absolute inset-0"
|
||||
alt="product-background"
|
||||
/>
|
||||
|
||||
<div
|
||||
v-if="darkLayer"
|
||||
class="bg-linear-to-t inset-0 from-black/50 to-transparent to-55% absolute z-10 size-full"
|
||||
/>
|
||||
|
||||
<div
|
||||
class="flex justify-between items-center absolute px-4 @[280px]:px-6 pt-4 @[280px]:pt-6 top-0 w-full inset-x-0"
|
||||
>
|
||||
<Rate v-if="rate" :rate="rate" />
|
||||
<Tag v-if="tag">
|
||||
{{ tag }}
|
||||
</Tag>
|
||||
</div>
|
||||
<div
|
||||
:class="
|
||||
colorObject?.isLight && !darkLayer
|
||||
? 'text-black'
|
||||
: 'text-white'
|
||||
"
|
||||
class="absolute inset-x-0 bottom-0 pb-4 @[280px]:pb-6 px-4 @[280px]:px-6 flex flex-row-reverse justify-between items-end z-10"
|
||||
>
|
||||
|
||||
<div class="flex flex-col gap-2 items-start w-full">
|
||||
<span class="@max-[280px]:hidden typo-sub-h-md @[280px]:typo-sub-h-lg truncate w-full">
|
||||
{{ title }}
|
||||
</span>
|
||||
<div class="flex items-center justify-between w-full mt-1">
|
||||
<div class="flex items-center gap-2 @[280px]:mt-1">
|
||||
<ColorCircle
|
||||
v-for="color in colors"
|
||||
:key="color"
|
||||
:style="{ backgroundColor: color }"
|
||||
class="!size-5 @[280px]:!size-6"
|
||||
/>
|
||||
</div>
|
||||
<span class="@max-[280px]:hidden typo-p-xs @[280px]:typo-p-md !font-semibold whitespace-nowrap">
|
||||
{{ price }}
|
||||
</span>
|
||||
</div>
|
||||
<span class="typo-p-sm md:typo-p-md font-medium whitespace-nowrap">
|
||||
{{ price }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col gap-1 px-2 items-start w-full text-black mt-4 @[280px]:hidden">
|
||||
<span class="typo-sub-h-sm w-full truncate">
|
||||
{{ title }}
|
||||
</span>
|
||||
<div class="@[280px]:hidden flex items-center justify-between w-full mt-1">
|
||||
<span class="typo-p-xs !font-semibold whitespace-nowrap">
|
||||
{{ price }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</NuxtLink>
|
||||
</template>
|
||||
|
||||
@@ -122,7 +122,7 @@ onMounted(() => {
|
||||
end: "bottom top"
|
||||
});
|
||||
|
||||
setTimeout(() => {
|
||||
const calculateOnResize = () => {
|
||||
if (window.innerWidth > 768) {
|
||||
gsap.to("#header-navbar", {
|
||||
background: "transparent",
|
||||
@@ -133,19 +133,18 @@ onMounted(() => {
|
||||
resetTimelineForMobile();
|
||||
scrollTrigger.disable();
|
||||
}
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
calculateOnResize()
|
||||
}, 100);
|
||||
|
||||
setTimeout(() => {
|
||||
calculateOnResize()
|
||||
}, 200);
|
||||
|
||||
window.addEventListener("resize", () => {
|
||||
if (window.innerWidth > 768) {
|
||||
gsap.to("#header-navbar", {
|
||||
background: "transparent",
|
||||
filter: "invert(100%)"
|
||||
});
|
||||
scrollTrigger.enable();
|
||||
} else {
|
||||
resetTimelineForMobile();
|
||||
scrollTrigger.disable();
|
||||
}
|
||||
calculateOnResize()
|
||||
});
|
||||
|
||||
});
|
||||
@@ -170,7 +169,7 @@ onUnmounted(() => {
|
||||
:centered-slides="true"
|
||||
:breakpoints="{
|
||||
768: {
|
||||
spaceBetween : 40
|
||||
spaceBetween : 40,
|
||||
}
|
||||
}"
|
||||
@swiper="onSwiper"
|
||||
@@ -178,96 +177,97 @@ onUnmounted(() => {
|
||||
<SwiperSlide
|
||||
v-for="(slide, index) in homeData!.sliders"
|
||||
:key="slide.id"
|
||||
class="max-md:container"
|
||||
>
|
||||
<div
|
||||
class="header-slider-item relative w-full overflow-hidden max-md:rounded-[20px]"
|
||||
>
|
||||
<template v-if="!!slide.video">
|
||||
<video
|
||||
:id="`slide-video-${index}`"
|
||||
:muted="swiper_instance?.realIndex !== index ? true : isMuted"
|
||||
loop
|
||||
class="slide-video absolute inset-0 size-full object-cover brightness-90"
|
||||
:src="slide.video"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<img
|
||||
v-else
|
||||
class="absolute inset-0 size-full object-cover"
|
||||
:src="slide.image!"
|
||||
:alt="slide.title"
|
||||
/>
|
||||
|
||||
<div class="size-full absolute z-10 bg-linear-to-t from-black/50 to-transparent" />
|
||||
|
||||
<div class="max-md:container">
|
||||
<div
|
||||
:class="swiper_instance?.realIndex !== index ? 'opacity-0' : ''"
|
||||
class="w-full transition-opacity pb-6 xs:pb-10 lg:pb-16 px-6 xs:px-10 lg:px-16 gap-6 xs:gap-10 lg:gap-12 container flex flex-col h-full justify-end relative z-10"
|
||||
class="header-slider-item relative w-full overflow-hidden max-md:rounded-[20px]"
|
||||
>
|
||||
<template v-if="!!slide.video">
|
||||
<video
|
||||
:id="`slide-video-${index}`"
|
||||
:muted="swiper_instance?.realIndex !== index ? true : isMuted"
|
||||
loop
|
||||
class="slide-video absolute inset-0 size-full object-cover brightness-90"
|
||||
:src="slide.video"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<div class="header-slider-item-child w-full">
|
||||
<div class="border-b border-white/10 pb-6 flex flex-col gap-2 md:gap-4">
|
||||
<div class="flex items-center gap-4 lg:gap-8">
|
||||
<div
|
||||
class="hover:scale-110 size-[36px] md:size-[42px] lg:size-[50px] relative flex items-center justify-center">
|
||||
<div class="size-full scale-75 bg-white absolute rounded-full animate-ping" />
|
||||
<button
|
||||
@click="isMuted = !isMuted"
|
||||
class="transition-all cursor-pointer flex-center bg-white z-10 size-full rounded-full"
|
||||
>
|
||||
<Icon
|
||||
:name="isMuted ? 'bi:volume-mute-fill' : 'bi:volume-up-fill'"
|
||||
class="text-black size-4 md:size-[18px] lg:size-[24px]"
|
||||
/>
|
||||
</button>
|
||||
<img
|
||||
v-else
|
||||
class="absolute inset-0 size-full object-cover"
|
||||
:src="slide.image!"
|
||||
:alt="slide.title"
|
||||
/>
|
||||
|
||||
<div class="size-full absolute z-10 bg-linear-to-t from-black/50 to-transparent" />
|
||||
|
||||
<div
|
||||
:class="swiper_instance?.realIndex !== index ? 'opacity-0' : ''"
|
||||
class="w-full transition-opacity pb-6 xs:pb-10 lg:pb-16 px-6 xs:px-10 lg:px-16 gap-6 xs:gap-10 lg:gap-12 container flex flex-col h-full justify-end relative z-10"
|
||||
>
|
||||
|
||||
<div class="header-slider-item-child w-full">
|
||||
<div class="border-b border-white/10 pb-6 flex flex-col gap-2 md:gap-4">
|
||||
<div class="flex items-center gap-4 lg:gap-8">
|
||||
<div
|
||||
class="hover:scale-110 size-[36px] md:size-[42px] lg:size-[50px] relative flex items-center justify-center">
|
||||
<div class="size-full scale-75 bg-white absolute rounded-full animate-ping" />
|
||||
<button
|
||||
@click="isMuted = !isMuted"
|
||||
class="transition-all cursor-pointer flex-center bg-white z-10 size-full rounded-full"
|
||||
>
|
||||
<Icon
|
||||
:name="isMuted ? 'bi:volume-mute-fill' : 'bi:volume-up-fill'"
|
||||
class="text-black size-4 md:size-[18px] lg:size-[24px]"
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
<h3 class="typo-h-6 md:typo-h-4 lg:typo-h-1 tracking-[-2px] text-white">
|
||||
{{ slide.title }}
|
||||
</h3>
|
||||
</div>
|
||||
<h3 class="typo-h-6 md:typo-h-4 lg:typo-h-1 tracking-[-2px] text-white">
|
||||
{{ slide.title }}
|
||||
</h3>
|
||||
</div>
|
||||
<div class="flex justify-between items-center">
|
||||
<div class="flex justify-between items-center">
|
||||
<span class="truncate typo-p-xs md:typo-p-sm lg:typo-p-lg text-white">
|
||||
{{ slide.description }}
|
||||
</span>
|
||||
<Button
|
||||
class="max-sm:hidden max-lg:typo-label-xs invert rounded-full hover:bg-transparent">
|
||||
مشاهده
|
||||
</Button>
|
||||
<Button
|
||||
class="max-sm:hidden max-lg:typo-label-xs invert rounded-full hover:bg-transparent">
|
||||
مشاهده
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
id="header-slider-pagination-child"
|
||||
class="flex items-center justify-between"
|
||||
>
|
||||
<button @click="swiper_instance?.slidePrev()">
|
||||
<Icon
|
||||
class="**:stroke-white cursor-pointer size-5 md:size-6"
|
||||
name="ci:arrow-right"
|
||||
/>
|
||||
</button>
|
||||
<div class="flex items-center justify-center gap-3 text-white">
|
||||
<div
|
||||
v-for="(_slide, index) in homeData!.sliders"
|
||||
:class="swiper_instance?.realIndex === index ? 'bg-white' : 'bg-transparent'"
|
||||
class="border border-white size-2 md:size-3 rounded-full transition-all duration-200"
|
||||
>
|
||||
<div
|
||||
id="header-slider-pagination-child"
|
||||
class="flex items-center justify-between"
|
||||
>
|
||||
<button @click="swiper_instance?.slidePrev()">
|
||||
<Icon
|
||||
class="**:stroke-white cursor-pointer size-5 md:size-6"
|
||||
name="ci:arrow-right"
|
||||
/>
|
||||
</button>
|
||||
<div class="flex items-center justify-center gap-3 text-white">
|
||||
<div
|
||||
v-for="(_slide, index) in homeData!.sliders"
|
||||
:class="swiper_instance?.realIndex === index ? 'bg-white' : 'bg-transparent'"
|
||||
class="border border-white size-2 md:size-3 rounded-full transition-all duration-200"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<button>
|
||||
<Icon
|
||||
@click="swiper_instance?.slideNext()"
|
||||
class="**:stroke-white cursor-pointer size-5 md:size-6"
|
||||
name="ci:arrow-left"
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
<button>
|
||||
<Icon
|
||||
@click="swiper_instance?.slideNext()"
|
||||
class="**:stroke-white cursor-pointer size-5 md:size-6"
|
||||
name="ci:arrow-left"
|
||||
/>
|
||||
</button>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</SwiperSlide>
|
||||
</Swiper>
|
||||
|
||||
@@ -16,7 +16,7 @@ await suspense();
|
||||
<template>
|
||||
<section class="mt-20 container">
|
||||
<div class="flex items-center justify-between mb-20">
|
||||
<span class="typo-h-6 md:typo-h-5 lg:typo-h-4 text-black">
|
||||
<span class="typo-h-6 max-sm:text-xl md:typo-h-5 lg:typo-h-4 text-black">
|
||||
مقالات اخیر سایت
|
||||
</span>
|
||||
<NuxtLink to="/articles">
|
||||
|
||||
@@ -37,7 +37,7 @@ watch(
|
||||
(newValue) => {
|
||||
const clientRect = previewContainerEl.value?.getBoundingClientRect()!;
|
||||
const percent = clientRect.width / 100;
|
||||
const clipPercent = (newValue - clientRect.x - 8) / percent;
|
||||
const clipPercent = ((newValue + draggableEl.value!.clientWidth / 2) - clientRect.x - 8) / percent;
|
||||
if (clipPercent >= 5 && clipPercent <= 95) {
|
||||
clipPathPercent.value = clipPercent;
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ const { data : homeData } = useHomeData();
|
||||
const { $gsap: gsap, $ScrollTrigger: ScrollTrigger } = useNuxtApp();
|
||||
|
||||
let gsapTimeline: gsap.core.Timeline;
|
||||
let scrollTrigger: ScrollTrigger;
|
||||
|
||||
// lifecycle
|
||||
|
||||
@@ -67,7 +68,7 @@ onMounted(() => {
|
||||
filter: "invert(0%)"
|
||||
});
|
||||
|
||||
ScrollTrigger.create({
|
||||
scrollTrigger = ScrollTrigger.create({
|
||||
trigger: "#products-showcase-container",
|
||||
animation: gsapTimeline,
|
||||
scrub: 1,
|
||||
@@ -77,6 +78,10 @@ onMounted(() => {
|
||||
end: "bottom top"
|
||||
});
|
||||
|
||||
setTimeout(() => {
|
||||
scrollTrigger.refresh()
|
||||
}, 1000);
|
||||
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
@@ -89,7 +94,7 @@ onUnmounted(() => {
|
||||
<template>
|
||||
<div
|
||||
id="products-showcase-container"
|
||||
class="mt-80 mb-40 perspective-midrange w-full h-[125svh] bg-black flex items-center justify-center"
|
||||
class="mb-40 perspective-midrange w-full h-[125svh] bg-black flex items-center justify-center"
|
||||
>
|
||||
<NuxtLink
|
||||
v-for="slide in homeData!.show_case_slider"
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
import { useQuery } from "@tanstack/vue-query";
|
||||
import { API_ENDPOINTS, QUERY_KEYS } from "~/constants";
|
||||
import type { GetArticleResponse } from "~/composables/api/blog/useGetArticle";
|
||||
|
||||
// types
|
||||
|
||||
@@ -15,7 +16,7 @@ export type GetHomeDataResponse = {
|
||||
"video": string | null
|
||||
}[],
|
||||
"sub_categories": SubCategory[],
|
||||
"products": Product[],
|
||||
"products": ProductListItem[],
|
||||
"difreance_section": {
|
||||
"image1": string,
|
||||
"image2": string,
|
||||
|
||||
@@ -31,7 +31,6 @@
|
||||
"gsap": "^3.12.7",
|
||||
"isomorphic-dompurify": "^2.22.0",
|
||||
"jalali-ts": "^8.0.0",
|
||||
"masonry-layout": "^4.2.2",
|
||||
"nuxt": "^3.15.4",
|
||||
"reka-ui": "^1.0.0-alpha.6",
|
||||
"swiper": "^11.2.4",
|
||||
|
||||
@@ -3,10 +3,11 @@
|
||||
// import
|
||||
|
||||
import useHomeData from "~/composables/api/home/useHomeData";
|
||||
import ProductsGrid from "~/components/global/ProductsGrid.vue";
|
||||
|
||||
// state
|
||||
|
||||
const { suspense } = useHomeData();
|
||||
const { data: homeData, suspense } = useHomeData();
|
||||
|
||||
// ssr
|
||||
|
||||
@@ -27,7 +28,8 @@ if (response.isError) {
|
||||
<Hero />
|
||||
<Preview />
|
||||
<ProductsShowcase />
|
||||
<ProductsSlider title="محصولات پرفروش" />
|
||||
<!-- <ProductsSlider title="محصولات پرفروش" />-->
|
||||
<ProductsGrid title="محصولات پرفروش" :products="[...homeData!.products,...homeData!.products]"/>
|
||||
<Categories />
|
||||
<Brands />
|
||||
<MostRecentComments />
|
||||
|
||||
+22
-41
@@ -21,13 +21,12 @@ type LoginInfo = {
|
||||
// meta
|
||||
|
||||
definePageMeta({
|
||||
layout: "none",
|
||||
middleware: ["check-is-not-logged-in"]
|
||||
});
|
||||
|
||||
// state
|
||||
|
||||
const { $gsap: gsap } = useNuxtApp();
|
||||
|
||||
const { addToast } = useToast();
|
||||
|
||||
const { updateToken, updateRefreshToken } = useAuth();
|
||||
@@ -150,21 +149,6 @@ const resetForm = () => {
|
||||
showOtp.value = false;
|
||||
};
|
||||
|
||||
// const onMouseMove = (e: MouseEvent) => {
|
||||
// const heylmzEyesElement = document.querySelector("#heylmz-eyes") as HTMLDivElement;
|
||||
// const boundry = heylmzEyesElement.getBoundingClientRect();
|
||||
//
|
||||
// console.log(e.clientX, heylmzEyesElement.clientWidth, boundry.left, e.clientX - heylmzEyesElement.clientWidth);
|
||||
//
|
||||
// const moveX = e.clientX - heylmzEyesElement.clientWidth + 60;
|
||||
// const moveY = e.clientY - heylmzEyesElement.clientHeight - 155;
|
||||
//
|
||||
// gsap.to("#heylmz-eyes", {
|
||||
// x: moveX,
|
||||
// y: moveY
|
||||
// });
|
||||
// };
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -179,8 +163,7 @@ const resetForm = () => {
|
||||
<div class="flex items-center justify-center flex-col size-full">
|
||||
|
||||
<img
|
||||
id="heylmz-eyes"
|
||||
class="aspect-square w-[300px] translate-y-[100px]"
|
||||
class="aspect-square w-[300px] translate-y-[100px] animate-fade-in"
|
||||
src="/img/heymlz-seat.gif"
|
||||
alt=""
|
||||
/>
|
||||
@@ -188,30 +171,28 @@ const resetForm = () => {
|
||||
<div
|
||||
class="max-w-[600px] w-full p-6 h-[400px] flex flex-col items-center bg-white border shadow-black/10 justify-center border-slate-300 rounded-xl"
|
||||
>
|
||||
<h1 class="typo-hero-2 mt-8">فرم ورود</h1>
|
||||
<h1 class="typo-h-5 mt-8">شماره خود را وارد کنید</h1>
|
||||
|
||||
<form @submit.prevent class="max-w-[500px] w-full mt-12">
|
||||
<div v-if="!showOtp" class="flex items-center gap-2 w-full">
|
||||
<Input
|
||||
data-testid="phone-input"
|
||||
class="w-full"
|
||||
v-model="loginInfo.phone"
|
||||
placeholder="9380123456"
|
||||
dir="ltr"
|
||||
:error="formValidator$.phone.$error"
|
||||
>
|
||||
<template #startItem>
|
||||
<span class="text-slate-500"> +98 </span>
|
||||
</template>
|
||||
</Input>
|
||||
<div class="flex items-center gap-1">
|
||||
<Icon
|
||||
class="translate-y-[-1px]"
|
||||
name="twemoji:flag-iran"
|
||||
size="24"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<Input
|
||||
v-if="!showOtp"
|
||||
class="w-full tracking-[2px]"
|
||||
v-model="loginInfo.phone"
|
||||
placeholder="9380123456"
|
||||
dir="ltr"
|
||||
:error="formValidator$.phone.$error"
|
||||
>
|
||||
<template #startItem>
|
||||
<div class="flex items-center gap-3">
|
||||
<Icon
|
||||
class="translate-y-[-1px] static-icon"
|
||||
name="twemoji:flag-iran"
|
||||
size="24"
|
||||
/>
|
||||
<span class="text-slate-500 typo-label-sm"> +98 </span>
|
||||
</div>
|
||||
</template>
|
||||
</Input>
|
||||
|
||||
<OtpInput
|
||||
v-else
|
||||
|
||||
Reference in New Issue
Block a user