Fix missing H1 on list-style pages via SectionHeading template
SectionHeading always rendered its title as <h2>, so every page whose only heading came from a shared section component (services hub, promotions, cases, faq, contact, reviews, blog list) had no <h1> at all. Add a level prop (default h2) and pass headingLevel="h1" from each page where that section is the page's own top-level heading. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013otXCiTZsxdZ4SJKZ9wUky
This commit is contained in:
1 parent
30e1aea20b
commit
f53c8b1ed7
14 files changed
+28
-18
No files matched your search
@@ -16,7 +16,7 @@ export default async function PromotionsPage() {
|
||||
return (
|
||||
<div>
|
||||
<Header />
|
||||
<Promotions promotions={promotions} showMailNote />
|
||||
<Promotions promotions={promotions} showMailNote headingLevel="h1" />
|
||||
<Footer />
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -24,7 +24,12 @@ export default async function BlogListPage() {
|
||||
<div>
|
||||
<Header />
|
||||
<section className="max-w-3xl mx-auto px-5 sm:px-8 py-20 min-h-[60vh]">
|
||||
<SectionHeading eyebrow="blog --articles" title="Блог" desc="Заметки об IT-инфраструктуре, кибербезопасности и автоматизации." />
|
||||
<SectionHeading
|
||||
eyebrow="blog --articles"
|
||||
title="Блог"
|
||||
desc="Заметки об IT-инфраструктуре, кибербезопасности и автоматизации."
|
||||
level="h1"
|
||||
/>
|
||||
|
||||
{posts.length === 0 && <p className="text-sm text-slate-400">Пока нет опубликованных статей - загляните позже.</p>}
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ export default async function FaqPage() {
|
||||
<script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(faqSchema) }} />
|
||||
)}
|
||||
<Header />
|
||||
<Faq faqs={faqs} />
|
||||
<Faq faqs={faqs} headingLevel="h1" />
|
||||
<Footer />
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -16,7 +16,7 @@ export default async function CasesPage() {
|
||||
return (
|
||||
<div>
|
||||
<Header />
|
||||
<Cases cases={cases} showDisclaimer />
|
||||
<Cases cases={cases} showDisclaimer headingLevel="h1" />
|
||||
<Footer />
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -15,7 +15,7 @@ export default async function ContactPage() {
|
||||
return (
|
||||
<div>
|
||||
<Header />
|
||||
<Contact contact={contact} />
|
||||
<Contact contact={contact} headingLevel="h1" />
|
||||
<Footer />
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -15,7 +15,7 @@ export default async function ReviewsPage() {
|
||||
return (
|
||||
<div>
|
||||
<Header />
|
||||
<Reviews reviews={reviews} />
|
||||
<Reviews reviews={reviews} headingLevel="h1" />
|
||||
<Footer />
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -16,7 +16,7 @@ export default async function ServicesPage() {
|
||||
return (
|
||||
<div>
|
||||
<Header />
|
||||
<Services categories={services} />
|
||||
<Services categories={services} headingLevel="h1" />
|
||||
<Footer />
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import Reveal from './Reveal.jsx';
|
||||
|
||||
export default function SectionHeading({ eyebrow, title, desc }) {
|
||||
export default function SectionHeading({ eyebrow, title, desc, level = 'h2' }) {
|
||||
const Heading = level;
|
||||
return (
|
||||
<Reveal className="mb-10 max-w-2xl">
|
||||
<p className="text-xs uppercase tracking-widest text-emerald-500 mb-3 font-mono">> {eyebrow}</p>
|
||||
<h2 className="text-2xl sm:text-3xl font-bold mb-3 font-display">{title}</h2>
|
||||
<Heading className="text-2xl sm:text-3xl font-bold mb-3 font-display">{title}</Heading>
|
||||
{desc && <p className="text-sm sm:text-base text-slate-600 dark:text-slate-400">{desc}</p>}
|
||||
</Reveal>
|
||||
);
|
||||
|
||||
@@ -3,13 +3,13 @@ import Reveal from '../Reveal.jsx';
|
||||
import SectionHeading from '../SectionHeading.jsx';
|
||||
import StatusDot from '../StatusDot.jsx';
|
||||
|
||||
export default function Cases({ cases, limit, moreHref, showDisclaimer = false }) {
|
||||
export default function Cases({ cases, limit, moreHref, showDisclaimer = false, headingLevel = 'h2' }) {
|
||||
if (cases.length === 0) return null;
|
||||
const list = limit ? cases.slice(0, limit) : cases;
|
||||
|
||||
return (
|
||||
<section id="cases" className="max-w-6xl mx-auto px-5 sm:px-8 py-20">
|
||||
<SectionHeading eyebrow="cases --log" title="Кейсы и портфолио" />
|
||||
<SectionHeading eyebrow="cases --log" title="Кейсы и портфолио" level={headingLevel} />
|
||||
<div className="grid sm:grid-cols-2 lg:grid-cols-3 gap-5">
|
||||
{list.map((c, i) => (
|
||||
<Reveal key={c.id} delay={i * 60}>
|
||||
|
||||
@@ -3,7 +3,7 @@ import { MapPin, Phone, Mail, Clock, ArrowRight } from 'lucide-react';
|
||||
import Reveal from '../Reveal.jsx';
|
||||
import SectionHeading from '../SectionHeading.jsx';
|
||||
|
||||
export default function Contact({ contact, compact = false }) {
|
||||
export default function Contact({ contact, compact = false, headingLevel = 'h2' }) {
|
||||
const rows = contact
|
||||
? [
|
||||
{ icon: MapPin, label: 'Адрес', value: contact.address },
|
||||
@@ -39,7 +39,7 @@ export default function Contact({ contact, compact = false }) {
|
||||
|
||||
return (
|
||||
<section id="contact" className="max-w-6xl mx-auto px-5 sm:px-8 py-20">
|
||||
<SectionHeading eyebrow="contact --reach-us" title="Контакты" />
|
||||
<SectionHeading eyebrow="contact --reach-us" title="Контакты" level={headingLevel} />
|
||||
<div className="grid md:grid-cols-2 gap-5">
|
||||
<Reveal>
|
||||
<div className="rounded-lg border p-5 h-full bg-white border-slate-200 dark:bg-slate-900 dark:border-slate-800">
|
||||
|
||||
@@ -23,13 +23,13 @@ function FaqItem({ item }) {
|
||||
);
|
||||
}
|
||||
|
||||
export default function Faq({ faqs, limit, moreHref }) {
|
||||
export default function Faq({ faqs, limit, moreHref, headingLevel = 'h2' }) {
|
||||
if (faqs.length === 0) return null;
|
||||
const list = limit ? faqs.slice(0, limit) : faqs;
|
||||
|
||||
return (
|
||||
<section id="faq" className="max-w-3xl mx-auto px-5 sm:px-8 py-20">
|
||||
<SectionHeading eyebrow="faq --common" title="Частые вопросы" />
|
||||
<SectionHeading eyebrow="faq --common" title="Частые вопросы" level={headingLevel} />
|
||||
<Reveal>
|
||||
<div>
|
||||
{list.map((item) => (
|
||||
|
||||
@@ -3,7 +3,7 @@ import { ArrowUpRight } from 'lucide-react';
|
||||
import Reveal from '../Reveal.jsx';
|
||||
import SectionHeading from '../SectionHeading.jsx';
|
||||
|
||||
export default function Promotions({ promotions, limit, moreHref, showMailNote = false }) {
|
||||
export default function Promotions({ promotions, limit, moreHref, showMailNote = false, headingLevel = 'h2' }) {
|
||||
if (promotions.length === 0) return null;
|
||||
const list = limit ? promotions.slice(0, limit) : promotions;
|
||||
|
||||
@@ -14,6 +14,7 @@ export default function Promotions({ promotions, limit, moreHref, showMailNote =
|
||||
eyebrow="promotions --active"
|
||||
title="Акции и специальные предложения"
|
||||
desc="Актуальные сроки и условия уточняйте у менеджера при обращении."
|
||||
level={headingLevel}
|
||||
/>
|
||||
<div className="grid sm:grid-cols-2 lg:grid-cols-3 gap-5">
|
||||
{list.map((p, i) => (
|
||||
|
||||
@@ -8,7 +8,7 @@ function cx(...args) {
|
||||
return args.filter(Boolean).join(' ');
|
||||
}
|
||||
|
||||
export default function Reviews({ reviews, limit, moreHref, showForm = true }) {
|
||||
export default function Reviews({ reviews, limit, moreHref, showForm = true, headingLevel = 'h2' }) {
|
||||
const list = limit ? reviews.slice(0, limit) : reviews;
|
||||
|
||||
// Пустая витрина отзывов на тизере (главная) выглядит слабо - лучше не показывать
|
||||
@@ -23,6 +23,7 @@ export default function Reviews({ reviews, limit, moreHref, showForm = true }) {
|
||||
eyebrow="reviews --approved"
|
||||
title="Отзывы клиентов"
|
||||
desc="Отзывов пока нет - будьте первым, кто расскажет о работе с нами. Публикуется после проверки менеджером."
|
||||
level={headingLevel}
|
||||
/>
|
||||
<Reveal>
|
||||
<ReviewForm />
|
||||
@@ -39,6 +40,7 @@ export default function Reviews({ reviews, limit, moreHref, showForm = true }) {
|
||||
eyebrow="reviews --approved"
|
||||
title="Отзывы клиентов"
|
||||
desc="Публикуются после проверки менеджером - это защищает страницу от спама и фейков."
|
||||
level={headingLevel}
|
||||
/>
|
||||
<div className={cx('grid gap-10', showForm && 'md:grid-cols-2')}>
|
||||
<Reveal>
|
||||
|
||||
@@ -30,12 +30,13 @@ export default function Services({
|
||||
eyebrow = 'services --price-list',
|
||||
title = 'Услуги IT-аутсорсинга и техподдержки: прайс-лист',
|
||||
desc = 'Гибкие тарифы для бизнеса любого масштаба. Возможна индивидуальная настройка под ваши задачи.',
|
||||
headingLevel = 'h2',
|
||||
}) {
|
||||
const list = limit ? categories.slice(0, limit) : categories;
|
||||
|
||||
return (
|
||||
<section id="services" className="max-w-6xl mx-auto px-5 sm:px-8 py-20">
|
||||
<SectionHeading eyebrow={eyebrow} title={title} desc={desc} />
|
||||
<SectionHeading eyebrow={eyebrow} title={title} desc={desc} level={headingLevel} />
|
||||
|
||||
{list.length === 0 && <p className="text-sm text-slate-400">Прайс-лист пока пуст.</p>}
|
||||
|
||||
|
||||
Reference in new issue
Block a user