feat: OG-image, логотип, компактный hero, кнопка отзыва consent

- public/logo-mark.svg (знак, 512×512) и public/logo.svg (знак+надпись,
  640×160). Копии для пользователя — E:/Projects/anotherreflections-logo*.{svg,png}
- public/og-image.png 1200×630 — тематический баннер с лого, заголовком
  градиентом и подписью. og:image + twitter:summary_large_image в meta,
  расшаривание в Telegram/VK/WhatsApp/Twitter получит превью
- scripts/build-og-image.mjs — пересоздание баннера через sharp (devdep)
- .hero.hero-compact — внутренние страницы /miry/, /kontakty/, /privacy/,
  /category/* перешли на компактный hero (меньше padding, без курсивного
  tagline). На главной hero остался прежний — entry point
- На /privacy/ кнопка «Отозвать согласие» — ставит ar-consent=deny
  одним кликом (152-ФЗ: отозвать должно быть так же просто, как дать)
- Описание Главного форума: «Архивный» → «Действующий форум проекта»
This commit is contained in:
2026-05-21 02:14:49 +03:00
parent 6f2cfdd63d
commit 4319759d88
14 changed files with 277 additions and 12 deletions

View File

@@ -122,7 +122,7 @@ export const WORLDS: World[] = [
{
name: 'Главный форум',
tag: 'Общая площадка',
desc: 'Архивный форум проекта со всеми мирами в одном месте.',
desc: 'Действующий форум проекта — общие темы, объявления и обсуждения миров в одном месте.',
url: 'https://forum.anotherreflections.ru/',
color: 'var(--c-news)',
},

View File

@@ -35,6 +35,14 @@ const year = new Date().getFullYear();
<meta property="og:url" content={canonical} />
<meta property="og:site_name" content={SITE_TITLE} />
<meta property="og:locale" content="ru_RU" />
<meta property="og:image" content={new URL('/og-image.png', SITE_URL).toString()} />
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
<meta property="og:image:alt" content={`${SITE_TITLE} — ${SITE_DESCRIPTION}`} />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content={pageTitle} />
<meta name="twitter:description" content={pageDesc} />
<meta name="twitter:image" content={new URL('/og-image.png', SITE_URL).toString()} />
<link rel="alternate" type="application/rss+xml" title={`${SITE_TITLE} — RSS`} href="/feed.xml" />

View File

@@ -29,7 +29,7 @@ const fmtDate = (d: Date) =>
d.toLocaleDateString('ru-RU', { year: 'numeric', month: 'long', day: 'numeric' });
---
<BaseLayout title={`Категория: ${name}`}>
<section class="hero" style={`padding: 3rem 1rem 2rem; --cat-color: ${catColor};`}>
<section class="hero hero-compact" style={`--cat-color: ${catColor};`}>
<span class="hero-eyebrow" style={`color: ${catColor}; border-color: ${catColor};`}>Категория</span>
<h1 style={`background: linear-gradient(180deg, #ffffff 0%, ${catColor} 100%); -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent;`}>{name}</h1>
<p class="hero-tagline">{sorted.length} {plural(sorted.length, ['публикация', 'публикации', 'публикаций'])} · <a href={`/category/${Astro.params.slug}/feed.xml`}>RSS этой категории</a></p>

View File

@@ -6,7 +6,7 @@ import { CONTACT_EMAIL, SOCIAL } from '../consts';
title="Контакты"
description={`Связаться с проектом «Иные Отражения»: ${CONTACT_EMAIL}, Telegram, ВКонтакте.`}
>
<section class="hero" style="padding: 4rem 1rem 2rem;">
<section class="hero hero-compact">
<span class="hero-eyebrow">На связи</span>
<h1>Контакты</h1>
<p class="hero-tagline">

View File

@@ -6,7 +6,7 @@ import { WORLDS } from '../consts';
title="Миры"
description="Восемь игровых вселенных проекта «Иные Отражения» — Дозоры, Амбер, Киндрет, Над бездной, Глубина, Ренессанс, Warhammer 40k."
>
<section class="hero" style="padding: 4rem 1rem 2.5rem;">
<section class="hero hero-compact">
<span class="hero-eyebrow">Игровые проекты</span>
<h1>Миры</h1>
<p class="hero-tagline">

View File

@@ -71,8 +71,10 @@ const lastUpdated = '20 мая 2026 г.';
<h2>5. Ваши права</h2>
<p>Вы можете в любой момент:</p>
<ul>
<li>Отозвать согласие на статистику — очистите cookies сайта или удалите <code>ar-consent</code>
в DevTools. При следующем визите снова появится уведомление, выберите «Только необходимые».</li>
<li>
<strong>Отозвать согласие на статистику</strong> — нажмите кнопку ниже.
Ваш выбор сохранится, при следующих визитах статистика загружаться не будет.
</li>
<li>Запросить удаление ваших данных из систем статистики — обратитесь напрямую к операторам
(<a href="https://yandex.ru/support/metrica/" target="_blank" rel="noopener">Яндекс</a>,
<a href="https://support.google.com/analytics/" target="_blank" rel="noopener">Google</a>).</li>
@@ -80,6 +82,28 @@ const lastUpdated = '20 мая 2026 г.';
по любым вопросам, связанным с данными.</li>
</ul>
<p style="margin: 1.5em 0 2em;">
<button type="button" class="cookie-btn cookie-btn-primary" id="revoke-consent-btn">
Отозвать согласие на статистику
</button>
<span id="revoke-status" style="margin-left: 1em; color: var(--fg-muted); font-size: .9em;"></span>
</p>
<script is:inline>
(() => {
const btn = document.getElementById('revoke-consent-btn');
const status = document.getElementById('revoke-status');
if (!btn) return;
btn.addEventListener('click', () => {
try { localStorage.setItem('ar-consent', 'deny'); } catch {}
document.cookie = 'ar-consent=deny; expires=' +
new Date(Date.now() + 365 * 24 * 60 * 60 * 1000).toUTCString() +
'; path=/; SameSite=Lax';
if (status) status.textContent = '✓ Согласие отозвано. Перезагрузите страницу.';
btn.disabled = true;
});
})();
</script>
<h2>6. Изменения</h2>
<p>
Мы можем обновлять эту Политику. Актуальная версия всегда доступна по адресу

View File

@@ -223,6 +223,22 @@ pre {
margin: 0 0 3rem;
position: relative;
}
.hero.hero-compact {
padding: 2.2rem 1rem 1.5rem;
margin: 0 0 2rem;
}
.hero.hero-compact h1 {
font-size: clamp(2rem, 4vw, 2.6rem);
}
.hero.hero-compact .hero-tagline {
font-size: 1rem;
margin-bottom: 0;
}
.hero.hero-compact .hero-eyebrow {
margin-bottom: .9rem;
padding: .3em 1em;
font-size: .72rem;
}
.hero-eyebrow {
display: inline-block;
font-size: .8rem;