This commit is contained in:
Mamalizz
2025-02-21 23:14:10 +03:30
63 changed files with 1464 additions and 364 deletions
+1 -1
View File
@@ -12,7 +12,7 @@ const {} = toRefs(props);
</script>
<template>
<div class="relative w-full flex flex-col justify-center h-[350px]">
<div class="relative w-full flex flex-col justify-center min-h-[700px] h-[80svh]">
<div class="-rotate-z-2 z-20">
<div
class="bg-warning-500 flex pr-20 gap-20 py-2 w-max animate-marquee-reverse"
+3 -3
View File
@@ -3,7 +3,7 @@
// types
type Props = {
selected ?: boolean;
selected?: boolean;
}
// props
@@ -14,7 +14,7 @@ defineProps<Props>();
<template>
<div
class="size-[25px] rounded-full shadow-black/30 shadow-inner"
:class="selected ? 'ring-black' : 'ring-transparent'"
class="size-[25px] rounded-full transition-all ring-2 ring-offset-4 shadow-black/30 shadow-inner"
:class="selected ? 'ring-blue-500' : 'ring-transparent'"
/>
</template>
@@ -21,7 +21,7 @@ nuxtApp.hook("page:finish", () => {
<Transition name="fade">
<div
v-if="isLoading"
class="h-[20px] flex items-center justify-center bg-black w-full left-0 top-0 fixed z-100"
class="h-[20px] flex items-center justify-center bg-black w-full left-0 top-0 fixed z-9999"
>
<div class="absolute progress-indicator w-1/3 bg-white h-1 rounded-full"></div>
</div>
@@ -0,0 +1,88 @@
<script lang="ts" setup>
// state
const { $gsap: gsap } = useNuxtApp();
// lifecycle
onMounted(() => {
const timeline = gsap.timeline();
timeline
.to("#loading-overlay", {
scale: 1
})
.to("#loading-overlay", {
scale: 0.8,
opacity: 0,
delay: 5
})
.to("#loading-overlay", {
opacity: 0,
y: "20%"
});
});
</script>
<template>
<div id="loading-overlay" class="fixed inset-0 size-full z-9999 flex-center bg-black">
<img id="loading-overlay-image" src="/video/loading-2.gif" class="opacity-0 scale-70 absolute z-20" alt="" />
<div
id="loading-overlay-gradient"
class="opacity-0 scale-x-0 w-[1000px] h-[70px] bg-linear-to-r from-blue-500 via-violet-500 to-purple-500 blur-[150px] rounded-[100px]"
/>
</div>
</template>
<style>
#loading-overlay-image {
animation-name: loading-overlay-image-animation;
animation-duration: 1s;
animation-delay: 0.75s;
animation-fill-mode: forwards;
}
#loading-overlay-gradient {
animation: 1.5s normal 0.5s 1 forwards loading-overlay-gradient-animation,
1s ease-in-out 2s infinite alternate-reverse loading-overlay-gradient-pules-animation;
}
@keyframes loading-overlay-image-animation {
from {
opacity: 0;
scale: 0.7;
}
to {
opacity: 1;
scale: 1;
}
}
@keyframes loading-overlay-gradient-animation {
from {
opacity: 0;
scale: 0 1 1;
}
to {
opacity: 0.9;
scale: 1 1 1;
}
}
@keyframes loading-overlay-gradient-pules-animation {
from {
opacity: 0.8;
scale: 0.8 1 1;
}
to {
opacity: 0.9;
scale: 1 1 1;
}
}
</style>
@@ -91,9 +91,9 @@ const onSwiper = (swiper: SwiperClass) => {
:id="product.id"
brand="برند محصول"
:title="product.name"
:picture="product.image1"
:colors="['white', 'black']"
:price="product.price"
:picture="product.variants[0].images[0].image"
:colors="product.variants.map(v => v.color)"
:price="product.variants[0].price"
:rate="product.rating"
:dark-layer="true"
/>
@@ -10,49 +10,58 @@ type Props = {
// props
const props = defineProps<Props>();
const { modelValue } = toRefs(props);
const { modelValue, max } = toRefs(props);
// state
const timer = ref<NodeJS.Timeout | null>(null);
// emit
const emit = defineEmits(["update:modelValue"]);
// state
// computed
const currentQuantity = ref(modelValue.value);
const currentQuantity = computed({
get: () => modelValue.value ?? 0,
set: (value: number) => {
if (timer.value) clearTimeout(timer.value);
timer.value = setTimeout(() => {
emit("update:modelValue", value);
}, 50);
}
});
// methods
const onInput = (e: any) => {
currentQuantity.value = Number(e.target.value);
const value = Number(e.target.value);
if (value > 0 && value <= max.value) {
currentQuantity.value = value;
} else {
currentQuantity.value = 1;
}
};
// watch
watch(() => currentQuantity.value, (newValue) => {
emit("update:modelValue", newValue);
});
</script>
<template>
<div class="">
<NumberFieldRoot
class="rounded-full border-slate-200 border-[1.5px] flex items-center bg-white gap-4 p-4"
v-model="currentQuantity"
:min="1"
:max="max"
>
<NumberFieldIncrement class="cursor-pointer">
<Icon name="ci:plus" class="**:stroke-slate-500 size-5" />
</NumberFieldIncrement>
<NumberFieldInput
@input="onInput"
class="field-sizing-content bg-transparent outline-none typo-label-md text-black"
/>
<NumberFieldDecrement class="cursor-pointer">
<Icon name="ci:minus" class="**:stroke-slate-500 size-5" />
</NumberFieldDecrement>
</NumberFieldRoot>
</div>
<NumberFieldRoot
class="rounded-full border-slate-200 border-[1.5px] flex items-center bg-white gap-4 p-4"
v-model="currentQuantity"
:min="1"
:max="max"
>
<NumberFieldIncrement class="cursor-pointer">
<Icon name="ci:plus" class="**:stroke-slate-500 size-5" />
</NumberFieldIncrement>
<NumberFieldInput
@input="onInput"
class="field-sizing-content bg-transparent outline-none typo-label-md text-black"
/>
<NumberFieldDecrement class="cursor-pointer">
<Icon name="ci:minus" class="**:stroke-slate-500 size-5" />
</NumberFieldDecrement>
</NumberFieldRoot>
</template>
@@ -15,12 +15,12 @@ defineProps<Props>();
<template>
<div class="flex flex-col gap-2 w-full">
<p class="typo-p-sm text-slate-500">
سریع باش فقط
<span class="text-black">
<p class="typo-p-md text-slate-500">
تعداد
<span class="text-black font-bold">
{{ maxQuantity }}
</span>
عدد از این محصول باقی مانده
عدد از این محصول موجود است
</p>
<div class="h-2 rounded-full relative bg-slate-200 w-full">
<div
@@ -4,10 +4,7 @@
type Props = {
selectedSlide: number;
slides: {
id: number;
picture: string;
}[]
slides: ProductImage[]
}
// props
@@ -41,8 +38,8 @@ const changeSlide = (id: number) => {
<img
:key="selectedSlideDetail.id"
class="size-full absolute object-contain"
:src="selectedSlideDetail.picture"
:alt="String(selectedSlideDetail.id)"
:src="selectedSlideDetail.image"
:alt="selectedSlideDetail.name"
/>
</Transition>
</div>
@@ -56,7 +53,7 @@ const changeSlide = (id: number) => {
>
<img
class="absolute object-cover size-full"
:src="slide.picture"
:src="slide.image"
:alt="String(slide.id)"
/>
</div>
@@ -1,16 +1,30 @@
<script lang="ts" setup>
// provide / inject
import type { ProductVariantProvideType } from "~/pages/product/[id].vue";
const { selectedVariant } = inject("productVariant") as ProductVariantProvideType;
</script>
<template>
<div class="w-full flex flex-col">
<AccordionRoot
class="w-full last:border-b last:border-slate-200"
default-value="item-1"
:default-value="'item' + selectedVariant.details[0].detail_category"
type="single"
:collapsible="true"
>
<AccordionItem value="item-1" class="overflow-hidden">
<AccordionItem
v-for="detailItem in selectedVariant.details"
:value="'item' + detailItem.detail_category"
class="overflow-hidden"
>
<AccordionHeader
class="border-t border-slate-200 py-[1.5rem] flex justify-between items-center"
>
<span class="typo-sub-h-md text-black">مشخصات</span>
<span class="typo-sub-h-md text-black">{{ detailItem.detail_category }}</span>
<AccordionTrigger class="group">
<Icon
name="ci:plus"
@@ -26,97 +40,20 @@
class="w-full grid grid-cols-2 gap-y-[1.5rem] gap-x-[1rem]"
>
<div
v-for="i in 4"
v-for="item in detailItem.detail"
class="flex flex-col gap-y-[1.5rem]"
>
<span
class="typo-sub-h-lg text-black w-full pt-[1.5rem]"
>صفحه نمایش</span
>
{{ item.title }}
</span>
<ul class="list-disc w-full ps-5">
<li class="text-slate-500 typo-p-md">
روشنایی :3000mn
</li>
<li class="text-slate-500 typo-p-md">
روشنایی :3000mn
</li>
</ul>
</div>
</div>
</AccordionContent>
</AccordionItem>
<AccordionItem value="item-2" class="overflow-hidden">
<AccordionHeader
class="border-t border-slate-200 py-[1.5rem] flex justify-between items-center"
>
<span class="typo-sub-h-md text-black">مشخصات</span>
<AccordionTrigger class="group">
<Icon
name="ci:plus"
size="24"
class="group-data-[state=open]:rotate-45 transition-transform"
/>
</AccordionTrigger>
</AccordionHeader>
<AccordionContent
class="data-[state=open]:animate-slide-down pb-[1.5rem] data-[state=closed]:animate-slide-up overflow-hidden"
>
<div
class="w-full grid grid-cols-2 gap-y-[1.5rem] gap-x-[1rem]"
>
<div
v-for="i in 4"
class="flex flex-col gap-y-[1.5rem]"
>
<span
class="typo-sub-h-lg text-black w-full pt-[1.5rem]"
>صفحه نمایش</span
>
<ul class="list-disc w-full ps-5">
<li class="text-slate-500 typo-p-md">
روشنایی :3000mn
</li>
<li class="text-slate-500 typo-p-md">
روشنایی :3000mn
</li>
</ul>
</div>
</div>
</AccordionContent>
</AccordionItem>
<AccordionItem value="item-3" class="overflow-hidden">
<AccordionHeader
class="border-t border-slate-200 py-[1.5rem] flex justify-between items-center"
>
<span class="typo-sub-h-md text-black">مشخصات</span>
<AccordionTrigger class="group">
<Icon
name="ci:plus"
size="24"
class="group-data-[state=open]:rotate-45 transition-transform"
/>
</AccordionTrigger>
</AccordionHeader>
<AccordionContent
class="data-[state=open]:animate-slide-down pb-[1.5rem] data-[state=closed]:animate-slide-up overflow-hidden"
>
<div
class="w-full grid grid-cols-2 gap-y-[1.5rem] gap-x-[1rem]"
>
<div
v-for="i in 4"
class="flex flex-col gap-y-[1.5rem]"
>
<span
class="typo-sub-h-lg text-black w-full pt-[1.5rem]"
>صفحه نمایش</span
>
<ul class="list-disc w-full ps-5">
<li class="text-slate-500 typo-p-md">
روشنایی :3000mn
</li>
<li class="text-slate-500 typo-p-md">
روشنایی :3000mn
<li
v-for="detail in [ item.detail_text1, item.detail_text2, item.detail_text3, item.detail_text4 ]"
class="text-slate-500 typo-p-md"
>
{{ detail }}
</li>
</ul>
</div>
@@ -125,8 +62,4 @@
</AccordionItem>
</AccordionRoot>
</div>
</template>
<script setup lang="ts"></script>
<style scoped></style>
</template>
@@ -22,9 +22,12 @@ const { picture, price, title, color } = toRefs(props);
<div class="relative size-[100px] rounded-100 overflow-hidden border-[0.5px] border-slate-200">
<img :src="picture" :alt="title" class="object-cover absolute" />
</div>
<div class="flex flex-col gap-1">
<div class="flex flex-col gap-1.5">
<span class="typo-sub-h-md text-black">{{ title }}</span>
<span class="typo-p-sm text-slate-500">{{ color }}</span>
<div class="flex items-center gap-2">
<span class="typo-p-sm text-slate-500">رنگ</span>
<ColorCircle class="!size-5" :style="{backgroundColor: color}" />
</div>
<span class="typo-p-md text-black">{{ price }}</span>
</div>
</div>