add files
This commit is contained in:
117
src/components/ContentGrid.astro
Normal file
117
src/components/ContentGrid.astro
Normal file
@@ -0,0 +1,117 @@
|
||||
---
|
||||
export interface Props {
|
||||
items: any[];
|
||||
showCount?: boolean;
|
||||
}
|
||||
|
||||
const {
|
||||
items = [],
|
||||
showCount = false,
|
||||
} = Astro.props;
|
||||
---
|
||||
|
||||
<section class="posts-section" id="posts-section">
|
||||
<h2>
|
||||
{showCount && items.length > 0 && (
|
||||
<span id="posts-count"> ({items.length})</span>
|
||||
)}
|
||||
</h2>
|
||||
|
||||
<div id="posts-grid" class="posts-grid">
|
||||
{items.map((item, index) => {
|
||||
const postUrl = item.uri || `/blog/${item.databaseId}`;
|
||||
const postDate = new Date(item.date);
|
||||
|
||||
// Логика для больших плиток на десктопе
|
||||
let isLarge = false;
|
||||
let largePosition = '';
|
||||
|
||||
const rowNumber = Math.floor(index / 4) + 1;
|
||||
const positionInRow = index % 4;
|
||||
|
||||
if (index >= 8) {
|
||||
const largeRowStart = (rowNumber - 3) % 3 === 0 && rowNumber >= 3;
|
||||
|
||||
if (largeRowStart && positionInRow === 0) {
|
||||
isLarge = true;
|
||||
largePosition = 'first';
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<article
|
||||
class={`post-card ${isLarge ? 'post-card-large' : ''}`}
|
||||
data-large-position={isLarge ? largePosition : ''}
|
||||
data-index={index}
|
||||
itemscope
|
||||
itemtype="https://schema.org/BlogPosting"
|
||||
>
|
||||
<a href={postUrl} class="post-card-link">
|
||||
<div class="post-image-container">
|
||||
{item.featuredImage?.node?.sourceUrl ? (
|
||||
<img loading="lazy"
|
||||
src={item.featuredImage.node.sourceUrl}
|
||||
alt={item.featuredImage.node.altText || item.title}
|
||||
width="400"
|
||||
height="400"
|
||||
loading="lazy"
|
||||
class="post-image"
|
||||
itemprop="image"
|
||||
/>
|
||||
) : (
|
||||
<div class="post-image-placeholder"></div>
|
||||
)}
|
||||
|
||||
{/* Рубрика в верхнем правом углу */}
|
||||
{item.categories?.nodes?.[0]?.name && (
|
||||
<div class="post-category-badge">
|
||||
{item.categories.nodes[0].name}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Оверлей с контентом */}
|
||||
<div class="post-content-overlay">
|
||||
<div class="post-meta-overlay">
|
||||
<time
|
||||
datetime={item.date}
|
||||
class="post-date-overlay"
|
||||
itemprop="datePublished"
|
||||
>
|
||||
{postDate.toLocaleDateString('ru-RU', {
|
||||
day: 'numeric',
|
||||
month: 'short',
|
||||
year: 'numeric'
|
||||
}).replace(' г.', '')}
|
||||
</time>
|
||||
</div>
|
||||
|
||||
<h3 class="post-title-overlay" itemprop="headline">
|
||||
{item.title}
|
||||
</h3>
|
||||
|
||||
{item.author?.node?.name && (
|
||||
<div class="author-name" itemprop="author">
|
||||
{item.author.node.name}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
{/* Скринридеру и SEO */}
|
||||
<div class="sr-only">
|
||||
<h3 itemprop="headline">
|
||||
<a href={postUrl} itemprop="url">{item.title}</a>
|
||||
</h3>
|
||||
<time
|
||||
datetime={item.date}
|
||||
itemprop="datePublished"
|
||||
>
|
||||
{postDate.toLocaleDateString('ru-RU')}
|
||||
</time>
|
||||
</div>
|
||||
</article>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</section>
|
||||
275
src/components/EndnewsList.astro
Normal file
275
src/components/EndnewsList.astro
Normal file
@@ -0,0 +1,275 @@
|
||||
---
|
||||
import { getLatestAnews } from '../lib/api/posts.js';
|
||||
|
||||
// Функции для работы с датами
|
||||
function formatDate(dateString: string): string {
|
||||
const date = new Date(dateString);
|
||||
const today = new Date();
|
||||
const yesterday = new Date(today);
|
||||
yesterday.setDate(yesterday.getDate() - 1);
|
||||
|
||||
if (date.toDateString() === today.toDateString()) {
|
||||
return 'Сегодня';
|
||||
}
|
||||
|
||||
if (date.toDateString() === yesterday.toDateString()) {
|
||||
return 'Вчера';
|
||||
}
|
||||
|
||||
return date.toLocaleDateString('ru-RU', {
|
||||
day: 'numeric',
|
||||
month: 'long',
|
||||
year: 'numeric'
|
||||
});
|
||||
}
|
||||
|
||||
function formatTime(dateString: string): string {
|
||||
const date = new Date(dateString);
|
||||
return date.toLocaleTimeString('ru-RU', {
|
||||
hour: '2-digit',
|
||||
minute: '2-digit'
|
||||
});
|
||||
}
|
||||
|
||||
function groupByDate(posts: Array<{ date: string }>) {
|
||||
const grouped: Record<string, Array<any>> = {};
|
||||
|
||||
posts.forEach(post => {
|
||||
const date = new Date(post.date);
|
||||
const dateKey = date.toISOString().split('T')[0];
|
||||
|
||||
if (!grouped[dateKey]) {
|
||||
grouped[dateKey] = [];
|
||||
}
|
||||
|
||||
grouped[dateKey].push(post);
|
||||
});
|
||||
|
||||
const sortedEntries = Object.entries(grouped).sort((a, b) =>
|
||||
b[0].localeCompare(a[0])
|
||||
);
|
||||
|
||||
return Object.fromEntries(sortedEntries);
|
||||
}
|
||||
|
||||
// Получаем данные при сборке (используем правильное имя функции)
|
||||
const posts = await getLatestAnews(20);
|
||||
const groupedPosts = groupByDate(posts);
|
||||
const totalPosts = posts.length;
|
||||
---
|
||||
|
||||
<!-- HTML разметка -->
|
||||
<div class="endnews-container">
|
||||
<!-- Шапка с заголовком и счетчиком -->
|
||||
<div class="endnews-header">
|
||||
<h4 class="endnews-title">Новости</h4>
|
||||
</div>
|
||||
|
||||
<!-- Список новостей с группировкой по датам -->
|
||||
<div class="latestnews-list">
|
||||
{Object.entries(groupedPosts).map(([dateKey, datePosts]) => {
|
||||
const dateStr = new Date(dateKey).toLocaleDateString('ru-RU', {
|
||||
day: 'numeric',
|
||||
month: 'long',
|
||||
year: 'numeric'
|
||||
});
|
||||
|
||||
return (
|
||||
<div class="latestnews-date-group" key={dateKey}>
|
||||
|
||||
<div class="latestnews-date">{formatDate(dateKey + 'T00:00:00')}</div>
|
||||
|
||||
|
||||
<!-- Список новостей за эту дату -->
|
||||
{datePosts.map((post, index) => {
|
||||
const postNumber = index + 1;
|
||||
const isLastInGroup = postNumber === datePosts.length;
|
||||
|
||||
return (
|
||||
<article 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>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
|
||||
/* Базовые стили */
|
||||
.endnews-container {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.endnews-header {
|
||||
padding: 12px 16px;
|
||||
background: #B61D1D;
|
||||
border-radius: 6px 6px 0 0;
|
||||
}
|
||||
|
||||
.endnews-title {
|
||||
color: white;
|
||||
margin: 0;
|
||||
font-size: 1.1rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.latestnews-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border: 1px solid #ECECEC;
|
||||
border-top: none;
|
||||
border-radius: 0 0 6px 6px;
|
||||
background: white;
|
||||
}
|
||||
|
||||
.latestnews-date-group {
|
||||
padding: 12px 16px;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
}
|
||||
|
||||
.latestnews-date-group:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.latestnews-date {
|
||||
font-size: 0.625rem;
|
||||
line-height: 1.1;
|
||||
color: #505258;
|
||||
margin: 0 0 0.4375rem;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
.lastnews-item {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 12px;
|
||||
margin-bottom: 10px;
|
||||
contain: content;
|
||||
}
|
||||
|
||||
.lastnews-item:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.lastnews-time {
|
||||
font-size: 0.75rem;
|
||||
font-weight: 700;
|
||||
line-height: 1.2;
|
||||
color: #B61D1D;
|
||||
min-width: 2.5rem;
|
||||
flex-shrink: 0;
|
||||
margin-top: 1px;
|
||||
}
|
||||
|
||||
.lastnews-content {
|
||||
line-height: 1.3;
|
||||
font-weight: 500;
|
||||
font-size: 0.9em;
|
||||
color: #000;
|
||||
transition: color 0.2s;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.endnews-link {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.endnews-link:hover {
|
||||
color: #B61D1D;
|
||||
}
|
||||
|
||||
/* Десктоп: фиксированная высота со скроллом */
|
||||
@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::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
|
||||
.latestnews-list::-webkit-scrollbar-track {
|
||||
background: #f5f5f5;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.latestnews-list::-webkit-scrollbar-thumb {
|
||||
background: #d0d0d0;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.latestnews-list::-webkit-scrollbar-thumb:hover {
|
||||
background: #b0b0b0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Мобильные устройства: автоматическая высота */
|
||||
@media (max-width: 1023px) {
|
||||
.endnews-container {
|
||||
height: auto; /* Автоматическая высота */
|
||||
}
|
||||
|
||||
.latestnews-list {
|
||||
max-height: none;
|
||||
overflow: visible;
|
||||
}
|
||||
}
|
||||
|
||||
/* Планшеты (опционально) */
|
||||
@media (min-width: 768px) and (max-width: 1023px) {
|
||||
.endnews-container {
|
||||
height: auto;
|
||||
/* или можно задать другую фиксированную высоту для планшетов */
|
||||
}
|
||||
}
|
||||
|
||||
/* Анимация появления скролла (опционально) */
|
||||
.latestnews-list {
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
|
||||
/* Улучшение для touch-устройств */
|
||||
@media (hover: none) and (pointer: coarse) {
|
||||
.endnews-link {
|
||||
padding: 8px 0; /* Увеличение touch-зоны */
|
||||
}
|
||||
|
||||
.lastnews-item {
|
||||
margin: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
</style>
|
||||
365
src/components/Footer.astro
Normal file
365
src/components/Footer.astro
Normal file
@@ -0,0 +1,365 @@
|
||||
---
|
||||
interface Props {
|
||||
publicationName: string;
|
||||
organization: string;
|
||||
menuItems: Array<{
|
||||
text: string;
|
||||
url: string;
|
||||
}>;
|
||||
}
|
||||
|
||||
const { publicationName, organization, menuItems } = Astro.props;
|
||||
|
||||
// Получаем текущий год автоматически
|
||||
const currentYear = new Date().getFullYear();
|
||||
|
||||
const footerId = `footer-profile`;
|
||||
---
|
||||
|
||||
<footer id={footerId} class="footer">
|
||||
<!-- Свернутое состояние -->
|
||||
<div class="footer__collapsed">
|
||||
<button
|
||||
class="footer__toggle"
|
||||
onclick="toggleFooter(this)"
|
||||
aria-label="Развернуть футер"
|
||||
aria-expanded="false"
|
||||
aria-controls="footer-expanded-${footerId}"
|
||||
>
|
||||
<span class="footer__publication-name">
|
||||
<a class="footer__logo" href="/">
|
||||
<img loading="lazy" class="footer-logo" src="https://cdn.profile.ru/wp-content/themes/profile/assets/img/profil-logo-footer.png" width="136" height="30" alt="">
|
||||
</a>
|
||||
</span>
|
||||
<svg
|
||||
class="footer__arrow"
|
||||
width="20"
|
||||
height="20"
|
||||
viewBox="0 0 20 20"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<!-- Стрелка вверх (направлена вверх в свернутом состоянии) -->
|
||||
<path
|
||||
d="M5 12.5L10 7.5L15 12.5"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
fill="none"
|
||||
/>
|
||||
</svg>
|
||||
<span class="footer__copyright-collapsed">
|
||||
© {currentYear}, {organization}
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Раскрытое состояние -->
|
||||
<div
|
||||
id="footer-expanded-${footerId}"
|
||||
class="footer__expanded"
|
||||
hidden
|
||||
>
|
||||
<!-- Меню -->
|
||||
<nav class="footer__menu" aria-label="Дополнительная навигация">
|
||||
<ul class="footer__menu-list">
|
||||
{menuItems.map((item) => (
|
||||
<li class="footer__menu-item" key={item.url}>
|
||||
<a
|
||||
href={item.url}
|
||||
class="footer__menu-link"
|
||||
>
|
||||
{item.text}
|
||||
</a>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
<span class="footer__age">16+</span>
|
||||
|
||||
<!-- Полный копирайт -->
|
||||
<div class="footer__copyright-expanded">
|
||||
|
||||
<p>
|
||||
© {currentYear} {organization}. Все права защищены.
|
||||
Информационное агентство "Деловой журнал "Профиль" зарегистрировано в Федеральной службе по надзору в сфере связи, информационных технологий и массовых коммуникаций. Свидетельство о государственной регистрации серии ИА № ФС 77 - 89668 от 23.06.2025
|
||||
</p>
|
||||
|
||||
<ul class="menu-conf-docs">
|
||||
<li><a href="">Положение об обработке и защите персональных данных</a></li>
|
||||
<li><a href="">Политика конфиденциальности</a></li>
|
||||
<li><a href="">Правила применения рекомендательных технологий</a></li>
|
||||
</ul>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<!-- Кнопка сворачивания -->
|
||||
<div class="footer__expanded-bottom">
|
||||
<button
|
||||
class="footer__collapse-btn"
|
||||
onclick="toggleFooter(document.querySelector('#${footerId} .footer__toggle'))"
|
||||
aria-label="Свернуть футер"
|
||||
>
|
||||
<svg
|
||||
width="20"
|
||||
height="20"
|
||||
viewBox="0 0 20 20"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<!-- Стрелка вниз (направлена вниз в развернутом состоянии) -->
|
||||
<path
|
||||
d="M5 7.5L10 12.5L15 7.5"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
fill="none"
|
||||
/>
|
||||
</svg>
|
||||
<span>Свернуть</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<style is:global>
|
||||
.footer {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: #303030;
|
||||
border-top: 2px solid #404040;
|
||||
transition: all 0.3s ease;
|
||||
z-index: 100;
|
||||
box-shadow: 0 -2px 15px rgba(0, 0, 0, 0.3);
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Свернутое состояние */
|
||||
.footer__collapsed {
|
||||
padding: 12px 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.footer__toggle {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
max-width: 1200px;
|
||||
background: none;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
padding: 8px 16px;
|
||||
transition: all 0.2s ease;
|
||||
border-radius: 8px;
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.footer__toggle:hover {
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
.footer__publication-name {
|
||||
font-size: 1.1rem;
|
||||
font-weight: 600;
|
||||
color: #ffffff;
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
margin: 0 20px;
|
||||
}
|
||||
|
||||
.footer__arrow {
|
||||
transition: transform 0.3s ease;
|
||||
color: #cccccc;
|
||||
}
|
||||
|
||||
/* При развернутом состоянии стрелка поворачивается на 180° (вниз) */
|
||||
.footer__toggle[aria-expanded="true"] .footer__arrow {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
.footer__copyright-collapsed {
|
||||
font-size: 0.9rem;
|
||||
color: #cccccc;
|
||||
flex: 1;
|
||||
text-align: right;
|
||||
margin: 0 20px;
|
||||
}
|
||||
|
||||
/* Раскрытое состояние */
|
||||
.footer__expanded {
|
||||
max-height: 0;
|
||||
opacity: 0;
|
||||
overflow: hidden;
|
||||
transition: all 0.3s ease;
|
||||
padding: 0 20px;
|
||||
background: #303030;
|
||||
}
|
||||
|
||||
.footer__expanded:not([hidden]) {
|
||||
max-height: 400px;
|
||||
opacity: 1;
|
||||
padding: 20px;
|
||||
border-top: 1px solid #404040;
|
||||
}
|
||||
|
||||
.footer__menu {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.footer__menu-list {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 20px;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.footer__menu-item {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.footer__menu-link {
|
||||
color: #ffffff;
|
||||
text-decoration: none;
|
||||
font-size: 1rem;
|
||||
padding: 8px 12px;
|
||||
border-radius: 6px;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.footer__menu-link:hover {
|
||||
background: rgba(255, 255, 255, 0.15);
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.footer__copyright-expanded {
|
||||
color: #cccccc;
|
||||
font-size: 0.9rem;
|
||||
line-height: 1.5;
|
||||
margin-bottom: 20px;
|
||||
max-width: 800px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
.footer__copyright-expanded p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.footer__expanded-bottom {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.footer__collapse-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
border: none;
|
||||
padding: 8px 16px;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
font-size: 0.9rem;
|
||||
color: #ffffff;
|
||||
transition: all 0.2s ease;
|
||||
font-family: inherit;
|
||||
}
|
||||
|
||||
.footer__collapse-btn:hover {
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
|
||||
.menu-conf-docs{
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
.footer__age {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
background-color: #ffffff;
|
||||
color: #000000;
|
||||
border-radius: 50%;
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
border: 2px solid #404040;
|
||||
margin-left: 10px;
|
||||
flex-shrink: 0;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
|
||||
/* Адаптивность */
|
||||
@media (max-width: 768px) {
|
||||
.footer__toggle {
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.footer__publication-name,
|
||||
.footer__copyright-collapsed {
|
||||
margin: 4px 0;
|
||||
text-align: center;
|
||||
flex: none;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.footer__menu-list {
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.footer__copyright-expanded {
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* Анимация для стрелки */
|
||||
@keyframes bounce {
|
||||
0%, 100% {
|
||||
transform: translateY(0);
|
||||
}
|
||||
50% {
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
}
|
||||
|
||||
.footer__toggle:hover .footer__arrow {
|
||||
animation: bounce 0.5s ease;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script is:inline>
|
||||
function toggleFooter(button) {
|
||||
const footer = button.closest('.footer');
|
||||
const expandedSection = footer.querySelector('.footer__expanded');
|
||||
const isExpanded = button.getAttribute('aria-expanded') === 'true';
|
||||
|
||||
// Обновляем состояние кнопки
|
||||
button.setAttribute('aria-expanded', !isExpanded);
|
||||
button.setAttribute('aria-label', isExpanded ? 'Развернуть футер' : 'Свернуть футер');
|
||||
|
||||
// Показываем/скрываем контент
|
||||
if (isExpanded) {
|
||||
expandedSection.setAttribute('hidden', '');
|
||||
} else {
|
||||
expandedSection.removeAttribute('hidden');
|
||||
}
|
||||
}
|
||||
</script>
|
||||
53
src/components/Header/CurrentDate.astro
Normal file
53
src/components/Header/CurrentDate.astro
Normal file
@@ -0,0 +1,53 @@
|
||||
<div class="current-date" id="current-date">
|
||||
<!-- Дата будет обновляться в полночь -->
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function updateDate() {
|
||||
const element = document.getElementById('current-date');
|
||||
if (!element) return;
|
||||
|
||||
const today = new Date();
|
||||
const dateStr = today.toLocaleDateString('ru-RU', {
|
||||
day: 'numeric',
|
||||
month: 'long',
|
||||
year: 'numeric'
|
||||
});
|
||||
|
||||
element.textContent = dateStr;
|
||||
}
|
||||
|
||||
// Функция для расчета времени до следующей полночи
|
||||
function getTimeUntilMidnight() {
|
||||
const now = new Date();
|
||||
const midnight = new Date();
|
||||
midnight.setHours(24, 0, 0, 0); // Следующая полночь
|
||||
|
||||
return midnight.getTime() - now.getTime();
|
||||
}
|
||||
|
||||
// Обновляем дату сразу
|
||||
updateDate();
|
||||
|
||||
// Устанавливаем таймер на обновление в полночь
|
||||
const timeUntilMidnight = getTimeUntilMidnight();
|
||||
setTimeout(function() {
|
||||
updateDate();
|
||||
// После первой полночи ставим ежедневное обновление
|
||||
setInterval(updateDate, 24 * 60 * 60 * 1000);
|
||||
}, timeUntilMidnight);
|
||||
|
||||
// Дополнительно: обновляем при возвращении на вкладку после полуночи
|
||||
document.addEventListener('visibilitychange', function() {
|
||||
if (!document.hidden) {
|
||||
const now = new Date();
|
||||
const lastUpdate = new Date(localStorage.getItem('dateLastUpdate') || 0);
|
||||
|
||||
// Если прошло больше 12 часов с последнего обновления
|
||||
if (now - lastUpdate > 12 * 60 * 60 * 1000) {
|
||||
updateDate();
|
||||
localStorage.setItem('dateLastUpdate', now.toISOString());
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
27
src/components/Header/Header.astro
Normal file
27
src/components/Header/Header.astro
Normal file
@@ -0,0 +1,27 @@
|
||||
---
|
||||
|
||||
import Stores from './LazyStores.astro';
|
||||
|
||||
const MENU_ID = 103245;
|
||||
let menuItems = [];
|
||||
|
||||
---
|
||||
|
||||
<header class="header" itemscope itemtype="https://schema.org/WPHeader">
|
||||
|
||||
<div class="top-bar">
|
||||
<img alt="Профиль" width="249" height="55" src="https://cdn.profile.ru/wp-content/themes/profile/assets/img/profile-logo-delovoy.svg">
|
||||
<Stores />
|
||||
</div>
|
||||
|
||||
</header>
|
||||
|
||||
|
||||
<style>
|
||||
|
||||
.top-bar{
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
</style>
|
||||
76
src/components/Header/LazyStores.astro
Normal file
76
src/components/Header/LazyStores.astro
Normal file
@@ -0,0 +1,76 @@
|
||||
---
|
||||
// Иконки загрузятся после DOM
|
||||
---
|
||||
|
||||
<div class="header-stores" id="stores-container">
|
||||
</div>
|
||||
|
||||
|
||||
<script>
|
||||
// Ждем полной загрузки DOM
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const container = document.getElementById('stores-container');
|
||||
if (!container) return;
|
||||
|
||||
// Создаем HTML с иконками
|
||||
const storesHTML = `
|
||||
<a class="float-xs-none float-md-left header__store"
|
||||
href="https://apps.apple.com"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer">
|
||||
<img loading="lazy"
|
||||
src="https://cdn.profile.ru/wp-content/themes/profile/assets/img/appstore.svg"
|
||||
width="103" height="32"
|
||||
alt="AppStore">
|
||||
</a>
|
||||
<a class="float-xs-none float-md-left header__store"
|
||||
href="https://play.google.com"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer">
|
||||
<img loading="lazy"
|
||||
src="https://cdn.profile.ru/wp-content/themes/profile/assets/img/googleplay.png"
|
||||
width="115" height="32"
|
||||
alt="Google Play">
|
||||
</a>
|
||||
<a class="float-xs-none float-md-left header__store"
|
||||
href="https://apps.rustore.ru"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer">
|
||||
<img loading="lazy"
|
||||
src="https://cdn.profile.ru/wp-content/themes/profile/assets/img/rustore.svg"
|
||||
width="98" height="32"
|
||||
alt="RuStore">
|
||||
</a>
|
||||
`;
|
||||
|
||||
// Вставляем иконки
|
||||
container.innerHTML = storesHTML;
|
||||
|
||||
|
||||
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
<style>
|
||||
.header-stores {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
align-items: center;
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.header__store {
|
||||
display: inline-block;
|
||||
transition: transform 0.2s ease;
|
||||
}
|
||||
|
||||
.header__store:hover {
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.header__store img {
|
||||
display: block;
|
||||
height: auto;
|
||||
}
|
||||
</style>
|
||||
0
src/components/Header/MenuBar.astro
Normal file
0
src/components/Header/MenuBar.astro
Normal file
21
src/components/Header/Stores.astro
Normal file
21
src/components/Header/Stores.astro
Normal file
@@ -0,0 +1,21 @@
|
||||
<div class="header__social clearfix">
|
||||
<div class="header-stores">
|
||||
<a class="float-xs-none float-md-left header__store" href="https://apps.apple.com/ru/app/id6476872853" target="_blank">
|
||||
<img loading="lazy" src="https://cdn.profile.ru/wp-content/themes/profile/assets/img/appstore.svg" width="103" height="32" alt="AppStore">
|
||||
</a>
|
||||
<a class="float-xs-none float-md-left header__store" href="https://play.google.com/store/apps/details?id=com.profile.magazine" target="_blank">
|
||||
<img loading="lazy" src="https://cdn.profile.ru/wp-content/themes/profile/assets/img/googleplay.png" width="115" height="32" alt="Google Play">
|
||||
</a>
|
||||
<a class="float-xs-none float-md-left header__store" href="https://apps.rustore.ru/app/com.profile.magazine" target="_blank">
|
||||
<img loading="lazy" src="https://cdn.profile.ru/wp-content/themes/profile/assets/img/rustore.svg" width="98" height="32" alt="Google Play">
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.header-stores{
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user