Обновлены метаданные в компоненте layout для SEO, изменены адреса в компонентах Contacts и Footer, улучшена структура отображения контактов. Добавлен динамический заголовок и описание для страницы услуги с использованием useEffect в компоненте ServicePage.
This commit is contained in:
@ -7,7 +7,6 @@ import {
|
|||||||
Mail,
|
Mail,
|
||||||
Clock,
|
Clock,
|
||||||
MapPin,
|
MapPin,
|
||||||
Building,
|
|
||||||
MessagesSquare,
|
MessagesSquare,
|
||||||
FileText,
|
FileText,
|
||||||
} from 'lucide-react';
|
} from 'lucide-react';
|
||||||
@ -22,7 +21,7 @@ const cityContacts = {
|
|||||||
coordinates: [37.539042, 55.74733],
|
coordinates: [37.539042, 55.74733],
|
||||||
},
|
},
|
||||||
Чебоксары: {
|
Чебоксары: {
|
||||||
address: 'г. Чебоксары, пр. Тракторостроителей, д. 11',
|
address: 'г. Чебоксары, ул. Зои Яковлевой, д. 54',
|
||||||
phone: '+7 (916) 830-58-58',
|
phone: '+7 (916) 830-58-58',
|
||||||
email: 'ckeproekt@yandex.ru',
|
email: 'ckeproekt@yandex.ru',
|
||||||
workHours: 'ПН-ПТ: 8:00 - 20:00',
|
workHours: 'ПН-ПТ: 8:00 - 20:00',
|
||||||
@ -42,11 +41,6 @@ const features = [
|
|||||||
title: 'Документы онлайн',
|
title: 'Документы онлайн',
|
||||||
description: 'Возможность получить документы в электронном виде',
|
description: 'Возможность получить документы в электронном виде',
|
||||||
},
|
},
|
||||||
{
|
|
||||||
icon: Building,
|
|
||||||
title: 'Удобное расположение',
|
|
||||||
description: 'Офис в центре города с удобной транспортной доступностью',
|
|
||||||
},
|
|
||||||
];
|
];
|
||||||
|
|
||||||
interface ContactsProps {
|
interface ContactsProps {
|
||||||
@ -228,17 +222,28 @@ const Contacts = ({ selectedCity }: ContactsProps) => {
|
|||||||
</motion.div>
|
</motion.div>
|
||||||
</div>
|
</div>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
|
</motion.div>
|
||||||
|
|
||||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
|
<motion.div variants={itemVariants} className="space-y-8">
|
||||||
|
<motion.div
|
||||||
|
variants={mapVariants}
|
||||||
|
className="bg-white rounded-xl shadow-lg overflow-hidden"
|
||||||
|
>
|
||||||
|
<div className="p-8">
|
||||||
|
<h3 className="text-2xl font-semibold text-gray-900 mb-4">
|
||||||
|
Как с нами связаться
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
<div className="grid grid-cols-1 gap-6 mt-6">
|
||||||
{features.map((feature, index) => (
|
{features.map((feature, index) => (
|
||||||
<motion.div
|
<motion.div
|
||||||
key={index}
|
key={index}
|
||||||
variants={itemVariants}
|
variants={itemVariants}
|
||||||
whileHover={{ scale: 1.05 }}
|
whileHover={{ scale: 1.02 }}
|
||||||
className="bg-white rounded-xl p-6 shadow-lg text-center"
|
className="flex items-start gap-4"
|
||||||
>
|
>
|
||||||
<motion.div
|
<motion.div
|
||||||
className="mb-4 flex justify-center"
|
className="flex-shrink-0"
|
||||||
whileHover={{ rotate: 360 }}
|
whileHover={{ rotate: 360 }}
|
||||||
transition={{ duration: 0.5 }}
|
transition={{ duration: 0.5 }}
|
||||||
>
|
>
|
||||||
@ -246,28 +251,17 @@ const Contacts = ({ selectedCity }: ContactsProps) => {
|
|||||||
<feature.icon className="h-6 w-6 text-blue-700" />
|
<feature.icon className="h-6 w-6 text-blue-700" />
|
||||||
</div>
|
</div>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
|
<div>
|
||||||
<h3 className="text-lg font-semibold text-gray-900 mb-2">
|
<h3 className="text-lg font-semibold text-gray-900 mb-2">
|
||||||
{feature.title}
|
{feature.title}
|
||||||
</h3>
|
</h3>
|
||||||
<p className="text-gray-600 text-sm">
|
<p className="text-gray-600">{feature.description}</p>
|
||||||
{feature.description}
|
</div>
|
||||||
</p>
|
|
||||||
</motion.div>
|
</motion.div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
|
|
||||||
<motion.div
|
|
||||||
variants={mapVariants}
|
|
||||||
className="bg-white rounded-xl shadow-lg overflow-hidden h-[600px]"
|
|
||||||
>
|
|
||||||
<iframe
|
|
||||||
src={`https://yandex.ru/map-widget/v1/?ll=${cityData.coordinates[0]},${cityData.coordinates[1]}&z=16&mode=search&whatshere[point]=${cityData.coordinates[0]},${cityData.coordinates[1]}&whatshere[zoom]=16`}
|
|
||||||
width="100%"
|
|
||||||
height="100%"
|
|
||||||
frameBorder="0"
|
|
||||||
title="Карта с местоположением офиса"
|
|
||||||
/>
|
|
||||||
</motion.div>
|
</motion.div>
|
||||||
</div>
|
</div>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
|
@ -22,12 +22,12 @@ const legalLinks = [
|
|||||||
|
|
||||||
const cityContacts = {
|
const cityContacts = {
|
||||||
Москва: {
|
Москва: {
|
||||||
address: 'г. Москва, ул. Пресненская, д. 6, стр. 2',
|
address: 'г. Москва, ул. Космонавта Волкова, д. 29к1',
|
||||||
phone: '+7 (916) 830-58-58',
|
phone: '+7 (916) 830-58-58',
|
||||||
email: 'ckeproekt@yandex.ru',
|
email: 'ckeproekt@yandex.ru',
|
||||||
},
|
},
|
||||||
Чебоксары: {
|
Чебоксары: {
|
||||||
address: 'г. Чебоксары, пр. Тракторостроителей, д. 11',
|
address: 'г. Чебоксары, ул. Зои Яковлевой, д. 54',
|
||||||
phone: '+7 (916) 830-58-58',
|
phone: '+7 (916) 830-58-58',
|
||||||
email: 'ckeproekt@yandex.ru',
|
email: 'ckeproekt@yandex.ru',
|
||||||
},
|
},
|
||||||
|
@ -178,9 +178,9 @@ const Services = () => {
|
|||||||
scale: 1.02,
|
scale: 1.02,
|
||||||
transition: { duration: 0.2 },
|
transition: { duration: 0.2 },
|
||||||
}}
|
}}
|
||||||
className="group bg-gray-50 rounded-xl p-6 hover:bg-blue-700 transition-all duration-300 h-full"
|
className="group bg-gray-50 rounded-xl p-6 hover:bg-blue-700 transition-all duration-300 h-full flex flex-col"
|
||||||
>
|
>
|
||||||
<div className="flex items-start space-x-4">
|
<div className="flex items-start space-x-4 mb-4">
|
||||||
<div className="flex-shrink-0">
|
<div className="flex-shrink-0">
|
||||||
<motion.div
|
<motion.div
|
||||||
whileHover={{ rotate: 360 }}
|
whileHover={{ rotate: 360 }}
|
||||||
@ -191,26 +191,28 @@ const Services = () => {
|
|||||||
</motion.div>
|
</motion.div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<h3 className="text-xl font-semibold text-gray-900 group-hover:text-white mb-2">
|
<h3 className="text-xl font-semibold text-gray-900 group-hover:text-white mb-2 line-clamp-2 h-14">
|
||||||
{service.title}
|
{service.title}
|
||||||
</h3>
|
</h3>
|
||||||
<p className="text-gray-600 group-hover:text-blue-100 mb-4">
|
<p className="text-gray-600 group-hover:text-blue-100 mb-4 line-clamp-3 h-18">
|
||||||
{service.description}
|
{service.description}
|
||||||
</p>
|
</p>
|
||||||
<ul className="space-y-2">
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ul className="space-y-2 mb-4">
|
||||||
{service.details.map((detail, idx) => (
|
{service.details.map((detail, idx) => (
|
||||||
<li
|
<li
|
||||||
key={idx}
|
key={idx}
|
||||||
className="flex items-center text-gray-600 group-hover:text-blue-100"
|
className="flex items-start text-gray-600 group-hover:text-blue-100"
|
||||||
>
|
>
|
||||||
<ArrowRight className="h-4 w-4 mr-2 flex-shrink-0" />
|
<ArrowRight className="h-4 w-4 mr-2 flex-shrink-0 mt-1" />
|
||||||
<span>{detail}</span>
|
<span className="line-clamp-1">{detail}</span>
|
||||||
</li>
|
</li>
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
|
||||||
</div>
|
<div className="relative h-48 mt-auto rounded-lg overflow-hidden">
|
||||||
<div className="relative h-64 mt-4 rounded-lg overflow-hidden">
|
|
||||||
<div className="absolute inset-0 bg-gradient-to-t from-black/50 to-transparent z-10" />
|
<div className="absolute inset-0 bg-gradient-to-t from-black/50 to-transparent z-10" />
|
||||||
<Image
|
<Image
|
||||||
src={service.image}
|
src={service.image}
|
||||||
|
@ -1,20 +1,23 @@
|
|||||||
import type { Metadata } from "next";
|
import type { Metadata } from 'next';
|
||||||
import { Geist, Geist_Mono } from "next/font/google";
|
import { Geist, Geist_Mono } from 'next/font/google';
|
||||||
import "./globals.css";
|
import './globals.css';
|
||||||
|
|
||||||
const geistSans = Geist({
|
const geistSans = Geist({
|
||||||
variable: "--font-geist-sans",
|
variable: '--font-geist-sans',
|
||||||
subsets: ["latin"],
|
subsets: ['latin'],
|
||||||
});
|
});
|
||||||
|
|
||||||
const geistMono = Geist_Mono({
|
const geistMono = Geist_Mono({
|
||||||
variable: "--font-geist-mono",
|
variable: '--font-geist-mono',
|
||||||
subsets: ["latin"],
|
subsets: ['latin'],
|
||||||
});
|
});
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: "Create Next App",
|
title: 'Независимая строительно-техническая экспертиза | СКЭ Проект',
|
||||||
description: "Generated by create next app",
|
description:
|
||||||
|
'Профессиональная экспертиза при заливах, обследование инженерных систем, оценка качества строительных работ в Москве и Чебоксарах. Официальные заключения.',
|
||||||
|
keywords:
|
||||||
|
'строительная экспертиза, экспертиза залива, обследование канализации, тепловизионная экспертиза, оценка строительных работ',
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function RootLayout({
|
export default function RootLayout({
|
||||||
@ -23,7 +26,7 @@ export default function RootLayout({
|
|||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
}>) {
|
}>) {
|
||||||
return (
|
return (
|
||||||
<html lang="en">
|
<html lang="ru">
|
||||||
<body
|
<body
|
||||||
className={`${geistSans.variable} ${geistMono.variable} antialiased`}
|
className={`${geistSans.variable} ${geistMono.variable} antialiased`}
|
||||||
>
|
>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { useState } from 'react';
|
import { useState, useEffect } from 'react';
|
||||||
import { motion } from 'framer-motion';
|
import { motion } from 'framer-motion';
|
||||||
import {
|
import {
|
||||||
ArrowLeft,
|
ArrowLeft,
|
||||||
@ -33,6 +33,24 @@ export default function ServicePage({ params }: ServicePageProps) {
|
|||||||
const { slug } = use(params);
|
const { slug } = use(params);
|
||||||
const service = services.find((s) => s.slug === slug);
|
const service = services.find((s) => s.slug === slug);
|
||||||
|
|
||||||
|
// Добавляем динамический заголовок и описание для SEO
|
||||||
|
useEffect(() => {
|
||||||
|
if (service) {
|
||||||
|
document.title = `${service.title} | СКЭ Проект`;
|
||||||
|
const metaDescription = document.querySelector(
|
||||||
|
'meta[name="description"]'
|
||||||
|
);
|
||||||
|
if (metaDescription) {
|
||||||
|
metaDescription.setAttribute('content', service.description);
|
||||||
|
} else {
|
||||||
|
const meta = document.createElement('meta');
|
||||||
|
meta.name = 'description';
|
||||||
|
meta.content = service.description;
|
||||||
|
document.head.appendChild(meta);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [service]);
|
||||||
|
|
||||||
if (!service) {
|
if (!service) {
|
||||||
return <div>Услуга не найдена</div>;
|
return <div>Услуга не найдена</div>;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user