Обновлены страницы с мета-тегами: заменены статические мета-теги на компонент MetaTags, который динамически получает данные через getMetaByPath. Изменен язык документа на русский в _document.tsx. Добавлены мета-теги для страниц: brands, catalog, contacts, index, search-result, thankyoupage, vin, wholesale и vehicle-search.
This commit is contained in:
98
src/components/MetaTags.tsx
Normal file
98
src/components/MetaTags.tsx
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
import Head from 'next/head';
|
||||||
|
import { useRouter } from 'next/router';
|
||||||
|
|
||||||
|
interface MetaTagsProps {
|
||||||
|
title?: string;
|
||||||
|
description?: string;
|
||||||
|
keywords?: string;
|
||||||
|
ogTitle?: string;
|
||||||
|
ogDescription?: string;
|
||||||
|
ogImage?: string;
|
||||||
|
ogUrl?: string;
|
||||||
|
twitterTitle?: string;
|
||||||
|
twitterDescription?: string;
|
||||||
|
twitterImage?: string;
|
||||||
|
canonical?: string;
|
||||||
|
robots?: string;
|
||||||
|
author?: string;
|
||||||
|
viewport?: string;
|
||||||
|
charset?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const MetaTags: React.FC<MetaTagsProps> = ({
|
||||||
|
title = 'Protek - Автозапчасти и аксессуары',
|
||||||
|
description = 'Protek - широкий ассортимент автозапчастей и аксессуаров для всех марок автомобилей. Быстрая доставка, гарантия качества.',
|
||||||
|
keywords = 'автозапчасти, запчасти, автомобили, аксессуары, доставка, protek',
|
||||||
|
ogTitle,
|
||||||
|
ogDescription,
|
||||||
|
ogImage = '/images/og-image.jpg',
|
||||||
|
ogUrl,
|
||||||
|
twitterTitle,
|
||||||
|
twitterDescription,
|
||||||
|
twitterImage,
|
||||||
|
canonical,
|
||||||
|
robots = 'index, follow',
|
||||||
|
author = 'Protek',
|
||||||
|
viewport = 'width=device-width, initial-scale=1',
|
||||||
|
charset = 'utf-8'
|
||||||
|
}) => {
|
||||||
|
const router = useRouter();
|
||||||
|
const baseUrl = 'https://protek.ru'; // Замените на ваш домен
|
||||||
|
|
||||||
|
const currentUrl = ogUrl || `${baseUrl}${router.asPath}`;
|
||||||
|
const canonicalUrl = canonical || currentUrl;
|
||||||
|
|
||||||
|
const finalOgTitle = ogTitle || title;
|
||||||
|
const finalOgDescription = ogDescription || description;
|
||||||
|
const finalTwitterTitle = twitterTitle || title;
|
||||||
|
const finalTwitterDescription = twitterDescription || description;
|
||||||
|
const finalTwitterImage = twitterImage || ogImage;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Head>
|
||||||
|
{/* Базовые meta-теги */}
|
||||||
|
<meta charSet={charset} />
|
||||||
|
<title>{title}</title>
|
||||||
|
<meta name="description" content={description} />
|
||||||
|
<meta name="keywords" content={keywords} />
|
||||||
|
<meta name="author" content={author} />
|
||||||
|
<meta name="viewport" content={viewport} />
|
||||||
|
<meta name="robots" content={robots} />
|
||||||
|
|
||||||
|
{/* Canonical URL */}
|
||||||
|
<link rel="canonical" href={canonicalUrl} />
|
||||||
|
|
||||||
|
{/* Open Graph теги */}
|
||||||
|
<meta property="og:type" content="website" />
|
||||||
|
<meta property="og:title" content={finalOgTitle} />
|
||||||
|
<meta property="og:description" content={finalOgDescription} />
|
||||||
|
<meta property="og:image" content={ogImage} />
|
||||||
|
<meta property="og:url" content={currentUrl} />
|
||||||
|
<meta property="og:site_name" content="Protek" />
|
||||||
|
<meta property="og:locale" content="ru_RU" />
|
||||||
|
|
||||||
|
{/* Twitter Card теги */}
|
||||||
|
<meta name="twitter:card" content="summary_large_image" />
|
||||||
|
<meta name="twitter:title" content={finalTwitterTitle} />
|
||||||
|
<meta name="twitter:description" content={finalTwitterDescription} />
|
||||||
|
<meta name="twitter:image" content={finalTwitterImage} />
|
||||||
|
|
||||||
|
{/* Favicon и иконки */}
|
||||||
|
<link href="/images/favicon.png" rel="shortcut icon" type="image/x-icon" />
|
||||||
|
<link href="/images/webclip.png" rel="apple-touch-icon" />
|
||||||
|
|
||||||
|
{/* Preconnect для производительности */}
|
||||||
|
<link href="https://fonts.googleapis.com" rel="preconnect" />
|
||||||
|
<link href="https://fonts.gstatic.com" rel="preconnect" crossOrigin="anonymous" />
|
||||||
|
|
||||||
|
{/* Дополнительные meta-теги для SEO */}
|
||||||
|
<meta name="format-detection" content="telephone=no" />
|
||||||
|
<meta name="theme-color" content="#dc2626" />
|
||||||
|
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||||
|
<meta name="apple-mobile-web-app-status-bar-style" content="default" />
|
||||||
|
<meta name="apple-mobile-web-app-title" content="Protek" />
|
||||||
|
</Head>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default MetaTags;
|
30
src/hooks/useMetaTags.ts
Normal file
30
src/hooks/useMetaTags.ts
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
import { useRouter } from 'next/router';
|
||||||
|
import { useMemo } from 'react';
|
||||||
|
import { getMetaByPath } from '@/lib/meta-config';
|
||||||
|
|
||||||
|
interface MetaTagsData {
|
||||||
|
title: string;
|
||||||
|
description: string;
|
||||||
|
keywords: string;
|
||||||
|
ogTitle?: string;
|
||||||
|
ogDescription?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useMetaTags = (customMeta?: Partial<MetaTagsData>): MetaTagsData => {
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
|
const metaData = useMemo(() => {
|
||||||
|
// Получаем базовые meta-теги для текущего пути
|
||||||
|
const baseMeta = getMetaByPath(router.asPath);
|
||||||
|
|
||||||
|
// Объединяем с пользовательскими meta-тегами
|
||||||
|
return {
|
||||||
|
...baseMeta,
|
||||||
|
...customMeta
|
||||||
|
};
|
||||||
|
}, [router.asPath, customMeta]);
|
||||||
|
|
||||||
|
return metaData;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default useMetaTags;
|
192
src/lib/meta-config.ts
Normal file
192
src/lib/meta-config.ts
Normal file
@ -0,0 +1,192 @@
|
|||||||
|
interface MetaConfig {
|
||||||
|
title: string;
|
||||||
|
description: string;
|
||||||
|
keywords: string;
|
||||||
|
ogTitle?: string;
|
||||||
|
ogDescription?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const metaConfig: Record<string, MetaConfig> = {
|
||||||
|
// Главная страница
|
||||||
|
'/': {
|
||||||
|
title: 'Protek - Автозапчасти и аксессуары для всех марок автомобилей',
|
||||||
|
description: 'Protek - широкий ассортимент автозапчастей и аксессуаров для всех марок автомобилей. Быстрая доставка по России, гарантия качества, низкие цены.',
|
||||||
|
keywords: 'автозапчасти, запчасти для автомобилей, автоаксессуары, доставка запчастей, protek, протек',
|
||||||
|
ogTitle: 'Protek - Автозапчасти и аксессуары',
|
||||||
|
ogDescription: 'Широкий ассортимент автозапчастей и аксессуаров для всех марок автомобилей. Быстрая доставка, гарантия качества.'
|
||||||
|
},
|
||||||
|
|
||||||
|
// Каталог
|
||||||
|
'/catalog': {
|
||||||
|
title: 'Каталог автозапчастей - Protek',
|
||||||
|
description: 'Полный каталог автозапчастей для всех марок автомобилей. Более 1 миллиона наименований запчастей в наличии и под заказ.',
|
||||||
|
keywords: 'каталог запчастей, автозапчасти каталог, запчасти для авто, поиск запчастей',
|
||||||
|
ogTitle: 'Каталог автозапчастей - Protek',
|
||||||
|
ogDescription: 'Полный каталог автозапчастей для всех марок автомобилей. Более 1 миллиона наименований.'
|
||||||
|
},
|
||||||
|
|
||||||
|
// Марки автомобилей
|
||||||
|
'/brands': {
|
||||||
|
title: 'Все марки автомобилей - Каталог запчастей Protek',
|
||||||
|
description: 'Полный каталог автомобильных брендов для поиска запчастей. Выберите марку вашего автомобиля и найдите нужные запчасти.',
|
||||||
|
keywords: 'марки автомобилей, бренды авто, запчасти по маркам, автомобильные марки',
|
||||||
|
ogTitle: 'Все марки автомобилей - Protek',
|
||||||
|
ogDescription: 'Полный каталог автомобильных брендов для поиска запчастей.'
|
||||||
|
},
|
||||||
|
|
||||||
|
// Поиск по VIN
|
||||||
|
'/vin': {
|
||||||
|
title: 'Поиск запчастей по VIN коду - Protek',
|
||||||
|
description: 'Быстрый и точный поиск автозапчастей по VIN коду автомобиля. Определите совместимые запчасти для вашего авто.',
|
||||||
|
keywords: 'поиск по VIN, VIN код, запчасти по VIN, определение запчастей, совместимость',
|
||||||
|
ogTitle: 'Поиск запчастей по VIN коду - Protek',
|
||||||
|
ogDescription: 'Быстрый и точный поиск автозапчастей по VIN коду автомобиля.'
|
||||||
|
},
|
||||||
|
|
||||||
|
// Контакты
|
||||||
|
'/contacts': {
|
||||||
|
title: 'Контакты - Protek',
|
||||||
|
description: 'Контактная информация компании Protek. Адреса магазинов, телефоны, режим работы. Свяжитесь с нами для консультации.',
|
||||||
|
keywords: 'контакты protek, адрес, телефон, режим работы, магазины запчастей',
|
||||||
|
ogTitle: 'Контакты - Protek',
|
||||||
|
ogDescription: 'Контактная информация компании Protek. Адреса магазинов, телефоны, режим работы.'
|
||||||
|
},
|
||||||
|
|
||||||
|
// О компании
|
||||||
|
'/about': {
|
||||||
|
title: 'О компании Protek - Автозапчасти и аксессуары',
|
||||||
|
description: 'Компания Protek - надежный поставщик автозапчастей с многолетним опытом. Узнайте больше о нашей истории и преимуществах.',
|
||||||
|
keywords: 'о компании protek, история компании, преимущества, автозапчасти',
|
||||||
|
ogTitle: 'О компании Protek',
|
||||||
|
ogDescription: 'Компания Protek - надежный поставщик автозапчастей с многолетним опытом.'
|
||||||
|
},
|
||||||
|
|
||||||
|
// Новости
|
||||||
|
'/news': {
|
||||||
|
title: 'Новости и акции - Protek',
|
||||||
|
description: 'Актуальные новости компании Protek, специальные предложения и акции на автозапчасти.',
|
||||||
|
keywords: 'новости protek, акции, специальные предложения, скидки на запчасти',
|
||||||
|
ogTitle: 'Новости и акции - Protek',
|
||||||
|
ogDescription: 'Актуальные новости компании Protek, специальные предложения и акции.'
|
||||||
|
},
|
||||||
|
|
||||||
|
// Оптовые продажи
|
||||||
|
'/wholesale': {
|
||||||
|
title: 'Оптовые продажи автозапчастей - Protek',
|
||||||
|
description: 'Оптовые продажи автозапчастей для автосервисов и дилеров. Специальные цены, гибкие условия сотрудничества.',
|
||||||
|
keywords: 'оптовые продажи, запчасти оптом, для автосервисов, дилерам, оптовые цены',
|
||||||
|
ogTitle: 'Оптовые продажи автозапчастей - Protek',
|
||||||
|
ogDescription: 'Оптовые продажи автозапчастей для автосервисов и дилеров. Специальные цены.'
|
||||||
|
},
|
||||||
|
|
||||||
|
// Способы оплаты
|
||||||
|
'/payments-method': {
|
||||||
|
title: 'Способы оплаты - Protek',
|
||||||
|
description: 'Удобные способы оплаты автозапчастей: наличными, картой, банковским переводом, онлайн-платежи.',
|
||||||
|
keywords: 'способы оплаты, оплата запчастей, банковская карта, наличные, онлайн-платеж',
|
||||||
|
ogTitle: 'Способы оплаты - Protek',
|
||||||
|
ogDescription: 'Удобные способы оплаты автозапчастей: наличными, картой, банковским переводом.'
|
||||||
|
},
|
||||||
|
|
||||||
|
// Корзина
|
||||||
|
'/cart': {
|
||||||
|
title: 'Корзина - Protek',
|
||||||
|
description: 'Корзина покупок. Оформите заказ на выбранные автозапчасти с быстрой доставкой.',
|
||||||
|
keywords: 'корзина покупок, оформление заказа, заказать запчасти',
|
||||||
|
ogTitle: 'Корзина - Protek',
|
||||||
|
ogDescription: 'Корзина покупок. Оформите заказ на выбранные автозапчасти.'
|
||||||
|
},
|
||||||
|
|
||||||
|
// Избранное
|
||||||
|
'/favorite': {
|
||||||
|
title: 'Избранные товары - Protek',
|
||||||
|
description: 'Ваши избранные автозапчасти. Сохраните интересующие товары для быстрого доступа.',
|
||||||
|
keywords: 'избранные товары, сохраненные запчасти, избранное',
|
||||||
|
ogTitle: 'Избранные товары - Protek',
|
||||||
|
ogDescription: 'Ваши избранные автозапчасти. Сохраните интересующие товары.'
|
||||||
|
},
|
||||||
|
|
||||||
|
// Профиль
|
||||||
|
'/profile-orders': {
|
||||||
|
title: 'Мои заказы - Личный кабинет Protek',
|
||||||
|
description: 'Личный кабинет клиента Protek. Управляйте своими заказами, отслеживайте статус доставки.',
|
||||||
|
keywords: 'личный кабинет, мои заказы, статус заказа, история покупок',
|
||||||
|
ogTitle: 'Мои заказы - Личный кабинет Protek',
|
||||||
|
ogDescription: 'Личный кабинет клиента Protek. Управляйте своими заказами.'
|
||||||
|
},
|
||||||
|
|
||||||
|
// Страница благодарности
|
||||||
|
'/thankyoupage': {
|
||||||
|
title: 'Спасибо за заказ - Protek',
|
||||||
|
description: 'Ваш заказ успешно оформлен. Мы свяжемся с вами в ближайшее время для подтверждения.',
|
||||||
|
keywords: 'заказ оформлен, спасибо за заказ, подтверждение заказа',
|
||||||
|
ogTitle: 'Спасибо за заказ - Protek',
|
||||||
|
ogDescription: 'Ваш заказ успешно оформлен. Мы свяжемся с вами в ближайшее время.'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Функция для получения meta-тегов по пути
|
||||||
|
export const getMetaByPath = (path: string): MetaConfig => {
|
||||||
|
// Нормализуем путь (убираем query параметры)
|
||||||
|
const normalizedPath = path.split('?')[0];
|
||||||
|
|
||||||
|
// Проверяем точное совпадение
|
||||||
|
if (metaConfig[normalizedPath]) {
|
||||||
|
return metaConfig[normalizedPath];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Проверяем динамические пути
|
||||||
|
if (normalizedPath.startsWith('/vehicle-search/')) {
|
||||||
|
return {
|
||||||
|
title: 'Поиск запчастей по автомобилю - Protek',
|
||||||
|
description: 'Найдите подходящие запчасти для вашего автомобиля. Точный подбор по марке, модели и году выпуска.',
|
||||||
|
keywords: 'поиск запчастей, подбор по автомобилю, запчасти для авто'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (normalizedPath.startsWith('/search-result')) {
|
||||||
|
return {
|
||||||
|
title: 'Результаты поиска - Protek',
|
||||||
|
description: 'Результаты поиска автозапчастей. Найдите нужные запчасти среди широкого ассортимента.',
|
||||||
|
keywords: 'результаты поиска, поиск запчастей, найти запчасти'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (normalizedPath.startsWith('/payment/')) {
|
||||||
|
return {
|
||||||
|
title: 'Оплата заказа - Protek',
|
||||||
|
description: 'Оплата заказа автозапчастей. Безопасные способы оплаты онлайн.',
|
||||||
|
keywords: 'оплата заказа, онлайн оплата, безопасная оплата'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Возвращаем дефолтные meta-теги
|
||||||
|
return metaConfig['/'];
|
||||||
|
};
|
||||||
|
|
||||||
|
// Функция для создания динамических meta-тегов для товаров
|
||||||
|
export const createProductMeta = (product: {
|
||||||
|
name: string;
|
||||||
|
brand: string;
|
||||||
|
articleNumber: string;
|
||||||
|
price?: number;
|
||||||
|
}): MetaConfig => {
|
||||||
|
return {
|
||||||
|
title: `${product.brand} ${product.articleNumber} - ${product.name} - Protek`,
|
||||||
|
description: `Купить ${product.name} ${product.brand} артикул ${product.articleNumber}${product.price ? ` по цене ${product.price} руб.` : ''}. Гарантия качества, быстрая доставка.`,
|
||||||
|
keywords: `${product.name}, ${product.brand}, ${product.articleNumber}, запчасти, автозапчасти`,
|
||||||
|
ogTitle: `${product.brand} ${product.articleNumber} - ${product.name}`,
|
||||||
|
ogDescription: `Купить ${product.name} ${product.brand} артикул ${product.articleNumber}. Гарантия качества, быстрая доставка.`
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// Функция для создания meta-тегов для категорий
|
||||||
|
export const createCategoryMeta = (categoryName: string, count?: number): MetaConfig => {
|
||||||
|
return {
|
||||||
|
title: `${categoryName} - Каталог запчастей Protek`,
|
||||||
|
description: `Купить ${categoryName.toLowerCase()} для автомобилей${count ? `. В наличии ${count} товаров` : ''}. Широкий выбор, низкие цены, быстрая доставка.`,
|
||||||
|
keywords: `${categoryName.toLowerCase()}, запчасти, автозапчасти, каталог`,
|
||||||
|
ogTitle: `${categoryName} - Protek`,
|
||||||
|
ogDescription: `Купить ${categoryName.toLowerCase()} для автомобилей. Широкий выбор, низкие цены.`
|
||||||
|
};
|
||||||
|
};
|
@ -2,8 +2,23 @@ import { Html, Head, Main, NextScript } from "next/document";
|
|||||||
|
|
||||||
export default function Document() {
|
export default function Document() {
|
||||||
return (
|
return (
|
||||||
<Html lang="en">
|
<Html lang="ru">
|
||||||
<Head />
|
<Head>
|
||||||
|
{/* Базовые meta-теги */}
|
||||||
|
<meta name="format-detection" content="telephone=no" />
|
||||||
|
<meta name="theme-color" content="#dc2626" />
|
||||||
|
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||||
|
<meta name="apple-mobile-web-app-status-bar-style" content="default" />
|
||||||
|
<meta name="apple-mobile-web-app-title" content="Protek" />
|
||||||
|
|
||||||
|
{/* Preconnect для производительности */}
|
||||||
|
<link href="https://fonts.googleapis.com" rel="preconnect" />
|
||||||
|
<link href="https://fonts.gstatic.com" rel="preconnect" crossOrigin="anonymous" />
|
||||||
|
|
||||||
|
{/* Favicon */}
|
||||||
|
<link href="/images/favicon.png" rel="shortcut icon" type="image/x-icon" />
|
||||||
|
<link href="/images/webclip.png" rel="apple-touch-icon" />
|
||||||
|
</Head>
|
||||||
<body>
|
<body>
|
||||||
<Main />
|
<Main />
|
||||||
<NextScript />
|
<NextScript />
|
||||||
|
@ -8,6 +8,8 @@ import MobileMenuBottomSection from "@/components/MobileMenuBottomSection";
|
|||||||
import { GET_LAXIMO_BRANDS } from "@/lib/graphql";
|
import { GET_LAXIMO_BRANDS } from "@/lib/graphql";
|
||||||
import { LaximoBrand } from "@/types/laximo";
|
import { LaximoBrand } from "@/types/laximo";
|
||||||
import BrandWizardSearchSection from "@/components/BrandWizardSearchSection";
|
import BrandWizardSearchSection from "@/components/BrandWizardSearchSection";
|
||||||
|
import MetaTags from "@/components/MetaTags";
|
||||||
|
import { getMetaByPath } from "@/lib/meta-config";
|
||||||
|
|
||||||
const InfoBrands = () => (
|
const InfoBrands = () => (
|
||||||
<section className="section-info">
|
<section className="section-info">
|
||||||
@ -85,14 +87,11 @@ const BrandsPage = () => {
|
|||||||
setSelectedLetter(selectedLetter === letter ? '' : letter);
|
setSelectedLetter(selectedLetter === letter ? '' : letter);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const metaData = getMetaByPath('/brands');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Head>
|
<MetaTags {...metaData} />
|
||||||
<title>Все марки автомобилей - Protek</title>
|
|
||||||
<meta name="description" content="Полный каталог автомобильных брендов для поиска запчастей" />
|
|
||||||
<link href="images/favicon.png" rel="shortcut icon" type="image/x-icon" />
|
|
||||||
<link href="images/webclip.png" rel="apple-touch-icon" />
|
|
||||||
</Head>
|
|
||||||
<InfoBrands />
|
<InfoBrands />
|
||||||
<BrandWizardSearchSection />
|
<BrandWizardSearchSection />
|
||||||
<Footer />
|
<Footer />
|
||||||
|
@ -24,6 +24,8 @@ import { PriceSkeleton } from '@/components/skeletons/ProductListSkeleton';
|
|||||||
import { useCart } from '@/contexts/CartContext';
|
import { useCart } from '@/contexts/CartContext';
|
||||||
import toast from 'react-hot-toast';
|
import toast from 'react-hot-toast';
|
||||||
import CartIcon from '@/components/CartIcon';
|
import CartIcon from '@/components/CartIcon';
|
||||||
|
import MetaTags from "@/components/MetaTags";
|
||||||
|
import { getMetaByPath, createCategoryMeta } from "@/lib/meta-config";
|
||||||
|
|
||||||
const mockData = Array(12).fill({
|
const mockData = Array(12).fill({
|
||||||
image: "",
|
image: "",
|
||||||
@ -506,16 +508,13 @@ export default function Catalog() {
|
|||||||
return <div className="py-8 text-center">Загрузка фильтров...</div>;
|
return <div className="py-8 text-center">Загрузка фильтров...</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Определяем meta-теги для каталога
|
||||||
|
const categoryNameDecoded = decodeURIComponent(categoryName as string || 'Каталог');
|
||||||
|
const metaData = createCategoryMeta(categoryNameDecoded, visibleProductsCount || undefined);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Head>
|
<MetaTags {...metaData} />
|
||||||
<title>Catalog</title>
|
|
||||||
<meta name="description" content="Catalog" />
|
|
||||||
<link href="https://fonts.googleapis.com" rel="preconnect" />
|
|
||||||
<link href="https://fonts.gstatic.com" rel="preconnect" crossOrigin="anonymous" />
|
|
||||||
<link href="images/favicon.png" rel="shortcut icon" type="image/x-icon" />
|
|
||||||
<link href="images/webclip.png" rel="apple-touch-icon" />
|
|
||||||
</Head>
|
|
||||||
<CatalogInfoHeader
|
<CatalogInfoHeader
|
||||||
title={
|
title={
|
||||||
isPartsAPIMode ? decodeURIComponent(categoryName as string || 'Запчасти') :
|
isPartsAPIMode ? decodeURIComponent(categoryName as string || 'Запчасти') :
|
||||||
|
@ -8,17 +8,15 @@ import InfoContacts from "@/components/contacts/InfoContacts";
|
|||||||
import MapContacts from "@/components/contacts/MapContacts";
|
import MapContacts from "@/components/contacts/MapContacts";
|
||||||
import OrderContacts from "@/components/contacts/OrderContacts";
|
import OrderContacts from "@/components/contacts/OrderContacts";
|
||||||
import LegalContacts from "@/components/contacts/LegalContacts";
|
import LegalContacts from "@/components/contacts/LegalContacts";
|
||||||
|
import MetaTags from "@/components/MetaTags";
|
||||||
|
import { getMetaByPath } from "@/lib/meta-config";
|
||||||
|
|
||||||
const Contacts = () => (
|
const Contacts = () => {
|
||||||
<>
|
const metaData = getMetaByPath('/contacts');
|
||||||
<Head>
|
|
||||||
<title>Contacts</title>
|
return (
|
||||||
<meta name="description" content="Contacts" />
|
<>
|
||||||
<link href="https://fonts.googleapis.com" rel="preconnect" />
|
<MetaTags {...metaData} />
|
||||||
<link href="https://fonts.gstatic.com" rel="preconnect" crossOrigin="anonymous" />
|
|
||||||
<link href="images/favicon.png" rel="shortcut icon" type="image/x-icon" />
|
|
||||||
<link href="images/webclip.png" rel="apple-touch-icon" />
|
|
||||||
</Head>
|
|
||||||
<InfoContacts />
|
<InfoContacts />
|
||||||
<section className="main">
|
<section className="main">
|
||||||
<div className="w-layout-blockcontainer container w-container">
|
<div className="w-layout-blockcontainer container w-container">
|
||||||
@ -38,7 +36,8 @@ const Contacts = () => (
|
|||||||
</section>
|
</section>
|
||||||
<Footer />
|
<Footer />
|
||||||
<MobileMenuBottomSection />
|
<MobileMenuBottomSection />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
};
|
||||||
|
|
||||||
export default Contacts;
|
export default Contacts;
|
@ -11,6 +11,8 @@ import CatalogSection from "@/components/index/CatalogSection";
|
|||||||
import AvailableParts from "@/components/index/AvailableParts";
|
import AvailableParts from "@/components/index/AvailableParts";
|
||||||
import NewsAndPromos from "@/components/index/NewsAndPromos";
|
import NewsAndPromos from "@/components/index/NewsAndPromos";
|
||||||
import AboutHelp from "@/components/about/AboutHelp";
|
import AboutHelp from "@/components/about/AboutHelp";
|
||||||
|
import MetaTags from "@/components/MetaTags";
|
||||||
|
import { getMetaByPath } from "@/lib/meta-config";
|
||||||
|
|
||||||
const geistSans = Geist({
|
const geistSans = Geist({
|
||||||
variable: "--font-geist-sans",
|
variable: "--font-geist-sans",
|
||||||
@ -23,16 +25,11 @@ const geistMono = Geist_Mono({
|
|||||||
});
|
});
|
||||||
|
|
||||||
export default function Home() {
|
export default function Home() {
|
||||||
|
const metaData = getMetaByPath('/');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Head>
|
<MetaTags {...metaData} />
|
||||||
<title>Protek</title>
|
|
||||||
<meta name="description" content="Protek" />
|
|
||||||
<link href="https://fonts.googleapis.com" rel="preconnect" />
|
|
||||||
<link href="https://fonts.gstatic.com" rel="preconnect" crossOrigin="anonymous" />
|
|
||||||
<link href="images/favicon.png" rel="shortcut icon" type="image/x-icon" />
|
|
||||||
<link href="images/webclip.png" rel="apple-touch-icon" />
|
|
||||||
</Head>
|
|
||||||
<HeroSlider />
|
<HeroSlider />
|
||||||
<CatalogSection />
|
<CatalogSection />
|
||||||
<div className="w-layout-blockcontainer container w-container">
|
<div className="w-layout-blockcontainer container w-container">
|
||||||
|
@ -16,6 +16,8 @@ import MobileMenuBottomSection from '../components/MobileMenuBottomSection';
|
|||||||
import { SEARCH_PRODUCT_OFFERS, GET_ANALOG_OFFERS } from "@/lib/graphql";
|
import { SEARCH_PRODUCT_OFFERS, GET_ANALOG_OFFERS } from "@/lib/graphql";
|
||||||
import { useArticleImage } from "@/hooks/useArticleImage";
|
import { useArticleImage } from "@/hooks/useArticleImage";
|
||||||
import { usePartsIndexEntityInfo } from "@/hooks/usePartsIndex";
|
import { usePartsIndexEntityInfo } from "@/hooks/usePartsIndex";
|
||||||
|
import MetaTags from "@/components/MetaTags";
|
||||||
|
import { createProductMeta } from "@/lib/meta-config";
|
||||||
|
|
||||||
const ANALOGS_CHUNK_SIZE = 5;
|
const ANALOGS_CHUNK_SIZE = 5;
|
||||||
|
|
||||||
@ -435,21 +437,21 @@ export default function SearchResult() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Создаем динамические meta-теги для товара
|
||||||
|
const metaData = result ? createProductMeta({
|
||||||
|
name: result.name,
|
||||||
|
brand: result.brand,
|
||||||
|
articleNumber: result.articleNumber,
|
||||||
|
price: minPrice
|
||||||
|
}) : {
|
||||||
|
title: 'Результаты поиска - Protek',
|
||||||
|
description: 'Результаты поиска автозапчастей. Найдите нужные запчасти среди широкого ассортимента.',
|
||||||
|
keywords: 'результаты поиска, поиск запчастей, найти запчасти'
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Head>
|
<MetaTags {...metaData} />
|
||||||
<title>{result ? `${result.brand} ${result.articleNumber} - ${result.name}` : `Результаты поиска`} - Protek</title>
|
|
||||||
<meta name="description" content={`Лучшие предложения и аналоги для ${result?.name}`} />
|
|
||||||
<meta content="Search result" property="og:title" />
|
|
||||||
<meta content="Search result" property="twitter:title" />
|
|
||||||
<meta content="width=device-width, initial-scale=1" name="viewport" />
|
|
||||||
<meta content="Webflow" name="generator" />
|
|
||||||
|
|
||||||
<link href="https://fonts.googleapis.com" rel="preconnect" />
|
|
||||||
<link href="https://fonts.gstatic.com" rel="preconnect" crossOrigin="anonymous" />
|
|
||||||
<link href="images/favicon.png" rel="shortcut icon" type="image/x-icon" />
|
|
||||||
<link href="images/webclip.png" rel="apple-touch-icon" />
|
|
||||||
</Head>
|
|
||||||
<InfoSearch
|
<InfoSearch
|
||||||
brand={result ? result.brand : brandQuery}
|
brand={result ? result.brand : brandQuery}
|
||||||
articleNumber={result ? result.articleNumber : searchQuery}
|
articleNumber={result ? result.articleNumber : searchQuery}
|
||||||
|
@ -5,23 +5,19 @@ import CatalogSubscribe from "@/components/CatalogSubscribe";
|
|||||||
import Footer from "@/components/Footer";
|
import Footer from "@/components/Footer";
|
||||||
import MobileMenuBottomSection from "@/components/MobileMenuBottomSection";
|
import MobileMenuBottomSection from "@/components/MobileMenuBottomSection";
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
|
import MetaTags from "@/components/MetaTags";
|
||||||
|
import { getMetaByPath } from "@/lib/meta-config";
|
||||||
|
|
||||||
export default function ThankYouPage() {
|
export default function ThankYouPage() {
|
||||||
|
const metaData = getMetaByPath('/thankyoupage');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
<MetaTags {...metaData} />
|
||||||
<Head>
|
<Head>
|
||||||
<meta charSet="utf-8" />
|
|
||||||
<title>thankyoupage</title>
|
|
||||||
<meta content="thankyoupage" property="og:title" />
|
|
||||||
<meta content="thankyoupage" property="twitter:title" />
|
|
||||||
<meta content="width=device-width, initial-scale=1" name="viewport" />
|
|
||||||
<link href="https://fonts.googleapis.com" rel="preconnect" />
|
|
||||||
<link href="https://fonts.gstatic.com" rel="preconnect" crossOrigin="anonymous" />
|
|
||||||
<script src="https://ajax.googleapis.com/ajax/libs/webfont/1.6.26/webfont.js" type="text/javascript"></script>
|
<script src="https://ajax.googleapis.com/ajax/libs/webfont/1.6.26/webfont.js" type="text/javascript"></script>
|
||||||
<script type="text/javascript" dangerouslySetInnerHTML={{__html: `WebFont.load({ google: { families: [\"Onest:regular,600,700,800,900:cyrillic-ext,latin\"] }});`}} />
|
<script type="text/javascript" dangerouslySetInnerHTML={{__html: `WebFont.load({ google: { families: [\"Onest:regular,600,700,800,900:cyrillic-ext,latin\"] }});`}} />
|
||||||
<script type="text/javascript" dangerouslySetInnerHTML={{__html: `!function(o,c){var n=c.documentElement,t=\" w-mod-\";n.className+=t+\"js\",(\"ontouchstart\"in o||o.DocumentTouch&&c instanceof DocumentTouch)&&(n.className+=t+\"touch\")}(window,document);`}} />
|
<script type="text/javascript" dangerouslySetInnerHTML={{__html: `!function(o,c){var n=c.documentElement,t=\" w-mod-\";n.className+=t+\"js\",(\"ontouchstart\"in o||o.DocumentTouch&&c instanceof DocumentTouch)&&(n.className+=t+\"touch\")}(window,document);`}} />
|
||||||
<link href="images/favicon.png" rel="shortcut icon" type="image/x-icon" />
|
|
||||||
<link href="images/webclip.png" rel="apple-touch-icon" />
|
|
||||||
</Head>
|
</Head>
|
||||||
|
|
||||||
<ThankInfo />
|
<ThankInfo />
|
||||||
|
@ -19,6 +19,8 @@ import KnotParts from '@/components/vin/KnotParts';
|
|||||||
import VinQuick from '@/components/vin/VinQuick';
|
import VinQuick from '@/components/vin/VinQuick';
|
||||||
import CatalogSubscribe from '@/components/CatalogSubscribe';
|
import CatalogSubscribe from '@/components/CatalogSubscribe';
|
||||||
import MobileMenuBottomSection from '@/components/MobileMenuBottomSection';
|
import MobileMenuBottomSection from '@/components/MobileMenuBottomSection';
|
||||||
|
import MetaTags from '@/components/MetaTags';
|
||||||
|
import { getMetaByPath } from '@/lib/meta-config';
|
||||||
|
|
||||||
|
|
||||||
interface LaximoVehicleInfo {
|
interface LaximoVehicleInfo {
|
||||||
@ -290,16 +292,24 @@ const VehicleDetailsPage = () => {
|
|||||||
const hasError = vehicleError && !vehicleData?.laximoVehicleInfo;
|
const hasError = vehicleError && !vehicleData?.laximoVehicleInfo;
|
||||||
const catalogInfo = catalogData.laximoCatalogInfo;
|
const catalogInfo = catalogData.laximoCatalogInfo;
|
||||||
|
|
||||||
|
// Создаем динамические meta-теги
|
||||||
|
const vehicleName = vehicleInfo.brand && vehicleInfo.name
|
||||||
|
? (vehicleInfo.name.indexOf(vehicleInfo.brand) !== 0
|
||||||
|
? `${vehicleInfo.brand} ${vehicleInfo.name}`
|
||||||
|
: vehicleInfo.name)
|
||||||
|
: 'Автомобиль';
|
||||||
|
|
||||||
|
const metaData = {
|
||||||
|
title: `Запчасти для ${vehicleName} - Поиск по каталогу Protek`,
|
||||||
|
description: `Найдите и купите запчасти для ${vehicleName}. Широкий выбор оригинальных и аналоговых запчастей с быстрой доставкой.`,
|
||||||
|
keywords: `запчасти ${vehicleName}, ${vehicleInfo.brand} запчасти, автозапчасти, каталог запчастей`,
|
||||||
|
ogTitle: `Запчасти для ${vehicleName} - Protek`,
|
||||||
|
ogDescription: `Найдите и купите запчасти для ${vehicleName}. Широкий выбор оригинальных и аналоговых запчастей.`
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Head>
|
<MetaTags {...metaData} />
|
||||||
<title>VIN</title>
|
|
||||||
<meta content="vin" property="og:title" />
|
|
||||||
<meta content="vin" property="twitter:title" />
|
|
||||||
|
|
||||||
<link href="images/favicon.png" rel="shortcut icon" type="image/x-icon" />
|
|
||||||
<link href="images/webclip.png" rel="apple-touch-icon" />
|
|
||||||
</Head>
|
|
||||||
|
|
||||||
{/* ====== ВРЕМЕННЫЙ МАКЕТ ДЛЯ ВЕРСТКИ (начало) ====== */}
|
{/* ====== ВРЕМЕННЫЙ МАКЕТ ДЛЯ ВЕРСТКИ (начало) ====== */}
|
||||||
<InfoVin
|
<InfoVin
|
||||||
|
@ -8,6 +8,8 @@ import VinLeftbar from "@/components/vin/VinLeftbar";
|
|||||||
import VinCategory from "@/components/vin/VinCategory";
|
import VinCategory from "@/components/vin/VinCategory";
|
||||||
import VinKnot from "@/components/vin/VinKnot";
|
import VinKnot from "@/components/vin/VinKnot";
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
|
import MetaTags from "@/components/MetaTags";
|
||||||
|
import { getMetaByPath } from "@/lib/meta-config";
|
||||||
|
|
||||||
export default function Vin() {
|
export default function Vin() {
|
||||||
const [showKnot, setShowKnot] = useState(false);
|
const [showKnot, setShowKnot] = useState(false);
|
||||||
@ -31,18 +33,11 @@ export default function Vin() {
|
|||||||
return () => document.removeEventListener("click", handler);
|
return () => document.removeEventListener("click", handler);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const metaData = getMetaByPath('/vin');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Head>
|
<MetaTags {...metaData} />
|
||||||
<title>VIN</title>
|
|
||||||
<meta content="vin" property="og:title" />
|
|
||||||
<meta content="vin" property="twitter:title" />
|
|
||||||
<meta content="width=device-width, initial-scale=1" name="viewport" />
|
|
||||||
<link href="https://fonts.googleapis.com" rel="preconnect" />
|
|
||||||
<link href="https://fonts.gstatic.com" rel="preconnect" crossOrigin="anonymous" />
|
|
||||||
<link href="images/favicon.png" rel="shortcut icon" type="image/x-icon" />
|
|
||||||
<link href="images/webclip.png" rel="apple-touch-icon" />
|
|
||||||
</Head>
|
|
||||||
<InfoVin />
|
<InfoVin />
|
||||||
<section className="main">
|
<section className="main">
|
||||||
<div className="w-layout-blockcontainer container-vin w-container">
|
<div className="w-layout-blockcontainer container-vin w-container">
|
||||||
|
@ -9,25 +9,16 @@ import WhyWholesale from "@/components/wholesale/WhyWholesale";
|
|||||||
import ServiceWholesale from "@/components/wholesale/ServiceWholesale";
|
import ServiceWholesale from "@/components/wholesale/ServiceWholesale";
|
||||||
import HowToBuy from "@/components/wholesale/HowToBuy";
|
import HowToBuy from "@/components/wholesale/HowToBuy";
|
||||||
import Help from "@/components/Help";
|
import Help from "@/components/Help";
|
||||||
|
import MetaTags from "@/components/MetaTags";
|
||||||
|
import { getMetaByPath } from "@/lib/meta-config";
|
||||||
|
|
||||||
|
|
||||||
export default function Wholesale() {
|
export default function Wholesale() {
|
||||||
|
const metaData = getMetaByPath('/wholesale');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Head>
|
<MetaTags {...metaData} />
|
||||||
<title>wholesale</title>
|
|
||||||
<meta content="wholesale" property="og:title" />
|
|
||||||
<meta content="wholesale" property="twitter:title" />
|
|
||||||
<meta content="width=device-width, initial-scale=1" name="viewport" />
|
|
||||||
<meta content="Webflow" name="generator" />
|
|
||||||
<link href="/css/normalize.css" rel="stylesheet" type="text/css" />
|
|
||||||
<link href="/css/webflow.css" rel="stylesheet" type="text/css" />
|
|
||||||
<link href="/css/protekproject.webflow.css" rel="stylesheet" type="text/css" />
|
|
||||||
<link href="https://fonts.googleapis.com" rel="preconnect" />
|
|
||||||
<link href="https://fonts.gstatic.com" rel="preconnect" crossOrigin="anonymous" />
|
|
||||||
<link href="images/favicon.png" rel="shortcut icon" type="image/x-icon" />
|
|
||||||
<link href="images/webclip.png" rel="apple-touch-icon" />
|
|
||||||
</Head>
|
|
||||||
|
|
||||||
<InfoWholesale />
|
<InfoWholesale />
|
||||||
<section className="main">
|
<section className="main">
|
||||||
|
Reference in New Issue
Block a user