add logic exclude
This commit is contained in:
@@ -1,8 +1,11 @@
|
||||
---
|
||||
import { getLatestColonPost } from '@lib/api/colon-posts';
|
||||
|
||||
import Author from '@components/AuthorDisplay.astro';
|
||||
|
||||
const colonPost = await getLatestColonPost();
|
||||
const {
|
||||
colonPost=[]
|
||||
} = Astro.props;
|
||||
|
||||
---
|
||||
|
||||
{colonPost && (
|
||||
@@ -42,150 +45,4 @@ const colonPost = await getLatestColonPost();
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<style>
|
||||
/* Основная карточка */
|
||||
.colon-post-card {
|
||||
background: #ececec;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
transition: transform 0.3s ease, box-shadow 0.3s ease;
|
||||
width: 100%;
|
||||
max-width: 800px; /* опционально, для демо */
|
||||
height: 200px; /* фиксированная высота карточки */
|
||||
}
|
||||
|
||||
.colon-post-card:hover {
|
||||
transform: translateY(-4px);
|
||||
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
/* Flex-контейнер: две части */
|
||||
.split-flex {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* ЛЕВЫЙ БЛОК: ровно 30% */
|
||||
.left-photo {
|
||||
flex: 0 0 34%; /* ширина 30%, не растягивается */
|
||||
height: 100%;
|
||||
background: #d4d4d4; /* фон, если нет фото */
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.photo-link {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.photo-img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover; /* заполняет контейнер, сохраняя пропорции и обрезаясь */
|
||||
display: block;
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
|
||||
.photo-img:hover {
|
||||
transform: scale(1.05); /* легкий эффект при наведении */
|
||||
}
|
||||
|
||||
.photo-placeholder {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
|
||||
}
|
||||
|
||||
/* ПРАВЫЙ БЛОК: 70% */
|
||||
.right-content {
|
||||
flex: 1; /* занимает оставшееся место (70%) */
|
||||
height: 100%;
|
||||
padding: 16px 20px; /* внутренние отступы */
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
/* Обёртка для контента, чтобы занять всю высоту и распределить пространство */
|
||||
.content-wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* Заголовок жирным */
|
||||
.bold-title {
|
||||
font-size: 1.125rem;
|
||||
font-weight: 700;
|
||||
line-height: 1.4;
|
||||
color: #2c3e50;
|
||||
margin: 0 0 8px 0;
|
||||
transition: color 0.3s ease;
|
||||
}
|
||||
|
||||
.title-link {
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.title-link:hover .bold-title {
|
||||
color: #3498db;
|
||||
}
|
||||
|
||||
/* Мета-строка: прижимаем к низу */
|
||||
.meta-line {
|
||||
font-size: 0.9rem;
|
||||
color: #666;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
margin-top: auto; /* это прижимает мету к низу */
|
||||
}
|
||||
|
||||
.separator {
|
||||
color: #aaa;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
.author :global(a) {
|
||||
color: #2c3e50;
|
||||
text-decoration: none;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.author :global(a:hover) {
|
||||
color: #3498db;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/* Адаптивность */
|
||||
@media (max-width: 600px) {
|
||||
.colon-post-card {
|
||||
height: auto;
|
||||
min-height: 180px;
|
||||
}
|
||||
|
||||
.left-photo {
|
||||
flex: 0 0 30%;
|
||||
aspect-ratio: 1 / 1; /* сохраняем квадрат на мобильных */
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.right-content {
|
||||
padding: 12px 16px;
|
||||
}
|
||||
|
||||
.bold-title {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* Если нужно точное соответствие макету, можно добавить медиа-запросы под свои нужды */
|
||||
</style>
|
||||
)}
|
||||
@@ -9,6 +9,7 @@ let menuItems = [];
|
||||
---
|
||||
|
||||
<header class="header" itemscope itemtype="https://schema.org/WPHeader">
|
||||
|
||||
<div class="top-bar">
|
||||
<a href="/"><img alt="Профиль" width="249" height="55" src="https://cdn.profile.ru/wp-content/themes/profile/assets/img/profile-logo-delovoy.svg"></a>
|
||||
|
||||
@@ -25,5 +26,6 @@ let menuItems = [];
|
||||
</div>
|
||||
|
||||
<MainMenu menuId={MENU_ID} />
|
||||
|
||||
</header>
|
||||
|
||||
|
||||
@@ -1,128 +1,26 @@
|
||||
---
|
||||
|
||||
// src/components/MainLine.astro
|
||||
import EndnewsList from '@components/EndnewsList.astro';
|
||||
import MainPostWidget from '@components/MainPostWidget.astro';
|
||||
import ColonPost from '@components/ColonPost.astro';
|
||||
|
||||
const {
|
||||
mainPost=[],
|
||||
colonPost=[]
|
||||
} = Astro.props;
|
||||
|
||||
---
|
||||
|
||||
<div class="three-col-block">
|
||||
<div class="left-col"><EndnewsList /></div>
|
||||
<div class="center-col">
|
||||
<div class="center-top"><MainPostWidget /></div>
|
||||
<div class="center-bottom"><ColonPost /></div>
|
||||
<div class="center-top">
|
||||
<MainPostWidget mainPost={mainPost}/>
|
||||
</div>
|
||||
<div class="center-bottom">
|
||||
<ColonPost colonPost={colonPost}/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="right-col">Правая колонка (260px)</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
/* Основной контейнер */
|
||||
.three-col-block {
|
||||
display: flex;
|
||||
margin: 30px 0;
|
||||
width: 100%;
|
||||
max-width: 1200px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
flex-wrap: nowrap;
|
||||
align-items: stretch; /* ВАЖНО: растягиваем все колонки на всю высоту */
|
||||
}
|
||||
|
||||
/* ЛЕВАЯ КОЛОНКА - фиксированная */
|
||||
.left-col {
|
||||
flex: 0 0 260px;
|
||||
min-width: 260px;
|
||||
max-width: 260px;
|
||||
box-sizing: border-box;
|
||||
display: flex; /* Добавляем flex для растягивания содержимого */
|
||||
}
|
||||
|
||||
.left-col > :deep(*) {
|
||||
width: 100%; /* Растягиваем компонент на всю ширину */
|
||||
height: 100%; /* Растягиваем компонент на всю высоту */
|
||||
}
|
||||
|
||||
/* ЦЕНТРАЛЬНАЯ КОЛОНКА - гибкая */
|
||||
.center-col {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
margin: 0 20px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.center-top, .center-bottom {
|
||||
#flex: 1 1 0; /* ВАЖНО: оба блока занимают равную высоту */
|
||||
background: #fff;
|
||||
box-sizing: border-box;
|
||||
overflow: hidden;
|
||||
word-wrap: break-word;
|
||||
display: flex; /* Для растягивания внутреннего содержимого */
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.center-top > :deep(*), .center-bottom > :deep(*) {
|
||||
width: 100%;
|
||||
flex: 1; /* Растягиваем компонент на всю доступную высоту */
|
||||
}
|
||||
|
||||
/* ПРАВАЯ КОЛОНКА - фиксированная */
|
||||
.right-col {
|
||||
flex: 0 0 260px;
|
||||
min-width: 260px;
|
||||
max-width: 260px;
|
||||
background: #f0f0f0;
|
||||
padding: 20px;
|
||||
box-sizing: border-box;
|
||||
display: flex; /* Добавляем flex для растягивания содержимого */
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.right-col > :deep(*) {
|
||||
width: 100%;
|
||||
flex: 1; /* Растягиваем контент на всю высоту */
|
||||
}
|
||||
|
||||
/* Ограничиваем контент внутри центральной колонки */
|
||||
.center-col > * {
|
||||
max-width: 100%;
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
|
||||
/* МОБИЛЬНАЯ ВЕРСИЯ */
|
||||
@media (max-width: 768px) {
|
||||
.three-col-block {
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
max-width: 100%;
|
||||
overflow: visible;
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
.left-col, .center-col, .right-col {
|
||||
flex: 1 1 100%;
|
||||
min-width: 100%;
|
||||
max-width: 100%;
|
||||
width: 100%;
|
||||
margin: 0 0 20px 0;
|
||||
}
|
||||
|
||||
.center-col {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.right-col{
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Сбрасываем flex свойства для мобильной версии */
|
||||
.left-col, .right-col {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.center-top, .center-bottom {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</div>
|
||||
@@ -1,11 +1,11 @@
|
||||
---
|
||||
// src/components/MainPostWidget.astro
|
||||
import { getLatestMainPost } from '@lib/api/main-posts';
|
||||
|
||||
import Author from '@components/AuthorDisplay.astro';
|
||||
import CategoryBadge from '@components/CategoryBadge.astro'; // цветная плитка рубрик
|
||||
|
||||
const mainPost = await getLatestMainPost();
|
||||
const {
|
||||
mainPost=[]
|
||||
} = Astro.props;
|
||||
|
||||
if (!mainPost) return null;
|
||||
|
||||
@@ -88,115 +88,3 @@ const formattedDate = postDate.toLocaleDateString('ru-RU', {
|
||||
{categoryName && <meta itemprop="articleSection" content={categoryName} />}
|
||||
</article>
|
||||
|
||||
<style>
|
||||
/* ОСНОВНОЕ: ограничиваем ширину виджета */
|
||||
.main-post-widget {
|
||||
width: 100%;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
background: white;
|
||||
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.image-container {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
aspect-ratio: 16/9;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.image-link {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.post-image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
|
||||
.image-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.625rem;
|
||||
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.4rem;
|
||||
font-weight: 700;
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
.title-link {
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
transition: opacity 0.2s ease;
|
||||
}
|
||||
|
||||
.title-link:hover {
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
.author-overlay {
|
||||
font-size: 0.875rem;
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
/* Адаптивность */
|
||||
@media (max-width: 1023px) {
|
||||
.main-post-widget {
|
||||
border-radius: 0;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.content-overlay {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.title-overlay {
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -11,101 +11,156 @@ export interface AnewsPost {
|
||||
date: string;
|
||||
}
|
||||
|
||||
export async function getLatestPosts(first = 14, after = null) {
|
||||
// Создаем уникальный ключ для кэша
|
||||
const cacheKey = `latest-posts:${first}:${after || 'first-page'}`;
|
||||
|
||||
|
||||
export async function getLatestPosts(first = 14, after = null, excludeIds = []) {
|
||||
// Нормализуем excludeIds - работаем только с databaseId (числа или строки)
|
||||
const excludeArray = Array.isArray(excludeIds)
|
||||
? excludeIds.filter(id => id != null).map(id => id.toString())
|
||||
: (excludeIds ? [excludeIds.toString()] : []);
|
||||
|
||||
// Создаем уникальный ключ для кэша с учетом исключений
|
||||
const excludeKey = excludeArray.length ? `exclude:${excludeArray.sort().join(',')}` : '';
|
||||
const cacheKey = `latest-posts:${first}:${after || 'first-page'}${excludeKey ? `:${excludeKey}` : ''}`;
|
||||
|
||||
return await cache.wrap(
|
||||
cacheKey,
|
||||
async () => {
|
||||
const query = `
|
||||
query GetLatestProfileArticles($first: Int!, $after: String) {
|
||||
profileArticles(
|
||||
first: $first
|
||||
after: $after
|
||||
where: { orderby: { field: DATE, order: DESC } }
|
||||
) {
|
||||
pageInfo {
|
||||
hasNextPage
|
||||
endCursor
|
||||
}
|
||||
edges {
|
||||
cursor
|
||||
node {
|
||||
id
|
||||
databaseId
|
||||
title
|
||||
uri
|
||||
date
|
||||
featuredImage {
|
||||
node {
|
||||
sourceUrl(size: LARGE)
|
||||
altText
|
||||
}
|
||||
}
|
||||
author {
|
||||
node {
|
||||
id
|
||||
name
|
||||
firstName
|
||||
lastName
|
||||
avatar {
|
||||
url
|
||||
// Функция для выполнения запроса
|
||||
const fetchPosts = async (limit, cursor) => {
|
||||
const query = `
|
||||
query GetLatestProfileArticles($first: Int!, $after: String) {
|
||||
profileArticles(
|
||||
first: $first
|
||||
after: $after
|
||||
where: { orderby: { field: DATE, order: DESC } }
|
||||
) {
|
||||
pageInfo {
|
||||
hasNextPage
|
||||
endCursor
|
||||
}
|
||||
edges {
|
||||
cursor
|
||||
node {
|
||||
databaseId
|
||||
title
|
||||
uri
|
||||
date
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
uri
|
||||
}
|
||||
}
|
||||
# Соавторы как массив
|
||||
coauthors {
|
||||
id
|
||||
name
|
||||
firstName
|
||||
lastName
|
||||
url
|
||||
description
|
||||
}
|
||||
categories {
|
||||
nodes {
|
||||
id
|
||||
name
|
||||
color
|
||||
slug
|
||||
uri
|
||||
databaseId
|
||||
}
|
||||
}
|
||||
tags {
|
||||
nodes {
|
||||
id
|
||||
name
|
||||
slug
|
||||
uri
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
`;
|
||||
|
||||
return await fetchGraphQL(query, { first: limit, after: cursor });
|
||||
};
|
||||
|
||||
const data = await fetchGraphQL(query, { first, after });
|
||||
// Если нет исключений, просто возвращаем результат
|
||||
if (excludeArray.length === 0) {
|
||||
const data = await fetchPosts(first, after);
|
||||
const posts = data.profileArticles?.edges?.map(edge => edge.node) || [];
|
||||
|
||||
return {
|
||||
posts,
|
||||
pageInfo: data.profileArticles?.pageInfo || { hasNextPage: false, endCursor: null }
|
||||
};
|
||||
}
|
||||
|
||||
// Логика с исключениями - дозагружаем недостающие
|
||||
let allPosts = [];
|
||||
let currentAfter = after;
|
||||
let hasMore = true;
|
||||
let totalNeeded = first;
|
||||
|
||||
// Преобразуем edges в nodes
|
||||
const posts = data.profileArticles?.edges?.map(edge => edge.node) || [];
|
||||
// Продолжаем загрузку пока не наберем нужное количество или не кончатся посты
|
||||
while (allPosts.length < totalNeeded && hasMore) {
|
||||
// Запрашиваем с запасом, чтобы компенсировать исключения
|
||||
const fetchLimit = Math.max(totalNeeded - allPosts.length + excludeArray.length, 1);
|
||||
|
||||
const data = await fetchPosts(fetchLimit, currentAfter);
|
||||
const edges = data.profileArticles?.edges || [];
|
||||
const pageInfo = data.profileArticles?.pageInfo;
|
||||
|
||||
// Фильтруем исключенные ID - сравниваем ТОЛЬКО databaseId
|
||||
const newPosts = edges
|
||||
.map(edge => edge.node)
|
||||
.filter(node => !excludeArray.includes(node.databaseId?.toString()));
|
||||
|
||||
allPosts = [...allPosts, ...newPosts];
|
||||
|
||||
// Обновляем курсор для следующей страницы
|
||||
currentAfter = pageInfo?.endCursor;
|
||||
hasMore = pageInfo?.hasNextPage && edges.length > 0;
|
||||
|
||||
// Защита от бесконечного цикла (если что-то пошло не так)
|
||||
if (edges.length === 0) break;
|
||||
}
|
||||
|
||||
// Обрезаем до нужного количества
|
||||
const finalPosts = allPosts.slice(0, first);
|
||||
|
||||
// Определяем, есть ли еще страницы
|
||||
const hasNextPage = allPosts.length > first || hasMore;
|
||||
|
||||
return {
|
||||
posts,
|
||||
pageInfo: data.profileArticles?.pageInfo || { hasNextPage: false, endCursor: null }
|
||||
posts: finalPosts,
|
||||
pageInfo: {
|
||||
hasNextPage,
|
||||
endCursor: currentAfter // Последний использованный курсор
|
||||
}
|
||||
};
|
||||
},
|
||||
{ ttl: CACHE_TTL.POSTS } // из конфигурации
|
||||
{ ttl: CACHE_TTL.POSTS }
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
export async function getPostsByCategory(slug, first = 14, after = null) {
|
||||
// Создаем уникальный ключ для кэша
|
||||
const cacheKey = `category-posts:${slug}:${first}:${after || 'first-page'}`;
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
import ContentLayout from '@layouts/ContentLayout.astro';
|
||||
import ContentGrid from '@components/ContentGrid.astro';
|
||||
|
||||
import { getLatestPosts } from '@api/posts.js';
|
||||
import { getLatestPosts } from '@api/posts';
|
||||
|
||||
const { posts, pageInfo } = await getLatestPosts(41); // Сразу деструктурируем
|
||||
const { posts, pageInfo } = await getLatestPosts(41);
|
||||
|
||||
|
||||
//ISR
|
||||
|
||||
@@ -1,15 +1,10 @@
|
||||
---
|
||||
import { getSiteInfo } from "../lib/wp-api.js";
|
||||
import { getLatestPosts } from '@api/posts.js';
|
||||
|
||||
import { fetchWPRestGet } from "../lib/api/wp-rest-get-client";
|
||||
|
||||
|
||||
import '../styles/home.css';
|
||||
|
||||
const site = await getSiteInfo();
|
||||
const { posts, pageInfo } = await getLatestPosts(41); // Сразу деструктурируем
|
||||
import { getSiteInfo } from "@lib/wp-api.js";
|
||||
import { getLatestPosts } from '@api/posts';
|
||||
import { getLatestMainPost } from '@lib/api/main-posts';
|
||||
import { getLatestColonPost } from '@lib/api/colon-posts';
|
||||
|
||||
import { fetchWPRestGet } from "@lib/api/wp-rest-get-client";
|
||||
|
||||
// визуальные компоненты
|
||||
import MainLayout from '@layouts/MainLayout.astro';
|
||||
@@ -19,6 +14,39 @@ import MainLine from '@components/MainLine.astro';
|
||||
import HomeNews from "@components/HomeNews.astro";
|
||||
|
||||
|
||||
//import '../styles/home.css';
|
||||
import '../styles/main.css';
|
||||
|
||||
|
||||
//получаем главный пост
|
||||
const mainPost = await getLatestMainPost();
|
||||
const mainPostId = mainPost?.databaseId;
|
||||
|
||||
//колонка
|
||||
const colonPost = await getLatestColonPost();
|
||||
const colonPostId = mainPost?.databaseId;
|
||||
|
||||
|
||||
// Создаем массив исключений
|
||||
const excludeIds = [];
|
||||
|
||||
// Добавляем ID если они существуют
|
||||
if (mainPostId) {
|
||||
excludeIds.push(mainPostId);
|
||||
}
|
||||
|
||||
if (colonPostId) {
|
||||
excludeIds.push(colonPostId);
|
||||
}
|
||||
|
||||
|
||||
|
||||
const site = await getSiteInfo();
|
||||
const { posts, pageInfo } = await getLatestPosts(41, null, excludeIds ); // Сразу деструктурируем
|
||||
|
||||
|
||||
|
||||
|
||||
//ISR
|
||||
export const prerender = false;
|
||||
---
|
||||
@@ -30,7 +58,10 @@ export const prerender = false;
|
||||
|
||||
<!-- index.astro -->
|
||||
|
||||
<MainLine />
|
||||
<MainLine
|
||||
mainPost={mainPost}
|
||||
colonPost={colonPost}
|
||||
/>excludeIds
|
||||
|
||||
|
||||
<ContentGrid
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
---
|
||||
|
||||
import ContentLayout from '@layouts/ContentLayout.astro';
|
||||
import ContentGrid from '@components/ContentGrid.astro';
|
||||
|
||||
import { getLatestAnews } from '@api/posts';
|
||||
|
||||
const { posts, pageInfo } = await getLatestAnews(41);
|
||||
|
||||
---
|
||||
|
||||
@@ -9,4 +14,15 @@ import ContentLayout from '@layouts/ContentLayout.astro';
|
||||
description=Новости
|
||||
>
|
||||
<h1>Все новости</h1>
|
||||
|
||||
<ContentGrid
|
||||
items={posts}
|
||||
pageInfo={pageInfo}
|
||||
type="latest"
|
||||
gridColumns={3}
|
||||
perLoad={11}
|
||||
showCount={false}
|
||||
/>
|
||||
|
||||
|
||||
</MainLayout>
|
||||
141
src/styles/components/colon-post.css
Normal file
141
src/styles/components/colon-post.css
Normal file
@@ -0,0 +1,141 @@
|
||||
/* Основная карточка */
|
||||
.colon-post-card {
|
||||
background: #ececec;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
transition: transform 0.3s ease, box-shadow 0.3s ease;
|
||||
width: 100%;
|
||||
max-width: 800px; /* опционально, для демо */
|
||||
height: 200px; /* фиксированная высота карточки */
|
||||
}
|
||||
|
||||
.colon-post-card:hover {
|
||||
transform: translateY(-4px);
|
||||
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
/* Flex-контейнер: две части */
|
||||
.split-flex {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* ЛЕВЫЙ БЛОК: ровно 30% */
|
||||
.left-photo {
|
||||
flex: 0 0 34%; /* ширина 30%, не растягивается */
|
||||
height: 100%;
|
||||
background: #d4d4d4; /* фон, если нет фото */
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.photo-link {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.photo-img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover; /* заполняет контейнер, сохраняя пропорции и обрезаясь */
|
||||
display: block;
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
|
||||
.photo-img:hover {
|
||||
transform: scale(1.05); /* легкий эффект при наведении */
|
||||
}
|
||||
|
||||
.photo-placeholder {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
|
||||
}
|
||||
|
||||
/* ПРАВЫЙ БЛОК: 70% */
|
||||
.right-content {
|
||||
flex: 1; /* занимает оставшееся место (70%) */
|
||||
height: 100%;
|
||||
padding: 16px 20px; /* внутренние отступы */
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
/* Обёртка для контента, чтобы занять всю высоту и распределить пространство */
|
||||
.content-wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* Заголовок жирным */
|
||||
.bold-title {
|
||||
font-size: 1.125rem;
|
||||
font-weight: 700;
|
||||
line-height: 1.4;
|
||||
color: #2c3e50;
|
||||
margin: 0 0 8px 0;
|
||||
transition: color 0.3s ease;
|
||||
}
|
||||
|
||||
.title-link {
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.title-link:hover .bold-title {
|
||||
color: #3498db;
|
||||
}
|
||||
|
||||
/* Мета-строка: прижимаем к низу */
|
||||
.meta-line {
|
||||
font-size: 0.9rem;
|
||||
color: #666;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
margin-top: auto; /* это прижимает мету к низу */
|
||||
}
|
||||
|
||||
.separator {
|
||||
color: #aaa;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
.author :global(a) {
|
||||
color: #2c3e50;
|
||||
text-decoration: none;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.author :global(a:hover) {
|
||||
color: #3498db;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/* Адаптивность */
|
||||
@media (max-width: 600px) {
|
||||
.colon-post-card {
|
||||
height: auto;
|
||||
min-height: 180px;
|
||||
}
|
||||
|
||||
.left-photo {
|
||||
flex: 0 0 30%;
|
||||
aspect-ratio: 1 / 1; /* сохраняем квадрат на мобильных */
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.right-content {
|
||||
padding: 12px 16px;
|
||||
}
|
||||
|
||||
.bold-title {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
}
|
||||
110
src/styles/components/main-post-widget.css
Normal file
110
src/styles/components/main-post-widget.css
Normal file
@@ -0,0 +1,110 @@
|
||||
/* ОСНОВНОЕ: ограничиваем ширину виджета */
|
||||
.main-post-widget {
|
||||
width: 100%;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
background: white;
|
||||
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.image-container {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
aspect-ratio: 16/9;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.image-link {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.post-image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
|
||||
.image-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.625rem;
|
||||
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.4rem;
|
||||
font-weight: 700;
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
.title-link {
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
transition: opacity 0.2s ease;
|
||||
}
|
||||
|
||||
.title-link:hover {
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
.author-overlay {
|
||||
font-size: 0.875rem;
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
/* Адаптивность */
|
||||
@media (max-width: 1023px) {
|
||||
.main-post-widget {
|
||||
border-radius: 0;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.content-overlay {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.title-overlay {
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
}
|
||||
110
src/styles/components/mainline.css
Normal file
110
src/styles/components/mainline.css
Normal file
@@ -0,0 +1,110 @@
|
||||
/* Основной контейнер */
|
||||
.three-col-block {
|
||||
display: flex;
|
||||
margin: 30px 0;
|
||||
width: 100%;
|
||||
max-width: 1200px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
flex-wrap: nowrap;
|
||||
align-items: stretch; /* ВАЖНО: растягиваем все колонки на всю высоту */
|
||||
}
|
||||
|
||||
/* ЛЕВАЯ КОЛОНКА - фиксированная */
|
||||
.left-col {
|
||||
flex: 0 0 260px;
|
||||
min-width: 260px;
|
||||
max-width: 260px;
|
||||
box-sizing: border-box;
|
||||
display: flex; /* Добавляем flex для растягивания содержимого */
|
||||
}
|
||||
|
||||
.left-col > :deep(*) {
|
||||
width: 100%; /* Растягиваем компонент на всю ширину */
|
||||
height: 100%; /* Растягиваем компонент на всю высоту */
|
||||
}
|
||||
|
||||
/* ЦЕНТРАЛЬНАЯ КОЛОНКА - гибкая */
|
||||
.center-col {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
margin: 0 20px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.center-top, .center-bottom {
|
||||
#flex: 1 1 0; /* ВАЖНО: оба блока занимают равную высоту */
|
||||
background: #fff;
|
||||
box-sizing: border-box;
|
||||
overflow: hidden;
|
||||
word-wrap: break-word;
|
||||
display: flex; /* Для растягивания внутреннего содержимого */
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.center-top > :deep(*), .center-bottom > :deep(*) {
|
||||
width: 100%;
|
||||
flex: 1; /* Растягиваем компонент на всю доступную высоту */
|
||||
}
|
||||
|
||||
/* ПРАВАЯ КОЛОНКА - фиксированная */
|
||||
.right-col {
|
||||
flex: 0 0 260px;
|
||||
min-width: 260px;
|
||||
max-width: 260px;
|
||||
background: #f0f0f0;
|
||||
padding: 20px;
|
||||
box-sizing: border-box;
|
||||
display: flex; /* Добавляем flex для растягивания содержимого */
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.right-col > :deep(*) {
|
||||
width: 100%;
|
||||
flex: 1; /* Растягиваем контент на всю высоту */
|
||||
}
|
||||
|
||||
/* Ограничиваем контент внутри центральной колонки */
|
||||
.center-col > * {
|
||||
max-width: 100%;
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
|
||||
/* МОБИЛЬНАЯ ВЕРСИЯ */
|
||||
@media (max-width: 768px) {
|
||||
.three-col-block {
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
max-width: 100%;
|
||||
overflow: visible;
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
.left-col, .center-col, .right-col {
|
||||
flex: 1 1 100%;
|
||||
min-width: 100%;
|
||||
max-width: 100%;
|
||||
width: 100%;
|
||||
margin: 0 0 20px 0;
|
||||
}
|
||||
|
||||
.center-col {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.right-col{
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Сбрасываем flex свойства для мобильной версии */
|
||||
.left-col, .right-col {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.center-top, .center-bottom {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,10 @@
|
||||
@import './ContentLayout.css';
|
||||
@import './header.css';
|
||||
@import './mainmenu.css';
|
||||
@import './article.css';
|
||||
@import './mainmenu.css';
|
||||
@import './components/mainline.css';
|
||||
@import './components/colon-post.css';
|
||||
@import './components/main-post-widget.css';
|
||||
@import './footer.css';
|
||||
@import './embedded-content.css';
|
||||
@import './components/ContentGrid.css';
|
||||
|
||||
Reference in New Issue
Block a user