merge
This commit is contained in:
@@ -1,73 +0,0 @@
|
|||||||
@layer base {
|
|
||||||
@font-face {
|
|
||||||
font-family: "Morabba";
|
|
||||||
src: url("/fonts/Morabba/Morabba-UltraLight.woff2");
|
|
||||||
font-weight: 200;
|
|
||||||
font-style: normal;
|
|
||||||
font-display: swap;
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: "Morabba";
|
|
||||||
src: url("/fonts/Morabba/Morabba-Light.woff2");
|
|
||||||
font-weight: 300;
|
|
||||||
font-style: normal;
|
|
||||||
font-display: swap;
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: "Morabba";
|
|
||||||
src: url("/fonts/Morabba/Morabba-Regular.woff2");
|
|
||||||
font-weight: 400;
|
|
||||||
font-style: normal;
|
|
||||||
font-display: swap;
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: "Morabba";
|
|
||||||
src: url("/fonts/Morabba/Morabba-Medium.woff2");
|
|
||||||
font-weight: 500;
|
|
||||||
font-style: normal;
|
|
||||||
font-display: swap;
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: "Morabba";
|
|
||||||
src: url("/fonts/Morabba/Morabba-SemiBold.woff2");
|
|
||||||
font-weight: 600;
|
|
||||||
font-style: normal;
|
|
||||||
font-display: swap;
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: "Morabba";
|
|
||||||
src: url("/fonts/Morabba/Morabba-Bold.woff2");
|
|
||||||
font-weight: 700;
|
|
||||||
font-style: normal;
|
|
||||||
font-display: swap;
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: "Morabba";
|
|
||||||
src: url("/fonts/Morabba/Morabba-ExtraBold.woff2");
|
|
||||||
font-weight: 800;
|
|
||||||
font-style: normal;
|
|
||||||
font-display: swap;
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: "Morabba";
|
|
||||||
src: url("/fonts/Morabba/Morabba-Black.woff2");
|
|
||||||
font-weight: 900;
|
|
||||||
font-style: normal;
|
|
||||||
font-display: swap;
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: "Morabba";
|
|
||||||
src: url("/fonts/Morabba/Morabba-Heavy.woff2");
|
|
||||||
font-weight: 1000;
|
|
||||||
font-style: normal;
|
|
||||||
font-display: swap;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
@layer base {
|
|
||||||
@font-face {
|
|
||||||
font-family: "YekanBakh";
|
|
||||||
src: url("/fonts/YekanBakh/YekanBakh-Thin.woff");
|
|
||||||
font-weight: 100;
|
|
||||||
font-style: normal;
|
|
||||||
font-display: swap;
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: "YekanBakh";
|
|
||||||
src: url("/fonts/YekanBakh/YekanBakh-Light.woff");
|
|
||||||
font-weight: 300;
|
|
||||||
font-style: normal;
|
|
||||||
font-display: swap;
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: "YekanBakh";
|
|
||||||
src: url("/fonts/YekanBakh/YekanBakh-Regular.woff");
|
|
||||||
font-weight: 400;
|
|
||||||
font-style: normal;
|
|
||||||
font-display: swap;
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: "YekanBakh";
|
|
||||||
src: url("/fonts/YekanBakh/YekanBakh-SemiBold.woff");
|
|
||||||
font-weight: 600;
|
|
||||||
font-style: normal;
|
|
||||||
font-display: swap;
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: "YekanBakh";
|
|
||||||
src: url("/fonts/YekanBakh/YekanBakh-Bold.woff");
|
|
||||||
font-weight: 700;
|
|
||||||
font-style: normal;
|
|
||||||
font-display: swap;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -6,8 +6,6 @@
|
|||||||
@import "./button.comp.css";
|
@import "./button.comp.css";
|
||||||
@import "./input.comp.css";
|
@import "./input.comp.css";
|
||||||
@import "./fonts/iran-yekan-x.css";
|
@import "./fonts/iran-yekan-x.css";
|
||||||
@import "./fonts/morabba.css";
|
|
||||||
@import "./fonts/yekan-bakh.css";
|
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
/* CONTAINER */
|
/* CONTAINER */
|
||||||
@@ -117,8 +115,6 @@
|
|||||||
--font-inter: "Inter", sans-serif;
|
--font-inter: "Inter", sans-serif;
|
||||||
--font-dmsans: "DM Sans", sans-serif;
|
--font-dmsans: "DM Sans", sans-serif;
|
||||||
--font-iran-yekan-x: "IRANYekanXVF", "sans-serif";
|
--font-iran-yekan-x: "IRANYekanXVF", "sans-serif";
|
||||||
--font-yekan-bakh: "YekanBakh", "sans-serif";
|
|
||||||
--font-morabba: "Morabba", "sans-serif";
|
|
||||||
|
|
||||||
/* BREAKPOINTS */
|
/* BREAKPOINTS */
|
||||||
--breakpoint-2xs: 400px;
|
--breakpoint-2xs: 400px;
|
||||||
|
|||||||
@@ -22,15 +22,16 @@ const emit = defineEmits<Emits>();
|
|||||||
<template>
|
<template>
|
||||||
<button
|
<button
|
||||||
@click="emit('select', null)"
|
@click="emit('select', null)"
|
||||||
:class="
|
:class="isSelected ? 'ring-2 ring-offset-2 ring-blue-500 border-blue-500' : 'border-slate-200'"
|
||||||
isSelected
|
|
||||||
? 'ring-2 ring-offset-2 ring-blue-500 border-blue-500'
|
|
||||||
: 'border-slate-200'
|
|
||||||
"
|
|
||||||
class="w-full p-5 border rounded-xl flex flex-col gap-4 transition-all cursor-pointer relative overflow-hidden"
|
class="w-full p-5 border rounded-xl flex flex-col gap-4 transition-all cursor-pointer relative overflow-hidden"
|
||||||
>
|
>
|
||||||
<div class="aspect-square flex-center">
|
<div class="aspect-square flex-center">
|
||||||
<NuxtImg :src="gateway.picture" class="object-cover" />
|
<NuxtImg
|
||||||
|
:src="gateway.picture"
|
||||||
|
loading="lazy"
|
||||||
|
fetch-priority="low"
|
||||||
|
class="object-cover"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<span class="typo-label-sm text-right text-black">
|
<span class="typo-label-sm text-right text-black">
|
||||||
{{ gateway.title }}
|
{{ gateway.title }}
|
||||||
@@ -43,7 +44,11 @@ const emit = defineEmits<Emits>();
|
|||||||
v-if="isSelected"
|
v-if="isSelected"
|
||||||
class="bg-blue-500 rounded-md p-0.5 text-center bottom-4 left-4 text-slate-200 text-[10px] lg:text-xs absolute"
|
class="bg-blue-500 rounded-md p-0.5 text-center bottom-4 left-4 text-slate-200 text-[10px] lg:text-xs absolute"
|
||||||
>
|
>
|
||||||
<Icon name="bi:check" size="20" class="**:fill-white" />
|
<Icon
|
||||||
|
name="bi:check"
|
||||||
|
size="20"
|
||||||
|
class="**:fill-white"
|
||||||
|
/>
|
||||||
</span>
|
</span>
|
||||||
</Transition>
|
</Transition>
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -30,15 +30,11 @@ const visible = computed({
|
|||||||
class="fixed inset-0 w-full h-svh z-9999 flex-center"
|
class="fixed inset-0 w-full h-svh z-9999 flex-center"
|
||||||
v-if="visible"
|
v-if="visible"
|
||||||
>
|
>
|
||||||
<div
|
<div class="overflow-y-auto max-h-svh absolute left-[50%] py-10 w-fit max-w-[50rem] translate-x-[-50%]">
|
||||||
class="overflow-y-auto max-h-svh absolute left-[50%] py-10 w-fit max-w-[50rem] translate-x-[-50%]"
|
|
||||||
>
|
|
||||||
<DialogContent
|
<DialogContent
|
||||||
class="min-w-[30vw] max-w-[50vw] data-[state=open]:animate-content-show text-black font-iran-yekan-x focus:outline-none z-[100]"
|
class="min-w-[30vw] max-w-[50vw] data-[state=open]:animate-content-show text-black font-iran-yekan-x focus:outline-none z-[100]"
|
||||||
>
|
>
|
||||||
<div
|
<div class="w-full h-[350px] shrink-0 rounded-2xl relative overflow-hidden flex-center">
|
||||||
class="w-full h-[350px] shrink-0 rounded-2xl relative overflow-hidden flex-center"
|
|
||||||
>
|
|
||||||
<div
|
<div
|
||||||
class="bg-custom-conic size-[200%] absolute -top-1/2 -left-1/2 animate-spin [animation-duration:3s] z-[1]"
|
class="bg-custom-conic size-[200%] absolute -top-1/2 -left-1/2 animate-spin [animation-duration:3s] z-[1]"
|
||||||
></div>
|
></div>
|
||||||
@@ -48,6 +44,8 @@ const visible = computed({
|
|||||||
<NuxtImg
|
<NuxtImg
|
||||||
class="aspect-square w-[300px]"
|
class="aspect-square w-[300px]"
|
||||||
src="/img/heymlz/heymlz-payment-progress.gif"
|
src="/img/heymlz/heymlz-payment-progress.gif"
|
||||||
|
loading="lazy"
|
||||||
|
fetch-priority="low"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div class="-translate-y-28 flex-center gap-3">
|
<div class="-translate-y-28 flex-center gap-3">
|
||||||
@@ -55,9 +53,7 @@ const visible = computed({
|
|||||||
name="svg-spinners:3-dots-bounce"
|
name="svg-spinners:3-dots-bounce"
|
||||||
size="20"
|
size="20"
|
||||||
/>
|
/>
|
||||||
<span class="text-lg">
|
<span class="text-lg"> در حال انتقال به درگاه پرداخت </span>
|
||||||
در حال انتقال به درگاه پرداخت
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -72,15 +68,7 @@ const visible = computed({
|
|||||||
.bg-custom-conic {
|
.bg-custom-conic {
|
||||||
background-size: 100% 100%;
|
background-size: 100% 100%;
|
||||||
background-position: 0px 0px, 0px 0px;
|
background-position: 0px 0px, 0px 0px;
|
||||||
background-image: radial-gradient(
|
background-image: radial-gradient(142% 91% at -6% 90%, #ff000000 1%, #ff000000 99%),
|
||||||
142% 91% at -6% 90%,
|
conic-gradient(from 0deg at 50% 50%, var(--color-blue-500) 0%, #ff000000 34%);
|
||||||
#ff000000 1%,
|
|
||||||
#ff000000 99%
|
|
||||||
),
|
|
||||||
conic-gradient(
|
|
||||||
from 0deg at 50% 50%,
|
|
||||||
var(--color-blue-500) 0%,
|
|
||||||
#ff000000 34%
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -27,15 +27,19 @@ const { isLoading: cartImageIsLoading } = useImage({
|
|||||||
v-if="!cartImageIsLoading"
|
v-if="!cartImageIsLoading"
|
||||||
class="size-[3.5rem] shrink-0 rounded-100 border border-gray-300 overflow-hidden"
|
class="size-[3.5rem] shrink-0 rounded-100 border border-gray-300 overflow-hidden"
|
||||||
>
|
>
|
||||||
<NuxtImg :src="image" alt="product" class="object-conver" />
|
<NuxtImg
|
||||||
|
:src="image"
|
||||||
|
alt="product"
|
||||||
|
loading="lazy"
|
||||||
|
fetch-priority="low"
|
||||||
|
class="object-conver"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<Skeleton
|
<Skeleton
|
||||||
v-else
|
v-else
|
||||||
class="!size-[3.5rem] aspect-square shrink-0 !rounded-100 border border-slate-200"
|
class="!size-[3.5rem] aspect-square shrink-0 !rounded-100 border border-slate-200"
|
||||||
/>
|
/>
|
||||||
<span
|
<span class="text-xs font-semibold lg:text-sm text-gray-800 line-clamp-2">
|
||||||
class="text-xs font-semibold lg:text-sm text-gray-800 line-clamp-2"
|
|
||||||
>
|
|
||||||
{{ title }}
|
{{ title }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -123,6 +123,8 @@ watch(
|
|||||||
>
|
>
|
||||||
<NuxtImg
|
<NuxtImg
|
||||||
:src="data.product.image"
|
:src="data.product.image"
|
||||||
|
loading="lazy"
|
||||||
|
fetch-priority="low"
|
||||||
class="object-cover size-full"
|
class="object-cover size-full"
|
||||||
alt="product"
|
alt="product"
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -38,6 +38,8 @@ const remaining = computed(() => items.value.length - max.value);
|
|||||||
>
|
>
|
||||||
<NuxtImg
|
<NuxtImg
|
||||||
:src="item"
|
:src="item"
|
||||||
|
loading="lazy"
|
||||||
|
fetch-priority="low"
|
||||||
alt="avatar"
|
alt="avatar"
|
||||||
class="rounded-full object-cover w-full h-full"
|
class="rounded-full object-cover w-full h-full"
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -51,6 +51,8 @@ const createdAt = usePersianTimeAgo(new Date(date.value));
|
|||||||
|
|
||||||
<NuxtImg
|
<NuxtImg
|
||||||
:src="image"
|
:src="image"
|
||||||
|
loading="lazy"
|
||||||
|
fetch-priority="low"
|
||||||
class="group-hover:scale-105 transition-transform duration-200 absolute size-full object-cover z-10"
|
class="group-hover:scale-105 transition-transform duration-200 absolute size-full object-cover z-10"
|
||||||
alt=""
|
alt=""
|
||||||
/>
|
/>
|
||||||
@@ -98,6 +100,8 @@ const createdAt = usePersianTimeAgo(new Date(date.value));
|
|||||||
|
|
||||||
<NuxtImg
|
<NuxtImg
|
||||||
v-if="variant === 'lg'"
|
v-if="variant === 'lg'"
|
||||||
|
loading="lazy"
|
||||||
|
fetch-priority="low"
|
||||||
:src="image"
|
:src="image"
|
||||||
class="group-hover:scale-105 transition-transform duration-200 absolute size-full object-cover z-10"
|
class="group-hover:scale-105 transition-transform duration-200 absolute size-full object-cover z-10"
|
||||||
alt=""
|
alt=""
|
||||||
|
|||||||
@@ -41,6 +41,8 @@ const brands = ref([
|
|||||||
HEYMLZ
|
HEYMLZ
|
||||||
</div>
|
</div>
|
||||||
<NuxtImg
|
<NuxtImg
|
||||||
|
loading="lazy"
|
||||||
|
fetch-priority="low"
|
||||||
src="/img/heymlz/heymlz-logo.png"
|
src="/img/heymlz/heymlz-logo.png"
|
||||||
class="h-[25px] sm:h-[45px] invert"
|
class="h-[25px] sm:h-[45px] invert"
|
||||||
/>
|
/>
|
||||||
@@ -62,6 +64,8 @@ const brands = ref([
|
|||||||
class="flex items-center px-6 sm:px-10 h-[90px] sm:h-[140px]"
|
class="flex items-center px-6 sm:px-10 h-[90px] sm:h-[140px]"
|
||||||
>
|
>
|
||||||
<NuxtImg
|
<NuxtImg
|
||||||
|
loading="lazy"
|
||||||
|
fetch-priority="low"
|
||||||
:src="brand"
|
:src="brand"
|
||||||
class="h-[25px] sm:h-[45px] opacity-25"
|
class="h-[25px] sm:h-[45px] opacity-25"
|
||||||
/>
|
/>
|
||||||
@@ -70,23 +74,3 @@ const brands = ref([
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<!-- <NuxtImg
|
|
||||||
src="/img/brands/brand-2.png"
|
|
||||||
class="h-[25px] sm:h-[45px]"
|
|
||||||
/>
|
|
||||||
<NuxtImg
|
|
||||||
src="/img/brands/brand-3.png"
|
|
||||||
class="h-[25px] sm:h-[45px]"
|
|
||||||
/>
|
|
||||||
<NuxtImg
|
|
||||||
src="/img/brands/brand-4.png"
|
|
||||||
class="h-[25px] sm:h-[45px]"
|
|
||||||
/>
|
|
||||||
<NuxtImg
|
|
||||||
src="/img/brands/brand-5.png"
|
|
||||||
class="h-[25px] sm:h-[45px]"
|
|
||||||
/>
|
|
||||||
<NuxtImg
|
|
||||||
src="/img/brands/brand-6.png"
|
|
||||||
class="h-[25px] sm:h-[45px]"
|
|
||||||
/> -->
|
|
||||||
|
|||||||
@@ -44,6 +44,8 @@ const { colorObject } = useImageColor(`#category-image-${id.value}`);
|
|||||||
:id="`category-image-${id}`"
|
:id="`category-image-${id}`"
|
||||||
class="group-hover:scale-105 transition-transform duration-200 absolute object-contain size-full"
|
class="group-hover:scale-105 transition-transform duration-200 absolute object-contain size-full"
|
||||||
:src="picture"
|
:src="picture"
|
||||||
|
loading="lazy"
|
||||||
|
fetch-priority="low"
|
||||||
alt=""
|
alt=""
|
||||||
/>
|
/>
|
||||||
</Transition>
|
</Transition>
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
<script setup lang="ts"></script>
|
<script setup lang="ts"></script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<SideModal title="فیلتر محصولات">
|
<SideModal
|
||||||
|
modalId="product-filters"
|
||||||
|
title="فیلتر محصولات"
|
||||||
|
>
|
||||||
<template #button>
|
<template #button>
|
||||||
<Button
|
<Button
|
||||||
end-icon="ci:filter"
|
end-icon="ci:filter"
|
||||||
|
|||||||
@@ -3,6 +3,8 @@
|
|||||||
<NuxtImg
|
<NuxtImg
|
||||||
src="/img/footer-bg.jpg"
|
src="/img/footer-bg.jpg"
|
||||||
alt=""
|
alt=""
|
||||||
|
loading="lazy"
|
||||||
|
fetch-priority="low"
|
||||||
class="absolute z-10 object-cover opacity-45"
|
class="absolute z-10 object-cover opacity-45"
|
||||||
:style="{
|
:style="{
|
||||||
mask: 'linear-gradient(to bottom, black 0%, rgba(0,0,0,0) 100%',
|
mask: 'linear-gradient(to bottom, black 0%, rgba(0,0,0,0) 100%',
|
||||||
@@ -13,6 +15,8 @@
|
|||||||
<div class="flex items-center flex-col gap-8 pb-[10px] pt-[80px] lg:pt-[100px] lg:pb-[50px] justify-center">
|
<div class="flex items-center flex-col gap-8 pb-[10px] pt-[80px] lg:pt-[100px] lg:pb-[50px] justify-center">
|
||||||
<img
|
<img
|
||||||
src="/img/heymlz/heymlz-small-idle.gif"
|
src="/img/heymlz/heymlz-small-idle.gif"
|
||||||
|
loading="lazy"
|
||||||
|
fetch-priority="low"
|
||||||
class="size-[150px] lg:size-[220px] rounded-full drop-shadow-2xl"
|
class="size-[150px] lg:size-[220px] rounded-full drop-shadow-2xl"
|
||||||
/>
|
/>
|
||||||
<span class="font-bold text-2xl lg:text-5xl text-gradient bg-gradient-to-l from-blue-500 to-blue-700">
|
<span class="font-bold text-2xl lg:text-5xl text-gradient bg-gradient-to-l from-blue-500 to-blue-700">
|
||||||
|
|||||||
@@ -122,8 +122,18 @@ const isHomePage = computed(() => route.path === "/");
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="header-navbar-item flex items-center justify-end h-full">
|
<div class="header-navbar-item flex items-center justify-end h-full">
|
||||||
<NuxtImg
|
<!-- <NuxtImg
|
||||||
src="/img/heymlz/heymlz-logomotion.gif"
|
src="/img/heymlz/heymlz-logomotion.gif"
|
||||||
|
preload
|
||||||
|
loading="eager"
|
||||||
|
fetch-priority="high"
|
||||||
|
class="h-2/3"
|
||||||
|
/> -->
|
||||||
|
<NuxtImg
|
||||||
|
src="/img/static-logo.png"
|
||||||
|
preload
|
||||||
|
loading="eager"
|
||||||
|
fetch-priority="high"
|
||||||
class="h-2/3"
|
class="h-2/3"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -35,24 +35,26 @@ const highlights = ref<Highlight[]>([
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<section class="w-full border-t-[0.5px] border-slate-200">
|
<section class="w-full border-t-[0.5px] border-slate-200">
|
||||||
<div
|
<div class="w-full py-[3rem] lg:py-[5rem] gap-8 sm:gap-12 xl:gap-0 container grid grid-cols-2 lg:grid-cols-4">
|
||||||
class="w-full py-[3rem] lg:py-[5rem] gap-8 sm:gap-12 xl:gap-0 container grid grid-cols-2 lg:grid-cols-4"
|
<template
|
||||||
>
|
v-for="(highlight, index) in highlights"
|
||||||
<template v-for="(highlight, index) in highlights" :key="index">
|
:key="index"
|
||||||
|
>
|
||||||
<div class="flex flex-col-center gap-[.75rem] px-5">
|
<div class="flex flex-col-center gap-[.75rem] px-5">
|
||||||
<div class="size-[70px] md:size-[100px] flex-center">
|
<div class="size-[70px] md:size-[100px] flex-center">
|
||||||
<NuxtImg :src="highlight.icon" class="w-full" />
|
<NuxtImg
|
||||||
|
:src="highlight.icon"
|
||||||
|
loading="lazy"
|
||||||
|
fetch-priority="low"
|
||||||
|
class="w-full"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="w-full flex-col-center gap-[.25rem]">
|
<div class="w-full flex-col-center gap-[.25rem]">
|
||||||
<span
|
<span class="typo-sub-h-sm lg:typo-sub-h-md text-black text-center">
|
||||||
class="typo-sub-h-sm lg:typo-sub-h-md text-black text-center"
|
|
||||||
>
|
|
||||||
{{ highlight.title }}
|
{{ highlight.title }}
|
||||||
</span>
|
</span>
|
||||||
<p
|
<p class="text-slate-500 typo-p-xs lg:typo-p-sm mt-1 text-center">
|
||||||
class="text-slate-500 typo-p-xs lg:typo-p-sm mt-1 text-center"
|
|
||||||
>
|
|
||||||
{{ highlight.description }}
|
{{ highlight.description }}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -3,13 +3,15 @@
|
|||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
title: string;
|
title: string;
|
||||||
|
modalId: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
defineProps<Props>();
|
const props = defineProps<Props>();
|
||||||
|
const { modalId } = toRefs(props);
|
||||||
|
|
||||||
// state
|
// state
|
||||||
|
|
||||||
const isSideShow = ref(false);
|
const isSideShow = useState(`side-modal-${modalId.value}`, () => false);
|
||||||
|
|
||||||
const isLocked = useScrollLock(window);
|
const isLocked = useScrollLock(window);
|
||||||
|
|
||||||
|
|||||||
@@ -90,6 +90,8 @@ const changeSlide = (id: number) => {
|
|||||||
<NuxtImg
|
<NuxtImg
|
||||||
class="absolute object-cover size-full"
|
class="absolute object-cover size-full"
|
||||||
:src="slide.image"
|
:src="slide.image"
|
||||||
|
loading="lazy"
|
||||||
|
fetch-priority="low"
|
||||||
:alt="String(slide.id)"
|
:alt="String(slide.id)"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -67,6 +67,8 @@ const parallaxStyle = computed(() => {
|
|||||||
<NuxtImg
|
<NuxtImg
|
||||||
:id="`product-image-${id}`"
|
:id="`product-image-${id}`"
|
||||||
:src="picture"
|
:src="picture"
|
||||||
|
loading="lazy"
|
||||||
|
fetch-priority="low"
|
||||||
class="group-hover:scale-105 transition-transform duration-200 size-full object-contain absolute inset-0"
|
class="group-hover:scale-105 transition-transform duration-200 size-full object-contain absolute inset-0"
|
||||||
alt="product-background"
|
alt="product-background"
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -42,6 +42,8 @@ const onSlideChange = (swiper: SwiperClass) => {
|
|||||||
:style="{
|
:style="{
|
||||||
filter: 'drop-shadow(0px 0px 20px rgba(0, 0, 0, 0.4))',
|
filter: 'drop-shadow(0px 0px 20px rgba(0, 0, 0, 0.4))',
|
||||||
}"
|
}"
|
||||||
|
loading="lazy"
|
||||||
|
fetch-priority="low"
|
||||||
src="/img/heymlz/heymlz-category-seat.gif"
|
src="/img/heymlz/heymlz-category-seat.gif"
|
||||||
/>
|
/>
|
||||||
<Swiper
|
<Swiper
|
||||||
|
|||||||
@@ -209,11 +209,15 @@ onUnmounted(() => {
|
|||||||
webkit-playsinline
|
webkit-playsinline
|
||||||
class="slide-video absolute inset-0 size-full object-cover brightness-90"
|
class="slide-video absolute inset-0 size-full object-cover brightness-90"
|
||||||
:src="slide.video"
|
:src="slide.video"
|
||||||
|
poster="/img/test-thumbnail.jpeg"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<NuxtImg
|
<NuxtImg
|
||||||
v-else
|
v-else
|
||||||
|
preload
|
||||||
|
loading="eager"
|
||||||
|
fetch-priority="high"
|
||||||
class="absolute inset-0 size-full object-cover"
|
class="absolute inset-0 size-full object-cover"
|
||||||
:src="slide.image!"
|
:src="slide.image!"
|
||||||
:alt="slide.title"
|
:alt="slide.title"
|
||||||
@@ -259,13 +263,15 @@ onUnmounted(() => {
|
|||||||
:to="slide.link"
|
:to="slide.link"
|
||||||
class="relative max-sm:hidden"
|
class="relative max-sm:hidden"
|
||||||
>
|
>
|
||||||
<NuxtImg
|
<!-- <NuxtImg
|
||||||
class="aspect-square w-[110px] lg:w-[120px] translate-y-[-75px] lg:translate-y-[-82px] absolute left-1/2 -translate-x-1/2 z-10"
|
class="aspect-square w-[110px] lg:w-[120px] translate-y-[-75px] lg:translate-y-[-82px] absolute left-1/2 -translate-x-1/2 z-10"
|
||||||
:style="{
|
:style="{
|
||||||
filter: 'drop-shadow(0px 0px 20px rgba(0, 0, 0, 0.4))',
|
filter: 'drop-shadow(0px 0px 20px rgba(0, 0, 0, 0.4))',
|
||||||
}"
|
}"
|
||||||
src="/img/heymlz/heymlz-seat.gif"
|
src="/img/heymlz/heymlz-seat.gif"
|
||||||
/>
|
loading="lazy"
|
||||||
|
fetch-priority="low"
|
||||||
|
/> -->
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
variant="primary"
|
variant="primary"
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
|
||||||
// import
|
// import
|
||||||
|
|
||||||
import { Swiper, SwiperSlide } from "swiper/vue";
|
import { Swiper, SwiperSlide } from "swiper/vue";
|
||||||
@@ -7,7 +6,7 @@ import type { SwiperClass } from "swiper/react";
|
|||||||
|
|
||||||
// types
|
// types
|
||||||
|
|
||||||
type Props = {}
|
type Props = {};
|
||||||
|
|
||||||
// props
|
// props
|
||||||
|
|
||||||
@@ -23,7 +22,6 @@ const swiper_instance = ref<SwiperClass | null>(null);
|
|||||||
const onSwiper = (swiper: SwiperClass) => {
|
const onSwiper = (swiper: SwiperClass) => {
|
||||||
swiper_instance.value = swiper;
|
swiper_instance.value = swiper;
|
||||||
};
|
};
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -31,6 +29,8 @@ const onSwiper = (swiper: SwiperClass) => {
|
|||||||
<NuxtImg
|
<NuxtImg
|
||||||
class="absolute size-full object-cover"
|
class="absolute size-full object-cover"
|
||||||
src="/img/hero-bg.jpg"
|
src="/img/hero-bg.jpg"
|
||||||
|
loading="lazy"
|
||||||
|
fetch-priority="low"
|
||||||
alt=""
|
alt=""
|
||||||
/>
|
/>
|
||||||
<div class="absolute bg-black/60 size-full z-10" />
|
<div class="absolute bg-black/60 size-full z-10" />
|
||||||
@@ -50,15 +50,18 @@ const onSwiper = (swiper: SwiperClass) => {
|
|||||||
>
|
>
|
||||||
<div class="flex justify-center items-center">
|
<div class="flex justify-center items-center">
|
||||||
<div class="max-w-[900px] px-4 text-white flex flex-col items-center gap-4">
|
<div class="max-w-[900px] px-4 text-white flex flex-col items-center gap-4">
|
||||||
<Icon name="ci:instagram" size="28" class="**:stroke-white" />
|
<Icon
|
||||||
<p class="text-base xs:text-lg sm:typo-h-6 lg:typo-h-5 !font-normal !leading-[150%] lg:leading-[175%] max-sm:px-4 sm:max-w-[600px] lg:max-w-[800px] text-center">
|
name="ci:instagram"
|
||||||
لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ و با
|
size="28"
|
||||||
استفاده از طراحان گرافیک است. چاپگرها و متون بلکه روزنامه و مجله
|
class="**:stroke-white"
|
||||||
در ستون و سطرآنچنان که لازم.
|
/>
|
||||||
|
<p
|
||||||
|
class="text-base xs:text-lg sm:typo-h-6 lg:typo-h-5 !font-normal !leading-[150%] lg:leading-[175%] max-sm:px-4 sm:max-w-[600px] lg:max-w-[800px] text-center"
|
||||||
|
>
|
||||||
|
لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ و با استفاده از طراحان گرافیک
|
||||||
|
است. چاپگرها و متون بلکه روزنامه و مجله در ستون و سطرآنچنان که لازم.
|
||||||
</p>
|
</p>
|
||||||
<span class="typo-p-sm md:typo-p-xl text-center">
|
<span class="typo-p-sm md:typo-p-xl text-center"> - منصور مرزبان </span>
|
||||||
- منصور مرزبان
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</SwiperSlide>
|
</SwiperSlide>
|
||||||
@@ -69,10 +72,8 @@ const onSwiper = (swiper: SwiperClass) => {
|
|||||||
v-for="(i, index) in 6"
|
v-for="(i, index) in 6"
|
||||||
:class="swiper_instance?.realIndex === index ? 'bg-white' : 'bg-transparent'"
|
:class="swiper_instance?.realIndex === index ? 'bg-white' : 'bg-transparent'"
|
||||||
class="border border-white size-1.5 md:size-2 rounded-full transition-all duration-200"
|
class="border border-white size-1.5 md:size-2 rounded-full transition-all duration-200"
|
||||||
>
|
></div>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -88,6 +88,8 @@ watch(
|
|||||||
:src="homeData!.difreance_section.image1"
|
:src="homeData!.difreance_section.image1"
|
||||||
class="select-none absolute size-full object-cover transition-[filter] duration-250 brightness-[95%]"
|
class="select-none absolute size-full object-cover transition-[filter] duration-250 brightness-[95%]"
|
||||||
:alt="homeData!.difreance_section.title1"
|
:alt="homeData!.difreance_section.title1"
|
||||||
|
loading="lazy"
|
||||||
|
fetch-priority="low"
|
||||||
/>
|
/>
|
||||||
<video
|
<video
|
||||||
v-else
|
v-else
|
||||||
@@ -110,6 +112,8 @@ watch(
|
|||||||
:src="homeData!.difreance_section.image2"
|
:src="homeData!.difreance_section.image2"
|
||||||
class="overlay-image select-none absolute object-cover size-full transition-[filter] duration-250 brightness-[95%]"
|
class="overlay-image select-none absolute object-cover size-full transition-[filter] duration-250 brightness-[95%]"
|
||||||
:alt="homeData!.difreance_section.title2"
|
:alt="homeData!.difreance_section.title2"
|
||||||
|
loading="lazy"
|
||||||
|
fetch-priority="low"
|
||||||
/>
|
/>
|
||||||
<video
|
<video
|
||||||
v-else
|
v-else
|
||||||
@@ -126,9 +130,7 @@ watch(
|
|||||||
:style="{
|
:style="{
|
||||||
left: `${clipPathPercent}%`,
|
left: `${clipPathPercent}%`,
|
||||||
}"
|
}"
|
||||||
:class="[
|
:class="[activeSlideVideo !== 'none' ? 'opacity-10' : '']"
|
||||||
activeSlideVideo !== 'none' ? 'opacity-10' : '',
|
|
||||||
]"
|
|
||||||
class="select-none w-[5px] sm:w-2 bg-black h-full absolute left-0 flex items-center justify-center transition-opacity duration-250"
|
class="select-none w-[5px] sm:w-2 bg-black h-full absolute left-0 flex items-center justify-center transition-opacity duration-250"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
@@ -143,9 +145,7 @@ watch(
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div class="absolute bottom-0 p-6 md:p-10 w-full flex justify-between items-end transition-opacity">
|
||||||
class="absolute bottom-0 p-6 md:p-10 w-full flex justify-between items-end transition-opacity"
|
|
||||||
>
|
|
||||||
<div
|
<div
|
||||||
class="flex flex-col gap-2 text-black transition-opacity"
|
class="flex flex-col gap-2 text-black transition-opacity"
|
||||||
:class="activeSlideVideo === 'right' ? 'opacity-0' : ''"
|
:class="activeSlideVideo === 'right' ? 'opacity-0' : ''"
|
||||||
|
|||||||
@@ -0,0 +1,208 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
// import
|
||||||
|
|
||||||
|
import useHomeData from "~/composables/api/home/useHomeData";
|
||||||
|
|
||||||
|
// state
|
||||||
|
|
||||||
|
const { data: homeData } = useHomeData();
|
||||||
|
|
||||||
|
const clipPathPercent = ref(49);
|
||||||
|
|
||||||
|
const activeSlideVideo = ref<"left" | "right" | "none">("none");
|
||||||
|
|
||||||
|
const draggableEl = ref<HTMLElement | null>(null);
|
||||||
|
const previewContainerEl = ref<HTMLElement | null>(null);
|
||||||
|
|
||||||
|
const heymlzElement = useTemplateRef<HTMLDivElement>("heymlzElement");
|
||||||
|
const heymlzElementIsVisible = useElementVisibility(heymlzElement, {
|
||||||
|
rootMargin: "0px 0px -40% 0px",
|
||||||
|
});
|
||||||
|
|
||||||
|
const showHeymlzAnimation = ref(false);
|
||||||
|
|
||||||
|
const { x: dragAxisX } = useDraggable(draggableEl, {
|
||||||
|
initialValue: { x: 0, y: 0 },
|
||||||
|
axis: "x",
|
||||||
|
});
|
||||||
|
|
||||||
|
// watch
|
||||||
|
|
||||||
|
watch(
|
||||||
|
heymlzElementIsVisible,
|
||||||
|
(newValue) => {
|
||||||
|
if (newValue) {
|
||||||
|
setTimeout(() => {
|
||||||
|
showHeymlzAnimation.value = true;
|
||||||
|
setTimeout(() => {
|
||||||
|
showHeymlzAnimation.value = false;
|
||||||
|
}, 3200);
|
||||||
|
}, 400);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
once: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => clipPathPercent.value,
|
||||||
|
(newValue) => {
|
||||||
|
if (newValue > 80) {
|
||||||
|
activeSlideVideo.value = "right";
|
||||||
|
} else if (newValue < 20) {
|
||||||
|
activeSlideVideo.value = "left";
|
||||||
|
} else {
|
||||||
|
activeSlideVideo.value = "none";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => dragAxisX.value,
|
||||||
|
(newValue) => {
|
||||||
|
const clientRect = previewContainerEl.value?.getBoundingClientRect()!;
|
||||||
|
const percent = clientRect.width / 100;
|
||||||
|
const clipPercent = (newValue + draggableEl.value!.clientWidth / 2 - clientRect.x - 8) / percent;
|
||||||
|
if (clipPercent >= 1 && clipPercent <= 99) {
|
||||||
|
clipPathPercent.value = clipPercent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="container mb-40 lg:mb-40 max-lg:mt-20 lg:-mt-32">
|
||||||
|
<div>
|
||||||
|
<div class="flex flex-col items-center gap-3 mb-10 lg:mb-16">
|
||||||
|
<span class="typo-p-sm md:typo-p-md text-slate-500"> مقایسه محصولات </span>
|
||||||
|
<span class="typo-h-6 md:typo-h-5 lg:typo-h-3 text-black"> تفاوت محصلات ما را ببینید </span>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
ref="previewContainerEl"
|
||||||
|
class="rounded-200 overflow-hidden h-[70svh] relative"
|
||||||
|
>
|
||||||
|
<Transition name="fade">
|
||||||
|
<NuxtImg
|
||||||
|
v-if="activeSlideVideo !== 'right'"
|
||||||
|
:src="homeData!.difreance_section.image1"
|
||||||
|
:class="showHeymlzAnimation ? 'brightness-25 blur-sm' : 'brightness-[95%] blur-[0px]'"
|
||||||
|
class="select-none absolute size-full object-cover transition-[filter] duration-250"
|
||||||
|
:alt="homeData!.difreance_section.title1"
|
||||||
|
/>
|
||||||
|
<video
|
||||||
|
v-else
|
||||||
|
autoplay
|
||||||
|
muted
|
||||||
|
playsinline
|
||||||
|
webkit-playsinline
|
||||||
|
src="/video/vid-3.mp4"
|
||||||
|
class="select-none absolute size-full object-cover brightness-[95%]"
|
||||||
|
/>
|
||||||
|
</Transition>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="absolute size-full right-0 w-full"
|
||||||
|
ref="heymlzElement"
|
||||||
|
>
|
||||||
|
<Transition name="fade">
|
||||||
|
<NuxtImg
|
||||||
|
v-if="activeSlideVideo !== 'left'"
|
||||||
|
:src="homeData!.difreance_section.image2"
|
||||||
|
:class="showHeymlzAnimation ? 'brightness-25 blur-sm' : 'brightness-[95%] blur-[0px]'"
|
||||||
|
class="overlay-image select-none absolute object-cover size-full transition-[filter] duration-250"
|
||||||
|
:alt="homeData!.difreance_section.title2"
|
||||||
|
/>
|
||||||
|
<video
|
||||||
|
v-else
|
||||||
|
autoplay
|
||||||
|
muted
|
||||||
|
playsinline
|
||||||
|
webkit-playsinline
|
||||||
|
src="/video/vid-3.mp4"
|
||||||
|
class="overlay-image select-none absolute object-cover size-full brightness-[95%]"
|
||||||
|
/>
|
||||||
|
</Transition>
|
||||||
|
|
||||||
|
<Transition
|
||||||
|
name="fade"
|
||||||
|
:duration="250"
|
||||||
|
>
|
||||||
|
<NuxtImg
|
||||||
|
v-if="showHeymlzAnimation"
|
||||||
|
src="/img/heymlz/heymlz-pullingg.gif"
|
||||||
|
class="size-[250px] sm:size-[400px] absolute translate-x-[-62px] sm:translate-x-[-107px] z-10 top-[50%] -translate-y-1/2"
|
||||||
|
:style="{
|
||||||
|
left: `${clipPathPercent}%`,
|
||||||
|
filter: 'drop-shadow(0px 0px 20px rgba(0, 0, 0, 0.3))',
|
||||||
|
}"
|
||||||
|
/>
|
||||||
|
</Transition>
|
||||||
|
|
||||||
|
<div
|
||||||
|
:style="{
|
||||||
|
left: `${clipPathPercent}%`,
|
||||||
|
}"
|
||||||
|
:class="[
|
||||||
|
activeSlideVideo !== 'none' ? 'opacity-10' : '',
|
||||||
|
showHeymlzAnimation ? 'bg-neutral-200' : 'bg-black',
|
||||||
|
]"
|
||||||
|
class="select-none w-[5px] sm:w-2 h-full absolute left-0 flex items-center justify-center transition-opacity duration-250"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
ref="draggableEl"
|
||||||
|
:class="showHeymlzAnimation ? 'bg-neutral-200' : 'bg-black'"
|
||||||
|
class="touch-none cursor-grab hover:scale-115 transition-transform rounded-full absolute size-9 sm:size-11 flex items-center justify-center"
|
||||||
|
>
|
||||||
|
<Icon
|
||||||
|
name="ci:arrows"
|
||||||
|
class="transition-all size-5 sm:size-6"
|
||||||
|
:class="showHeymlzAnimation ? '**:stroke-black' : '**:stroke-white'"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
:class="showHeymlzAnimation ? 'opacity-0' : 'opacity-100'"
|
||||||
|
class="absolute bottom-0 p-6 md:p-10 w-full flex justify-between items-end transition-opacity"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="flex flex-col gap-2 text-black transition-opacity"
|
||||||
|
:class="activeSlideVideo === 'right' ? 'opacity-0' : ''"
|
||||||
|
>
|
||||||
|
<span class="typo-p-sm md:typo-p-md">
|
||||||
|
{{ homeData!.difreance_section.description1 }}
|
||||||
|
</span>
|
||||||
|
<NuxtLink
|
||||||
|
:to="homeData!.difreance_section.link1"
|
||||||
|
class="typo-h-6 md:typo-h-5 lg:typo-h-3"
|
||||||
|
>
|
||||||
|
{{ homeData!.difreance_section.title1 }}
|
||||||
|
</NuxtLink>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="flex flex-col gap-2 text-black transition-opacity"
|
||||||
|
:class="activeSlideVideo === 'left' ? 'opacity-0' : ''"
|
||||||
|
>
|
||||||
|
<span class="typo-p-sm md:typo-p-md text-end">
|
||||||
|
{{ homeData!.difreance_section.description2 }}
|
||||||
|
</span>
|
||||||
|
<NuxtLink
|
||||||
|
:to="homeData!.difreance_section.link2"
|
||||||
|
class="typo-h-6 md:typo-h-5 lg:typo-h-3 text-end"
|
||||||
|
>
|
||||||
|
{{ homeData!.difreance_section.title2 }}
|
||||||
|
</NuxtLink>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.overlay-image {
|
||||||
|
clip-path: polygon(v-bind('clipPathPercent + "%"') 0, 100% 0, 100% 100%, v-bind('clipPathPercent + "%"') 100%);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -106,6 +106,8 @@ const childImageVariants = {
|
|||||||
<NuxtImg
|
<NuxtImg
|
||||||
:src="slide.background_image"
|
:src="slide.background_image"
|
||||||
class="absolute size-full object-cover"
|
class="absolute size-full object-cover"
|
||||||
|
loading="lazy"
|
||||||
|
fetch-priority="low"
|
||||||
/>
|
/>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
</template>
|
</template>
|
||||||
@@ -133,6 +135,8 @@ const childImageVariants = {
|
|||||||
<NuxtImg
|
<NuxtImg
|
||||||
class="w-[130px] sm:w-[180px] lg:w-[250px] xl:w-[300px] z-20 mt-40"
|
class="w-[130px] sm:w-[180px] lg:w-[250px] xl:w-[300px] z-20 mt-40"
|
||||||
:src="slide.image3"
|
:src="slide.image3"
|
||||||
|
loading="lazy"
|
||||||
|
fetch-priority="low"
|
||||||
alt=""
|
alt=""
|
||||||
/>
|
/>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
@@ -144,6 +148,8 @@ const childImageVariants = {
|
|||||||
<NuxtImg
|
<NuxtImg
|
||||||
class="w-[130px] sm:w-[180px] lg:w-[250px] xl:w-[300px] z-20"
|
class="w-[130px] sm:w-[180px] lg:w-[250px] xl:w-[300px] z-20"
|
||||||
:src="slide.image2"
|
:src="slide.image2"
|
||||||
|
loading="lazy"
|
||||||
|
fetch-priority="low"
|
||||||
alt=""
|
alt=""
|
||||||
/>
|
/>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
@@ -155,6 +161,8 @@ const childImageVariants = {
|
|||||||
<NuxtImg
|
<NuxtImg
|
||||||
class="w-[130px] sm:w-[180px] lg:w-[250px] xl:w-[300px] z-20 mt-40"
|
class="w-[130px] sm:w-[180px] lg:w-[250px] xl:w-[300px] z-20 mt-40"
|
||||||
:src="slide.image1"
|
:src="slide.image1"
|
||||||
|
loading="lazy"
|
||||||
|
fetch-priority="low"
|
||||||
alt=""
|
alt=""
|
||||||
/>
|
/>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
@@ -211,17 +219,19 @@ const childImageVariants = {
|
|||||||
<span class="text-white typo-h-6 sm:typo-h-5 lg:typo-h-4 xl:typo-h-3">
|
<span class="text-white typo-h-6 sm:typo-h-5 lg:typo-h-4 xl:typo-h-3">
|
||||||
{{ slide.title }}
|
{{ slide.title }}
|
||||||
</span>
|
</span>
|
||||||
<p
|
<!-- <p
|
||||||
class="text-white max-w-[320px] xs:max-w-[360px] sm:max-w-[480px] lg:max-w-[550px] xl:max-w-[750px] typo-p-sm lg:typo-p-md xl:typo-p-lg"
|
class="text-white max-w-[320px] xs:max-w-[360px] sm:max-w-[480px] lg:max-w-[550px] xl:max-w-[750px] typo-p-sm lg:typo-p-md xl:typo-p-lg"
|
||||||
>
|
>
|
||||||
{{ slide.description }}
|
{{ slide.description }}
|
||||||
</p>
|
</p> -->
|
||||||
<NuxtLink
|
<NuxtLink
|
||||||
:to="`/resellers/category/${slide.id}`"
|
:to="`/resellers/category/${slide.id}`"
|
||||||
class="relative"
|
class="relative"
|
||||||
>
|
>
|
||||||
<NuxtImg
|
<NuxtImg
|
||||||
src="/img/heymlz/heymlz-falling.gif"
|
src="/img/heymlz/heymlz-falling.gif"
|
||||||
|
loading="lazy"
|
||||||
|
fetch-priority="low"
|
||||||
class="absolute top-[101px] sm:top-[100px] lg:top-[117px] left-1/2 -translate-1/2 w-[200px] lg:w-[250px] drop-shadow-md"
|
class="absolute top-[101px] sm:top-[100px] lg:top-[117px] left-1/2 -translate-1/2 w-[200px] lg:w-[250px] drop-shadow-md"
|
||||||
/>
|
/>
|
||||||
<Button
|
<Button
|
||||||
|
|||||||
@@ -187,6 +187,8 @@ whenever(
|
|||||||
<NuxtImg
|
<NuxtImg
|
||||||
class="size-[225px] sm:size-[250px] drop-shadow-2xl"
|
class="size-[225px] sm:size-[250px] drop-shadow-2xl"
|
||||||
src="/img/heymlz/heymlz-small-idle.gif"
|
src="/img/heymlz/heymlz-small-idle.gif"
|
||||||
|
loading="lazy"
|
||||||
|
fetch-priority="low"
|
||||||
alt=""
|
alt=""
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -199,6 +201,8 @@ whenever(
|
|||||||
<NuxtImg
|
<NuxtImg
|
||||||
class="size-[225px] sm:size-[250px] drop-shadow-2xl"
|
class="size-[225px] sm:size-[250px] drop-shadow-2xl"
|
||||||
src="/img/heymlz/heymlz-small-idle.gif"
|
src="/img/heymlz/heymlz-small-idle.gif"
|
||||||
|
loading="lazy"
|
||||||
|
fetch-priority="low"
|
||||||
alt=""
|
alt=""
|
||||||
/>
|
/>
|
||||||
<div class="flex flex-col gap-4 items-center">
|
<div class="flex flex-col gap-4 items-center">
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import useGetAccount from '~/composables/api/account/useGetAccount';
|
import useGetAccount from "~/composables/api/account/useGetAccount";
|
||||||
|
|
||||||
// types
|
// types
|
||||||
|
|
||||||
@@ -85,31 +85,34 @@ onMounted(() => {
|
|||||||
src="/img/heymlz/heymlz-full-body.jpg"
|
src="/img/heymlz/heymlz-full-body.jpg"
|
||||||
class="size-full object-cover absolute"
|
class="size-full object-cover absolute"
|
||||||
alt="profile"
|
alt="profile"
|
||||||
|
loading="lazy"
|
||||||
|
fetch-priority="low"
|
||||||
/>
|
/>
|
||||||
<NuxtImg
|
<NuxtImg
|
||||||
v-else
|
v-else
|
||||||
:src="account?.profile_photo ?? ''"
|
:src="account?.profile_photo ?? ''"
|
||||||
class="size-full object-cover absolute"
|
class="size-full object-cover absolute"
|
||||||
|
loading="lazy"
|
||||||
|
fetch-priority="low"
|
||||||
alt="profile"
|
alt="profile"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="rounded-150 px-4 py-3 whitespace-pre-wrap overflow-hidden"
|
class="rounded-150 px-4 py-3 whitespace-pre-wrap overflow-hidden"
|
||||||
:class="
|
:class="reverse ? 'bg-slate-100 text-slate-600' : 'bg-black text-white'"
|
||||||
reverse
|
|
||||||
? 'bg-slate-100 text-slate-600'
|
|
||||||
: 'bg-black text-white'
|
|
||||||
"
|
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
v-if="!loadingContent"
|
v-if="!loadingContent"
|
||||||
:id="`chat-message-content-${id}`"
|
:id="`chat-message-content-${id}`"
|
||||||
class="typo-p-sm font-normal whitespace-pre-wrap"
|
class="typo-p-sm font-normal whitespace-pre-wrap"
|
||||||
v-html="content"
|
v-html="content"
|
||||||
>
|
></div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<Icon v-else name="svg-spinners:3-dots-bounce" size="20" />
|
<Icon
|
||||||
|
v-else
|
||||||
|
name="svg-spinners:3-dots-bounce"
|
||||||
|
size="20"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -127,6 +127,8 @@ const limitedComments = computed(() => {
|
|||||||
>
|
>
|
||||||
<NuxtImg
|
<NuxtImg
|
||||||
src="/img/heymlz/heymlz-contact-us.gif"
|
src="/img/heymlz/heymlz-contact-us.gif"
|
||||||
|
loading="lazy"
|
||||||
|
fetch-priority="low"
|
||||||
class="w-[200px] lg:w-[300px] translate-y-[-25px]"
|
class="w-[200px] lg:w-[300px] translate-y-[-25px]"
|
||||||
/>
|
/>
|
||||||
<span class="text-xl text-black font-semibold translate-y-[-25px]"> هیچ نظری ثبت نشده است </span>
|
<span class="text-xl text-black font-semibold translate-y-[-25px]"> هیچ نظری ثبت نشده است </span>
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
|
||||||
// import
|
// import
|
||||||
|
|
||||||
import type { ProductVariantProvideType } from "~/pages/product/[id].vue";
|
import type { ProductVariantProvideType } from "~/pages/product/[id].vue";
|
||||||
@@ -7,7 +6,6 @@ import type { ProductVariantProvideType } from "~/pages/product/[id].vue";
|
|||||||
// provide / inject
|
// provide / inject
|
||||||
|
|
||||||
const { selectedVariant } = inject("productVariant") as ProductVariantProvideType;
|
const { selectedVariant } = inject("productVariant") as ProductVariantProvideType;
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -20,30 +18,26 @@ const { selectedVariant } = inject("productVariant") as ProductVariantProvideTyp
|
|||||||
<Accordion />
|
<Accordion />
|
||||||
</div>
|
</div>
|
||||||
<div class="w-full lg:w-[450px] xl:w-[600px]">
|
<div class="w-full lg:w-[450px] xl:w-[600px]">
|
||||||
<div
|
<div class="w-full bg-slate-50 rounded-xl flex-col-center px-5 py-16 sm:p-[5rem] gap-[1.5rem]">
|
||||||
class="w-full bg-slate-50 rounded-xl flex-col-center px-5 py-16 sm:p-[5rem] gap-[1.5rem]"
|
|
||||||
>
|
|
||||||
<span class="typo-h-6 mb-8">داخل جعبه چیه؟</span>
|
<span class="typo-h-6 mb-8">داخل جعبه چیه؟</span>
|
||||||
<div
|
<div class="w-full grid grid-cols-2 gap-y-[1.5rem] sm:gap-x-[3rem]">
|
||||||
class="w-full grid grid-cols-2 gap-y-[1.5rem] sm:gap-x-[3rem]"
|
|
||||||
>
|
|
||||||
<div
|
<div
|
||||||
v-for="inPackItem in selectedVariant!.in_pack_items"
|
v-for="inPackItem in selectedVariant!.in_pack_items"
|
||||||
class="w-full flex-col-center gap-[.75rem]"
|
class="w-full flex-col-center gap-[.75rem]"
|
||||||
>
|
>
|
||||||
<div
|
<div class="size-[6.25rem] rounded-full border-slate-200 bg-white flex-center">
|
||||||
class="size-[6.25rem] rounded-full border-slate-200 bg-white flex-center"
|
|
||||||
>
|
|
||||||
<div class="size-11 relative">
|
<div class="size-11 relative">
|
||||||
<NuxtImg
|
<NuxtImg
|
||||||
class="size-full absolute object-cover"
|
class="size-full absolute object-cover"
|
||||||
:src="inPackItem.cover"
|
:src="inPackItem.cover"
|
||||||
:alt="inPackItem.item_title"
|
:alt="inPackItem.item_title"
|
||||||
|
loading="lazy"
|
||||||
|
fetch-priority="low"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<span class="text-black typo-p-md">
|
<span class="text-black typo-p-md">
|
||||||
{{ inPackItem.item_title}}
|
{{ inPackItem.item_title }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -51,4 +45,4 @@ const { selectedVariant } = inject("productVariant") as ProductVariantProvideTyp
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -253,6 +253,26 @@ watch(
|
|||||||
<UpdateQuantity v-else-if="selectedVariant!.in_stock > 0" />
|
<UpdateQuantity v-else-if="selectedVariant!.in_stock > 0" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="flex items-center gap-4"
|
||||||
|
v-if="selectedVariant!.cart_quantity === 0"
|
||||||
|
>
|
||||||
|
<Button
|
||||||
|
variant="secondary"
|
||||||
|
class="w-full rounded-full h-full max-sm:h-[48px]"
|
||||||
|
end-icon="bi:percent"
|
||||||
|
>
|
||||||
|
۱۰۰ تومان تخفیف بگیر
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant="secondary"
|
||||||
|
class="w-full rounded-full h-full max-sm:h-[48px]"
|
||||||
|
end-icon="bi:person-check"
|
||||||
|
>
|
||||||
|
پورسانت بگیر
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
|
||||||
<InfoCard />
|
<InfoCard />
|
||||||
|
|
||||||
<Share />
|
<Share />
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ const router = useRouter();
|
|||||||
|
|
||||||
const params = inject("params") as GetProductsFilters;
|
const params = inject("params") as GetProductsFilters;
|
||||||
|
|
||||||
|
const isSideShow = useState("side-modal-product-filters");
|
||||||
|
|
||||||
const currentCategory = computed({
|
const currentCategory = computed({
|
||||||
get: () => {
|
get: () => {
|
||||||
return Array.isArray(route.params.slug) ? route.params.slug[1] ?? undefined : undefined;
|
return Array.isArray(route.params.slug) ? route.params.slug[1] ?? undefined : undefined;
|
||||||
@@ -238,38 +240,59 @@ watch(
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</Transition>
|
</Transition>
|
||||||
<Button
|
<div class="flex items-center gap-4 w-full">
|
||||||
:disabled="productsIsPending"
|
<Button
|
||||||
variant="solid"
|
:disabled="productsIsPending"
|
||||||
@click="resetFilters"
|
variant="primary"
|
||||||
class="w-full rounded-full py-4 !cursor-pointer disabled:pointer-events-none z-[3]"
|
@click="() => (isSideShow = false)"
|
||||||
>
|
class="w-full rounded-full py-4 !cursor-pointer disabled:pointer-events-none z-[3]"
|
||||||
<Transition
|
|
||||||
name="fade"
|
|
||||||
mode="out-in"
|
|
||||||
>
|
>
|
||||||
<span
|
<Transition
|
||||||
v-if="productsIsPending"
|
name="fade"
|
||||||
class="flex-center gap-3"
|
mode="out-in"
|
||||||
>
|
>
|
||||||
در حال دریافت اطلاعات
|
<span class="flex-center gap-3">
|
||||||
<Icon
|
ثبت فیلتر جدید
|
||||||
name="svg-spinners:3-dots-bounce"
|
<Icon
|
||||||
size="20"
|
name="ci:plus"
|
||||||
/>
|
size="20"
|
||||||
</span>
|
/>
|
||||||
<span
|
</span>
|
||||||
v-else
|
</Transition>
|
||||||
class="flex-center gap-3"
|
</Button>
|
||||||
|
<Button
|
||||||
|
:disabled="productsIsPending"
|
||||||
|
variant="solid"
|
||||||
|
@click="resetFilters"
|
||||||
|
class="w-full rounded-full py-4 !cursor-pointer disabled:pointer-events-none z-[3]"
|
||||||
|
>
|
||||||
|
<Transition
|
||||||
|
name="fade"
|
||||||
|
mode="out-in"
|
||||||
>
|
>
|
||||||
بازنشانی به پیش فرض
|
<span
|
||||||
<Icon
|
v-if="productsIsPending"
|
||||||
name="ci:close"
|
class="flex-center gap-3"
|
||||||
size="20"
|
>
|
||||||
/>
|
در حال دریافت اطلاعات
|
||||||
</span>
|
<Icon
|
||||||
</Transition>
|
name="svg-spinners:3-dots-bounce"
|
||||||
</Button>
|
size="20"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
v-else
|
||||||
|
class="flex-center gap-3"
|
||||||
|
>
|
||||||
|
بازنشانی به پیش فرض
|
||||||
|
<Icon
|
||||||
|
name="ci:close"
|
||||||
|
size="20"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
</Transition>
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -38,9 +38,7 @@ const profile = computed(() => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const username = computed(() => {
|
const username = computed(() => {
|
||||||
return is_user.value
|
return is_user.value ? `${account.value?.first_name} ${account.value?.last_name}` : "ادمین پشتیبانی هی ملز";
|
||||||
? `${account.value?.first_name} ${account.value?.last_name}`
|
|
||||||
: "ادمین پشتیبانی هی ملز";
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -54,7 +52,12 @@ const username = computed(() => {
|
|||||||
:class="is_user ? 'rounded-br-none' : 'rounded-bl-none'"
|
:class="is_user ? 'rounded-br-none' : 'rounded-bl-none'"
|
||||||
>
|
>
|
||||||
<div class="w-2/12 flex items-start justify-start">
|
<div class="w-2/12 flex items-start justify-start">
|
||||||
<NuxtImg :src="profile" class="size-16 rounded-full" />
|
<NuxtImg
|
||||||
|
:src="profile"
|
||||||
|
loading="lazy"
|
||||||
|
fetch-priority="low"
|
||||||
|
class="size-16 rounded-full"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="w-10/12 flex flex-col items-start pt-2">
|
<div class="w-10/12 flex flex-col items-start pt-2">
|
||||||
@@ -65,9 +68,7 @@ const username = computed(() => {
|
|||||||
>
|
>
|
||||||
{{ timeAgo }}
|
{{ timeAgo }}
|
||||||
</p>
|
</p>
|
||||||
<p
|
<p class="text-xs font-semibold text-dynamic-secondary line-clamp-1">
|
||||||
class="text-xs font-semibold text-dynamic-secondary line-clamp-1"
|
|
||||||
>
|
|
||||||
{{ username }}
|
{{ username }}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ const useSlider = ({ duration = 0, count }: Props) => {
|
|||||||
const restartSliderTimer = () => {
|
const restartSliderTimer = () => {
|
||||||
if (sliderTimer.value) clearInterval(sliderTimer.value);
|
if (sliderTimer.value) clearInterval(sliderTimer.value);
|
||||||
runProgress();
|
runProgress();
|
||||||
|
|
||||||
if (duration > 0) {
|
if (duration > 0) {
|
||||||
sliderTimer.value = setInterval(() => {
|
sliderTimer.value = setInterval(() => {
|
||||||
runProgress();
|
runProgress();
|
||||||
@@ -76,7 +76,9 @@ const useSlider = ({ duration = 0, count }: Props) => {
|
|||||||
restartSliderTimer();
|
restartSliderTimer();
|
||||||
});
|
});
|
||||||
|
|
||||||
onUnmounted(() => {});
|
onUnmounted(() => {
|
||||||
|
restartSliderTimer();
|
||||||
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
activeSlide,
|
activeSlide,
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ const hasCartItem = computed(() => !!cart.value && cart.value.items.length! > 0)
|
|||||||
<div class="hidden w-3/12 shrink-0 lg:block"> </div>
|
<div class="hidden w-3/12 shrink-0 lg:block"> </div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="w-full flex flex-col items-center relative justify-between gap-4 lg:gap-6 lg:flex-row lg:items-start"
|
class="w-full flex flex-col items-center relative justify-between gap-8 lg:gap-6 lg:flex-row lg:items-start"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="flex flex-col w-full gap-4 lg:gap-6 shrink-0"
|
class="flex flex-col w-full gap-4 lg:gap-6 shrink-0"
|
||||||
|
|||||||
+11
-11
@@ -61,17 +61,17 @@ export default defineNuxtConfig({
|
|||||||
},
|
},
|
||||||
|
|
||||||
modules: [
|
modules: [
|
||||||
[
|
// [
|
||||||
"@nuxtjs/google-fonts",
|
// "@nuxtjs/google-fonts",
|
||||||
{
|
// {
|
||||||
families: {
|
// families: {
|
||||||
"DM Sans": "100..900",
|
// "DM Sans": "100..900",
|
||||||
Inter: "100..900",
|
// Inter: "100..900",
|
||||||
download: true,
|
// download: true,
|
||||||
inject: false,
|
// inject: false,
|
||||||
},
|
// },
|
||||||
},
|
// },
|
||||||
],
|
// ],
|
||||||
"@nuxt/icon",
|
"@nuxt/icon",
|
||||||
"reka-ui/nuxt",
|
"reka-ui/nuxt",
|
||||||
"@vueuse/nuxt",
|
"@vueuse/nuxt",
|
||||||
|
|||||||
Generated
-26
@@ -25,7 +25,6 @@
|
|||||||
"date-fns-jalali": "^4.1.0-0",
|
"date-fns-jalali": "^4.1.0-0",
|
||||||
"fast-average-color": "^9.4.0",
|
"fast-average-color": "^9.4.0",
|
||||||
"gsap": "^3.12.7",
|
"gsap": "^3.12.7",
|
||||||
"highlight.js": "^11.11.1",
|
|
||||||
"jalali-ts": "^8.0.0",
|
"jalali-ts": "^8.0.0",
|
||||||
"motion-v": "^1.1.1",
|
"motion-v": "^1.1.1",
|
||||||
"nuxt": "^3.15.4",
|
"nuxt": "^3.15.4",
|
||||||
@@ -36,7 +35,6 @@
|
|||||||
"vue": "latest",
|
"vue": "latest",
|
||||||
"vue-image-zoomer": "^2.4.4",
|
"vue-image-zoomer": "^2.4.4",
|
||||||
"vue-router": "latest",
|
"vue-router": "latest",
|
||||||
"vue-scrollto": "^2.20.0",
|
|
||||||
"vue-skeletor": "^1.0.6",
|
"vue-skeletor": "^1.0.6",
|
||||||
"vue3-marquee": "^4.2.2",
|
"vue3-marquee": "^4.2.2",
|
||||||
"vue3-persian-datetime-picker": "^1.2.2",
|
"vue3-persian-datetime-picker": "^1.2.2",
|
||||||
@@ -6555,12 +6553,6 @@
|
|||||||
],
|
],
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/bezier-easing": {
|
|
||||||
"version": "2.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/bezier-easing/-/bezier-easing-2.1.0.tgz",
|
|
||||||
"integrity": "sha512-gbIqZ/eslnUFC1tjEvtz0sgx+xTK20wDnYMIA27VA04R7w6xxXQPZDbibjA9DTWZRA2CXtwHykkVzlCaAJAZig==",
|
|
||||||
"license": "MIT"
|
|
||||||
},
|
|
||||||
"node_modules/bindings": {
|
"node_modules/bindings": {
|
||||||
"version": "1.5.0",
|
"version": "1.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
|
||||||
@@ -9240,15 +9232,6 @@
|
|||||||
"integrity": "sha512-COpmrF2NOg4TBWUJ5UVyaCU2A88wEMkUPK4hNqyCkqHbxT92BbvfjoSozkAIIm6XhicGlJHhFdullInrdhwU8Q==",
|
"integrity": "sha512-COpmrF2NOg4TBWUJ5UVyaCU2A88wEMkUPK4hNqyCkqHbxT92BbvfjoSozkAIIm6XhicGlJHhFdullInrdhwU8Q==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/highlight.js": {
|
|
||||||
"version": "11.11.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.11.1.tgz",
|
|
||||||
"integrity": "sha512-Xwwo44whKBVCYoliBQwaPvtd/2tYFkRQtXDWj1nackaV2JPXx3L0+Jvd8/qCJ2p+ML0/XVkJ2q+Mr+UVdpJK5w==",
|
|
||||||
"license": "BSD-3-Clause",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=12.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/hookable": {
|
"node_modules/hookable": {
|
||||||
"version": "5.5.3",
|
"version": "5.5.3",
|
||||||
"resolved": "https://registry.npmjs.org/hookable/-/hookable-5.5.3.tgz",
|
"resolved": "https://registry.npmjs.org/hookable/-/hookable-5.5.3.tgz",
|
||||||
@@ -16810,15 +16793,6 @@
|
|||||||
"vue": "^3.2.0"
|
"vue": "^3.2.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/vue-scrollto": {
|
|
||||||
"version": "2.20.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/vue-scrollto/-/vue-scrollto-2.20.0.tgz",
|
|
||||||
"integrity": "sha512-7i+AGKJTThZnMEkhIPgrZjyAX+fXV7/rGdg+CV283uZZwCxwiMXaBLTmIc5RTA4uwGnT+E6eJle3mXQfM2OD3A==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"bezier-easing": "2.1.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/vue-skeletor": {
|
"node_modules/vue-skeletor": {
|
||||||
"version": "1.0.6",
|
"version": "1.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/vue-skeletor/-/vue-skeletor-1.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/vue-skeletor/-/vue-skeletor-1.0.6.tgz",
|
||||||
|
|||||||
@@ -33,7 +33,6 @@
|
|||||||
"date-fns-jalali": "^4.1.0-0",
|
"date-fns-jalali": "^4.1.0-0",
|
||||||
"fast-average-color": "^9.4.0",
|
"fast-average-color": "^9.4.0",
|
||||||
"gsap": "^3.12.7",
|
"gsap": "^3.12.7",
|
||||||
"highlight.js": "^11.11.1",
|
|
||||||
"jalali-ts": "^8.0.0",
|
"jalali-ts": "^8.0.0",
|
||||||
"motion-v": "^1.1.1",
|
"motion-v": "^1.1.1",
|
||||||
"nuxt": "^3.15.4",
|
"nuxt": "^3.15.4",
|
||||||
@@ -44,7 +43,6 @@
|
|||||||
"vue": "latest",
|
"vue": "latest",
|
||||||
"vue-image-zoomer": "^2.4.4",
|
"vue-image-zoomer": "^2.4.4",
|
||||||
"vue-router": "latest",
|
"vue-router": "latest",
|
||||||
"vue-scrollto": "^2.20.0",
|
|
||||||
"vue-skeletor": "^1.0.6",
|
"vue-skeletor": "^1.0.6",
|
||||||
"vue3-marquee": "^4.2.2",
|
"vue3-marquee": "^4.2.2",
|
||||||
"vue3-persian-datetime-picker": "^1.2.2",
|
"vue3-persian-datetime-picker": "^1.2.2",
|
||||||
|
|||||||
@@ -38,6 +38,9 @@ if (response.isError) {
|
|||||||
class="absolute object-cover size-full"
|
class="absolute object-cover size-full"
|
||||||
:alt="article!.title"
|
:alt="article!.title"
|
||||||
:src="article!.cover_image"
|
:src="article!.cover_image"
|
||||||
|
preload
|
||||||
|
loading="eager"
|
||||||
|
fetch-priority="high"
|
||||||
/>
|
/>
|
||||||
<div class="absolute bg-linear-to-t from-black/75 to-transparent size-full" />
|
<div class="absolute bg-linear-to-t from-black/75 to-transparent size-full" />
|
||||||
<div class="absolute pl-10 right-10 bottom-10 flex flex-col gap-6">
|
<div class="absolute pl-10 right-10 bottom-10 flex flex-col gap-6">
|
||||||
@@ -62,6 +65,8 @@ if (response.isError) {
|
|||||||
class="size-full object-cover absolute"
|
class="size-full object-cover absolute"
|
||||||
:src="article!.author.profile_photo"
|
:src="article!.author.profile_photo"
|
||||||
alt="article-author"
|
alt="article-author"
|
||||||
|
loading="lazy"
|
||||||
|
fetch-priority="low"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<span class="typo-label-sm">
|
<span class="typo-label-sm">
|
||||||
|
|||||||
@@ -61,6 +61,8 @@ const deliveryData = ref<DeliveryData>({
|
|||||||
<div class="flex items-center gap-3 py-3">
|
<div class="flex items-center gap-3 py-3">
|
||||||
<NuxtImg
|
<NuxtImg
|
||||||
src="/img/location.gif"
|
src="/img/location.gif"
|
||||||
|
loading="lazy"
|
||||||
|
fetch-priority="low"
|
||||||
class="size-12 pb-1 -mr-3"
|
class="size-12 pb-1 -mr-3"
|
||||||
/>
|
/>
|
||||||
<span class="typo-sub-h-xl -mr-3"> آدرس های شما </span>
|
<span class="typo-sub-h-xl -mr-3"> آدرس های شما </span>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import useGetCartOrders from "~/composables/api/orders/useGetCartOrders";
|
|||||||
// meta
|
// meta
|
||||||
|
|
||||||
useSeoMeta({
|
useSeoMeta({
|
||||||
title : "سبد خرید"
|
title: "سبد خرید",
|
||||||
});
|
});
|
||||||
|
|
||||||
definePageMeta({
|
definePageMeta({
|
||||||
@@ -22,9 +22,7 @@ const { data: cart, isLoading: cartIsLoading } = useGetCartOrders();
|
|||||||
|
|
||||||
// computed
|
// computed
|
||||||
|
|
||||||
const hasCartItem = computed(
|
const hasCartItem = computed(() => !!cart.value && cart.value.items.length! > 0);
|
||||||
() => !!cart.value && cart.value.items.length! > 0
|
|
||||||
);
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -38,11 +36,17 @@ const hasCartItem = computed(
|
|||||||
class="!w-36 !h-[43px] !rounded-lg"
|
class="!w-36 !h-[43px] !rounded-lg"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div v-else class="flex items-center w-full gap-2 lg:w-1/2">
|
<div
|
||||||
<NuxtImg src="/img/box.gif" class="size-12 pb-2" />
|
v-else
|
||||||
<p class="font-semibold lg:text-lg text-black">
|
class="flex items-center w-full gap-2 lg:w-1/2"
|
||||||
{{ cart?.items.length }} مرسوله
|
>
|
||||||
</p>
|
<NuxtImg
|
||||||
|
src="/img/box.gif"
|
||||||
|
loading="lazy"
|
||||||
|
fetch-priority="low"
|
||||||
|
class="size-12 pb-2"
|
||||||
|
/>
|
||||||
|
<p class="font-semibold lg:text-lg text-black">{{ cart?.items.length }} مرسوله</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Skeleton
|
<Skeleton
|
||||||
@@ -53,7 +57,10 @@ const hasCartItem = computed(
|
|||||||
<DeleteCartAllModal v-else />
|
<DeleteCartAllModal v-else />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ul v-if="cartIsLoading" class="w-full flex flex-col gap-4 lg:gap-6">
|
<ul
|
||||||
|
v-if="cartIsLoading"
|
||||||
|
class="w-full flex flex-col gap-4 lg:gap-6"
|
||||||
|
>
|
||||||
<Skeleton
|
<Skeleton
|
||||||
v-for="i in 4"
|
v-for="i in 4"
|
||||||
:key="i"
|
:key="i"
|
||||||
@@ -61,20 +68,38 @@ const hasCartItem = computed(
|
|||||||
/>
|
/>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<div v-else class="w-full h-max">
|
<div
|
||||||
<div v-if="!cart?.items.length" class="flex flex-grow w-full">
|
v-else
|
||||||
<Placeholder title="سبد خرید شما خالی است :(" icon="bi:cart">
|
class="w-full h-max"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
v-if="!cart?.items.length"
|
||||||
|
class="flex flex-grow w-full"
|
||||||
|
>
|
||||||
|
<Placeholder
|
||||||
|
title="سبد خرید شما خالی است :("
|
||||||
|
icon="bi:cart"
|
||||||
|
>
|
||||||
<template #actions>
|
<template #actions>
|
||||||
<NuxtLink :to="{ name: 'products' }">
|
<NuxtLink :to="{ name: 'products' }">
|
||||||
<Button class="rounded-full" size="md">
|
<Button
|
||||||
|
class="rounded-full"
|
||||||
|
size="md"
|
||||||
|
>
|
||||||
<span> مشاهده محصولات </span>
|
<span> مشاهده محصولات </span>
|
||||||
<Icon name="ci:left-rotation" size="24" />
|
<Icon
|
||||||
|
name="ci:left-rotation"
|
||||||
|
size="24"
|
||||||
|
/>
|
||||||
</Button>
|
</Button>
|
||||||
</NuxtLink>
|
</NuxtLink>
|
||||||
</template>
|
</template>
|
||||||
</Placeholder>
|
</Placeholder>
|
||||||
</div>
|
</div>
|
||||||
<ul v-else class="w-full flex flex-col gap-4 lg:gap-6">
|
<ul
|
||||||
|
v-else
|
||||||
|
class="w-full flex flex-col gap-4 lg:gap-6"
|
||||||
|
>
|
||||||
<CartItem
|
<CartItem
|
||||||
v-for="(item, index) in cart?.items"
|
v-for="(item, index) in cart?.items"
|
||||||
:key="index"
|
:key="index"
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ if (response.isError) {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="w-full">
|
<div class="w-full">
|
||||||
<LoadingOverlay />
|
<!-- <LoadingOverlay /> -->
|
||||||
<Hero class="mb-20 max-md:mt-[80px]" />
|
<Hero class="mb-20 max-md:mt-[80px]" />
|
||||||
<Preview />
|
<Preview />
|
||||||
<ProductsShowcase class="lg:mb-12" />
|
<ProductsShowcase class="lg:mb-12" />
|
||||||
|
|||||||
@@ -1,173 +0,0 @@
|
|||||||
<script lang="ts" setup>
|
|
||||||
|
|
||||||
// import
|
|
||||||
|
|
||||||
import hljs from "highlight.js";
|
|
||||||
import json from "highlight.js/lib/languages/json";
|
|
||||||
import xml from "highlight.js/lib/languages/xml";
|
|
||||||
import "highlight.js/styles/atom-one-dark.css";
|
|
||||||
import LogDate from "~/components/server-logs/LogDate.vue";
|
|
||||||
import { useQuery } from "@tanstack/vue-query";
|
|
||||||
|
|
||||||
// meta
|
|
||||||
|
|
||||||
definePageMeta({
|
|
||||||
middleware: "check-is-debug",
|
|
||||||
layout: "none"
|
|
||||||
});
|
|
||||||
|
|
||||||
// state
|
|
||||||
|
|
||||||
const { $axios: axios } = useNuxtApp();
|
|
||||||
|
|
||||||
const { data: serverLogs, isFetching, suspense } = useQuery({
|
|
||||||
queryKey: ["server-logs"],
|
|
||||||
queryFn: async () => {
|
|
||||||
const response = await axios.get<AxiosLogType[]>("http://localhost:3000/api/server-logger");
|
|
||||||
return response.data.reverse();
|
|
||||||
},
|
|
||||||
refetchInterval: 5000,
|
|
||||||
staleTime: 0
|
|
||||||
});
|
|
||||||
|
|
||||||
await suspense();
|
|
||||||
|
|
||||||
// computed
|
|
||||||
|
|
||||||
const logIcon = (status: number) => {
|
|
||||||
if (status >= 200 && status < 300) return "bi:check-circle-fill";
|
|
||||||
return "bi:x-circle-fill";
|
|
||||||
};
|
|
||||||
|
|
||||||
// lifecycle
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
hljs.registerLanguage("json", json);
|
|
||||||
hljs.registerLanguage("xml", xml);
|
|
||||||
|
|
||||||
hljs.highlightAll();
|
|
||||||
});
|
|
||||||
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div class="bg-neutral-900 w-full min-h-svh py-32">
|
|
||||||
<div class="fixed top-10 right-1/2 translate-x-1/2 flex-center" v-if="isFetching">
|
|
||||||
<Icon
|
|
||||||
name="svg-spinners:180-ring-with-bg"
|
|
||||||
class="size-12 mb-1 **:fill-neutral-500"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div class="w-full container flex flex-col gap-8">
|
|
||||||
<div
|
|
||||||
v-for="(log,index) in serverLogs"
|
|
||||||
:key="index"
|
|
||||||
class="border-2 p-5 rounded-xl log-item-animation"
|
|
||||||
:class="{
|
|
||||||
'bg-success-950/30 border-success-800' : log.status >= 200 && log.status < 300,
|
|
||||||
'bg-danger-950/30 border-danger-800' : log.status >= 400 && log.status < 600,
|
|
||||||
}"
|
|
||||||
>
|
|
||||||
<div class="flex items-center gap-4 mt-4">
|
|
||||||
<Icon
|
|
||||||
:name="logIcon(log.status)"
|
|
||||||
class="size-8 mb-1"
|
|
||||||
:class="{
|
|
||||||
'**:fill-success-500' : log.status >= 200 && log.status < 300,
|
|
||||||
'**:fill-danger-500' : log.status >= 400 && log.status < 600,
|
|
||||||
}"
|
|
||||||
/>
|
|
||||||
<h3 class="text-white font-medium text-3xl">
|
|
||||||
{{ log.url }}
|
|
||||||
</h3>
|
|
||||||
</div>
|
|
||||||
<div class="flex items-center gap-2 py-8">
|
|
||||||
<div
|
|
||||||
class="px-3 pb-1 pt-1.5 rounded-lg uppercase font-bold text-white"
|
|
||||||
:class="{
|
|
||||||
'bg-success-500' : log.status >= 200 && log.status < 300,
|
|
||||||
'bg-danger-500' : log.status >= 400 && log.status < 600,
|
|
||||||
}"
|
|
||||||
>
|
|
||||||
{{ log.method }}
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
class="px-3 pb-1 pt-1.5 rounded-lg font-bold text-white"
|
|
||||||
:class="{
|
|
||||||
'bg-success-500' : log.status >= 200 && log.status < 300,
|
|
||||||
'bg-danger-500' : log.status >= 400 && log.status < 600,
|
|
||||||
}"
|
|
||||||
>
|
|
||||||
{{ log.status }}
|
|
||||||
</div>
|
|
||||||
<LogDate :date="log.date" />
|
|
||||||
</div>
|
|
||||||
<details class="text-white">
|
|
||||||
<summary class="cursor-pointer select-none">Details :</summary>
|
|
||||||
<div class="flex flex-col gap-2 mt-2 ml-4">
|
|
||||||
<details
|
|
||||||
v-if="log.response && typeof log.response === 'string' && (log.response.startsWith('<!DOCTYPE html>') || log.response.startsWith('<html>'))"
|
|
||||||
class="text-white"
|
|
||||||
>
|
|
||||||
<summary class="cursor-pointer select-none">Preview :</summary>
|
|
||||||
<iframe class="w-full h-[500px] bg-white" :srcdoc="log.response"></iframe>
|
|
||||||
</details>
|
|
||||||
<details v-if="log.response" class="text-white">
|
|
||||||
<summary class="cursor-pointer select-none">Response :</summary>
|
|
||||||
<pre style="tab-size: 2">
|
|
||||||
<code class="whitespace-pre-wrap">
|
|
||||||
{{ String(log.response) }}
|
|
||||||
</code>
|
|
||||||
</pre>
|
|
||||||
</details>
|
|
||||||
<details class="text-white">
|
|
||||||
<summary class="cursor-pointer select-none">Req Headers :</summary>
|
|
||||||
<pre style="tab-size: 2">
|
|
||||||
<code class="whitespace-pre-line">
|
|
||||||
{{ log.requestHeaders }}
|
|
||||||
</code>
|
|
||||||
</pre>
|
|
||||||
</details>
|
|
||||||
<details class="text-white">
|
|
||||||
<summary class="cursor-pointer select-none">Res Headers :</summary>
|
|
||||||
<pre style="tab-size: 2">
|
|
||||||
<code class="whitespace-pre-line">
|
|
||||||
{{ log.responseHeaders }}
|
|
||||||
</code>
|
|
||||||
</pre>
|
|
||||||
</details>
|
|
||||||
<details v-if="log.payload" class="text-white">
|
|
||||||
<summary class="cursor-pointer select-none">Payload :</summary>
|
|
||||||
<pre style="tab-size: 2">
|
|
||||||
<code class="whitespace-pre-line">
|
|
||||||
{{ log.payload }}
|
|
||||||
</code>
|
|
||||||
</pre>
|
|
||||||
</details>
|
|
||||||
</div>
|
|
||||||
</details>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
|
|
||||||
.log-item-animation {
|
|
||||||
animation-name: log-fade-in;
|
|
||||||
animation-duration: 0.5s;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes log-fade-in {
|
|
||||||
from {
|
|
||||||
opacity: 0;
|
|
||||||
scale: 0.8;
|
|
||||||
}
|
|
||||||
to {
|
|
||||||
opacity: 1;
|
|
||||||
scale: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
</style>
|
|
||||||
@@ -7,10 +7,10 @@ import usePersianDate from "~/composables/global/usePersianDate";
|
|||||||
// meta
|
// meta
|
||||||
|
|
||||||
useSeoMeta({
|
useSeoMeta({
|
||||||
title: "نتیجه تراکنش",
|
title: "نتیجه تراکنش",
|
||||||
description : "",
|
description: "",
|
||||||
keywords : ""
|
keywords: "",
|
||||||
})
|
});
|
||||||
|
|
||||||
definePageMeta({
|
definePageMeta({
|
||||||
layout: "none",
|
layout: "none",
|
||||||
@@ -91,6 +91,8 @@ const statusTitle = computed(() => {
|
|||||||
class="aspect-square w-[220px] md:w-[280px] lg:w-[320px] absolute -top-[70px] md:-top-[110px] lg:-top-[138px] left-1/2 -translate-x-1/2 z-10 [filter:_drop-shadow(0px_4px_20px_rgba(0, 0, 0, 0.15))]"
|
class="aspect-square w-[220px] md:w-[280px] lg:w-[320px] absolute -top-[70px] md:-top-[110px] lg:-top-[138px] left-1/2 -translate-x-1/2 z-10 [filter:_drop-shadow(0px_4px_20px_rgba(0, 0, 0, 0.15))]"
|
||||||
src="/img/heymlz/heymlz-seat.gif"
|
src="/img/heymlz/heymlz-seat.gif"
|
||||||
:class="statusVariants.hue_deg"
|
:class="statusVariants.hue_deg"
|
||||||
|
loading="lazy"
|
||||||
|
fetch-priority="low"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
import VueScrollTo from "vue-scrollto";
|
|
||||||
|
|
||||||
export default defineNuxtPlugin(() => {
|
|
||||||
return {
|
|
||||||
provide: {
|
|
||||||
vScrollTo: VueScrollTo,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
});
|
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 53 KiB |
Reference in New Issue
Block a user