add news post

This commit is contained in:
Profile Profile
2026-02-18 23:33:35 +03:00
parent 9e32f4f064
commit b58b35bf47
6 changed files with 135 additions and 111 deletions

View File

@@ -0,0 +1,41 @@
---
export interface Props {
name?: string;
color?: string;
class?: string;
}
const { name, color = '', class: className = '' } = Astro.props;
function extractColorClass(colorString: string): string {
if (!colorString) return 'bg-blue';
if (colorString.includes('фон меню:')) {
const color = colorString.split(':')[1]?.trim();
const valid = [
'black', 'yellow', 'blue', 'green', 'red', 'orange', 'gray',
'indigo', 'purple', 'pink', 'teal', 'cyan', 'white',
'gray-dark', 'light', 'dark'
];
if (color && valid.includes(color)) return `bg-${color}`;
}
if (colorString.startsWith('bg-')) return colorString;
const simple = colorString.toLowerCase();
const valid = [
'black', 'yellow', 'blue', 'green', 'red', 'orange', 'gray',
'indigo', 'purple', 'pink', 'teal', 'cyan', 'white',
'gray-dark', 'light', 'dark'
];
return valid.includes(simple) ? `bg-${simple}` : 'bg-blue';
}
const bgClass = extractColorClass(color);
---
{name && (
<div class={`post-category-badge ${bgClass}${className ? ` ${className}` : ''}`}>
{name}
</div>
)}

View File

