Files
imen_pishghaman/app/components/layout/Header.vue
T
S. EsmaeiliandClaude Opus 4.6 e31ef5a21f feat: migrate landing from Next.js to Nuxt 4 (Vue 3)
Full 1:1 migration preserving all visuals, animations and behavior:
- Nuxt 4 + Vue 3 (script setup, TypeScript strict) with SSG output
- Tailwind CSS v4 with @tailwindcss/vite
- Ant Design Vue 4 (dark theme, RTL, Persian locale) for design system
- Pinia for state management (ui + contact stores)
- motion-v (framer-motion port) for all animations
- lucide-vue-next for icons
- SEO improvements: og:image, canonical fix, real 404 page, JSON-LD services
- JS bundle reduced from 302KB to 239KB gzip
- Docker/nginx deployment preserved (out/ -> nginx)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-10-06 16:28:05 +03:30

136 lines
4.6 KiB
Vue

<script setup lang="ts">
import { AnimatePresence, motion } from "motion-v";
import { Menu, Phone, X } from "lucide-vue-next";
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 ui = useUiStore();
const scrolled = useScrolledPast(40);
const { time, shift } = useTehranClock();
watch(
() => ui.menuOpen,
(open) => {
document.body.style.overflow = open ? "hidden" : "";
},
);
onBeforeUnmount(() => {
document.body.style.overflow = "";
});
</script>
<template>
<motion.header
:initial="{ y: -90, opacity: 0 }"
:animate="ui.ready ? { y: 0, opacity: 1 } : {}"
:transition="{ duration: 0.9, delay: 0.15, ease: EASE }"
:class="`fixed inset-x-0 top-0 z-[80] transition-all duration-500 ${
scrolled ? 'border-b border-line bg-bg/85 py-3 backdrop-blur-xl' : 'py-5'
}`"
>
<div class="mx-auto flex max-w-7xl items-center justify-between px-5 md:px-8">
<Logo />
<nav class="hidden items-center gap-7 lg:flex">
<a
v-for="l in LINKS"
:key="l.href"
:href="l.href"
class="group relative py-2 text-sm text-ink/75 transition-colors hover:text-ink"
>
{{ l.label }}
<span
class="absolute bottom-0 start-0 h-0.5 w-full origin-right scale-x-0 bg-accent transition-transform duration-300 group-hover:scale-x-100"
/>
</a>
</nav>
<div class="flex items-center gap-3">
<div
class="hidden items-center gap-2.5 rounded-full border border-line px-4 py-2 text-[11px] text-muted xl:flex"
>
<span class="size-1.5 animate-pulse rounded-full bg-emerald-400" />
<span class="font-mono">{{ time }}</span>
<span class="text-muted/50">|</span>
<span>تهران — شیفت {{ shift }}</span>
</div>
<a
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" />
درخواست مشاوره
</a>
<button
aria-label="باز کردن منو"
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" />
</button>
</div>
</div>
</motion.header>
<AnimatePresence>
<motion.div
v-if="ui.menuOpen"
:initial="{ opacity: 0 }"
:animate="{ opacity: 1 }"
:exit="{ opacity: 0 }"
:transition="{ duration: 0.35 }"
class="fixed inset-0 z-[110] flex flex-col bg-bg/95 backdrop-blur-2xl"
>
<div class="flex items-center justify-between border-b border-line px-5 py-4 md:px-8">
<Logo />
<button
aria-label="بستن منو"
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" />
</button>
</div>
<nav class="flex flex-1 flex-col justify-center gap-1 overflow-y-auto px-8">
<motion.a
v-for="(l, i) in LINKS"
:key="l.href"
:href="l.href"
:initial="{ opacity: 0, x: 44 }"
:animate="{ opacity: 1, x: 0 }"
:transition="{ delay: 0.08 + i * 0.055, duration: 0.55, ease: EASE }"
class="group flex items-baseline gap-5 border-b border-line/60 py-4"
@click="ui.closeMenu"
>
<span class="font-mono text-xs text-accent">
{{ faNum(String(i + 1).padStart(2, "0")) }}
</span>
<span class="text-3xl font-black transition-colors group-hover:text-accent">
{{ l.label }}
</span>
</motion.a>
</nav>
<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" />
<span class="font-mono">۰۲۱-۹۱۰۰۸۸۰۰</span>
</div>
<div class="text-xs text-muted">تهران — شیفت {{ shift }}، {{ time }}</div>
</div>
</motion.div>
</AnimatePresence>
</template>