diff --git a/src/components/ContactModal.tsx b/src/components/ContactModal.tsx
index cf42de3..b08d101 100644
--- a/src/components/ContactModal.tsx
+++ b/src/components/ContactModal.tsx
@@ -1,13 +1,17 @@
-import { X, Mail, Phone, MapPin, Clock, Calendar } from 'lucide-react'
+import { X, Calendar } from 'lucide-react'
import { useEffect, useState } from 'react'
import { createPortal } from 'react-dom'
+import { SiteContactItems } from './SiteContactItems'
+import type { SiteConfigContact } from '../lib/cms/contact/types'
+
interface ContactModalProps {
isOpen: boolean
onClose: () => void
+ contacts: readonly SiteConfigContact[]
}
-export function ContactModal({ isOpen, onClose }: ContactModalProps) {
+export function ContactModal({ isOpen, onClose, contacts }: ContactModalProps) {
useEffect(() => {
if (isOpen) {
document.body.style.overflow = 'hidden'
@@ -198,27 +202,8 @@ export function ContactModal({ isOpen, onClose }: ContactModalProps) {
- {/* Контакты компактно */}
-
diff --git a/src/components/SiteContactItems.tsx b/src/components/SiteContactItems.tsx
new file mode 100644
index 0000000..f7b1b8c
--- /dev/null
+++ b/src/components/SiteContactItems.tsx
@@ -0,0 +1,82 @@
+import { Enum_Componentsharedcontact_Type } from '../graphql/graphql'
+import { toIcon } from '../lib/cms/contact/toIcon'
+import type { SiteConfigContact } from '../lib/cms/contact/types'
+
+function hrefFor(contact: SiteConfigContact): string | undefined {
+ switch (contact.type) {
+ case Enum_Componentsharedcontact_Type.Phone:
+ return `tel:${contact.value.replace(/\s/g, '')}`
+ case Enum_Componentsharedcontact_Type.Email:
+ return `mailto:${contact.value}`
+ default:
+ return undefined
+ }
+}
+
+function labelFor(contact: SiteConfigContact): string {
+ const d = contact.displayValue?.trim()
+ return d || contact.value
+}
+
+export interface SiteContactItemsProps {
+ contacts: readonly SiteConfigContact[]
+ variant: 'inline' | 'footer'
+ /** Applied to the outer wrapper (inline: flex row; footer: ul gets section spacing from parent) */
+ className?: string
+}
+
+export function SiteContactItems({ contacts, variant, className }: SiteContactItemsProps) {
+ if (!contacts.length) return null
+
+ if (variant === 'footer') {
+ return (
+
+ {contacts.map(c => {
+ const Icon = toIcon(c.type)
+ const href = hrefFor(c)
+ const label = labelFor(c)
+ const content = href ? (
+
+ {label}
+
+ ) : (
+ {label}
+ )
+ return (
+ -
+
+
{content}
+
+ )
+ })}
+
+ )
+ }
+
+ const rowClass = className ?? 'flex flex-wrap justify-center gap-6 text-sm text-gray-600'
+
+ return (
+
+ {contacts.map(c => {
+ const Icon = toIcon(c.type)
+ const href = hrefFor(c)
+ const label = labelFor(c)
+ const linkClass = 'flex items-center gap-2 hover:text-blue-600 transition-colors'
+ if (href) {
+ return (
+
+
+ {label}
+
+ )
+ }
+ return (
+
+
+ {label}
+
+ )
+ })}
+
+ )
+}
diff --git a/src/lib/cms/contact/types.ts b/src/lib/cms/contact/types.ts
new file mode 100644
index 0000000..f8c3ede
--- /dev/null
+++ b/src/lib/cms/contact/types.ts
@@ -0,0 +1,5 @@
+import type { SiteConfigQueryQuery } from '../../../graphql/graphql'
+
+export type SiteConfigContact = NonNullable<
+ NonNullable['contacts']>[number]
+>
diff --git a/src/pages/[slug].astro b/src/pages/[slug].astro
index cfa435b..70e30c6 100644
--- a/src/pages/[slug].astro
+++ b/src/pages/[slug].astro
@@ -5,15 +5,24 @@ import { getCollection, type CollectionEntry } from 'astro:content'
import { Header } from '../sections/Header'
import { Footer } from '../sections/Footer'
import { CategoryView } from '../views/CategoryView'
+import type { SiteConfigContact } from '../lib/cms/contact/types'
+import { siteConfigQueryQuery } from '../graphql-documents/site-config.gql.generated'
export async function getStaticPaths() {
const categories = await getCollection('categories')
+ const siteResult = await siteConfigQueryQuery.execute()
+ if (siteResult.errors?.length) {
+ throw new Error(siteResult.errors.map(e => e.message).join(', '))
+ }
+ const contacts = siteResult.data?.siteConfig?.contacts?.filter(c => c != null) ?? []
+
return categories.map((entry: CollectionEntry<'categories'>) => ({
params: { slug: entry.id },
props: {
title: entry.data.title,
description: entry.data.description,
vendors: entry.data.vendors,
+ contacts,
},
}))
}
@@ -26,15 +35,16 @@ interface Props {
description: string
products?: string[]
}[]
+ contacts: SiteConfigContact[]
}
-const { title, description, vendors } = Astro.props as Props
+const { title, description, vendors, contacts } = Astro.props as Props
---
-
+
-
+
diff --git a/src/pages/index.astro b/src/pages/index.astro
index 6c91ab8..8f92c3b 100644
--- a/src/pages/index.astro
+++ b/src/pages/index.astro
@@ -5,19 +5,28 @@ import { Header } from '../sections/Header'
import { Footer } from '../sections/Footer'
import { HomePage } from '../views/HomePage'
import { homePageQueryQuery } from '../graphql-documents/home-page.gql.generated'
+import { siteConfigQueryQuery } from '../graphql-documents/site-config.gql.generated'
-const result = await homePageQueryQuery.execute()
-if (result.errors?.length) {
- throw new Error(result.errors.map(e => e.message).join(', '))
+const [homeResult, siteResult] = await Promise.all([
+ homePageQueryQuery.execute(),
+ siteConfigQueryQuery.execute(),
+])
+
+if (homeResult.errors?.length) {
+ throw new Error(homeResult.errors.map(e => e.message).join(', '))
+}
+if (siteResult.errors?.length) {
+ throw new Error(siteResult.errors.map(e => e.message).join(', '))
}
-const homePage = result.data?.homePage ?? null
+const homePage = homeResult.data?.homePage ?? null
+const contacts = siteResult.data?.siteConfig?.contacts?.filter(c => c != null) ?? []
---
-
-
-
+
+
+
diff --git a/src/sections/Contact.tsx b/src/sections/Contact.tsx
index 320ab15..de9d4b1 100644
--- a/src/sections/Contact.tsx
+++ b/src/sections/Contact.tsx
@@ -1,6 +1,11 @@
-import { Phone, Mail, MapPin, Clock } from 'lucide-react'
+import { SiteContactItems } from '../components/SiteContactItems'
+import type { SiteConfigContact } from '../lib/cms/contact/types'
-export function Contact() {
+export interface ContactProps {
+ contacts: readonly SiteConfigContact[]
+}
+
+export function Contact({ contacts }: ContactProps) {
return (
@@ -77,25 +82,11 @@ export function Contact() {
- {/* Контакты компактно */}
-
+
)
diff --git a/src/sections/Footer.tsx b/src/sections/Footer.tsx
index e9374c1..f1f0192 100644
--- a/src/sections/Footer.tsx
+++ b/src/sections/Footer.tsx
@@ -1,6 +1,13 @@
-import { Mail, Phone, MapPin, Send, Hash, Code, Video } from 'lucide-react'
+import { Send, Video } from 'lucide-react'
-export function Footer() {
+import { SiteContactItems } from '../components/SiteContactItems'
+import type { SiteConfigContact } from '../lib/cms/contact/types'
+
+export interface FooterProps {
+ contacts: readonly SiteConfigContact[]
+}
+
+export function Footer({ contacts }: FooterProps) {
return (