add tags logic
This commit is contained in:
@@ -15,8 +15,8 @@
|
|||||||
<div class="top-bar">
|
<div class="top-bar">
|
||||||
<img alt="Профиль" width="249" height="55" src="https://cdn.profile.ru/wp-content/themes/profile/assets/img/profile-logo-delovoy.svg">
|
<img alt="Профиль" width="249" height="55" src="https://cdn.profile.ru/wp-content/themes/profile/assets/img/profile-logo-delovoy.svg">
|
||||||
{category && (
|
{category && (
|
||||||
<div class="parttile-block">
|
<div class="header__subtitle">
|
||||||
{category.name}
|
<a href={`/${category.slug}`}>{category.name}</a>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<Stores />
|
<Stores />
|
||||||
@@ -32,6 +32,25 @@
|
|||||||
.top-bar{
|
.top-bar{
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header__subtitle{
|
||||||
|
font-size: 22px;
|
||||||
|
font-weight: bold;
|
||||||
|
margin-left: 42px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header__subtitle::before{
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: -15px;
|
||||||
|
width: 3px;
|
||||||
|
height: 80%;
|
||||||
|
border-left: 3px solid;
|
||||||
|
transform: translate(0, -40%);
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
@@ -29,8 +29,7 @@ const { post, pageInfo } = Astro.props;
|
|||||||
<div class="publication__author">
|
<div class="publication__author">
|
||||||
<Author post={post} separator=", " />
|
<Author post={post} separator=", " />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<h1>{post.title}</h1>
|
<h1>{post.title}</h1>
|
||||||
{post.secondaryTitle && <h2 class="secondary-title">{post.secondaryTitle}</h2>}
|
{post.secondaryTitle && <h2 class="secondary-title">{post.secondaryTitle}</h2>}
|
||||||
@@ -58,21 +57,37 @@ const { post, pageInfo } = Astro.props;
|
|||||||
</figure>
|
</figure>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|
||||||
{post.content && <div set:html={post.content} />}
|
{post.content && <div set:html={post.content} />}
|
||||||
|
|
||||||
<Subscribe />
|
<Subscribe />
|
||||||
</article>
|
</article>
|
||||||
|
|
||||||
<ShareButtons url={post.uri} title={post.title} />
|
<ShareButtons url={post.uri} title={post.title} />
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div>Новость не найдена</div>
|
<div>Новость не найдена</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<style>
|
{/* Блок с тегами */}
|
||||||
|
{post.tags?.nodes && post.tags.nodes.length > 0 && (
|
||||||
|
<div class="tags-block">
|
||||||
|
<span class="tags-label">Теги:</span>
|
||||||
|
<div class="tags-list">
|
||||||
|
{post.tags.nodes.map((tag) => (
|
||||||
|
<a
|
||||||
|
href={`/tag/${encodeURIComponent(tag.name.replace(/\s+/g, '+'))}/`}
|
||||||
|
class="tag-link"
|
||||||
|
key={tag.id}
|
||||||
|
>
|
||||||
|
{tag.name}
|
||||||
|
</a>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<style>
|
||||||
.article-wrapper {
|
.article-wrapper {
|
||||||
position: relative;
|
position: relative;
|
||||||
max-width: 75%;
|
max-width: 75%;
|
||||||
@@ -95,11 +110,10 @@ const { post, pageInfo } = Astro.props;
|
|||||||
color: #0d6efd;
|
color: #0d6efd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.article_info {
|
.article_info {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: .475rem; /* одинаковое расстояние с обеих сторон от черты */
|
gap: .475rem;
|
||||||
margin-top: 1.9375rem;
|
margin-top: 1.9375rem;
|
||||||
margin-bottom: .9375rem;
|
margin-bottom: .9375rem;
|
||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
@@ -118,8 +132,45 @@ const { post, pageInfo } = Astro.props;
|
|||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Стили для блока тегов */
|
||||||
|
.tags-block {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.75rem;
|
||||||
|
margin: 1.5rem 0;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tags-label {
|
||||||
|
font-size: 0.875rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tags-list {
|
||||||
|
display: flex;
|
||||||
|
gap: 0.5rem;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tag-link {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 0.25rem 0.75rem;
|
||||||
|
font-size: 0.8125rem;
|
||||||
|
line-height: 1.5;
|
||||||
|
color: #666;
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
border: 1px solid #e0e0e0;
|
||||||
|
border-radius: 4px;
|
||||||
|
text-decoration: none;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tag-link:hover {
|
||||||
|
color: #fff;
|
||||||
|
background-color: #0d6efd;
|
||||||
|
border-color: #0d6efd;
|
||||||
|
}
|
||||||
|
|
||||||
.featured-image {
|
.featured-image {
|
||||||
margin: 1.5rem 0;
|
margin: 1.5rem 0;
|
||||||
|
|||||||
@@ -114,13 +114,15 @@ export async function getPostsByCategory(slug, first = 14, after = null) {
|
|||||||
cacheKey,
|
cacheKey,
|
||||||
async () => {
|
async () => {
|
||||||
const query = `
|
const query = `
|
||||||
query GetPostsByCategory($first: Int!, $after: String, $slug: String!) {
|
query GetPostsByCategory($first: Int!, $after: String, $slug: ID!) {
|
||||||
profileArticles(
|
category(id: $slug, idType: SLUG) {
|
||||||
|
name
|
||||||
|
contentNodes(
|
||||||
first: $first
|
first: $first
|
||||||
after: $after
|
after: $after
|
||||||
where: {
|
where: {
|
||||||
|
contentTypes: [PROFILE_ARTICLE, ANEW]
|
||||||
orderby: { field: DATE, order: DESC }
|
orderby: { field: DATE, order: DESC }
|
||||||
categoryName: $slug
|
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
pageInfo {
|
pageInfo {
|
||||||
@@ -130,46 +132,77 @@ export async function getPostsByCategory(slug, first = 14, after = null) {
|
|||||||
edges {
|
edges {
|
||||||
cursor
|
cursor
|
||||||
node {
|
node {
|
||||||
|
__typename
|
||||||
id
|
id
|
||||||
databaseId
|
databaseId
|
||||||
title
|
|
||||||
uri
|
uri
|
||||||
date
|
date
|
||||||
|
|
||||||
|
... on NodeWithTitle {
|
||||||
|
title
|
||||||
|
}
|
||||||
|
|
||||||
|
... on NodeWithFeaturedImage {
|
||||||
featuredImage {
|
featuredImage {
|
||||||
node {
|
node {
|
||||||
sourceUrl(size: LARGE)
|
sourceUrl(size: LARGE)
|
||||||
altText
|
altText
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Для ваших кастомных типов
|
||||||
|
... on ProfileArticle {
|
||||||
|
categories {
|
||||||
|
nodes {
|
||||||
|
name
|
||||||
|
slug
|
||||||
|
color
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
... on ANew {
|
||||||
|
categories {
|
||||||
|
nodes {
|
||||||
|
name
|
||||||
|
slug
|
||||||
|
color
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
... on NodeWithAuthor {
|
||||||
author {
|
author {
|
||||||
node {
|
node {
|
||||||
id
|
|
||||||
name
|
name
|
||||||
firstName
|
|
||||||
lastName
|
|
||||||
avatar {
|
avatar {
|
||||||
url
|
url
|
||||||
}
|
}
|
||||||
uri
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
# Соавторы как массив
|
}
|
||||||
|
|
||||||
|
# Coauthors для ProfileArticle (без description)
|
||||||
|
... on ProfileArticle {
|
||||||
coauthors {
|
coauthors {
|
||||||
id
|
id
|
||||||
name
|
name
|
||||||
firstName
|
firstName
|
||||||
lastName
|
lastName
|
||||||
url
|
url
|
||||||
description
|
|
||||||
}
|
}
|
||||||
categories {
|
}
|
||||||
nodes {
|
|
||||||
|
# Coauthors для ANew (без description)
|
||||||
|
... on ANew {
|
||||||
|
coauthors {
|
||||||
id
|
id
|
||||||
name
|
name
|
||||||
color
|
firstName
|
||||||
slug
|
lastName
|
||||||
uri
|
url
|
||||||
databaseId
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -180,11 +213,31 @@ export async function getPostsByCategory(slug, first = 14, after = null) {
|
|||||||
|
|
||||||
const data = await fetchGraphQL(query, { first, after, slug });
|
const data = await fetchGraphQL(query, { first, after, slug });
|
||||||
|
|
||||||
const posts = data.profileArticles?.edges?.map(edge => edge.node) || [];
|
// Обрабатываем посты
|
||||||
|
const posts = data.category?.contentNodes?.edges?.map(edge => {
|
||||||
|
const node = edge.node;
|
||||||
|
|
||||||
|
// Приводим coauthors к единому формату (если нужно)
|
||||||
|
if (node.coauthors) {
|
||||||
|
node.coauthors = node.coauthors.map(author => ({
|
||||||
|
id: author.id,
|
||||||
|
name: author.name || '',
|
||||||
|
firstName: author.firstName || '',
|
||||||
|
lastName: author.lastName || '',
|
||||||
|
url: author.url || ''
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}) || [];
|
||||||
|
|
||||||
return {
|
return {
|
||||||
posts,
|
posts,
|
||||||
pageInfo: data.profileArticles?.pageInfo || { hasNextPage: false, endCursor: null }
|
pageInfo: data.category?.contentNodes?.pageInfo || {
|
||||||
|
hasNextPage: false,
|
||||||
|
endCursor: null
|
||||||
|
},
|
||||||
|
categoryName: data.category?.name || ''
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
{ ttl: CACHE_TTL.POSTS }
|
{ ttl: CACHE_TTL.POSTS }
|
||||||
@@ -192,6 +245,156 @@ export async function getPostsByCategory(slug, first = 14, after = null) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export async function getPostsByTag(slug, first = 14, after = null) {
|
||||||
|
// Создаем уникальный ключ для кэша
|
||||||
|
const cacheKey = `tag-posts:${slug}:${first}:${after || 'first-page'}`;
|
||||||
|
|
||||||
|
return await cache.wrap(
|
||||||
|
cacheKey,
|
||||||
|
async () => {
|
||||||
|
const query = `
|
||||||
|
query GetPostsByTag($first: Int!, $after: String, $slug: ID!) {
|
||||||
|
tag(id: $slug, idType: NAME) {
|
||||||
|
id
|
||||||
|
databaseId
|
||||||
|
name
|
||||||
|
slug
|
||||||
|
count
|
||||||
|
description
|
||||||
|
|
||||||
|
contentNodes(
|
||||||
|
first: $first
|
||||||
|
after: $after
|
||||||
|
where: {
|
||||||
|
contentTypes: [PROFILE_ARTICLE, ANEW]
|
||||||
|
orderby: { field: DATE, order: DESC }
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
pageInfo {
|
||||||
|
hasNextPage
|
||||||
|
endCursor
|
||||||
|
}
|
||||||
|
edges {
|
||||||
|
cursor
|
||||||
|
node {
|
||||||
|
__typename
|
||||||
|
id
|
||||||
|
databaseId
|
||||||
|
uri
|
||||||
|
date
|
||||||
|
|
||||||
|
... on NodeWithTitle {
|
||||||
|
title
|
||||||
|
}
|
||||||
|
|
||||||
|
... on NodeWithFeaturedImage {
|
||||||
|
featuredImage {
|
||||||
|
node {
|
||||||
|
sourceUrl(size: LARGE)
|
||||||
|
altText
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
... on NodeWithAuthor {
|
||||||
|
author {
|
||||||
|
node {
|
||||||
|
name
|
||||||
|
avatar {
|
||||||
|
url
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
... on ProfileArticle {
|
||||||
|
categories {
|
||||||
|
nodes {
|
||||||
|
name
|
||||||
|
slug
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
... on ANew {
|
||||||
|
categories {
|
||||||
|
nodes {
|
||||||
|
name
|
||||||
|
slug
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
... on ProfileArticle {
|
||||||
|
coauthors {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
... on ANew {
|
||||||
|
coauthors {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
console.log('Fetching with:', { first, after, slug }); // Добавим лог параметров
|
||||||
|
|
||||||
|
const data = await fetchGraphQL(query, { first, after, slug });
|
||||||
|
|
||||||
|
|
||||||
|
// Проверяем структуру data
|
||||||
|
if (!data?.tag) {
|
||||||
|
console.log('Tag not found');
|
||||||
|
return {
|
||||||
|
posts: [],
|
||||||
|
pageInfo: { hasNextPage: false, endCursor: null },
|
||||||
|
tagName: slug,
|
||||||
|
tagSlug: slug,
|
||||||
|
tagCount: 0,
|
||||||
|
tagDescription: ''
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Обрабатываем посты
|
||||||
|
const posts = data.tag?.contentNodes?.edges?.map(edge => {
|
||||||
|
const node = edge.node;
|
||||||
|
|
||||||
|
// Приводим данные к единому формату
|
||||||
|
return {
|
||||||
|
...node,
|
||||||
|
// Убеждаемся, что coauthors всегда массив
|
||||||
|
coauthors: node.coauthors || [],
|
||||||
|
// Убеждаемся, что categories всегда есть
|
||||||
|
categories: node.categories || { nodes: [] }
|
||||||
|
};
|
||||||
|
}) || [];
|
||||||
|
|
||||||
|
return {
|
||||||
|
posts,
|
||||||
|
pageInfo: data.tag?.contentNodes?.pageInfo || {
|
||||||
|
hasNextPage: false,
|
||||||
|
endCursor: null
|
||||||
|
},
|
||||||
|
tagName: data.tag?.name || slug,
|
||||||
|
tagSlug: data.tag?.slug || slug,
|
||||||
|
tagCount: data.tag?.count || 0,
|
||||||
|
tagDescription: data.tag?.description || ''
|
||||||
|
};
|
||||||
|
},
|
||||||
|
{ ttl: CACHE_TTL.POSTS }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import { detectPageType } from '@lib/detect-page-type';
|
|||||||
|
|
||||||
export const prerender = false;
|
export const prerender = false;
|
||||||
|
|
||||||
const pathname = Astro.url.pathname; // "/news/society/chto-sluchilos-nochju-27-oktyabrya-2025-goda-1772178/"
|
const pathname = Astro.url.pathname;
|
||||||
const pageInfo = detectPageType(pathname); //определяем тип страницы
|
const pageInfo = detectPageType(pathname); //определяем тип страницы
|
||||||
|
|
||||||
|
|
||||||
@@ -37,7 +37,7 @@ if (pageInfo.type === 'single') { //одиночная статья
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
article = await getProfileArticleById(pageInfo.postId); //получвем данные поста
|
article = await getProfileArticleById(pageInfo.postId); //получвем данные поста
|
||||||
title=article.titleж
|
title=article.title
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error fetching node:', error);
|
console.error('Error fetching node:', error);
|
||||||
}
|
}
|
||||||
@@ -64,6 +64,12 @@ if (pageInfo.type === 'single') { //одиночная статья
|
|||||||
category={category}
|
category={category}
|
||||||
>
|
>
|
||||||
|
|
||||||
|
{/* Page (страница) */}
|
||||||
|
{pageInfo.type === 'unknown' && (
|
||||||
|
<div>✅ Это страница: {pageInfo.pageSlug}</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
|
||||||
{/* Single post */}
|
{/* Single post */}
|
||||||
{pageInfo.type === 'single' && article && (
|
{pageInfo.type === 'single' && article && (
|
||||||
<NewsSingle post={article} pageInfo={pageInfo} />
|
<NewsSingle post={article} pageInfo={pageInfo} />
|
||||||
|
|||||||
74
src/pages/author/[slug]/[page].astro
Normal file
74
src/pages/author/[slug]/[page].astro
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
---
|
||||||
|
// pages/author/[slug]/[page].astro
|
||||||
|
import { wpClient } from '@lib/wp-client';
|
||||||
|
import MainLayout from '@layouts/MainLayout.astro';
|
||||||
|
|
||||||
|
export const prerender = false;
|
||||||
|
|
||||||
|
const { slug, page } = Astro.params;
|
||||||
|
|
||||||
|
// Преобразуем номер страницы в cursor
|
||||||
|
// Для страницы 1: cursor = 0
|
||||||
|
// Для страницы 2: нужно знать ID последнего поста с первой страницы
|
||||||
|
// Это сложнее для cursor-based пагинации, поэтому либо:
|
||||||
|
// Вариант 1: Используем номер страницы как offset (нужно изменить эндпоинт)
|
||||||
|
// Вариант 2: Делаем отдельный запрос для получения cursor по номеру страницы
|
||||||
|
|
||||||
|
const currentPage = parseInt(page) || 1;
|
||||||
|
let cursor = 0;
|
||||||
|
|
||||||
|
// Если страница > 1, нам нужно получить cursor для этой страницы
|
||||||
|
// Для простоты пока используем номер страницы как offset в URL
|
||||||
|
// или модифицируем эндпоинт для поддержки page
|
||||||
|
|
||||||
|
// Временное решение: используем cursor = (page - 1) * limit
|
||||||
|
// Но это не точно, лучше модифицировать эндпоинт
|
||||||
|
const limit = 10;
|
||||||
|
const estimatedCursor = (currentPage - 1) * limit;
|
||||||
|
|
||||||
|
const data = await wpClient.get(`my/v1/author-posts/${slug}`, {
|
||||||
|
cursor: currentPage === 1 ? 0 : estimatedCursor,
|
||||||
|
limit
|
||||||
|
});
|
||||||
|
|
||||||
|
//if (!data) {
|
||||||
|
// return Astro.redirect('/404');
|
||||||
|
//}
|
||||||
|
|
||||||
|
const { author, posts, pagination } = data;
|
||||||
|
---
|
||||||
|
|
||||||
|
<MainLayout>
|
||||||
|
<div class="author-header">
|
||||||
|
<h1>{author.name}</h1>
|
||||||
|
<p>Статьи автора</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="posts-list">
|
||||||
|
{posts.map(post => (
|
||||||
|
<article key={post.id} class="post-item">
|
||||||
|
<h2>
|
||||||
|
<a href={`/posts/${post.slug}`}>{post.title}</a>
|
||||||
|
</h2>
|
||||||
|
<time datetime={post.date}>
|
||||||
|
{new Date(post.date).toLocaleDateString('ru-RU')}
|
||||||
|
</time>
|
||||||
|
<div class="post-meta">
|
||||||
|
<span class="cursor-info">ID: {post.id}</span>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{pagination.has_more && (
|
||||||
|
<div class="load-more">
|
||||||
|
<button
|
||||||
|
hx-get={`/author/${slug}/page/${currentPage + 1}`}
|
||||||
|
hx-target=".posts-list"
|
||||||
|
hx-swap="beforeend"
|
||||||
|
>
|
||||||
|
Загрузить еще
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</MainLayout>
|
||||||
56
src/pages/author/[slug]/index.astro
Normal file
56
src/pages/author/[slug]/index.astro
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
---
|
||||||
|
// pages/author/[slug]/index.astro
|
||||||
|
import { wpClient } from '@lib/wp-client';
|
||||||
|
|
||||||
|
export const prerender = false;
|
||||||
|
|
||||||
|
const { slug } = Astro.params;
|
||||||
|
|
||||||
|
// Функция для получения данных автора
|
||||||
|
async function getAuthorData(authorSlug) {
|
||||||
|
try {
|
||||||
|
// Используем ваш кастомный эндпоинт или стандартный WP endpoint
|
||||||
|
const data = await wpClient.get(`my/v1/author-posts/${authorSlug}/1`);
|
||||||
|
|
||||||
|
if (!data) {
|
||||||
|
// Если кастомный эндпоинт не работает, пробуем стандартный
|
||||||
|
const users = await wpClient.get('wp/v2/users', { slug: authorSlug });
|
||||||
|
if (users && users.length > 0) {
|
||||||
|
return { author: users[0], posts: [] };
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error fetching author:', error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const authorData = await getAuthorData(slug);
|
||||||
|
|
||||||
|
// Если автор не найден - 404
|
||||||
|
//if (!authorData) {
|
||||||
|
// return Astro.redirect('/404');
|
||||||
|
//}
|
||||||
|
|
||||||
|
const { author, posts } = authorData;
|
||||||
|
---
|
||||||
|
|
||||||
|
<h1>Author: {author.name || slug}</h1>
|
||||||
|
|
||||||
|
{posts && posts.length > 0 ? (
|
||||||
|
<div>
|
||||||
|
<h2>Статьи автора:</h2>
|
||||||
|
<ul>
|
||||||
|
{posts.map(post => (
|
||||||
|
<li key={post.id}>
|
||||||
|
<a href={post.link}>{post.title}</a>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<p>У автора пока нет статей</p>
|
||||||
|
)}
|
||||||
@@ -26,7 +26,7 @@ console.log('📥 Load more request:', { perLoad, after, type, slug, startIndex
|
|||||||
|
|
||||||
|
|
||||||
// Импортируем функции для получения данных
|
// Импортируем функции для получения данных
|
||||||
const { getLatestPosts, getPostsByCategory, getAuthorPosts, getTagPosts } =
|
const { getLatestPosts, getPostsByCategory, getAuthorPosts, getPostsByTag } =
|
||||||
await import('../lib/api/posts');
|
await import('../lib/api/posts');
|
||||||
|
|
||||||
let result;
|
let result;
|
||||||
@@ -43,7 +43,7 @@ switch (type) {
|
|||||||
break;
|
break;
|
||||||
case 'tag':
|
case 'tag':
|
||||||
if (!slug) throw new Error('Slug required for tag');
|
if (!slug) throw new Error('Slug required for tag');
|
||||||
result = await getTagPosts(slug, perLoad, after); // Используем perLoad
|
result = await getPostsByTag(slug, perLoad, after); // Используем perLoad
|
||||||
break;
|
break;
|
||||||
case 'latest':
|
case 'latest':
|
||||||
default:
|
default:
|
||||||
|
|||||||
0
src/pages/tag/[slug]/[page].astro
Normal file
0
src/pages/tag/[slug]/[page].astro
Normal file
68
src/pages/tag/[slug]/___index.astro
Normal file
68
src/pages/tag/[slug]/___index.astro
Normal 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>
|
||||||
@@ -1,68 +1,38 @@
|
|||||||
---
|
---
|
||||||
|
|
||||||
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 MainLayout from '@layouts/MainLayout.astro';
|
||||||
import TagArchive from '@/templates/TagArchive.astro';
|
import ContentGrid from '@components/ContentGrid.astro';
|
||||||
|
|
||||||
|
import { getPostsByTag } from '@lib/api/posts';
|
||||||
|
|
||||||
//ISR
|
|
||||||
export const prerender = false;
|
export const prerender = false;
|
||||||
|
|
||||||
const { slug } = Astro.params;
|
const { slug } = Astro.params;
|
||||||
|
|
||||||
// Используем функцию (правильное название)
|
// Декодируем URL и преобразуем в формат для WP
|
||||||
const { slug: tagSlug, page: currentPage } = slugParse(slug);
|
const decodedSlug = slug ? decodeURIComponent(slug.replace(/\+/g, ' ')) : '';
|
||||||
|
|
||||||
// Если slug пустой - 404
|
// Получаем данные по тегу
|
||||||
if (!tagSlug) {
|
const result = await getPostsByTag(decodedSlug);
|
||||||
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');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
const posts = result?.posts || [];
|
||||||
|
const pageInfo = result?.pageInfo || {};
|
||||||
|
const tagName = result?.tagName || slug;
|
||||||
|
const hasNextPage = pageInfo?.hasNextPage || false;
|
||||||
|
const endCursor = pageInfo?.endCursor || null;
|
||||||
---
|
---
|
||||||
|
|
||||||
<MainLayout
|
<MainLayout
|
||||||
title='Тег'
|
title={`Записи по тегу: ${tagName}`}
|
||||||
description="Информационное агентство Деловой журнал Профиль"
|
description={`Информационное агентство Деловой журнал Профиль - записи по тегу ${tagName}`}
|
||||||
>
|
>
|
||||||
|
<h1>#{decodedSlug}</h1>
|
||||||
<TagArchive
|
<ContentGrid
|
||||||
tag={tag}
|
items={posts}
|
||||||
posts={posts}
|
pageInfo={pageInfo}
|
||||||
page={1}
|
slug={slug}
|
||||||
hasNextPage={pageInfo.hasNextPage}
|
showCount={false}
|
||||||
baseUrl={`/tag/${slug}`}
|
type='tag'
|
||||||
|
perLoad={11}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</MainLayout>
|
</MainLayout>
|
||||||
|
|
||||||
@@ -10,7 +10,7 @@ html{
|
|||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
|
font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans","Liberation Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user