add support pages
This commit is contained in:
85
src/lib/api/pages.ts
Normal file
85
src/lib/api/pages.ts
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
import { fetchGraphQL } from './graphql-client.js';
|
||||||
|
|
||||||
|
/** подключаем страницу по slug */
|
||||||
|
interface PageData {
|
||||||
|
id: string;
|
||||||
|
title: string;
|
||||||
|
content: string;
|
||||||
|
image: string | null;
|
||||||
|
imageAlt: string;
|
||||||
|
type: 'page';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Интерфейс для ответа GraphQL
|
||||||
|
interface GraphQLResponse {
|
||||||
|
data?: {
|
||||||
|
pages?: {
|
||||||
|
nodes: Array<{
|
||||||
|
id: string;
|
||||||
|
title: string;
|
||||||
|
content: string;
|
||||||
|
slug: string;
|
||||||
|
featuredImage?: {
|
||||||
|
node: {
|
||||||
|
sourceUrl: string;
|
||||||
|
altText: string;
|
||||||
|
};
|
||||||
|
} | null;
|
||||||
|
}>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getPageBySlug(slug: string): Promise<PageData | null> {
|
||||||
|
if (!slug) return null;
|
||||||
|
|
||||||
|
const query = `
|
||||||
|
query GetPageBySlug($slug: String!) {
|
||||||
|
pages(where: {name: $slug}) {
|
||||||
|
nodes {
|
||||||
|
id
|
||||||
|
title
|
||||||
|
content
|
||||||
|
slug
|
||||||
|
featuredImage {
|
||||||
|
node {
|
||||||
|
sourceUrl(size: LARGE)
|
||||||
|
altText
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Получаем данные
|
||||||
|
const response = await fetchGraphQL(query, { slug });
|
||||||
|
|
||||||
|
// ПРОВЕРЯЕМ СТРУКТУРУ ОТВЕТА
|
||||||
|
console.log('🔍 FULL RESPONSE:', JSON.stringify(response, null, 2));
|
||||||
|
|
||||||
|
// Пробуем разные варианты доступа к данным
|
||||||
|
const pages = response?.data?.pages?.nodes || response?.pages?.nodes || [];
|
||||||
|
const page = pages[0];
|
||||||
|
|
||||||
|
if (!page) {
|
||||||
|
console.log('❌ No page found for slug:', slug);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('✅ Page found:', page.title);
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: page.id,
|
||||||
|
title: page.title,
|
||||||
|
content: page.content,
|
||||||
|
image: page.featuredImage?.node?.sourceUrl || null,
|
||||||
|
imageAlt: page.featuredImage?.node?.altText || page.title || '',
|
||||||
|
type: 'page'
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
console.error('❌ Error in getPageBySlug:', error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { wpInfo } from './wpInfo';
|
||||||
|
|
||||||
export interface PageTypeInfo {
|
export interface PageTypeInfo {
|
||||||
type: 'single' | 'archive' | 'home' | 'unknown';
|
type: 'single' | 'archive' | 'home' | 'unknown';
|
||||||
contentType?: 'news' | 'post';
|
contentType?: 'news' | 'post';
|
||||||
@@ -5,14 +7,33 @@ export interface PageTypeInfo {
|
|||||||
postSlug?: string;
|
postSlug?: string;
|
||||||
postId?: number;
|
postId?: number;
|
||||||
page: number;
|
page: number;
|
||||||
|
pageSlug?: string;
|
||||||
uriParts: string[];
|
uriParts: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export function detectPageType(uri: string): PageTypeInfo {
|
export function detectPageType(uri: string): PageTypeInfo {
|
||||||
|
//console.log('🔍 detectPageType INPUT:', uri);
|
||||||
|
|
||||||
|
// Убираем query параметры если есть
|
||||||
|
const uriWithoutQuery = uri.split('?')[0];
|
||||||
|
|
||||||
// Убираем слэши по краям
|
// Убираем слэши по краям
|
||||||
const cleanUri = uri.replace(/^\/|\/$/g, '');
|
const cleanUri = uriWithoutQuery.replace(/^\/|\/$/g, '');
|
||||||
const parts = cleanUri ? cleanUri.split('/') : [];
|
|
||||||
|
console.log('📌 Clean URI:', cleanUri);
|
||||||
|
|
||||||
|
// Если URI пустой - это главная
|
||||||
|
if (cleanUri === '') {
|
||||||
|
console.log('🏠 Home page detected');
|
||||||
|
return {
|
||||||
|
type: 'home',
|
||||||
|
page: 1,
|
||||||
|
uriParts: []
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const parts = cleanUri.split('/');
|
||||||
|
console.log('📦 Parts:', parts);
|
||||||
|
|
||||||
// Ищем пагинацию
|
// Ищем пагинацию
|
||||||
const processedParts: string[] = [];
|
const processedParts: string[] = [];
|
||||||
@@ -23,20 +44,27 @@ export function detectPageType(uri: string): PageTypeInfo {
|
|||||||
const pageNum = parseInt(parts[i + 1]);
|
const pageNum = parseInt(parts[i + 1]);
|
||||||
if (pageNum > 0) {
|
if (pageNum > 0) {
|
||||||
page = pageNum;
|
page = pageNum;
|
||||||
i++; // Пропускаем номер страницы
|
i++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
processedParts.push(parts[i]);
|
processedParts.push(parts[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//console.log('🔄 Processed parts:', processedParts);
|
||||||
|
|
||||||
// Определяем, это новость или нет
|
// Определяем, это новость или нет
|
||||||
const isNews = processedParts[0] === 'news';
|
const isNews = processedParts[0] === 'news';
|
||||||
|
//console.log('📰 isNews:', isNews);
|
||||||
|
|
||||||
// Для анализа убираем 'news' из начала если есть
|
// Для анализа убираем 'news' из начала если есть
|
||||||
const partsWithoutNews = isNews ? processedParts.slice(1) : processedParts;
|
const partsWithoutNews = isNews ? processedParts.slice(1) : processedParts;
|
||||||
const partsCount = partsWithoutNews.length;
|
//console.log('✂️ Parts without news:', partsWithoutNews);
|
||||||
|
|
||||||
|
const partsCount = partsWithoutNews.length;
|
||||||
|
//console.log('🔢 Parts count:', partsCount);
|
||||||
|
|
||||||
|
// Домашняя страница
|
||||||
if (partsCount === 0) {
|
if (partsCount === 0) {
|
||||||
return {
|
return {
|
||||||
type: 'home',
|
type: 'home',
|
||||||
@@ -45,42 +73,66 @@ export function detectPageType(uri: string): PageTypeInfo {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Одиночный пост
|
// Проверяем, является ли последний сегмент постом (содержит ID)
|
||||||
if (partsCount === 1 || partsCount === 2) {
|
|
||||||
const lastPart = partsWithoutNews[partsWithoutNews.length - 1];
|
const lastPart = partsWithoutNews[partsWithoutNews.length - 1];
|
||||||
const match = lastPart.match(/-(\d+)$/);
|
//console.log('🔚 Last part:', lastPart);
|
||||||
|
|
||||||
|
const match = lastPart.match(/-(\d+)$/);
|
||||||
|
//console.log('🎯 Post ID match:', match);
|
||||||
|
|
||||||
|
// Одиночный пост
|
||||||
if (match) {
|
if (match) {
|
||||||
const id = parseInt(match[1]);
|
const id = parseInt(match[1]);
|
||||||
if (id > 0) {
|
if (id > 0) {
|
||||||
const slugWithoutId = lastPart.substring(0, lastPart.lastIndexOf('-'));
|
const slugWithoutId = lastPart.substring(0, lastPart.lastIndexOf('-'));
|
||||||
|
|
||||||
|
//console.log('📄 Single post detected:', { id, slugWithoutId });
|
||||||
|
|
||||||
return {
|
return {
|
||||||
type: 'single',
|
type: 'single',
|
||||||
contentType: isNews ? 'news' : 'post', // Теперь правильно
|
contentType: isNews ? 'news' : 'post',
|
||||||
categorySlug: partsCount === 2 ? partsWithoutNews[0] : undefined,
|
categorySlug: partsCount === 2 ? partsWithoutNews[0] : undefined,
|
||||||
postSlug: slugWithoutId,
|
postSlug: slugWithoutId,
|
||||||
postId: id,
|
postId: id,
|
||||||
page,
|
page,
|
||||||
uriParts: processedParts // Сохраняем исходные части
|
uriParts: processedParts
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Проверяем, является ли первый сегмент существующей рубрикой
|
||||||
|
if (partsCount === 1) {
|
||||||
|
const potentialCategorySlug = partsWithoutNews[0];
|
||||||
|
//console.log('📁 Checking if category exists:', potentialCategorySlug);
|
||||||
|
|
||||||
|
// Ждем загрузки рубрик если нужно
|
||||||
|
if (!wpInfo.isLoaded()) {
|
||||||
|
//console.log('⏳ Waiting for categories to load...');
|
||||||
|
// В синхронной функции не можем ждать, поэтому проверяем позже
|
||||||
}
|
}
|
||||||
|
|
||||||
// Рубрика
|
const category = wpInfo.getCategoryBySlug(potentialCategorySlug);
|
||||||
if (partsCount === 1) {
|
//console.log('🏷️ Category found:', category ? 'YES' : 'NO');
|
||||||
|
|
||||||
|
if (category) {
|
||||||
|
//console.log('📁 Archive detected (existing category):', potentialCategorySlug);
|
||||||
return {
|
return {
|
||||||
type: 'archive',
|
type: 'archive',
|
||||||
contentType: isNews ? 'news' : undefined,
|
contentType: isNews ? 'news' : undefined,
|
||||||
categorySlug: partsWithoutNews[0],
|
categorySlug: potentialCategorySlug,
|
||||||
page,
|
page,
|
||||||
uriParts: processedParts
|
uriParts: processedParts
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Если это не рубрика - это обычная страница
|
||||||
|
const pageSlug = partsWithoutNews.join('/');
|
||||||
|
//console.log('📄 PAGE DETECTED with slug:', pageSlug);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
type: 'unknown',
|
type: 'unknown',
|
||||||
|
pageSlug: pageSlug,
|
||||||
page,
|
page,
|
||||||
uriParts: processedParts
|
uriParts: processedParts
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -4,58 +4,57 @@ import NewsSingle from '@components/NewsSingle.astro';
|
|||||||
import ContentGrid from '@components/ContentGrid.astro';
|
import ContentGrid from '@components/ContentGrid.astro';
|
||||||
|
|
||||||
import { getNodeByURI } from '@lib/api/all';
|
import { getNodeByURI } from '@lib/api/all';
|
||||||
import { getProfileArticleById, getPostsByCategory } from '@lib/api/posts'; //логика
|
import { getProfileArticleById, getPostsByCategory } from '@lib/api/posts';
|
||||||
|
import { getPageBySlug } from '@lib/api/pages';
|
||||||
|
|
||||||
|
import { getCategory } from '@lib/api/categories';
|
||||||
import { getCategory } from '@lib/api/categories'; //логика
|
|
||||||
import { wpInfo } from '@lib/wpInfo';
|
import { wpInfo } from '@lib/wpInfo';
|
||||||
import { detectPageType } from '@lib/detect-page-type';
|
import { detectPageType } from '@lib/detect-page-type';
|
||||||
|
|
||||||
export const prerender = false;
|
export const prerender = false;
|
||||||
|
|
||||||
const pathname = Astro.url.pathname;
|
const pathname = Astro.url.pathname;
|
||||||
const pageInfo = detectPageType(pathname); //определяем тип страницы
|
|
||||||
|
|
||||||
|
// Убеждаемся что рубрики загружены перед определением типа
|
||||||
let response;
|
|
||||||
let article = null;
|
|
||||||
let posts = null;
|
|
||||||
let result = null;
|
|
||||||
let category;
|
|
||||||
|
|
||||||
// Определяем категорию
|
|
||||||
if (!wpInfo.isLoaded()) {
|
if (!wpInfo.isLoaded()) {
|
||||||
await wpInfo.fetchAllCategories();
|
await wpInfo.fetchAllCategories();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const pageInfo = detectPageType(pathname);
|
||||||
|
|
||||||
|
let article = null;
|
||||||
|
let posts = null;
|
||||||
|
let result = null;
|
||||||
|
let category;
|
||||||
|
let page = null;
|
||||||
|
|
||||||
|
// Получаем категорию если есть
|
||||||
category = wpInfo.getCategoryBySlug(pageInfo.categorySlug);
|
category = wpInfo.getCategoryBySlug(pageInfo.categorySlug);
|
||||||
|
|
||||||
|
let title = 'Профиль';
|
||||||
|
|
||||||
let title = 'Профиль'; //title page
|
console.log(pageInfo);
|
||||||
|
|
||||||
if (pageInfo.type === 'single') { //одиночная статья
|
|
||||||
|
|
||||||
|
if (pageInfo.type === 'single') {
|
||||||
try {
|
try {
|
||||||
article = await getProfileArticleById(pageInfo.postId); //получвем данные поста
|
article = await getProfileArticleById(pageInfo.postId);
|
||||||
title=article.title
|
title = article?.title || title;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error fetching node:', error);
|
console.error('Error fetching node:', error);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (pageInfo.type === 'archive') {
|
} else if (pageInfo.type === 'archive') {
|
||||||
|
result = await getPostsByCategory(pageInfo.categorySlug, 21);
|
||||||
result = await getPostsByCategory(pageInfo.categorySlug, 21); //получвем данные поста
|
posts = result?.posts;
|
||||||
posts = result.posts;
|
} else if (pageInfo.type === 'unknown' && pageInfo.pageSlug) {
|
||||||
|
try {
|
||||||
|
page = await getPageBySlug(pageInfo.pageSlug);
|
||||||
|
if (page) {
|
||||||
|
title = page.title;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error fetching page:', error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ISR кэширование
|
|
||||||
//Astro.response.headers.set(
|
|
||||||
// 'Cache-Control',
|
|
||||||
// 'public, s-maxage=3600, stale-while-revalidate=86400'
|
|
||||||
//);
|
|
||||||
---
|
---
|
||||||
|
|
||||||
<ContentLayout
|
<ContentLayout
|
||||||
@@ -64,23 +63,26 @@ if (pageInfo.type === 'single') { //одиночная статья
|
|||||||
category={category}
|
category={category}
|
||||||
>
|
>
|
||||||
|
|
||||||
{/* Page (страница) */}
|
{/* СТРАНИЦА */}
|
||||||
{pageInfo.type === 'unknown' && (
|
{pageInfo.type === 'unknown' && page && (
|
||||||
<div>✅ Это страница: {pageInfo.pageSlug}</div>
|
<div class="article-wrapper">
|
||||||
)}
|
<article class="news-single">
|
||||||
|
<h1>{page.title}</h1>
|
||||||
|
<div set:html={page.content} />
|
||||||
|
</article>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Single post */}
|
||||||
{/* Single post */}
|
{pageInfo.type === 'single' && article && (
|
||||||
{pageInfo.type === 'single' && article && (
|
|
||||||
<NewsSingle post={article} pageInfo={pageInfo} />
|
<NewsSingle post={article} pageInfo={pageInfo} />
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{/* Category archive */}
|
||||||
{/* Category archive */}
|
|
||||||
{pageInfo.type === 'archive' && posts && (
|
{pageInfo.type === 'archive' && posts && (
|
||||||
<ContentGrid
|
<ContentGrid
|
||||||
items={posts}
|
items={posts}
|
||||||
pageInfo={result.pageInfo}
|
pageInfo={result?.pageInfo}
|
||||||
slug={pageInfo.categorySlug}
|
slug={pageInfo.categorySlug}
|
||||||
showCount={false}
|
showCount={false}
|
||||||
type='category'
|
type='category'
|
||||||
@@ -89,7 +91,4 @@ if (pageInfo.type === 'single') { //одиночная статья
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</ContentLayout>
|
</ContentLayout>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user