Переписаны компоенты главной страницы
This commit is contained in:
parent
2b087c02b7
commit
284e37fa94
7 changed files with 320 additions and 227 deletions
|
|
@ -2,15 +2,35 @@
|
|||
import { reviewsData } from '@data/reviewsData';
|
||||
import ReviewCard from '@components/reviews/ReviewCard.astro';
|
||||
|
||||
// Берём 6 последних отзывов (сортируем по дате, берём последние)
|
||||
// Берём 6 последних отзывов
|
||||
const latestReviews = [...reviewsData]
|
||||
.sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime())
|
||||
.slice(0, 6);
|
||||
|
||||
// Для эффекта бесконечности клонируем элементы (один набор в начало, один в конец)
|
||||
// Для эффекта бесконечности клонируем элементы
|
||||
const displayReviews = [...latestReviews, ...latestReviews, ...latestReviews];
|
||||
|
||||
// Функция для получения инициала из имени
|
||||
const getInitial = (name: string) => name.charAt(0).toUpperCase();
|
||||
|
||||
// Функция для получения цвета аватара (циклически из набора)
|
||||
const colors = ['#eac26e', '#22c55e', '#3b82f6', '#ef4444', '#8b5cf6', '#f59e0b'];
|
||||
const getColor = (index: number) => colors[index % colors.length];
|
||||
---
|
||||
|
||||
<!-- КРИТИЧНО: Скрипт скрывает элементы ДО рендера -->
|
||||
<script is:inline>
|
||||
(function() {
|
||||
if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) return;
|
||||
|
||||
const style = document.createElement('style');
|
||||
style.textContent = '.animate-on-scroll{opacity:0;transform:translateY(30px)}' +
|
||||
'[data-animation="scale-up"]{transform:translateY(40px) scale(0.95)}' +
|
||||
'[data-animation="fade-in"]{opacity:0;transform:none}';
|
||||
document.head.appendChild(style);
|
||||
})();
|
||||
</script>
|
||||
|
||||
<section class="reviews-section py-16 bg-[#ffffff] overflow-hidden">
|
||||
<div class="site-container">
|
||||
<div class="section-header">
|
||||
|
|
@ -40,11 +60,11 @@ const displayReviews = [...latestReviews, ...latestReviews, ...latestReviews];
|
|||
car={review.car}
|
||||
text={review.text}
|
||||
rating={review.rating}
|
||||
initial={review.initial}
|
||||
color={review.color}
|
||||
date={review.date}
|
||||
votesCount={review.votesCount || 0}
|
||||
isHelpful={review.isHelpful || false}
|
||||
initial={getInitial(review.name)}
|
||||
color={getColor(index)}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
|
|
@ -69,33 +89,24 @@ const displayReviews = [...latestReviews, ...latestReviews, ...latestReviews];
|
|||
display: none;
|
||||
}
|
||||
|
||||
/* Карточка в слайдере — полностью сохраняет оригинальный дизайн ReviewCard */
|
||||
.card-item {
|
||||
scroll-snap-align: center;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
/* Центрирование карточки на мобильном */
|
||||
#sliderContainer {
|
||||
scroll-snap-type: x mandatory;
|
||||
}
|
||||
|
||||
#sliderTrack {
|
||||
scroll-snap-align: center;
|
||||
}
|
||||
|
||||
/* Убедимся, что карточка растягивается на всю ширину слайда */
|
||||
.card-item :global(.review-card) {
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* Уменьшаем имя для слайдера — влезает в одну строку */
|
||||
.card-item :global(.author-name) {
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
/* Заголовок секции */
|
||||
.section-header {
|
||||
margin-bottom: 4rem;
|
||||
text-align: center;
|
||||
|
|
@ -127,14 +138,14 @@ const displayReviews = [...latestReviews, ...latestReviews, ...latestReviews];
|
|||
width: 100%;
|
||||
}
|
||||
|
||||
/* Анимации при скроллинге */
|
||||
/* ИСПРАВЛЕНИЕ LCP: opacity: 1 по умолчанию */
|
||||
.animate-on-scroll {
|
||||
opacity: 0;
|
||||
opacity: 1;
|
||||
transform: translateY(0) scale(1);
|
||||
will-change: opacity, transform;
|
||||
}
|
||||
|
||||
[data-animation="fade-up"] {
|
||||
transform: translateY(30px);
|
||||
transition: opacity 0.8s cubic-bezier(0.4, 0, 0.2, 1),
|
||||
transform 0.8s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
}
|
||||
|
|
@ -144,7 +155,6 @@ const displayReviews = [...latestReviews, ...latestReviews, ...latestReviews];
|
|||
}
|
||||
|
||||
[data-animation="scale-up"] {
|
||||
transform: translateY(40px) scale(0.95);
|
||||
transition: opacity 0.7s cubic-bezier(0.4, 0, 0.2, 1),
|
||||
transform 0.7s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
}
|
||||
|
|
@ -156,15 +166,14 @@ const displayReviews = [...latestReviews, ...latestReviews, ...latestReviews];
|
|||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.animate-on-scroll {
|
||||
opacity: 1;
|
||||
transform: none;
|
||||
transition: none;
|
||||
opacity: 1 !important;
|
||||
transform: none !important;
|
||||
transition: none !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
// Intersection Observer для анимаций
|
||||
const setupAnimations = () => {
|
||||
const observerOptions = {
|
||||
root: null,
|
||||
|
|
@ -179,7 +188,9 @@ const displayReviews = [...latestReviews, ...latestReviews, ...latestReviews];
|
|||
const delay = parseInt(el.dataset.delay || '0');
|
||||
|
||||
setTimeout(() => {
|
||||
el.classList.add('is-visible');
|
||||
requestAnimationFrame(() => {
|
||||
el.classList.add('is-visible');
|
||||
});
|
||||
}, delay);
|
||||
|
||||
observer.unobserve(el);
|
||||
|
|
@ -194,12 +205,11 @@ const displayReviews = [...latestReviews, ...latestReviews, ...latestReviews];
|
|||
|
||||
const setupSlider = () => {
|
||||
const container = document.getElementById('sliderContainer');
|
||||
const track = document.getElementById('sliderTrack');
|
||||
const nextBtn = document.getElementById('nextBtn');
|
||||
const prevBtn = document.getElementById('prevBtn');
|
||||
const cards = document.querySelectorAll('.card-item');
|
||||
|
||||
if (!container || !track || !nextBtn || !prevBtn || cards.length === 0) return;
|
||||
if (!container || !nextBtn || !prevBtn || cards.length === 0) return;
|
||||
|
||||
const totalOriginal = cards.length / 3;
|
||||
const firstCard = cards[0] as HTMLElement;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue