feat: complete UI/UX improvements, vuesax icons, media server, and section management

This commit is contained in:
s.esmaeili
2026-10-23 21:06:15 +03:30
parent 49f30a96b1
commit fa61a76444
64 changed files with 4527 additions and 819 deletions
+4 -4
View File
@@ -1,6 +1,6 @@
<script setup lang="ts">
import type { PublicCategory } from "@imen/shared";
import { ArrowLeft, ArrowRight, Phone } from "lucide-vue-next";
import VuesaxIcon from "~/components/ui/VuesaxIcon.vue";
import { categoryPageSchema } from "#shared/seo/schema";
import SectionHead from "~/components/ui/SectionHead.vue";
import Reveal from "~/components/ui/Reveal.vue";
@@ -215,7 +215,7 @@ const groupCount = (g: string) => category.products.filter((p) => p.group === g)
<span class="mt-auto inline-flex items-center gap-2 pt-5 text-sm font-bold text-accent">
مشاهده جزئیات
<ArrowLeft class="size-4 transition-transform group-hover:-translate-x-1" />
<VuesaxIcon name="arrow-left" class="size-4 transition-transform group-hover:-translate-x-1" />
</span>
</div>
</NuxtLink>
@@ -231,14 +231,14 @@ const groupCount = (g: string) => category.products.filter((p) => p.group === g)
to="/#products"
class="group inline-flex items-center gap-2 text-muted transition-colors hover:text-accent"
>
<ArrowRight class="size-4 transition-transform group-hover:translate-x-1" />
<VuesaxIcon name="arrow-right" class="size-4 transition-transform group-hover:translate-x-1" />
بازگشت به دسته‌بندی‌ها
</NuxtLink>
<a
href="/#contact"
class="inline-flex items-center gap-2 rounded-full bg-accent px-6 py-3 text-sm font-bold text-bg transition-all hover:bg-accent-soft hover:shadow-[0_8px_45px_rgba(255,90,0,0.5)]"
>
<Phone class="size-4" />
<VuesaxIcon name="call" class="size-4" />
درخواست قیمت
</a>
</div>
+20 -12
View File
@@ -11,31 +11,39 @@ import Testimonials from "~/components/sections/Testimonials.vue";
import Contact from "~/components/sections/Contact.vue";
const canonical = useAbsUrl()("/");
const { hero } = useSiteStore().sections;
const siteStore = useSiteStore();
const sections = computed(() => siteStore.sections);
const hero = computed(() => sections.value.hero);
useHead({
link: [
{ rel: "canonical", href: canonical },
{ rel: "preload", as: "image", href: hero.image.url, fetchpriority: "high" },
...(hero.value?.image?.url && hero.value.enabled !== false
? [{ rel: "preload" as const, as: "image" as const, href: hero.value.image.url, fetchpriority: "high" as const }]
: []),
],
});
useSeoMeta({
robots: "index, follow",
ogUrl: canonical,
});
onMounted(() => {
void siteStore.load();
});
</script>
<template>
<main>
<Hero />
<TapeMarquee />
<Stats />
<Products />
<About />
<Services />
<Standards />
<Industries />
<Testimonials />
<Contact />
<Hero v-if="sections.hero?.enabled !== false" />
<TapeMarquee v-if="sections.tape?.enabled !== false" />
<Stats v-if="sections.stats?.enabled !== false" />
<Products v-if="sections.productsIntro?.enabled !== false" />
<About v-if="sections.about?.enabled !== false" />
<Services v-if="sections.services?.enabled !== false" />
<Standards v-if="sections.standards?.enabled !== false" />
<Industries v-if="sections.industries?.enabled !== false" />
<Testimonials v-if="sections.testimonials?.enabled !== false" />
<Contact v-if="sections.contact?.enabled !== false" />
</main>
</template>
+15 -25
View File
@@ -1,17 +1,7 @@
<script setup lang="ts">
import type { PublicProductDetail, PublicProductImage } from "@imen/shared";
import { useEventListener } from "@vueuse/core";
import {
ArrowLeft,
ArrowRight,
Check,
ChevronLeft,
ChevronRight,
Expand,
Headset,
Phone,
X,
} from "lucide-vue-next";
import VuesaxIcon from "~/components/ui/VuesaxIcon.vue";
import { breadcrumbSchema, productSchema } from "#shared/seo/schema";
import DynamicIcon from "~/components/ui/DynamicIcon.vue";
import Reveal from "~/components/ui/Reveal.vue";
@@ -221,7 +211,7 @@ useJsonLd(
class="absolute bottom-4 start-4 flex size-11 items-center justify-center rounded-full border border-line bg-bg/70 text-ink/80 backdrop-blur transition-colors hover:border-accent hover:text-accent"
@click="lightbox = true"
>
<Expand class="size-4" />
<VuesaxIcon name="maximize-4" class="size-4" />
</button>
<template v-if="images.length > 1">
@@ -231,7 +221,7 @@ useJsonLd(
class="absolute start-4 top-1/2 flex size-11 -translate-y-1/2 items-center justify-center rounded-full border border-line bg-bg/70 text-ink/80 opacity-0 backdrop-blur transition-all hover:border-accent hover:text-accent group-hover:opacity-100 max-md:opacity-100"
@click="go(-1)"
>
<ChevronRight class="size-5" />
<VuesaxIcon name="arrow-right-1" class="size-5" />
</button>
<button
type="button"
@@ -239,7 +229,7 @@ useJsonLd(
class="absolute end-4 top-1/2 flex size-11 -translate-y-1/2 items-center justify-center rounded-full border border-line bg-bg/70 text-ink/80 opacity-0 backdrop-blur transition-all hover:border-accent hover:text-accent group-hover:opacity-100 max-md:opacity-100"
@click="go(1)"
>
<ChevronLeft class="size-5" />
<VuesaxIcon name="arrow-left-1" class="size-5" />
</button>
</template>
</div>
@@ -358,13 +348,13 @@ useJsonLd(
@click="requestQuote"
>
درخواست قیمت و موجودی
<ArrowLeft class="size-5 transition-transform duration-300 group-hover:-translate-x-1.5" />
<VuesaxIcon name="arrow-left" class="size-5 transition-transform duration-300 group-hover:-translate-x-1.5" />
</NuxtLink>
<a
:href="`tel:${settings.phone}`"
class="inline-flex items-center gap-2.5 rounded-full border border-ink/25 px-6 py-4 font-bold text-ink transition-colors duration-300 hover:border-accent hover:text-accent"
>
<Phone class="size-4" />
<VuesaxIcon name="call" class="size-4" />
<span class="font-mono tracking-wider" dir="ltr">{{ settings.phoneDisplay }}</span>
</a>
</div>
@@ -412,7 +402,7 @@ useJsonLd(
<Reveal v-for="(f, i) in product.features" :key="f" :delay="i * 0.04">
<li class="flex h-full items-start gap-3 rounded-xl border border-line bg-panel/60 p-4">
<span class="mt-0.5 flex size-6 shrink-0 items-center justify-center rounded-full bg-accent text-bg">
<Check class="size-3.5" :stroke-width="3" />
<VuesaxIcon name="tick-circle" class="size-3.5" />
</span>
<span class="text-sm leading-7 text-ink/85">{{ f }}</span>
</li>
@@ -471,7 +461,7 @@ useJsonLd(
<Reveal :delay="0.18">
<div class="flex items-start gap-4 rounded-xl border border-hazard/30 bg-hazard/5 p-5">
<Headset class="size-6 shrink-0 text-hazard" />
<VuesaxIcon name="24-support" class="size-6 shrink-0 text-hazard" />
<div>
<div class="font-bold text-hazard">مشاوره رایگان انتخاب تجهیزات</div>
<p class="mt-1.5 text-sm leading-7 text-muted">
@@ -505,7 +495,7 @@ useJsonLd(
class="group inline-flex items-center gap-2 rounded-full border border-line px-6 py-3 text-sm text-muted transition-colors hover:border-accent hover:text-accent"
>
مشاهده همه
<ArrowLeft class="size-4 transition-transform group-hover:-translate-x-1" />
<VuesaxIcon name="arrow-left" class="size-4 transition-transform group-hover:-translate-x-1" />
</NuxtLink>
</Reveal>
</div>
@@ -537,7 +527,7 @@ useJsonLd(
<p class="mt-1 font-mono text-[10px] tracking-[0.2em] text-muted">{{ r.nameEn }}</p>
<span class="mt-auto inline-flex items-center gap-2 pt-4 text-xs font-bold text-accent">
مشاهده محصول
<ArrowLeft class="size-3.5 transition-transform group-hover:-translate-x-1" />
<VuesaxIcon name="arrow-left" class="size-3.5 transition-transform group-hover:-translate-x-1" />
</span>
</div>
</NuxtLink>
@@ -553,7 +543,7 @@ useJsonLd(
:to="categoryPath"
class="group inline-flex items-center gap-2 text-muted transition-colors hover:text-accent"
>
<ArrowRight class="size-4 transition-transform group-hover:translate-x-1" />
<VuesaxIcon name="arrow-right" class="size-4 transition-transform group-hover:translate-x-1" />
بازگشت به {{ product.category.name }}
</NuxtLink>
<NuxtLink
@@ -561,7 +551,7 @@ useJsonLd(
class="inline-flex items-center gap-2 rounded-full bg-accent px-6 py-3 text-sm font-bold text-bg transition-all hover:bg-accent-soft hover:shadow-[0_8px_45px_rgba(255,90,0,0.5)]"
@click="requestQuote"
>
<Phone class="size-4" />
<VuesaxIcon name="call" class="size-4" />
درخواست قیمت این محصول
</NuxtLink>
</div>
@@ -595,7 +585,7 @@ useJsonLd(
class="flex size-11 items-center justify-center rounded-lg border border-line transition-colors hover:border-accent hover:text-accent"
@click="lightbox = false"
>
<X class="size-5" />
<VuesaxIcon name="close-circle" class="size-5" />
</button>
</div>
<div class="relative flex min-h-0 flex-1 items-center justify-center px-5 pb-8" @click.self="lightbox = false">
@@ -607,7 +597,7 @@ useJsonLd(
class="absolute start-5 top-1/2 flex size-12 -translate-y-1/2 items-center justify-center rounded-full border border-line bg-bg/70 transition-colors hover:border-accent hover:text-accent"
@click="go(-1)"
>
<ChevronRight class="size-5" />
<VuesaxIcon name="arrow-right-1" class="size-5" />
</button>
<button
type="button"
@@ -615,7 +605,7 @@ useJsonLd(
class="absolute end-5 top-1/2 flex size-12 -translate-y-1/2 items-center justify-center rounded-full border border-line bg-bg/70 transition-colors hover:border-accent hover:text-accent"
@click="go(1)"
>
<ChevronLeft class="size-5" />
<VuesaxIcon name="arrow-left-1" class="size-5" />
</button>
</template>
</div>