merge with front and test clear cache build

This commit is contained in:
Parsa Nazer
2025-03-08 20:08:31 +03:30
38 changed files with 208 additions and 173 deletions
+7 -9
View File
@@ -265,32 +265,30 @@
/* CONTAINER */
@utility container {
@apply mx-auto;
padding-inline: 1.5rem;
max-width: 1380px;
@apply mx-auto px-6;
@screen 2xs {
padding-inline: 1rem;
@apply px-4;
}
@screen xs {
padding-inline: 1rem;
@apply px-4;
}
@screen sm {
padding-inline: 1rem;
@apply px-4;
}
@screen md {
padding-inline: 2rem;
@apply px-8;
}
@screen lg {
padding-inline: 3rem;
@apply px-12;
}
@screen xl {
padding-inline: 5rem;
@apply px-20;
}
}
+7 -15
View File
@@ -37,28 +37,20 @@ const { colorObject } = useImageColor(`#category-image-${id.value}`);
/>
<div
class="absolute z-20 bottom-0 p-4 md:p-6 flex items-end justify-between w-full"
class="absolute z-20 bottom-0 p-4 md:p-6 flex items-center justify-between w-full"
>
<div
:class="
colorObject?.isLight && !darkLayer
? 'text-black'
: 'text-white'
"
class="flex flex-col gap-2"
:class="colorObject?.isLight && !darkLayer ? 'text-black': 'text-white'"
class="typo-sub-h-sm md:typo-sub-h-md"
>
<div class="typo-sub-h-sm md:typo-sub-h-md">
{{ category }}
<span class="typo-p-xs -translate-y-1 inline-block mr-1">
{{ count }}
</span>
</div>
<span class="typo-p-sm md:typo-p-md">محصولات ما را مشاهده کنید</span>
{{ category }}
</div>
<Icon
name="ci:arrow-left"
class="mb-1 size-5 md:size-6"
class="size-5 md:size-6"
:class="
colorObject?.isLight && !darkLayer
? '**:stroke-black'
+3 -3
View File
@@ -1,7 +1,9 @@
<script setup lang="ts">
// imports
import { NAV_LINKS } from "~/constants";
</script>
<template>
@@ -125,6 +127,4 @@ import { NAV_LINKS } from "~/constants";
</div>
</div>
</footer>
</template>
<style scoped></style>
</template>
@@ -11,35 +11,35 @@ type Highlight = {
const highlights = ref<Highlight[]>([
{
icon: "ci:headset",
icon: "/img/footer-support.svg",
title: "خدمات مشتری",
description: "پشتیبانی استثنایی، راه‌حل‌های پایدار برای شما عزیزان"
description: "پشتیبانی استثنایی، راه‌حل‌های پایدار برای شما"
},
{
icon: "ci:delivery",
icon: "/img/footer-send.svg",
title: "ارسال سریع و رایگان",
description: "ارسال رایگان برای سفارش‌های بالای ۱۵۰ دلار و خورده"
description: "ارسال رایگان برای سفارش‌های بالای ۱۵۰ دلار"
},
{
icon: "ci:users",
icon: "/img/footer-share.svg",
title: "معرفی به دوستان",
description: "دوستان خود را معرفی کنید و هر دو ۱۵٪ تخفیف بگیرید"
description: "ما را به دوستان خود معرفی کنید"
},
{
icon: "ci:shield-done",
icon: "/img/footer-security.svg",
title: "پرداخت امن",
description: "اطلاعات پرداخت شما به‌صورت امن پردازش می‌شود"
description: "پرداخت شما به‌صورت امن پردازش می‌شود"
}
]);
</script>
<template>
<section class="w-full border-t-[0.5px] border-slate-200 mt-20">
<section class="w-full border-t-[0.5px] border-slate-200">
<div class="w-full flex-center py-[5rem] gap-[1.25rem] container">
<template v-for="(highlight, index) in highlights" :key="index">
<div class="flex flex-col-center gap-[.75rem] w-1/4 px-5">
<Icon :name="highlight.icon" size="32px" />
<img :src="highlight.icon" class="size-[90px]" alt="" />
<div class="w-full flex-col-center gap-[.25rem]">
<span class="typo-sub-h-md text-black text-center">
@@ -106,7 +106,6 @@ const onSwiper = (swiper: SwiperClass) => {
>
<ProductCard
:id="product.id"
brand="برند محصول"
:title="product.name"
:picture="product.variants[0].images[0].image"
:colors="product.colors"
@@ -1,33 +1,33 @@
<script lang="ts">
<script lang="ts" setup>
// types
type Props = {
rate: number
}
// props
defineProps<Props>();
</script>
<template>
<div class="flex items-center gap-2">
<span class="typo-p-sm">
{{ rate }}
</span>
<div class="flex items-center gap-1">
<Icon
v-for="i in Math.round(5 - rate)"
name="ci:star-solid"
class="size-4.5 **:fill-yellow-500"
/>
<Icon
name="ci:star-solid"
class="size-4.5 **:fill-yellow-500"
/>
<Icon
name="ci:star-solid"
class="size-4.5 **:fill-yellow-500"
/>
<Icon
name="ci:star-solid"
class="size-4.5 **:fill-yellow-500"
class="size-4.5 **:fill-slate-300"
/>
<Icon
v-for="i in Math.round(rate)"
name="ci:star-solid"
class="size-4.5 **:fill-yellow-500"
/>
</div>
<span class="typo-p-sm">
5.0
</span>
</div>
</template>
@@ -11,7 +11,6 @@ import { useImageColor } from "~/composables/global/useImageColor";
type Props = {
id: number,
brand: string;
title: string;
colors: string[];
price: string;
@@ -67,9 +66,9 @@ const { colorObject } = useImageColor(`#product-image-${id.value}`);
>
<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-p-sm md:typo-p-md !font-medium">-->
<!-- {{ brand }}-->
<!-- </span>-->
<span class="typo-sub-h-md md:typo-sub-h-lg">
{{ title }}
</span>
+11 -10
View File
@@ -57,11 +57,6 @@ watch(() => [shouldPauseVideos.value, swiper_instance.value?.realIndex], () => {
// lifecycle
const initializeGsapAnimation = () => {
gsap.to("#header-navbar", {
background: "transparent",
filter: "invert(100%)"
});
gsapTimeline
.fromTo(".header-slider-item", {
borderRadius: 0,
@@ -129,6 +124,10 @@ onMounted(() => {
setTimeout(() => {
if (window.innerWidth > 768) {
gsap.to("#header-navbar", {
background: "transparent",
filter: "invert(100%)"
});
scrollTrigger.enable();
} else {
resetTimelineForMobile();
@@ -138,6 +137,10 @@ onMounted(() => {
window.addEventListener("resize", () => {
if (window.innerWidth > 768) {
gsap.to("#header-navbar", {
background: "transparent",
filter: "invert(100%)"
});
scrollTrigger.enable();
} else {
resetTimelineForMobile();
@@ -148,8 +151,8 @@ onMounted(() => {
});
onUnmounted(() => {
gsapTimeline.progress(1).pause();
gsapTimeline.kill();
resetTimelineForMobile();
scrollTrigger.disable();
});
</script>
@@ -209,8 +212,7 @@ onUnmounted(() => {
<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" />
<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"
@@ -252,7 +254,6 @@ onUnmounted(() => {
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"
@click="swiper_instance?.slideTo(index)"
>
</div>
</div>
+13 -7
View File
@@ -46,7 +46,7 @@ watch(
</script>
<template>
<div class="container max-w-[1000px]">
<div class="container">
<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">
@@ -55,7 +55,7 @@ watch(
</div>
<div
ref="previewContainerEl"
class="rounded-200 overflow-hidden h-[60svh] md:h-[70svh] relative"
class="rounded-200 overflow-hidden h-[70svh] md:h-[80svh] relative"
>
<Transition name="fade">
<img
@@ -93,10 +93,10 @@ watch(
:style="{
left: `${clipPathPercent}%`,
}"
ref="draggableEl"
class="select-none w-2 h-full bg-black absolute left-0 flex items-center justify-center"
>
<div
ref="draggableEl"
class="cursor-grab hover:scale-115 transition-transform rounded-full absolute bg-black size-11 flex items-center justify-center"
>
<Icon
@@ -115,17 +115,23 @@ watch(
<span class="typo-p-sm md:typo-p-md">
{{ homeData!.difreance_section.description1 }}
</span>
<span class="typo-h-6 md:typo-h-5 lg:typo-h-3">
<NuxtLink
:to="homeData!.difreance_section.link1"
class="typo-h-6 md:typo-h-5 lg:typo-h-3"
>
{{ homeData!.difreance_section.title1 }}
</span>
</NuxtLink>
</div>
<div class="flex flex-col gap-2 text-black">
<span class="typo-p-sm md:typo-p-md text-end">
{{ homeData!.difreance_section.description2 }}
</span>
<span class="typo-h-6 md:typo-h-5 lg:typo-h-3 text-end">
<NuxtLink
:to="homeData!.difreance_section.link2"
class="typo-h-6 md:typo-h-5 lg:typo-h-3 text-end"
>
{{ homeData!.difreance_section.title2 }}
</span>
</NuxtLink>
</div>
</div>
</div>
@@ -91,14 +91,13 @@ onUnmounted(() => {
id="products-showcase-container"
class="mt-80 mb-40 perspective-midrange w-full h-[125svh] bg-black flex items-center justify-center"
>
<div
<NuxtLink
v-for="slide in homeData!.show_case_slider"
:key="slide.id"
:to="slide.link"
class="showcase-slide origin-bottom absolute size-full bg-transparent flex items-center justify-center"
>
<div
class="blur-[150px] w-[400px] sm:w-[600px] h-[80px] sm:h-[80px] bg-white/70 absolute z-10"
/>
<img
class="w-[280px] xs:w-[350px] lg:w-[500px] xl:w-[650px] z-20 mb-30 sm:mb-20 lg:mb-30"
:src="slide.image"
@@ -115,6 +114,6 @@ onUnmounted(() => {
{{ slide.description }}
</p>
</div>
</div>
</NuxtLink>
</div>
</template>
-2
View File
@@ -5,5 +5,3 @@
<NuxtPage />
</main>
</template>
<style scoped></style>
+128 -89
View File
@@ -1,4 +1,5 @@
<script lang="ts" setup>
// import
import { helpers, required } from "@vuelidate/validators";
@@ -20,11 +21,13 @@ type LoginInfo = {
// meta
definePageMeta({
middleware: ["check-is-not-logged-in"],
middleware: ["check-is-not-logged-in"]
});
// state
const { $gsap: gsap } = useNuxtApp();
const { addToast } = useToast();
const { updateToken, updateRefreshToken } = useAuth();
@@ -41,13 +44,13 @@ const formRules = computed(() => {
phoneValidator: helpers.withMessage(
"شماره تلفن وارد شده معتبر نمی باشد",
helpers.regex(/^[1-9][0-9]{9}$/)
),
},
)
}
};
});
const loginInfo = ref<LoginInfo>({
phone: "",
phone: ""
});
const formValidator$ = useVuelidate(formRules, loginInfo);
@@ -56,16 +59,16 @@ const {
timer: otpBlockerTimePassed,
start: startOtpBlocker,
reset: resetOtpBlocker,
isPending: isResendOtpBlocked,
isPending: isResendOtpBlocked
} = useTimer({
duration: 5000,
duration: 5000
});
const { mutateAsync: sendOtp, isPending: sendOtpIsPending } = useOtp();
const {
mutateAsync: signIn,
isPending: signInIsPending,
status: signInStatus,
status: signInStatus
} = useSignIn();
// computed
@@ -74,14 +77,14 @@ const sendOtpHandler = async () => {
if (!sendOtpIsPending.value) {
try {
await sendOtp({
phone: `0${loginInfo.value.phone}`,
phone: `0${loginInfo.value.phone}`
});
addToast({
message: "کد برای شما ارسال شد",
options: {
status: "success",
},
status: "success"
}
});
showOtp.value = true;
@@ -89,8 +92,8 @@ const sendOtpHandler = async () => {
addToast({
message: "مشکلی پیش آمده",
options: {
status: "error",
},
status: "error"
}
});
}
}
@@ -107,7 +110,7 @@ const handleLogin = async () => {
try {
const response = await signIn({
otp: otpCode.value.join(""),
phone: `0${loginInfo.value.phone}`,
phone: `0${loginInfo.value.phone}`
});
updateToken(response.access);
@@ -118,8 +121,8 @@ const handleLogin = async () => {
addToast({
message: "با موفقیت وارد شدید",
options: {
status: "success",
},
status: "success"
}
});
navigateTo("/");
@@ -146,93 +149,129 @@ const resetForm = () => {
otpCode.value = [];
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>
<div
class="container min-h-[700px] flex flex-col items-center justify-center"
>
<h1 class="typo-hero-2">فرم ورود</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>
<div class="flex h-svh items-center relative">
<div
class="bg-[url(/img/pattern-1.png)] -z-10 size-full absolute opacity-70"
:style="{
backgroundSize: 150,
mask: 'linear-gradient(to bottom, black 0%, rgba(0,0,0,0.3) 80%)'
}"
/>
<div class="flex items-center justify-center flex-col size-full">
<OtpInput
v-else
v-model="otpCode"
:status="
signInStatus === 'success'
? 'success'
: signInStatus === 'error'
? 'error'
: 'idle'
"
:disabled="signInIsPending || sendOtpIsPending"
:autofocus="true"
@complete="handleLogin"
<img
id="heylmz-eyes"
class="aspect-square w-[300px] translate-y-[100px]"
src="/img/heymlz-seat.gif"
alt=""
/>
<Button
data-testid="send-otp-code-button"
v-if="!showOtp"
class="rounded-full w-full mt-4"
type="submit"
@click="handleLogin"
:loading="sendOtpIsPending"
:disabled="sendOtpIsPending"
<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"
>
ارسال کد
</Button>
<h1 class="typo-hero-2 mt-8">فرم ورود</h1>
<div v-else class="flex items-center w-full gap-4 mt-4">
<Button
class="rounded-full w-full mt-4"
type="button"
variant="secondary"
@click="resetForm"
:disabled="signInIsPending || sendOtpIsPending"
>
تغییر شماره
</Button>
<Button
class="rounded-full w-full mt-4"
type="submit"
@click="resendOtp"
:loading="signInIsPending || sendOtpIsPending"
:disabled="
<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>
<OtpInput
v-else
v-model="otpCode"
:status="
signInStatus === 'success'
? 'success'
: signInStatus === 'error'
? 'error'
: 'idle'
"
:disabled="signInIsPending || sendOtpIsPending"
:autofocus="true"
@complete="handleLogin"
/>
<Button
data-testid="send-otp-code-button"
v-if="!showOtp"
class="rounded-full w-full mt-4"
type="submit"
@click="handleLogin"
:loading="sendOtpIsPending"
:disabled="sendOtpIsPending"
>
ارسال کد
</Button>
<div v-else class="flex items-center w-full gap-4 mt-4">
<Button
class="rounded-full w-full mt-4"
type="button"
variant="secondary"
@click="resetForm"
:disabled="signInIsPending || sendOtpIsPending"
>
تغییر شماره
</Button>
<Button
class="rounded-full w-full mt-4"
type="submit"
@click="resendOtp"
:loading="signInIsPending || sendOtpIsPending"
:disabled="
signInIsPending ||
isResendOtpBlocked ||
sendOtpIsPending
"
>
ارسال مجدد کد
{{ isResendOtpBlocked ? otpBlockerTimePassed : "" }}
</Button>
</div>
>
ارسال مجدد کد
{{ isResendOtpBlocked ? otpBlockerTimePassed : "" }}
</Button>
</div>
<div class="flex items-center gap-2 justify-center mt-6">
<span> بازگشت به فروشگاه </span>
<Icon name="ci:left-rotation" size="24" />
<NuxtLink to="/" class="flex items-center gap-2 justify-center mt-6">
<span> بازگشت به فروشگاه </span>
<Icon name="ci:left-rotation" size="24" />
</NuxtLink>
</form>
</div>
</form>
</div>
</div>
</template>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 806 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 606 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 917 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 16 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 21 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 15 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 237 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 261 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 344 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 421 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 648 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 206 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 325 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 MiB

+1 -1
View File
@@ -5,7 +5,7 @@ precacheAndRoute(self.__WB_MANIFEST);
// Version
const VERSION = "1.0.911";
const VERSION = "1.0.9112";
// Service Worker Installation
self.addEventListener("install", (event) => {
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.