From 2703137ca195c88cd9bcc2fa267a6f93f0c861ac Mon Sep 17 00:00:00 2001 From: egortriston Date: Wed, 16 Jul 2025 14:28:47 +0300 Subject: [PATCH] fix1607 --- src/components/SearchHistoryDropdown.tsx | 117 +++++-- src/components/index/CategoryNavSection.tsx | 145 +++----- src/components/index/ProductOfDayBanner.tsx | 321 ++++++++++-------- src/components/profile/ProfileHistoryMain.tsx | 6 +- src/pages/profile-history.tsx | 6 +- src/pages/search-result.tsx | 2 +- src/styles/my.css | 46 +++ 7 files changed, 368 insertions(+), 275 deletions(-) diff --git a/src/components/SearchHistoryDropdown.tsx b/src/components/SearchHistoryDropdown.tsx index df2bc98..8dfc45f 100644 --- a/src/components/SearchHistoryDropdown.tsx +++ b/src/components/SearchHistoryDropdown.tsx @@ -38,7 +38,7 @@ const SearchHistoryDropdown: React.FC = ({ }; return ( -
+
{loading ? (
@@ -51,32 +51,24 @@ const SearchHistoryDropdown: React.FC = ({
) : uniqueQueries.length > 0 ? ( <> -
-

- Последние запросы -

-
{uniqueQueries.map((item) => ( ))} @@ -86,6 +78,91 @@ const SearchHistoryDropdown: React.FC = ({

История поиска пуста

)} +
); }; diff --git a/src/components/index/CategoryNavSection.tsx b/src/components/index/CategoryNavSection.tsx index f985f50..3f38f83 100644 --- a/src/components/index/CategoryNavSection.tsx +++ b/src/components/index/CategoryNavSection.tsx @@ -3,138 +3,69 @@ import { useQuery } from '@apollo/client'; import { GET_PARTSINDEX_CATEGORIES } from '@/lib/graphql'; import { useRouter } from 'next/router'; -interface PartsIndexCatalog { +interface CategoryNavItem { id: string; name: string; image?: string; - groups?: PartsIndexGroup[]; } -interface PartsIndexGroup { - id: string; - name: string; - image?: string; - subgroups?: PartsIndexSubgroup[]; - entityNames?: { id: string; name: string }[]; -} - -interface PartsIndexSubgroup { - id: string; - name: string; - image?: string; - entityNames?: { id: string; name: string }[]; -} +const FALLBACK_CATEGORIES: CategoryNavItem[] = [ + { id: '1', name: 'Детали для ТО', image: '/images/catalog_item.png' }, + { id: '2', name: 'Шины', image: '/images/catalog_item2.png' }, + { id: '3', name: 'Диски', image: '/images/catalog_item3.png' }, + { id: '4', name: 'Масла и жидкости', image: '/images/catalog_item4.png' }, + { id: '5', name: 'Инструменты', image: '/images/catalog_item5.png' }, + { id: '6', name: 'Автохимия', image: '/images/catalog_item6.png' }, + { id: '7', name: 'Аксессуары', image: '/images/catalog_item7.png' }, + { id: '8', name: 'Электрика', image: '/images/catalog_item8.png' }, + { id: '9', name: 'АКБ', image: '/images/catalog_item9.png' }, +]; const CategoryNavSection: React.FC = () => { const router = useRouter(); - - const { data, loading, error } = useQuery<{ partsIndexCategoriesWithGroups: PartsIndexCatalog[] }>( + + const { data } = useQuery<{ partsIndexCategoriesWithGroups: CategoryNavItem[] }>( GET_PARTSINDEX_CATEGORIES, { - variables: { - lang: 'ru' - }, + variables: { lang: 'ru' }, errorPolicy: 'all', - fetchPolicy: 'cache-first' + fetchPolicy: 'cache-first', } ); - // Обработчик клика по категории для перехода в каталог с товарами - const handleCategoryClick = (catalog: PartsIndexCatalog) => { - console.log('🔍 Клик по категории:', { catalogId: catalog.id, categoryName: catalog.name }); - - // Получаем первую группу для groupId (это правильный ID для partsIndexCategory) - const firstGroup = catalog.groups?.[0]; - const groupId = firstGroup?.id; - - console.log('🔍 Найденная группа:', { groupId, groupName: firstGroup?.name }); - - // Переходим на страницу каталога с параметрами PartsIndex + const categories = (data?.partsIndexCategoriesWithGroups && data.partsIndexCategoriesWithGroups.length > 0) + ? data.partsIndexCategoriesWithGroups.slice(0, 9) + : FALLBACK_CATEGORIES; + + const handleCategoryClick = (category: CategoryNavItem) => { router.push({ pathname: '/catalog', query: { - partsIndexCatalog: catalog.id, - categoryName: encodeURIComponent(catalog.name), - ...(groupId && { partsIndexCategory: groupId }) + categoryId: category.id, + categoryName: encodeURIComponent(category.name) } }); }; - // Fallback данные на случай ошибки - const fallbackCategories = [ - { id: '1', name: 'Двигатель', image: '/images/catalog_item.png' }, - { id: '2', name: 'Трансмиссия', image: '/images/catalog_item2.png' }, - { id: '3', name: 'Подвеска', image: '/images/catalog_item3.png' }, - { id: '4', name: 'Тормоза', image: '/images/catalog_item4.png' }, - { id: '5', name: 'Электрика', image: '/images/catalog_item5.png' }, - { id: '6', name: 'Кузов', image: '/images/catalog_item6.png' }, - { id: '7', name: 'Салон', image: '/images/catalog_item7.png' }, - { id: '8', name: 'Климат', image: '/images/catalog_item8.png' }, - { id: '9', name: 'Расходники', image: '/images/catalog_item9.png' } - ]; - - // Используем данные из API или fallback - const categories = data?.partsIndexCategoriesWithGroups || []; - const displayCategories = categories.length > 0 ? categories : fallbackCategories; - - if (loading) { - return ( -
-
- {Array.from({ length: 9 }).map((_, index) => ( -
-
-
- ))} -
-
- {Array.from({ length: 9 }).map((_, index) => ( -
-
-
- ))} -
-
- ); - } - return ( -
- {/* Навигационная панель с названиями категорий */} -
- {displayCategories.slice(0, 9).map((catalog) => ( -
-
handleCategoryClick(catalog)} - style={{ cursor: 'pointer' }} +
+
+
+ {categories.map((category, idx) => ( +
handleCategoryClick(category)} > - {catalog.name} +
+ {category.name} +
-
- ))} + ))} +
- - {/* Блок с изображениями категорий */} -
- {displayCategories.slice(0, 9).map((catalog) => ( -
- {catalog.name} handleCategoryClick(catalog)} - style={{ cursor: 'pointer' }} - onError={(e) => { - const target = e.target as HTMLImageElement; - target.src = '/images/catalog_item.png'; - }} - /> -
- ))} -
-
+ ); }; diff --git a/src/components/index/ProductOfDayBanner.tsx b/src/components/index/ProductOfDayBanner.tsx index 88e76df..d23948f 100644 --- a/src/components/index/ProductOfDayBanner.tsx +++ b/src/components/index/ProductOfDayBanner.tsx @@ -1,4 +1,4 @@ -import React, { useState, useEffect } from 'react'; +import React, { useState, useEffect, useRef } from 'react'; import { useQuery } from '@apollo/client'; import { GET_HERO_BANNERS } from '@/lib/graphql'; import Link from 'next/link'; @@ -13,20 +13,94 @@ interface HeroBanner { sortOrder: number; } +// Добавим CSS для стрелок +const arrowStyles = ` +.pod-slider-arrow { + width: 40px; + height: 40px; + border: none; + background: none; + padding: 0; + position: absolute; + top: 50%; + transform: translateY(-50%); + z-index: 10; + display: flex; + align-items: center; + justify-content: center; + opacity: 1; + transition: opacity 0.2s; + cursor: pointer; +} +.pod-slider-arrow-left { left: 12px; } +.pod-slider-arrow-right { right: 12px; } +.pod-slider-arrow .arrow-circle { + width: 36px; + height: 36px; + border-radius: 50%; + background: rgba(255,255,255,0.85); + display: flex; + align-items: center; + justify-content: center; + transition: background 0.2s; +} +.pod-slider-arrow:hover .arrow-circle, +.pod-slider-arrow:focus .arrow-circle { + background: #ec1c24; +} +.pod-slider-arrow .arrow-svg { + width: 20px; + height: 20px; + display: block; + transition: stroke 0.2s; + stroke: #222; +} +.pod-slider-arrow:hover .arrow-svg, +.pod-slider-arrow:focus .arrow-svg { + stroke: #fff; +} +`; + +const slideStyles = ` +.pod-slider-slide { + position: absolute; + top: 0; left: 0; + opacity: 0; + transform: translateX(40px) scale(0.98); + transition: opacity 0.5s cubic-bezier(.4,0,.2,1), transform 0.5s cubic-bezier(.4,0,.2,1); + pointer-events: none; + z-index: 1; +} +.pod-slider-slide.active { + opacity: 1; + transform: translateX(0) scale(1); + pointer-events: auto; + z-index: 2; +} +.pod-slider-slide.prev { + opacity: 0; + transform: translateX(-40px) scale(0.98); + z-index: 1; +} +.pod-slider-slide.next { + opacity: 0; + transform: translateX(40px) scale(0.98); + z-index: 1; +} +.mask.w-slider-mask { position: relative; } +`; + const ProductOfDayBanner: React.FC = () => { const [currentSlide, setCurrentSlide] = useState(0); - - const { data, loading, error } = useQuery(GET_HERO_BANNERS, { - errorPolicy: 'all' - }); + const [showArrows, setShowArrows] = useState(false); + const sliderRef = useRef(null); + const { data } = useQuery(GET_HERO_BANNERS, { errorPolicy: 'all' }); - // Фильтруем только активные баннеры и сортируем их const banners: HeroBanner[] = data?.heroBanners ?.filter((banner: HeroBanner) => banner.isActive) ?.slice() ?.sort((a: HeroBanner, b: HeroBanner) => a.sortOrder - b.sortOrder) || []; - // Если нет баннеров из админки, показываем дефолтный const allBanners = banners.length > 0 ? banners : [{ id: 'default', title: 'ДОСТАВИМ БЫСТРО!', @@ -37,18 +111,15 @@ const ProductOfDayBanner: React.FC = () => { sortOrder: 0 }]; - // Автопрокрутка слайдов useEffect(() => { if (allBanners.length > 1) { const interval = setInterval(() => { setCurrentSlide(prev => (prev + 1) % allBanners.length); - }, 5000); // Меняем слайд каждые 5 секунд - + }, 5000); return () => clearInterval(interval); } }, [allBanners.length]); - // Сброс текущего слайда если он вне диапазона useEffect(() => { if (currentSlide >= allBanners.length) { setCurrentSlide(0); @@ -67,141 +138,109 @@ const ProductOfDayBanner: React.FC = () => { setCurrentSlide(index); }; - const currentBanner = allBanners[currentSlide]; - - const renderBannerContent = (banner: HeroBanner) => { - return ( -
- {(banner.title || banner.subtitle) && ( -
- {banner.title && ( -

- {banner.title} -

- )} - {banner.subtitle && ( -

- {banner.subtitle} -

- )} -
- )} -
- ); - }; - - const bannerContent = renderBannerContent(currentBanner); - - const finalContent = currentBanner.linkUrl ? ( - - {bannerContent} - - ) : bannerContent; + // Показывать стрелки при наведении на слайдер или стрелки + const handleMouseEnter = () => setShowArrows(true); + const handleMouseLeave = () => setShowArrows(false); return ( -
- {finalContent} - - {/* Навигация стрелками (показываем только если баннеров больше 1) */} - {allBanners.length > 1 && ( - <> -
- ‹ -
-
- › -
- - )} - - {/* Индикаторы слайдов (показываем только если баннеров больше 1) */} - {allBanners.length > 1 && ( -
- {allBanners.map((_, index) => ( +
+ {/* Вставляем стили для стрелок */} + +
+ {allBanners.map((banner, idx) => { + let slideClass = 'pod-slider-slide'; + if (idx === currentSlide) slideClass += ' active'; + else if (idx === (currentSlide === 0 ? allBanners.length - 1 : currentSlide - 1)) slideClass += ' prev'; + else if (idx === (currentSlide + 1) % allBanners.length) slideClass += ' next'; + const slideContent = (
handleSlideIndicator(index)} + className="div-block-128" style={{ - width: '10px', - height: '10px', - borderRadius: '50%', - background: index === currentSlide ? 'white' : 'rgba(255,255,255,0.5)', - cursor: 'pointer', - transition: 'background 0.3s' + backgroundImage: `url(${banner.imageUrl})`, + // backgroundSize: 'cover', + // backgroundPosition: 'center', + // backgroundRepeat: 'no-repeat', }} - /> - ))} -
- )} + > + {/* Можно добавить текст поверх баннера, если нужно */} +
+ ); + return ( +
+ {banner.linkUrl ? ( + {slideContent} + ) : slideContent} +
+ ); + })} +
+ {/* SVG-стрелки как в Webflow, поверх баннера, с hover-эффектом */} + + +
+ {allBanners.map((_, idx) => ( +
handleSlideIndicator(idx)} + /> + ))} +
); }; diff --git a/src/components/profile/ProfileHistoryMain.tsx b/src/components/profile/ProfileHistoryMain.tsx index 9a891fa..2955072 100644 --- a/src/components/profile/ProfileHistoryMain.tsx +++ b/src/components/profile/ProfileHistoryMain.tsx @@ -284,7 +284,7 @@ const ProfileHistoryMain = () => { if (loading && historyItems.length === 0) { return ( -
+
Загрузка истории поиска...
@@ -294,7 +294,7 @@ const ProfileHistoryMain = () => { if (error) { return ( -
+
Ошибка загрузки истории поиска
@@ -303,7 +303,7 @@ const ProfileHistoryMain = () => { } return ( -
+
{ return ( <> -
+
-
-
+
+
diff --git a/src/pages/search-result.tsx b/src/pages/search-result.tsx index 301ea9c..6681817 100644 --- a/src/pages/search-result.tsx +++ b/src/pages/search-result.tsx @@ -589,7 +589,7 @@ export default function SearchResult() { )} {/* Лучшие предложения */} {bestOffersData.length > 0 && ( -
+
{bestOffersData.map(({ offer, type }, index) => ( diff --git a/src/styles/my.css b/src/styles/my.css index f5d7893..8b419bd 100644 --- a/src/styles/my.css +++ b/src/styles/my.css @@ -499,7 +499,27 @@ input#VinSearchInput { white-space: nowrap; } +.heading-9-copy { + + text-align: right; + margin-left: auto; + display: block; +} +.pcs-search { + color: var(--_fonts---color--black); + font-size: var(--_fonts---font-size--core); + width: 200px; +} + + + @media (max-width: 767px) { + .heading-9-copy { + text-align: left; + + display: block; + } + .w-layout-hflex.flex-block-6 { flex-direction: column !important; } @@ -1147,4 +1167,30 @@ a.link-block-2.w-inline-block { justify-content: flex-start !important; align-items: flex-start !important; } +} + +@media (max-width: 767px) { + .mask.w-slider-mask { + height: 100px !important; + min-height: 0 !important; + } +} + +@media (max-width: 767px) { + .search-history-dropdown, + .search-results-dropdown, + .dropdown-search, + .dropdown-list-3.w--open { + position: fixed !important; + left: 0 !important; + right: 0 !important; + top: 72px !important; /* подберите под ваш header */ + width: 100vw !important; + z-index: 9999 !important; + border-radius: 0 0 16px 16px !important; + margin: 0 !important; + max-width: 100vw !important; + background: white !important; + box-shadow: 0 8px 32px rgba(44,62,80,0.10), 0 1.5px 4px rgba(44,62,80,0.08) !important; + } } \ No newline at end of file -- 2.49.0