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>
@@ -1,10 +1,12 @@
|
||||
node_modules
|
||||
.next
|
||||
.nuxt
|
||||
.output
|
||||
.git
|
||||
.gitignore
|
||||
src
|
||||
app
|
||||
server
|
||||
shared
|
||||
public
|
||||
_old_vite_backup
|
||||
*.md
|
||||
_dev.log
|
||||
.env*
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
# dependencies
|
||||
node_modules/
|
||||
|
||||
# next.js
|
||||
.next/
|
||||
# nuxt
|
||||
.nuxt/
|
||||
.output/
|
||||
.data/
|
||||
dist
|
||||
# out/ عمداً در git نگه داشته میشود (بیلد محلی → دیپلوی با Docker)
|
||||
next-env.d.ts
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
@@ -14,7 +16,5 @@ next-env.d.ts
|
||||
npm-debug.log*
|
||||
|
||||
# local env files
|
||||
.env
|
||||
.env*.local
|
||||
|
||||
# old vite backup (remove once migration is verified and no longer needed)
|
||||
_old_vite_backup/
|
||||
|
||||
@@ -1,35 +1,64 @@
|
||||
# آریا ایمن — لندینگ (Next.js)
|
||||
# آریا ایمن — لندینگ (Nuxt)
|
||||
|
||||
لندینگ شرکت آریا ایمن، مهاجرتیافته از Vite/React به Next.js (App Router) با خروجی کاملاً استاتیک، بهینه برای سئو و سرعت.
|
||||
لندینگ شرکت آریا ایمن، مهاجرتیافته از Next.js به **Nuxt 4 (Vue 3)** با خروجی کاملاً استاتیک (SSG)، بهینه برای سئو و سرعت.
|
||||
ظاهر و رفتار صفحه دقیقاً همان نسخه Next.js است.
|
||||
|
||||
## نصب
|
||||
| لایه | ابزار |
|
||||
|---|---|
|
||||
| فریمورک | Nuxt 4 + Vue 3 (`<script setup>`, TypeScript strict) |
|
||||
| استایل | Tailwind CSS v4 (`@tailwindcss/vite`) — توکنها در `app/assets/css/main.css` |
|
||||
| Design system | Ant Design Vue 4 — تم تیره با پالت پروژه در `app/design/theme.ts`، RTL و لوکال فارسی |
|
||||
| State management | Pinia (`app/stores/`) |
|
||||
| انیمیشن | motion-v (پورت Motion/framer-motion برای Vue) |
|
||||
| آیکن | lucide-vue-next |
|
||||
|
||||
## نصب و اجرا
|
||||
|
||||
```bash
|
||||
npm install
|
||||
npm run dev # http://localhost:3000
|
||||
npm run typecheck # بررسی TypeScript
|
||||
```
|
||||
|
||||
## اجرا در حالت توسعه
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
```
|
||||
|
||||
سپس آدرس `http://localhost:3000` را باز کنید.
|
||||
|
||||
## Build (تولید نسخه نهایی استاتیک)
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
npm run build # = nuxt generate
|
||||
```
|
||||
|
||||
خروجی در پوشه `out/` ساخته میشود — مجموعهای از فایلهای HTML/CSS/JS کاملاً استاتیک که نیازی به سرور Node ندارند.
|
||||
خروجی در پوشه `out/` ساخته میشود — فایلهای HTML/CSS/JS کاملاً استاتیک که نیازی به سرور Node ندارند
|
||||
(`index.html`، `404.html`، `robots.txt`، `sitemap.xml`، `manifest.webmanifest`، `_nuxt/`).
|
||||
|
||||
برای پیشنمایش محلی خروجی build:
|
||||
پیشنمایش محلی خروجی:
|
||||
|
||||
```bash
|
||||
npx serve out
|
||||
npm run preview # = npx serve out
|
||||
```
|
||||
|
||||
## ساختار پروژه
|
||||
|
||||
```
|
||||
app/
|
||||
app.vue ConfigProvider (antd) + سئوی سراسری + JSON-LD سازمان/وبسایت
|
||||
error.vue صفحه ۴۰۴ / خطا (noindex) — در build بهصورت out/404.html پیشرندر میشود
|
||||
pages/index.vue صفحه اصلی (AppShell → ۱۰ سکشن + Footer)، canonical
|
||||
components/layout/ AppShell, Header, Footer, Preloader, Cursor, BackToTop
|
||||
components/sections/ Hero, TapeMarquee, Stats, CountUp, Products, About, Services, Standards, Industries, Testimonials, Contact
|
||||
components/ui/ Logo, Reveal, SectionHead
|
||||
composables/ useSiteSeo, useJsonLd, useTehranClock, useScrolledPast
|
||||
stores/ ui (Preloader/منوی موبایل)، contact (فرم تماس)
|
||||
design/theme.ts توکنهای Ant Design (همگام با @theme در main.css)
|
||||
assets/css/ main.css (Tailwind + فونتها)، antd-overrides.css
|
||||
plugins/antd-style.ts استخراج CSS-in-JS آنتدیزاین در SSR (بدون FOUC)
|
||||
shared/ config/site.ts و seo/schema.ts (مشترک بین app و server)
|
||||
server/routes/ robots.txt، sitemap.xml، manifest.webmanifest
|
||||
public/ فونتها، تصاویر، favicon.svg
|
||||
```
|
||||
|
||||
### نکات Ant Design + Tailwind
|
||||
- استایلهای Tailwind v4 داخل cascade layer هستند و CSS-in-JS آنتدیزاین بیرون از layer؛ بنابراین روی کامپوننتهای antd کلاس ظاهری Tailwind نگذارید. ظاهر کامپوننتهای antd از توکنها (`app/design/theme.ts`) و `app/assets/css/antd-overrides.css` میآید.
|
||||
- پالت رنگ در دو جا تعریف شده (`@theme` در `main.css` برای Tailwind و `palette` در `theme.ts` برای antd)؛ هنگام تغییر، هر دو را همگام کنید.
|
||||
|
||||
## دیپلوی پروداکشن با Docker
|
||||
|
||||
بیلد روی ماشین توسعه انجام میشود؛ خروجی `out/` داخل گیت commit میشود و روی سرور فقط image ساخته و اجرا میشود (بدون `npm install` / `npm run build` در سرور).
|
||||
@@ -61,28 +90,22 @@ docker build -t aria-imen-landing .
|
||||
docker run -d --name aria-imen-landing -p 8080:80 --restart unless-stopped aria-imen-landing
|
||||
```
|
||||
|
||||
تنظیمات Nginx داخل image مطابق export استاتیک Next.js است (`try_files`، کش `/_next/static/`، صفحه `404.html`).
|
||||
تنظیمات Nginx داخل image مطابق خروجی استاتیک Nuxt است (`try_files`، کش immutable برای `/_nuxt/`، صفحه `404.html`).
|
||||
|
||||
## آپلود روی هاست (Static Hosting)
|
||||
|
||||
این پروژه با `output: 'export'` پیکربندی شده، یعنی:
|
||||
|
||||
1. `npm run build` را اجرا کنید.
|
||||
2. کل محتوای پوشه `out/` را (نه خود پوشه، بلکه فایلهای داخلش) در ریشه هاست (public_html، یا مشابه آن در cPanel/Nginx) آپلود کنید.
|
||||
3. سایت بدون نیاز به Node.js یا هیچ سرور اختصاصی کار میکند.
|
||||
|
||||
### نکات مهم هاست استاتیک (cPanel / Nginx / هاست ایرانی)
|
||||
|
||||
- **ریدایرکتها و هدرها** در `next.config.ts` روی static export اجرا نمیشوند. اگر بعداً نیاز به ریدایرکت ۳۰۱ داشتید (مثلاً از `/index.html`)، باید در سطح هاست تنظیم شود:
|
||||
|
||||
**Apache (.htaccess):**
|
||||
```apache
|
||||
Redirect 301 /index.html /
|
||||
<IfModule mod_expires.c>
|
||||
ExpiresActive On
|
||||
ExpiresByType text/css "access plus 1 year"
|
||||
ExpiresByType application/javascript "access plus 1 year"
|
||||
ExpiresByType image/webp "access plus 1 year"
|
||||
ExpiresByType font/woff2 "access plus 1 year"
|
||||
</IfModule>
|
||||
ErrorDocument 404 /404.html
|
||||
@@ -90,49 +113,37 @@ docker run -d --name aria-imen-landing -p 8080:80 --restart unless-stopped aria-
|
||||
|
||||
**Nginx:**
|
||||
```nginx
|
||||
location /_next/static/ { expires 1y; add_header Cache-Control "public, immutable"; }
|
||||
location /_nuxt/ { expires 1y; add_header Cache-Control "public, immutable"; }
|
||||
location / { try_files $uri $uri.html $uri/index.html =404; }
|
||||
error_page 404 /404.html;
|
||||
gzip on; gzip_types text/css application/javascript image/svg+xml;
|
||||
gzip on; gzip_types text/css application/javascript application/json image/svg+xml;
|
||||
```
|
||||
|
||||
ریدایرکت `location = /index.html { return 301 /; }` را نگذارید؛ با `index index.html` حلقهٔ ۳۰۱ روی `/` میسازد.
|
||||
|
||||
## پیش از دیپلوی واقعی — کارهایی که باید انجام دهید
|
||||
|
||||
این پروژه فعلاً با دادههای تستی/placeholder برای موارد زیر ساخته شده و **باید قبل از انتشار واقعی بررسی و اصلاح شوند**:
|
||||
|
||||
1. **دامنه واقعی**: در فایل [`src/config/site.ts`](src/config/site.ts) مقدار `url: "https://ariaiman.ir"` باید با دامنه نهایی واقعی جایگزین شود (این مقدار روی canonical، Open Graph، sitemap و JSON-LD اثر مستقیم دارد).
|
||||
1. **دامنه واقعی**: در [`shared/config/site.ts`](shared/config/site.ts) مقدار `url: "https://ariaiman.ir"` را با دامنه نهایی جایگزین کنید (روی canonical، Open Graph، sitemap، robots و JSON-LD اثر مستقیم دارد).
|
||||
2. **لوگوی رسمی**: در همان فایل، `logo` فعلاً به تصویر hero اشاره میکند؛ یک فایل PNG/SVG لوگوی واقعی جایگزین شود.
|
||||
3. **آیکونهای PWA**: `src/app/manifest.ts` فعلاً بدون آیکون است. دو فایل `icon-192.png` و `icon-512.png` در `public/` قرار داده و در manifest معرفی شوند.
|
||||
4. **تصویر Open Graph**: یک فایل `opengraph-image.png` با ابعاد ۱۲۰۰×۶۳۰ در `src/app/` قرار دهید (Next.js آن را بهصورت خودکار شناسایی میکند).
|
||||
5. **شبکههای اجتماعی**: در `src/config/site.ts`، آرایه `socials` خالی است. لینکهای واقعی اینستاگرام/تلگرام/لینکدین را اضافه کنید تا در Schema.org (`sameAs`) درج شود.
|
||||
6. **فرم تماس**: فرم بخش «تماس» فعلاً فقط یک شبیهسازی محلی است (بدون ارسال واقعی به سرور یا سرویس ایمیل) — دقیقاً همان رفتاری که در نسخه قبلی هم وجود داشت. برای فعالسازی واقعی باید به یک سرویس فرم (مثل فرماسپری، ایمیل، یا API اختصاصی) متصل شود.
|
||||
7. **npm audit**: یک آسیبپذیری «high» در نسخه postcss داخلی Next.js 15.5 گزارش میشود (`npm audit`). این مربوط به مرحله build/dev است، نه کد سمت کاربر نهایی. رفع کامل آن نیازمند ارتقا به Next.js 16 (breaking change) است — در صورت تمایل بهروزرسانی جداگانه انجام شود.
|
||||
3. **تصویر Open Graph**: `ogImage` فعلاً `hero.jpg` است؛ یک تصویر اختصاصی ۱۲۰۰×۶۳۰ در `public/` قرار دهید و مسیر/ابعاد را در `site.ts` بهروز کنید.
|
||||
4. **آیکونهای PWA**: manifest فعلاً از `favicon.svg` استفاده میکند؛ برای سازگاری کامل، `icon-192.png`، `icon-512.png` و `apple-touch-icon.png` اضافه شوند.
|
||||
5. **شبکههای اجتماعی**: آرایه `socials` در `site.ts` خالی است؛ لینکهای واقعی را اضافه کنید تا در Schema.org (`sameAs`) درج شوند.
|
||||
6. **فرم تماس**: اکشن `submit` در [`app/stores/contact.ts`](app/stores/contact.ts) فعلاً فقط ارسال را شبیهسازی میکند (مثل نسخه قبلی)؛ برای فعالسازی واقعی به API/سرویس فرم متصل شود.
|
||||
|
||||
## چکلیست سئوی پیادهسازیشده
|
||||
## چکلیست سئو
|
||||
|
||||
| مورد | وضعیت | فایل |
|
||||
|---|---|---|
|
||||
| یک H1 با کلمه کلیدی اصلی | ✅ | `src/components/sections/Hero.tsx` |
|
||||
| سلسلهمراتب H2/H3 منطقی، بدون پرش سطح | ✅ | `src/components/ui/SectionHead.tsx` و همه سکشنها |
|
||||
| عنوان و توضیحات با طول مناسب | ✅ | `src/config/site.ts` |
|
||||
| Canonical، metadataBase، Open Graph، Twitter Card | ✅ | `src/app/layout.tsx` |
|
||||
| `lang="fa"` و `dir="rtl"` | ✅ | `src/app/layout.tsx` |
|
||||
| JSON-LD (LocalBusiness + WebSite) | ✅ | `src/lib/seo/schema.ts`, `src/components/seo/JsonLd.tsx` |
|
||||
| `sitemap.xml` | ✅ | `src/app/sitemap.ts` |
|
||||
| `robots.txt` | ✅ | `src/app/robots.ts` |
|
||||
| `manifest.webmanifest` | ✅ (بدون آیکون — نیاز به تکمیل) | `src/app/manifest.ts` |
|
||||
| صفحه ۴۰۴ واقعی (بدون ریدایرکت به خانه) | ✅ | `src/app/not-found.tsx` |
|
||||
| alt توصیفی روی همه تصاویر محتوایی | ✅ | همه کامپوننتهای سکشن |
|
||||
| تمام متن در HTML بدون نیاز به اجرای JS | ✅ | تأیید شده با بررسی خروجی build |
|
||||
| لینکهای داخلی سالم (`#anchor`) | ✅ | بدون تغییر نسبت به نسخه اصلی |
|
||||
| فونت خودمیزبان (self-hosted) بدون CDN خارجی | ✅ | `public/fonts/`, `src/app/layout.tsx` |
|
||||
| تصاویر بدون وابستگی به CDN خارجی | ✅ | تصاویر Industries از pexels دانلود و داخلی شدند |
|
||||
|
||||
## معماری فنی مهاجرت
|
||||
|
||||
- **Server Components برای محتوا**: تمام بخشهای بدون تعامل (Hero, About, Standards, TapeMarquee, Footer) بهصورت Server Component هستند و در HTML build نهایی کامل قابل مشاهدهاند.
|
||||
- **Client Components فقط برای تعامل**: منو موبایل، فرم تماس، اسلایدر نظرات، پنلهای تعاملی محصولات/خدمات، شمارنده آمار، کرسر سفارشی و Preloader، هرکدام جداگانه `'use client'` هستند تا حجم JS اولیه صفحه کمینه بماند.
|
||||
- **بدون بکاند**: هیچ `app/api`، دیتابیس یا server action اضافه نشده؛ طبق درخواست پروژه.
|
||||
- **انیمیشن ورودی Hero با CSS خالص**: برخلاف نسخه اصلی (که H1 تا پایان انیمیشن Preloader با `opacity:0` مخفی بود)، اکنون محتوای Hero همیشه در HTML اولیه قابل مشاهده است و فقط با CSS keyframes (بدون وابستگی به اجرای JS) وارد صفحه میشود — این تغییر برای رفع مشکل LCP/SEO با تأیید شما انجام شد.
|
||||
| یک H1 با کلمه کلیدی اصلی | ✅ | `app/components/sections/Hero.vue` |
|
||||
| سلسلهمراتب H2/H3 منطقی، بدون پرش سطح | ✅ | `app/components/ui/SectionHead.vue` و همه سکشنها |
|
||||
| عنوان، title template و توضیحات | ✅ | `shared/config/site.ts`, `app/composables/useSiteSeo.ts` |
|
||||
| Canonical یکسان با sitemap (`https://ariaiman.ir/`) | ✅ | `app/pages/index.vue` |
|
||||
| Open Graph و Twitter Card **همراه با تصویر** (og:image/twitter:image) | ✅ | `app/composables/useSiteSeo.ts` |
|
||||
| `lang="fa"` و `dir="rtl"` | ✅ | `nuxt.config.ts` |
|
||||
| JSON-LD: LocalBusiness (+ ساعات کاری، سال تأسیس، منطقه خدمات)، WebSite، Service ×۴ | ✅ | `shared/seo/schema.ts`, `app/composables/useJsonLd.ts` |
|
||||
| `sitemap.xml` / `robots.txt` / `manifest.webmanifest` (با آیکون) | ✅ | `server/routes/` |
|
||||
| صفحه ۴۰۴ واقعی پیشرندرشده، `noindex` و بدون canonical | ✅ | `app/error.vue`, `nuxt.config.ts` |
|
||||
| preload تصویر hero و فونتها | ✅ | `app/pages/index.vue`, `nuxt.config.ts` |
|
||||
| alt توصیفی روی همه تصاویر محتوایی | ✅ | همه سکشنها |
|
||||
| تمام متن در HTML بدون نیاز به اجرای JS | ✅ | خروجی `out/index.html` |
|
||||
| فونت و تصاویر خودمیزبان (بدون CDN) | ✅ | `public/` |
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
<script setup lang="ts">
|
||||
import { ConfigProvider, StyleProvider } from "ant-design-vue";
|
||||
import faIR from "ant-design-vue/es/locale/fa_IR";
|
||||
import { antdTheme } from "~/design/theme";
|
||||
import { organizationSchema, websiteSchema } from "#shared/seo/schema";
|
||||
|
||||
const { $antdCache } = useNuxtApp();
|
||||
|
||||
useSiteSeo();
|
||||
useJsonLd([organizationSchema(), websiteSchema()]);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<StyleProvider :cache="$antdCache">
|
||||
<ConfigProvider :theme="antdTheme" direction="rtl" :locale="faIR">
|
||||
<NuxtPage />
|
||||
</ConfigProvider>
|
||||
</StyleProvider>
|
||||
</template>
|
||||
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Ant Design Vue ↔ project look.
|
||||
* antd's CSS-in-JS is unlayered while Tailwind v4 lives in cascade layers, so Tailwind classes
|
||||
* can't restyle antd elements. These unlayered rules pin antd form controls to the exact
|
||||
* pre-migration styling (same values as the old Tailwind `inputCls` / submit button).
|
||||
*/
|
||||
|
||||
/* ---- form shell ---- */
|
||||
.contact-form.ant-form {
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
line-height: inherit;
|
||||
}
|
||||
/* antd resets items and their grid wrappers to 14px/1.5714; inherit like the original markup did
|
||||
(the control line box decides the gap under the inline-block textarea) */
|
||||
.contact-form .ant-form-item,
|
||||
.contact-form .ant-form-item .ant-row,
|
||||
.contact-form .ant-form-item .ant-col {
|
||||
margin-bottom: 0;
|
||||
font-size: inherit;
|
||||
line-height: inherit;
|
||||
}
|
||||
.contact-form .ant-form-item .ant-form-item-label {
|
||||
padding: 0 0 8px; /* mb-2 */
|
||||
line-height: 16px;
|
||||
}
|
||||
.contact-form .ant-form-item-label > label {
|
||||
width: 100%; /* original labels were full-width blocks */
|
||||
height: auto;
|
||||
font-size: 12px; /* text-xs */
|
||||
line-height: 16px;
|
||||
color: var(--color-muted);
|
||||
}
|
||||
.contact-form .ant-form-item-explain {
|
||||
font-size: 12px;
|
||||
line-height: 20px;
|
||||
padding-top: 4px;
|
||||
}
|
||||
|
||||
/* ---- inputs (= w-full rounded-lg border border-line bg-bg px-4 py-3.5 text-sm text-ink) ---- */
|
||||
.contact-form .ant-input {
|
||||
width: 100%;
|
||||
border-radius: 8px;
|
||||
border: 1px solid var(--color-line);
|
||||
background-color: var(--color-bg);
|
||||
padding: 14px 16px;
|
||||
font-family: inherit;
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
color: var(--color-ink);
|
||||
box-shadow: none;
|
||||
transition-property: color, background-color, border-color;
|
||||
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
||||
transition-duration: 150ms;
|
||||
}
|
||||
.contact-form .ant-input::placeholder {
|
||||
color: color-mix(in oklab, var(--color-muted) 50%, transparent);
|
||||
}
|
||||
.contact-form .ant-input:hover {
|
||||
border-color: var(--color-line);
|
||||
}
|
||||
.contact-form .ant-input:focus,
|
||||
.contact-form .ant-input-focused {
|
||||
border-color: var(--color-accent);
|
||||
outline: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
/* antd's .ant-input-rtl forces direction:rtl; honour an explicit dir="ltr" (phone field) */
|
||||
.contact-form .ant-input[dir="ltr"] {
|
||||
direction: ltr;
|
||||
text-align: left;
|
||||
}
|
||||
.contact-form textarea.ant-input {
|
||||
resize: none;
|
||||
min-height: 0;
|
||||
vertical-align: baseline; /* native inline-block textarea alignment (antd sets bottom) */
|
||||
}
|
||||
|
||||
/* ---- submit (= rounded-full bg-accent py-4 font-bold text-bg, hover:bg-accent-soft + glow) ---- */
|
||||
.contact-form .ant-btn.contact-submit {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height: auto;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 10px;
|
||||
border: 0;
|
||||
border-radius: calc(infinity * 1px); /* = tailwind rounded-full */
|
||||
background-color: var(--color-accent);
|
||||
padding: 16px 0;
|
||||
font-family: inherit;
|
||||
font-size: 16px;
|
||||
line-height: 24px;
|
||||
font-weight: 700;
|
||||
color: var(--color-bg);
|
||||
box-shadow: none;
|
||||
cursor: default;
|
||||
transition: all 300ms cubic-bezier(0.4, 0, 0.2, 1);
|
||||
}
|
||||
.contact-form .ant-btn.contact-submit > span {
|
||||
display: inline;
|
||||
}
|
||||
@media (hover: hover) {
|
||||
.contact-form .ant-btn.contact-submit:hover {
|
||||
background-color: var(--color-accent-soft);
|
||||
color: var(--color-bg);
|
||||
box-shadow: 0 8px 45px rgba(255, 90, 0, 0.45);
|
||||
}
|
||||
}
|
||||
.contact-form .ant-btn.contact-submit:disabled {
|
||||
opacity: 0.6;
|
||||
border: 0;
|
||||
}
|
||||
/* no click-wave ring (wasn't part of the original button) */
|
||||
.contact-form .ant-btn.contact-submit::after,
|
||||
.contact-form .ant-wave {
|
||||
display: none;
|
||||
}
|
||||
@@ -1,8 +1,61 @@
|
||||
@import "tailwindcss";
|
||||
|
||||
/* ---- local fonts (replaces next/font/local) ----
|
||||
Same family names, fallback faces and metric overrides that next/font generated, so text
|
||||
(including Persian glyphs inside font-mono, which fall back to the size-adjusted Arial face)
|
||||
renders exactly as before. */
|
||||
@font-face {
|
||||
font-family: "vazirmatn";
|
||||
src: url("/fonts/Vazirmatn-Variable.woff2") format("woff2");
|
||||
font-weight: 100 900;
|
||||
font-display: swap;
|
||||
}
|
||||
@font-face {
|
||||
font-family: "vazirmatn Fallback";
|
||||
src: local("Arial");
|
||||
ascent-override: 102.54%;
|
||||
descent-override: 53.71%;
|
||||
line-gap-override: 0%;
|
||||
size-adjust: 100%;
|
||||
}
|
||||
@font-face {
|
||||
font-family: "ibmPlexMono";
|
||||
src: url("/fonts/IBMPlexMono-Regular.woff2") format("woff2");
|
||||
font-weight: 400;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
@font-face {
|
||||
font-family: "ibmPlexMono";
|
||||
src: url("/fonts/IBMPlexMono-Medium.woff2") format("woff2");
|
||||
font-weight: 500;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
@font-face {
|
||||
font-family: "ibmPlexMono";
|
||||
src: url("/fonts/IBMPlexMono-SemiBold.woff2") format("woff2");
|
||||
font-weight: 600;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
@font-face {
|
||||
font-family: "ibmPlexMono Fallback";
|
||||
src: local("Arial");
|
||||
ascent-override: 77.95%;
|
||||
descent-override: 20.91%;
|
||||
line-gap-override: 0%;
|
||||
size-adjust: 131.49%;
|
||||
}
|
||||
|
||||
:root {
|
||||
--font-vazirmatn: "vazirmatn", "vazirmatn Fallback", Tahoma, system-ui, sans-serif;
|
||||
--font-ibm-plex-mono: "ibmPlexMono", "ibmPlexMono Fallback", ui-monospace, monospace;
|
||||
}
|
||||
|
||||
@theme {
|
||||
--font-sans: var(--font-vazirmatn), ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif; /* added for migration: next/font variable */
|
||||
--font-mono: var(--font-ibm-plex-mono), "Vazirmatn", ui-monospace, monospace; /* added for migration: next/font variable */
|
||||
--font-sans: var(--font-vazirmatn), ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif; /* font variables defined in :root above */
|
||||
--font-mono: var(--font-ibm-plex-mono), "Vazirmatn", ui-monospace, monospace; /* font variables defined in :root above */
|
||||
|
||||
--color-bg: #0a0a0c;
|
||||
--color-panel: #121216;
|
||||
@@ -0,0 +1,24 @@
|
||||
<script setup lang="ts">
|
||||
import { AnimatePresence } from "motion-v";
|
||||
import Preloader from "./Preloader.vue";
|
||||
import Cursor from "./Cursor.vue";
|
||||
import Header from "./Header.vue";
|
||||
import BackToTop from "./BackToTop.vue";
|
||||
|
||||
const ui = useUiStore();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<AnimatePresence>
|
||||
<Preloader v-if="!ui.ready" @complete="ui.setReady" />
|
||||
</AnimatePresence>
|
||||
|
||||
<Cursor />
|
||||
<div class="noise" aria-hidden="true" />
|
||||
|
||||
<Header />
|
||||
|
||||
<slot />
|
||||
|
||||
<BackToTop />
|
||||
</template>
|
||||
@@ -0,0 +1,22 @@
|
||||
<script setup lang="ts">
|
||||
import { AnimatePresence, motion } from "motion-v";
|
||||
import { ArrowUp } from "lucide-vue-next";
|
||||
|
||||
const show = useScrolledPast(700);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<AnimatePresence>
|
||||
<motion.a
|
||||
v-if="show"
|
||||
href="#home"
|
||||
aria-label="بازگشت به بالا"
|
||||
:initial="{ opacity: 0, y: 24 }"
|
||||
:animate="{ opacity: 1, y: 0 }"
|
||||
: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" />
|
||||
</motion.a>
|
||||
</AnimatePresence>
|
||||
</template>
|
||||
@@ -0,0 +1,52 @@
|
||||
<script setup lang="ts">
|
||||
import { motion, useMotionValue, useSpring } from "motion-v";
|
||||
|
||||
const x = useMotionValue(-100);
|
||||
const y = useMotionValue(-100);
|
||||
const sx = useSpring(x, { stiffness: 550, damping: 45, mass: 0.4 });
|
||||
const sy = useSpring(y, { stiffness: 550, damping: 45, mass: 0.4 });
|
||||
const hover = ref(false);
|
||||
const visible = ref(false);
|
||||
|
||||
const move = (e: MouseEvent) => {
|
||||
x.set(e.clientX);
|
||||
y.set(e.clientY);
|
||||
visible.value = true;
|
||||
};
|
||||
const over = (e: MouseEvent) => {
|
||||
const t = e.target as HTMLElement | null;
|
||||
hover.value = !!t?.closest?.(
|
||||
"a, button, input, textarea, select, label, [data-hover]",
|
||||
);
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
window.addEventListener("mousemove", move, { passive: true });
|
||||
window.addEventListener("mouseover", over, { passive: true });
|
||||
});
|
||||
onBeforeUnmount(() => {
|
||||
window.removeEventListener("mousemove", move);
|
||||
window.removeEventListener("mouseover", over);
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="pointer-events-none fixed inset-0 z-[120] hidden [@media(pointer:fine)]:block">
|
||||
<motion.div :style="{ x: sx, y: sy }" class="absolute -left-4 -top-4 size-8">
|
||||
<motion.div
|
||||
:animate="{
|
||||
scale: hover ? 1.9 : 1,
|
||||
opacity: visible ? 1 : 0,
|
||||
rotate: hover ? 45 : 0,
|
||||
}"
|
||||
:transition="{ type: 'spring', stiffness: 320, damping: 24 }"
|
||||
class="size-8 rounded-md border-2 border-accent/80"
|
||||
/>
|
||||
<div
|
||||
:class="`absolute inset-0 m-auto size-1 rounded-full bg-accent transition-opacity duration-300 ${
|
||||
visible ? 'opacity-100' : 'opacity-0'
|
||||
}`"
|
||||
/>
|
||||
</motion.div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,118 @@
|
||||
<script setup lang="ts">
|
||||
import { AtSign, Globe, Phone, Send } from "lucide-vue-next";
|
||||
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 PRODUCT_LINKS = [
|
||||
"کلاه ایمنی",
|
||||
"دستکش ضدبرش",
|
||||
"کفش ایمنی",
|
||||
"عینک ایمنی",
|
||||
"هارنس ضدسقوط",
|
||||
"لباس کار بازتابنده",
|
||||
];
|
||||
|
||||
const SOCIALS = [
|
||||
{ icon: Globe, label: "وبسایت" },
|
||||
{ icon: Send, label: "تلگرام" },
|
||||
{ icon: AtSign, label: "ایمیل" },
|
||||
{ icon: Phone, label: "تماس" },
|
||||
];
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<footer class="relative overflow-hidden border-t border-line">
|
||||
<div class="hazard h-2.5" />
|
||||
|
||||
<div class="mx-auto max-w-7xl px-5 md:px-8">
|
||||
<div class="grid gap-12 py-16 md:grid-cols-12 md:py-20">
|
||||
<!-- brand -->
|
||||
<div class="md:col-span-5">
|
||||
<Logo />
|
||||
<p class="mt-6 max-w-sm text-sm leading-8 text-muted">
|
||||
تأمینکننده تخصصی تجهیزات حفاظت فردی و راهکارهای ایمنی صنعتی؛
|
||||
همراه سازمانها از سال ۱۳۸۶ در مسیر صفر شدن حوادث کاری.
|
||||
</p>
|
||||
<div class="mt-7 flex gap-3">
|
||||
<a
|
||||
v-for="s in SOCIALS"
|
||||
:key="s.label"
|
||||
href="#contact"
|
||||
:aria-label="s.label"
|
||||
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" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- quick links -->
|
||||
<div class="md:col-span-2">
|
||||
<div class="font-mono text-xs tracking-[0.25em] text-accent">// دسترسی</div>
|
||||
<ul class="mt-5 space-y-3">
|
||||
<li v-for="l in QUICK_LINKS" :key="l.href">
|
||||
<a :href="l.href" class="text-sm text-muted transition-colors hover:text-ink">
|
||||
{{ l.label }}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<!-- products -->
|
||||
<div class="md:col-span-2">
|
||||
<div class="font-mono text-xs tracking-[0.25em] text-accent">// محصولات</div>
|
||||
<ul class="mt-5 space-y-3">
|
||||
<li v-for="p in PRODUCT_LINKS" :key="p">
|
||||
<a href="#products" class="text-sm text-muted transition-colors hover:text-ink">
|
||||
{{ p }}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<!-- contact -->
|
||||
<div class="md:col-span-3">
|
||||
<div class="font-mono text-xs tracking-[0.25em] text-accent">// ارتباط</div>
|
||||
<address class="mt-5 space-y-3 text-sm text-muted not-italic">
|
||||
<p class="leading-7">
|
||||
تهران، خیابان کارگر شمالی،
|
||||
<br />
|
||||
خیابان فر، کوچه دوم، پلاک ۱۲
|
||||
</p>
|
||||
<p class="font-mono tracking-wider" dir="ltr">۰۲۱ - ۹۱ ۰۰ ۸۸ ۰۰</p>
|
||||
<p class="font-mono tracking-wider" dir="ltr">info@ariaiman.ir</p>
|
||||
<p class="pt-2 text-xs leading-6">
|
||||
شنبه تا پنجشنبه — ۸:۰۰ تا ۱۷:۰۰
|
||||
<br />
|
||||
پشتیبانی اضطراری: ۲۴/۷
|
||||
</p>
|
||||
</address>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- giant wordmark -->
|
||||
<div aria-hidden="true" class="pointer-events-none select-none pb-6">
|
||||
<div class="text-outline text-center text-[17vw] font-black leading-[0.85] md:text-[11vw]">
|
||||
آریا ایمن
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="flex flex-wrap items-center justify-between gap-4 border-t border-line py-6 text-xs text-muted"
|
||||
>
|
||||
<div>© ۱۴۰۴ آریا ایمن — تمامی حقوق محفوظ است.</div>
|
||||
<div class="font-mono text-[10px] tracking-[0.25em]">
|
||||
ISO 9001:2015 — CE CERTIFIED PPE SUPPLIER
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
</template>
|
||||
@@ -0,0 +1,135 @@
|
||||
<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>
|
||||
@@ -0,0 +1,78 @@
|
||||
<script setup lang="ts">
|
||||
import { motion } from "motion-v";
|
||||
import { ShieldCheck } from "lucide-vue-next";
|
||||
|
||||
const STEPS = [
|
||||
"بررسی سیستمهای ایمنی",
|
||||
"تأیید استانداردهای بینالمللی",
|
||||
"بارگذاری تجهیزات حفاظت فردی",
|
||||
"محیط کاری آماده است",
|
||||
];
|
||||
|
||||
const emit = defineEmits<{ complete: [] }>();
|
||||
|
||||
const progress = ref(0);
|
||||
let done = false;
|
||||
let t: ReturnType<typeof setInterval> | undefined;
|
||||
|
||||
onMounted(() => {
|
||||
let v = 0;
|
||||
t = setInterval(() => {
|
||||
v += Math.floor(Math.random() * 11) + 7;
|
||||
if (v >= 100) {
|
||||
v = 100;
|
||||
clearInterval(t);
|
||||
if (!done) {
|
||||
done = true;
|
||||
setTimeout(() => emit("complete"), 450);
|
||||
}
|
||||
}
|
||||
progress.value = v;
|
||||
}, 140);
|
||||
});
|
||||
onBeforeUnmount(() => clearInterval(t));
|
||||
|
||||
const step = computed(
|
||||
() =>
|
||||
STEPS[
|
||||
Math.min(STEPS.length - 1, Math.floor((progress.value / 100) * STEPS.length))
|
||||
],
|
||||
);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<motion.div
|
||||
:exit="{ y: '-100%' }"
|
||||
:transition="{ duration: 0.85, ease: [0.76, 0, 0.24, 1] }"
|
||||
class="fixed inset-0 z-[200] flex flex-col items-center justify-center bg-bg"
|
||||
>
|
||||
<div class="hazard absolute inset-x-0 top-0 h-3" />
|
||||
<div class="hazard absolute inset-x-0 bottom-0 h-3" />
|
||||
|
||||
<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" />
|
||||
</span>
|
||||
<span class="font-mono text-xs tracking-[0.35em] text-muted">
|
||||
ARIA IMEN CO.
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="mt-12 font-mono text-7xl font-semibold tabular-nums md:text-8xl">
|
||||
{{ progress.toLocaleString("fa-IR") }}<span class="text-accent">٪</span>
|
||||
</div>
|
||||
|
||||
<div class="mt-8 h-[3px] w-64 overflow-hidden rounded-full bg-line md:w-80">
|
||||
<div
|
||||
class="h-full bg-accent transition-all duration-200"
|
||||
:style="{ width: `${progress}%` }"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="mt-6 flex items-center gap-3 text-xs text-muted">
|
||||
<span class="size-1.5 animate-pulse rounded-full bg-accent" />
|
||||
{{ step }}
|
||||
<span class="animate-blink text-accent">▍</span>
|
||||
</div>
|
||||
</motion.div>
|
||||
</template>
|
||||
@@ -0,0 +1,103 @@
|
||||
<script setup lang="ts">
|
||||
import { Globe, Headset, Users } from "lucide-vue-next";
|
||||
import Reveal from "~/components/ui/Reveal.vue";
|
||||
import SectionHead from "~/components/ui/SectionHead.vue";
|
||||
|
||||
const TIMELINE = [
|
||||
{ year: "۱۳۸۶", text: "تأسیس آریا ایمن در تهران با تمرکز بر تجهیزات حفاظت فردی" },
|
||||
{ year: "۱۳۹۲", text: "توسعه شبکه توزیع به تمام ۳۱ استان کشور" },
|
||||
{ year: "۱۳۹۸", text: "راهاندازی آزمایشگاه کنترل کیفیت و تست تجهیزات" },
|
||||
{ year: "۱۴۰۲", text: "افتتاح مرکز تخصصی آموزش و بازرسی HSE" },
|
||||
];
|
||||
|
||||
const FEATURES = [
|
||||
{ icon: Globe, label: "نماینده رسمی ۴۰+ برند جهانی" },
|
||||
{ icon: Users, label: "تیم مهندسی و بازرسی HSE" },
|
||||
{ icon: Headset, label: "پشتیبانی ۲۴/۷ قراردادها" },
|
||||
];
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section
|
||||
id="about"
|
||||
aria-labelledby="about-title"
|
||||
class="relative overflow-hidden border-t border-line py-24 md:py-32"
|
||||
>
|
||||
<div class="absolute inset-0 bg-grid-fine opacity-50" />
|
||||
|
||||
<div class="relative mx-auto max-w-7xl px-5 md:px-8">
|
||||
<div class="grid items-center gap-14 lg:grid-cols-2">
|
||||
<!-- ---- image ---- -->
|
||||
<Reveal class="relative order-2 lg:order-1" :delay="0.1">
|
||||
<div class="relative overflow-hidden rounded-2xl border border-line">
|
||||
<img
|
||||
src="/images/about.jpg"
|
||||
alt="انبار تجهیزات ایمنی آریا ایمن"
|
||||
width="800"
|
||||
height="600"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
class="aspect-[4/3] w-full object-cover"
|
||||
/>
|
||||
<div class="absolute inset-0 bg-gradient-to-t from-bg/80 via-transparent to-transparent" />
|
||||
<div
|
||||
class="absolute bottom-5 start-5 flex items-center gap-4 rounded-xl border border-line bg-bg/80 px-5 py-4 backdrop-blur-md"
|
||||
>
|
||||
<span class="font-mono text-3xl font-bold text-accent">۱۸+</span>
|
||||
<span class="text-xs leading-5 text-muted">
|
||||
سال حفاظت از
|
||||
<br />
|
||||
جان نیروی کار
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="hazard absolute -top-3 -end-3 h-6 w-28 rounded-full opacity-90" />
|
||||
</Reveal>
|
||||
|
||||
<!-- ---- text ---- -->
|
||||
<div class="order-1 lg:order-2">
|
||||
<SectionHead heading-id="about-title" tag="۰۲ — درباره ما">
|
||||
<template #title>
|
||||
ایمنی برای ما شعار نیست؛
|
||||
<br />
|
||||
<span class="text-accent">قرارداد است.</span>
|
||||
</template>
|
||||
</SectionHead>
|
||||
<Reveal :delay="0.2">
|
||||
<p class="mt-6 leading-9 text-muted">
|
||||
از سال ۱۳۸۶، زمانی که اولین کلاه ایمنی را به یک کارگاه کوچک در
|
||||
جنوب تهران فروختیم، باور ما همین یک جمله بود: پشت هر تجهیز
|
||||
ایمنی، یک خانواده هست که منتظر بازگشت عزیزش است. امروز با بیش
|
||||
از ۸۵۰ سازمان، از پالایشگاهها تا معادن و سایتهای ساختمانی، در
|
||||
کنار کسانی هستیم که ایمنی را یک خط قرمز میدانند.
|
||||
</p>
|
||||
</Reveal>
|
||||
|
||||
<div class="mt-10 space-y-1">
|
||||
<Reveal v-for="(t, i) in TIMELINE" :key="t.year" :delay="0.25 + i * 0.07">
|
||||
<div
|
||||
class="group border-s-2 border-accent/30 ps-6 transition-colors duration-300 hover:border-accent"
|
||||
>
|
||||
<span class="font-mono text-sm font-bold text-accent">{{ t.year }}</span>
|
||||
<p class="mt-1 pb-5 text-sm leading-7 text-ink/75">{{ t.text }}</p>
|
||||
</div>
|
||||
</Reveal>
|
||||
</div>
|
||||
|
||||
<Reveal :delay="0.5">
|
||||
<div class="mt-4 flex flex-wrap gap-3">
|
||||
<span
|
||||
v-for="f in FEATURES"
|
||||
:key="f.label"
|
||||
class="inline-flex items-center gap-2 rounded-full border border-line bg-panel/60 px-4 py-2 text-xs text-ink/80 transition-colors hover:border-accent/50 hover:text-ink"
|
||||
>
|
||||
<component :is="f.icon" class="size-4 text-accent" />
|
||||
{{ f.label }}
|
||||
</span>
|
||||
</div>
|
||||
</Reveal>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
@@ -0,0 +1,190 @@
|
||||
<script setup lang="ts">
|
||||
import { Button as AButton, Form as AForm, FormItem as AFormItem, Input as AInput, Textarea as ATextarea } from "ant-design-vue";
|
||||
import type { Rule } from "ant-design-vue/es/form";
|
||||
import {
|
||||
CheckCircle2,
|
||||
Clock,
|
||||
Loader2,
|
||||
Mail,
|
||||
MapPin,
|
||||
Phone,
|
||||
Send,
|
||||
Siren,
|
||||
} from "lucide-vue-next";
|
||||
import Reveal from "~/components/ui/Reveal.vue";
|
||||
import SectionHead from "~/components/ui/SectionHead.vue";
|
||||
|
||||
const INFO = [
|
||||
{
|
||||
icon: MapPin,
|
||||
label: "نشانی",
|
||||
value: "تهران، خیابان کارگر شمالی، خیابان فر، کوچه دوم، پلاک ۱۲",
|
||||
},
|
||||
{ icon: Phone, label: "تلفن تماس", value: "۰۲۱ - ۹۱ ۰۰ ۸۸ ۰۰", ltr: true },
|
||||
{ icon: Mail, label: "ایمیل", value: "info@ariaiman.ir", ltr: true },
|
||||
{ icon: Clock, label: "ساعات کاری", value: "شنبه تا پنجشنبه — ۸:۰۰ تا ۱۷:۰۰" },
|
||||
];
|
||||
|
||||
const required = (message: string): Rule[] => [
|
||||
{ required: true, whitespace: true, message, trigger: "blur" },
|
||||
];
|
||||
|
||||
const rules: Record<string, Rule[]> = {
|
||||
name: required("لطفاً نام و نام خانوادگی را وارد کنید"),
|
||||
org: required("لطفاً نام سازمان را وارد کنید"),
|
||||
phone: required("لطفاً شماره تماس را وارد کنید"),
|
||||
};
|
||||
|
||||
const contact = useContactStore();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section
|
||||
id="contact"
|
||||
aria-labelledby="contact-title"
|
||||
class="relative overflow-hidden border-t border-line py-24 md:py-32"
|
||||
>
|
||||
<div class="absolute inset-0 bg-grid-fine opacity-40" />
|
||||
|
||||
<div class="relative mx-auto max-w-7xl px-5 md:px-8">
|
||||
<div class="grid gap-14 lg:grid-cols-2">
|
||||
<!-- ---- info ---- -->
|
||||
<div>
|
||||
<SectionHead
|
||||
heading-id="contact-title"
|
||||
tag="۰۷ — تماس"
|
||||
desc="فرم را پر کنید تا کارشناسان ما برای هماهنگی جلسه بازدید رایگان سایت شما تماس بگیرند؛ یا مستقیم با ما در ارتباط باشید."
|
||||
>
|
||||
<template #title>
|
||||
بیایید ایمنی را
|
||||
<br />
|
||||
با هم جدی بگیریم
|
||||
</template>
|
||||
</SectionHead>
|
||||
|
||||
<div class="mt-10 space-y-1">
|
||||
<Reveal v-for="(item, i) in INFO" :key="item.label" :delay="0.15 + i * 0.06">
|
||||
<div class="group flex items-center gap-4 border-b border-line/70 py-4">
|
||||
<span
|
||||
class="flex size-11 shrink-0 items-center justify-center rounded-lg border border-line text-accent transition-colors duration-300 group-hover:border-accent/50"
|
||||
>
|
||||
<component :is="item.icon" class="size-5" />
|
||||
</span>
|
||||
<div class="min-w-0">
|
||||
<div class="text-xs text-muted">{{ item.label }}</div>
|
||||
<div
|
||||
:class="`mt-1 text-sm font-medium ${item.ltr ? 'font-mono tracking-wider' : ''}`"
|
||||
:dir="item.ltr ? 'ltr' : 'rtl'"
|
||||
>
|
||||
{{ item.value }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Reveal>
|
||||
</div>
|
||||
|
||||
<Reveal :delay="0.45">
|
||||
<div class="mt-8 flex items-start gap-4 rounded-xl border border-hazard/30 bg-hazard/5 p-5">
|
||||
<Siren 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">
|
||||
برای مشتریان دارای قرارداد سازمانی، خط ویژه حوادث و تأمین
|
||||
فوری تجهیزات در تمام ساعات شبانهروز فعال است.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</Reveal>
|
||||
</div>
|
||||
|
||||
<!-- ---- form ---- -->
|
||||
<Reveal :delay="0.15">
|
||||
<div class="rounded-2xl border border-line bg-panel/60 p-6 backdrop-blur md:p-9">
|
||||
<div class="font-mono text-xs tracking-[0.25em] text-accent">// فرم درخواست مشاوره</div>
|
||||
<h3 class="mt-3 text-2xl font-black leading-snug">
|
||||
در کمتر از ۲۴ ساعت
|
||||
<br />
|
||||
با شما تماس میگیریم
|
||||
</h3>
|
||||
|
||||
<div
|
||||
v-if="contact.status === 'success'"
|
||||
class="mt-10 flex flex-col items-center rounded-xl border border-emerald-500/30 bg-emerald-500/5 p-10 text-center"
|
||||
>
|
||||
<CheckCircle2 class="size-14 text-emerald-400" />
|
||||
<div class="mt-5 text-xl font-black">درخواست شما ثبت شد</div>
|
||||
<p class="mt-2.5 max-w-sm text-sm leading-7 text-muted">
|
||||
کارشناسان ما تا ۲۴ ساعت آینده برای هماهنگی جلسه بازدید با
|
||||
شما تماس میگیرند.
|
||||
</p>
|
||||
<button
|
||||
type="button"
|
||||
class="mt-7 rounded-full border border-line px-7 py-3 text-sm transition-colors hover:border-accent hover:text-accent"
|
||||
@click="contact.reset"
|
||||
>
|
||||
ثبت درخواست جدید
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<AForm
|
||||
v-else
|
||||
class="contact-form"
|
||||
layout="vertical"
|
||||
:model="contact.form"
|
||||
:rules="rules"
|
||||
hide-required-mark
|
||||
@finish="contact.submit"
|
||||
>
|
||||
<div class="mt-8 grid gap-5 sm:grid-cols-2">
|
||||
<AFormItem name="name" label="نام و نام خانوادگی *" html-for="f-name">
|
||||
<AInput id="f-name" v-model:value="contact.form.name" placeholder="مثلاً: علی رضایی" />
|
||||
</AFormItem>
|
||||
<AFormItem name="org" label="نام سازمان *" html-for="f-org">
|
||||
<AInput
|
||||
id="f-org"
|
||||
v-model:value="contact.form.org"
|
||||
placeholder="مثلاً: شرکت پتروشیمی خلیج"
|
||||
/>
|
||||
</AFormItem>
|
||||
<AFormItem class="sm:col-span-2" name="phone" label="شماره تماس *" html-for="f-phone">
|
||||
<AInput
|
||||
id="f-phone"
|
||||
v-model:value="contact.form.phone"
|
||||
type="tel"
|
||||
dir="ltr"
|
||||
placeholder="0912 000 0000"
|
||||
/>
|
||||
</AFormItem>
|
||||
<AFormItem class="sm:col-span-2" name="message" label="شرح درخواست" html-for="f-msg">
|
||||
<ATextarea
|
||||
id="f-msg"
|
||||
v-model:value="contact.form.message"
|
||||
:rows="4"
|
||||
placeholder="تجهیزات موردنیاز، تعداد پرسنل یا هر نکتهای که لازم است بدانیم..."
|
||||
/>
|
||||
</AFormItem>
|
||||
<div class="sm:col-span-2">
|
||||
<AButton
|
||||
type="primary"
|
||||
html-type="submit"
|
||||
class="contact-submit"
|
||||
:disabled="contact.status === 'loading'"
|
||||
>
|
||||
<template v-if="contact.status === 'loading'">
|
||||
<Loader2 class="size-5 animate-spin" />
|
||||
در حال ارسال...
|
||||
</template>
|
||||
<template v-else>
|
||||
<Send class="size-5" />
|
||||
ارسال درخواست مشاوره
|
||||
</template>
|
||||
</AButton>
|
||||
</div>
|
||||
</div>
|
||||
</AForm>
|
||||
</div>
|
||||
</Reveal>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
@@ -0,0 +1,29 @@
|
||||
<script setup lang="ts">
|
||||
import { useInView } from "motion-v";
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{ end: number; suffix?: string; duration?: number }>(),
|
||||
{ suffix: "", duration: 1800 },
|
||||
);
|
||||
|
||||
const el = ref<HTMLSpanElement | null>(null);
|
||||
const inView = useInView(el, { once: true, margin: "-60px" });
|
||||
const val = ref(0);
|
||||
let raf = 0;
|
||||
|
||||
watch(inView, (v) => {
|
||||
if (!v) return;
|
||||
const t0 = performance.now();
|
||||
const tick = (t: number) => {
|
||||
const p = Math.min(1, (t - t0) / props.duration);
|
||||
val.value = Math.round(props.end * (1 - Math.pow(1 - p, 3)));
|
||||
if (p < 1) raf = requestAnimationFrame(tick);
|
||||
};
|
||||
raf = requestAnimationFrame(tick);
|
||||
});
|
||||
onBeforeUnmount(() => cancelAnimationFrame(raf));
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<span ref="el" class="tabular-nums">{{ val.toLocaleString("fa-IR") }}<span v-if="suffix" class="text-accent">{{ suffix }}</span></span>
|
||||
</template>
|
||||
@@ -0,0 +1,188 @@
|
||||
<script setup lang="ts">
|
||||
import {
|
||||
ArrowLeft,
|
||||
Award,
|
||||
BadgeCheck,
|
||||
ChevronDown,
|
||||
HardHat,
|
||||
ShieldCheck,
|
||||
} from "lucide-vue-next";
|
||||
|
||||
const CHIPS = [
|
||||
{ icon: ShieldCheck, label: "ISO 9001:2015" },
|
||||
{ icon: BadgeCheck, label: "CE CERTIFIED" },
|
||||
{ icon: Award, label: "EN STANDARDS" },
|
||||
];
|
||||
|
||||
const MINI_STATS = [
|
||||
{ value: "۱۸+", label: "سال تجربه در صنعت ایمنی" },
|
||||
{ value: "۸۵۰+", label: "سازمان تحت پوشش" },
|
||||
{ value: "۹۸٪", label: "رضایت مشتریان" },
|
||||
];
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section id="home" class="relative flex min-h-screen flex-col overflow-hidden">
|
||||
<!-- ---- background ---- -->
|
||||
<div class="absolute inset-0">
|
||||
<img
|
||||
src="/images/hero.jpg"
|
||||
alt="کارگر صنعتی با تجهیزات ایمنی کامل"
|
||||
width="1792"
|
||||
height="1008"
|
||||
fetchpriority="high"
|
||||
decoding="async"
|
||||
class="absolute inset-0 size-full object-cover"
|
||||
/>
|
||||
<div class="absolute inset-0 bg-gradient-to-l from-bg via-bg/80 to-bg/25" />
|
||||
<div class="absolute inset-0 bg-gradient-to-t from-bg via-transparent to-bg/60" />
|
||||
<div class="absolute inset-0 bg-grid opacity-50" />
|
||||
</div>
|
||||
|
||||
<!-- ---- side tape ---- -->
|
||||
<div class="tape-v absolute bottom-0 end-0 z-10 h-44 w-1.5 opacity-70" />
|
||||
|
||||
<!-- ---- content ---- -->
|
||||
<div
|
||||
class="relative z-10 mx-auto flex w-full max-w-7xl flex-1 items-center px-5 pb-24 pt-36 md:px-8"
|
||||
>
|
||||
<div class="grid w-full items-center gap-12 lg:grid-cols-12">
|
||||
<div class="lg:col-span-7">
|
||||
<div
|
||||
class="animate-fade-up-1 inline-flex items-center gap-2.5 rounded-full border border-accent/30 bg-accent/10 px-4 py-2 backdrop-blur"
|
||||
>
|
||||
<span class="size-1.5 animate-pulse rounded-full bg-accent" />
|
||||
<span class="text-xs font-medium text-accent">
|
||||
تأمینکننده رسمی تجهیزات حفاظت فردی (PPE)
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<h1
|
||||
class="animate-fade-up-2 mt-7 text-5xl font-black leading-[1.15] md:text-7xl md:leading-[1.1]"
|
||||
>
|
||||
ایمنی یعنی
|
||||
<br />
|
||||
<span
|
||||
class="mt-3 inline-block -rotate-1 rounded-lg bg-hazard px-4 py-1.5 text-bg shadow-[0_10px_50px_rgba(255,184,0,0.25)]"
|
||||
>
|
||||
بازگشت به خانه
|
||||
</span>
|
||||
</h1>
|
||||
|
||||
<p
|
||||
class="animate-fade-up-3 mt-7 max-w-xl text-base leading-9 text-ink/70 md:text-lg md:leading-10"
|
||||
>
|
||||
آریا ایمن با بیش از ۱۸ سال تجربه، تأمینکننده تخصصی تجهیزات ایمنی و
|
||||
حفاظت فردی برای سازمانهایی است که جان انسانها را جدی میگیرند؛ از
|
||||
کلاه ایمنی تا هارنس نجات، از مشاوره تا بازرسی و آموزش.
|
||||
</p>
|
||||
|
||||
<div class="animate-fade-up-4 mt-9 flex flex-wrap items-center gap-4">
|
||||
<a
|
||||
href="#contact"
|
||||
class="group inline-flex items-center gap-2.5 rounded-full bg-accent px-7 py-4 font-bold text-bg transition-all duration-300 hover:bg-accent-soft hover:shadow-[0_8px_45px_rgba(255,90,0,0.5)]"
|
||||
>
|
||||
درخواست مشاوره رایگان
|
||||
<ArrowLeft
|
||||
class="size-5 transition-transform duration-300 group-hover:-translate-x-1.5"
|
||||
/>
|
||||
</a>
|
||||
<a
|
||||
href="#products"
|
||||
class="inline-flex items-center gap-2.5 rounded-full border border-ink/25 px-7 py-4 font-bold text-ink backdrop-blur transition-colors duration-300 hover:border-accent hover:text-accent"
|
||||
>
|
||||
مشاهده محصولات
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="animate-fade-up-5 mt-10 flex flex-wrap gap-3">
|
||||
<span
|
||||
v-for="c in CHIPS"
|
||||
:key="c.label"
|
||||
class="inline-flex items-center gap-2 rounded-full border border-ink/15 bg-bg/50 px-4 py-2 font-mono text-[11px] tracking-wider text-ink/70 backdrop-blur transition-colors hover:border-accent/50 hover:text-ink"
|
||||
>
|
||||
<component :is="c.icon" class="size-4 text-accent" />
|
||||
{{ c.label }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ---- rotating badge + status card ---- -->
|
||||
<div class="hidden flex-col items-center gap-10 lg:col-span-5 lg:flex">
|
||||
<div class="animate-fade-up-6 relative">
|
||||
<div class="relative size-44">
|
||||
<div class="animate-spin-slow absolute inset-0">
|
||||
<svg viewBox="0 0 120 120" class="size-full">
|
||||
<defs>
|
||||
<path
|
||||
id="badge-circle"
|
||||
d="M60,60 m-47,0 a47,47 0 1,1 94,0 a47,47 0 1,1 -94,0"
|
||||
/>
|
||||
</defs>
|
||||
<text font-size="9" letter-spacing="2.6" class="fill-ink/60 font-mono">
|
||||
<textPath href="#badge-circle">
|
||||
ARIA IMEN SAFETY • ISO 9001 • CE CERTIFIED • EST 2007 •
|
||||
</textPath>
|
||||
</text>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="absolute inset-0 flex items-center justify-center">
|
||||
<span
|
||||
class="flex size-20 items-center justify-center rounded-full border border-accent/30 bg-accent/10"
|
||||
>
|
||||
<HardHat class="size-9 text-accent" />
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="animate-fade-up-7 w-full max-w-sm border border-line bg-bg/70 p-5 backdrop-blur-md"
|
||||
>
|
||||
<div class="flex items-center justify-between font-mono text-[11px]">
|
||||
<span class="text-muted">SITE STATUS</span>
|
||||
<span class="flex items-center gap-2 text-emerald-400">
|
||||
<span class="size-1.5 animate-pulse rounded-full bg-emerald-400" />
|
||||
SECURE
|
||||
</span>
|
||||
</div>
|
||||
<div class="mt-3.5 flex items-center justify-between font-mono text-[11px]">
|
||||
<span class="text-muted">PPE COMPLIANCE</span>
|
||||
<span class="font-semibold text-accent">۱۰۰٪</span>
|
||||
</div>
|
||||
<div class="mt-3.5 flex items-center justify-between font-mono text-[11px]">
|
||||
<span class="text-muted">آخرین بازرسی</span>
|
||||
<span>۱۴۰۴/۰۸/۱۲</span>
|
||||
</div>
|
||||
<div class="my-4 h-px bg-line" />
|
||||
<div class="font-mono text-[11px] leading-6 text-muted">
|
||||
سیستم پایش حرفهای آریا ایمن<span class="animate-blink text-accent">▍</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ---- scroll hint ---- -->
|
||||
<div class="animate-fade-up-9 absolute bottom-28 left-1/2 z-10 hidden md:block">
|
||||
<div class="-translate-x-1/2 flex flex-col items-center gap-2">
|
||||
<span class="font-mono text-[10px] tracking-[0.35em] text-muted">SCROLL</span>
|
||||
<ChevronDown class="size-4 animate-bounce text-accent" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ---- bottom bar ---- -->
|
||||
<div class="animate-fade-up-8 relative z-10 border-t border-ink/10 backdrop-blur-sm">
|
||||
<div class="mx-auto grid max-w-7xl grid-cols-1 gap-px bg-ink/10 sm:grid-cols-3">
|
||||
<div
|
||||
v-for="s in MINI_STATS"
|
||||
:key="s.label"
|
||||
class="flex items-baseline gap-4 bg-bg/60 px-6 py-5 backdrop-blur-md md:px-8"
|
||||
>
|
||||
<span class="text-2xl font-black text-ink md:text-3xl">{{ s.value }}</span>
|
||||
<span class="text-xs leading-5 text-muted md:text-sm">{{ s.label }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
@@ -0,0 +1,137 @@
|
||||
<script setup lang="ts">
|
||||
import { AnimatePresence, motion, useMotionValue, useSpring } from "motion-v";
|
||||
import { ArrowLeft } from "lucide-vue-next";
|
||||
import SectionHead from "~/components/ui/SectionHead.vue";
|
||||
|
||||
const INDUSTRIES = [
|
||||
{ name: "نفت و گاز", en: "OIL & GAS", count: "۱۴۰+", img: "/images/industries/oil-gas.jpg" },
|
||||
{
|
||||
name: "ساختمان و عمران",
|
||||
en: "CONSTRUCTION",
|
||||
count: "۲۱۰+",
|
||||
img: "/images/industries/construction.jpg",
|
||||
},
|
||||
{
|
||||
name: "پتروشیمی",
|
||||
en: "PETROCHEMICAL",
|
||||
count: "۹۰+",
|
||||
img: "/images/industries/petrochemical.jpg",
|
||||
},
|
||||
{ name: "صنایع معدنی", en: "MINING", count: "۷۵+", img: "/images/industries/mining.jpg" },
|
||||
{
|
||||
name: "برق و انرژی",
|
||||
en: "POWER & ENERGY",
|
||||
count: "۶۰+",
|
||||
img: "/images/industries/power-energy.jpg",
|
||||
},
|
||||
{
|
||||
name: "حملونقل و لجستیک",
|
||||
en: "TRANSPORT",
|
||||
count: "۴۵+",
|
||||
img: "/images/industries/transport.jpg",
|
||||
},
|
||||
];
|
||||
|
||||
const hovered = ref<number | null>(null);
|
||||
const x = useMotionValue(0);
|
||||
const y = useMotionValue(0);
|
||||
const sx = useSpring(x, { stiffness: 220, damping: 26, mass: 0.6 });
|
||||
const sy = useSpring(y, { stiffness: 220, damping: 26, mass: 0.6 });
|
||||
|
||||
const onMove = (e: MouseEvent) => {
|
||||
x.set(e.clientX);
|
||||
y.set(e.clientY);
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section
|
||||
id="industries"
|
||||
aria-labelledby="industries-title"
|
||||
class="relative border-t border-line py-24 md:py-32"
|
||||
@mousemove="onMove"
|
||||
>
|
||||
<div class="mx-auto max-w-7xl px-5 md:px-8">
|
||||
<SectionHead
|
||||
heading-id="industries-title"
|
||||
tag="۰۵ — صنایع"
|
||||
desc="جایی که دمای محیط از ۵۰ درجه گذر میکند یا ارتفاع کار به دهها متر میرسد، تجهیزات ما باید بینقص عمل کنند — و عمل میکنند."
|
||||
>
|
||||
<template #title>
|
||||
حضور در سختترین
|
||||
<br />
|
||||
میدانهای کاری
|
||||
</template>
|
||||
</SectionHead>
|
||||
|
||||
<div class="mt-16" @mouseleave="hovered = null">
|
||||
<motion.div
|
||||
v-for="(ind, i) in INDUSTRIES"
|
||||
:key="ind.name"
|
||||
v-bind="fade(i * 0.05)"
|
||||
data-hover
|
||||
:class="`group relative flex cursor-pointer items-center justify-between gap-4 border-t border-line px-2 py-7 transition-colors duration-300 hover:bg-panel/40 md:px-4 md:py-9 ${
|
||||
i === INDUSTRIES.length - 1 ? 'border-b' : ''
|
||||
}`"
|
||||
@mouseenter="hovered = i"
|
||||
>
|
||||
<div class="flex min-w-0 items-baseline gap-5 md:gap-8">
|
||||
<span class="shrink-0 font-mono text-xs text-muted">
|
||||
{{ faNum(String(i + 1).padStart(2, "0")) }}
|
||||
</span>
|
||||
<h3
|
||||
class="truncate text-2xl font-black transition-all duration-300 group-hover:-translate-x-2 group-hover:text-accent md:text-5xl"
|
||||
>
|
||||
{{ ind.name }}
|
||||
</h3>
|
||||
<span
|
||||
class="hidden shrink-0 font-mono text-[10px] tracking-[0.3em] text-muted/60 md:inline"
|
||||
>
|
||||
{{ ind.en }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex shrink-0 items-center gap-4 md:gap-8">
|
||||
<span class="text-xs text-muted md:text-sm">{{ ind.count }} پروژه</span>
|
||||
<span
|
||||
class="flex size-10 items-center justify-center rounded-full border border-line text-muted transition-all duration-300 group-hover:-translate-x-1.5 group-hover:border-accent group-hover:text-accent md:size-12"
|
||||
>
|
||||
<ArrowLeft class="size-4 md:size-5" />
|
||||
</span>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ---- floating preview (desktop) ---- -->
|
||||
<motion.div
|
||||
:style="{ x: sx, y: sy }"
|
||||
class="pointer-events-none fixed left-0 top-0 z-40 hidden lg:block"
|
||||
>
|
||||
<AnimatePresence>
|
||||
<motion.div
|
||||
v-if="hovered !== null"
|
||||
:key="hovered"
|
||||
:initial="{ opacity: 0, scale: 0.82, rotate: -3 }"
|
||||
:animate="{ opacity: 1, scale: 1, rotate: 0 }"
|
||||
:exit="{ opacity: 0, scale: 0.9, rotate: 2 }"
|
||||
:transition="{ duration: 0.35, ease: EASE }"
|
||||
class="relative -ml-40 -mt-28 h-56 w-80 overflow-hidden rounded-xl border border-accent/40 shadow-[0_25px_80px_rgba(0,0,0,0.6)]"
|
||||
>
|
||||
<img
|
||||
:src="INDUSTRIES[hovered]!.img"
|
||||
:alt="INDUSTRIES[hovered]!.name"
|
||||
decoding="async"
|
||||
class="absolute inset-0 size-full object-cover grayscale-[35%] transition-all duration-500"
|
||||
/>
|
||||
<div class="absolute inset-0 bg-accent/15 mix-blend-multiply" />
|
||||
<div class="absolute inset-0 bg-gradient-to-t from-bg/70 to-transparent" />
|
||||
<div
|
||||
class="absolute bottom-3 start-3 rounded-md border border-line bg-bg/80 px-3 py-1.5 font-mono text-[10px] tracking-widest text-ink backdrop-blur"
|
||||
>
|
||||
{{ INDUSTRIES[hovered]!.en }}
|
||||
</div>
|
||||
</motion.div>
|
||||
</AnimatePresence>
|
||||
</motion.div>
|
||||
</section>
|
||||
</template>
|
||||
@@ -0,0 +1,209 @@
|
||||
<script setup lang="ts">
|
||||
import { AnimatePresence, motion } from "motion-v";
|
||||
import { ArrowLeft, BadgeCheck, PackageCheck, ShieldCheck } from "lucide-vue-next";
|
||||
import Reveal from "~/components/ui/Reveal.vue";
|
||||
import SectionHead from "~/components/ui/SectionHead.vue";
|
||||
|
||||
type Product = {
|
||||
code: string;
|
||||
name: string;
|
||||
en: string;
|
||||
desc: string;
|
||||
img: string;
|
||||
specs: string[];
|
||||
};
|
||||
|
||||
const PRODUCTS: Product[] = [
|
||||
{
|
||||
code: "AP-101",
|
||||
name: "کلاه ایمنی",
|
||||
en: "SAFETY HELMET",
|
||||
img: "/images/products/helmet.jpg",
|
||||
desc: "کلاههای ایمنی با بدنه HDPE مقاوم به ضربه و ترتیهبند ضدتعریق؛ با قابلیت نصب هدفون و شیشه محافظ صورت برای محیطهای ساختمانی و صنعتی.",
|
||||
specs: ["EN 397", "مقاوم به ضربه ۵۰ ژول", "بدنه HDPE"],
|
||||
},
|
||||
{
|
||||
code: "AP-205",
|
||||
name: "دستکش ضدبرش",
|
||||
en: "CUT-RESISTANT GLOVE",
|
||||
img: "/images/products/gloves.jpg",
|
||||
desc: "دستکشهای سطح ۵ ضدبرش با پوشش نیتریل؛ طراحیشده برای کار با ورق فلز، شیشه و ابزار برنده با چسبندگی عالی در محیط خشک و چرب.",
|
||||
specs: ["EN 388 — 4X43C", "سطح ۵ ضدبرش", "پوشش نیتریل"],
|
||||
},
|
||||
{
|
||||
code: "AP-310",
|
||||
name: "کفش ایمنی",
|
||||
en: "SAFETY BOOTS",
|
||||
img: "/images/products/shoes.jpg",
|
||||
desc: "کفشهای ایمنی با پنجه فولادی و کف مقاوم در برابر سوراخشدگی و روغن؛ راحتی تمامروز برای شیفتهای طولانی در سایت.",
|
||||
specs: ["EN ISO 20345", "پنجه فولادی", "کف ضدروغن"],
|
||||
},
|
||||
{
|
||||
code: "AP-412",
|
||||
name: "عینک ایمنی",
|
||||
en: "SAFETY GOGGLES",
|
||||
img: "/images/products/goggles.jpg",
|
||||
desc: "عینکهای محافظ ضدخش با پوشش UV400 و تهویه ضدمه؛ سازگار با عینک طبی برای کارهای جوشکاری، سنگزنی و محیطهای شیمیایی.",
|
||||
specs: ["EN 166", "عدسی ضدخش", "پوشش UV400"],
|
||||
},
|
||||
{
|
||||
code: "AP-508",
|
||||
name: "هارنس ضدسقوط",
|
||||
en: "FULL BODY HARNESS",
|
||||
img: "/images/products/harness.jpg",
|
||||
desc: "هارنس تمامبدنی با دو شیر پیچی و نوارهای دوختهشده با نخ نارنجی سیگنال؛ تستشده برای کار در ارتفاع با ظرفیت ۱۰۰ کیلوگرم.",
|
||||
specs: ["EN 361", "ظرفیت ۱۰۰ کیلوگرم", "شیر دوگانه"],
|
||||
},
|
||||
{
|
||||
code: "AP-615",
|
||||
name: "لباس کار بازتابنده",
|
||||
en: "HI-VIS WORKWEAR",
|
||||
img: "/images/products/vest.jpg",
|
||||
desc: "جلیقهها و لباسهای کار بازتابنده کلاس ۲ با نوارهای ۳M؛ دیدهشدن کامل پرسنل در شب، مه و محیطهای پرتردد خودرویی.",
|
||||
specs: ["EN ISO 20471", "کلاس ۲", "نوار ۳M"],
|
||||
},
|
||||
];
|
||||
|
||||
const TRUST = [
|
||||
{
|
||||
icon: BadgeCheck,
|
||||
title: "گارانتی اصالت کالا",
|
||||
desc: "تمام محصولات با فاکتور رسمی و کد رهگیری اصالت",
|
||||
},
|
||||
{
|
||||
icon: PackageCheck,
|
||||
title: "تست نمونه قبل از خرید",
|
||||
desc: "نمونههای نمایشی برای ارزیابی تیم HSE شما",
|
||||
},
|
||||
{
|
||||
icon: ShieldCheck,
|
||||
title: "امکان قرارداد سالانه",
|
||||
desc: "قیمت ثابت و تأمین مستمر برای سازمانهای بزرگ",
|
||||
},
|
||||
];
|
||||
|
||||
const active = ref(0);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section id="products" aria-labelledby="products-title" class="relative py-24 md:py-32">
|
||||
<div class="mx-auto max-w-7xl px-5 md:px-8">
|
||||
<div class="flex flex-wrap items-end justify-between gap-6">
|
||||
<SectionHead
|
||||
heading-id="products-title"
|
||||
tag="۰۱ — محصولات"
|
||||
desc="هر محصول پیش از عرضه، زیر ذرهبین کنترل کیفیت و تطبیق با استانداردهای جهانی قرار میگیرد. روی هر پنل کلیک کنید."
|
||||
>
|
||||
<template #title>
|
||||
خط اول دفاع،
|
||||
<br />
|
||||
تجهیزات ماست
|
||||
</template>
|
||||
</SectionHead>
|
||||
<Reveal :delay="0.2" class="hidden md:block">
|
||||
<a
|
||||
href="#contact"
|
||||
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" />
|
||||
</a>
|
||||
</Reveal>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mx-auto mt-14 max-w-7xl px-5 md:px-8">
|
||||
<div class="flex flex-col gap-2 md:h-[74vh] md:min-h-[580px] md:flex-row">
|
||||
<div
|
||||
v-for="(p, i) in PRODUCTS"
|
||||
:key="p.code"
|
||||
data-hover
|
||||
:class="`group relative cursor-pointer overflow-hidden rounded-xl border transition-all duration-700 ease-[cubic-bezier(0.22,1,0.36,1)] ${
|
||||
active === i
|
||||
? 'h-[500px] flex-[3.4] border-accent/60 md:h-auto'
|
||||
: 'h-24 flex-[1] border-line hover:border-ink/30 md:h-auto'
|
||||
}`"
|
||||
@mouseenter="active = i"
|
||||
@click="active = i"
|
||||
>
|
||||
<img
|
||||
:src="p.img"
|
||||
:alt="p.name"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
:class="`absolute inset-0 size-full object-cover transition-all duration-700 ${
|
||||
active === i ? 'scale-100 grayscale-0' : 'scale-110 grayscale group-hover:grayscale-0'
|
||||
}`"
|
||||
/>
|
||||
<div
|
||||
:class="`absolute inset-0 transition-opacity duration-700 ${
|
||||
active === i
|
||||
? 'bg-gradient-to-t from-bg via-bg/35 to-bg/5'
|
||||
: 'bg-gradient-to-t from-bg/95 via-bg/30 to-transparent'
|
||||
}`"
|
||||
/>
|
||||
|
||||
<div class="absolute inset-x-0 top-0 flex items-center justify-between p-5">
|
||||
<span class="font-mono text-[10px] tracking-widest text-ink/60">{{ p.code }}</span>
|
||||
<span
|
||||
:class="`font-mono text-xs transition-colors duration-500 ${
|
||||
active === i ? 'text-accent' : 'text-ink/40'
|
||||
}`"
|
||||
>
|
||||
{{ faNum(String(i + 1).padStart(2, "0")) }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="absolute inset-x-0 bottom-0 p-5 md:p-6">
|
||||
<h3
|
||||
:class="`font-black transition-all duration-500 ${
|
||||
active === i ? 'text-2xl' : 'text-base md:text-sm'
|
||||
}`"
|
||||
>
|
||||
{{ p.name }}
|
||||
</h3>
|
||||
<p class="mt-1 font-mono text-[10px] tracking-[0.2em] text-muted">{{ p.en }}</p>
|
||||
<AnimatePresence>
|
||||
<motion.div
|
||||
v-if="active === i"
|
||||
:initial="{ opacity: 0, y: 18 }"
|
||||
:animate="{ opacity: 1, y: 0 }"
|
||||
:exit="{ opacity: 0, y: 10 }"
|
||||
:transition="{ duration: 0.45, delay: 0.12, ease: EASE }"
|
||||
>
|
||||
<p class="mt-4 max-w-md text-sm leading-8 text-ink/75">{{ p.desc }}</p>
|
||||
<div class="mt-4 flex flex-wrap gap-2">
|
||||
<span
|
||||
v-for="s in p.specs"
|
||||
:key="s"
|
||||
class="rounded-full border border-accent/40 bg-accent/10 px-3 py-1 font-mono text-[10px] text-accent"
|
||||
>
|
||||
{{ s }}
|
||||
</span>
|
||||
</div>
|
||||
</motion.div>
|
||||
</AnimatePresence>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="mx-auto mt-10 grid max-w-7xl gap-px overflow-hidden rounded-xl border border-line bg-line md:grid-cols-3"
|
||||
>
|
||||
<Reveal v-for="(t, i) in TRUST" :key="t.title" :delay="i * 0.08">
|
||||
<div class="flex h-full items-center gap-4 bg-panel/60 p-6">
|
||||
<span
|
||||
class="flex size-12 shrink-0 items-center justify-center rounded-xl bg-accent/10 text-accent"
|
||||
>
|
||||
<component :is="t.icon" class="size-6" />
|
||||
</span>
|
||||
<div>
|
||||
<div class="font-bold">{{ t.title }}</div>
|
||||
<div class="mt-1 text-xs leading-6 text-muted">{{ t.desc }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</Reveal>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
@@ -0,0 +1,142 @@
|
||||
<script setup lang="ts">
|
||||
import { AnimatePresence, motion } from "motion-v";
|
||||
import { ClipboardCheck, Gauge, GraduationCap, Plus, Truck } from "lucide-vue-next";
|
||||
import Reveal from "~/components/ui/Reveal.vue";
|
||||
import SectionHead from "~/components/ui/SectionHead.vue";
|
||||
import { serviceSchema } from "#shared/seo/schema";
|
||||
|
||||
const SERVICES = [
|
||||
{
|
||||
icon: ClipboardCheck,
|
||||
title: "بازرسی و ارزیابی ریسک",
|
||||
desc: "تیم مهندسی ما با بازدید از سایت شما، خطرات را شناسایی، اولویتبندی و برای هر کدام راهکار اجرایی مشخص با برآورد هزینه ارائه میدهد.",
|
||||
items: [
|
||||
"ارزیابی HAZOP و HAZID",
|
||||
"شناسایی و اولویتبندی خطرات",
|
||||
"گزارش مدیریتی با راهکار اجرایی",
|
||||
],
|
||||
},
|
||||
{
|
||||
icon: GraduationCap,
|
||||
title: "آموزش تخصصی ایمنی",
|
||||
desc: "از دورههای عمومی تا تربیت مربی؛ آموزشهای عملی و میدانی که ایمنی را از دفتر کلانها به رفتار روزمره پرسنل تبدیل میکند.",
|
||||
items: [
|
||||
"دورههای عمومی و تخصصی HSE",
|
||||
"تربیت مربی ایمنی سایت",
|
||||
"مانور و شبیهسازی شرایط اضطراری",
|
||||
],
|
||||
},
|
||||
{
|
||||
icon: Gauge,
|
||||
title: "تست و کالیبراسیون تجهیزات",
|
||||
desc: "تجهیزات ایمنی فقط وقتی قابل اعتمادند که تست شده باشند. تست دورهای، سرویس و صدور گواهی معتبر را به تیم تخصصی ما بسپارید.",
|
||||
items: [
|
||||
"تست هارنس و لاین نجات",
|
||||
"کالیبراسیون آشکارسازهای گاز",
|
||||
"سرویس دورهای و صدور گواهی",
|
||||
],
|
||||
},
|
||||
{
|
||||
icon: Truck,
|
||||
title: "تأمین و لجستیک سازمانی",
|
||||
desc: "با قرارداد سالانه، قیمتگذاری شفاف و انبار محلی در سایت شما، نگرانی کمبود تجهیزات را از فهرست دغدغههایتان حذف کنید.",
|
||||
items: [
|
||||
"قرارداد سالانه با قیمت ثابت",
|
||||
"انبار محلی در سایت شما",
|
||||
"تحویل سراسری در ۴۸ ساعت",
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
useJsonLd(
|
||||
SERVICES.map((s) => serviceSchema({ name: s.title, description: s.desc })),
|
||||
"services",
|
||||
);
|
||||
|
||||
const open = ref(0);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section id="services" aria-labelledby="services-title" class="border-t border-line py-24 md:py-32">
|
||||
<div class="mx-auto max-w-7xl px-5 md:px-8">
|
||||
<SectionHead
|
||||
heading-id="services-title"
|
||||
tag="۰۳ — خدمات"
|
||||
desc="ما در آریا ایمن، تجهیزات را تحویل میدهیم و کنار شما میمانیم؛ از نخستین ارزیابی ریسک تا آخرین تست دورهای."
|
||||
>
|
||||
<template #title>
|
||||
فراتر از تأمین؛
|
||||
<br />
|
||||
همراهی کامل ایمنی
|
||||
</template>
|
||||
</SectionHead>
|
||||
|
||||
<div class="mt-16">
|
||||
<Reveal v-for="(s, i) in SERVICES" :key="s.title" :delay="i * 0.05">
|
||||
<div :class="`border-t border-line ${i === SERVICES.length - 1 ? 'border-b' : ''}`">
|
||||
<button
|
||||
class="group flex w-full items-center gap-5 py-7 text-start md:gap-10 md:py-9"
|
||||
@click="open = open === i ? -1 : i"
|
||||
>
|
||||
<span
|
||||
:class="`font-mono text-sm transition-colors duration-300 md:text-base ${
|
||||
open === i ? 'text-accent' : 'text-muted'
|
||||
}`"
|
||||
>
|
||||
{{ faNum(String(i + 1).padStart(2, "0")) }}
|
||||
</span>
|
||||
<span
|
||||
:class="`flex-1 text-2xl font-black transition-colors duration-300 md:text-4xl ${
|
||||
open === i ? 'text-accent' : 'text-ink group-hover:text-accent'
|
||||
}`"
|
||||
>
|
||||
{{ s.title }}
|
||||
</span>
|
||||
<span
|
||||
:class="`hidden size-12 shrink-0 items-center justify-center rounded-full border transition-all duration-500 md:flex ${
|
||||
open === i
|
||||
? 'rotate-45 border-accent bg-accent text-bg'
|
||||
: 'border-line text-muted group-hover:border-accent/50 group-hover:text-accent'
|
||||
}`"
|
||||
>
|
||||
<Plus class="size-5" />
|
||||
</span>
|
||||
</button>
|
||||
|
||||
<AnimatePresence :initial="false">
|
||||
<motion.div
|
||||
v-if="open === i"
|
||||
:initial="{ height: 0, opacity: 0 }"
|
||||
:animate="{ height: 'auto', opacity: 1 }"
|
||||
:exit="{ height: 0, opacity: 0 }"
|
||||
:transition="{ duration: 0.55, ease: EASE }"
|
||||
class="overflow-hidden"
|
||||
>
|
||||
<div class="grid gap-8 pb-10 md:grid-cols-2 md:ps-16">
|
||||
<div class="flex items-start gap-4">
|
||||
<span
|
||||
class="flex size-12 shrink-0 items-center justify-center rounded-xl bg-accent/10 text-accent"
|
||||
>
|
||||
<component :is="s.icon" class="size-6" />
|
||||
</span>
|
||||
<p class="text-sm leading-8 text-muted">{{ s.desc }}</p>
|
||||
</div>
|
||||
<ul class="space-y-3.5">
|
||||
<li
|
||||
v-for="it in s.items"
|
||||
:key="it"
|
||||
class="flex items-center gap-3 text-sm text-ink/80"
|
||||
>
|
||||
<span class="size-1.5 shrink-0 rounded-full bg-accent" />
|
||||
{{ it }}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</motion.div>
|
||||
</AnimatePresence>
|
||||
</div>
|
||||
</Reveal>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
@@ -0,0 +1,97 @@
|
||||
<script setup lang="ts">
|
||||
import { FileSearch, ShieldCheck } from "lucide-vue-next";
|
||||
import Reveal from "~/components/ui/Reveal.vue";
|
||||
import SectionHead from "~/components/ui/SectionHead.vue";
|
||||
|
||||
const STANDARDS = [
|
||||
{ code: "EN 397", label: "کلاه ایمنی صنعتی" },
|
||||
{ code: "EN 388", label: "دستکشهای مکانیکی" },
|
||||
{ code: "EN 166", label: "محافظ چشم و صورت" },
|
||||
{ code: "EN 361", label: "هارنس ضدسقوط" },
|
||||
{ code: "ISO 20345", label: "کفش ایمنی" },
|
||||
{ code: "ISO 9001", label: "سیستم مدیریت کیفیت" },
|
||||
];
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section
|
||||
id="standards"
|
||||
aria-labelledby="standards-title"
|
||||
class="relative overflow-hidden border-t border-line py-24 md:py-32"
|
||||
>
|
||||
<!-- watermark -->
|
||||
<div
|
||||
aria-hidden="true"
|
||||
class="text-outline pointer-events-none absolute -bottom-14 -start-8 select-none font-mono text-[24vw] font-bold leading-none opacity-60"
|
||||
>
|
||||
CE
|
||||
</div>
|
||||
|
||||
<div class="relative mx-auto max-w-7xl px-5 md:px-8">
|
||||
<div class="grid items-center gap-14 lg:grid-cols-12">
|
||||
<div class="lg:col-span-5">
|
||||
<SectionHead
|
||||
heading-id="standards-title"
|
||||
tag="۰۴ — استانداردها"
|
||||
desc="ما فقط تجهیزاتی را عرضه میکنیم که تأییدیه معتبر بینالمللی و تست آزمایشگاهی داشته باشند؛ بدون استثنا."
|
||||
>
|
||||
<template #title>
|
||||
مهرتأیید جهانی
|
||||
<br />
|
||||
روی هر محصول
|
||||
</template>
|
||||
</SectionHead>
|
||||
<Reveal :delay="0.25">
|
||||
<div class="mt-8 flex items-start gap-4 rounded-xl border border-accent/25 bg-accent/5 p-5">
|
||||
<FileSearch class="size-6 shrink-0 text-accent" />
|
||||
<p class="text-sm leading-8 text-ink/80">
|
||||
شماره سریال تمام محصولات در پایگاه داده استانداردهای اروپا
|
||||
قابل استعلام است و گواهی تست هر بچ تحویل مشتری میشود.
|
||||
</p>
|
||||
</div>
|
||||
</Reveal>
|
||||
<Reveal :delay="0.35">
|
||||
<a
|
||||
href="#contact"
|
||||
class="group mt-8 inline-flex items-center gap-2.5 rounded-full border border-line px-6 py-3.5 text-sm font-bold transition-colors hover:border-accent hover:text-accent"
|
||||
>
|
||||
<ShieldCheck class="size-4 text-accent" />
|
||||
درخواست گواهی تست محصولات
|
||||
</a>
|
||||
</Reveal>
|
||||
</div>
|
||||
|
||||
<div class="grid gap-4 sm:grid-cols-2 lg:col-span-7 xl:grid-cols-3">
|
||||
<Reveal v-for="(s, i) in STANDARDS" :key="s.code" :delay="i * 0.06">
|
||||
<div
|
||||
data-hover
|
||||
class="group relative h-full border border-line bg-panel/50 p-6 text-center transition-all duration-500 hover:-translate-y-1.5 hover:border-accent/50 hover:bg-panel"
|
||||
>
|
||||
<span class="absolute end-3 top-3 font-mono text-[9px] tracking-[0.2em] text-muted/50">
|
||||
CERT
|
||||
</span>
|
||||
<div
|
||||
class="mx-auto flex size-24 items-center justify-center rounded-full border border-dashed border-ink/20 transition-all duration-500 group-hover:rotate-12 group-hover:border-accent/60"
|
||||
>
|
||||
<div>
|
||||
<div
|
||||
class="font-mono text-base font-bold text-ink transition-colors duration-300 group-hover:text-accent"
|
||||
>
|
||||
{{ s.code }}
|
||||
</div>
|
||||
<div
|
||||
class="mx-auto mt-1.5 h-px w-8 bg-line transition-colors duration-300 group-hover:bg-accent/50"
|
||||
/>
|
||||
<div class="mt-1.5 font-mono text-[8px] tracking-[0.25em] text-muted">
|
||||
EURO NORM
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-4 text-sm font-medium text-ink/85">{{ s.label }}</div>
|
||||
</div>
|
||||
</Reveal>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
@@ -0,0 +1,38 @@
|
||||
<script setup lang="ts">
|
||||
import Reveal from "~/components/ui/Reveal.vue";
|
||||
import CountUp from "./CountUp.vue";
|
||||
|
||||
const STATS = [
|
||||
{ end: 18, suffix: "+", label: "سال تجربه در صنعت ایمنی", note: "SINCE 2007" },
|
||||
{ end: 2400, suffix: "+", label: "کد کالای ایمنی", note: "PPE CATALOG" },
|
||||
{ end: 850, suffix: "+", label: "مشتری سازمانی فعال", note: "B2B CLIENTS" },
|
||||
{ end: 98, suffix: "٪", label: "رضایت مشتریان", note: "SATISFACTION" },
|
||||
];
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section class="relative" aria-label="آمار و دستاوردهای آریا ایمن">
|
||||
<div class="grid grid-cols-2 gap-px border-y border-line bg-line lg:grid-cols-4">
|
||||
<div
|
||||
v-for="(s, i) in STATS"
|
||||
:key="s.label"
|
||||
class="group relative bg-bg p-8 transition-colors duration-500 hover:bg-panel md:p-10"
|
||||
>
|
||||
<span
|
||||
class="absolute end-5 top-5 font-mono text-[10px] tracking-[0.25em] text-muted/50 transition-colors duration-500 group-hover:text-accent/70"
|
||||
>
|
||||
{{ s.note }}
|
||||
</span>
|
||||
<Reveal :delay="i * 0.08">
|
||||
<div class="text-4xl font-black md:text-6xl">
|
||||
<CountUp :end="s.end" :suffix="s.suffix" />
|
||||
</div>
|
||||
<div class="mt-3 text-sm text-muted">{{ s.label }}</div>
|
||||
</Reveal>
|
||||
<span
|
||||
class="absolute bottom-0 start-0 h-0.5 w-0 bg-accent transition-all duration-500 group-hover:w-full"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
@@ -0,0 +1,35 @@
|
||||
<script setup lang="ts">
|
||||
import { ShieldCheck } from "lucide-vue-next";
|
||||
|
||||
const ITEMS = [
|
||||
"ISO 9001:2015",
|
||||
"CE CERTIFIED",
|
||||
"گارانتی اصالت کالا",
|
||||
"تحویل سراسری کشوری",
|
||||
"مشاوره و بازرسی تخصصی رایگان",
|
||||
"EN STANDARDS",
|
||||
"پشتیبانی ۲۴/۷ قراردادهای سازمانی",
|
||||
"تست نمونه قبل از خرید",
|
||||
];
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section aria-hidden="true" class="pointer-events-none relative z-20 overflow-hidden py-10">
|
||||
<div class="-rotate-[1.6deg] scale-[1.04]">
|
||||
<div class="hazard h-2.5" />
|
||||
<div dir="ltr" class="overflow-hidden bg-hazard py-3.5 text-bg">
|
||||
<div class="animate-marquee flex w-max">
|
||||
<span
|
||||
v-for="(item, i) in [...ITEMS, ...ITEMS]"
|
||||
:key="i"
|
||||
class="flex items-center gap-7 px-7 text-sm font-extrabold whitespace-nowrap"
|
||||
>
|
||||
{{ item }}
|
||||
<ShieldCheck class="size-4 shrink-0" :stroke-width="2.5" />
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="hazard h-2.5" />
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
@@ -0,0 +1,94 @@
|
||||
<script setup lang="ts">
|
||||
import { AnimatePresence, motion } from "motion-v";
|
||||
import { Quote } from "lucide-vue-next";
|
||||
import SectionHead from "~/components/ui/SectionHead.vue";
|
||||
|
||||
const QUOTES = [
|
||||
{
|
||||
text: "آریا ایمن فقط تأمینکننده نیست؛ شریک ایمنی ماست. بازرسیهای دورهای و آموزشهای میدانیشان نرخ حوادث سایت را به کمترین رقم تاریخ مجموعه رساند.",
|
||||
name: "مهندس رضا کاظمی",
|
||||
role: "مدیر HSE — مجتمع پتروشیمی خلیج فارس",
|
||||
},
|
||||
{
|
||||
text: "کیفیت تجهیزات و سرعت پاسخگویی در سطحی بود که قرارداد سالانه را بدون هیچ تردیدی تمدید کردیم؛ از خط تولید تا دفتر مرکزی.",
|
||||
name: "سارا محمدی",
|
||||
role: "سرپرست تدارکات — هلدینگ ساختمانی آرکان",
|
||||
},
|
||||
{
|
||||
text: "۱۴۰ کیلومتر دورتر از سایت، در عرض ۲۴ ساعت تجهیزات حیاتی را تحویل گرفتیم. به این میگویند شریک واقعی کاری.",
|
||||
name: "امیرحسین راد",
|
||||
role: "مدیر پروژه — صنایع معدنی کاوه",
|
||||
},
|
||||
];
|
||||
|
||||
const idx = ref(0);
|
||||
const q = computed(() => QUOTES[idx.value]!);
|
||||
let t: ReturnType<typeof setInterval> | undefined;
|
||||
|
||||
onMounted(() => {
|
||||
t = setInterval(() => (idx.value = (idx.value + 1) % QUOTES.length), 7000);
|
||||
});
|
||||
onBeforeUnmount(() => clearInterval(t));
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section
|
||||
aria-labelledby="testimonials-title"
|
||||
class="relative overflow-hidden border-t border-line py-24 md:py-32"
|
||||
>
|
||||
<div class="absolute inset-0 bg-grid opacity-40" />
|
||||
<div
|
||||
class="pointer-events-none absolute -top-10 -end-10 select-none font-mono text-[18vw] font-bold leading-none text-outline opacity-50"
|
||||
>
|
||||
"
|
||||
</div>
|
||||
|
||||
<div class="relative mx-auto max-w-4xl px-5 text-center md:px-8">
|
||||
<SectionHead
|
||||
heading-id="testimonials-title"
|
||||
center
|
||||
tag="۰۶ — اعتماد"
|
||||
title="آنچه مشتریان ما میگویند"
|
||||
/>
|
||||
|
||||
<div class="mt-14 flex min-h-[320px] flex-col items-center md:min-h-[280px]">
|
||||
<span
|
||||
class="flex size-16 items-center justify-center rounded-full border border-accent/30 bg-accent/10"
|
||||
>
|
||||
<Quote class="size-7 text-accent" />
|
||||
</span>
|
||||
|
||||
<AnimatePresence mode="wait">
|
||||
<motion.blockquote
|
||||
:key="idx"
|
||||
:initial="{ opacity: 0, y: 26 }"
|
||||
:animate="{ opacity: 1, y: 0 }"
|
||||
:exit="{ opacity: 0, y: -26 }"
|
||||
:transition="{ duration: 0.55, ease: EASE }"
|
||||
class="mt-8"
|
||||
>
|
||||
<p class="text-xl font-bold leading-[2.1] text-ink/90 md:text-2xl md:leading-[2]">
|
||||
«{{ q.text }}»
|
||||
</p>
|
||||
<footer class="mt-8">
|
||||
<div class="text-lg font-black">{{ q.name }}</div>
|
||||
<div class="mt-2 font-mono text-xs text-muted">{{ q.role }}</div>
|
||||
</footer>
|
||||
</motion.blockquote>
|
||||
</AnimatePresence>
|
||||
</div>
|
||||
|
||||
<div class="mt-12 flex items-center justify-center gap-3">
|
||||
<button
|
||||
v-for="(_, i) in QUOTES"
|
||||
:key="i"
|
||||
:aria-label="`نظر شماره ${faNum(i + 1)}`"
|
||||
:class="`h-1.5 rounded-full transition-all duration-500 ${
|
||||
i === idx ? 'w-12 bg-accent' : 'w-4 bg-line hover:bg-muted'
|
||||
}`"
|
||||
@click="idx = i"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
@@ -0,0 +1,19 @@
|
||||
<script setup lang="ts">
|
||||
import { ShieldCheck } from "lucide-vue-next";
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<a href="#home" class="flex items-center gap-3" aria-label="آریا ایمن">
|
||||
<span
|
||||
class="flex size-10 items-center justify-center rounded-xl bg-accent text-bg shadow-[0_0_28px_rgba(255,90,0,0.35)]"
|
||||
>
|
||||
<ShieldCheck class="size-6" />
|
||||
</span>
|
||||
<span class="leading-tight">
|
||||
<span class="block text-lg font-black">آریا ایمن</span>
|
||||
<span class="block font-mono text-[9px] tracking-[0.32em] text-muted">
|
||||
ARIA IMEN CO.
|
||||
</span>
|
||||
</span>
|
||||
</a>
|
||||
</template>
|
||||
@@ -0,0 +1,12 @@
|
||||
<script setup lang="ts">
|
||||
import { motion } from "motion-v";
|
||||
|
||||
const props = withDefaults(defineProps<{ delay?: number }>(), { delay: 0 });
|
||||
const motionProps = computed(() => fade(props.delay, 34));
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<motion.div v-bind="motionProps">
|
||||
<slot />
|
||||
</motion.div>
|
||||
</template>
|
||||
@@ -0,0 +1,42 @@
|
||||
<script setup lang="ts">
|
||||
import Reveal from "./Reveal.vue";
|
||||
|
||||
withDefaults(
|
||||
defineProps<{
|
||||
tag: string;
|
||||
/** plain-text title; use the #title slot for rich markup (line breaks, spans) */
|
||||
title?: string;
|
||||
desc?: string;
|
||||
center?: boolean;
|
||||
headingId?: string;
|
||||
}>(),
|
||||
{ center: false },
|
||||
);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div :class="center ? 'text-center' : ''">
|
||||
<Reveal>
|
||||
<div :class="`flex items-center gap-3 ${center ? 'justify-center' : ''}`">
|
||||
<span class="font-mono text-sm text-accent">//</span>
|
||||
<span class="font-mono text-xs tracking-[0.25em] text-muted">
|
||||
{{ tag }}
|
||||
</span>
|
||||
<span class="h-px w-14 bg-line" />
|
||||
</div>
|
||||
</Reveal>
|
||||
<Reveal :delay="0.08">
|
||||
<h2
|
||||
:id="headingId"
|
||||
class="mt-5 text-3xl font-black leading-[1.25] md:text-5xl md:leading-[1.2]"
|
||||
>
|
||||
<slot name="title">{{ title }}</slot>
|
||||
</h2>
|
||||
</Reveal>
|
||||
<Reveal v-if="desc" :delay="0.16">
|
||||
<p :class="`mt-5 max-w-xl leading-8 text-muted ${center ? 'mx-auto' : ''}`">
|
||||
{{ desc }}
|
||||
</p>
|
||||
</Reveal>
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,16 @@
|
||||
import { toJsonLd } from "#shared/seo/schema";
|
||||
|
||||
type Ld = Record<string, unknown>;
|
||||
|
||||
/** Renders JSON-LD <script> tags at the start of <body> (replaces the React <JsonLd> component). */
|
||||
export function useJsonLd(data: Ld | Ld[], id = "site") {
|
||||
const items = Array.isArray(data) ? data : [data];
|
||||
useHead({
|
||||
script: items.map((item, i) => ({
|
||||
key: `ld-${id}-${i}`,
|
||||
type: "application/ld+json",
|
||||
innerHTML: toJsonLd(item),
|
||||
tagPosition: "bodyOpen" as const,
|
||||
})),
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
/** Reactive `window.scrollY > threshold`, evaluated after mount (passive listener). */
|
||||
export function useScrolledPast(threshold: number) {
|
||||
const past = ref(false);
|
||||
const on = () => (past.value = window.scrollY > threshold);
|
||||
|
||||
onMounted(() => {
|
||||
on();
|
||||
window.addEventListener("scroll", on, { passive: true });
|
||||
});
|
||||
onBeforeUnmount(() => window.removeEventListener("scroll", on));
|
||||
|
||||
return past;
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
import { absUrl, siteConfig as s } from "#shared/config/site";
|
||||
|
||||
/** Site-wide <head> defaults shared by the app shell and the error page. */
|
||||
export function useSiteSeo() {
|
||||
useHead({
|
||||
titleTemplate: (title) => (title ? `${title} | ${s.name}` : s.title),
|
||||
});
|
||||
|
||||
useSeoMeta({
|
||||
description: s.description,
|
||||
themeColor: s.themeColor,
|
||||
formatDetection: "telephone=no",
|
||||
ogType: "website",
|
||||
ogSiteName: s.name,
|
||||
ogLocale: s.locale,
|
||||
ogTitle: s.title,
|
||||
ogDescription: s.description,
|
||||
ogImage: absUrl(s.ogImage.src),
|
||||
ogImageWidth: s.ogImage.width,
|
||||
ogImageHeight: s.ogImage.height,
|
||||
ogImageAlt: s.ogImage.alt,
|
||||
twitterCard: "summary_large_image",
|
||||
twitterTitle: s.title,
|
||||
twitterDescription: s.description,
|
||||
twitterImage: absUrl(s.ogImage.src),
|
||||
twitterImageAlt: s.ogImage.alt,
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/* Starts with "--:--" on the server so the first client render matches,
|
||||
then sets the real Tehran time only after mount (avoids a hydration mismatch on the clock text) */
|
||||
export function useTehranClock() {
|
||||
const now = ref<Date | null>(null);
|
||||
let t: ReturnType<typeof setInterval> | undefined;
|
||||
|
||||
onMounted(() => {
|
||||
now.value = new Date();
|
||||
t = setInterval(() => (now.value = new Date()), 15000);
|
||||
});
|
||||
onBeforeUnmount(() => clearInterval(t));
|
||||
|
||||
const time = computed(() =>
|
||||
now.value
|
||||
? new Intl.DateTimeFormat("fa-IR", {
|
||||
hour: "2-digit",
|
||||
minute: "2-digit",
|
||||
timeZone: "Asia/Tehran",
|
||||
}).format(now.value)
|
||||
: "--:--",
|
||||
);
|
||||
|
||||
const shift = computed(() => {
|
||||
if (!now.value) return "";
|
||||
const hour = Number(
|
||||
new Intl.DateTimeFormat("en-US", {
|
||||
hour: "numeric",
|
||||
hour12: false,
|
||||
timeZone: "Asia/Tehran",
|
||||
}).format(now.value),
|
||||
);
|
||||
return hour >= 6 && hour < 14 ? "صبح" : hour >= 14 && hour < 22 ? "عصر" : "شب";
|
||||
});
|
||||
|
||||
return { time, shift };
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
import { theme } from "ant-design-vue";
|
||||
import type { ThemeConfig } from "ant-design-vue/es/config-provider/context";
|
||||
|
||||
/**
|
||||
* Design-system palette — mirrors the Tailwind `@theme` tokens in assets/css/main.css.
|
||||
* Keep both in sync: Tailwind drives layout/sections, Ant Design drives form controls.
|
||||
*/
|
||||
export const palette = {
|
||||
bg: "#0a0a0c",
|
||||
panel: "#121216",
|
||||
panel2: "#17171c",
|
||||
ink: "#edede6",
|
||||
muted: "#8e8e96",
|
||||
accent: "#ff5a00",
|
||||
accentSoft: "#ff7a2a",
|
||||
hazard: "#ffb800",
|
||||
line: "#232329",
|
||||
success: "#34d399", // tailwind emerald-400
|
||||
} as const;
|
||||
|
||||
export const antdTheme: ThemeConfig = {
|
||||
algorithm: theme.darkAlgorithm,
|
||||
token: {
|
||||
colorPrimary: palette.accent,
|
||||
colorInfo: palette.accent,
|
||||
colorWarning: palette.hazard,
|
||||
colorSuccess: palette.success,
|
||||
colorBgBase: palette.bg,
|
||||
colorBgContainer: palette.bg,
|
||||
colorBgElevated: palette.panel,
|
||||
colorBorder: palette.line,
|
||||
colorBorderSecondary: palette.line,
|
||||
colorText: palette.ink,
|
||||
colorTextDescription: palette.muted,
|
||||
colorTextPlaceholder: "rgba(142, 142, 150, 0.5)",
|
||||
colorTextLightSolid: palette.bg,
|
||||
fontFamily: "var(--font-sans)",
|
||||
fontSize: 14,
|
||||
borderRadius: 8,
|
||||
controlOutlineWidth: 0,
|
||||
motionDurationMid: "0.15s",
|
||||
wireframe: false,
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,37 @@
|
||||
<script setup lang="ts">
|
||||
import type { NuxtError } from "#app";
|
||||
import { ShieldAlert } from "lucide-vue-next";
|
||||
|
||||
const props = defineProps<{ error: NuxtError }>();
|
||||
const notFound = computed(() => props.error.statusCode === 404);
|
||||
|
||||
useSiteSeo();
|
||||
useHead({ title: () => (notFound.value ? "صفحه پیدا نشد" : "خطا") });
|
||||
useSeoMeta({ robots: "noindex, follow" });
|
||||
|
||||
const goHome = () => clearError({ redirect: "/" });
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<main class="flex min-h-screen flex-col items-center justify-center px-5 text-center">
|
||||
<div class="hazard absolute inset-x-0 top-0 h-2.5" />
|
||||
<ShieldAlert class="size-16 text-accent" />
|
||||
<h1 class="mt-8 text-4xl font-black md:text-6xl">
|
||||
{{ notFound ? "صفحه مورد نظر پیدا نشد" : "خطایی رخ داد" }}
|
||||
</h1>
|
||||
<p class="mt-5 max-w-md leading-8 text-muted">
|
||||
{{
|
||||
notFound
|
||||
? "ممکن است آدرس اشتباه وارد شده باشد یا این صفحه جابهجا شده باشد."
|
||||
: "لطفاً چند لحظه بعد دوباره تلاش کنید."
|
||||
}}
|
||||
</p>
|
||||
<a
|
||||
href="/"
|
||||
class="mt-9 inline-flex items-center gap-2.5 rounded-full bg-accent px-7 py-4 font-bold text-bg transition-all duration-300 hover:bg-accent-soft"
|
||||
@click.prevent="goHome"
|
||||
>
|
||||
بازگشت به صفحه اصلی
|
||||
</a>
|
||||
</main>
|
||||
</template>
|
||||
@@ -0,0 +1,46 @@
|
||||
<script setup lang="ts">
|
||||
import { absUrl } from "#shared/config/site";
|
||||
import AppShell from "~/components/layout/AppShell.vue";
|
||||
import Footer from "~/components/layout/Footer.vue";
|
||||
import Hero from "~/components/sections/Hero.vue";
|
||||
import TapeMarquee from "~/components/sections/TapeMarquee.vue";
|
||||
import Stats from "~/components/sections/Stats.vue";
|
||||
import Products from "~/components/sections/Products.vue";
|
||||
import About from "~/components/sections/About.vue";
|
||||
import Services from "~/components/sections/Services.vue";
|
||||
import Standards from "~/components/sections/Standards.vue";
|
||||
import Industries from "~/components/sections/Industries.vue";
|
||||
import Testimonials from "~/components/sections/Testimonials.vue";
|
||||
import Contact from "~/components/sections/Contact.vue";
|
||||
|
||||
const canonical = absUrl("/");
|
||||
|
||||
useHead({
|
||||
link: [
|
||||
{ rel: "canonical", href: canonical },
|
||||
{ rel: "preload", as: "image", href: "/images/hero.jpg", fetchpriority: "high" },
|
||||
],
|
||||
});
|
||||
useSeoMeta({
|
||||
robots: "index, follow",
|
||||
ogUrl: canonical,
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<AppShell>
|
||||
<main>
|
||||
<Hero />
|
||||
<TapeMarquee />
|
||||
<Stats />
|
||||
<Products />
|
||||
<About />
|
||||
<Services />
|
||||
<Standards />
|
||||
<Industries />
|
||||
<Testimonials />
|
||||
<Contact />
|
||||
</main>
|
||||
<Footer />
|
||||
</AppShell>
|
||||
</template>
|
||||
@@ -0,0 +1,22 @@
|
||||
import { createCache, extractStyle } from "ant-design-vue";
|
||||
|
||||
/**
|
||||
* Ant Design Vue uses CSS-in-JS. During SSR/SSG we collect the generated styles into a cache
|
||||
* and inline them into <head>, so prerendered HTML is fully styled before hydration (no FOUC).
|
||||
*/
|
||||
export default defineNuxtPlugin((nuxtApp) => {
|
||||
const cache = createCache();
|
||||
|
||||
if (import.meta.server) {
|
||||
nuxtApp.hook("app:rendered", ({ ssrContext }) => {
|
||||
const css = extractStyle(cache, true);
|
||||
if (css && ssrContext) {
|
||||
ssrContext.head.push({
|
||||
style: [{ key: "antd-cssinjs", innerHTML: css }],
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return { provide: { antdCache: cache } };
|
||||
});
|
||||
@@ -0,0 +1,24 @@
|
||||
import { defineStore } from "pinia";
|
||||
|
||||
export type ContactStatus = "idle" | "loading" | "success";
|
||||
|
||||
const emptyForm = () => ({ name: "", org: "", phone: "", message: "" });
|
||||
|
||||
export const useContactStore = defineStore("contact", {
|
||||
state: () => ({
|
||||
form: emptyForm(),
|
||||
status: "idle" as ContactStatus,
|
||||
}),
|
||||
actions: {
|
||||
// TODO: connect to the real API endpoint; currently simulates the request like the original
|
||||
async submit() {
|
||||
this.status = "loading";
|
||||
await new Promise((r) => setTimeout(r, 1100));
|
||||
this.status = "success";
|
||||
},
|
||||
reset() {
|
||||
this.form = emptyForm();
|
||||
this.status = "idle";
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,21 @@
|
||||
import { defineStore } from "pinia";
|
||||
|
||||
export const useUiStore = defineStore("ui", {
|
||||
state: () => ({
|
||||
/** true once the preloader has finished */
|
||||
ready: false,
|
||||
/** mobile navigation overlay */
|
||||
menuOpen: false,
|
||||
}),
|
||||
actions: {
|
||||
setReady() {
|
||||
this.ready = true;
|
||||
},
|
||||
openMenu() {
|
||||
this.menuOpen = true;
|
||||
},
|
||||
closeMenu() {
|
||||
this.menuOpen = false;
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,13 @@
|
||||
export const EASE: [number, number, number, number] = [0.22, 1, 0.36, 1];
|
||||
|
||||
/** Convert latin digits to Persian digits */
|
||||
export const faNum = (v: number | string): string =>
|
||||
String(v).replace(/\d/g, (d) => "۰۱۲۳۴۵۶۷۸۹"[Number(d)]!);
|
||||
|
||||
/** While-in-view fade-up props for motion elements (spread with v-bind) */
|
||||
export const fade = (delay = 0, y = 36) => ({
|
||||
initial: { opacity: 0, y },
|
||||
whileInView: { opacity: 1, y: 0 },
|
||||
inViewOptions: { once: true, margin: "-60px" as const },
|
||||
transition: { duration: 0.8, delay, ease: EASE },
|
||||
});
|
||||
@@ -1,12 +0,0 @@
|
||||
import type { NextConfig } from "next";
|
||||
|
||||
const nextConfig: NextConfig = {
|
||||
output: "export",
|
||||
trailingSlash: false,
|
||||
images: {
|
||||
unoptimized: true,
|
||||
},
|
||||
poweredByHeader: false,
|
||||
};
|
||||
|
||||
export default nextConfig;
|
||||
@@ -4,11 +4,16 @@ server {
|
||||
root /usr/share/nginx/html;
|
||||
index index.html;
|
||||
|
||||
location /_next/static/ {
|
||||
location /_nuxt/ {
|
||||
expires 1y;
|
||||
add_header Cache-Control "public, immutable";
|
||||
}
|
||||
|
||||
# mime.types پیشفرض nginx نوع webmanifest را ندارد
|
||||
location = /manifest.webmanifest {
|
||||
default_type application/manifest+json;
|
||||
}
|
||||
|
||||
# $uri/index.html بهجای $uri/ تا دایرکتوری / ریدایرکت ۳۰۱ نسازد
|
||||
location / {
|
||||
try_files $uri $uri.html $uri/index.html =404;
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
import { fileURLToPath } from "node:url";
|
||||
import tailwindcss from "@tailwindcss/vite";
|
||||
import { siteConfig } from "./shared/config/site";
|
||||
|
||||
/** Unmatched path rendered through error.vue at build time and saved as out/404.html */
|
||||
const NOT_FOUND_ROUTE = "/__not-found";
|
||||
|
||||
export default defineNuxtConfig({
|
||||
compatibilityDate: "2026-10-01",
|
||||
ssr: true,
|
||||
devtools: { enabled: false },
|
||||
modules: ["@pinia/nuxt"],
|
||||
css: ["~/assets/css/main.css", "~/assets/css/antd-overrides.css"],
|
||||
|
||||
app: {
|
||||
head: {
|
||||
htmlAttrs: { lang: siteConfig.lang, dir: siteConfig.dir },
|
||||
bodyAttrs: {
|
||||
class: "relative min-h-screen bg-bg font-sans text-ink antialiased",
|
||||
},
|
||||
charset: "utf-8",
|
||||
viewport: "width=device-width, initial-scale=1",
|
||||
link: [
|
||||
{
|
||||
rel: "preload",
|
||||
href: "/fonts/Vazirmatn-Variable.woff2",
|
||||
as: "font",
|
||||
type: "font/woff2",
|
||||
crossorigin: "",
|
||||
},
|
||||
{
|
||||
rel: "preload",
|
||||
href: "/fonts/IBMPlexMono-Regular.woff2",
|
||||
as: "font",
|
||||
type: "font/woff2",
|
||||
crossorigin: "",
|
||||
},
|
||||
{ rel: "icon", type: "image/svg+xml", href: siteConfig.favicon },
|
||||
{ rel: "manifest", href: "/manifest.webmanifest" },
|
||||
],
|
||||
},
|
||||
},
|
||||
|
||||
vite: {
|
||||
plugins: [tailwindcss()],
|
||||
ssr: { noExternal: ["ant-design-vue", "@ant-design/icons-vue"] },
|
||||
},
|
||||
|
||||
// Static export (`npm run build` → ./out), served by nginx in Docker — same flow as the Next build.
|
||||
nitro: {
|
||||
output: { publicDir: fileURLToPath(new URL("./out", import.meta.url)) },
|
||||
prerender: {
|
||||
crawlLinks: false,
|
||||
routes: ["/", "/robots.txt", "/sitemap.xml", "/manifest.webmanifest", NOT_FOUND_ROUTE],
|
||||
},
|
||||
hooks: {
|
||||
// Nuxt's own /404.html is an empty SPA shell. Replace it with a server-rendered error.vue
|
||||
// (real content + noindex in the static HTML) produced by prerendering an unmatched route.
|
||||
"prerender:generate"(route) {
|
||||
if (route.route === "/404.html") route.skip = true;
|
||||
if (route.route === NOT_FOUND_ROUTE && route.error?.statusCode === 404) {
|
||||
route.error = undefined;
|
||||
route.fileName = "/404.html";
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
typescript: { strict: true },
|
||||
});
|
||||
@@ -1 +0,0 @@
|
||||
self.__BUILD_MANIFEST=function(e,r,t){return{__rewrites:{afterFiles:[],beforeFiles:[],fallback:[]},__routerFilterStatic:{numItems:5,errorRate:1e-4,numBits:96,numHashes:14,bitArray:[1,1,0,e,e,0,r,r,e,r,e,e,e,r,e,r,r,e,e,e,e,r,e,r,r,e,e,r,e,r,r,r,r,r,r,r,r,e,r,e,e,r,e,e,r,e,r,e,r,e,e,r,e,r,r,r,e,r,e,e,e,e,r,e,e,e,r,r,r,e,e,e,r,r,e,r,r,r,e,e,e,e,e,e,r,r,r,e,e,r,r,r,e,e,r,r]},__routerFilterDynamic:{numItems:r,errorRate:1e-4,numBits:r,numHashes:null,bitArray:[]},"/_error":["static/chunks/pages/_error-013f4188946cdd04.js"],sortedPages:["/_app","/_error"]}}(1,0,1e-4),self.__BUILD_MANIFEST_CB&&self.__BUILD_MANIFEST_CB();
|
||||
@@ -1 +0,0 @@
|
||||
self.__SSG_MANIFEST=new Set([]);self.__SSG_MANIFEST_CB&&self.__SSG_MANIFEST_CB()
|
||||
@@ -1 +0,0 @@
|
||||
"use strict";(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[139],{5139:(e,t,l)=>{Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"default",{enumerable:!0,get:function(){return s}});let u=l(4252),n=l(7876),a=u._(l(4232)),o=l(1033);async function r(e){let{Component:t,ctx:l}=e;return{pageProps:await (0,o.loadGetInitialProps)(t,l)}}class s extends a.default.Component{render(){let{Component:e,pageProps:t}=this.props;return(0,n.jsx)(e,{...t})}}s.origGetInitialProps=r,s.getInitialProps=r,("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)}}]);
|
||||
@@ -1 +0,0 @@
|
||||
(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[337,475,492,784],{4441:()=>{}},_=>{_.O(0,[441,255,358],()=>_(_.s=4441)),_N_E=_.O()}]);
|
||||
@@ -1 +0,0 @@
|
||||
(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[177],{1255:e=>{e.exports={style:{fontFamily:"'vazirmatn', 'vazirmatn Fallback', Tahoma, system-ui, sans-serif"},className:"__className_b3ce59",variable:"__variable_b3ce59"}},3795:()=>{},4393:e=>{e.exports={style:{fontFamily:"'ibmPlexMono', 'ibmPlexMono Fallback', ui-monospace, monospace"},className:"__className_d30186",variable:"__variable_d30186"}},5776:(e,a,s)=>{Promise.resolve().then(s.t.bind(s,1255,23)),Promise.resolve().then(s.t.bind(s,4393,23)),Promise.resolve().then(s.t.bind(s,3795,23))}},e=>{e.O(0,[266,441,255,358],()=>e(e.s=5776)),_N_E=e.O()}]);
|
||||
@@ -1 +0,0 @@
|
||||
(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[337,475,492,784],{4441:()=>{}},_=>{_.O(0,[441,255,358],()=>_(_.s=4441)),_N_E=_.O()}]);
|
||||
@@ -1 +0,0 @@
|
||||
(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[337,475,492,784],{4441:()=>{}},_=>{_.O(0,[441,255,358],()=>_(_.s=4441)),_N_E=_.O()}]);
|
||||
@@ -1 +0,0 @@
|
||||
(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[337,475,492,784],{4441:()=>{}},_=>{_.O(0,[441,255,358],()=>_(_.s=4441)),_N_E=_.O()}]);
|
||||
@@ -1 +0,0 @@
|
||||
(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[358],{7283:(e,s,n)=>{Promise.resolve().then(n.t.bind(n,7150,23)),Promise.resolve().then(n.t.bind(n,1959,23)),Promise.resolve().then(n.t.bind(n,7989,23)),Promise.resolve().then(n.t.bind(n,3886,23)),Promise.resolve().then(n.t.bind(n,9766,23)),Promise.resolve().then(n.t.bind(n,5278,23)),Promise.resolve().then(n.t.bind(n,8924,23)),Promise.resolve().then(n.t.bind(n,4431,23)),Promise.resolve().then(n.bind(n,622))},9393:()=>{}},e=>{var s=s=>e(e.s=s);e.O(0,[441,255],()=>(s(1666),s(7283))),_N_E=e.O()}]);
|
||||
@@ -1 +0,0 @@
|
||||
(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[139,636],{326:(e,t,n)=>{(window.__NEXT_P=window.__NEXT_P||[]).push(["/_app",function(){return n(5139)}])},5139:(e,t,n)=>{"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"default",{enumerable:!0,get:function(){return s}});let u=n(4252),l=n(7876),a=u._(n(4232)),o=n(1033);async function r(e){let{Component:t,ctx:n}=e;return{pageProps:await (0,o.loadGetInitialProps)(t,n)}}class s extends a.default.Component{render(){let{Component:e,pageProps:t}=this.props;return(0,l.jsx)(e,{...t})}}s.origGetInitialProps=r,s.getInitialProps=r,("function"==typeof t.default||"object"==typeof t.default&&null!==t.default)&&void 0===t.default.__esModule&&(Object.defineProperty(t.default,"__esModule",{value:!0}),Object.assign(t.default,t),e.exports=t.default)}},e=>{var t=t=>e(e.s=t);e.O(0,[593,792],()=>(t(326),t(6763))),_N_E=e.O()}]);
|
||||
@@ -1 +0,0 @@
|
||||
(()=>{"use strict";var e={},t={};function r(o){var n=t[o];if(void 0!==n)return n.exports;var a=t[o]={exports:{}},i=!0;try{e[o](a,a.exports,r),i=!1}finally{i&&delete t[o]}return a.exports}r.m=e,(()=>{var e=[];r.O=(t,o,n,a)=>{if(o){a=a||0;for(var i=e.length;i>0&&e[i-1][2]>a;i--)e[i]=e[i-1];e[i]=[o,n,a];return}for(var u=1/0,i=0;i<e.length;i++){for(var[o,n,a]=e[i],l=!0,c=0;c<o.length;c++)(!1&a||u>=a)&&Object.keys(r.O).every(e=>r.O[e](o[c]))?o.splice(c--,1):(l=!1,a<u&&(u=a));if(l){e.splice(i--,1);var d=n();void 0!==d&&(t=d)}}return t}})(),r.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return r.d(t,{a:t}),t},(()=>{var e,t=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__;r.t=function(o,n){if(1&n&&(o=this(o)),8&n||"object"==typeof o&&o&&(4&n&&o.__esModule||16&n&&"function"==typeof o.then))return o;var a=Object.create(null);r.r(a);var i={};e=e||[null,t({}),t([]),t(t)];for(var u=2&n&&o;"object"==typeof u&&!~e.indexOf(u);u=t(u))Object.getOwnPropertyNames(u).forEach(e=>i[e]=()=>o[e]);return i.default=()=>o,r.d(a,i),a}})(),r.d=(e,t)=>{for(var o in t)r.o(t,o)&&!r.o(e,o)&&Object.defineProperty(e,o,{enumerable:!0,get:t[o]})},r.f={},r.e=e=>Promise.all(Object.keys(r.f).reduce((t,o)=>(r.f[o](e,t),t),[])),r.u=e=>"static/chunks/"+e+"."+({139:"7a5a8e93a21948c1",646:"f342b7cffc01feb0"})[e]+".js",r.miniCssF=e=>{},r.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||Function("return this")()}catch(e){if("object"==typeof window)return window}}(),r.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),(()=>{var e={},t="_N_E:";r.l=(o,n,a,i)=>{if(e[o])return void e[o].push(n);if(void 0!==a)for(var u,l,c=document.getElementsByTagName("script"),d=0;d<c.length;d++){var s=c[d];if(s.getAttribute("src")==o||s.getAttribute("data-webpack")==t+a){u=s;break}}u||(l=!0,(u=document.createElement("script")).charset="utf-8",u.timeout=120,r.nc&&u.setAttribute("nonce",r.nc),u.setAttribute("data-webpack",t+a),u.src=r.tu(o)),e[o]=[n];var f=(t,r)=>{u.onerror=u.onload=null,clearTimeout(p);var n=e[o];if(delete e[o],u.parentNode&&u.parentNode.removeChild(u),n&&n.forEach(e=>e(r)),t)return t(r)},p=setTimeout(f.bind(null,void 0,{type:"timeout",target:u}),12e4);u.onerror=f.bind(null,u.onerror),u.onload=f.bind(null,u.onload),l&&document.head.appendChild(u)}})(),r.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},(()=>{var e;r.tt=()=>(void 0===e&&(e={createScriptURL:e=>e},"undefined"!=typeof trustedTypes&&trustedTypes.createPolicy&&(e=trustedTypes.createPolicy("nextjs#bundler",e))),e)})(),r.tu=e=>r.tt().createScriptURL(e),r.p="/_next/",(()=>{var e={68:0,266:0};r.f.j=(t,o)=>{var n=r.o(e,t)?e[t]:void 0;if(0!==n)if(n)o.push(n[2]);else if(/^(266|68)$/.test(t))e[t]=0;else{var a=new Promise((r,o)=>n=e[t]=[r,o]);o.push(n[2]=a);var i=r.p+r.u(t),u=Error();r.l(i,o=>{if(r.o(e,t)&&(0!==(n=e[t])&&(e[t]=void 0),n)){var a=o&&("load"===o.type?"missing":o.type),i=o&&o.target&&o.target.src;u.message="Loading chunk "+t+" failed.\n("+a+": "+i+")",u.name="ChunkLoadError",u.type=a,u.request=i,n[1](u)}},"chunk-"+t,t)}},r.O.j=t=>0===e[t];var t=(t,o)=>{var n,a,[i,u,l]=o,c=0;if(i.some(t=>0!==e[t])){for(n in u)r.o(u,n)&&(r.m[n]=u[n]);if(l)var d=l(r)}for(t&&t(o);c<i.length;c++)a=i[c],r.o(e,a)&&e[a]&&e[a][0](),e[a]=0;return r.O(d)},o=self.webpackChunk_N_E=self.webpackChunk_N_E||[];o.forEach(t.bind(null,0)),o.push=t.bind(null,o.push.bind(o))})()})();
|
||||
|
Before Width: | Height: | Size: 306 KiB |
|
Before Width: | Height: | Size: 201 KiB |
|
Before Width: | Height: | Size: 108 KiB |
|
Before Width: | Height: | Size: 119 KiB |
|
Before Width: | Height: | Size: 116 KiB |
|
Before Width: | Height: | Size: 188 KiB |
|
Before Width: | Height: | Size: 76 KiB |
|
Before Width: | Height: | Size: 101 KiB |
|
Before Width: | Height: | Size: 265 KiB |
|
Before Width: | Height: | Size: 132 KiB |
|
Before Width: | Height: | Size: 244 KiB |
|
Before Width: | Height: | Size: 123 KiB |
|
Before Width: | Height: | Size: 191 KiB |
|
Before Width: | Height: | Size: 198 KiB |
@@ -1,75 +0,0 @@
|
||||
1:"$Sreact.fragment"
|
||||
2:I[9766,[],""]
|
||||
3:I[8924,[],""]
|
||||
4:I[2619,["345","static/chunks/app/not-found-7b6fd15ee953c61c.js"],""]
|
||||
5:I[1232,["421","static/chunks/421-20f474da4f0f7dbd.js","974","static/chunks/app/page-a20904802d61ed6a.js"],"AppShell"]
|
||||
6:I[1356,["421","static/chunks/421-20f474da4f0f7dbd.js","974","static/chunks/app/page-a20904802d61ed6a.js"],"Image"]
|
||||
1b:I[7150,[],""]
|
||||
:HL["/_next/static/css/2a3679b3ddc69c91.css","style"]
|
||||
0:{"P":null,"b":"71ES_mB02KTIaEPcPlWHR","p":"","c":["",""],"i":false,"f":[[["",{"children":["__PAGE__",{}]},"$undefined","$undefined",true],["",["$","$1","c",{"children":[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/2a3679b3ddc69c91.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}]],["$","html",null,{"lang":"fa","dir":"rtl","className":"__variable_b3ce59 __variable_d30186","children":["$","body",null,{"className":"relative min-h-screen bg-bg font-sans text-ink antialiased","children":[[["$","script","0",{"type":"application/ld+json","dangerouslySetInnerHTML":{"__html":"{\"@context\":\"https://schema.org\",\"@type\":\"LocalBusiness\",\"@id\":\"https://ariaiman.ir/#organization\",\"name\":\"آریا ایمن\",\"url\":\"https://ariaiman.ir\",\"logo\":\"https://ariaiman.ir/images/hero.jpg\",\"image\":\"https://ariaiman.ir/images/hero.jpg\",\"email\":\"info@ariaiman.ir\",\"telephone\":\"+98-21-91008800\",\"address\":{\"@type\":\"PostalAddress\",\"streetAddress\":\"خیابان کارگر شمالی، خیابان فر، کوچه دوم، پلاک ۱۲\",\"addressLocality\":\"تهران\",\"addressCountry\":\"IR\"}}"}}],["$","script","1",{"type":"application/ld+json","dangerouslySetInnerHTML":{"__html":"{\"@context\":\"https://schema.org\",\"@type\":\"WebSite\",\"@id\":\"https://ariaiman.ir/#website\",\"url\":\"https://ariaiman.ir\",\"name\":\"آریا ایمن\",\"inLanguage\":\"fa\",\"publisher\":{\"@id\":\"https://ariaiman.ir/#organization\"}}"}}]],["$","$L2",null,{"parallelRouterKey":"children","error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L3",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[["$","main",null,{"className":"flex min-h-screen flex-col items-center justify-center px-5 text-center","children":[["$","div",null,{"className":"hazard absolute inset-x-0 top-0 h-2.5"}],["$","svg",null,{"ref":"$undefined","xmlns":"http://www.w3.org/2000/svg","width":24,"height":24,"viewBox":"0 0 24 24","fill":"none","stroke":"currentColor","strokeWidth":2,"strokeLinecap":"round","strokeLinejoin":"round","className":"lucide lucide-shield-alert size-16 text-accent","children":[["$","path","oel41y",{"d":"M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z"}],["$","path","1got3b",{"d":"M12 8v4"}],["$","path","1drbdi",{"d":"M12 16h.01"}],"$undefined"]}],["$","h1",null,{"className":"mt-8 text-4xl font-black md:text-6xl","children":"صفحه مورد نظر پیدا نشد"}],["$","p",null,{"className":"mt-5 max-w-md leading-8 text-muted","children":"ممکن است آدرس اشتباه وارد شده باشد یا این صفحه جابهجا شده باشد."}],["$","$L4",null,{"href":"/","className":"mt-9 inline-flex items-center gap-2.5 rounded-full bg-accent px-7 py-4 font-bold text-bg transition-all duration-300 hover:bg-accent-soft","children":"بازگشت به صفحه اصلی"}]]}],[]],"forbidden":"$undefined","unauthorized":"$undefined"}]]}]}]]}],{"children":["__PAGE__",["$","$1","c",{"children":[["$","$L5",null,{"children":[["$","main",null,{"children":[["$","section",null,{"id":"home","className":"relative flex min-h-screen flex-col overflow-hidden","children":[["$","div",null,{"className":"absolute inset-0","children":[["$","$L6",null,{"src":"/images/hero.jpg","alt":"کارگر صنعتی با تجهیزات ایمنی کامل","fill":true,"priority":true,"sizes":"100vw","className":"object-cover"}],["$","div",null,{"className":"absolute inset-0 bg-gradient-to-l from-bg via-bg/80 to-bg/25"}],["$","div",null,{"className":"absolute inset-0 bg-gradient-to-t from-bg via-transparent to-bg/60"}],["$","div",null,{"className":"absolute inset-0 bg-grid opacity-50"}]]}],["$","div",null,{"className":"tape-v absolute bottom-0 end-0 z-10 h-44 w-1.5 opacity-70"}],["$","div",null,{"className":"relative z-10 mx-auto flex w-full max-w-7xl flex-1 items-center px-5 pb-24 pt-36 md:px-8","children":["$","div",null,{"className":"grid w-full items-center gap-12 lg:grid-cols-12","children":[["$","div",null,{"className":"lg:col-span-7","children":[["$","div",null,{"className":"animate-fade-up-1 inline-flex items-center gap-2.5 rounded-full border border-accent/30 bg-accent/10 px-4 py-2 backdrop-blur","children":[["$","span",null,{"className":"size-1.5 animate-pulse rounded-full bg-accent"}],"$L7"]}],"$L8","$L9","$La","$Lb"]}],"$Lc"]}]}],"$Ld","$Le"]}],"$Lf","$L10","$L11","$L12","$L13","$L14","$L15","$L16","$L17"]}],"$L18"]}],null,"$L19"]}],{},null,false]},null,false],"$L1a",false]],"m":"$undefined","G":["$1b",[]],"s":false,"S":true}
|
||||
29:I[1181,["421","static/chunks/421-20f474da4f0f7dbd.js","974","static/chunks/app/page-a20904802d61ed6a.js"],"Reveal"]
|
||||
2a:I[470,["421","static/chunks/421-20f474da4f0f7dbd.js","974","static/chunks/app/page-a20904802d61ed6a.js"],"CountUp"]
|
||||
2b:I[2236,["421","static/chunks/421-20f474da4f0f7dbd.js","974","static/chunks/app/page-a20904802d61ed6a.js"],"Products"]
|
||||
2f:I[1180,["421","static/chunks/421-20f474da4f0f7dbd.js","974","static/chunks/app/page-a20904802d61ed6a.js"],"Services"]
|
||||
37:I[9570,["421","static/chunks/421-20f474da4f0f7dbd.js","974","static/chunks/app/page-a20904802d61ed6a.js"],"Industries"]
|
||||
38:I[5559,["421","static/chunks/421-20f474da4f0f7dbd.js","974","static/chunks/app/page-a20904802d61ed6a.js"],"Testimonials"]
|
||||
39:I[4960,["421","static/chunks/421-20f474da4f0f7dbd.js","974","static/chunks/app/page-a20904802d61ed6a.js"],"Contact"]
|
||||
40:I[4431,[],"OutletBoundary"]
|
||||
42:I[5278,[],"AsyncMetadataOutlet"]
|
||||
44:I[4431,[],"ViewportBoundary"]
|
||||
46:I[4431,[],"MetadataBoundary"]
|
||||
47:"$Sreact.suspense"
|
||||
7:["$","span",null,{"className":"text-xs font-medium text-accent","children":"تأمینکننده رسمی تجهیزات حفاظت فردی (PPE)"}]
|
||||
8:["$","h1",null,{"className":"animate-fade-up-2 mt-7 text-5xl font-black leading-[1.15] md:text-7xl md:leading-[1.1]","children":["ایمنی یعنی",["$","br",null,{}],["$","span",null,{"className":"mt-3 inline-block -rotate-1 rounded-lg bg-hazard px-4 py-1.5 text-bg shadow-[0_10px_50px_rgba(255,184,0,0.25)]","children":"بازگشت به خانه"}]]}]
|
||||
9:["$","p",null,{"className":"animate-fade-up-3 mt-7 max-w-xl text-base leading-9 text-ink/70 md:text-lg md:leading-10","children":"آریا ایمن با بیش از ۱۸ سال تجربه، تأمینکننده تخصصی تجهیزات ایمنی و حفاظت فردی برای سازمانهایی است که جان انسانها را جدی میگیرند؛ از کلاه ایمنی تا هارنس نجات، از مشاوره تا بازرسی و آموزش."}]
|
||||
a:["$","div",null,{"className":"animate-fade-up-4 mt-9 flex flex-wrap items-center gap-4","children":[["$","a",null,{"href":"#contact","className":"group inline-flex items-center gap-2.5 rounded-full bg-accent px-7 py-4 font-bold text-bg transition-all duration-300 hover:bg-accent-soft hover:shadow-[0_8px_45px_rgba(255,90,0,0.5)]","children":["درخواست مشاوره رایگان",["$","svg",null,{"ref":"$undefined","xmlns":"http://www.w3.org/2000/svg","width":24,"height":24,"viewBox":"0 0 24 24","fill":"none","stroke":"currentColor","strokeWidth":2,"strokeLinecap":"round","strokeLinejoin":"round","className":"lucide lucide-arrow-left size-5 transition-transform duration-300 group-hover:-translate-x-1.5","children":[["$","path","1l729n",{"d":"m12 19-7-7 7-7"}],["$","path","x3x0zl",{"d":"M19 12H5"}],"$undefined"]}]]}],["$","a",null,{"href":"#products","className":"inline-flex items-center gap-2.5 rounded-full border border-ink/25 px-7 py-4 font-bold text-ink backdrop-blur transition-colors duration-300 hover:border-accent hover:text-accent","children":"مشاهده محصولات"}]]}]
|
||||
b:["$","div",null,{"className":"animate-fade-up-5 mt-10 flex flex-wrap gap-3","children":[["$","span","ISO 9001:2015",{"className":"inline-flex items-center gap-2 rounded-full border border-ink/15 bg-bg/50 px-4 py-2 font-mono text-[11px] tracking-wider text-ink/70 backdrop-blur transition-colors hover:border-accent/50 hover:text-ink","children":[["$","svg",null,{"ref":"$undefined","xmlns":"http://www.w3.org/2000/svg","width":24,"height":24,"viewBox":"0 0 24 24","fill":"none","stroke":"currentColor","strokeWidth":2,"strokeLinecap":"round","strokeLinejoin":"round","className":"lucide lucide-shield-check size-4 text-accent","children":[["$","path","oel41y",{"d":"M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z"}],["$","path","dzmm74",{"d":"m9 12 2 2 4-4"}],"$undefined"]}],"ISO 9001:2015"]}],["$","span","CE CERTIFIED",{"className":"inline-flex items-center gap-2 rounded-full border border-ink/15 bg-bg/50 px-4 py-2 font-mono text-[11px] tracking-wider text-ink/70 backdrop-blur transition-colors hover:border-accent/50 hover:text-ink","children":[["$","svg",null,{"ref":"$undefined","xmlns":"http://www.w3.org/2000/svg","width":24,"height":24,"viewBox":"0 0 24 24","fill":"none","stroke":"currentColor","strokeWidth":2,"strokeLinecap":"round","strokeLinejoin":"round","className":"lucide lucide-badge-check size-4 text-accent","children":[["$","path","3c2336",{"d":"M3.85 8.62a4 4 0 0 1 4.78-4.77 4 4 0 0 1 6.74 0 4 4 0 0 1 4.78 4.78 4 4 0 0 1 0 6.74 4 4 0 0 1-4.77 4.78 4 4 0 0 1-6.75 0 4 4 0 0 1-4.78-4.77 4 4 0 0 1 0-6.76Z"}],["$","path","dzmm74",{"d":"m9 12 2 2 4-4"}],"$undefined"]}],"CE CERTIFIED"]}],["$","span","EN STANDARDS",{"className":"inline-flex items-center gap-2 rounded-full border border-ink/15 bg-bg/50 px-4 py-2 font-mono text-[11px] tracking-wider text-ink/70 backdrop-blur transition-colors hover:border-accent/50 hover:text-ink","children":[["$","svg",null,{"ref":"$undefined","xmlns":"http://www.w3.org/2000/svg","width":24,"height":24,"viewBox":"0 0 24 24","fill":"none","stroke":"currentColor","strokeWidth":2,"strokeLinecap":"round","strokeLinejoin":"round","className":"lucide lucide-award size-4 text-accent","children":[["$","path","1yiouv",{"d":"m15.477 12.89 1.515 8.526a.5.5 0 0 1-.81.47l-3.58-2.687a1 1 0 0 0-1.197 0l-3.586 2.686a.5.5 0 0 1-.81-.469l1.514-8.526"}],["$","circle","1vp47v",{"cx":"12","cy":"8","r":"6"}],"$undefined"]}],"EN STANDARDS"]}]]}]
|
||||
c:["$","div",null,{"className":"hidden flex-col items-center gap-10 lg:col-span-5 lg:flex","children":[["$","div",null,{"className":"animate-fade-up-6 relative","children":["$","div",null,{"className":"relative size-44","children":[["$","div",null,{"className":"animate-spin-slow absolute inset-0","children":["$","svg",null,{"viewBox":"0 0 120 120","className":"size-full","children":[["$","defs",null,{"children":["$","path",null,{"id":"badge-circle","d":"M60,60 m-47,0 a47,47 0 1,1 94,0 a47,47 0 1,1 -94,0"}]}],["$","text",null,{"fontSize":"9","letterSpacing":"2.6","className":"fill-ink/60 font-mono","children":["$","textPath",null,{"href":"#badge-circle","children":"ARIA IMEN SAFETY • ISO 9001 • CE CERTIFIED • EST 2007 •"}]}]]}]}],["$","div",null,{"className":"absolute inset-0 flex items-center justify-center","children":["$","span",null,{"className":"flex size-20 items-center justify-center rounded-full border border-accent/30 bg-accent/10","children":["$","svg",null,{"ref":"$undefined","xmlns":"http://www.w3.org/2000/svg","width":24,"height":24,"viewBox":"0 0 24 24","fill":"none","stroke":"currentColor","strokeWidth":2,"strokeLinecap":"round","strokeLinejoin":"round","className":"lucide lucide-hard-hat size-9 text-accent","children":[["$","path","1p9q5i",{"d":"M10 10V5a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1v5"}],["$","path","1hnv84",{"d":"M14 6a6 6 0 0 1 6 6v3"}],["$","path","9ciidu",{"d":"M4 15v-3a6 6 0 0 1 6-6"}],["$","rect","g3x8cw",{"x":"2","y":"15","width":"20","height":"4","rx":"1"}],"$undefined"]}]}]}]]}]}],["$","div",null,{"className":"animate-fade-up-7 w-full max-w-sm border border-line bg-bg/70 p-5 backdrop-blur-md","children":[["$","div",null,{"className":"flex items-center justify-between font-mono text-[11px]","children":[["$","span",null,{"className":"text-muted","children":"SITE STATUS"}],["$","span",null,{"className":"flex items-center gap-2 text-emerald-400","children":[["$","span",null,{"className":"size-1.5 animate-pulse rounded-full bg-emerald-400"}],"SECURE"]}]]}],["$","div",null,{"className":"mt-3.5 flex items-center justify-between font-mono text-[11px]","children":[["$","span",null,{"className":"text-muted","children":"PPE COMPLIANCE"}],["$","span",null,{"className":"font-semibold text-accent","children":"۱۰۰٪"}]]}],["$","div",null,{"className":"mt-3.5 flex items-center justify-between font-mono text-[11px]","children":[["$","span",null,{"className":"text-muted","children":"آخرین بازرسی"}],["$","span",null,{"children":"۱۴۰۴/۰۸/۱۲"}]]}],["$","div",null,{"className":"my-4 h-px bg-line"}],["$","div",null,{"className":"font-mono text-[11px] leading-6 text-muted","children":["سیستم پایش حرفهای آریا ایمن",["$","span",null,{"className":"animate-blink text-accent","children":"▍"}]]}]]}]]}]
|
||||
d:["$","div",null,{"className":"animate-fade-up-9 absolute bottom-28 left-1/2 z-10 hidden md:block","children":["$","div",null,{"className":"-translate-x-1/2 flex flex-col items-center gap-2","children":[["$","span",null,{"className":"font-mono text-[10px] tracking-[0.35em] text-muted","children":"SCROLL"}],["$","svg",null,{"ref":"$undefined","xmlns":"http://www.w3.org/2000/svg","width":24,"height":24,"viewBox":"0 0 24 24","fill":"none","stroke":"currentColor","strokeWidth":2,"strokeLinecap":"round","strokeLinejoin":"round","className":"lucide lucide-chevron-down size-4 animate-bounce text-accent","children":[["$","path","qrunsl",{"d":"m6 9 6 6 6-6"}],"$undefined"]}]]}]}]
|
||||
e:["$","div",null,{"className":"animate-fade-up-8 relative z-10 border-t border-ink/10 backdrop-blur-sm","children":["$","div",null,{"className":"mx-auto grid max-w-7xl grid-cols-1 gap-px bg-ink/10 sm:grid-cols-3","children":[["$","div","سال تجربه در صنعت ایمنی",{"className":"flex items-baseline gap-4 bg-bg/60 px-6 py-5 backdrop-blur-md md:px-8","children":[["$","span",null,{"className":"text-2xl font-black text-ink md:text-3xl","children":"۱۸+"}],["$","span",null,{"className":"text-xs leading-5 text-muted md:text-sm","children":"سال تجربه در صنعت ایمنی"}]]}],["$","div","سازمان تحت پوشش",{"className":"flex items-baseline gap-4 bg-bg/60 px-6 py-5 backdrop-blur-md md:px-8","children":[["$","span",null,{"className":"text-2xl font-black text-ink md:text-3xl","children":"۸۵۰+"}],["$","span",null,{"className":"text-xs leading-5 text-muted md:text-sm","children":"سازمان تحت پوشش"}]]}],["$","div","رضایت مشتریان",{"className":"flex items-baseline gap-4 bg-bg/60 px-6 py-5 backdrop-blur-md md:px-8","children":[["$","span",null,{"className":"text-2xl font-black text-ink md:text-3xl","children":"۹۸٪"}],["$","span",null,{"className":"text-xs leading-5 text-muted md:text-sm","children":"رضایت مشتریان"}]]}]]}]}]
|
||||
f:["$","section",null,{"aria-hidden":true,"className":"pointer-events-none relative z-20 overflow-hidden py-10","children":["$","div",null,{"className":"-rotate-[1.6deg] scale-[1.04]","children":[["$","div",null,{"className":"hazard h-2.5"}],["$","div",null,{"dir":"ltr","className":"overflow-hidden bg-hazard py-3.5 text-bg","children":["$","div",null,{"className":"animate-marquee flex w-max","children":[["$","span","0",{"className":"flex items-center gap-7 px-7 text-sm font-extrabold whitespace-nowrap","children":["ISO 9001:2015",["$","svg",null,{"ref":"$undefined","xmlns":"http://www.w3.org/2000/svg","width":24,"height":24,"viewBox":"0 0 24 24","fill":"none","stroke":"currentColor","strokeWidth":2.5,"strokeLinecap":"round","strokeLinejoin":"round","className":"lucide lucide-shield-check size-4 shrink-0","children":[["$","path","oel41y",{"d":"M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z"}],["$","path","dzmm74",{"d":"m9 12 2 2 4-4"}],"$undefined"]}]]}],["$","span","1",{"className":"flex items-center gap-7 px-7 text-sm font-extrabold whitespace-nowrap","children":["CE CERTIFIED",["$","svg",null,{"ref":"$undefined","xmlns":"http://www.w3.org/2000/svg","width":24,"height":24,"viewBox":"0 0 24 24","fill":"none","stroke":"currentColor","strokeWidth":2.5,"strokeLinecap":"round","strokeLinejoin":"round","className":"lucide lucide-shield-check size-4 shrink-0","children":[["$","path","oel41y",{"d":"M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z"}],["$","path","dzmm74",{"d":"m9 12 2 2 4-4"}],"$undefined"]}]]}],["$","span","2",{"className":"flex items-center gap-7 px-7 text-sm font-extrabold whitespace-nowrap","children":["گارانتی اصالت کالا",["$","svg",null,{"ref":"$undefined","xmlns":"http://www.w3.org/2000/svg","width":24,"height":24,"viewBox":"0 0 24 24","fill":"none","stroke":"currentColor","strokeWidth":2.5,"strokeLinecap":"round","strokeLinejoin":"round","className":"lucide lucide-shield-check size-4 shrink-0","children":[["$","path","oel41y",{"d":"M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z"}],["$","path","dzmm74",{"d":"m9 12 2 2 4-4"}],"$undefined"]}]]}],["$","span","3",{"className":"flex items-center gap-7 px-7 text-sm font-extrabold whitespace-nowrap","children":["تحویل سراسری کشوری",["$","svg",null,{"ref":"$undefined","xmlns":"http://www.w3.org/2000/svg","width":24,"height":24,"viewBox":"0 0 24 24","fill":"none","stroke":"currentColor","strokeWidth":2.5,"strokeLinecap":"round","strokeLinejoin":"round","className":"lucide lucide-shield-check size-4 shrink-0","children":[["$","path","oel41y",{"d":"M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z"}],["$","path","dzmm74",{"d":"m9 12 2 2 4-4"}],"$undefined"]}]]}],["$","span","4",{"className":"flex items-center gap-7 px-7 text-sm font-extrabold whitespace-nowrap","children":["مشاوره و بازرسی تخصصی رایگان",["$","svg",null,{"ref":"$undefined","xmlns":"http://www.w3.org/2000/svg","width":24,"height":24,"viewBox":"0 0 24 24","fill":"none","stroke":"currentColor","strokeWidth":2.5,"strokeLinecap":"round","strokeLinejoin":"round","className":"lucide lucide-shield-check size-4 shrink-0","children":[["$","path","oel41y",{"d":"M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z"}],["$","path","dzmm74",{"d":"m9 12 2 2 4-4"}],"$undefined"]}]]}],["$","span","5",{"className":"flex items-center gap-7 px-7 text-sm font-extrabold whitespace-nowrap","children":["EN STANDARDS",["$","svg",null,{"ref":"$undefined","xmlns":"http://www.w3.org/2000/svg","width":24,"height":24,"viewBox":"0 0 24 24","fill":"none","stroke":"currentColor","strokeWidth":2.5,"strokeLinecap":"round","strokeLinejoin":"round","className":"lucide lucide-shield-check size-4 shrink-0","children":["$L1c","$L1d","$undefined"]}]]}],"$L1e","$L1f","$L20","$L21","$L22","$L23","$L24","$L25","$L26","$L27"]}]}],"$L28"]}]}]
|
||||
10:["$","section",null,{"className":"relative","aria-label":"آمار و دستاوردهای آریا ایمن","children":["$","div",null,{"className":"grid grid-cols-2 gap-px border-y border-line bg-line lg:grid-cols-4","children":[["$","div","سال تجربه در صنعت ایمنی",{"className":"group relative bg-bg p-8 transition-colors duration-500 hover:bg-panel md:p-10","children":[["$","span",null,{"className":"absolute end-5 top-5 font-mono text-[10px] tracking-[0.25em] text-muted/50 transition-colors duration-500 group-hover:text-accent/70","children":"SINCE 2007"}],["$","$L29",null,{"delay":0,"children":[["$","div",null,{"className":"text-4xl font-black md:text-6xl","children":["$","$L2a",null,{"end":18,"suffix":"+"}]}],["$","div",null,{"className":"mt-3 text-sm text-muted","children":"سال تجربه در صنعت ایمنی"}]]}],["$","span",null,{"className":"absolute bottom-0 start-0 h-0.5 w-0 bg-accent transition-all duration-500 group-hover:w-full"}]]}],["$","div","کد کالای ایمنی",{"className":"group relative bg-bg p-8 transition-colors duration-500 hover:bg-panel md:p-10","children":[["$","span",null,{"className":"absolute end-5 top-5 font-mono text-[10px] tracking-[0.25em] text-muted/50 transition-colors duration-500 group-hover:text-accent/70","children":"PPE CATALOG"}],["$","$L29",null,{"delay":0.08,"children":[["$","div",null,{"className":"text-4xl font-black md:text-6xl","children":["$","$L2a",null,{"end":2400,"suffix":"+"}]}],["$","div",null,{"className":"mt-3 text-sm text-muted","children":"کد کالای ایمنی"}]]}],["$","span",null,{"className":"absolute bottom-0 start-0 h-0.5 w-0 bg-accent transition-all duration-500 group-hover:w-full"}]]}],["$","div","مشتری سازمانی فعال",{"className":"group relative bg-bg p-8 transition-colors duration-500 hover:bg-panel md:p-10","children":[["$","span",null,{"className":"absolute end-5 top-5 font-mono text-[10px] tracking-[0.25em] text-muted/50 transition-colors duration-500 group-hover:text-accent/70","children":"B2B CLIENTS"}],["$","$L29",null,{"delay":0.16,"children":[["$","div",null,{"className":"text-4xl font-black md:text-6xl","children":["$","$L2a",null,{"end":850,"suffix":"+"}]}],["$","div",null,{"className":"mt-3 text-sm text-muted","children":"مشتری سازمانی فعال"}]]}],["$","span",null,{"className":"absolute bottom-0 start-0 h-0.5 w-0 bg-accent transition-all duration-500 group-hover:w-full"}]]}],["$","div","رضایت مشتریان",{"className":"group relative bg-bg p-8 transition-colors duration-500 hover:bg-panel md:p-10","children":[["$","span",null,{"className":"absolute end-5 top-5 font-mono text-[10px] tracking-[0.25em] text-muted/50 transition-colors duration-500 group-hover:text-accent/70","children":"SATISFACTION"}],["$","$L29",null,{"delay":0.24,"children":[["$","div",null,{"className":"text-4xl font-black md:text-6xl","children":["$","$L2a",null,{"end":98,"suffix":"٪"}]}],["$","div",null,{"className":"mt-3 text-sm text-muted","children":"رضایت مشتریان"}]]}],["$","span",null,{"className":"absolute bottom-0 start-0 h-0.5 w-0 bg-accent transition-all duration-500 group-hover:w-full"}]]}]]}]}]
|
||||
11:["$","$L2b",null,{}]
|
||||
12:["$","section",null,{"id":"about","aria-labelledby":"about-title","className":"relative overflow-hidden border-t border-line py-24 md:py-32","children":[["$","div",null,{"className":"absolute inset-0 bg-grid-fine opacity-50"}],["$","div",null,{"className":"relative mx-auto max-w-7xl px-5 md:px-8","children":["$","div",null,{"className":"grid items-center gap-14 lg:grid-cols-2","children":[["$","$L29",null,{"className":"relative order-2 lg:order-1","delay":0.1,"children":[["$","div",null,{"className":"relative overflow-hidden rounded-2xl border border-line","children":[["$","$L6",null,{"src":"/images/about.jpg","alt":"انبار تجهیزات ایمنی آریا ایمن","width":800,"height":600,"className":"aspect-[4/3] w-full object-cover"}],["$","div",null,{"className":"absolute inset-0 bg-gradient-to-t from-bg/80 via-transparent to-transparent"}],["$","div",null,{"className":"absolute bottom-5 start-5 flex items-center gap-4 rounded-xl border border-line bg-bg/80 px-5 py-4 backdrop-blur-md","children":[["$","span",null,{"className":"font-mono text-3xl font-bold text-accent","children":"۱۸+"}],["$","span",null,{"className":"text-xs leading-5 text-muted","children":["سال حفاظت از",["$","br",null,{}],"جان نیروی کار"]}]]}]]}],["$","div",null,{"className":"hazard absolute -top-3 -end-3 h-6 w-28 rounded-full opacity-90"}]]}],["$","div",null,{"className":"order-1 lg:order-2","children":[["$","div",null,{"className":"","children":[["$","$L29",null,{"children":["$","div",null,{"className":"flex items-center gap-3 ","children":[["$","span",null,{"className":"font-mono text-sm text-accent","children":"//"}],["$","span",null,{"className":"font-mono text-xs tracking-[0.25em] text-muted","children":"۰۲ — درباره ما"}],["$","span",null,{"className":"h-px w-14 bg-line"}]]}]}],["$","$L29",null,{"delay":0.08,"children":["$","h2",null,{"id":"about-title","className":"mt-5 text-3xl font-black leading-[1.25] md:text-5xl md:leading-[1.2]","children":["ایمنی برای ما شعار نیست؛",["$","br",null,{}],["$","span",null,{"className":"text-accent","children":"قرارداد است."}]]}]}],null]}],["$","$L29",null,{"delay":0.2,"children":["$","p",null,{"className":"mt-6 leading-9 text-muted","children":"از سال ۱۳۸۶، زمانی که اولین کلاه ایمنی را به یک کارگاه کوچک در جنوب تهران فروختیم، باور ما همین یک جمله بود: پشت هر تجهیز ایمنی، یک خانواده هست که منتظر بازگشت عزیزش است. امروز با بیش از ۸۵۰ سازمان، از پالایشگاهها تا معادن و سایتهای ساختمانی، در کنار کسانی هستیم که ایمنی را یک خط قرمز میدانند."}]}],["$","div",null,{"className":"mt-10 space-y-1","children":[["$","$L29","۱۳۸۶",{"delay":0.25,"children":["$","div",null,{"className":"group border-s-2 border-accent/30 ps-6 transition-colors duration-300 hover:border-accent","children":[["$","span",null,{"className":"font-mono text-sm font-bold text-accent","children":"۱۳۸۶"}],["$","p",null,{"className":"mt-1 pb-5 text-sm leading-7 text-ink/75","children":"تأسیس آریا ایمن در تهران با تمرکز بر تجهیزات حفاظت فردی"}]]}]}],["$","$L29","۱۳۹۲",{"delay":0.32,"children":["$","div",null,{"className":"group border-s-2 border-accent/30 ps-6 transition-colors duration-300 hover:border-accent","children":[["$","span",null,{"className":"font-mono text-sm font-bold text-accent","children":"۱۳۹۲"}],["$","p",null,{"className":"mt-1 pb-5 text-sm leading-7 text-ink/75","children":"توسعه شبکه توزیع به تمام ۳۱ استان کشور"}]]}]}],["$","$L29","۱۳۹۸",{"delay":0.39,"children":["$","div",null,{"className":"group border-s-2 border-accent/30 ps-6 transition-colors duration-300 hover:border-accent","children":[["$","span",null,{"className":"font-mono text-sm font-bold text-accent","children":"۱۳۹۸"}],["$","p",null,{"className":"mt-1 pb-5 text-sm leading-7 text-ink/75","children":"راهاندازی آزمایشگاه کنترل کیفیت و تست تجهیزات"}]]}]}],["$","$L29","۱۴۰۲",{"delay":0.46,"children":["$","div",null,{"className":"group border-s-2 border-accent/30 ps-6 transition-colors duration-300 hover:border-accent","children":[["$","span",null,{"className":"font-mono text-sm font-bold text-accent","children":"۱۴۰۲"}],["$","p",null,{"className":"mt-1 pb-5 text-sm leading-7 text-ink/75","children":"افتتاح مرکز تخصصی آموزش و بازرسی HSE"}]]}]}]]}],["$","$L29",null,{"delay":0.5,"children":["$","div",null,{"className":"mt-4 flex flex-wrap gap-3","children":["$L2c","$L2d","$L2e"]}]}]]}]]}]}]]}]
|
||||
13:["$","$L2f",null,{}]
|
||||
14:["$","section",null,{"id":"standards","aria-labelledby":"standards-title","className":"relative overflow-hidden border-t border-line py-24 md:py-32","children":[["$","div",null,{"aria-hidden":true,"className":"text-outline pointer-events-none absolute -bottom-14 -start-8 select-none font-mono text-[24vw] font-bold leading-none opacity-60","children":"CE"}],["$","div",null,{"className":"relative mx-auto max-w-7xl px-5 md:px-8","children":["$","div",null,{"className":"grid items-center gap-14 lg:grid-cols-12","children":[["$","div",null,{"className":"lg:col-span-5","children":[["$","div",null,{"className":"","children":[["$","$L29",null,{"children":["$","div",null,{"className":"flex items-center gap-3 ","children":[["$","span",null,{"className":"font-mono text-sm text-accent","children":"//"}],["$","span",null,{"className":"font-mono text-xs tracking-[0.25em] text-muted","children":"۰۴ — استانداردها"}],["$","span",null,{"className":"h-px w-14 bg-line"}]]}]}],["$","$L29",null,{"delay":0.08,"children":["$","h2",null,{"id":"standards-title","className":"mt-5 text-3xl font-black leading-[1.25] md:text-5xl md:leading-[1.2]","children":["مهرتأیید جهانی",["$","br",null,{}],"روی هر محصول"]}]}],["$","$L29",null,{"delay":0.16,"children":["$","p",null,{"className":"mt-5 max-w-xl leading-8 text-muted ","children":"ما فقط تجهیزاتی را عرضه میکنیم که تأییدیه معتبر بینالمللی و تست آزمایشگاهی داشته باشند؛ بدون استثنا."}]}]]}],["$","$L29",null,{"delay":0.25,"children":["$","div",null,{"className":"mt-8 flex items-start gap-4 rounded-xl border border-accent/25 bg-accent/5 p-5","children":[["$","svg",null,{"ref":"$undefined","xmlns":"http://www.w3.org/2000/svg","width":24,"height":24,"viewBox":"0 0 24 24","fill":"none","stroke":"currentColor","strokeWidth":2,"strokeLinecap":"round","strokeLinejoin":"round","className":"lucide lucide-file-search size-6 shrink-0 text-accent","children":[["$","path","tnqrlb",{"d":"M14 2v4a2 2 0 0 0 2 2h4"}],["$","path","ms7g94",{"d":"M4.268 21a2 2 0 0 0 1.727 1H18a2 2 0 0 0 2-2V7l-5-5H6a2 2 0 0 0-2 2v3"}],["$","path","1j6qii",{"d":"m9 18-1.5-1.5"}],["$","circle","ufru5t",{"cx":"5","cy":"14","r":"3"}],"$undefined"]}],["$","p",null,{"className":"text-sm leading-8 text-ink/80","children":"شماره سریال تمام محصولات در پایگاه داده استانداردهای اروپا قابل استعلام است و گواهی تست هر بچ تحویل مشتری میشود."}]]}]}],["$","$L29",null,{"delay":0.35,"children":["$","a",null,{"href":"#contact","className":"group mt-8 inline-flex items-center gap-2.5 rounded-full border border-line px-6 py-3.5 text-sm font-bold transition-colors hover:border-accent hover:text-accent","children":[["$","svg",null,{"ref":"$undefined","xmlns":"http://www.w3.org/2000/svg","width":24,"height":24,"viewBox":"0 0 24 24","fill":"none","stroke":"currentColor","strokeWidth":2,"strokeLinecap":"round","strokeLinejoin":"round","className":"lucide lucide-shield-check size-4 text-accent","children":[["$","path","oel41y",{"d":"M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z"}],["$","path","dzmm74",{"d":"m9 12 2 2 4-4"}],"$undefined"]}],"درخواست گواهی تست محصولات"]}]}]]}],["$","div",null,{"className":"grid gap-4 sm:grid-cols-2 lg:col-span-7 xl:grid-cols-3","children":[["$","$L29","EN 397",{"delay":0,"children":["$","div",null,{"data-hover":true,"className":"group relative h-full border border-line bg-panel/50 p-6 text-center transition-all duration-500 hover:-translate-y-1.5 hover:border-accent/50 hover:bg-panel","children":[["$","span",null,{"className":"absolute end-3 top-3 font-mono text-[9px] tracking-[0.2em] text-muted/50","children":"CERT"}],["$","div",null,{"className":"mx-auto flex size-24 items-center justify-center rounded-full border border-dashed border-ink/20 transition-all duration-500 group-hover:rotate-12 group-hover:border-accent/60","children":["$","div",null,{"children":[["$","div",null,{"className":"font-mono text-base font-bold text-ink transition-colors duration-300 group-hover:text-accent","children":"EN 397"}],["$","div",null,{"className":"mx-auto mt-1.5 h-px w-8 bg-line transition-colors duration-300 group-hover:bg-accent/50"}],"$L30"]}]}],"$L31"]}]}],"$L32","$L33","$L34","$L35","$L36"]}]]}]}]]}]
|
||||
15:["$","$L37",null,{}]
|
||||
16:["$","$L38",null,{}]
|
||||
17:["$","$L39",null,{}]
|
||||
18:["$","footer",null,{"className":"relative overflow-hidden border-t border-line","children":[["$","div",null,{"className":"hazard h-2.5"}],["$","div",null,{"className":"mx-auto max-w-7xl px-5 md:px-8","children":[["$","div",null,{"className":"grid gap-12 py-16 md:grid-cols-12 md:py-20","children":[["$","div",null,{"className":"md:col-span-5","children":[["$","a",null,{"href":"#home","className":"flex items-center gap-3","aria-label":"آریا ایمن","children":[["$","span",null,{"className":"flex size-10 items-center justify-center rounded-xl bg-accent text-bg shadow-[0_0_28px_rgba(255,90,0,0.35)]","children":["$","svg",null,{"ref":"$undefined","xmlns":"http://www.w3.org/2000/svg","width":24,"height":24,"viewBox":"0 0 24 24","fill":"none","stroke":"currentColor","strokeWidth":2,"strokeLinecap":"round","strokeLinejoin":"round","className":"lucide lucide-shield-check size-6","children":[["$","path","oel41y",{"d":"M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z"}],["$","path","dzmm74",{"d":"m9 12 2 2 4-4"}],"$undefined"]}]}],["$","span",null,{"className":"leading-tight","children":[["$","span",null,{"className":"block text-lg font-black","children":"آریا ایمن"}],["$","span",null,{"className":"block font-mono text-[9px] tracking-[0.32em] text-muted","children":"ARIA IMEN CO."}]]}]]}],["$","p",null,{"className":"mt-6 max-w-sm text-sm leading-8 text-muted","children":"تأمینکننده تخصصی تجهیزات حفاظت فردی و راهکارهای ایمنی صنعتی؛ همراه سازمانها از سال ۱۳۸۶ در مسیر صفر شدن حوادث کاری."}],["$","div",null,{"className":"mt-7 flex gap-3","children":[["$","a","وبسایت",{"href":"#contact","aria-label":"وبسایت","className":"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","children":["$","svg",null,{"ref":"$undefined","xmlns":"http://www.w3.org/2000/svg","width":24,"height":24,"viewBox":"0 0 24 24","fill":"none","stroke":"currentColor","strokeWidth":2,"strokeLinecap":"round","strokeLinejoin":"round","className":"lucide lucide-globe size-4","children":[["$","circle","1mglay",{"cx":"12","cy":"12","r":"10"}],["$","path","13o1zl",{"d":"M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20"}],["$","path","9i4pu4",{"d":"M2 12h20"}],"$undefined"]}]}],["$","a","تلگرام",{"href":"#contact","aria-label":"تلگرام","className":"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","children":["$","svg",null,{"ref":"$undefined","xmlns":"http://www.w3.org/2000/svg","width":24,"height":24,"viewBox":"0 0 24 24","fill":"none","stroke":"currentColor","strokeWidth":2,"strokeLinecap":"round","strokeLinejoin":"round","className":"lucide lucide-send size-4","children":[["$","path","1ffxy3",{"d":"M14.536 21.686a.5.5 0 0 0 .937-.024l6.5-19a.496.496 0 0 0-.635-.635l-19 6.5a.5.5 0 0 0-.024.937l7.93 3.18a2 2 0 0 1 1.112 1.11z"}],["$","path","12cjpa",{"d":"m21.854 2.147-10.94 10.939"}],"$undefined"]}]}],["$","a","ایمیل",{"href":"#contact","aria-label":"ایمیل","className":"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","children":["$","svg",null,{"ref":"$undefined","xmlns":"http://www.w3.org/2000/svg","width":24,"height":24,"viewBox":"0 0 24 24","fill":"none","stroke":"currentColor","strokeWidth":2,"strokeLinecap":"round","strokeLinejoin":"round","className":"lucide lucide-at-sign size-4","children":[["$","circle","4exip2",{"cx":"12","cy":"12","r":"4"}],["$","path","7n84p3",{"d":"M16 8v5a3 3 0 0 0 6 0v-1a10 10 0 1 0-4 8"}],"$undefined"]}]}],["$","a","تماس",{"href":"#contact","aria-label":"تماس","className":"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","children":["$","svg",null,{"ref":"$undefined","xmlns":"http://www.w3.org/2000/svg","width":24,"height":24,"viewBox":"0 0 24 24","fill":"none","stroke":"currentColor","strokeWidth":2,"strokeLinecap":"round","strokeLinejoin":"round","className":"lucide lucide-phone size-4","children":["$L3a","$undefined"]}]}]]}]]}],"$L3b","$L3c","$L3d"]}],"$L3e","$L3f"]}]]}]
|
||||
19:["$","$L40",null,{"children":["$L41",["$","$L42",null,{"promise":"$@43"}]]}]
|
||||
1a:["$","$1","h",{"children":[null,[["$","$L44",null,{"children":"$L45"}],null],["$","$L46",null,{"children":["$","div",null,{"hidden":true,"children":["$","$47",null,{"fallback":null,"children":"$L48"}]}]}]]}]
|
||||
1c:["$","path","oel41y",{"d":"M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z"}]
|
||||
1d:["$","path","dzmm74",{"d":"m9 12 2 2 4-4"}]
|
||||
1e:["$","span","6",{"className":"flex items-center gap-7 px-7 text-sm font-extrabold whitespace-nowrap","children":["پشتیبانی ۲۴/۷ قراردادهای سازمانی",["$","svg",null,{"ref":"$undefined","xmlns":"http://www.w3.org/2000/svg","width":24,"height":24,"viewBox":"0 0 24 24","fill":"none","stroke":"currentColor","strokeWidth":2.5,"strokeLinecap":"round","strokeLinejoin":"round","className":"lucide lucide-shield-check size-4 shrink-0","children":[["$","path","oel41y",{"d":"M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z"}],["$","path","dzmm74",{"d":"m9 12 2 2 4-4"}],"$undefined"]}]]}]
|
||||
1f:["$","span","7",{"className":"flex items-center gap-7 px-7 text-sm font-extrabold whitespace-nowrap","children":["تست نمونه قبل از خرید",["$","svg",null,{"ref":"$undefined","xmlns":"http://www.w3.org/2000/svg","width":24,"height":24,"viewBox":"0 0 24 24","fill":"none","stroke":"currentColor","strokeWidth":2.5,"strokeLinecap":"round","strokeLinejoin":"round","className":"lucide lucide-shield-check size-4 shrink-0","children":[["$","path","oel41y",{"d":"M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z"}],["$","path","dzmm74",{"d":"m9 12 2 2 4-4"}],"$undefined"]}]]}]
|
||||
20:["$","span","8",{"className":"flex items-center gap-7 px-7 text-sm font-extrabold whitespace-nowrap","children":["ISO 9001:2015",["$","svg",null,{"ref":"$undefined","xmlns":"http://www.w3.org/2000/svg","width":24,"height":24,"viewBox":"0 0 24 24","fill":"none","stroke":"currentColor","strokeWidth":2.5,"strokeLinecap":"round","strokeLinejoin":"round","className":"lucide lucide-shield-check size-4 shrink-0","children":[["$","path","oel41y",{"d":"M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z"}],["$","path","dzmm74",{"d":"m9 12 2 2 4-4"}],"$undefined"]}]]}]
|
||||
21:["$","span","9",{"className":"flex items-center gap-7 px-7 text-sm font-extrabold whitespace-nowrap","children":["CE CERTIFIED",["$","svg",null,{"ref":"$undefined","xmlns":"http://www.w3.org/2000/svg","width":24,"height":24,"viewBox":"0 0 24 24","fill":"none","stroke":"currentColor","strokeWidth":2.5,"strokeLinecap":"round","strokeLinejoin":"round","className":"lucide lucide-shield-check size-4 shrink-0","children":[["$","path","oel41y",{"d":"M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z"}],["$","path","dzmm74",{"d":"m9 12 2 2 4-4"}],"$undefined"]}]]}]
|
||||
22:["$","span","10",{"className":"flex items-center gap-7 px-7 text-sm font-extrabold whitespace-nowrap","children":["گارانتی اصالت کالا",["$","svg",null,{"ref":"$undefined","xmlns":"http://www.w3.org/2000/svg","width":24,"height":24,"viewBox":"0 0 24 24","fill":"none","stroke":"currentColor","strokeWidth":2.5,"strokeLinecap":"round","strokeLinejoin":"round","className":"lucide lucide-shield-check size-4 shrink-0","children":[["$","path","oel41y",{"d":"M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z"}],["$","path","dzmm74",{"d":"m9 12 2 2 4-4"}],"$undefined"]}]]}]
|
||||
23:["$","span","11",{"className":"flex items-center gap-7 px-7 text-sm font-extrabold whitespace-nowrap","children":["تحویل سراسری کشوری",["$","svg",null,{"ref":"$undefined","xmlns":"http://www.w3.org/2000/svg","width":24,"height":24,"viewBox":"0 0 24 24","fill":"none","stroke":"currentColor","strokeWidth":2.5,"strokeLinecap":"round","strokeLinejoin":"round","className":"lucide lucide-shield-check size-4 shrink-0","children":[["$","path","oel41y",{"d":"M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z"}],["$","path","dzmm74",{"d":"m9 12 2 2 4-4"}],"$undefined"]}]]}]
|
||||
24:["$","span","12",{"className":"flex items-center gap-7 px-7 text-sm font-extrabold whitespace-nowrap","children":["مشاوره و بازرسی تخصصی رایگان",["$","svg",null,{"ref":"$undefined","xmlns":"http://www.w3.org/2000/svg","width":24,"height":24,"viewBox":"0 0 24 24","fill":"none","stroke":"currentColor","strokeWidth":2.5,"strokeLinecap":"round","strokeLinejoin":"round","className":"lucide lucide-shield-check size-4 shrink-0","children":[["$","path","oel41y",{"d":"M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z"}],["$","path","dzmm74",{"d":"m9 12 2 2 4-4"}],"$undefined"]}]]}]
|
||||
25:["$","span","13",{"className":"flex items-center gap-7 px-7 text-sm font-extrabold whitespace-nowrap","children":["EN STANDARDS",["$","svg",null,{"ref":"$undefined","xmlns":"http://www.w3.org/2000/svg","width":24,"height":24,"viewBox":"0 0 24 24","fill":"none","stroke":"currentColor","strokeWidth":2.5,"strokeLinecap":"round","strokeLinejoin":"round","className":"lucide lucide-shield-check size-4 shrink-0","children":[["$","path","oel41y",{"d":"M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z"}],["$","path","dzmm74",{"d":"m9 12 2 2 4-4"}],"$undefined"]}]]}]
|
||||
26:["$","span","14",{"className":"flex items-center gap-7 px-7 text-sm font-extrabold whitespace-nowrap","children":["پشتیبانی ۲۴/۷ قراردادهای سازمانی",["$","svg",null,{"ref":"$undefined","xmlns":"http://www.w3.org/2000/svg","width":24,"height":24,"viewBox":"0 0 24 24","fill":"none","stroke":"currentColor","strokeWidth":2.5,"strokeLinecap":"round","strokeLinejoin":"round","className":"lucide lucide-shield-check size-4 shrink-0","children":[["$","path","oel41y",{"d":"M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z"}],["$","path","dzmm74",{"d":"m9 12 2 2 4-4"}],"$undefined"]}]]}]
|
||||
27:["$","span","15",{"className":"flex items-center gap-7 px-7 text-sm font-extrabold whitespace-nowrap","children":["تست نمونه قبل از خرید",["$","svg",null,{"ref":"$undefined","xmlns":"http://www.w3.org/2000/svg","width":24,"height":24,"viewBox":"0 0 24 24","fill":"none","stroke":"currentColor","strokeWidth":2.5,"strokeLinecap":"round","strokeLinejoin":"round","className":"lucide lucide-shield-check size-4 shrink-0","children":[["$","path","oel41y",{"d":"M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z"}],["$","path","dzmm74",{"d":"m9 12 2 2 4-4"}],"$undefined"]}]]}]
|
||||
28:["$","div",null,{"className":"hazard h-2.5"}]
|
||||
2c:["$","span","نماینده رسمی ۴۰+ برند جهانی",{"className":"inline-flex items-center gap-2 rounded-full border border-line bg-panel/60 px-4 py-2 text-xs text-ink/80 transition-colors hover:border-accent/50 hover:text-ink","children":[["$","svg",null,{"ref":"$undefined","xmlns":"http://www.w3.org/2000/svg","width":24,"height":24,"viewBox":"0 0 24 24","fill":"none","stroke":"currentColor","strokeWidth":2,"strokeLinecap":"round","strokeLinejoin":"round","className":"lucide lucide-globe size-4 text-accent","children":[["$","circle","1mglay",{"cx":"12","cy":"12","r":"10"}],["$","path","13o1zl",{"d":"M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20"}],["$","path","9i4pu4",{"d":"M2 12h20"}],"$undefined"]}],"نماینده رسمی ۴۰+ برند جهانی"]}]
|
||||
2d:["$","span","تیم مهندسی و بازرسی HSE",{"className":"inline-flex items-center gap-2 rounded-full border border-line bg-panel/60 px-4 py-2 text-xs text-ink/80 transition-colors hover:border-accent/50 hover:text-ink","children":[["$","svg",null,{"ref":"$undefined","xmlns":"http://www.w3.org/2000/svg","width":24,"height":24,"viewBox":"0 0 24 24","fill":"none","stroke":"currentColor","strokeWidth":2,"strokeLinecap":"round","strokeLinejoin":"round","className":"lucide lucide-users size-4 text-accent","children":[["$","path","1yyitq",{"d":"M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"}],["$","circle","nufk8",{"cx":"9","cy":"7","r":"4"}],["$","path","kshegd",{"d":"M22 21v-2a4 4 0 0 0-3-3.87"}],["$","path","1da9ce",{"d":"M16 3.13a4 4 0 0 1 0 7.75"}],"$undefined"]}],"تیم مهندسی و بازرسی HSE"]}]
|
||||
2e:["$","span","پشتیبانی ۲۴/۷ قراردادها",{"className":"inline-flex items-center gap-2 rounded-full border border-line bg-panel/60 px-4 py-2 text-xs text-ink/80 transition-colors hover:border-accent/50 hover:text-ink","children":[["$","svg",null,{"ref":"$undefined","xmlns":"http://www.w3.org/2000/svg","width":24,"height":24,"viewBox":"0 0 24 24","fill":"none","stroke":"currentColor","strokeWidth":2,"strokeLinecap":"round","strokeLinejoin":"round","className":"lucide lucide-headset size-4 text-accent","children":[["$","path","12oyoe",{"d":"M3 11h3a2 2 0 0 1 2 2v3a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-5Zm0 0a9 9 0 1 1 18 0m0 0v5a2 2 0 0 1-2 2h-1a2 2 0 0 1-2-2v-3a2 2 0 0 1 2-2h3Z"}],["$","path","1x7m43",{"d":"M21 16v2a4 4 0 0 1-4 4h-5"}],"$undefined"]}],"پشتیبانی ۲۴/۷ قراردادها"]}]
|
||||
30:["$","div",null,{"className":"mt-1.5 font-mono text-[8px] tracking-[0.25em] text-muted","children":"EURO NORM"}]
|
||||
31:["$","div",null,{"className":"mt-4 text-sm font-medium text-ink/85","children":"کلاه ایمنی صنعتی"}]
|
||||
32:["$","$L29","EN 388",{"delay":0.06,"children":["$","div",null,{"data-hover":true,"className":"group relative h-full border border-line bg-panel/50 p-6 text-center transition-all duration-500 hover:-translate-y-1.5 hover:border-accent/50 hover:bg-panel","children":[["$","span",null,{"className":"absolute end-3 top-3 font-mono text-[9px] tracking-[0.2em] text-muted/50","children":"CERT"}],["$","div",null,{"className":"mx-auto flex size-24 items-center justify-center rounded-full border border-dashed border-ink/20 transition-all duration-500 group-hover:rotate-12 group-hover:border-accent/60","children":["$","div",null,{"children":[["$","div",null,{"className":"font-mono text-base font-bold text-ink transition-colors duration-300 group-hover:text-accent","children":"EN 388"}],["$","div",null,{"className":"mx-auto mt-1.5 h-px w-8 bg-line transition-colors duration-300 group-hover:bg-accent/50"}],["$","div",null,{"className":"mt-1.5 font-mono text-[8px] tracking-[0.25em] text-muted","children":"EURO NORM"}]]}]}],["$","div",null,{"className":"mt-4 text-sm font-medium text-ink/85","children":"دستکشهای مکانیکی"}]]}]}]
|
||||
33:["$","$L29","EN 166",{"delay":0.12,"children":["$","div",null,{"data-hover":true,"className":"group relative h-full border border-line bg-panel/50 p-6 text-center transition-all duration-500 hover:-translate-y-1.5 hover:border-accent/50 hover:bg-panel","children":[["$","span",null,{"className":"absolute end-3 top-3 font-mono text-[9px] tracking-[0.2em] text-muted/50","children":"CERT"}],["$","div",null,{"className":"mx-auto flex size-24 items-center justify-center rounded-full border border-dashed border-ink/20 transition-all duration-500 group-hover:rotate-12 group-hover:border-accent/60","children":["$","div",null,{"children":[["$","div",null,{"className":"font-mono text-base font-bold text-ink transition-colors duration-300 group-hover:text-accent","children":"EN 166"}],["$","div",null,{"className":"mx-auto mt-1.5 h-px w-8 bg-line transition-colors duration-300 group-hover:bg-accent/50"}],["$","div",null,{"className":"mt-1.5 font-mono text-[8px] tracking-[0.25em] text-muted","children":"EURO NORM"}]]}]}],["$","div",null,{"className":"mt-4 text-sm font-medium text-ink/85","children":"محافظ چشم و صورت"}]]}]}]
|
||||
34:["$","$L29","EN 361",{"delay":0.18,"children":["$","div",null,{"data-hover":true,"className":"group relative h-full border border-line bg-panel/50 p-6 text-center transition-all duration-500 hover:-translate-y-1.5 hover:border-accent/50 hover:bg-panel","children":[["$","span",null,{"className":"absolute end-3 top-3 font-mono text-[9px] tracking-[0.2em] text-muted/50","children":"CERT"}],["$","div",null,{"className":"mx-auto flex size-24 items-center justify-center rounded-full border border-dashed border-ink/20 transition-all duration-500 group-hover:rotate-12 group-hover:border-accent/60","children":["$","div",null,{"children":[["$","div",null,{"className":"font-mono text-base font-bold text-ink transition-colors duration-300 group-hover:text-accent","children":"EN 361"}],["$","div",null,{"className":"mx-auto mt-1.5 h-px w-8 bg-line transition-colors duration-300 group-hover:bg-accent/50"}],["$","div",null,{"className":"mt-1.5 font-mono text-[8px] tracking-[0.25em] text-muted","children":"EURO NORM"}]]}]}],["$","div",null,{"className":"mt-4 text-sm font-medium text-ink/85","children":"هارنس ضدسقوط"}]]}]}]
|
||||
35:["$","$L29","ISO 20345",{"delay":0.24,"children":["$","div",null,{"data-hover":true,"className":"group relative h-full border border-line bg-panel/50 p-6 text-center transition-all duration-500 hover:-translate-y-1.5 hover:border-accent/50 hover:bg-panel","children":[["$","span",null,{"className":"absolute end-3 top-3 font-mono text-[9px] tracking-[0.2em] text-muted/50","children":"CERT"}],["$","div",null,{"className":"mx-auto flex size-24 items-center justify-center rounded-full border border-dashed border-ink/20 transition-all duration-500 group-hover:rotate-12 group-hover:border-accent/60","children":["$","div",null,{"children":[["$","div",null,{"className":"font-mono text-base font-bold text-ink transition-colors duration-300 group-hover:text-accent","children":"ISO 20345"}],["$","div",null,{"className":"mx-auto mt-1.5 h-px w-8 bg-line transition-colors duration-300 group-hover:bg-accent/50"}],["$","div",null,{"className":"mt-1.5 font-mono text-[8px] tracking-[0.25em] text-muted","children":"EURO NORM"}]]}]}],["$","div",null,{"className":"mt-4 text-sm font-medium text-ink/85","children":"کفش ایمنی"}]]}]}]
|
||||
36:["$","$L29","ISO 9001",{"delay":0.3,"children":["$","div",null,{"data-hover":true,"className":"group relative h-full border border-line bg-panel/50 p-6 text-center transition-all duration-500 hover:-translate-y-1.5 hover:border-accent/50 hover:bg-panel","children":[["$","span",null,{"className":"absolute end-3 top-3 font-mono text-[9px] tracking-[0.2em] text-muted/50","children":"CERT"}],["$","div",null,{"className":"mx-auto flex size-24 items-center justify-center rounded-full border border-dashed border-ink/20 transition-all duration-500 group-hover:rotate-12 group-hover:border-accent/60","children":["$","div",null,{"children":[["$","div",null,{"className":"font-mono text-base font-bold text-ink transition-colors duration-300 group-hover:text-accent","children":"ISO 9001"}],["$","div",null,{"className":"mx-auto mt-1.5 h-px w-8 bg-line transition-colors duration-300 group-hover:bg-accent/50"}],["$","div",null,{"className":"mt-1.5 font-mono text-[8px] tracking-[0.25em] text-muted","children":"EURO NORM"}]]}]}],["$","div",null,{"className":"mt-4 text-sm font-medium text-ink/85","children":"سیستم مدیریت کیفیت"}]]}]}]
|
||||
3a:["$","path","foiqr5",{"d":"M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z"}]
|
||||
3b:["$","div",null,{"className":"md:col-span-2","children":[["$","div",null,{"className":"font-mono text-xs tracking-[0.25em] text-accent","children":"// دسترسی"}],["$","ul",null,{"className":"mt-5 space-y-3","children":[["$","li","#home",{"children":["$","a",null,{"href":"#home","className":"text-sm text-muted transition-colors hover:text-ink","children":"خانه"}]}],["$","li","#products",{"children":["$","a",null,{"href":"#products","className":"text-sm text-muted transition-colors hover:text-ink","children":"محصولات"}]}],["$","li","#about",{"children":["$","a",null,{"href":"#about","className":"text-sm text-muted transition-colors hover:text-ink","children":"درباره ما"}]}],["$","li","#services",{"children":["$","a",null,{"href":"#services","className":"text-sm text-muted transition-colors hover:text-ink","children":"خدمات"}]}],["$","li","#standards",{"children":["$","a",null,{"href":"#standards","className":"text-sm text-muted transition-colors hover:text-ink","children":"استانداردها"}]}],["$","li","#industries",{"children":["$","a",null,{"href":"#industries","className":"text-sm text-muted transition-colors hover:text-ink","children":"صنایع"}]}]]}]]}]
|
||||
3c:["$","div",null,{"className":"md:col-span-2","children":[["$","div",null,{"className":"font-mono text-xs tracking-[0.25em] text-accent","children":"// محصولات"}],["$","ul",null,{"className":"mt-5 space-y-3","children":[["$","li","کلاه ایمنی",{"children":["$","a",null,{"href":"#products","className":"text-sm text-muted transition-colors hover:text-ink","children":"کلاه ایمنی"}]}],["$","li","دستکش ضدبرش",{"children":["$","a",null,{"href":"#products","className":"text-sm text-muted transition-colors hover:text-ink","children":"دستکش ضدبرش"}]}],["$","li","کفش ایمنی",{"children":["$","a",null,{"href":"#products","className":"text-sm text-muted transition-colors hover:text-ink","children":"کفش ایمنی"}]}],["$","li","عینک ایمنی",{"children":["$","a",null,{"href":"#products","className":"text-sm text-muted transition-colors hover:text-ink","children":"عینک ایمنی"}]}],["$","li","هارنس ضدسقوط",{"children":["$","a",null,{"href":"#products","className":"text-sm text-muted transition-colors hover:text-ink","children":"هارنس ضدسقوط"}]}],["$","li","لباس کار بازتابنده",{"children":["$","a",null,{"href":"#products","className":"text-sm text-muted transition-colors hover:text-ink","children":"لباس کار بازتابنده"}]}]]}]]}]
|
||||
3d:["$","div",null,{"className":"md:col-span-3","children":[["$","div",null,{"className":"font-mono text-xs tracking-[0.25em] text-accent","children":"// ارتباط"}],["$","address",null,{"className":"mt-5 space-y-3 text-sm text-muted not-italic","children":[["$","p",null,{"className":"leading-7","children":["تهران، خیابان کارگر شمالی،",["$","br",null,{}],"خیابان فر، کوچه دوم، پلاک ۱۲"]}],["$","p",null,{"className":"font-mono tracking-wider","dir":"ltr","children":"۰۲۱ - ۹۱ ۰۰ ۸۸ ۰۰"}],["$","p",null,{"className":"font-mono tracking-wider","dir":"ltr","children":"info@ariaiman.ir"}],["$","p",null,{"className":"pt-2 text-xs leading-6","children":["شنبه تا پنجشنبه — ۸:۰۰ تا ۱۷:۰۰",["$","br",null,{}],"پشتیبانی اضطراری: ۲۴/۷"]}]]}]]}]
|
||||
3e:["$","div",null,{"aria-hidden":true,"className":"pointer-events-none select-none pb-6","children":["$","div",null,{"className":"text-outline text-center text-[17vw] font-black leading-[0.85] md:text-[11vw]","children":"آریا ایمن"}]}]
|
||||
3f:["$","div",null,{"className":"flex flex-wrap items-center justify-between gap-4 border-t border-line py-6 text-xs text-muted","children":[["$","div",null,{"children":"© ۱۴۰۴ آریا ایمن — تمامی حقوق محفوظ است."}],["$","div",null,{"className":"font-mono text-[10px] tracking-[0.25em]","children":"ISO 9001:2015 — CE CERTIFIED PPE SUPPLIER"}]]}]
|
||||
45:[["$","meta","0",{"charSet":"utf-8"}],["$","meta","1",{"name":"viewport","content":"width=device-width, initial-scale=1"}],["$","meta","2",{"name":"theme-color","content":"#0a0a0c"}]]
|
||||
41:null
|
||||
49:I[622,[],"IconMark"]
|
||||
43:{"metadata":[["$","title","0",{"children":"آریا ایمن | تجهیزات ایمنی و حفاظت فردی صنعتی"}],["$","meta","1",{"name":"description","content":"آریا ایمن — تأمینکننده تخصصی تجهیزات حفاظت فردی (PPE)، بازرسی، آموزش و راهکارهای ایمنی صنعتی برای سازمانهایی که جان انسانها را جدی میگیرند."}],["$","link","2",{"rel":"manifest","href":"/manifest.webmanifest","crossOrigin":"$undefined"}],["$","meta","3",{"name":"robots","content":"index, follow"}],["$","link","4",{"rel":"canonical","href":"https://ariaiman.ir"}],["$","meta","5",{"name":"format-detection","content":"telephone=no"}],["$","meta","6",{"property":"og:title","content":"آریا ایمن | تجهیزات ایمنی و حفاظت فردی صنعتی"}],["$","meta","7",{"property":"og:description","content":"آریا ایمن — تأمینکننده تخصصی تجهیزات حفاظت فردی (PPE)، بازرسی، آموزش و راهکارهای ایمنی صنعتی برای سازمانهایی که جان انسانها را جدی میگیرند."}],["$","meta","8",{"property":"og:url","content":"https://ariaiman.ir"}],["$","meta","9",{"property":"og:site_name","content":"آریا ایمن"}],["$","meta","10",{"property":"og:locale","content":"fa_IR"}],["$","meta","11",{"property":"og:type","content":"website"}],["$","meta","12",{"name":"twitter:card","content":"summary_large_image"}],["$","meta","13",{"name":"twitter:title","content":"آریا ایمن | تجهیزات ایمنی و حفاظت فردی صنعتی"}],["$","meta","14",{"name":"twitter:description","content":"آریا ایمن — تأمینکننده تخصصی تجهیزات حفاظت فردی (PPE)، بازرسی، آموزش و راهکارهای ایمنی صنعتی برای سازمانهایی که جان انسانها را جدی میگیرند."}],["$","link","15",{"rel":"icon","href":"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'%3E%3Crect width='100' height='100' rx='22' fill='%23FF5A00'/%3E%3Cpath d='M50 20 L72 28 V48 C72 66 62 76 50 82 C38 76 28 66 28 48 V28 Z' fill='%230A0A0C'/%3E%3Cpath d='M40 50 L47 57 L62 42' stroke='%23FF5A00' stroke-width='7' fill='none' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E"}],["$","$L49","16",{}]],"error":null,"digest":"$undefined"}
|
||||
48:"$43:metadata"
|
||||
@@ -1 +0,0 @@
|
||||
{"name":"آریا ایمن","short_name":"آریا ایمن","lang":"fa","dir":"rtl","start_url":"/","display":"standalone","background_color":"#0a0a0c","theme_color":"#0a0a0c","icons":[]}
|
||||
@@ -1,5 +0,0 @@
|
||||
User-Agent: *
|
||||
Allow: /
|
||||
|
||||
Host: https://ariaiman.ir
|
||||
Sitemap: https://ariaiman.ir/sitemap.xml
|
||||
@@ -1,9 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||
<url>
|
||||
<loc>https://ariaiman.ir/</loc>
|
||||
<lastmod>2026-09-27T05:23:55.892Z</lastmod>
|
||||
<changefreq>monthly</changefreq>
|
||||
<priority>1</priority>
|
||||
</url>
|
||||
</urlset>
|
||||
@@ -1,27 +1,31 @@
|
||||
{
|
||||
"name": "aria-imen-landing",
|
||||
"private": true,
|
||||
"version": "0.1.0",
|
||||
"version": "0.2.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
"build": "next build",
|
||||
"start": "next start",
|
||||
"lint": "next lint"
|
||||
"dev": "nuxt dev",
|
||||
"build": "nuxt generate",
|
||||
"preview": "npx serve out",
|
||||
"typecheck": "nuxt typecheck",
|
||||
"postinstall": "nuxt prepare"
|
||||
},
|
||||
"dependencies": {
|
||||
"framer-motion": "^13.2.0",
|
||||
"lucide-react": "^0.475.0",
|
||||
"next": "15.5.25",
|
||||
"react": "19.0.0",
|
||||
"react-dom": "19.0.0"
|
||||
"@pinia/nuxt": "^1.0.2",
|
||||
"@vueuse/core": "^15.0.0",
|
||||
"ant-design-vue": "^4.2.6",
|
||||
"lucide-vue-next": "^0.475.0",
|
||||
"motion-v": "^2.6.0",
|
||||
"nuxt": "^4.5.2",
|
||||
"pinia": "^4.0.3",
|
||||
"vue": "^3.5.43",
|
||||
"vue-router": "^5.3.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@tailwindcss/postcss": "4.1.17",
|
||||
"@types/node": "22.19.17",
|
||||
"@types/react": "19.0.8",
|
||||
"@types/react-dom": "19.0.3",
|
||||
"tailwindcss": "4.1.17",
|
||||
"typescript": "5.9.3"
|
||||
"@tailwindcss/vite": "^4.1.17",
|
||||
"@types/node": "^22.20.5",
|
||||
"tailwindcss": "^4.1.17",
|
||||
"typescript": "^5.9.3",
|
||||
"vue-tsc": "^3.3.12"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
const config = {
|
||||
plugins: {
|
||||
"@tailwindcss/postcss": {},
|
||||
},
|
||||
};
|
||||
|
||||
export default config;
|
||||
@@ -0,0 +1 @@
|
||||
<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><rect width='100' height='100' rx='22' fill='#FF5A00'/><path d='M50 20 L72 28 V48 C72 66 62 76 50 82 C38 76 28 66 28 48 V28 Z' fill='#0A0A0C'/><path d='M40 50 L47 57 L62 42' stroke='#FF5A00' stroke-width='7' fill='none' stroke-linecap='round' stroke-linejoin='round'/></svg>
|
||||
|
After Width: | Height: | Size: 337 B |
@@ -0,0 +1,23 @@
|
||||
import { siteConfig } from "../../shared/config/site";
|
||||
|
||||
export default defineEventHandler((event) => {
|
||||
setHeader(event, "Content-Type", "application/manifest+json; charset=utf-8");
|
||||
return {
|
||||
name: siteConfig.name,
|
||||
short_name: siteConfig.name,
|
||||
lang: siteConfig.lang,
|
||||
dir: siteConfig.dir,
|
||||
start_url: "/",
|
||||
display: "standalone",
|
||||
background_color: siteConfig.themeColor,
|
||||
theme_color: siteConfig.themeColor,
|
||||
icons: [
|
||||
{
|
||||
src: siteConfig.favicon,
|
||||
sizes: "any",
|
||||
type: "image/svg+xml",
|
||||
purpose: "any",
|
||||
},
|
||||
],
|
||||
};
|
||||
});
|
||||
@@ -0,0 +1,13 @@
|
||||
import { siteConfig } from "../../shared/config/site";
|
||||
|
||||
export default defineEventHandler((event) => {
|
||||
setHeader(event, "Content-Type", "text/plain; charset=utf-8");
|
||||
return [
|
||||
"User-Agent: *",
|
||||
"Allow: /",
|
||||
"",
|
||||
`Host: ${siteConfig.url}`,
|
||||
`Sitemap: ${siteConfig.url}/sitemap.xml`,
|
||||
"",
|
||||
].join("\n");
|
||||
});
|
||||
@@ -0,0 +1,15 @@
|
||||
import { absUrl } from "../../shared/config/site";
|
||||
|
||||
const pages = ["/"];
|
||||
|
||||
export default defineEventHandler((event) => {
|
||||
setHeader(event, "Content-Type", "application/xml; charset=utf-8");
|
||||
const lastmod = new Date().toISOString();
|
||||
const urls = pages
|
||||
.map(
|
||||
(p) =>
|
||||
`<url>\n<loc>${absUrl(p)}</loc>\n<lastmod>${lastmod}</lastmod>\n<changefreq>monthly</changefreq>\n<priority>1</priority>\n</url>`,
|
||||
)
|
||||
.join("\n");
|
||||
return `<?xml version="1.0" encoding="UTF-8"?>\n<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">\n${urls}\n</urlset>\n`;
|
||||
});
|
||||
@@ -8,9 +8,23 @@ export const siteConfig = {
|
||||
title: "آریا ایمن | تجهیزات ایمنی و حفاظت فردی صنعتی",
|
||||
description:
|
||||
"آریا ایمن — تأمینکننده تخصصی تجهیزات حفاظت فردی (PPE)، بازرسی، آموزش و راهکارهای ایمنی صنعتی برای سازمانهایی که جان انسانها را جدی میگیرند.",
|
||||
ogImage: "/opengraph-image.png",
|
||||
// TODO: replace with a dedicated 1200×630 social image when available
|
||||
ogImage: {
|
||||
src: "/images/hero.jpg",
|
||||
width: 1792,
|
||||
height: 1008,
|
||||
alt: "کارگر صنعتی با تجهیزات ایمنی کامل",
|
||||
},
|
||||
logo: "/images/hero.jpg", // TODO: replace with a dedicated PNG/SVG logo file when available
|
||||
favicon: "/favicon.svg",
|
||||
themeColor: "#0a0a0c",
|
||||
foundingDate: "2007",
|
||||
areaServed: "IR",
|
||||
openingHours: {
|
||||
days: ["Saturday", "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday"],
|
||||
opens: "08:00",
|
||||
closes: "17:00",
|
||||
},
|
||||
contact: {
|
||||
phone: "+98-21-91008800",
|
||||
phoneDisplay: "۰۲۱ - ۹۱ ۰۰ ۸۸ ۰۰",
|
||||
@@ -23,3 +37,6 @@ export const siteConfig = {
|
||||
},
|
||||
socials: [] as string[], // TODO: add real social profile URLs when available
|
||||
};
|
||||
|
||||
/** Absolute URL on the production domain. "/" → "https://domain/" (matches the sitemap entry). */
|
||||
export const absUrl = (p: string) => new URL(p, siteConfig.url).toString();
|
||||
@@ -1,7 +1,8 @@
|
||||
import { siteConfig as s } from "@/config/site";
|
||||
import { absUrl as abs, siteConfig as s } from "../config/site";
|
||||
|
||||
const abs = (p: string) => new URL(p, s.url).toString();
|
||||
const clean = <T extends object>(o: T) =>
|
||||
type Json = Record<string, unknown>;
|
||||
|
||||
const clean = <T extends object>(o: T): Json =>
|
||||
JSON.parse(
|
||||
JSON.stringify(o, (_, v) =>
|
||||
v === "" || (Array.isArray(v) && !v.length) ? undefined : v,
|
||||
@@ -14,17 +15,27 @@ export const organizationSchema = () =>
|
||||
"@type": "LocalBusiness",
|
||||
"@id": `${s.url}/#organization`,
|
||||
name: s.name,
|
||||
url: s.url,
|
||||
alternateName: s.nameEn,
|
||||
url: abs("/"),
|
||||
logo: abs(s.logo),
|
||||
image: abs(s.logo),
|
||||
description: s.description,
|
||||
email: s.contact.email,
|
||||
telephone: s.contact.phone,
|
||||
foundingDate: s.foundingDate,
|
||||
areaServed: s.areaServed,
|
||||
address: {
|
||||
"@type": "PostalAddress",
|
||||
streetAddress: s.contact.address.streetAddress,
|
||||
addressLocality: s.contact.address.addressLocality,
|
||||
addressCountry: s.contact.address.addressCountry,
|
||||
},
|
||||
openingHoursSpecification: {
|
||||
"@type": "OpeningHoursSpecification",
|
||||
dayOfWeek: s.openingHours.days,
|
||||
opens: s.openingHours.opens,
|
||||
closes: s.openingHours.closes,
|
||||
},
|
||||
sameAs: s.socials,
|
||||
});
|
||||
|
||||
@@ -32,7 +43,7 @@ export const websiteSchema = () => ({
|
||||
"@context": "https://schema.org",
|
||||
"@type": "WebSite",
|
||||
"@id": `${s.url}/#website`,
|
||||
url: s.url,
|
||||
url: abs("/"),
|
||||
name: s.name,
|
||||
inLanguage: s.lang,
|
||||
publisher: { "@id": `${s.url}/#organization` },
|
||||
@@ -48,6 +59,10 @@ export const serviceSchema = (opts: {
|
||||
"@type": "Service",
|
||||
name: opts.name,
|
||||
description: opts.description,
|
||||
areaServed: opts.areaServed,
|
||||
areaServed: opts.areaServed ?? s.areaServed,
|
||||
provider: { "@id": `${s.url}/#organization` },
|
||||
});
|
||||
|
||||
/** Serialize JSON-LD safely for an inline <script> (escape "<"). */
|
||||
export const toJsonLd = (data: Json) =>
|
||||
JSON.stringify(data).replace(/</g, "\\u003c");
|
||||
@@ -1,91 +0,0 @@
|
||||
import type { Metadata, Viewport } from "next";
|
||||
import localFont from "next/font/local";
|
||||
import { siteConfig } from "@/config/site";
|
||||
import { JsonLd } from "@/components/seo/JsonLd";
|
||||
import { organizationSchema, websiteSchema } from "@/lib/seo/schema";
|
||||
import "@/styles/main.css";
|
||||
|
||||
const vazirmatn = localFont({
|
||||
src: "../../public/fonts/Vazirmatn-Variable.woff2",
|
||||
weight: "100 900",
|
||||
display: "swap",
|
||||
variable: "--font-vazirmatn",
|
||||
fallback: ["Tahoma", "system-ui", "sans-serif"],
|
||||
});
|
||||
|
||||
const ibmPlexMono = localFont({
|
||||
src: [
|
||||
{
|
||||
path: "../../public/fonts/IBMPlexMono-Regular.woff2",
|
||||
weight: "400",
|
||||
style: "normal",
|
||||
},
|
||||
{
|
||||
path: "../../public/fonts/IBMPlexMono-Medium.woff2",
|
||||
weight: "500",
|
||||
style: "normal",
|
||||
},
|
||||
{
|
||||
path: "../../public/fonts/IBMPlexMono-SemiBold.woff2",
|
||||
weight: "600",
|
||||
style: "normal",
|
||||
},
|
||||
],
|
||||
display: "swap",
|
||||
variable: "--font-ibm-plex-mono",
|
||||
fallback: ["ui-monospace", "monospace"],
|
||||
});
|
||||
|
||||
export const metadata: Metadata = {
|
||||
metadataBase: new URL(siteConfig.url),
|
||||
title: {
|
||||
default: siteConfig.title,
|
||||
template: `%s | ${siteConfig.name}`,
|
||||
},
|
||||
description: siteConfig.description,
|
||||
alternates: { canonical: "/" },
|
||||
openGraph: {
|
||||
type: "website",
|
||||
url: "/",
|
||||
siteName: siteConfig.name,
|
||||
locale: siteConfig.locale,
|
||||
title: siteConfig.title,
|
||||
description: siteConfig.description,
|
||||
},
|
||||
twitter: {
|
||||
card: "summary_large_image",
|
||||
title: siteConfig.title,
|
||||
description: siteConfig.description,
|
||||
},
|
||||
robots: { index: true, follow: true },
|
||||
formatDetection: { telephone: false },
|
||||
icons: {
|
||||
icon:
|
||||
"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'%3E%3Crect width='100' height='100' rx='22' fill='%23FF5A00'/%3E%3Cpath d='M50 20 L72 28 V48 C72 66 62 76 50 82 C38 76 28 66 28 48 V28 Z' fill='%230A0A0C'/%3E%3Cpath d='M40 50 L47 57 L62 42' stroke='%23FF5A00' stroke-width='7' fill='none' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E",
|
||||
},
|
||||
};
|
||||
|
||||
export const viewport: Viewport = {
|
||||
themeColor: siteConfig.themeColor,
|
||||
width: "device-width",
|
||||
initialScale: 1,
|
||||
};
|
||||
|
||||
export default function RootLayout({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
}) {
|
||||
return (
|
||||
<html
|
||||
lang={siteConfig.lang}
|
||||
dir={siteConfig.dir}
|
||||
className={`${vazirmatn.variable} ${ibmPlexMono.variable}`}
|
||||
>
|
||||
<body className="relative min-h-screen bg-bg font-sans text-ink antialiased">
|
||||
<JsonLd data={[organizationSchema(), websiteSchema()]} />
|
||||
{children}
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||