diff --git a/hypn0/hypn0_site/models.py b/hypn0/hypn0_site/models.py index 1a931ae..b795caa 100644 --- a/hypn0/hypn0_site/models.py +++ b/hypn0/hypn0_site/models.py @@ -567,3 +567,19 @@ class TbBlogPost(models.Model): def get_absolute_url(self) -> str: """Возвращает канонический URL статьи блога.""" return f"/blog/{self.slug}" if self.slug else f"/blog/{self.pk}" + + @property + def blog_nav_title(self) -> str: + """Детерминированный выбор названия раздела блога для навигации на основе ID статьи.""" + nav_titles = ( + "Блог Мозгоклюя", + "Записки Гипножабы", + "Дневник Мозговых Перцепторов", + "Хроники психо-резонанса", + "Мемуары астрального архива", + "Манифесты волновой матрицы", + "Бортовой журнал транс-погружения", + ) + if not self.id: + return nav_titles[0] + return nav_titles[self.id % len(nav_titles)] diff --git a/hypn0/hypn0_site/tests.py b/hypn0/hypn0_site/tests.py index fa8f221..f6e99a3 100644 --- a/hypn0/hypn0_site/tests.py +++ b/hypn0/hypn0_site/tests.py @@ -1386,7 +1386,7 @@ class BlogPostModelAndAdminTests(BaseMediaTestCase): self.assertContains(resp_parent, "Глава 1: Первичная модуляция") self.assertContains(resp_parent, "Глава 2: Фазовый сдвиг матрицы") - # 2. Проверка первой главы (связанный SVG, ссылка на родителя, следующая глава) + # 2. Проверка первой главы (связанный SVG, ссылка на родителя, следующая глава, хлебные крошки и JSON-LD) resp_ch1 = self.client.get(f"/blog/{ch1.slug}") self.assertEqual(resp_ch1.status_code, 200) self.assertContains(resp_ch1, "Глава 1: Первичная модуляция") @@ -1399,6 +1399,18 @@ class BlogPostModelAndAdminTests(BaseMediaTestCase): self.assertContains(resp_ch1, "Следующая глава цикла") self.assertContains(resp_ch1, "Глава 2: Фазовый сдвиг матрицы") + # Проверка хлебных крошек + self.assertContains(resp_ch1, 'aria-label="Хлебные крошки"') + self.assertContains(resp_ch1, ch1.blog_nav_title) + self.assertContains(resp_ch1, "Глава 1 из 2") + self.assertContains(resp_ch1, 'aria-current="page"') + + # Проверка JSON-LD BreadcrumbList + self.assertContains(resp_ch1, '"@type": "BreadcrumbList"') + self.assertContains(resp_ch1, '"name": "Главная"') + self.assertContains(resp_ch1, '"name": "Хроники гипноза"') + self.assertContains(resp_ch1, series_parent.s_title) + # 3. Проверка второй главы (ссылка назад на главу 1) resp_ch2 = self.client.get(f"/blog/{ch2.slug}") self.assertEqual(resp_ch2.status_code, 200) diff --git a/hypn0/hypn0_site/views.py b/hypn0/hypn0_site/views.py index d9b8c5b..06dd006 100644 --- a/hypn0/hypn0_site/views.py +++ b/hypn0/hypn0_site/views.py @@ -710,6 +710,7 @@ def blog_detail(request: HttpRequest, slug: str) -> HttpResponse: "svg_stats": svg_stats, "series_parent": series_parent, "series_posts": series_posts, + "series_total_count": len(series_posts) if series_posts else 0, "prev_post": prev_post, "next_post": next_post, } diff --git a/hypn0/templates/_base.html b/hypn0/templates/_base.html index f0bcde3..de7d243 100644 --- a/hypn0/templates/_base.html +++ b/hypn0/templates/_base.html @@ -101,13 +101,16 @@ val=>{if(val)document.documentElement.classList.add('dark');else document.docume файла css/tailwind-custom.css (подключён в input.css через @import).{% endcomment %} {% endif %} + [ + { + "@context": "https://schema.org", + "@type": "WebSite", + "name": "hypn0.xyz", + "url": "{{ request.scheme }}://{{ request.get_host }}/" + }{% block EXTRA_LD_JSON %} + {% endblock EXTRA_LD_JSON %} + ] +