Wire landing footer contact info to site settings.

Admin phone/email/address/socials now drive the public footer instead of stale section JSON.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-09-30 21:36:43 +03:30
co-authored by Cursor
parent e9eafdaabc
commit 55e3b6a0e9
4 changed files with 112 additions and 32 deletions
+67 -18
View File
@@ -2,45 +2,56 @@
<footer id="contact" class="relative overflow-hidden border-t border-white/[0.07]">
<div class="border-b border-white/[0.07] py-8 md:py-10">
<SiteMarquee
:items="data.marquee"
:items="data.marquee || []"
:duration="20"
class-name="font-display text-xl font-bold md:text-3xl"
/>
</div>
<div class="mx-auto max-w-[1500px] px-6 py-20 md:px-10 md:py-28">
<SectionTag index="۰۶" :title="data.tag" right="پاسخ تا ۲۴ ساعت" />
<SectionTag index="۰۶" :title="data.tag || 'تماس'" right="پاسخ تا ۲۴ ساعت" />
<div class="mt-14 grid gap-12 lg:grid-cols-[1.4fr_1fr]">
<div>
<h2 class="font-display text-[clamp(2.2rem,6vw,4.5rem)] font-extrabold leading-[1.15] tracking-[-0.02em]">
{{ data.cta }}
{{ data.cta || "شروع همکاری" }}
</h2>
<a
:href="`mailto:${data.email}`"
v-if="email"
:href="`mailto:${email}`"
class="mt-8 inline-flex items-center gap-3 border border-volt bg-volt px-6 py-3 text-sm text-ink transition hover:bg-transparent hover:text-volt"
dir="ltr"
>
{{ data.email }} ↗
{{ email }} ↗
</a>
</div>
<div class="grid gap-8 sm:grid-cols-3 lg:grid-cols-1">
<div>
<p class="text-xs text-ash">کسب‌وکار جدید</p>
<p class="mt-2 text-sm" dir="ltr">{{ data.email }}</p>
<p class="text-sm text-ash" dir="ltr">{{ data.phone }}</p>
<p v-if="email" class="mt-2 text-sm" dir="ltr">{{ email }}</p>
<p v-if="phone" class="text-sm text-ash" dir="ltr">{{ phone }}</p>
</div>
<div>
<p class="text-xs text-ash">استودیو</p>
<p v-for="line in data.address" :key="line" class="mt-1 text-sm text-ash">{{ line }}</p>
<p v-for="line in addressLines" :key="line" class="mt-1 text-sm text-ash">{{ line }}</p>
</div>
<div>
<p class="text-xs text-ash">شبکه‌های اجتماعی</p>
<p v-for="s in data.socials" :key="s" class="mt-1 text-sm text-ash">{{ s }}</p>
<template v-if="socialLinks.length">
<a
v-for="s in socialLinks"
:key="s.label + s.url"
:href="s.url || undefined"
class="mt-1 block text-sm text-ash hover:text-volt"
:target="s.url ? '_blank' : undefined"
rel="noopener"
>{{ s.label }}</a>
</template>
<p v-else-if="legacySocials.length" v-for="s in legacySocials" :key="s" class="mt-1 text-sm text-ash">{{ s }}</p>
</div>
</div>
</div>
<div class="mt-20 flex flex-wrap items-center justify-between gap-4 border-t border-white/[0.07] pt-6 text-xs text-ash">
<span>© {{ year }} گروه نرم‌افزاری منتک</span>
<span>© {{ year }} گروه نرم‌افزاری {{ brand || "منتک" }}</span>
<span>{{ brand || "منتک" }}®</span>
</div>
</div>
@@ -48,17 +59,55 @@
</template>
<script setup lang="ts">
defineProps<{
const props = defineProps<{
brand?: string;
email?: string;
phone?: string;
address?: string;
socials?: Array<{ label: string; url: string }>;
data: {
tag: string;
marquee: string[];
cta: string;
email: string;
phone: string;
address: string[];
socials: string[];
tag?: string;
marquee?: string[];
cta?: string;
email?: string;
phone?: string;
address?: string[] | string;
socials?: string[] | Array<{ label: string; url: string }>;
};
}>();
const year = new Date().getFullYear();
const email = computed(() => props.email || props.data.email || "");
const phone = computed(() => props.phone || props.data.phone || "");
const addressLines = computed(() => {
if (props.address) {
return props.address
.split(/\n|,/)
.map((s) => s.trim())
.filter(Boolean);
}
const a = props.data.address;
if (Array.isArray(a)) return a;
if (typeof a === "string") return a.split(/\n|,/).map((s) => s.trim()).filter(Boolean);
return [];
});
const socialLinks = computed(() => {
if (props.socials?.length) return props.socials.filter((s) => s.label);
const raw = props.data.socials;
if (!Array.isArray(raw) || !raw.length) return [];
if (typeof raw[0] === "object" && raw[0] !== null) {
return (raw as Array<{ label: string; url: string }>).filter((s) => s.label);
}
return [];
});
const legacySocials = computed(() => {
const raw = props.data.socials;
if (!Array.isArray(raw) || !raw.length) return [] as string[];
if (typeof raw[0] === "string") return raw as string[];
return [];
});
</script>