add templates

This commit is contained in:
Profile Profile
2025-12-15 17:01:51 +03:00
parent 11e2a99646
commit a72d47f6d9
13 changed files with 749 additions and 353 deletions

26
src/pages/[...slug].astro Normal file
View File

@@ -0,0 +1,26 @@
---
import { fetchCategory } from '@api/categories';
import MainLayout from '@layouts/MainLayout.astro';
import CategoryArchive from '@templates/CategoryArchive.astro';
import { getCategory } from '@api/categories';
import { getArchivePostsById } from '@api/archiveById';
export const prerender = false; // ISR
//export const revalidate = 60;
const { slug } = Astro.params;
const pathArray = Array.isArray(slug) ? slug : [slug];
// Получаем категорию по цепочке slug
const category = await getCategory(pathArray);
if (!category) return Astro.redirect('/404');
const perPage = 20;
---
<MainLayout title={category.name}>
<h1>{category.name}</h1>
</MainLayout>

View File

View File

@@ -1,109 +0,0 @@
---
import { getProfileArticleById } from '@api/posts.js';
import MainLayout from '@layouts/MainLayout.astro';
export const prerender = false; // динамический роутинг
const { category, slug } = Astro.params;
// ищем ID поста
function findPostId(slug) {
const lastItem = Array.isArray(slug) ? slug[slug.length - 1] : slug;
// Находим последний дефис
const dashIndex = lastItem.lastIndexOf('-');
if (dashIndex === -1) return null;
// Берем всё после дефиса
const idStr = lastItem.substring(dashIndex + 1);
// Преобразуем в число
const id = Number(idStr);
return Number.isInteger(id) ? id : null;
}
const postId = findPostId(slug);
let article;
try {
article = await getProfileArticleById(postId);
} catch (error) {
return Astro.redirect('/404');
}
if (!article) {
return Astro.redirect('/404');
}
// Валидация: проверяем категорию
const articleCategory = article.categories?.nodes?.[0]?.slug;
// Если категория не совпадает, делаем редирект
if (articleCategory && category !== articleCategory) {
debugLog(`Редирект: категория не совпадает (${category} != ${articleCategory})`);
// Строим правильный URL
const correctUri = article.uri
.replace(/^\//, '')
.replace(/\/$/, '');
return Astro.redirect(`/${correctUri}/`, 301);
}
// Валидация: проверяем полный путь
const currentPath = `${category}/${Array.isArray(slug) ? slug.join('/') : slug}`;
const correctPath = article.uri
.replace(/^\//, '')
.replace(/\/$/, '');
if (currentPath !== correctPath) {
debugLog(`Редирект: путь не совпадает (${currentPath} != ${correctPath})`);
return Astro.redirect(`/${correctPath}/`, 301);
}
---
<MainLayout
title={article.title}
description="Информационное агентство Деловой журнал Профиль"
>
<h1 class="article-title">{article.title}</h1>
{article.tags?.nodes?.length > 0 && (
<div class="tags-list">
<strong>Метки:</strong>
{article.tags.nodes.map(tag => (
<a href={tag.uri} class="tag" key={tag.id}>{tag.name}</a>
))}
</div>
)}
{article.featuredImage?.node?.sourceUrl && (
<figure class="featured-image">
<img
src={article.featuredImage.node.sourceUrl}
alt={article.featuredImage.node.altText || article.title}
loading="eager"
class="article-image"
/>
{article.featuredImage.node.caption && (
<figcaption class="image-caption" set:html={article.featuredImage.node.caption} />
)}
</figure>
)}
<div class="article-content" set:html={article.content} />
</MainLayout>

View File

@@ -10,9 +10,10 @@ import MainLayout from '@layouts/MainLayout.astro';
import ContentGrid from '@components/ContentGrid.astro';
import EndnewsList from '@components/EndnewsList.astro';
//export const prerender = {
// isr: { expiration: 3 } // ISR: обновлять раз в 3 секунды
//};
//ISR
export const prerender = false;
//export const revalidate = 1;
---
<MainLayout

View File

@@ -1,148 +0,0 @@
---
import { slugParse } from '@utils/slugParser';
import SimplePagination from '@components/Pagination.astro';
//api
import { getTag, getTagWithPostsById } from '@api/tags.js';
import { getArchivePostsById } from '@api/archiveById.ts';
import MainLayout from '@layouts/MainLayout.astro';
export const prerender = false; // динамический роутинг
const { slug } = Astro.params;
// Используем функцию (правильное название)
const { slug: tagSlug, page: currentPage } = slugParse(slug);
// Если slug пустой - 404
if (!tagSlug) {
return Astro.redirect('/404');
}
// Получаем данные тега
const tag = await getTag(tagSlug);
if (!tag) {
return Astro.redirect('/404');
}
const { posts, pageInfo } = await getArchivePostsById({
type: 'tag',
id: tag.databaseId, // ID тега
page: 2,
perPage: 10
});
console.log('Данные, полученные от pageInfo:', pageInfo);
---
<MainLayout
title='Тег'
description="Информационное агентство Деловой журнал Профиль"
>
<div class="container mx-auto px-4 py-8">
<!-- Заголовок тега -->
<header class="mb-8">
<h1 class="text-3xl md:text-4xl font-bold mb-2">
Тег: {tag.name}
</h1>
{tag.description && (
<div class="text-lg text-gray-600 mb-4" set:html={tag.description} />
)}
<div class="text-gray-500">
<span>Всего постов: {data.pagination?.totalPosts || 0}</span>
</div>
</header>
<!-- Список постов -->
{data.posts && data.posts.length > 0 ? (
<>
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 mb-8">
{data.posts.map(post => (
<article class="bg-white rounded-lg shadow-md overflow-hidden hover:shadow-lg transition-shadow duration-300">
{post.featuredImage?.node?.sourceUrl && (
<a href={post.uri} class="block">
<img
src={post.featuredImage.node.sourceUrl}
alt={post.featuredImage.node.altText || post.title}
width="400"
height="250"
loading="lazy"
class="w-full h-48 object-cover"
/>
</a>
)}
<div class="p-4">
<h2 class="text-xl font-semibold mb-2">
<a href={post.uri} class="hover:text-blue-600 transition-colors">
{post.title}
</a>
</h2>
{post.excerpt && (
<div
class="text-gray-600 mb-3 line-clamp-3"
set:html={post.excerpt}
/>
)}
<div class="flex items-center justify-between text-sm text-gray-500">
<time datetime={post.date}>
{new Date(post.date).toLocaleDateString('ru-RU')}
</time>
{post.categories?.nodes?.length > 0 && (
<div class="flex gap-1">
{post.categories.nodes.slice(0, 2).map(cat => (
<a
href={`/category/${cat.slug}`}
class="px-2 py-1 bg-gray-100 rounded hover:bg-gray-200"
>
{cat.name}
</a>
))}
</div>
)}
</div>
</div>
</article>
))}
</div>
<!-- Пагинация -->
{data.pagination && data.pagination.totalPages > 1 && (
<SimplePagination
currentPage={pageNumber}
totalPages={data.pagination.totalPages}
baseUrl={baseUrl}
showPrevNext={true}
showFirstLast={true}
maxVisible={7}
className="mt-8"
/>
)}
</>
) : (
<div class="text-center py-12">
<h3 class="text-2xl font-semibold mb-4">Постов пока нет</h3>
<p class="text-gray-600">В этом теге еще нет опубликованных статей.</p>
</div>
)}
</div>
</MainLayout>
</MainLayout>

View File

@@ -0,0 +1,68 @@
---
import { slugParse } from '@utils/slugParser';
//api
import { getTag, getTagWithPostsById } from '@api/tags.js';
import { getArchivePostsById } from '@/lib/api/archiveById';
import MainLayout from '@layouts/MainLayout.astro';
import TagArchive from '@/templates/TagArchive.astro';
//ISR
export const prerender = false;
const { slug } = Astro.params;
// Используем функцию (правильное название)
const { slug: tagSlug, page: currentPage } = slugParse(slug);
// Если slug пустой - 404
if (!tagSlug) {
return Astro.redirect('/404');
}
// Получаем данные тега
const tag = await getTag(tagSlug);
if (!tag) {
return Astro.redirect('/404');
}
// ----------------------------
// fetch archive
// ----------------------------
const perPage = 35;
const { posts, pageInfo } = await getArchivePostsById({
type: 'tag',
id: tag.databaseId,
page: currentPage,
perPage,
});
// 404 если страница невалидна
if (!posts.length && currentPage > 1) {
return Astro.redirect('/404');
}
---
<MainLayout
title='Тег'
description="Информационное агентство Деловой журнал Профиль"
>
<TagArchive
tag={tag}
posts={posts}
page={1}
hasNextPage={pageInfo.hasNextPage}
baseUrl={`/tag/${slug}`}
/>
</MainLayout>