Новые изменения в компоенты
This commit is contained in:
parent
acb7b88ff1
commit
9122756a58
11 changed files with 360 additions and 13 deletions
|
|
@ -207,5 +207,5 @@ const iconPaths: Record<string, string> = {
|
|||
};
|
||||
|
||||
setupAnimations();
|
||||
document.addEventListener('astro:after-swap', setupAnimations);
|
||||
document.addEventListener('astro:page-load', setupAnimations);
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -13,13 +13,12 @@ const { categories, activeCategory = 'Все', currentPage = 1 } = Astro.props;
|
|||
<div class="categories-inner animate-on-scroll" data-animation="fade-up">
|
||||
<div class="categories-wrapper">
|
||||
{categories.map((cat) => (
|
||||
<a
|
||||
href={cat === 'Все' ? '/blog' : `/blog/category/${cat.toLowerCase()}`}
|
||||
<button
|
||||
class={`category-btn ${cat === activeCategory ? 'active' : ''}`}
|
||||
data-category={cat}
|
||||
>
|
||||
{cat}
|
||||
</a>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
|
||||
|
|
@ -100,7 +99,6 @@ const { categories, activeCategory = 'Все', currentPage = 1 } = Astro.props;
|
|||
border-color: #d4af37;
|
||||
color: #1e293b;
|
||||
box-shadow: 0 4px 12px rgba(212, 175, 55, 0.3);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
/* Анимации */
|
||||
|
|
|
|||
|
|
@ -282,7 +282,7 @@ const colors = ['bg-gradient-1', 'bg-gradient-2', 'bg-gradient-3', 'bg-gradient-
|
|||
setupSlider();
|
||||
setupAnimations();
|
||||
|
||||
document.addEventListener('astro:after-swap', () => {
|
||||
document.addEventListener('astro:page-load', () => {
|
||||
setupSlider();
|
||||
setupAnimations();
|
||||
});
|
||||
|
|
|
|||
|
|
@ -71,11 +71,17 @@ const { title, description, canonicalLink, breadcrumbs } = Astro.props;
|
|||
sessionStorage.setItem('scrollPosition', String(window.scrollY));
|
||||
});
|
||||
|
||||
// Восстанавливаем позицию скролла после перехода
|
||||
// Восстанавливаем позицию скролла после перехода с плавной анимацией
|
||||
document.addEventListener('astro:after-swap', () => {
|
||||
const savedPosition = sessionStorage.getItem('scrollPosition');
|
||||
if (savedPosition) {
|
||||
window.scrollTo(0, parseInt(savedPosition));
|
||||
const targetScroll = parseInt(savedPosition);
|
||||
setTimeout(() => {
|
||||
window.scrollTo({
|
||||
top: targetScroll,
|
||||
behavior: 'auto'
|
||||
});
|
||||
}, 50);
|
||||
sessionStorage.removeItem('scrollPosition');
|
||||
}
|
||||
});
|
||||
|
|
|
|||
171
frontend/src/pages/blog/category/[category].astro
Normal file
171
frontend/src/pages/blog/category/[category].astro
Normal file
|
|
@ -0,0 +1,171 @@
|
|||
---
|
||||
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 SearchModal from '@components/base/SearchModal.astro';
|
||||
import { getPosts, getAllCategories, getPostImageUrl } from '@lib/pb';
|
||||
|
||||
export const prerender = false;
|
||||
|
||||
const POSTS_PER_PAGE = 6;
|
||||
const categorySlug = Astro.params.category || '';
|
||||
|
||||
const categories = await getAllCategories();
|
||||
const categoryName = categories.find(c => c.toLowerCase() === categorySlug.toLowerCase()) || categorySlug;
|
||||
|
||||
const { posts, total, totalPages } = await getPosts({
|
||||
category: categoryName,
|
||||
page: 1,
|
||||
perPage: POSTS_PER_PAGE
|
||||
});
|
||||
|
||||
const formatDate = (date: string) => {
|
||||
const d = new Date(date);
|
||||
const day = d.getDate().toString().padStart(2, '0');
|
||||
const month = (d.getMonth() + 1).toString().padStart(2, '0');
|
||||
const year = new Date().getFullYear().toString().slice(-2);
|
||||
return `${day}/${month}/${year}`;
|
||||
};
|
||||
---
|
||||
|
||||
<Layout
|
||||
title={`${categoryName} — автоюрист в Сургуте`}
|
||||
description={`Статьи по теме "${categoryName}" — автоюрист в Сургуте. Полезные статьи и советы по автоспорам.`}
|
||||
canonicalLink={`${SITE_URL}/blog/category/${categorySlug}`}
|
||||
breadcrumbs={[
|
||||
{ label: 'Главная', href: '/' },
|
||||
{ label: 'Блог', href: '/blog' },
|
||||
{ label: categoryName }
|
||||
]}
|
||||
>
|
||||
<PageHero
|
||||
badgeText={categoryName.toUpperCase()}
|
||||
titleWhite={categoryName}
|
||||
titleGold="статьи"
|
||||
description={`Полезные статьи и советы по теме "${categoryName}" от автоюриста в Сургуте.`}
|
||||
layout="with-image"
|
||||
sideImage="/images/blog/blogImg.avif"
|
||||
sideImageAlt="Автоюрист Сургут"
|
||||
experienceBadge={{
|
||||
number: String(total),
|
||||
text: "СТАТЕЙ"
|
||||
}}
|
||||
bgImage="/images/blog/blogBg.avif"
|
||||
/>
|
||||
|
||||
<BlogCategories categories={categories} activeCategory={categoryName} currentPage={1} />
|
||||
|
||||
<section class="blog-grid-section">
|
||||
<div class="site-container">
|
||||
<div class="blog-grid" id="blog-grid">
|
||||
{posts.length > 0 ? (
|
||||
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}
|
||||
readmeTime={post.readmeTime}
|
||||
image={getPostImageUrl(post)}
|
||||
slug={`/blog/${post.slug}`}
|
||||
/>
|
||||
</article>
|
||||
))
|
||||
) : (
|
||||
<div class="no-results">
|
||||
<p>Статьи по теме "{categoryName}" не найдены</p>
|
||||
<a href="/blog" class="back-link">Вернуться к списку статей</a>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{totalPages > 1 && (
|
||||
<Pagination
|
||||
currentPage={1}
|
||||
totalPages={totalPages}
|
||||
baseUrl={`/blog/category/${categorySlug}`}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<SearchModal />
|
||||
</Layout>
|
||||
|
||||
<style>
|
||||
.blog-grid-section {
|
||||
padding: 3rem 0;
|
||||
background: #f8fafc;
|
||||
}
|
||||
|
||||
.blog-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 2rem;
|
||||
}
|
||||
|
||||
.no-results {
|
||||
grid-column: 1 / -1;
|
||||
text-align: center;
|
||||
padding: 4rem 0;
|
||||
color: #64748b;
|
||||
}
|
||||
|
||||
.back-link {
|
||||
display: inline-block;
|
||||
margin-top: 1rem;
|
||||
color: #d4af37;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
}
|
||||
</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);
|
||||
});
|
||||
};
|
||||
|
||||
setupAnimations();
|
||||
document.addEventListener('astro:page-load', setupAnimations);
|
||||
</script>
|
||||
172
frontend/src/pages/blog/category/[category]/page/[page].astro
Normal file
172
frontend/src/pages/blog/category/[category]/page/[page].astro
Normal file
|
|
@ -0,0 +1,172 @@
|
|||
---
|
||||
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 SearchModal from '@components/base/SearchModal.astro';
|
||||
import { getPosts, getAllCategories, getPostImageUrl } from '@lib/pb';
|
||||
|
||||
export const prerender = false;
|
||||
|
||||
const POSTS_PER_PAGE = 6;
|
||||
const categorySlug = Astro.params.category || '';
|
||||
const currentPage = Number(Astro.params.page) || 1;
|
||||
|
||||
const categories = await getAllCategories();
|
||||
const categoryName = categories.find(c => c.toLowerCase() === categorySlug.toLowerCase()) || categorySlug;
|
||||
|
||||
const { posts, total, totalPages } = await getPosts({
|
||||
category: categoryName,
|
||||
page: currentPage,
|
||||
perPage: POSTS_PER_PAGE
|
||||
});
|
||||
|
||||
const formatDate = (date: string) => {
|
||||
const d = new Date(date);
|
||||
const day = d.getDate().toString().padStart(2, '0');
|
||||
const month = (d.getMonth() + 1).toString().padStart(2, '0');
|
||||
const year = new Date().getFullYear().toString().slice(-2);
|
||||
return `${day}/${month}/${year}`;
|
||||
};
|
||||
---
|
||||
|
||||
<Layout
|
||||
title={`${categoryName} — автоюрист в Сургуте`}
|
||||
description={`Статьи по теме "${categoryName}" — автоюрист в Сургуте. Полезные статьи и советы по автоспорам.`}
|
||||
canonicalLink={`${SITE_URL}/blog/category/${categorySlug}`}
|
||||
breadcrumbs={[
|
||||
{ label: 'Главная', href: '/' },
|
||||
{ label: 'Блог', href: '/blog' },
|
||||
{ label: categoryName }
|
||||
]}
|
||||
>
|
||||
<PageHero
|
||||
badgeText={categoryName.toUpperCase()}
|
||||
titleWhite={categoryName}
|
||||
titleGold="статьи"
|
||||
description={`Полезные статьи и советы по теме "${categoryName}" от автоюриста в Сургуте.`}
|
||||
layout="with-image"
|
||||
sideImage="/images/blog/blogImg.avif"
|
||||
sideImageAlt="Автоюрист Сургут"
|
||||
experienceBadge={{
|
||||
number: String(total),
|
||||
text: "СТАТЕЙ"
|
||||
}}
|
||||
bgImage="/images/blog/blogBg.avif"
|
||||
/>
|
||||
|
||||
<BlogCategories categories={categories} activeCategory={categoryName} currentPage={currentPage} />
|
||||
|
||||
<section class="blog-grid-section">
|
||||
<div class="site-container">
|
||||
<div class="blog-grid" id="blog-grid">
|
||||
{posts.length > 0 ? (
|
||||
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}
|
||||
readmeTime={post.readmeTime}
|
||||
image={getPostImageUrl(post)}
|
||||
slug={`/blog/${post.slug}`}
|
||||
/>
|
||||
</article>
|
||||
))
|
||||
) : (
|
||||
<div class="no-results">
|
||||
<p>Статьи по теме "{categoryName}" не найдены</p>
|
||||
<a href="/blog" class="back-link">Вернуться к списку статей</a>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{totalPages > 1 && (
|
||||
<Pagination
|
||||
currentPage={currentPage}
|
||||
totalPages={totalPages}
|
||||
baseUrl={`/blog/category/${categorySlug}`}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<SearchModal />
|
||||
</Layout>
|
||||
|
||||
<style>
|
||||
.blog-grid-section {
|
||||
padding: 3rem 0;
|
||||
background: #f8fafc;
|
||||
}
|
||||
|
||||
.blog-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 2rem;
|
||||
}
|
||||
|
||||
.no-results {
|
||||
grid-column: 1 / -1;
|
||||
text-align: center;
|
||||
padding: 4rem 0;
|
||||
color: #64748b;
|
||||
}
|
||||
|
||||
.back-link {
|
||||
display: inline-block;
|
||||
margin-top: 1rem;
|
||||
color: #d4af37;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
}
|
||||
</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);
|
||||
});
|
||||
};
|
||||
|
||||
setupAnimations();
|
||||
document.addEventListener('astro:page-load', setupAnimations);
|
||||
</script>
|
||||
|
|
@ -183,7 +183,7 @@ const formatDate = (date: string) => {
|
|||
|
||||
setupAnimations();
|
||||
setupFilter();
|
||||
document.addEventListener('astro:after-swap', () => {
|
||||
document.addEventListener('astro:page-load', () => {
|
||||
setupAnimations();
|
||||
setupFilter();
|
||||
});
|
||||
|
|
|
|||
|
|
@ -149,5 +149,5 @@ const formatDate = (date: string) => {
|
|||
};
|
||||
|
||||
setupAnimations();
|
||||
document.addEventListener('astro:after-swap', setupAnimations);
|
||||
document.addEventListener('astro:page-load', setupAnimations);
|
||||
</script>
|
||||
|
|
@ -346,7 +346,7 @@ const isAuthorized = false; // Измените на true, чтобы увиде
|
|||
setupForm();
|
||||
|
||||
// Для поддержки Astro transitions
|
||||
document.addEventListener('astro:after-swap', () => {
|
||||
document.addEventListener('astro:page-load', () => {
|
||||
setupAnimations();
|
||||
setupForm();
|
||||
});
|
||||
|
|
|
|||
|
|
@ -182,7 +182,7 @@ const categories = getCategories();
|
|||
|
||||
setupFilter();
|
||||
|
||||
document.addEventListener('astro:after-swap', () => {
|
||||
document.addEventListener('astro:page-load', () => {
|
||||
setupFilter();
|
||||
});
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -197,7 +197,7 @@ import ReviewsList from '@components/reviews/ReviewsList.astro';
|
|||
setupAnimations();
|
||||
|
||||
// Для поддержки View Transitions в Astro
|
||||
document.addEventListener('astro:after-swap', () => {
|
||||
document.addEventListener('astro:page-load', () => {
|
||||
setupAnimations();
|
||||
});
|
||||
</script>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue