add shared buttons in post

This commit is contained in:
Profile Profile
2026-02-18 01:02:01 +03:00
parent abcc214ef6
commit 9e32f4f064
11 changed files with 687 additions and 276 deletions

View File

@@ -3,45 +3,57 @@ 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}>
<div class="split-flex">
<!-- ЛЕВЫЙ БЛОК: 30% ширины, фото впритык -->
<div class="left-photo">
{colonPost.featuredImage?.node?.sourceUrl ? (
<a href={colonPost.uri} class="photo-link">
<img
src={colonPost.featuredImage.node.sourceUrl}
alt={colonPost.featuredImage.node.altText || colonPost.secondaryTitle || colonPost.title}
loading="lazy"
class="colon-post-image"
class="photo-img"
/>
</a>
) : (
<div class="photo-placeholder"></div>
)}
<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>
<!-- ПРАВЫЙ БЛОК: 70% ширины, заголовок сверху, дата|автор снизу -->
<div class="right-content">
<div class="content-wrapper">
<!-- Заголовок жирным сверху -->
<a href={colonPost.uri} class="title-link">
<h3 class="bold-title">{colonPost.secondaryTitle || colonPost.title}</h3>
</a>
<!-- Мета-информация внизу: дата | автор -->
<div class="meta-line">
<span class="date">{new Date(colonPost.date).toLocaleDateString('ru-RU')}</span>
<span class="separator">|</span>
<span class="author"><Author post={colonPost} separator=", " /></span>
</div>
</div>
</div>
</div>
</div>
)}
<style>
/* Основная карточка */
.colon-post-card {
background: white;
background: #ececec;
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;
width: 100%;
max-width: 800px; /* опционально, для демо */
height: 200px; /* фиксированная высота карточки */
}
.colon-post-card:hover {
@@ -49,137 +61,131 @@ const colonPost = await getLatestColonPost();
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
}
.colon-post-content {
/* Flex-контейнер: две части */
.split-flex {
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 {
height: 100%;
width: 100%;
height: 150px;
object-fit: cover;
transition: transform 0.3s ease;
}
.colon-post-image:hover {
transform: scale(1.05);
}
.colon-post-image-placeholder {
/* ЛЕВЫЙ БЛОК: ровно 30% */
.left-photo {
flex: 0 0 34%; /* ширина 30%, не растягивается */
height: 100%;
background: #d4d4d4; /* фон, если нет фото */
display: flex;
}
.photo-link {
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;
height: 100%;
text-decoration: none;
}
.placeholder-text {
color: #666;
font-size: 14px;
.photo-img {
width: 100%;
height: 100%;
object-fit: cover; /* заполняет контейнер, сохраняя пропорции и обрезаясь */
display: block;
transition: transform 0.3s ease;
}
.colon-post-meta {
.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;
align-items: center;
font-size: 12px;
color: #666;
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;
}
.colon-post-date {
white-space: nowrap;
.title-link {
text-decoration: none;
color: inherit;
}
.meta-separator {
margin: 0 5px;
color: #ccc;
.title-link:hover .bold-title {
color: #3498db;
}
.colon-post-author {
white-space: nowrap;
/* Мета-строка: прижимаем к низу */
.meta-line {
font-size: 0.9rem;
color: #666;
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 0.5rem;
margin-top: auto; /* это прижимает мету к низу */
}
.author-link {
.separator {
color: #aaa;
font-weight: 300;
}
.author :global(a) {
color: #2c3e50;
text-decoration: none;
font-weight: 500;
}
.author-link:hover {
.author :global(a: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;
@media (max-width: 600px) {
.colon-post-card {
height: auto;
min-height: 180px;
}
.colon-post-left {
flex: 0 0 auto;
width: 100%;
.left-photo {
flex: 0 0 30%;
aspect-ratio: 1 / 1; /* сохраняем квадрат на мобильных */
height: auto;
}
.colon-post-image,
.colon-post-image-placeholder {
height: 200px;
.right-content {
padding: 12px 16px;
}
.colon-post-title {
font-size: 18px;
.bold-title {
font-size: 1.1rem;
}
}
.colon-post-secondary-title {
font-size: 15px;
}
}
/* Если нужно точное соответствие макету, можно добавить медиа-запросы под свои нужды */
</style>

View File

@@ -2,7 +2,6 @@
import { getLatestAnews } from '../lib/api/posts.js';
import { fetchWPRestGet } from "@/lib/api/wp-rest-get-client";
// Даты/время
function formatDate(dateString: string): string {
const date = new Date(dateString);
@@ -51,118 +50,129 @@ const hasNews = newsPosts.length > 0;
const hasTop = topPosts.length > 0;
// По умолчанию открываем вкладку, где есть данные
const defaultTab: "news" | "top" = hasTop ? "top" : "news";
const defaultTab: "news" | "top" = hasNews ? "news" : "top";
---
{(hasNews || hasTop) && (
<div class="endnews-container">
<div class="endnews-header">
<h4 class="endnews-title">Новости</h4>
</div>
{/* Radio-кнопки ВНЕ .endnews-tabs для работы CSS-селекторов */}
<input
class="endnews-tab-input"
type="radio"
name="endnews-tab"
id="endnews-tab-news"
checked={defaultTab === "news"}
/>
<input
class="endnews-tab-input"
type="radio"
name="endnews-tab"
id="endnews-tab-top"
checked={defaultTab === "top"}
/>
{/* Только labels в блоке табов */}
<div class="endnews-container" id="endnews-container">
{/* Табы на всю ширину, каждый по 50% - теперь div'ы */}
<div class="endnews-tabs">
<label class="endnews-tab-label" for="endnews-tab-news">Новости</label>
<label class="endnews-tab-label" for="endnews-tab-top">Топ10</label>
<div class={`endnews-tab-label ${defaultTab === 'news' ? 'active' : ''}`} data-tab="news">Новости</div>
<div class={`endnews-tab-label ${defaultTab === 'top' ? 'active' : ''}`} data-tab="top">Топ10</div>
</div>
{/* Контент: две панели, показываем нужную через :checked */}
{/* Контент: две панели */}
<div class="latestnews-list">
<section class="endnews-panel endnews-panel--news" aria-label="Новости">
<section class={`endnews-panel endnews-panel--news ${defaultTab === 'news' ? 'active' : ''}`} aria-label="Новости">
{Object.entries(groupedNews).map(([dateKey, datePosts]) => (
<div class="latestnews-date-group" key={dateKey}>
<div class="latestnews-date">{formatDate(dateKey + 'T00:00:00')}</div>
{/* Переделано в ul > li */}
<ul class="latestnews-items">
{datePosts.map((post) => (
<article class="lastnews-item" key={post.uri}>
<li class="lastnews-item" key={post.uri}>
<div class="lastnews-time">{formatTime(post.date)}</div>
<div class="lastnews-content">
<a href={post.uri || '#'} class="endnews-link">
{post.title}
</a>
</div>
</article>
</li>
))}
</ul>
</div>
))}
</section>
<section class="endnews-panel endnews-panel--top" aria-label="Топ-10">
<section class={`endnews-panel endnews-panel--top ${defaultTab === 'top' ? 'active' : ''}`} aria-label="Топ-10">
{topPosts.length > 0 ? (
<ul class="latestnews-items top-items">
{topPosts.map((post, i) => (
<article class="lastnews-item" key={(post.uri ?? post.link ?? post.title) + i}>
<div class="ltopnews-content">
<li class="lastnews-item top-item" key={(post.uri ?? post.link ?? post.title) + i}>
<div class="lastnews-content">
<a href={post.uri ?? post.link ?? '#'} class="endnews-link">
{post.title}
</a>
</div>
</article>
</li>
))}
{!hasTop && <div class="endnews-empty">Топ пока пуст</div>}
</ul>
) : (
<div class="endnews-empty">Топ пока пуст</div>
)}
</section>
</div>
</div>
)}
<script>
document.addEventListener('DOMContentLoaded', () => {
const container = document.getElementById('endnews-container');
if (!container) return;
const tabs = container.querySelectorAll('.endnews-tab-label');
const panels = {
news: container.querySelector('.endnews-panel--news'),
top: container.querySelector('.endnews-panel--top')
};
tabs.forEach(tab => {
tab.addEventListener('click', () => {
const tabName = tab.dataset.tab;
// Обновляем классы на табах
tabs.forEach(t => t.classList.remove('active'));
tab.classList.add('active');
// Обновляем классы на панелях
Object.values(panels).forEach(panel => {
if (panel) panel.classList.remove('active');
});
if (panels[tabName]) panels[tabName].classList.add('active');
});
});
});
</script>
<style>
.endnews-container { width:100%; }
.endnews-header{
padding:12px 16px;
background:#B61D1D;
border-radius:6px 6px 0 0;
}
.endnews-title{ color:#fff; margin:0; font-size:1.1rem; font-weight:600; }
/* Скрываем radio-кнопки */
.endnews-tab-input{
position:absolute;
opacity:0;
pointer-events:none;
}
/* Tabs */
/* Tabs на всю ширину */
.endnews-tabs{
display:flex;
gap:8px;
padding:10px 12px;
border:1px solid #ECECEC;
border-top:none;
background:#fff;
}
.endnews-tab-label{
cursor:pointer;
user-select:none;
font-size:0.85rem;
font-weight:700;
padding:8px 10px;
border-radius:6px;
background:#f5f5f5;
color:#505258;
transition: background 0.2s, color 0.2s;
width:100%;
background: #ECECEC;
border-radius: 6px 6px 0 0;
overflow: hidden;
}
/* Активный таб - используем общий сиблинг-селектор */
#endnews-tab-news:checked ~ .endnews-tabs label[for="endnews-tab-news"],
#endnews-tab-top:checked ~ .endnews-tabs label[for="endnews-tab-top"]{
background:#B61D1D;
color:#fff;
.endnews-tab-label{
flex: 1 1 0;
width: 50%;
min-width: 50%;
max-width: 50%;
cursor:pointer;
user-select:none;
font-size:0.95rem;
font-weight:400;
padding:12px 10px;
text-align: center;
background: #ECECEC;
color: #BFBFBF;
transition: background 0.2s, color 0.2s, font-weight 0.2s, border 0.2s;
box-sizing: border-box;
border: 1px solid transparent;
border-bottom: none;
}
/* Активный таб - черный жирный на белом фоне */
.endnews-tab-label.active{
background: #FFFFFF;
color: #000000;
font-weight: 700;
border: 1px solid #ECECEC;
border-bottom: none;
}
/* list container */
@@ -171,17 +181,40 @@ const defaultTab: "news" | "top" = hasTop ? "top" : "news";
border-top:none;
border-radius:0 0 6px 6px;
background:#fff;
overflow-y: auto;
overflow-x: hidden;
scrollbar-width: none;
-ms-overflow-style: none;
}
/* Скрываем скроллбар */
.latestnews-list::-webkit-scrollbar {
display: none;
}
/* Панели скрыты по умолчанию */
.endnews-panel{ display:none; }
/* Показываем нужную панель по выбранному radio */
#endnews-tab-news:checked ~ .latestnews-list .endnews-panel--news{ display:block; }
#endnews-tab-top:checked ~ .latestnews-list .endnews-panel--top { display:block; }
/* Показываем активную панель */
.endnews-panel.active{ display:block; }
/* Существующий стиль списка */
.latestnews-date-group{ padding:12px 16px; border-bottom:1px solid #f0f0f0; }
/* Стили для списка */
.latestnews-items {
list-style: none;
margin: 0;
padding: 0;
}
.latestnews-items li{
font-size: 0.8125rem;
line-height: 1.2;
font-weight: 500;
}
.latestnews-date-group{
padding:12px 16px;
border-bottom:1px solid #f0f0f0;
}
.latestnews-date-group:last-child{ border-bottom:none; }
.latestnews-date{
@@ -212,6 +245,46 @@ const defaultTab: "news" | "top" = hasTop ? "top" : "news";
margin-top:1px;
}
/* Стили для топ-новостей */
.top-items {
padding: 8px 0 0 0;
}
.top-item {
position: relative;
padding: 10px 0 10px 16px;
margin: 0;
border-bottom: 1px solid #f0f0f0;
gap: 0;
}
.top-item:last-child {
border-bottom: none;
}
.top-item::before {
content: '';
background: #b51d1d;
width: 3px;
height: 20px;
position: absolute;
top: 50%;
left: 0;
-webkit-transform: translate(0, -50%);
-ms-transform: translate(0,-50%);
transform: translate(0, -50%);
}
.top-item .lastnews-content {
margin-left: 0;
padding-right: 16px;
}
.lastnews-time-top{
min-width:2.5rem;
flex-shrink:0;
}
.lastnews-content{
line-height:1.3;
font-weight:500;
@@ -221,18 +294,6 @@ const defaultTab: "news" | "top" = hasTop ? "top" : "news";
flex:1;
}
.topnews-content{
line-height:1.3;
font-weight:500;
font-size:0.9em;
color:#000;
transition:color 0.2s;
margin-left: 4px;
}
.endnews-link{ color:inherit; text-decoration:none; display:block; }
.endnews-link:hover{ color:#B61D1D; }
@@ -244,14 +305,36 @@ const defaultTab: "news" | "top" = hasTop ? "top" : "news";
}
.endnews-empty{ padding:12px 16px; color:#6b6d72; font-size:0.85rem; }
/* Десктоп скролл */
/* Десктоп версия */
@media (min-width:1024px){
.endnews-container{ height:500px; display:flex; flex-direction:column; }
.latestnews-list{ flex:1; overflow-y:auto; overflow-x:hidden; }
.latestnews-list{ flex:1; }
}
/* Мобильная версия */
@media (max-width:1023px){
.endnews-container{ height:auto; }
.latestnews-list{ overflow:visible; }
/* Скрываем вкладку Топ-10 на мобильных */
.endnews-tab-label[data-tab="top"] {
display: none;
}
/* Оставляем только вкладку Новости на всю ширину */
.endnews-tab-label[data-tab="news"] {
width: 100%;
max-width: 100%;
min-width: 100%;
}
/* На мобильных всегда показываем панель новостей */
.endnews-panel--top {
display: none !important;
}
.endnews-panel--news {
display: block !important;
}
}
</style>

View File

@@ -17,8 +17,24 @@ if (!menu) {
---
<nav class="primary-nav" aria-label="Main navigation">
<div class="primary-nav__wrapper">
<div class="primary-nav__content">
<button class="primary-nav__burger" aria-label="Toggle menu"></button>
<!-- Логотип для фиксированного меню -->
<div class="primary-nav__logo-scroll">
<a href="/" aria-label="На главную">
<img
alt="Профиль"
width="120"
height="27"
src="https://cdn.profile.ru/wp-content/themes/profile/assets/img/profile-logo-delovoy.svg"
class="primary-nav__logo-image"
/>
</a>
</div>
<ul class="primary-nav__list">
{menu.menuItems.nodes.map(item => {
const colorClass = item.menuItemColor ? `color-${item.menuItemColor}` : 'color-black';
@@ -36,6 +52,7 @@ if (!menu) {
})}
</ul>
</div>
</div>
</nav>
<BurgerMenu colorMenuId={103246} standardMenuId={103247} submenuId={3341} />
@@ -43,16 +60,88 @@ if (!menu) {
<style>
.primary-nav {
margin: 12px 0;
position: relative;
border-top: 1px solid black;
border-bottom: 1px solid black;
background-color: white;
width: 100%;
transition: all 0.3s ease;
z-index: 1000;
}
/* Стили только для десктопа */
@media (min-width: 768px) {
.primary-nav.fixed {
position: fixed;
top: 0;
left: 0;
right: 0;
margin: 0;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
/* Добавляем отступ для контента, когда меню фиксированное */
.primary-nav.fixed + * {
margin-top: 60px;
}
}
/* Обертка для центрирования контента */
.primary-nav__wrapper {
width: 100%;
background-color: white;
}
/* При фиксированном меню обертка тоже фиксируется */
@media (min-width: 768px) {
.primary-nav.fixed .primary-nav__wrapper {
max-width: 1200px;
margin: 0 auto;
width: 100%;
padding: 0 20px; /* Добавляем отступы по бокам */
box-sizing: border-box;
}
}
.primary-nav__content {
display: flex;
align-items: stretch;
position: relative;
min-height: 48px;
width: 100%;
margin: 0 auto;
}
/* Для десктопа добавляем ограничение ширины */
@media (min-width: 768px) {
.primary-nav__content {
max-width: 1200px;
}
}
/* Стили для логотипа, появляющегося при скролле */
.primary-nav__logo-scroll {
display: none;
opacity: 0;
transition: opacity 0.3s ease;
margin-right: 20px;
flex-shrink: 0;
}
/* Показываем логотип только когда меню фиксированное и на десктопе */
@media (min-width: 768px) {
.primary-nav.fixed .primary-nav__logo-scroll {
display: flex;
align-items: center;
opacity: 1;
margin-left: 12px;
}
}
.primary-nav__logo-image {
display: block;
width: auto;
height: 27px;
}
.primary-nav__burger {
@@ -112,3 +201,89 @@ if (!menu) {
}
}
</style>
<script>
(function() {
document.addEventListener('DOMContentLoaded', function() {
const primaryNav = document.querySelector('.primary-nav');
const header = document.querySelector('.header');
if (!primaryNav || !header) return;
// Проверяем, что это десктоп
let isDesktop = window.innerWidth >= 768;
// Убираем ранний return, чтобы эффект мог включаться/выключаться при ресайзе
// Создаем плейсхолдер для сохранения места при фиксированном меню
const placeholder = document.createElement('div');
placeholder.className = 'primary-nav-placeholder';
placeholder.style.display = 'none';
placeholder.style.height = primaryNav.offsetHeight + 'px';
placeholder.style.width = '100%';
placeholder.style.backgroundColor = 'transparent';
// Вставляем плейсхолдер после меню
if (primaryNav.parentNode) {
primaryNav.parentNode.insertBefore(placeholder, primaryNav.nextSibling);
}
function handleScroll() {
// Применяем эффект только на десктопе
if (!isDesktop) return;
const topBar = document.querySelector('.top-bar');
if (!topBar) return;
const topBarHeight = topBar.offsetHeight;
const scrollPosition = window.scrollY;
if (scrollPosition > topBarHeight) {
if (!primaryNav.classList.contains('fixed')) {
primaryNav.classList.add('fixed');
if (placeholder.parentNode) {
placeholder.style.display = 'block';
// Обновляем высоту плейсхолдера
placeholder.style.height = primaryNav.offsetHeight + 'px';
}
}
} else {
if (primaryNav.classList.contains('fixed')) {
primaryNav.classList.remove('fixed');
if (placeholder.parentNode) {
placeholder.style.display = 'none';
}
}
}
}
window.addEventListener('scroll', handleScroll);
// Вызываем сразу для правильного начального состояния
handleScroll();
// Обновляем при изменении размера окна
window.addEventListener('resize', function() {
const newIsDesktop = window.innerWidth >= 768;
if (newIsDesktop !== isDesktop) {
isDesktop = newIsDesktop;
if (!isDesktop) {
// Стали мобильным - убираем эффект
primaryNav.classList.remove('fixed');
if (placeholder.parentNode) {
placeholder.style.display = 'none';
}
} else {
// Стали десктопом - проверяем скролл
handleScroll();
}
}
if (primaryNav.classList.contains('fixed')) {
placeholder.style.height = primaryNav.offsetHeight + 'px';
}
});
});
})();
</script>

View File

@@ -136,7 +136,7 @@ const formattedDate = postDate.toLocaleDateString('ru-RU', {
left: 16px;
padding: 6px 12px;
border-radius: 4px;
font-size: 0.75rem;
font-size: 0.625rem;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.5px;
@@ -164,7 +164,7 @@ const formattedDate = postDate.toLocaleDateString('ru-RU', {
.title-overlay {
margin: 0 0 12px 0;
font-size: 1.5rem;
font-size: 1.4rem;
font-weight: 700;
line-height: 1.3;
}
@@ -182,7 +182,6 @@ const formattedDate = postDate.toLocaleDateString('ru-RU', {
.author-overlay {
font-size: 0.875rem;
opacity: 0.9;
font-style: italic;
}
/* Адаптивность */

View File

@@ -1,4 +1,8 @@
---
import { stripHtml } from '@/utils/htmlhelpers';
import Author from '@components/AuthorDisplay.astro';
import Subscribe from '@components/SubscribePost.astro';
import ShareButtons from '@components/ShareButtons.astro';
interface Props {
post: any;
@@ -6,18 +10,114 @@ interface Props {
}
const { post, pageInfo } = Astro.props;
---
{post ? (
<div class="article-wrapper">
<article class="news-single">
<h1>{post.title}</h1>
<div class="meta">
{post.date && <time>{new Date(post.date).toLocaleDateString('ru-RU')}</time>}
<div class="article_info">
<div class="publication__data">{post.date && <time>{new Date(post.date).toLocaleDateString('ru-RU')}</time>}</div>
<span class="author"><Author post={post} separator=", " /></span>
</div>
<h1>{post.title}</h1>
{post.secondaryTitle && <p class="secondary-title">{post.secondaryTitle}</p>}
{post.featuredImage?.node?.sourceUrl && (
<figure class="featured-image">
<img
src={post.featuredImage.node.sourceUrl}
alt={post.featuredImage.node.altText || post.title}
width={post.featuredImage.node.mediaDetails?.width || 1200}
height={post.featuredImage.node.mediaDetails?.height || 675}
loading="eager"
class="post-image"
/>
{(post.featuredImage.node.description || post.featuredImage.node.caption) && (
<figcaption class="image-caption">
{post.featuredImage.node.description && (
<p>{stripHtml(post.featuredImage.node.description)}</p>
)}
{post.featuredImage.node.caption && (
<span>©{stripHtml(post.featuredImage.node.caption)}</span>
)}
</figcaption>
)}
</figure>
)}
{post.content && <div set:html={post.content} />}
</article>
<ShareButtons url={post.uri} title={post.title} />
<Subscribe />
</div>
) : (
<div>Новость не найдена</div>
)}
<style>
.article-wrapper {
position: relative;
max-width: 75%;
padding-bottom: 2rem;
}
.news-single h1{
font-size: 2.375rem;
line-height: 1.2;
margin: 0 0 0.625rem;
}
.secondary-title {
font-size: 1.25rem;
line-height: 1.4;
color: #666;
margin: 0.5rem 0 1rem;
font-weight: 400;
}
.article_info{
display: flex;
gap: 8px;
}
.publication__data::after{
content: '';
position: absolute;
left: 0;
top: 50%;
height: 12px;
margin-top: -6px;
border-left: 1px solid grey;
}
.featured-image {
margin: 1.5rem 0;
width: 100%;
}
.post-image {
width: 100%;
height: auto;
display: block;
border-radius: 8px;
object-fit: cover;
}
.image-caption {
font-size: 0.875rem;
color: #666;
margin-top: 0.5rem;
text-align: left;
}
.image-caption p {
margin: 0 0 0.25rem 0;
}
.image-caption span {
font-style: italic;
white-space: nowrap;
}
</style>

View File

@@ -0,0 +1,10 @@
---
---
<div class="clearfix">
<p>
Читайте на смартфоне наши Telegram-каналы: <a href="https://t.me/profile_newzzz/" target="_blank">Профиль-News</a>, и <a href="https://t.me/profilejournal" target="_blank">журнал Профиль</a>. Скачивайте полностью <a href="https://profile.ru/mobilnye-prilozheniya/" target="_blank">бесплатное мобильное</a> приложение журнала "Профиль".
</p>
</div>

View File

@@ -3,6 +3,7 @@
const { title, description } = Astro.props;
import Header from '../components/Header/Header.astro';
import Header_lite from '../components/Header/Header_lite.astro';
import CurrentDate from '../components/Header/CurrentDate.astro';
import Footer from '../components/Footer.astro';
@@ -34,7 +35,7 @@ import '../styles/global.css';
</div>
<Footer
publicationName="ТехноВестник"
publicationName="Профиль"
organization="Учредитель: ИДР. Все права защищены."
menuItems={[
{ text: "О нас", url: "/about" },
@@ -47,11 +48,3 @@ import '../styles/global.css';
</body>
</html>
<style>
main {
width:100%;
max-width: 1024px;
margin:auto;
}
</style>

View File

@@ -137,6 +137,7 @@ export async function getProfileArticleById(databaseId) {
id
databaseId
title
secondaryTitle
content
excerpt
uri
@@ -150,6 +151,7 @@ export async function getProfileArticleById(databaseId) {
sourceUrl
altText
caption
description
mediaDetails {
width
height
@@ -169,6 +171,15 @@ export async function getProfileArticleById(databaseId) {
uri
}
}
# Соавторы как массив
coauthors {
id
name
firstName
lastName
url
description
}
categories {
nodes {
id
@@ -195,7 +206,6 @@ export async function getProfileArticleById(databaseId) {
}
/**
* Получить Anews пост по databaseId
*/

View File

@@ -40,6 +40,7 @@ if (pageInfo.type === 'single') { //одиночная статья
description="Информационное агентство Деловой журнал Профиль"
>
{pageInfo.type === 'single' && article ? (
<NewsSingle post={article} pageInfo={pageInfo} />
) : (

View File

@@ -47,6 +47,10 @@ a {
font-weight: 700;
}
main {
width:100%;
}
@media (max-width: 767px) {

30
src/utils/htmlhelpers.ts Normal file
View File

@@ -0,0 +1,30 @@
/**
* Удаляет HTML-теги и декодирует HTML-сущности
*/
export function stripHtml(html: string): string {
if (!html) return '';
return html
.replace(/<[^>]*>/g, '')
.replace(/&quot;/g, '"')
.replace(/&apos;/g, "'")
.replace(/&#039;/g, "'")
.replace(/&lt;/g, '<')
.replace(/&gt;/g, '>')
.replace(/&amp;/g, '&')
.replace(/&nbsp;/g, ' ');
}
/**
* Только декодирует HTML-сущности, не удаляет теги
*/
export function decodeHtmlEntities(text: string): string {
if (!text) return '';
return text
.replace(/&quot;/g, '"')
.replace(/&apos;/g, "'")
.replace(/&#039;/g, "'")
.replace(/&lt;/g, '<')
.replace(/&gt;/g, '>')
.replace(/&amp;/g, '&')
.replace(/&nbsp;/g, ' ');
}