astro_avtourist/frontend/src/pages/blog/index.astro

198 lines
No EOL
5.4 KiB
Text
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
import Layout from '@layouts/Layout.astro';
import { SITE_URL } from '@constants';
import PageHero from '@components/base/PageHero.astro';
import BlogCategories from '@components/blog/BlogCategories.astro';
import BlogCard from '@components/blog/BlogCard.astro';
import Pagination from '@components/base/Pagination.astro';
import CTA from '@components/base/CTA.astro';
import SearchModal from '@components/base/SearchModal.astro';
import { getPosts, getAllCategories, getPostImageUrl } from '@lib/pb';
const POSTS_PER_PAGE = 6;
const currentPage = 1;
const { posts, total, totalPages } = await getPosts({ page: currentPage, perPage: POSTS_PER_PAGE });
const categories = await getAllCategories();
const formatDate = (date: string) => {
return new Date(date).toLocaleDateString('ru-RU', {
day: 'numeric',
month: 'long',
year: 'numeric'
});
};
---
<Layout
title="Блог — автоюрист в Сургуте"
description="Полезные статьи и советы по автоспорам, ДТП, ОСАГО, лишению прав и защите прав водителей."
canonicalLink={`${SITE_URL}/blog`}
breadcrumbs={[
{ label: "Главная", href: "/" },
{ label: "Блог" }
]}
>
<PageHero
badgeText="БЛОГ И СТАТЬИ"
titleWhite="Полезные статьи"
titleGold="для автовладельцев"
description="Разбираем сложные юридические вопросы простым языком. Советы юриста по автоспорам, ДТП, ОСАГО и защите прав водителей."
layout="with-image"
sideImage="/images/blog/blogImg.avif"
sideImageAlt="Автоюрист Сургут"
experienceBadge={{
number: "50+",
text: "ПОЛЕЗНЫХ СТАТЕЙ"
}}
bgImage="/images/blog/blogBg.avif"
icon="edit"
/>
<BlogCategories categories={categories} activeCategory="Все" currentPage={currentPage} />
<!-- Сетка статей -->
<section class="blog-grid-section">
<div class="site-container">
<div class="blog-grid" id="blog-grid">
{posts.map((post: any) => (
<article class="blog-card-wrapper" data-category={post.category}>
<BlogCard
title={post.title}
description={post.description}
category={post.category}
categoryColor={post.categoryColor}
date={formatDate(post.date)}
readTime={post.readTime}
image={getPostImageUrl(post)}
slug={`/blog/${post.slug}`}
/>
</article>
))}
</div>
<!-- Пагинация -->
<Pagination
currentPage={currentPage}
totalPages={totalPages}
baseUrl="/blog"
/>
</div>
</section>
<!-- CTA-блок -->
<CTA
icon="consult"
title="Нужна консультация юриста?"
description="Не нашли ответ на свой вопрос? Запишитесь на бесплатную консультацию — мы поможем разобраться в вашей ситуации"
btnText="Записаться на консультацию"
/>
<SearchModal />
</Layout>
<style>
.blog-grid-section {
padding: 3rem 0 0;
background: #f8fafc;
}
.blog-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 2rem;
}
.blog-card-wrapper {
transition: opacity 0.3s ease, transform 0.3s ease, display 0.3s ease;
}
/* ===== RESPONSIVE ===== */
@media (max-width: 1024px) {
.blog-grid {
grid-template-columns: repeat(2, 1fr);
}
}
@media (max-width: 768px) {
.blog-grid {
grid-template-columns: 1fr;
gap: 1.5rem;
}
.blog-cta {
padding: 3rem 0;
}
}
</style>
<script>
const setupAnimations = () => {
const observerOptions = {
root: null,
rootMargin: '0px 0px -50px 0px',
threshold: 0.1
};
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const el = entry.target as HTMLElement;
const delay = parseInt(el.dataset.delay || '0');
setTimeout(() => {
el.classList.add('is-visible');
}, delay);
observer.unobserve(el);
}
});
}, observerOptions);
document.querySelectorAll('.animate-on-scroll').forEach((el) => {
observer.observe(el);
});
};
const setupFilter = () => {
const buttons = document.querySelectorAll('.category-btn');
const cards = document.querySelectorAll('.blog-card-wrapper');
const grid = document.getElementById('blog-grid');
buttons.forEach((btn) => {
btn.addEventListener('click', (e) => {
e.preventDefault();
const category = btn.getAttribute('data-category');
// Обновляем активную кнопку
buttons.forEach(b => b.classList.remove('active'));
btn.classList.add('active');
// Фильтруем карточки
cards.forEach((card) => {
const cardCategory = card.getAttribute('data-category');
const el = card as HTMLElement;
if (category === 'Все' || cardCategory === category) {
el.style.display = '';
el.style.opacity = '0';
el.style.transform = 'translateY(20px)';
requestAnimationFrame(() => {
el.style.transition = 'opacity 0.4s ease, transform 0.4s ease';
el.style.opacity = '1';
el.style.transform = 'translateY(0)';
});
} else {
el.style.display = 'none';
}
});
});
});
};
setupAnimations();
setupFilter();
document.addEventListener('astro:after-swap', () => {
setupAnimations();
setupFilter();
});
</script>