fix(seo): убрать дубли title и description
- 6 pages (o-nas, nashi-druzya, 4 миры) получили свой description в frontmatter; раньше [slug].astro для типа page передавал description=undefined → fallback на SITE_DESCRIPTION даёт 6 одинаковых meta-description. - [slug].astro: для постов в SEO-title подставляется год публикации (или полная дата, если есть второй пост с тем же title в том же году). Покрывает дубли «Внимание! Технические работы!» (×5) и «С 23 февраля!» (×2). - index.astro: свой description для главной (вместо SITE_DESCRIPTION). - category/[slug].astro: вычисляемый description с количеством публикаций и диапазоном лет — на случай если категории попадут в индексацию.
This commit is contained in:
@@ -6,13 +6,27 @@ import { CATEGORY_COLORS } from '../consts';
|
||||
export async function getStaticPaths() {
|
||||
const posts = await getCollection('posts');
|
||||
const pages = await getCollection('pages');
|
||||
|
||||
// Считаем сколько постов с одинаковым {title, year} — если >1, в SEO-title
|
||||
// подставим полную дату, иначе только год.
|
||||
const titleYearCount = new Map<string, number>();
|
||||
for (const p of posts) {
|
||||
const key = `${p.data.title}|${p.data.pubDate.getFullYear()}`;
|
||||
titleYearCount.set(key, (titleYearCount.get(key) ?? 0) + 1);
|
||||
}
|
||||
|
||||
return [
|
||||
...posts.map((p) => ({ params: { slug: p.data.slug }, props: { entry: p, kind: 'post' as const } })),
|
||||
...pages.map((p) => ({ params: { slug: p.data.slug }, props: { entry: p, kind: 'page' as const } })),
|
||||
...posts.map((p) => {
|
||||
const year = p.data.pubDate.getFullYear();
|
||||
const key = `${p.data.title}|${year}`;
|
||||
const sameYearDup = (titleYearCount.get(key) ?? 1) > 1;
|
||||
return { params: { slug: p.data.slug }, props: { entry: p, kind: 'post' as const, sameYearDup } };
|
||||
}),
|
||||
...pages.map((p) => ({ params: { slug: p.data.slug }, props: { entry: p, kind: 'page' as const, sameYearDup: false } })),
|
||||
];
|
||||
}
|
||||
|
||||
const { entry, kind } = Astro.props;
|
||||
const { entry, kind, sameYearDup } = Astro.props;
|
||||
const { Content } = await render(entry);
|
||||
// Буквица — только для постов с телом длиннее короткого порога.
|
||||
const bodyLen = entry.body?.length ?? 0;
|
||||
@@ -20,10 +34,18 @@ const useDropCap = kind === 'post' && bodyLen > 240;
|
||||
|
||||
const fmtDate = (d: Date) =>
|
||||
d.toLocaleDateString('ru-RU', { year: 'numeric', month: 'long', day: 'numeric' });
|
||||
|
||||
// Короткая дата без "г." для SEO-title постов с одинаковым названием в одном году.
|
||||
const fmtDateForTitle = (d: Date) =>
|
||||
d.toLocaleDateString('ru-RU', { year: 'numeric', month: 'long', day: 'numeric' }).replace(/\sг\.?$/, '');
|
||||
|
||||
const seoTitle = kind === 'post'
|
||||
? `${entry.data.title} (${sameYearDup ? fmtDateForTitle(entry.data.pubDate) : entry.data.pubDate.getFullYear()})`
|
||||
: entry.data.title;
|
||||
---
|
||||
<BaseLayout
|
||||
title={entry.data.title}
|
||||
description={kind === 'post' ? entry.data.description : undefined}
|
||||
title={seoTitle}
|
||||
description={entry.data.description || undefined}
|
||||
ogType={kind === 'post' ? 'article' : 'website'}
|
||||
>
|
||||
<article class="post">
|
||||
|
||||
Reference in New Issue
Block a user