diff --git a/src/components/MainPostWidget.astro b/src/components/MainPostWidget.astro new file mode 100644 index 0000000..4d59c7c --- /dev/null +++ b/src/components/MainPostWidget.astro @@ -0,0 +1,95 @@ +--- +// src/components/MainPostWidget.astro +import { getLatestMainPost } from '@lib/api/main-posts'; + +const mainPost = await getLatestMainPost(); + +const postDate = mainPost ? new Date(mainPost.date) : null; +const imageUrl = mainPost?.featuredImage?.node?.sourceUrl; +const imageAlt = mainPost?.featuredImage?.node?.altText || mainPost?.title || ''; + +const category = mainPost?.categories?.nodes?.[0]; +const categoryName = category?.name || ''; +const categoryColor = category?.color || '#2271b1'; // цвет по умолчанию + +let authorName = ''; +if (mainPost?.coauthors && mainPost.coauthors.length > 0) { + authorName = mainPost.coauthors.map(author => { + if (author.firstName && author.lastName) { + return `${author.firstName} ${author.lastName}`; + } + return author.name; + }).join(', '); +} else if (mainPost?.author) { + const author = mainPost.author.node; + authorName = author.firstName && author.lastName + ? `${author.firstName} ${author.lastName}` + : author.name; +} +--- + +{mainPost && ( +
+ +
+ {imageUrl ? ( + {imageAlt} + ) : ( +
+ )} + + {categoryName && ( + + )} + +
+ + +

+ {mainPost.title} +

+ + {authorName && ( + + )} +
+
+
+ +
+

+ +

