add news post
This commit is contained in:
41
src/components/CategoryBadge.astro
Normal file
41
src/components/CategoryBadge.astro
Normal 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>
|
||||||
|
)}
|
||||||
@@ -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">
|
||||||
|
|||||||
@@ -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">
|
||||||
|
|||||||
@@ -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%;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
Reference in New Issue
Block a user