feat: соц-кнопки и кнопка «Наверх» внизу + русская плюрализация
- Под лентой контента появилась панель из трёх pill-кнопок: Telegram (t.me/anotherreflections), ВКонтакте (vk.com/anotherreflections) и «Наверх» (smooth scroll to top) - Универсальный plural() в consts.ts — больше нет «8 мира», hero показывает «8 миров / 50 публикаций / 20 лет онлайн» с автоматически правильной формой при любом значении - Уточнено описание Ренессанса: «фантастическими допущениями мира Сумрака»
This commit is contained in:
23
src/components/SocialLinks.astro
Normal file
23
src/components/SocialLinks.astro
Normal file
@@ -0,0 +1,23 @@
|
||||
---
|
||||
import { SOCIAL } from '../consts';
|
||||
---
|
||||
<div class="social-bar">
|
||||
<a class="social-btn" href={SOCIAL.telegram.url} target="_blank" rel="noopener" aria-label="Telegram-канал «Иные Отражения»" title="Telegram-канал">
|
||||
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" aria-hidden="true">
|
||||
<path d="M21.5 4.5 18.5 19.7c-.22 1-.82 1.25-1.66.78l-4.58-3.38-2.21 2.13c-.24.24-.45.45-.92.45l.33-4.65 8.48-7.66c.37-.33-.08-.51-.57-.18L6.93 13.28l-4.52-1.41c-.98-.31-1-.98.21-1.45L20.22 3.1c.82-.3 1.53.19 1.28 1.4Z" fill="currentColor"/>
|
||||
</svg>
|
||||
<span>Telegram</span>
|
||||
</a>
|
||||
<a class="social-btn" href={SOCIAL.vk.url} target="_blank" rel="noopener" aria-label="Сообщество ВКонтакте" title="ВКонтакте">
|
||||
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" aria-hidden="true">
|
||||
<path d="M12.785 16.241s.288-.032.435-.19c.135-.146.131-.42.131-.42s-.018-1.305.587-1.497c.596-.189 1.361 1.258 2.172 1.815.614.42 1.079.328 1.079.328l2.17-.03s1.135-.07.597-.962c-.044-.073-.314-.66-1.611-1.864-1.359-1.261-1.176-1.057.46-3.236.997-1.327 1.396-2.137 1.271-2.485-.119-.331-.852-.244-.852-.244l-2.44.015s-.181-.024-.315.056c-.13.078-.214.26-.214.26s-.388 1.033-.905 1.911c-1.09 1.85-1.526 1.948-1.705 1.832-.415-.268-.311-1.072-.311-1.643 0-1.783.27-2.526-.527-2.719-.265-.064-.46-.107-1.137-.114-.87-.009-1.605.003-2.022.207-.277.135-.49.437-.36.454.16.022.524.099.717.362.249.34.24 1.103.24 1.103s.143 2.094-.335 2.355c-.328.18-.778-.187-1.75-1.87a15.426 15.426 0 0 1-.871-1.797s-.072-.176-.2-.27c-.155-.115-.371-.151-.371-.151L4.65 7.32s-.348.01-.476.161c-.114.135-.009.413-.009.413s1.815 4.247 3.87 6.388c1.886 1.962 4.028 1.833 4.028 1.833l.722.126Z" fill="currentColor"/>
|
||||
</svg>
|
||||
<span>ВКонтакте</span>
|
||||
</a>
|
||||
<button class="social-btn social-btn-top" type="button" aria-label="Наверх" title="Наверх" onclick="window.scrollTo({top: 0, behavior: 'smooth'})">
|
||||
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" aria-hidden="true">
|
||||
<path d="M12 5v14M5 12l7-7 7 7" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
<span>Наверх</span>
|
||||
</button>
|
||||
</div>
|
||||
@@ -1,3 +1,18 @@
|
||||
export const SOCIAL = {
|
||||
telegram: { url: 'https://t.me/anotherreflections', label: 'Telegram' },
|
||||
vk: { url: 'https://vk.com/anotherreflections', label: 'ВКонтакте' },
|
||||
};
|
||||
|
||||
/** Русская плюрализация: [1, 2-4, 5+]. Пример: plural(8, ['мир', 'мира', 'миров']) → 'миров' */
|
||||
export function plural(n: number, forms: [string, string, string]): string {
|
||||
const a = Math.abs(n) % 100;
|
||||
const b = a % 10;
|
||||
if (a > 10 && a < 20) return forms[2];
|
||||
if (b > 1 && b < 5) return forms[1];
|
||||
if (b === 1) return forms[0];
|
||||
return forms[2];
|
||||
}
|
||||
|
||||
export const SITE_TITLE = 'Иные Отражения';
|
||||
export const SITE_DESCRIPTION = 'Ролевой проект по современной фантастике. Дозоры С. Лукьяненко, Амбер Р. Желязны, А. Пехов.';
|
||||
export const SITE_URL = 'https://anotherreflections.ru';
|
||||
@@ -69,7 +84,7 @@ export const WORLDS: World[] = [
|
||||
{
|
||||
name: 'Ренессанс',
|
||||
tag: 'Историческая фантастика',
|
||||
desc: 'Эпоха возрождения с фантастическими допущениями.',
|
||||
desc: 'Эпоха Возрождения с фантастическими допущениями мира Сумрака.',
|
||||
url: 'https://renessans.anotherreflections.ru/',
|
||||
color: 'var(--c-roleplay)',
|
||||
},
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import '../styles/global.css';
|
||||
import { SITE_TITLE, SITE_DESCRIPTION, SITE_URL, SITE_LANG, MAIN_NAV } from '../consts';
|
||||
import BrandMark from '../components/BrandMark.astro';
|
||||
import SocialLinks from '../components/SocialLinks.astro';
|
||||
|
||||
interface Props {
|
||||
title?: string;
|
||||
@@ -60,6 +61,7 @@ const year = new Date().getFullYear();
|
||||
|
||||
<main>
|
||||
<slot />
|
||||
<SocialLinks />
|
||||
</main>
|
||||
|
||||
<footer class="site-footer">
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
import { getCollection } from 'astro:content';
|
||||
import BaseLayout from '../../layouts/BaseLayout.astro';
|
||||
import { CATEGORY_COLORS } from '../../consts';
|
||||
import { CATEGORY_COLORS, plural } from '../../consts';
|
||||
|
||||
export async function getStaticPaths() {
|
||||
const posts = await getCollection('posts');
|
||||
@@ -32,7 +32,7 @@ const fmtDate = (d: Date) =>
|
||||
<section class="hero" style={`padding: 3rem 1rem 2rem; --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} {sorted.length === 1 ? 'публикация' : sorted.length < 5 ? 'публикации' : 'публикаций'} · <a href={`/category/${Astro.params.slug}/feed.xml`}>RSS этой категории</a></p>
|
||||
<p class="hero-tagline">{sorted.length} {plural(sorted.length, ['публикация', 'публикации', 'публикаций'])} · <a href={`/category/${Astro.params.slug}/feed.xml`}>RSS этой категории</a></p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
import { getCollection } from 'astro:content';
|
||||
import BaseLayout from '../layouts/BaseLayout.astro';
|
||||
import { WORLDS, CATEGORY_COLORS, HERO_TAGLINE, SITE_FOUNDED } from '../consts';
|
||||
import { WORLDS, CATEGORY_COLORS, HERO_TAGLINE, SITE_FOUNDED, plural } from '../consts';
|
||||
|
||||
const posts = (await getCollection('posts'))
|
||||
.sort((a, b) => b.data.pubDate.valueOf() - a.data.pubDate.valueOf());
|
||||
@@ -19,9 +19,9 @@ const fmtDate = (d: Date) =>
|
||||
<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>
|
||||
<span><strong>{totalWorlds}</strong> {plural(totalWorlds, ['мир', 'мира', 'миров'])}</span>
|
||||
<span><strong>{totalPosts}</strong> {plural(totalPosts, ['публикация', 'публикации', 'публикаций'])}</span>
|
||||
<span><strong>{new Date().getFullYear() - SITE_FOUNDED}</strong> {plural(new Date().getFullYear() - SITE_FOUNDED, ['год', 'года', 'лет'])} онлайн</span>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
@@ -519,6 +519,40 @@ pre {
|
||||
background: var(--bg-elev-2);
|
||||
}
|
||||
|
||||
/* ============================== SOCIAL BAR ============================== */
|
||||
.social-bar {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: .75rem;
|
||||
margin: 4rem auto 1rem;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.social-btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: .55em;
|
||||
padding: .65em 1.25em;
|
||||
background: var(--bg-elev);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 100px;
|
||||
color: var(--fg-muted);
|
||||
font-size: .88rem;
|
||||
font-weight: 500;
|
||||
letter-spacing: 0.02em;
|
||||
cursor: pointer;
|
||||
font-family: inherit;
|
||||
transition: border-color .2s, color .2s, background .2s, transform .2s;
|
||||
border-bottom: 1px solid var(--border);
|
||||
}
|
||||
.social-btn:hover {
|
||||
border-color: var(--accent);
|
||||
color: var(--accent);
|
||||
background: var(--bg-elev-2);
|
||||
transform: translateY(-1px);
|
||||
border-bottom-color: var(--accent);
|
||||
}
|
||||
.social-btn svg { flex-shrink: 0; }
|
||||
|
||||
/* ============================== FOOTER ============================== */
|
||||
.site-footer {
|
||||
border-top: 1px solid var(--border);
|
||||
|
||||
Reference in New Issue
Block a user