feat(design): добавлен характер — hero, цветные миры, карточки с акцентами

- Hero на главной: большой заголовок в градиенте, мистический тэглайн,
  мета-плашка «N миров / N публикаций / N лет онлайн»
- Декоративный фон: звёздная россыпь + радиальные градиенты акцента
  (CSS-only, без картинок)
- Карточки постов с цветовой полосой по категории + hover-эффект
- Цветные теги категорий с glow-точкой
- «Миры и проекты» вместо «Форумы»: 8 карточек с тэгом, названием,
  описанием каждой вселенной и цветовой кодировкой
- Single post: буквица в первом абзаце, центрированный заголовок
  в градиенте, тег категории сверху
- BrandMark SVG (две зеркальные арки) + липкая шапка с blur
- Cormorant Garamond вместо Lora — больше серифной выразительности
- CATEGORY_COLORS в consts.ts (расширяемая палитра)
- Mobile-адаптация (clamp заголовки, перенос меты, уменьшенные паддинги)
This commit is contained in:
2026-05-21 01:22:13 +03:00
parent 0c3e248ccc
commit 9a6f07d302
7 changed files with 631 additions and 179 deletions

View File

@@ -1,47 +1,83 @@
---
import { getCollection } from 'astro:content';
import BaseLayout from '../layouts/BaseLayout.astro';
import { FORUMS } from '../consts';
import { WORLDS, CATEGORY_COLORS, HERO_TAGLINE, SITE_FOUNDED } from '../consts';
const posts = (await getCollection('posts'))
.sort((a, b) => b.data.pubDate.valueOf() - a.data.pubDate.valueOf());
const totalPosts = posts.length;
const totalWorlds = WORLDS.length;
const oldestYear = posts.length ? posts[posts.length - 1].data.pubDate.getFullYear() : SITE_FOUNDED;
const fmtDate = (d: Date) =>
d.toLocaleDateString('ru-RU', { year: 'numeric', month: 'long', day: 'numeric' });
---
<BaseLayout>
<section>
<h1>Новости</h1>
<section class="hero">
<span class="hero-eyebrow">Ролевой проект · с {SITE_FOUNDED} года</span>
<h1>Иные<br/>Отражения</h1>
<p class="hero-tagline">{HERO_TAGLINE}</p>
<div class="hero-meta">
<span><strong>{totalWorlds}</strong> мира</span>
<span><strong>{totalPosts}</strong> публикаций</span>
<span><strong>{new Date().getFullYear() - SITE_FOUNDED}</strong> лет онлайн</span>
</div>
</section>
<section id="news">
<div class="section-head">
<h2>Хроника проекта</h2>
<span class="section-meta"><a href="/feed.xml">RSS-фид</a></span>
</div>
<ul class="post-list">
{posts.map((post) => (
<li class="post-list-item">
<div class="post-meta">
<time datetime={post.data.pubDate.toISOString()}>{fmtDate(post.data.pubDate)}</time>
{post.data.categories.length > 0 && (
<>
{' · '}
{post.data.categories.map((cat, i) => (
<>
{i > 0 && ', '}
<a href={`/category/${post.data.categorySlugs[i]}/`}>{cat}</a>
</>
))}
</>
)}
</div>
<h2><a href={`/${post.data.slug}/`}>{post.data.title}</a></h2>
{post.data.description && <p class="post-excerpt">{post.data.description}…</p>}
{posts.map((post) => {
const catColor = post.data.categorySlugs[0]
? CATEGORY_COLORS[post.data.categorySlugs[0]] ?? 'var(--accent)'
: 'var(--accent)';
return (
<li class="post-card" style={`--cat-color: ${catColor}`}>
<div class="post-meta">
<time datetime={post.data.pubDate.toISOString()}>{fmtDate(post.data.pubDate)}</time>
{post.data.categories.length > 0 && (
<a
href={`/category/${post.data.categorySlugs[0]}/`}
class="cat-tag"
style={`--cat-color: ${catColor}`}
>
{post.data.categories[0]}
</a>
)}
</div>
<h3><a href={`/${post.data.slug}/`}>{post.data.title}</a></h3>
{post.data.description && <p class="post-excerpt">{post.data.description}…</p>}
</li>
);
})}
</ul>
</section>
<section id="worlds" style="margin-top: 4rem;">
<div class="section-head">
<h2>Миры и проекты</h2>
<span class="section-meta">{WORLDS.length} вселенных</span>
</div>
<ul class="worlds-grid">
{WORLDS.map((w) => (
<li>
<a
class="world-card"
href={w.url}
target="_blank"
rel="noopener"
style={`--cat-color: ${w.color}`}
>
<span class="world-tag">{w.tag}</span>
<span class="world-name">{w.name}</span>
<span class="world-desc">{w.desc}</span>
</a>
</li>
))}
</ul>
</section>
<section id="forums">
<h2>Форумы и проекты</h2>
<ul class="forums-grid">
{FORUMS.map((f) => (
<li><a href={f.url} target="_blank" rel="noopener">{f.name}</a></li>
))}
</ul>
</section>
</BaseLayout>