187 lines
7.9 KiB
Vue
187 lines
7.9 KiB
Vue
<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 VuesaxIcon from "~/components/ui/VuesaxIcon.vue";
|
||
import Lines from "~/components/ui/Lines.vue";
|
||
import Reveal from "~/components/ui/Reveal.vue";
|
||
import SectionHead from "~/components/ui/SectionHead.vue";
|
||
|
||
const site = useSiteStore();
|
||
const content = computed(() => site.sections.contact);
|
||
|
||
const INFO = computed(() => {
|
||
const s = site.settings;
|
||
return [
|
||
{ icon: "location", label: "نشانی", value: `${s.address.locality}، ${s.address.street}` },
|
||
{ icon: "call", label: "تلفن تماس", value: s.phoneDisplay, ltr: true, href: `tel:${s.phone}` },
|
||
{ icon: "sms", label: "ایمیل", value: s.email, ltr: true, href: `mailto:${s.email}` },
|
||
{ icon: "clock", label: "ساعات کاری", value: s.workingHours },
|
||
];
|
||
});
|
||
|
||
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-[1480px] px-5 md:px-8">
|
||
<div class="grid gap-14 lg:grid-cols-2">
|
||
<!-- ---- info ---- -->
|
||
<div>
|
||
<SectionHead heading-id="contact-title" v-bind="content.head" />
|
||
|
||
<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"
|
||
>
|
||
<VuesaxIcon :name="item.icon" class="size-5" />
|
||
</span>
|
||
<div class="min-w-0">
|
||
<div class="text-xs text-muted">{{ item.label }}</div>
|
||
<component
|
||
:is="item.href ? 'a' : 'div'"
|
||
:href="item.href"
|
||
:class="`mt-1 block text-sm font-medium ${item.ltr ? 'font-mono tracking-wider' : ''}`"
|
||
:dir="item.ltr ? 'ltr' : 'rtl'"
|
||
>
|
||
{{ item.value }}
|
||
</component>
|
||
</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">
|
||
<VuesaxIcon name="lamp-on" class="size-6 shrink-0 text-hazard" />
|
||
<div>
|
||
<div class="font-bold text-hazard">{{ content.emergencyTitle }}</div>
|
||
<p class="mt-1.5 text-sm leading-7 text-muted">
|
||
{{ content.emergencyText }}
|
||
</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 v-if="content.formTag" class="font-mono text-xs tracking-[0.25em] text-accent">
|
||
{{ content.formTag }}
|
||
</div>
|
||
<h3 class="mt-3 text-2xl font-black leading-snug">
|
||
<Lines :text="content.formTitle" />
|
||
</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"
|
||
>
|
||
<VuesaxIcon name="tick-circle" class="size-14 text-emerald-400" />
|
||
<div class="mt-5 text-xl font-black">{{ content.successTitle }}</div>
|
||
<p class="mt-2.5 max-w-sm text-sm leading-7 text-muted">
|
||
{{ content.successText }}
|
||
</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"
|
||
>
|
||
<!-- honeypot: hidden from people, bots tend to fill it -->
|
||
<div class="absolute -start-[9999px] h-px w-px overflow-hidden" aria-hidden="true">
|
||
<label for="f-website">وبسایت</label>
|
||
<input id="f-website" v-model="contact.form.website" type="text" tabindex="-1" autocomplete="off" />
|
||
</div>
|
||
<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>
|
||
<p
|
||
v-if="contact.status === 'error'"
|
||
class="rounded-lg border border-accent/40 bg-accent/10 px-4 py-3 text-sm leading-7 text-accent sm:col-span-2"
|
||
role="alert"
|
||
>
|
||
{{ contact.error }}
|
||
</p>
|
||
<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'">
|
||
<VuesaxIcon name="refresh-circle" class="size-5 animate-spin" />
|
||
در حال ارسال...
|
||
</template>
|
||
<template v-else>
|
||
<VuesaxIcon name="send-2" class="size-5" />
|
||
ارسال درخواست مشاوره
|
||
</template>
|
||
</AButton>
|
||
</div>
|
||
</div>
|
||
</AForm>
|
||
</div>
|
||
</Reveal>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
</template>
|