add AuthorDispaly

This commit is contained in:
Profile Profile
2026-02-02 17:58:36 +03:00
parent 49a4638c75
commit 131deebffc
9 changed files with 600 additions and 137 deletions

View File

@@ -0,0 +1,29 @@
---
// src/components/DisplayAuthor.astro
const { post } = Astro.props;
// Ваша логика, адаптированная для компонента
let authorDisplay = '';
if (post?.coauthors && post.coauthors.length > 0) {
authorDisplay = post.coauthors.map(author => {
if (author.firstName && author.lastName) {
return `<a href="${author.url || '#'}">${author.firstName} ${author.lastName}</a>`;
}
return `<a href="${author.url || '#'}">${author.name}</a>`;
}).join(' ');
} else if (post?.author?.node) {
const author = post.author.node;
const name = author.firstName && author.lastName
? `${author.firstName} ${author.lastName}`
: author.name;
authorDisplay = `<a href="${author.url || '#'}">${name}</a>`;
}
---
{authorDisplay ? (
<span set:html={authorDisplay} />
) : (
<span>Автор не указан</span>
)}

View File

@@ -0,0 +1,185 @@
---
import { getLatestColonPost } from '@lib/api/colon-posts';
import Author from '@components/AuthorDisplay.astro';
const colonPost = await getLatestColonPost();
---
{colonPost && (
<div class="colon-post-card">
<div class="colon-post-content">
<div class="colon-post-left">
{colonPost.featuredImage?.node?.sourceUrl && (
<a href={colonPost.uri}>
<img
src={colonPost.featuredImage.node.sourceUrl}
alt={colonPost.featuredImage.node.altText || colonPost.secondaryTitle || colonPost.title}
loading="lazy"
class="colon-post-image"
/>
</a>
)}
<div class="colon-post-meta">
<span>{new Date(colonPost.date).toLocaleDateString('ru-RU')}</span>
<div><Author post={colonPost} separator=", " /></div>
</div>
</div>
<div class="colon-post-right">
<a href={colonPost.uri}>
<h3>{colonPost.secondaryTitle || colonPost.title}</h3>
</a>
</div>
</div>
</div>
)}
<style>
.colon-post-card {
background: white;
border-radius: 8px;
overflow: hidden;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.colon-post-card:hover {
transform: translateY(-4px);
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
}
.colon-post-content {
display: flex;
gap: 20px;
padding: 20px;
align-items: flex-start;
}
.colon-post-left {
flex: 0 0 200px;
position: relative;
}
.colon-post-image-link {
display: block;
overflow: hidden;
border-radius: 6px;
margin-bottom: 10px;
}
.colon-post-image {
width: 100%;
height: 150px;
object-fit: cover;
transition: transform 0.3s ease;
}
.colon-post-image:hover {
transform: scale(1.05);
}
.colon-post-image-placeholder {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 150px;
background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
border-radius: 6px;
margin-bottom: 10px;
text-decoration: none;
}
.placeholder-text {
color: #666;
font-size: 14px;
}
.colon-post-meta {
display: flex;
align-items: center;
font-size: 12px;
color: #666;
line-height: 1.4;
}
.colon-post-date {
white-space: nowrap;
}
.meta-separator {
margin: 0 5px;
color: #ccc;
}
.colon-post-author {
white-space: nowrap;
}
.author-link {
color: #2c3e50;
text-decoration: none;
font-weight: 500;
}
.author-link:hover {
color: #3498db;
text-decoration: underline;
}
.colon-post-right {
flex: 1;
}
.colon-post-title-link {
text-decoration: none;
color: inherit;
display: block;
}
.colon-post-title {
margin: 0 0 10px 0;
font-size: 20px;
line-height: 1.4;
color: #2c3e50;
transition: color 0.3s ease;
}
.colon-post-title:hover {
color: #3498db;
}
.colon-post-secondary-title {
font-size: 16px;
color: #666;
line-height: 1.5;
font-weight: 400;
}
/* Адаптивность */
@media (max-width: 768px) {
.colon-post-content {
flex-direction: column;
gap: 15px;
}
.colon-post-left {
flex: 0 0 auto;
width: 100%;
}
.colon-post-image,
.colon-post-image-placeholder {
height: 200px;
}
.colon-post-title {
font-size: 18px;
}
.colon-post-secondary-title {
font-size: 15px;
}
}
</style>

View File

@@ -1,4 +1,7 @@
---
export interface Props {
items: any[];
showCount?: boolean;

View File

@@ -1,95 +1,191 @@
---
// src/components/MainPostWidget.astro
import { getLatestMainPost } from '@lib/api/main-posts';
import Author from '@components/AuthorDisplay.astro';
const mainPost = await getLatestMainPost();
const postDate = mainPost ? new Date(mainPost.date) : null;
if (!mainPost) return null;
const postDate = new Date(mainPost.date);
const imageUrl = mainPost?.featuredImage?.node?.sourceUrl;
const imageAlt = mainPost?.featuredImage?.node?.altText || mainPost?.title || '';
const isoDate = postDate.toISOString();
const category = mainPost?.categories?.nodes?.[0];
const categoryName = category?.name || '';
const categoryColor = category?.color || '#2271b1'; // цвет по умолчанию
const categoryColor = category?.color || '#2271b1';
const formattedDate = postDate.toLocaleDateString('ru-RU', {
day: 'numeric',
month: 'short',
year: 'numeric'
}).replace(' г.', '');
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 && (
<article class="main-post-card" itemscope itemtype="https://schema.org/Article">
<a href={mainPost.uri} class="post-card-link">
<div class="post-image-container">
{imageUrl ? (
<img
src={imageUrl}
alt={imageAlt}
width="400"
height="400"
loading="lazy"
class="post-image"
itemprop="image"
/>
) : (
<div class="post-image-placeholder"></div>
)}
{categoryName && (
<div
class="post-category-badge"
style={`background-color: ${categoryColor}; color: white;`}
>
{categoryName}
</div>
)}
<div class="post-content-overlay">
<div class="post-meta-overlay">
<time
datetime={mainPost.date}
class="post-date-overlay"
itemprop="datePublished"
>
{postDate && postDate.toLocaleDateString('ru-RU', {
day: 'numeric',
month: 'short',
year: 'numeric'
}).replace(' г.', '')}
</time>
</div>
<h3 class="post-title-overlay" itemprop="headline">
{mainPost.title}
</h3>
{authorName && (
<div class="author-name" itemprop="author">
{authorName}
</div>
)}
<article
class="main-post-widget"
itemscope
itemtype="https://schema.org/Article"
itemid={mainPost.uri}
>
<a
href={mainPost.uri}
class="post-card-link"
aria-label={`Читать статью: ${mainPost.title}`}
>
<div class="image-container">
{imageUrl ? (
<img
src={imageUrl}
alt={imageAlt}
width="800"
height="450"
loading="eager"
class="post-image"
itemprop="image"
/>
) : (
<div class="image-placeholder" aria-hidden="true"></div>
)}
{categoryName && (
<div
class="category-badge"
style={`background-color: ${categoryColor}`}
>
{categoryName}
</div>
)}
<div class="content-overlay">
<div class="meta-overlay">
<time datetime={isoDate} class="date-overlay">
{formattedDate}
</time>
</div>
<h2 class="title-overlay">
{mainPost.title}
</h2>
{authorName && (
<div class="author-overlay">
<Author post={mainPost} separator=" " />
</div>
)}
</div>
</a>
<div class="sr-only">
<h3 itemprop="headline">
<a href={mainPost.uri} itemprop="url">{mainPost.title}</a>
</h3>
<time datetime={mainPost.date} itemprop="datePublished">
{postDate && postDate.toLocaleDateString('ru-RU')}
</time>
</div>
</article>
)}
</a>
<meta itemprop="url" content={mainPost.uri} />
<meta itemprop="datePublished" content={isoDate} />
{authorName && <meta itemprop="author" content={authorName} />}
{categoryName && <meta itemprop="articleSection" content={categoryName} />}
</article>
<style>
/* ОСНОВНОЕ: ограничиваем ширину виджета */
.main-post-widget {
width: 100%;
max-width: 800px; /* Вот это ключевое правило! */
margin: 0 auto; /* Центрируем */
border-radius: 8px;
overflow: hidden;
background: white;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
.post-card-link {
display: block;
text-decoration: none;
color: inherit;
}
.image-container {
position: relative;
width: 100%;
aspect-ratio: 16/9;
overflow: hidden;
}
.post-image {
width: 100%;
height: 100%;
object-fit: cover;
transition: transform 0.3s ease;
}
.post-card-link:hover .post-image {
transform: scale(1.03);
}
.image-placeholder {
width: 100%;
height: 100%;
background: linear-gradient(135deg, #f5f5f5, #e0e0e0);
}
.category-badge {
position: absolute;
top: 16px;
left: 16px;
padding: 6px 12px;
border-radius: 4px;
font-size: 0.75rem;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.5px;
color: white;
z-index: 2;
line-height: 1;
}
.content-overlay {
position: absolute;
bottom: 0;
left: 0;
right: 0;
padding: 24px;
background: linear-gradient(transparent, rgba(0,0,0,0.7) 70%);
color: white;
z-index: 1;
}
.date-overlay {
font-size: 0.875rem;
opacity: 0.9;
display: block;
}
.title-overlay {
margin: 0 0 12px 0;
font-size: 1.5rem;
font-weight: 700;
line-height: 1.3;
color: white;
}
.author-overlay {
font-size: 0.875rem;
opacity: 0.9;
font-style: italic;
}
/* Адаптивность */
@media (max-width: 1023px) {
.main-post-widget {
border-radius: 0;
max-width: 100%; /* На мобильных занимает всю ширину */
}
.content-overlay {
padding: 16px;
}
.title-overlay {
font-size: 1.25rem;
}
}
</style>