This commit is contained in:
Parsa Nazer
2025-01-25 22:09:39 +03:30
13 changed files with 350 additions and 16 deletions
+7
View File
@@ -0,0 +1,7 @@
<script setup lang="ts"></script>
<template>
<div></div>
</template>
<style scoped></style>
+138
View File
@@ -0,0 +1,138 @@
<script setup lang="ts">
// state
const counter = ref(1);
// methods
const handleDeleteFromCart = () => {};
</script>
<template>
<div
class="flex flex-col items-center w-full gap-4 p-4 border lg:flex-row border-gray-300 rounded-xl bg-gray-50"
>
<div class="flex items-center justify-start w-full gap-2.5 lg:gap-4">
<div
class="size-[88px] aspect-square shrink-0 rounded-100 border border-gray-300 overflow-hidden"
>
<img
src="../assets/images/products/product-1.png"
class="object-cover size-full"
alt="product"
/>
</div>
<div class="flex flex-col w-full gap-4">
<span class="font-semibold lg:text-[1.125rem] text-gray-900">
فشارسنج بازویی امرن Omron M3
</span>
<div class="items-center justify-between hidden w-full lg:flex">
<div class="flex items-center">
<button
@click="counter++"
class="border size-10 flex-center rounded-100 border-gray-400"
>
<Icon name="bi:plus" class="**:stroke-gray-800" />
</button>
<div class="size-10 flex-center">{{ counter }}</div>
<button
@click="
counter > 1 ? counter-- : handleDeleteFromCart
"
class="border size-10 flex-center rounded-100 border-gray-400"
>
<Icon
v-if="counter == 1"
name="bi:dash"
class="**:stroke-gray-800"
/>
<Icon
v-else
name="bi:trash"
class="**:fill-red-700"
/>
</button>
</div>
<span class="text-[1.25rem] text-gray-900 font-semibold">
۲,۸۹۱,۰۰۰&nbsp;تومان
</span>
</div>
</div>
</div>
<div class="flex items-center justify-between w-full lg:hidden">
<div class="flex items-center">
<button
class="border size-10 flex-center rounded-100 border-gray-400"
>
<svg
width="16"
height="16"
viewBox="0 0 16 16"
fill="none"
class="stroke-gray-800"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M3.33334 8H12.6667"
stroke-width="1.5"
stroke-linecap="round"
stroke-linejoin="round"
></path>
<path
d="M8 3.33325V12.6666"
stroke-width="1.5"
stroke-linecap="round"
stroke-linejoin="round"
></path>
</svg>
</button>
<div class="size-10 text-[1.125rem] flex-center">1</div>
<button
class="border size-10 flex-center rounded-100 border-gray-400"
>
<svg
width="16"
height="16"
viewBox="0 0 16 16"
fill="none"
class="stroke-status-error-primary"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M2 4H14"
stroke-width="1.5"
stroke-linecap="round"
stroke-linejoin="round"
></path>
<path
d="M12.6667 4V13.3333C12.6667 14 12 14.6667 11.3333 14.6667H4.66668C4.00001 14.6667 3.33334 14 3.33334 13.3333V4"
stroke-width="1.5"
stroke-linecap="round"
stroke-linejoin="round"
></path>
<path
d="M5.33334 3.99992V2.66659C5.33334 1.99992 6.00001 1.33325 6.66668 1.33325H9.33334C10 1.33325 10.6667 1.99992 10.6667 2.66659V3.99992"
stroke-width="1.5"
stroke-linecap="round"
stroke-linejoin="round"
></path>
</svg>
</button>
</div>
<span class="text-[1.125rem] text-gray-900 font-semibold">
۲,۸۹۱,۰۰۰&nbsp;تومان
</span>
</div>
</div>
</template>
<style scoped></style>
@@ -0,0 +1,7 @@
<script setup lang="ts"></script>
<template>
<div></div>
</template>
<style scoped></style>
@@ -23,11 +23,10 @@ const swiper_instance = ref<SwiperClass | null>(null);
const onSwiper = (swiper: SwiperClass) => {
swiper_instance.value = swiper;
};
</script>
<template>
<section class="w-full flex flex-col gap-[4rem] py-[5rem] container">
<section class="w-full flex flex-col gap-[4rem] px-0 py-[5rem] container">
<div class="w-full flex justify-between items-center">
<span class="text-black typo-h-3">
{{ title }}
+118
View File
@@ -0,0 +1,118 @@
<script setup lang="ts">
// state
const route = useRoute();
// computed
const pageTitle = computed(() => route.meta.pageTitle);
const prevPage = computed(() => route.meta.prevPage);
const nextPage = computed(() => route.meta.nextPage);
</script>
<template>
<div
class="w-full flex flex-col-center persian-number font-iran-yekan-x"
dir="rtl"
>
<Header />
<main
class="w-full overflow-x-hidden container flex flex-col gap-[5rem]"
>
<div class="w-full flex flex-col">
<div
class="flex flex-col items-center justify-center gap-4 py-[5rem] lg:gap-0 lg:flex-row"
>
<div
class="flex items-center justify-start w-full lg:w-3/12"
>
<NuxtLink
v-if="prevPage"
:to="{ name: prevPage.name }"
class="flex items-center gap-2 text-sm lg:text-[1rem]"
>
<Icon
name="bi:arrow-right"
class="**:stroke-cyan-400"
/>
<span class="font-bold text-cyan-400">
{{ prevPage.label }}
</span>
</NuxtLink>
</div>
<h1
class="w-full text-center typo-h-3 lg:w-6/12 title-large"
>
{{ pageTitle }}
</h1>
<div class="hidden w-3/12 shrink-0 lg:block">&nbsp;</div>
</div>
<div
class="w-full flex flex-col items-center relative justify-between gap-8 lg:gap-6 lg:flex-row lg:items-start"
>
<div class="flex flex-col w-full gap-4 lg:gap-6 lg:w-9/12">
<slot />
</div>
<div
class="space-y-[1.25rem] bg-gray-50 p-4 sticky top-44 w-full lg:w-3/12 transition-all border border-gray-300 rounded-xl"
>
<div
class="flex items-center justify-between w-full text-gray-800"
>
<span class="max-w-1/2 text-sm lg:text-[1rem]">
جمع سبد خرید:
</span>
<span class="max-w-1/2 text-sm lg:text-[1rem]">
۳,۲۹۱,۰۰۰ تومان
</span>
</div>
<div
class="flex items-center justify-between w-full text-status-error-primary"
>
<span class="max-w-1/2 text-sm lg:text-[1rem]">
تخفیف:
</span>
<span class="max-w-1/2 text-sm lg:text-[1rem]">
۹۰۰,۰۰۰ تومان
</span>
</div>
<div
class="flex items-center justify-between w-full text-gray-900"
>
<span class="max-w-1/2 text-sm lg:text-[1rem]">
جمع کل:
</span>
<span class="max-w-1/2 text-sm lg:text-[1rem]">
۲,۳۹۱,۰۰۰ تومان
</span>
</div>
<NuxtLink :to="{ name: nextPage.name }">
<Button
start-icon="bi:arrow-right"
class="w-full rounded-full"
>
{{ nextPage.label }}
</Button>
</NuxtLink>
</div>
</div>
</div>
<ProductsSlider title="دیگران این محصولات را هم خریده‌اند" />
</main>
<div class="w-full flex-col flex">
<ServiceHighlights />
<Footer />
</div>
</div>
</template>
<style scoped></style>
+9
View File
@@ -0,0 +1,9 @@
<script setup lang="ts"></script>
<template>
<main class="w-full h-[100svh] font-iran-yekan-x">
<slot />
</main>
</template>
<style scoped></style>
+14
View File
@@ -0,0 +1,14 @@
<script setup lang="ts">
definePageMeta({
layout: "cart",
pageTitle: "ثبت سفارش",
prevPage: { name: "cart-delivery", label: "انتخاب آدرس" },
nextPage: { name: "checkout", label: "پرداخت" },
});
</script>
<template>
<div></div>
</template>
<style scoped></style>
+14
View File
@@ -0,0 +1,14 @@
<script setup lang="ts">
definePageMeta({
layout: "cart",
pageTitle: "انتخاب آدرس",
prevPage: { name: "cart", label: "سبد خرید" },
nextPage: { name: "cart-checkout", label: "تسویه حساب" },
});
</script>
<template>
<div class="flex flex-col w-full gap-6"></div>
</template>
<style scoped></style>
+15
View File
@@ -0,0 +1,15 @@
<script setup lang="ts">
definePageMeta({
layout: "cart",
pageTitle: "سبد خرید",
nextPage: { name: "cart-delivery", label: "انتخاب آدرس" },
});
</script>
<template>
<div class="flex flex-col w-full gap-4 lg:gap-6">
<CartItem v-for="i in 3" />
</div>
</template>
<style scoped></style>
@@ -1,5 +1,4 @@
<script lang="ts" setup>
import useGetCategories from "~/composables/api/product/useGetCategories";
// state
@@ -13,7 +12,9 @@ const debouncedSearch = refDebounced(search, 300);
const filteredCategories = computed(() => {
if (debouncedSearch.value.length > 0) {
return categories.value!.filter(cat => cat.name.includes(debouncedSearch.value));
return categories.value!.filter((cat) =>
cat.name.includes(debouncedSearch.value)
);
}
return categories.value!;
@@ -27,16 +28,15 @@ onServerPrefetch(async () => {
if (response.isError) {
throw createError({
statusCode: 500,
statusMessage: `Error in categories page prefetch`
statusMessage: `Error in categories page prefetch`,
});
}
});
</script>
<template>
<div class="container">
<div class="mt-20 flex gap-6 justify-between items-center">
<div class="py-[5rem] flex gap-6 justify-between items-center">
<span class="typo-h-3 text-black">دسته بندی ها</span>
<Input
class="max-w-[400px] w-full"
@@ -46,7 +46,11 @@ onServerPrefetch(async () => {
>
<template #endItem>
<div class="flex items-center gap-1">
<Icon class="translate-y-[-1px]" name="ci:search" size="24" />
<Icon
class="translate-y-[-1px]"
name="ci:search"
size="24"
/>
</div>
</template>
</Input>
@@ -69,10 +73,7 @@ onServerPrefetch(async () => {
/>
</div>
<div
v-else
class="flex w-full mt-12"
>
<div v-else class="flex w-full mt-12">
<div
class="flex-col flex-grow py-[12rem] gap-6 border-2 border-slate-200 border-dashed size-full rounded-100 flex-center"
>
@@ -83,6 +84,5 @@ onServerPrefetch(async () => {
</div>
</div>
</Transition>
</div>
</template>
</template>
+13
View File
@@ -0,0 +1,13 @@
<script setup lang="ts">
// meta
definePageMeta({
layout: "none",
});
</script>
<template>
<div class="size-full flex-center"></div>
</template>
<style scoped></style>
+2 -2
View File
@@ -65,7 +65,7 @@ watch(
<span>/</span>
<span>همه</span>
</div> -->
<h1 class="typo-hero-2">همه محصولات</h1>
<h1 class="typo-h-3">همه محصولات</h1>
</div>
<div class="w-full flex items-center justify-end gap-4">
@@ -88,7 +88,7 @@ watch(
/>
</ul>
<div v-else class="w-full h-max">
<div v-if="!products?.length" class="flex flex-grow px-5 w-full">
<div v-if="!products?.length" class="flex flex-grow w-full">
<div
class="flex-col flex-grow py-[12rem] gap-6 border-2 border-slate-200 border-dashed size-full rounded-100 flex-center"
>