add endpoint authors
This commit is contained in:
@@ -23,19 +23,24 @@ const {
|
|||||||
perLoad = 11
|
perLoad = 11
|
||||||
} = Astro.props;
|
} = Astro.props;
|
||||||
|
|
||||||
// Используем perLoad везде
|
|
||||||
const loadMoreConfig = {
|
const loadMoreConfig = {
|
||||||
type,
|
type,
|
||||||
slug,
|
slug,
|
||||||
perLoad // Теперь используем perLoad вместо first
|
perLoad
|
||||||
};
|
};
|
||||||
|
|
||||||
function getCoauthorsNames(coauthors: any[]): string {
|
function getCoauthorsNames(coauthors: any[]): string {
|
||||||
if (!coauthors || coauthors.length === 0) return '';
|
if (!coauthors || coauthors.length === 0) return '';
|
||||||
|
|
||||||
return coauthors
|
return coauthors
|
||||||
.map((coauthor: any) => coauthor?.node?.name || coauthor?.name)
|
.map((coauthor: any) => {
|
||||||
|
const name = coauthor?.node?.name || coauthor?.name;
|
||||||
|
const nickname = coauthor?.node?.nickname || coauthor?.nickname;
|
||||||
|
|
||||||
|
return name; // Возвращаем только имя, ссылки будут в шаблоне
|
||||||
|
})
|
||||||
.filter(Boolean)
|
.filter(Boolean)
|
||||||
.join(' ');
|
.join(', ');
|
||||||
}
|
}
|
||||||
|
|
||||||
function shouldBeLarge(index: number): boolean {
|
function shouldBeLarge(index: number): boolean {
|
||||||
@@ -55,7 +60,6 @@ function shouldBeLarge(index: number): boolean {
|
|||||||
{items.map((item, index) => {
|
{items.map((item, index) => {
|
||||||
const postUrl = item.uri || `/blog/${item.databaseId}`;
|
const postUrl = item.uri || `/blog/${item.databaseId}`;
|
||||||
const postDate = new Date(item.date);
|
const postDate = new Date(item.date);
|
||||||
const coauthorsNames = getCoauthorsNames(item.coauthors || []);
|
|
||||||
const isLarge = shouldBeLarge(index);
|
const isLarge = shouldBeLarge(index);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -66,7 +70,6 @@ function shouldBeLarge(index: number): boolean {
|
|||||||
itemscope
|
itemscope
|
||||||
itemtype="https://schema.org/BlogPosting"
|
itemtype="https://schema.org/BlogPosting"
|
||||||
>
|
>
|
||||||
<a href={postUrl} class="post-card-link">
|
|
||||||
<div class="post-image-container">
|
<div class="post-image-container">
|
||||||
{item.featuredImage?.node?.sourceUrl ? (
|
{item.featuredImage?.node?.sourceUrl ? (
|
||||||
<img
|
<img
|
||||||
@@ -82,10 +85,18 @@ function shouldBeLarge(index: number): boolean {
|
|||||||
<div class="post-image-placeholder"></div>
|
<div class="post-image-placeholder"></div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{item.categories?.nodes?.[0] && (
|
||||||
|
<a
|
||||||
|
href={`/${item.categories.nodes[0].slug}`}
|
||||||
|
class="category-badge-link"
|
||||||
|
onClick={(e) => e.stopPropagation()}
|
||||||
|
>
|
||||||
<CategoryBadge
|
<CategoryBadge
|
||||||
name={item.categories?.nodes?.[0]?.name}
|
name={item.categories.nodes[0].name}
|
||||||
color={item.categories?.nodes?.[0]?.color}
|
color={item.categories.nodes[0].color}
|
||||||
/>
|
/>
|
||||||
|
</a>
|
||||||
|
)}
|
||||||
|
|
||||||
<div class="post-content-overlay">
|
<div class="post-content-overlay">
|
||||||
<div class="post-meta-overlay">
|
<div class="post-meta-overlay">
|
||||||
@@ -102,18 +113,40 @@ function shouldBeLarge(index: number): boolean {
|
|||||||
</time>
|
</time>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<a href={postUrl} class="post-title-link" itemprop="url">
|
||||||
<h3 class="post-title-overlay" itemprop="headline">
|
<h3 class="post-title-overlay" itemprop="headline">
|
||||||
{item.title}
|
{item.title}
|
||||||
</h3>
|
</h3>
|
||||||
|
</a>
|
||||||
|
|
||||||
{coauthorsNames && (
|
{item.coauthors && item.coauthors.length > 0 && (
|
||||||
<div class="author-name" itemprop="author">
|
<div class="coauthors-wrapper" itemprop="author">
|
||||||
{coauthorsNames}
|
{item.coauthors.map((coauthor: any, i: number) => {
|
||||||
|
const name = coauthor?.node?.name || coauthor?.name;
|
||||||
|
const nickname = coauthor?.node?.nickname || coauthor?.nickname;
|
||||||
|
console.log(nickname);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<span key={nickname || name}>
|
||||||
|
{i > 0 && ', '}
|
||||||
|
{nickname ? (
|
||||||
|
<a
|
||||||
|
href={`/author/${nickname}`}
|
||||||
|
class="author-link"
|
||||||
|
onClick={(e) => e.stopPropagation()}
|
||||||
|
>
|
||||||
|
{name}
|
||||||
|
</a>
|
||||||
|
) : (
|
||||||
|
<span class="author-name">{name}</span>
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
})}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</a>
|
|
||||||
|
|
||||||
<div class="sr-only">
|
<div class="sr-only">
|
||||||
<h3 itemprop="headline">
|
<h3 itemprop="headline">
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ const { post, pageInfo } = Astro.props;
|
|||||||
{/* Блок с тегами */}
|
{/* Блок с тегами */}
|
||||||
{post.tags?.nodes && post.tags.nodes.length > 0 && (
|
{post.tags?.nodes && post.tags.nodes.length > 0 && (
|
||||||
<div class="tags-block">
|
<div class="tags-block">
|
||||||
<span class="tags-label">Теги:</span>
|
<span class="tags-label">Метки:</span>
|
||||||
<div class="tags-list">
|
<div class="tags-list">
|
||||||
{post.tags.nodes.map((tag) => (
|
{post.tags.nodes.map((tag) => (
|
||||||
<a
|
<a
|
||||||
@@ -143,7 +143,7 @@ const { post, pageInfo } = Astro.props;
|
|||||||
|
|
||||||
.tags-label {
|
.tags-label {
|
||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
font-weight: 600;
|
font-weight: 500;
|
||||||
color: #333;
|
color: #333;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -158,18 +158,17 @@ const { post, pageInfo } = Astro.props;
|
|||||||
padding: 0.25rem 0.75rem;
|
padding: 0.25rem 0.75rem;
|
||||||
font-size: 0.8125rem;
|
font-size: 0.8125rem;
|
||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
color: #666;
|
color: black;
|
||||||
background-color: #f5f5f5;
|
font-weight: 700;
|
||||||
border: 1px solid #e0e0e0;
|
background-color: #ececec;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
transition: all 0.2s ease;
|
transition: all 0.2s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tag-link:hover {
|
.tag-link:hover {
|
||||||
color: #fff;
|
background-color: #d3d3d3;
|
||||||
background-color: #0d6efd;
|
border-color: #d3d3d3;
|
||||||
border-color: #0d6efd;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.featured-image {
|
.featured-image {
|
||||||
|
|||||||
370
src/lib/api/authors.ts
Normal file
370
src/lib/api/authors.ts
Normal file
@@ -0,0 +1,370 @@
|
|||||||
|
import { fetchGraphQL } from './graphql-client.js';
|
||||||
|
|
||||||
|
//кэширование
|
||||||
|
import { cache } from '@lib/cache/manager.js';
|
||||||
|
import { CACHE_TTL } from '@lib/cache/cache-ttl';
|
||||||
|
|
||||||
|
export async function getPostsByCoauthorName(coauthorName, first = 14, after = null) {
|
||||||
|
// Создаем уникальный ключ для кэша
|
||||||
|
const cacheKey = `coauthor-posts-known:${coauthorName}:${first}:${after || 'first-page'}`;
|
||||||
|
|
||||||
|
return await cache.wrap(
|
||||||
|
cacheKey,
|
||||||
|
async () => {
|
||||||
|
const query = `
|
||||||
|
query GetPostsByCoauthorName($first: Int!, $after: String, $coauthorName: String!) {
|
||||||
|
# Информация об авторе
|
||||||
|
users(where: {search: $coauthorName}) {
|
||||||
|
nodes {
|
||||||
|
databaseId
|
||||||
|
name
|
||||||
|
nicename
|
||||||
|
email
|
||||||
|
avatar {
|
||||||
|
url
|
||||||
|
}
|
||||||
|
description
|
||||||
|
posts {
|
||||||
|
pageInfo {
|
||||||
|
total
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Посты автора
|
||||||
|
contentNodes(
|
||||||
|
first: $first
|
||||||
|
after: $after
|
||||||
|
where: {
|
||||||
|
contentTypes: [PROFILE_ARTICLE, ANEW]
|
||||||
|
coauthorName: $coauthorName
|
||||||
|
orderby: { field: DATE, order: DESC }
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
pageInfo {
|
||||||
|
hasNextPage
|
||||||
|
endCursor
|
||||||
|
}
|
||||||
|
nodes {
|
||||||
|
__typename
|
||||||
|
id
|
||||||
|
databaseId
|
||||||
|
uri
|
||||||
|
date
|
||||||
|
|
||||||
|
... on NodeWithTitle {
|
||||||
|
title
|
||||||
|
}
|
||||||
|
|
||||||
|
... on NodeWithFeaturedImage {
|
||||||
|
featuredImage {
|
||||||
|
node {
|
||||||
|
sourceUrl(size: LARGE)
|
||||||
|
altText
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Для кастомных типов
|
||||||
|
... on ProfileArticle {
|
||||||
|
categories {
|
||||||
|
nodes {
|
||||||
|
name
|
||||||
|
slug
|
||||||
|
color
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
... on ANew {
|
||||||
|
categories {
|
||||||
|
nodes {
|
||||||
|
name
|
||||||
|
slug
|
||||||
|
color
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
... on NodeWithAuthor {
|
||||||
|
author {
|
||||||
|
node {
|
||||||
|
name
|
||||||
|
avatar {
|
||||||
|
url
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Coauthors для ProfileArticle
|
||||||
|
... on ProfileArticle {
|
||||||
|
coauthors {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
firstName
|
||||||
|
lastName
|
||||||
|
url
|
||||||
|
nicename
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Coauthors для ANew
|
||||||
|
... on ANew {
|
||||||
|
coauthors {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
firstName
|
||||||
|
lastName
|
||||||
|
url
|
||||||
|
nicename
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const data = await fetchGraphQL(query, {
|
||||||
|
first,
|
||||||
|
after,
|
||||||
|
coauthorName
|
||||||
|
});
|
||||||
|
|
||||||
|
// Находим автора (первый результат поиска)
|
||||||
|
const author = data.users?.nodes?.[0];
|
||||||
|
|
||||||
|
if (!author) {
|
||||||
|
return {
|
||||||
|
author: null,
|
||||||
|
posts: [],
|
||||||
|
pageInfo: { hasNextPage: false, endCursor: null },
|
||||||
|
totalPosts: 0
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Обрабатываем посты
|
||||||
|
const posts = data.contentNodes?.nodes?.map(node => {
|
||||||
|
// Приводим coauthors к единому формату
|
||||||
|
if (node.coauthors) {
|
||||||
|
node.coauthors = node.coauthors.map(coauthor => ({
|
||||||
|
id: coauthor.id,
|
||||||
|
nickname: coauthor.nickname,
|
||||||
|
name: coauthor.name || '',
|
||||||
|
firstName: coauthor.firstName || '',
|
||||||
|
lastName: coauthor.lastName || '',
|
||||||
|
url: coauthor.url || ''
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}) || [];
|
||||||
|
|
||||||
|
return {
|
||||||
|
author: {
|
||||||
|
id: author.databaseId,
|
||||||
|
name: author.name,
|
||||||
|
login: author.nicename,
|
||||||
|
email: author.email,
|
||||||
|
avatar: author.avatar?.url,
|
||||||
|
description: author.description,
|
||||||
|
totalPosts: author.posts?.pageInfo?.total || posts.length
|
||||||
|
},
|
||||||
|
posts,
|
||||||
|
pageInfo: data.contentNodes?.pageInfo || {
|
||||||
|
hasNextPage: false,
|
||||||
|
endCursor: null
|
||||||
|
},
|
||||||
|
authorName: coauthorName
|
||||||
|
};
|
||||||
|
},
|
||||||
|
{ ttl: CACHE_TTL.POSTS }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// все посты автора
|
||||||
|
export async function getPostsByCoauthorLogin(login, first = 14, after = null) {
|
||||||
|
// Создаем уникальный ключ для кэша
|
||||||
|
const cacheKey = `coauthor-posts-by-login:${login}:${first}:${after || 'first-page'}`;
|
||||||
|
|
||||||
|
return await cache.wrap(
|
||||||
|
cacheKey,
|
||||||
|
async () => {
|
||||||
|
const query = `
|
||||||
|
query GetPostsByCoauthorLogin($first: Int!, $after: String, $login: String!) {
|
||||||
|
contentNodes(
|
||||||
|
first: $first
|
||||||
|
after: $after
|
||||||
|
where: {
|
||||||
|
contentTypes: [PROFILE_ARTICLE, ANEW]
|
||||||
|
coauthorLogin: $login
|
||||||
|
orderby: { field: DATE, order: DESC }
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
pageInfo {
|
||||||
|
hasNextPage
|
||||||
|
endCursor
|
||||||
|
}
|
||||||
|
nodes {
|
||||||
|
__typename
|
||||||
|
id
|
||||||
|
databaseId
|
||||||
|
uri
|
||||||
|
date
|
||||||
|
|
||||||
|
... on NodeWithTitle {
|
||||||
|
title
|
||||||
|
}
|
||||||
|
|
||||||
|
... on NodeWithFeaturedImage {
|
||||||
|
featuredImage {
|
||||||
|
node {
|
||||||
|
sourceUrl(size: LARGE)
|
||||||
|
altText
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Для ваших кастомных типов
|
||||||
|
... on ProfileArticle {
|
||||||
|
categories {
|
||||||
|
nodes {
|
||||||
|
name
|
||||||
|
slug
|
||||||
|
color
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
... on ANew {
|
||||||
|
categories {
|
||||||
|
nodes {
|
||||||
|
name
|
||||||
|
slug
|
||||||
|
color
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
... on NodeWithAuthor {
|
||||||
|
author {
|
||||||
|
node {
|
||||||
|
name
|
||||||
|
avatar {
|
||||||
|
url
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Coauthors для ProfileArticle
|
||||||
|
... on ProfileArticle {
|
||||||
|
coauthors {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
firstName
|
||||||
|
lastName
|
||||||
|
url
|
||||||
|
nicename # Добавляем nicename (login)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Coauthors для ANew
|
||||||
|
... on ANew {
|
||||||
|
coauthors {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
firstName
|
||||||
|
lastName
|
||||||
|
url
|
||||||
|
nicename # Добавляем nicename (login)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const data = await fetchGraphQL(query, {
|
||||||
|
first,
|
||||||
|
after,
|
||||||
|
login
|
||||||
|
});
|
||||||
|
|
||||||
|
// Обрабатываем посты
|
||||||
|
const posts = data.contentNodes?.nodes?.map(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 || '',
|
||||||
|
nicename: author.nicename || '' // Добавляем login
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}) || [];
|
||||||
|
|
||||||
|
return {
|
||||||
|
posts,
|
||||||
|
pageInfo: data.contentNodes?.pageInfo || {
|
||||||
|
hasNextPage: false,
|
||||||
|
endCursor: null
|
||||||
|
},
|
||||||
|
authorLogin: login
|
||||||
|
};
|
||||||
|
},
|
||||||
|
{ ttl: CACHE_TTL.POSTS }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export async function getAuthorData(slug) {
|
||||||
|
const cacheKey = `author-data:slug:${slug}`;
|
||||||
|
|
||||||
|
return await cache.wrap(
|
||||||
|
cacheKey,
|
||||||
|
async () => {
|
||||||
|
const baseUrl = import.meta.env.WP_REST_BASE_URL.replace(/\/$/, '');
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch(`${baseUrl}/author/${slug}`);
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
if (response.status === 404) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
throw new Error(`HTTP error: ${response.status}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const author = await response.json();
|
||||||
|
|
||||||
|
// Форматируем ответ
|
||||||
|
return {
|
||||||
|
id: author.slug || author.id,
|
||||||
|
name: author.name,
|
||||||
|
firstName: author.firstName,
|
||||||
|
lastName: author.lastName,
|
||||||
|
avatar: author.photo || author.avatar,
|
||||||
|
avatar_sizes: author.photo_sizes || {},
|
||||||
|
bio: author.description,
|
||||||
|
social: author.social || {},
|
||||||
|
url: author.url,
|
||||||
|
type: author.type,
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`❌ Failed to fetch author ${slug}:`, error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ ttl: CACHE_TTL.AUTHOR }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -398,6 +398,8 @@ export async function getPostsByTag(slug, first = 14, after = null) {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//последние новости (кэшированная версия)
|
//последние новости (кэшированная версия)
|
||||||
export async function getLatestAnews(count = 12): Promise<AnewsPost[]> {
|
export async function getLatestAnews(count = 12): Promise<AnewsPost[]> {
|
||||||
const cacheKey = `latest-anews:${count}`;
|
const cacheKey = `latest-anews:${count}`;
|
||||||
|
|||||||
3
src/lib/cache/cache-ttl.ts
vendored
3
src/lib/cache/cache-ttl.ts
vendored
@@ -3,7 +3,8 @@
|
|||||||
*/
|
*/
|
||||||
export const CACHE_TTL = {
|
export const CACHE_TTL = {
|
||||||
TAXONOMY: parseInt(import.meta.env.CACHE_TAXONOMY_TTL || '3600'),
|
TAXONOMY: parseInt(import.meta.env.CACHE_TAXONOMY_TTL || '3600'),
|
||||||
POSTS: parseInt(import.meta.env.CACHE_POST_TTL || '1800')
|
POSTS: parseInt(import.meta.env.CACHE_POST_TTL || '1800'),
|
||||||
|
AUTHOR: parseInt(import.meta.env.CACHE_AUTHOR_TTL || '8')
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
// Для отключения кэша
|
// Для отключения кэша
|
||||||
|
|||||||
@@ -1,56 +1,77 @@
|
|||||||
---
|
---
|
||||||
// pages/author/[slug]/index.astro
|
import MainLayout from '@layouts/MainLayout.astro';
|
||||||
import { wpClient } from '@lib/wp-client';
|
import { getAuthorData, getPostsByCoauthorLogin } from '@lib/api/authors';
|
||||||
|
|
||||||
|
import ContentGrid from '@components/ContentGrid.astro';
|
||||||
|
|
||||||
export const prerender = false;
|
export const prerender = false;
|
||||||
|
|
||||||
const { slug } = Astro.params;
|
const { slug } = Astro.params;
|
||||||
|
|
||||||
// Функция для получения данных автора
|
const author = await getAuthorData(slug);
|
||||||
async function getAuthorData(authorSlug) {
|
|
||||||
try {
|
|
||||||
// Используем ваш кастомный эндпоинт или стандартный WP endpoint
|
|
||||||
const data = await wpClient.get(`my/v1/author-posts/${authorSlug}/1`);
|
|
||||||
|
|
||||||
if (!data) {
|
const data = await getPostsByCoauthorLogin(slug);
|
||||||
// Если кастомный эндпоинт не работает, пробуем стандартный
|
const posts = data.posts;
|
||||||
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
|
// Если автор не найден - 404
|
||||||
//if (!authorData) {
|
//if (!authorData) {
|
||||||
// return Astro.redirect('/404');
|
// return Astro.redirect('/404');
|
||||||
//}
|
//}
|
||||||
|
|
||||||
const { author, posts } = authorData;
|
|
||||||
---
|
---
|
||||||
|
|
||||||
<h1>Author: {author.name || slug}</h1>
|
<MainLayout
|
||||||
|
title={`Публикации автора: ${slug}`}
|
||||||
|
description={`Информационное агентство Деловой журнал Профиль - записи по тегу ${slug}`}
|
||||||
|
>
|
||||||
|
|
||||||
{posts && posts.length > 0 ? (
|
{author && (
|
||||||
<div>
|
<div class="author-card">
|
||||||
<h2>Статьи автора:</h2>
|
{author.avatar && (
|
||||||
<ul>
|
<img
|
||||||
{posts.map(post => (
|
src={author.avatar}
|
||||||
<li key={post.id}>
|
alt={author.name}
|
||||||
<a href={post.link}>{post.title}</a>
|
width="192"
|
||||||
</li>
|
height="192"
|
||||||
))}
|
class="avatar"
|
||||||
</ul>
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<h1>{author.name}</h1>
|
||||||
|
|
||||||
|
{(author.firstName || author.lastName) && (
|
||||||
|
<p class="full-name">
|
||||||
|
{author.firstName} {author.lastName}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{author.bio && (
|
||||||
|
<div class="bio">{author.bio}</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{author.social && Object.values(author.social).some(Boolean) && (
|
||||||
|
<div class="social-links">
|
||||||
|
{author.social.twitter && (
|
||||||
|
<a href={author.social.twitter}>Twitter</a>
|
||||||
|
)}
|
||||||
|
{author.social.facebook && (
|
||||||
|
<a href={author.social.facebook}>Facebook</a>
|
||||||
|
)}
|
||||||
|
{author.social.instagram && (
|
||||||
|
<a href={author.social.instagram}>Instagram</a>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
) : (
|
|
||||||
<p>У автора пока нет статей</p>
|
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
<ContentGrid
|
||||||
|
items={posts}
|
||||||
|
pageInfo={data.pageInfo}
|
||||||
|
slug={slug}
|
||||||
|
showCount={false}
|
||||||
|
type='author'
|
||||||
|
perLoad={11}
|
||||||
|
/>
|
||||||
|
</MainLayout>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
---
|
---
|
||||||
import ContentGrid from '@components/ContentGrid.astro';
|
import ContentGrid from '@components/ContentGrid.astro';
|
||||||
|
import { getLatestPosts, getPostsByCategory, getAuthorPosts, getPostsByTag } from '../lib/api/posts';
|
||||||
|
import { getPostsByCoauthorLogin } from '../lib/api/authors';
|
||||||
|
|
||||||
export const prerender = false;
|
export const prerender = false;
|
||||||
|
|
||||||
@@ -22,12 +24,6 @@ const {
|
|||||||
startIndex = 0
|
startIndex = 0
|
||||||
} = body;
|
} = body;
|
||||||
|
|
||||||
console.log('📥 Load more request:', { perLoad, after, type, slug, startIndex });
|
|
||||||
|
|
||||||
|
|
||||||
// Импортируем функции для получения данных
|
|
||||||
const { getLatestPosts, getPostsByCategory, getAuthorPosts, getPostsByTag } =
|
|
||||||
await import('../lib/api/posts');
|
|
||||||
|
|
||||||
let result;
|
let result;
|
||||||
|
|
||||||
@@ -39,7 +35,7 @@ switch (type) {
|
|||||||
break;
|
break;
|
||||||
case 'author':
|
case 'author':
|
||||||
if (!slug) throw new Error('Slug required for author');
|
if (!slug) throw new Error('Slug required for author');
|
||||||
result = await getAuthorPosts(slug, perLoad, after); // Используем perLoad
|
result = await getPostsByCoauthorLogin(slug, perLoad, after); // Используем perLoad
|
||||||
break;
|
break;
|
||||||
case 'tag':
|
case 'tag':
|
||||||
if (!slug) throw new Error('Slug required for tag');
|
if (!slug) throw new Error('Slug required for tag');
|
||||||
|
|||||||
Reference in New Issue
Block a user