This commit is contained in:
marzban-dev
2025-03-13 20:32:38 +03:30
parent 49cdcc28c0
commit d78a26ea08
4 changed files with 110 additions and 87 deletions
@@ -24,7 +24,7 @@ const { mutateAsync: createComment, isPending: isCreateCommentPending } =
const submitComment = async () => { const submitComment = async () => {
if (userComment.value.length > 3) { if (userComment.value.length > 3) {
await createComment({ await createComment({
content: userComment.value, content: userComment.value
}); });
userComment.value = ""; userComment.value = "";
@@ -36,11 +36,11 @@ const submitComment = async () => {
<template> <template>
<section class="bg-slate-50"> <section class="bg-slate-50">
<div class="flex relative gap-8 my-42 container"> <div class="flex relative gap-8 my-42 container max-lg:flex-col">
<div <div
class="sticky top-0 flex flex-col gap-6 min-w-[400px] max-h-min bg-white p-8 rounded-xl border-[0.5px] border-slate-200" class="sticky top-0 flex flex-col gap-6 lg:min-w-[400px] h-fit bg-white p-8 rounded-xl border-[0.5px] border-slate-200"
> >
<h3 class="typo-h-3">نظرات کاربران</h3> <h3 class="typo-h-6 max-sm:text-xl md:typo-h-5 lg:typo-h-4">نظرات کاربران</h3>
<div class="flex flex-col gap-2"> <div class="flex flex-col gap-2">
<Rating :rate="2" /> <Rating :rate="2" />
<span class="typo-p-sm"> <span class="typo-p-sm">
@@ -9,21 +9,21 @@ const { selectedVariant } = inject("productVariant") as ProductVariantProvideTyp
</script> </script>
<template> <template>
<section class="w-full p-[5rem] flex flex-col gap-y-[1.5rem]"> <section class="w-full container py-20 flex flex-col gap-y-[1.5rem]">
<div class="w-full flex"> <div class="w-full flex">
<span class="text-black typo-h-3"> جزيات محصول </span> <span class="text-black max-lg:hidden typo-h-4 mb-4"> جزيات محصول </span>
</div> </div>
<div class="w-full flex items-start justify-between gap-[3rem]"> <div class="w-full flex items-start justify-between gap-[3rem] max-lg:flex-col-reverse">
<div class="w-8/12"> <div class="flex-1 w-full">
<Accordion /> <Accordion />
</div> </div>
<div class="w-4/12"> <div class="w-full lg:w-[450px] xl:w-[600px]">
<div <div
class="w-full bg-slate-50 rounded-xl flex-col-center 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>داخل جعبه چیه؟</span> <span class="typo-h-6 mb-8">داخل جعبه چیه؟</span>
<div <div
class="w-full grid grid-cols-2 gap-y-[1.5rem] 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"
+89 -68
View File
@@ -1,4 +1,5 @@
<script lang="ts" setup> <script lang="ts" setup>
// import // import
import useGetProduct from "~/composables/api/product/useGetProduct"; import useGetProduct from "~/composables/api/product/useGetProduct";
@@ -20,9 +21,7 @@ const selectedColor = ref(product.value!.colors[0]);
// provide / inject // provide / inject
const { selectedVariant, changeSelectedVariant } = inject( const { selectedVariant, changeSelectedVariant } = inject("productVariant") as ProductVariantProvideType;
"productVariant"
) as ProductVariantProvideType;
// computed // computed
@@ -32,79 +31,105 @@ const sanitizedProductDescription = computed(() => {
// watch // watch
watch( watch(() => selectedVariantId.value, (newId) => {
() => selectedVariantId.value, const newVariant = product.value!.variants.find(variant => variant.id === newId)!;
(newId) => { changeSelectedVariant(newVariant);
const newVariant = product.value!.variants.find( });
(variant) => variant.id === newId
)!;
changeSelectedVariant(newVariant);
}
);
watch( watch(() => selectedColor.value, (newValue) => {
() => selectedColor.value, const filteredVariants = product.value!.variants.filter(v => v.color === newValue);
(newValue) => { selectedVariantId.value = filteredVariants[0].id;
const filteredVariants = product.value!.variants.filter( selectedVariant.value = filteredVariants[0];
(v) => v.color === newValue }, {
); immediate: true
selectedVariantId.value = filteredVariants[0].id; });
selectedVariant.value = filteredVariants[0];
}, watch(() => selectedVariant.value, (newValue) => {
{ selectedQuantity.value = 1;
immediate: true, selectedSlide.value = newValue.images[0].id;
} });
);
watch(
() => selectedVariant.value,
(newValue) => {
selectedQuantity.value = 1;
selectedSlide.value = newValue.images[0].id;
}
);
</script> </script>
<template> <template>
<div class="flex gap-16 container pt-[5rem] pb-28"> <div class="flex max-lg:flex-col gap-12 xl:gap-16 container pt-[5rem] pb-28">
<Slider <div class="flex flex-col gap-3 lg:hidden">
class="flex-1" <NuxtLink to="#" class="typo-label-sm"> {{ product!.category.name }}</NuxtLink>
v-model:selectedSlide="selectedSlide" <h1 class="typo-h-6 xs:typo-h-5 sm:typo-h-4 lg:typo-h-2"> {{ product!.name }} </h1>
:slides="selectedVariant.images"
/>
<div class="flex-1 flex flex-col gap-3 mt-12">
<span class="typo-label-sm"> سامسونگ </span>
<h1 class="typo-h-2">{{ product!.name }}</h1>
<div class="flex w-full items-center justify-between h-[85px]"> <div class="flex w-full items-center justify-between h-[85px]">
<div class="flex items-end gap-4"> <div class="flex items-end gap-4">
<div class="flex flex-col gap-2"> <div class="flex flex-col gap-2">
<span <span
v-if="selectedVariant.discount > 0" v-if="selectedVariant.discount > 0"
class="typo-p-lg relative flex-center w-fit line-through" class="typo-p-lg relative flex-center w-fit"
:class="'after:w-full after:h-[2px] after:bg-black after:absolute'"
> >
{{ selectedVariant.price }} {{ selectedVariant.price }}
</span> </span>
<span <span
class="typo-p-2xl relative flex-center w-fit font-medium" class="typo-p-2xl relative flex-center w-fit font-medium"
> >
{{ {{ selectedVariant.discount > 0 ? selectedVariant.price : selectedVariant.price }}
selectedVariant.discount > 0
? selectedVariant.price
: selectedVariant.price
}}
</span> </span>
</div> </div>
<div <div
v-if="selectedVariant.discount > 0" v-if="selectedVariant.discount > 0"
class="text-white bg-blue-500 mb-1 px-4 py-2 text-xs rounded-full flex items-center gap-1" class="text-white bg-blue-500 mb-1 px-4 py-2 text-xs rounded-full flex items-center gap-1"
> >
<Icon name="bi:percent" class="size-4" /> <Icon name="material-symbols:percent" class="size-4" />
{{ selectedVariant.discount }} {{ selectedVariant.discount }}
درصد تخفیف درصد تخفیف
</div> </div>
</div> </div>
<Rating :rate="3" /> <Rating :rate="3" />
</div> </div>
</div>
<Slider
class="w-full lg:w-1/2 lg:max-w-[620px]"
v-model:selectedSlide="selectedSlide"
:slides="selectedVariant.images"
/>
<div class="lg:w-1/2 flex flex-col gap-3 lg:mt-12">
<NuxtLink
to="#"
class="typo-label-sm max-lg:hidden"
>
{{ product!.category.name }}
</NuxtLink>
<h1 class="typo-h-4 xl:typo-h-3 max-lg:hidden"> {{ product!.name }} </h1>
<div class="flex w-full items-center justify-between h-[85px] max-lg:hidden">
<div class="flex items-end gap-4">
<div class="flex flex-col gap-2">
<span
v-if="selectedVariant.discount > 0"
class="typo-p-lg relative flex-center w-fit"
:class="'after:w-full after:h-[2px] after:bg-black after:absolute'"
>
{{ selectedVariant.price }}
</span>
<span
class="typo-p-2xl relative flex-center w-fit font-medium"
>
{{ selectedVariant.discount > 0 ? selectedVariant.price : selectedVariant.price }}
</span>
</div>
<div
v-if="selectedVariant.discount > 0"
class="text-white bg-blue-500 mb-1 px-4 py-2 text-xs rounded-full flex items-center gap-1"
>
<Icon name="material-symbols:percent" class="size-4" />
{{ selectedVariant.discount }}
<span class="max-sm:hidden">درصد</span>
تخفیف
</div>
<Rating :rate="3" class="sm:hidden" />
</div>
<Rating :rate="3" class="max-sm:hidden" />
</div>
<div <div
class="py-8 typo-p-md text-slate-500 text-justify [&_a]:text-blue-400 [&_strong]:font-bold [&_u]:text-red-400" class="py-8 typo-p-md text-slate-500 text-justify [&_a]:text-blue-400 [&_strong]:font-bold [&_u]:text-red-400"
@@ -112,15 +137,17 @@ watch(
/> />
<div class="flex items-center gap-4"> <div class="flex items-center gap-4">
<span class="typo-p-lg"> تنوع رنگی : </span> <span class="typo-p-lg">
تنوع رنگی :
</span>
<div class="flex items-center gap-4 py-4"> <div class="flex items-center gap-4 py-4">
<ColorCircle <ColorCircle
v-for="color in product!.colors" v-for="color in product!.colors"
:key="color" :key="color"
@click="selectedColor = color" @click="selectedColor = color"
selectable selectable
:selected="selectedColor === color" :selected="selectedColor === color "
:style="{ backgroundColor: color }" :style="{backgroundColor: color}"
class="cursor-pointer" class="cursor-pointer"
/> />
</div> </div>
@@ -128,11 +155,7 @@ watch(
<div class="flex items-center gap-6 flex-wrap"> <div class="flex items-center gap-6 flex-wrap">
<ProductVariant <ProductVariant
@click=" @click="variant.in_stock > 0 ? selectedVariantId = variant.id : undefined"
variant.in_stock > 0
? (selectedVariantId = variant.id)
: undefined
"
v-for="variant in product!.variants.filter(p => p.color === selectedColor)" v-for="variant in product!.variants.filter(p => p.color === selectedColor)"
:key="variant.id" :key="variant.id"
:variantDetail="variant" :variantDetail="variant"
@@ -141,28 +164,26 @@ watch(
</div> </div>
<div class="w-full flex flex-col gap-6 mt-10"> <div class="w-full flex flex-col gap-6 mt-10">
<RemainQuantity <RemainQuantity
:maxQuantity="selectedVariant.in_stock" :maxQuantity="selectedVariant.in_stock"
:quantity="selectedQuantity" :quantity="selectedQuantity"
/> />
<div class="w-full flex gap-3 flex-col"> <div class="w-full flex gap-3">
<div class="w-full flex gap-3"> <Button class="w-full rounded-full" end-icon="ci:plus">
<Button class="w-full rounded-full" end-icon="ci:plus"> افزودن به سبد خرید
افزودن به سبد خرید
</Button>
<QuantityCounter
v-model="selectedQuantity"
:max="selectedVariant.in_stock"
/>
</div>
<Button class="w-full rounded-full" variant="outlined">
همین الان بخر
</Button> </Button>
<QuantityCounter
v-model="selectedQuantity"
:max="selectedVariant.in_stock"
/>
</div> </div>
<InfoCard /> <InfoCard />
<Share /> <Share />
</div> </div>
</div> </div>
</div> </div>
+9 -7
View File
@@ -26,12 +26,14 @@ const { selectedVariant } = inject("productVariant") as ProductVariantProvideTyp
loop loop
/> />
<div class="size-full absolute inset-0 bg-black/20" /> <div class="size-full absolute inset-0 bg-black/20" />
<StickyCard <div class="absolute max-sm:flex items-center justify-center max-sm:px-5 sm:right-10 bottom-10 w-full">
:color="selectedVariant.color!" <StickyCard
:price="selectedVariant.price" :color="selectedVariant.color!"
:picture="selectedVariant.images[0].image" :price="selectedVariant.price"
:title="product!.name" :picture="selectedVariant.images[0].image"
class="absolute right-10 bottom-10" :title="product!.name"
/> class="max-sm:!w-full"
/>
</div>
</section> </section>
</template> </template>