+ +
+
+)} diff --git a/src/lib/api/colon-posts.ts b/src/lib/api/colon-posts.ts new file mode 100644 index 0000000..084e1b3 --- /dev/null +++ b/src/lib/api/colon-posts.ts @@ -0,0 +1,149 @@ +// src/lib/api/colon-posts.ts +import { fetchGraphQL } from './graphql-client.js'; +import { cache } from '@lib/cache/manager.js'; +import { CACHE_TTL } from '@lib/cache/cache-ttl'; + +/** + * Интерфейс для поста колонки (ProfileArticle с colonItem = true) + */ +export interface ColonPost { + id: string; + databaseId: number; + title: string; + uri: string; + date: string; + colonItem: boolean; + excerpt?: string; + featuredImage?: { + node: { + sourceUrl: string; + altText: string; + }; + }; + author: { + node: { + id: string; + name: string; + firstName: string; + lastName: string; + avatar: { + url: string; + }; + uri: string; + }; + }; + coauthors?: Array<{ + id: string; + name: string; + firstName: string; + lastName: string; + url: string; + description: string; + }>; + categories: { + nodes: Array<{ + id: string; + name: string; + color?: string; + slug: string; + uri: string; + databaseId: number; + }>; + }; + tags: { + nodes: Array<{ + id: string; + name: string; + slug: string; + uri: string; + }>; + }; +} + +/** + * GraphQL запрос для получения последнего поста колонки + */ +const LATEST_COLON_POST_QUERY = ` + query GetLatestColonPost { + profileArticles( + where: { + status: PUBLISH + colonItemEquals: true + orderby: { field: DATE, order: DESC } + } + first: 1 + ) { + nodes { + id + databaseId + title + uri + date + colonItem + excerpt + featuredImage { + node { + sourceUrl(size: LARGE) + altText + } + } + author { + node { + id + name + firstName + lastName + avatar { + url + } + uri + } + } + coauthors { + id + name + firstName + lastName + url + description + } + categories { + nodes { + id + name + color + slug + uri + databaseId + } + } + tags { + nodes { + id + name + slug + uri + } + } + } + } + } +`; + +/** + * Получает последний пост колонки + * + * @returns {Promise} Последний пост колонки или null + */ +export async function getLatestColonPost(): Promise { + const cacheKey = 'latest-colon-post'; + + return await cache.wrap( + cacheKey, + async () => { + const data = await fetchGraphQL(LATEST_COLON_POST_QUERY); + return data?.profileArticles?.nodes?.[0] || null; + }, + CACHE_TTL.SHORT + ); +} diff --git a/src/lib/api/main-posts.ts b/src/lib/api/main-posts.ts new file mode 100644 index 0000000..c2fbd22 --- /dev/null +++ b/src/lib/api/main-posts.ts @@ -0,0 +1,149 @@ +// src/lib/api/main-posts.ts +import { fetchGraphQL } from './graphql-client.js'; +import { cache } from '@lib/cache/manager.js'; +import { CACHE_TTL } from '@lib/cache/cache-ttl'; + +/** + * Интерфейс для главного поста (ProfileArticle с mainItem = true) + */ +export interface MainPost { + id: string; + databaseId: number; + title: string; + uri: string; + date: string; + mainItem: boolean; + excerpt?: string; + featuredImage?: { + node: { + sourceUrl: string; + altText: string; + }; + }; + author: { + node: { + id: string; + name: string; + firstName: string; + lastName: string; + avatar: { + url: string; + }; + uri: string; + }; + }; + coauthors?: Array<{ + id: string; + name: string; + firstName: string; + lastName: string; + url: string; + description: string; + }>; + categories: { + nodes: Array<{ + id: string; + name: string; + color?: string; + slug: string; + uri: string; + databaseId: number; + }>; + }; + tags: { + nodes: Array<{ + id: string; + name: string; + slug: string; + uri: string; + }>; + }; +} + +/** + * GraphQL запрос для получения последнего главного поста + */ +const LATEST_MAIN_POST_QUERY = ` + query GetLatestMainPost { + profileArticles( + where: { + status: PUBLISH + mainItemEquals: true + orderby: { field: DATE, order: DESC } + } + first: 1 + ) { + nodes { + id + databaseId + title + uri + date + mainItem + excerpt + featuredImage { + node { + sourceUrl(size: LARGE) + altText + } + } + author { + node { + id + name + firstName + lastName + avatar { + url + } + uri + } + } + coauthors { + id + name + firstName + lastName + url + description + } + categories { + nodes { + id + name + color + slug + uri + databaseId + } + } + tags { + nodes { + id + name + slug + uri + } + } + } + } + } +`; + +/** + * Получает последний главный пост + * + * @returns {Promise} Последний главный пост или null + */ +export async function getLatestMainPost(): Promise { + const cacheKey = 'latest-main-post'; + + return await cache.wrap( + cacheKey, + async () => { + const data = await fetchGraphQL(LATEST_MAIN_POST_QUERY); + return data?.profileArticles?.nodes?.[0] || null; + }, + CACHE_TTL.SHORT + ); +} diff --git a/src/pages/index.astro b/src/pages/index.astro index dbb4601..462d21c 100644 --- a/src/pages/index.astro +++ b/src/pages/index.astro @@ -1,14 +1,18 @@ --- import { getSiteInfo } from "../lib/wp-api.js"; import { getLatestPosts } from '@api/posts.js'; +import { getLatestColonPost } from '@lib/api/colon-posts'; const site = await getSiteInfo(); const { posts, pageInfo } = await getLatestPosts(41); // Сразу деструктурируем +const colonPost = await getLatestColonPost(); //последний пост колонки // визуальные компоненты import MainLayout from '@layouts/MainLayout.astro'; import ContentGrid from '@components/ContentGrid.astro'; import EndnewsList from '@components/EndnewsList.astro'; +import MainPostWidget from '@/components/MainPostWidget.astro'; + //ISR export const prerender = false; @@ -21,6 +25,15 @@ export const prerender = false;

{site.title}

{site.description &&

{site.description}

} + + + {colonPost && ( +
+

{colonPost.title}

+ Читать колонку +
+)} +