diff --git a/frontend/app.vue b/frontend/app.vue
index da627ed..54a43d4 100644
--- a/frontend/app.vue
+++ b/frontend/app.vue
@@ -5,6 +5,14 @@ import { VueQueryDevtools } from "@tanstack/vue-query-devtools";
// state
+useSeoMeta({
+ titleTemplate: (titleChunk) => {
+ return titleChunk ? `${titleChunk} | فروشگاه هی ملز` : "فروشگاه هی ملز";
+ },
+ ogImage: "/img/heymlz/global-cover.jpg",
+ twitterImage: "/img/heymlz/global-cover.jpg",
+});
+
const { $updateAvailable: updateAvailable, $handleUpdate: handleUpdate } = useNuxtApp();
const closeModal = () => {
@@ -37,7 +45,7 @@ const closeModal = () => {
diff --git a/frontend/assets/css/tailwind.css b/frontend/assets/css/tailwind.css
index f071dc5..5696404 100644
--- a/frontend/assets/css/tailwind.css
+++ b/frontend/assets/css/tailwind.css
@@ -131,8 +131,6 @@
--breakpoint-3xl: 1700px;
/* ANIMATIONS */
- --animate-marquee: marquee 20s linear infinite;
- --animate-marquee-reverse: marquee 20s linear infinite reverse;
--animate-fade-in: fadeIn 350ms ease-in-out;
--animate-slide-down: slideDown 300ms ease-out;
@@ -149,12 +147,6 @@
--animate-toast-in: toastSlideIn 600ms cubic-bezier(0.16, 1, 0.3, 1);
--animate-toast-out: toastSlideOut 200ms ease-out;
- @keyframes marquee {
- to {
- transform: translateX(50%);
- }
- }
-
@keyframes fadeIn {
from {
opacity: 0;
diff --git a/frontend/components/global/Brands.vue b/frontend/components/global/Brands.vue
index 370b2d5..d570827 100644
--- a/frontend/components/global/Brands.vue
+++ b/frontend/components/global/Brands.vue
@@ -9,6 +9,15 @@ type Props = {
const props = defineProps();
const {} = toRefs(props);
+
+const brands = ref([
+ "/img/brands/brand-1.png",
+ "/img/brands/brand-2.png",
+ "/img/brands/brand-3.png",
+ "/img/brands/brand-4.png",
+ "/img/brands/brand-5.png",
+ "/img/brands/brand-6.png",
+]);
@@ -20,136 +29,64 @@ const {} = toRefs(props);
متون بلکه روزنامه و مجله در ستون و سطرآنچنان که
-
-
+
-
-
+
+
HEYMLZ
-
-
-
- HEYMLZ
-
-
-
-
+
+
-
-
+
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
diff --git a/frontend/components/global/CategoryCard.vue b/frontend/components/global/CategoryCard.vue
index 9b96646..fe2fbff 100644
--- a/frontend/components/global/CategoryCard.vue
+++ b/frontend/components/global/CategoryCard.vue
@@ -10,6 +10,7 @@ type Props = {
description: string;
picture: string;
darkLayer?: boolean;
+ isActive: boolean;
};
// props
@@ -23,39 +24,45 @@ const { colorObject } = useImageColor(`#category-image-${id.value}`);
-
+
-
+
+
+
+
+
-
diff --git a/frontend/components/global/ComboBox.vue b/frontend/components/global/ComboBox.vue
index 70535bd..42a3718 100644
--- a/frontend/components/global/ComboBox.vue
+++ b/frontend/components/global/ComboBox.vue
@@ -47,9 +47,7 @@ watch(
watch(
() => modelValue.value,
(newValue) => {
- const target = options.value
- .flatMap((option) => option.children)
- .find((child) => child.id == newValue);
+ const target = options.value.flatMap((option) => option.children).find((child) => child.id == newValue);
value.value = target || undefined;
},
@@ -58,9 +56,13 @@ watch(
-
+
-
+
-
+
-
+
-
+
{{ group.name }}
-
+
-
+
-
-
+
+
{{ option.name }}
diff --git a/frontend/components/global/Footer.vue b/frontend/components/global/Footer.vue
index 42551b2..b9190b0 100644
--- a/frontend/components/global/Footer.vue
+++ b/frontend/components/global/Footer.vue
@@ -5,7 +5,7 @@
alt=""
class="absolute z-10 object-cover opacity-45"
: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%',
}"
/>
diff --git a/frontend/components/global/LoadingOverlay.vue b/frontend/components/global/LoadingOverlay.vue
index fecd7bf..4b10c09 100644
--- a/frontend/components/global/LoadingOverlay.vue
+++ b/frontend/components/global/LoadingOverlay.vue
@@ -27,12 +27,12 @@ const progressStyle = computed(() => {
// methods
-const onAssetLoaded = () => {
- clearInterval(progressInterval.value!);
- criticalLoad.value = false;
- assetLoadingProgress.value = 100;
- isAssetLoaded.value = true;
-};
+// const onAssetLoaded = () => {
+// clearInterval(progressInterval.value!);
+// criticalLoad.value = false;
+// assetLoadingProgress.value = 100;
+// isAssetLoaded.value = true;
+// };
const onAssetFinished = () => {
gsap.to("#loading-overlay", {
@@ -59,15 +59,15 @@ onMounted(() => {
if (!isSiteLoadingDisabled.value) {
isWindowScrollLocked.value = true;
- const heymlzLoadingAnimation = document.querySelector("#heymlz-loading-animation") as HTMLVideoElement;
+ // const heymlzLoadingAnimation = document.querySelector("#heymlz-loading-animation") as HTMLVideoElement;
- if (heymlzLoadingAnimation?.readyState >= HTMLMediaElement.HAVE_ENOUGH_DATA) {
- onAssetLoaded();
- }
+ // if (heymlzLoadingAnimation?.readyState >= HTMLMediaElement.HAVE_ENOUGH_DATA) {
+ // onAssetLoaded();
+ // }
progressInterval.value = setInterval(() => {
- assetLoadingProgress.value += Math.random() * 10;
- }, 250);
+ assetLoadingProgress.value += Math.random() * 50;
+ }, 150);
gsap.to("#loading-overlay", {
opacity: 1,
@@ -100,7 +100,7 @@ onMounted(() => {
- {
:style="{
mask: 'linear-gradient(to bottom, rgba(0,0,0,0) 0%, black 20%, black 80%, rgba(0,0,0,0) 100%)',
}"
- />
+ /> -->
diff --git a/frontend/components/global/Pagination.vue b/frontend/components/global/Pagination.vue
index cfed27a..90665f1 100644
--- a/frontend/components/global/Pagination.vue
+++ b/frontend/components/global/Pagination.vue
@@ -1,4 +1,8 @@
@@ -23,23 +33,32 @@ const onSwiper = (swiper: SwiperClass) => {
class="flex flex-col justify-center gap-4 bg-black sm:min-h-[110svh] relative overflow-hidden shrink-0 py-24 lg:py-32"
>
- دسته بندی ها
+ دسته بندی ها
{
:category="slide.name"
:picture="slide.image"
:count="slide.product_count"
+ :isActive="activeIndex === index"
description="توضیحات دسته بندی"
/>
@@ -69,7 +90,10 @@ const onSwiper = (swiper: SwiperClass) => {
{
{
-
+
{{ slide.title }}
@@ -250,10 +255,21 @@ onUnmounted(() => {
{{ slide.description }}
-
+
+
+
مشاهده
@@ -270,7 +286,9 @@ onUnmounted(() => {
@click="swiper_instance?.slidePrev()"
class="relative"
>
-
+
{
@click="swiper_instance?.slideNext()"
class="relative"
>
-
+
("none");
const draggableEl = ref(null);
const previewContainerEl = ref(null);
-const heymlzElement = useTemplateRef("heymlzElement");
-const heymlzElementIsVisible = useElementVisibility(heymlzElement, {
- rootMargin: "0px 0px -40% 0px",
-});
+// const heymlzElement = useTemplateRef("heymlzElement");
+// const heymlzElementIsVisible = useElementVisibility(heymlzElement, {
+// rootMargin: "0px 0px -40% 0px",
+// });
-const showHeymlzAnimation = ref(false);
+// const showHeymlzAnimation = ref(false);
const { x: dragAxisX } = useDraggable(draggableEl, {
initialValue: { x: 0, y: 0 },
@@ -28,22 +28,22 @@ const { x: dragAxisX } = useDraggable(draggableEl, {
// watch
-watch(
- heymlzElementIsVisible,
- (newValue) => {
- if (newValue) {
- setTimeout(() => {
- showHeymlzAnimation.value = true;
- setTimeout(() => {
- showHeymlzAnimation.value = false;
- }, 3200);
- }, 400);
- }
- },
- {
- once: true,
- }
-);
+// watch(
+// heymlzElementIsVisible,
+// (newValue) => {
+// if (newValue) {
+// setTimeout(() => {
+// showHeymlzAnimation.value = true;
+// setTimeout(() => {
+// showHeymlzAnimation.value = false;
+// }, 3200);
+// }, 400);
+// }
+// },
+// {
+// once: true,
+// }
+// );
watch(
() => clipPathPercent.value,
@@ -64,7 +64,7 @@ watch(
const clientRect = previewContainerEl.value?.getBoundingClientRect()!;
const percent = clientRect.width / 100;
const clipPercent = (newValue + draggableEl.value!.clientWidth / 2 - clientRect.x - 8) / percent;
- if (clipPercent >= 5 && clipPercent <= 95) {
+ if (clipPercent >= 1 && clipPercent <= 99) {
clipPathPercent.value = clipPercent;
}
}
@@ -72,7 +72,7 @@ watch(
-
+
مقایسه محصولات
@@ -86,8 +86,7 @@ watch(
-
-
-
-
{
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 max-lg:-mt-16 lg:mt-5"
+ class="showcase-slide origin-bottom absolute size-full bg-black flex items-center justify-center max-lg:-mt-16 lg:mt-5"
>
سلام دوست عزیز!
- من میتونم هر سوالی رو درمورد این محصول جواب بدم اگه میخوای شروع کنیم روی دکمه زیر کلیک کن
+ من میتونم هر سوالی رو درمورد این محصول جواب بدم اگه میخوای شروع کنیم وارد وبسایت شو
diff --git a/frontend/components/product/ProductComments.vue b/frontend/components/product/ProductComments.vue
index e5d9730..482cc39 100644
--- a/frontend/components/product/ProductComments.vue
+++ b/frontend/components/product/ProductComments.vue
@@ -62,7 +62,7 @@ const limitedComments = computed(() => {
>
@@ -98,15 +98,6 @@ const limitedComments = computed(() => {
:username="'منصور مرزبان'"
/>
-
-
- هیچ نظری ثبت نشده است
-
{
نمایش همه
+
+
+ هیچ نظری ثبت نشده است
+
diff --git a/frontend/components/product/ProductHero.vue b/frontend/components/product/ProductHero.vue
index f5880de..3f0e3f0 100644
--- a/frontend/components/product/ProductHero.vue
+++ b/frontend/components/product/ProductHero.vue
@@ -162,7 +162,7 @@ watch(
diff --git a/frontend/composables/api/products/useGetProducts.ts b/frontend/composables/api/products/useGetProducts.ts
index 6c5e6df..a842523 100644
--- a/frontend/composables/api/products/useGetProducts.ts
+++ b/frontend/composables/api/products/useGetProducts.ts
@@ -39,8 +39,8 @@ const useGetProducts = (params?: ComputedRef
) => {
category: params?.category,
price_gte: params?.price_gte,
price_lte: params?.price_lte,
- offset: Number(params?.page) * 9 - 9,
- limit: 9
+ offset: Number(params?.page) * 15 - 15,
+ limit: 15
}
}
);
diff --git a/frontend/middleware/route.global.ts b/frontend/middleware/route.global.ts
deleted file mode 100644
index ebb378b..0000000
--- a/frontend/middleware/route.global.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-export default defineNuxtRouteMiddleware((to, from) => {
- if (to.path !== from.path && process.client) {
- window.scrollTo(0, 0);
- }
-});
diff --git a/frontend/nuxt.config.ts b/frontend/nuxt.config.ts
index abebf1c..467d589 100644
--- a/frontend/nuxt.config.ts
+++ b/frontend/nuxt.config.ts
@@ -3,11 +3,7 @@ export default defineNuxtConfig({
compatibilityDate: "2024-11-01",
ssr: true,
devtools: { enabled: true },
- css: [
- "~/assets/css/tailwind.css",
- "swiper/css",
- "animate.css/animate.min.css",
- ],
+ css: ["~/assets/css/tailwind.css", "swiper/css", "animate.css/animate.min.css"],
routeRules: {
"/products": { prerender: false, ssr: false },
@@ -16,9 +12,6 @@ export default defineNuxtConfig({
},
app: {
- head: {
- title: "فروشگاه هی ملز",
- },
pageTransition: {
name: "fade",
mode: "out-in",
@@ -71,14 +64,18 @@ export default defineNuxtConfig({
"@formkit/auto-animate/nuxt",
"@vite-pwa/nuxt",
"@nuxt/image",
+ "@nuxtjs/seo",
],
+ sitemap: {
+ enabled: false,
+ },
+
pwa: {
strategies: "injectManifest",
srcDir: "public",
filename: "sw.js",
- registerType:
- process.env.NODE_ENV === "production" ? "autoUpdate" : "prompt",
+ registerType: process.env.NODE_ENV === "production" ? "autoUpdate" : "prompt",
manifest: {
name: "Heymlz",
short_name: "Heymlz",
diff --git a/frontend/package.json b/frontend/package.json
index ff3c169..fd054dd 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -19,6 +19,7 @@
"@nuxt/icon": "^1.10.3",
"@nuxt/image": "^1.10.0",
"@nuxtjs/google-fonts": "^3.2.0",
+ "@nuxtjs/seo": "^3.0.3",
"@tanstack/vue-query": "^5.62.2",
"@tanstack/vue-query-devtools": "^5.62.3",
"@vite-pwa/nuxt": "^0.10.6",
diff --git a/frontend/pages/article/[id].vue b/frontend/pages/article/[id].vue
index 2c2f43e..6f7d1fa 100644
--- a/frontend/pages/article/[id].vue
+++ b/frontend/pages/article/[id].vue
@@ -1,5 +1,4 @@
-
+
@@ -41,13 +51,13 @@ if (response.isError) {
/>
-
-
+ class="w-fit pr-2 pl-5 h-[50px] rounded-full flex items-center justify-center gap-3 bg-white"
+ >
+ class="relative flex items-center justify-center rounded-full overflow-hidden size-[35px]"
+ >
- {{ article!.author.full_name }}
-
+ {{ article!.author.full_name }}
+
-
- دسته بندی موبایل
-
+ class="w-fit pr-4 pl-5 h-[50px] rounded-full flex items-center justify-center gap-2 border-[1.5px] border-white text-white"
+ >
+ دسته بندی موبایل
-
-
-
- ۲۴ مهر 1403
-
+ class="w-fit pr-4 pl-5 h-[50px] rounded-full flex items-center justify-center gap-2 border-[1.5px] border-white text-white"
+ >
+
+ ۲۴ مهر 1403
-
+ class="w-fit pr-4 pl-5 h-[50px] rounded-full flex items-center justify-center gap-2 border-[1.5px] border-white text-white"
+ >
+
- {{ article!.views }}
-
+ {{ article!.views }}
+
-
-
-
\ No newline at end of file
+
diff --git a/frontend/pages/articles.vue b/frontend/pages/articles.vue
index fddeea3..39b29c7 100644
--- a/frontend/pages/articles.vue
+++ b/frontend/pages/articles.vue
@@ -7,6 +7,10 @@ import ArticlesList from "~/components/articles/ArticlesList.vue";
// state
+useSeoMeta({
+ title : "مقالات"
+});
+
const page = ref(1);
const search = ref("");
const debouncedSearch = refDebounced(search, 700);
diff --git a/frontend/pages/cart/checkout.vue b/frontend/pages/cart/checkout.vue
index e5e01fe..c37d546 100644
--- a/frontend/pages/cart/checkout.vue
+++ b/frontend/pages/cart/checkout.vue
@@ -3,10 +3,13 @@
const route = useRoute();
+useSeoMeta({
+ title: "ثبت سفارش",
+});
+
definePageMeta({
layout: "cart",
middleware: "check-is-logged-in",
- pageTitle: "ثبت سفارش",
prevPage: { name: "cart-delivery", label: "انتخاب آدرس" },
nextPage: { name: "payment", label: "پرداخت" },
});
diff --git a/frontend/pages/cart/delivery.vue b/frontend/pages/cart/delivery.vue
index 7174721..988e452 100644
--- a/frontend/pages/cart/delivery.vue
+++ b/frontend/pages/cart/delivery.vue
@@ -7,10 +7,14 @@ import useGetCartOrders from "~/composables/api/orders/useGetCartOrders";
// meta
+useSeoMeta({
+ title: "انتخاب آدرس",
+});
+
definePageMeta({
layout: "cart",
middleware: "check-is-logged-in",
- pageTitle: "انتخاب آدرس",
+
prevPage: { name: "cart", label: "سبد خرید" },
nextPage: { name: "cart-checkout", label: "تسویه حساب", query: "ZARINPAL" },
});
diff --git a/frontend/pages/cart/index.vue b/frontend/pages/cart/index.vue
index b9fbae4..84ef551 100644
--- a/frontend/pages/cart/index.vue
+++ b/frontend/pages/cart/index.vue
@@ -5,10 +5,13 @@ import useGetCartOrders from "~/composables/api/orders/useGetCartOrders";
// meta
+useSeoMeta({
+ title : "سبد خرید"
+});
+
definePageMeta({
layout: "cart",
middleware: "check-is-logged-in",
- pageTitle: "سبد خرید",
prevPage: { name: "index", label: "بازگشت به خانه" },
nextPage: { name: "cart-delivery", label: "انتخاب آدرس" },
});
diff --git a/frontend/pages/category.vue b/frontend/pages/category.vue
index 642c489..8fd4ed9 100644
--- a/frontend/pages/category.vue
+++ b/frontend/pages/category.vue
@@ -5,6 +5,10 @@ import useGetCategories from "~/composables/api/product/useGetCategories";
// state
+useSeoMeta({
+ title : "دسته بندی ها"
+});
+
const { data: categories, suspense } = useGetCategories();
const search = ref("");
diff --git a/frontend/pages/contact-us.vue b/frontend/pages/contact-us.vue
index dc7d036..00486ed 100644
--- a/frontend/pages/contact-us.vue
+++ b/frontend/pages/contact-us.vue
@@ -1,6 +1,10 @@