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
+2 -2
View File
@@ -1,6 +1,6 @@
<script setup lang="ts">
import { AnimatePresence, motion } from "motion-v";
import { ArrowUp } from "lucide-vue-next";
import VuesaxIcon from "~/components/ui/VuesaxIcon.vue";
const show = useScrolledPast(700);
</script>
@@ -16,7 +16,7 @@ const show = useScrolledPast(700);
:exit="{ opacity: 0, y: 24 }"
class="fixed bottom-6 left-6 z-[70] flex size-12 items-center justify-center rounded-full border border-line bg-panel/90 text-ink shadow-[0_10px_40px_rgba(0,0,0,0.5)] backdrop-blur transition-colors hover:border-accent hover:text-accent"
>
<ArrowUp class="size-5" />
<VuesaxIcon name="arrow-up" class="size-5" />
</motion.a>
</AnimatePresence>
</template>
+29 -32
View File
@@ -1,45 +1,42 @@
<script setup lang="ts">
import type { SocialType } from "@imen/shared";
import {
AtSign,
Globe,
Instagram,
Linkedin,
MessageCircle,
Phone,
Send,
Youtube,
} from "lucide-vue-next";
import type { Component } from "vue";
import VuesaxIcon from "~/components/ui/VuesaxIcon.vue";
import Logo from "~/components/ui/Logo.vue";
const QUICK_LINKS = [
{ href: "/#home", label: "خانه" },
{ href: "/#products", label: "محصولات" },
{ href: "/#about", label: "درباره ما" },
{ href: "/#services", label: "خدمات" },
{ href: "/#standards", label: "استانداردها" },
{ href: "/#industries", label: "صنایع" },
];
const ALL_QUICK_LINKS = [
{ href: "/#home", label: "خانه", section: "hero" },
{ href: "/#products", label: "محصولات", section: "productsIntro" },
{ href: "/#about", label: "درباره ما", section: "about" },
{ href: "/#services", label: "خدمات", section: "services" },
{ href: "/#standards", label: "استانداردها", section: "standards" },
{ href: "/#industries", label: "صنایع", section: "industries" },
] as const;
const SOCIAL_META: Record<SocialType, { icon: Component; label: string }> = {
website: { icon: Globe, label: "وب‌سایت" },
telegram: { icon: Send, label: "تلگرام" },
instagram: { icon: Instagram, label: "اینستاگرام" },
linkedin: { icon: Linkedin, label: "لینکدین" },
whatsapp: { icon: MessageCircle, label: "واتساپ" },
bale: { icon: MessageCircle, label: "بله" },
eitaa: { icon: MessageCircle, label: "ایتا" },
aparat: { icon: Youtube, label: "آپارات" },
youtube: { icon: Youtube, label: "یوتیوب" },
email: { icon: AtSign, label: "ایمیل" },
phone: { icon: Phone, label: "تماس" },
const SOCIAL_META: Record<SocialType, { icon: string; label: string }> = {
website: { icon: "global", label: "وب‌سایت" },
telegram: { icon: "send-2", label: "تلگرام" },
instagram: { icon: "instagram", label: "اینستاگرام" },
linkedin: { icon: "link", label: "لینکدین" },
whatsapp: { icon: "messages-2", label: "واتساپ" },
bale: { icon: "messages-2", label: "بله" },
eitaa: { icon: "messages-2", label: "ایتا" },
aparat: { icon: "video-play", label: "آپارات" },
youtube: { icon: "video-play", label: "یوتیوب" },
email: { icon: "sms", label: "ایمیل" },
phone: { icon: "call", label: "تماس" },
};
const site = useSiteStore();
const footer = computed(() => site.sections.footer);
const settings = computed(() => site.settings);
const QUICK_LINKS = computed(() =>
ALL_QUICK_LINKS.filter(
(l) =>
(site.sections as Record<string, { enabled?: boolean }>)?.[l.section]?.enabled !== false,
),
);
const PRODUCT_LINKS = computed(() =>
site.categories.map((c) => ({ label: c.name, href: `/categories/${c.slug}` })),
);
@@ -75,7 +72,7 @@ const SOCIALS = computed(() =>
:rel="s.external ? 'noopener' : undefined"
class="flex size-10 items-center justify-center rounded-lg border border-line text-muted transition-all duration-300 hover:border-accent hover:bg-accent hover:text-bg"
>
<component :is="s.icon" class="size-4" />
<VuesaxIcon :name="s.icon" class="size-4" />
</a>
</div>
</div>
+25 -15
View File
@@ -1,20 +1,30 @@
<script setup lang="ts">
import { AnimatePresence, motion } from "motion-v";
import { Menu, Phone, X } from "lucide-vue-next";
import VuesaxIcon from "~/components/ui/VuesaxIcon.vue";
import Logo from "~/components/ui/Logo.vue";
const LINKS = [
{ href: "/#home", label: "خانه" },
{ href: "/#products", label: "محصولات" },
{ href: "/#about", label: "درباره ما" },
{ href: "/#services", label: "خدمات" },
{ href: "/#standards", label: "استانداردها" },
{ href: "/#industries", label: "صنایع" },
{ href: "/#contact", label: "تماس" },
];
const ALL_LINKS = [
{ href: "/#home", label: "خانه", section: "hero" },
{ href: "/#products", label: "محصولات", section: "productsIntro" },
{ href: "/#about", label: "درباره ما", section: "about" },
{ href: "/#services", label: "خدمات", section: "services" },
{ href: "/#standards", label: "استانداردها", section: "standards" },
{ href: "/#industries", label: "صنایع", section: "industries" },
{ href: "/#contact", label: "تماس", section: "contact" },
] as const;
const ui = useUiStore();
const settings = computed(() => useSiteStore().settings);
const site = useSiteStore();
const settings = computed(() => site.settings);
const sections = computed(() => site.sections);
const LINKS = computed(() =>
ALL_LINKS.filter(
(l) =>
(sections.value as Record<string, { enabled?: boolean }>)?.[l.section]?.enabled !== false,
),
);
const scrolled = useScrolledPast(40);
const { time, shift } = useTehranClock();
@@ -69,7 +79,7 @@ onBeforeUnmount(() => {
href="/#contact"
class="hidden items-center gap-2 rounded-full bg-accent px-5 py-2.5 text-sm font-bold text-bg transition-all duration-300 hover:bg-accent-soft hover:shadow-[0_0_30px_rgba(255,90,0,0.4)] md:flex"
>
<Phone class="size-4" />
<VuesaxIcon name="call" class="size-4" />
درخواست مشاوره
</a>
@@ -78,7 +88,7 @@ onBeforeUnmount(() => {
class="flex size-11 items-center justify-center rounded-lg border border-line text-ink transition-colors hover:border-accent hover:text-accent lg:hidden"
@click="ui.openMenu"
>
<Menu class="size-5" />
<VuesaxIcon name="menu" class="size-5" />
</button>
</div>
</div>
@@ -100,7 +110,7 @@ onBeforeUnmount(() => {
class="flex size-11 items-center justify-center rounded-lg border border-line transition-colors hover:border-accent hover:text-accent"
@click="ui.closeMenu"
>
<X class="size-5" />
<VuesaxIcon name="close-circle" class="size-5" />
</button>
</div>
@@ -126,7 +136,7 @@ onBeforeUnmount(() => {
<div class="flex items-center justify-between border-t border-line p-8 text-sm">
<div class="flex items-center gap-3 text-muted">
<Phone class="size-4 text-accent" />
<VuesaxIcon name="call" class="size-4 text-accent" />
<a :href="`tel:${settings.phone}`" class="font-mono" dir="ltr">{{ settings.phoneDisplay }}</a>
</div>
<div class="text-xs text-muted">تهران — شیفت {{ shift }}، {{ time }}</div>
+2 -2
View File
@@ -1,6 +1,6 @@
<script setup lang="ts">
import { motion } from "motion-v";
import { ShieldCheck } from "lucide-vue-next";
import VuesaxIcon from "~/components/ui/VuesaxIcon.vue";
const STEPS = [
"بررسی سیستم‌های ایمنی",
@@ -51,7 +51,7 @@ const step = computed(
<div class="flex items-center gap-4">
<span class="flex size-12 items-center justify-center rounded-xl bg-accent text-bg">
<ShieldCheck class="size-7" />
<VuesaxIcon name="shield-tick" class="size-7" />
</span>
<span class="font-mono text-xs tracking-[0.35em] text-muted">
IMEN PISHGAMAN CO.