@@ -1,5 +1,6 @@
--- ---
import CategoryBadge from './CategoryBadge.astro'; // цветная плитка рубрик
export interface Props { export interface Props {
@@ -23,39 +24,6 @@ const {
loadMoreConfig = { type: 'latest', first: 11 } loadMoreConfig = { type: 'latest', first: 11 }
} = Astro.props; } = Astro.props;
function extractColorClass(colorString: string): string {
if (!colorString) return 'bg-blue';
if (colorString.includes('фон меню:')) {
const parts = colorString.split(':');
const color = parts[1]?.trim();
const validColors = [
'black', 'yellow', 'blue', 'green', 'red', 'orange', 'gray',
'indigo', 'purple', 'pink', 'teal', 'cyan', 'white',
'gray-dark', 'light', 'dark'
];
if (color && validColors.includes(color)) {
return `bg-${color}`;
}
}
if (colorString.startsWith('bg-')) {
return colorString;
}
const simpleColor = colorString.toLowerCase();
switch(simpleColor) {
case 'black': case 'yellow': case 'blue': case 'green':
case 'red': case 'orange': case 'gray': case 'indigo':
case 'purple': case 'pink': case 'teal': case 'cyan':
case 'white': case 'dark': case 'light':
return `bg-${simpleColor}`;
case 'gray-dark': return 'bg-gray-dark';
default: return 'bg-blue';
}
}
function getCoauthorsNames(coauthors: any[]): string { function getCoauthorsNames(coauthors: any[]): string {
if (!coauthors || coauthors.length === 0) return ''; if (!coauthors || coauthors.length === 0) return '';
@@ -89,8 +57,6 @@ function shouldBeLarge(index: number): boolean {
const coauthors = item.coauthors || []; const coauthors = item.coauthors || [];
const coauthorsNames = getCoauthorsNames(coauthors); const coauthorsNames = getCoauthorsNames(coauthors);
const rawColor = item.categories?.nodes?.[0]?.color || '';
const categoryBgClass = extractColorClass(rawColor);
// ✅ ИСПРАВЛЕННАЯ логика // ✅ ИСПРАВЛЕННАЯ логика
const isLarge = shouldBeLarge(index); const isLarge = shouldBeLarge(index);
@@ -120,11 +86,10 @@ function shouldBeLarge(index: number): boolean {
<div class="post-image-placeholder"></div> <div class="post-image-placeholder"></div>
)} )}
{item.categories?.nodes?.[0]?.name && ( <CategoryBadge
<div class={`post-category-badge ${categoryBgClass}`}> name={item.categories?.nodes?.[0]?.name}
{item.categories.nodes[0].name} color={item.categories?.nodes?.[0]?.color}
</div> />
)}
<div class="post-content-overlay"> <div class="post-content-overlay">
<div class="post-meta-overlay"> <div class="post-meta-overlay">

View File

@@ -1,7 +1,9 @@
--- ---
// src/components/MainPostWidget.astro // src/components/MainPostWidget.astro
import { getLatestMainPost } from '@lib/api/main-posts'; import { getLatestMainPost } from '@lib/api/main-posts';
import Author from '@components/AuthorDisplay.astro'; import Author from '@components/AuthorDisplay.astro';
import CategoryBadge from '@components/CategoryBadge.astro'; // цветная плитка рубрик
const mainPost = await getLatestMainPost(); const mainPost = await getLatestMainPost();
@@ -53,12 +55,10 @@ const formattedDate = postDate.toLocaleDateString('ru-RU', {
</a> </a>
{categoryName && ( {categoryName && (
<div <CategoryBadge
class="category-badge" name= {categoryName}
style={`background-color: ${categoryColor}`} color={categoryColor}
> />
{categoryName}
</div>
)} )}
<div class="content-overlay"> <div class="content-overlay">

View File

@@ -15,12 +15,24 @@ const { post, pageInfo } = Astro.props;
{post ? ( {post ? (
<div class="article-wrapper"> <div class="article-wrapper">
<article class="news-single"> <article class="news-single">
<div class="article_info"> <div class="article_info">
<div class="publication__data">{post.date && <time>{new Date(post.date).toLocaleDateString('ru-RU')}</time>}</div> <div class="publication__data">
<span class="author"><Author post={post} separator=", " /></span> {post.date && (
<time datetime={new Date(post.date).toISOString()}>
{new Date(post.date).toLocaleDateString('ru-RU')}
</time>
)}
</div> </div>
<span class="divider" aria-hidden="true"></span>
<div class="publication__author">
<Author post={post} separator=", " />
</div>
</div>
<h1>{post.title}</h1> <h1>{post.title}</h1>
{post.secondaryTitle && <p class="secondary-title">{post.secondaryTitle}</p>} {post.secondaryTitle && <h2 class="secondary-title">{post.secondaryTitle}</h2>}
{post.featuredImage?.node?.sourceUrl && ( {post.featuredImage?.node?.sourceUrl && (
<figure class="featured-image"> <figure class="featured-image">
@@ -46,17 +58,20 @@ const { post, pageInfo } = Astro.props;
)} )}
{post.content && <div set:html={post.content} />} {post.content && <div set:html={post.content} />}
<Subscribe />
</article> </article>
<ShareButtons url={post.uri} title={post.title} /> <ShareButtons url={post.uri} title={post.title} />
<Subscribe />
</div> </div>
) : ( ) : (
<div>Новость не найдена</div> <div>Новость не найдена</div>
)} )}
<style> <style>
.article-wrapper { .article-wrapper {
position: relative; position: relative;
max-width: 75%; max-width: 75%;
@@ -69,29 +84,42 @@ const { post, pageInfo } = Astro.props;
margin: 0 0 0.625rem; margin: 0 0 0.625rem;
} }
.secondary-title { .news-single h2{
font-size: 1.25rem; font-size: 1.5rem;
line-height: 1.4; line-height: 1.1;
color: #666; margin: 2.0625rem 0 .375rem;
margin: 0.5rem 0 1rem;
font-weight: 400;
} }
.news-single :global(p a) {
color: #0d6efd;
}
.article_info { .article_info {
display: flex; display: flex;
gap: 8px; align-items: center;
gap: .475rem; /* одинаковое расстояние с обеих сторон от черты */
margin-top: 1.9375rem;
margin-bottom: .9375rem;
font-size: 0.875rem;
color: #666;
} }
.publication__data::after{ .divider {
content: ''; display: block;
position: absolute; width: 1px;
left: 0;
top: 50%;
height: 12px; height: 12px;
margin-top: -6px; background-color: #999;
border-left: 1px solid grey; flex-shrink: 0;
} }
.publication__author :global(a){
text-decoration: underline;
}
.featured-image { .featured-image {
margin: 1.5rem 0; margin: 1.5rem 0;
width: 100%; width: 100%;

View File

@@ -209,15 +209,15 @@ export async function getProfileArticleById(databaseId) {
/** /**
* Получить Anews пост по databaseId * Получить Anews пост по databaseId
*/ */
export async function getAnewsById(databaseId: number): Promise<SingleAnewsPost | null> { export async function getAnewById(databaseId: number): Promise<SingleAnewsPost | null> {
const cacheKey = `anews:${databaseId}`; const cacheKey = `anews:${databaseId}`;
return await cache.wrap( return await cache.wrap(
cacheKey, cacheKey,
async () => { async () => {
const query = ` const query = `
query GetAnewsById($id: ID!) { query GetAnewById($id: ID!) {
aNews(id: $id, idType: DATABASE_ID) { aNew(id: $id, idType: DATABASE_ID) {
id id
databaseId databaseId
title title
@@ -270,23 +270,13 @@ export async function getAnewsById(databaseId: number): Promise<SingleAnewsPost
uri uri
} }
} }
seo {
title
metaDesc
canonical
opengraphTitle
opengraphDescription
opengraphImage {
sourceUrl
}
}
} }
} }
`; `;
try { try {
const data = await fetchGraphQL(query, { id: databaseId }); const data = await fetchGraphQL(query, { id: databaseId });
return data?.aNews || null; return data?.aNew || null;
} catch (error) { } catch (error) {
console.error(`Error fetching Anews post with ID ${databaseId}:`, error); console.error(`Error fetching Anews post with ID ${databaseId}:`, error);
return null; return null;

View File

@@ -3,54 +3,54 @@ import MainLayout from '@layouts/MainLayout.astro';
import NewsSingle from '@components/NewsSingle.astro'; import NewsSingle from '@components/NewsSingle.astro';
import { detectPageType } from '@lib/detect-page-type'; import { detectPageType } from '@lib/detect-page-type';
import { getAnewById } from '@lib/api/posts';
import { getAnewsById } from '@lib/api/posts'; //логика
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);
//console.log(pageInfo);
// Или для полного URL
const fullUrl = Astro.url.href; const fullUrl = Astro.url.href;
// Или для origin + pathname
const fullPath = Astro.url.origin + Astro.url.pathname; const fullPath = Astro.url.origin + Astro.url.pathname;
// Объявляем переменную для данных поста
let post = null;
if (pageInfo.type === 'single' && pageInfo.contentType === 'news') { if (pageInfo.type === 'single' && pageInfo.contentType === 'news') {
if (pageInfo.postId && typeof pageInfo.postId === 'number') { if (pageInfo.postId && typeof pageInfo.postId === 'number') {
const response = await getAnewsById(pageInfo.postId); const response = await getAnewById(pageInfo.postId);
console.log(response); console.log(response);
//pageData = response?.post; post = response ?? null;
console.log(post);
} }
} }
if (import.meta.env.DEV) { if (import.meta.env.DEV) {
const currentFile = import.meta.url const currentFile = import.meta.url
.replace('file://', '') .replace('file://', '')
.replace(process.cwd(), '') .replace(process.cwd(), '')
.replace(/^\//, ''); .replace(/^\\/, '');
console.log('Файл:', currentFile); console.log('Файл:', currentFile);
} }
--- ---
<MainLayout> <MainLayout>
{pageInfo.type === 'single' && post ? (
<NewsSingle post={post} pageInfo={pageInfo} />
) : (
<div> <div>
<p><strong>pathname:</strong> {pathname}</p> <p><strong>pathname:</strong> {pathname}</p>
<p><strong>Page Type:</strong> {pageInfo.type}</p> <p><strong>Page Type:</strong> {pageInfo.type}</p>
<p><strong>Content Type:</strong> {pageInfo.contentType}</p> <p><strong>Content Type:</strong> {pageInfo.contentType}</p>
<p><strong>ID:</strong> {pageInfo.postId}</p>
<p><strong>Full URL:</strong> {fullUrl}</p> <p><strong>Full URL:</strong> {fullUrl}</p>
</div> </div>
)}
</MainLayout> </MainLayout>