feat(sprint-5.5): add page preview section with Create button

- New route /pages/preview with empty state ("Создать") and assembled preview
- Preview assembles real site blocks in order (Hero + Doctors ready, rest placeholders)
- localStorage persists created state; "Пересобрать" resets it
- Extracted HeroBlock and DoctorsBlock as reusable components
- Refactored hero and doctors pages to import from components/blocks/
- Sidebar: added "Просмотр страницы" link, bumped to Sprint 5.5 · v0.5.5
- SPRINTS.md: added Sprint 5.5 plan with summary table row

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
AR 15 M4
2026-03-23 16:21:40 +05:00
parent 60619114a5
commit 72829b5d46
8 changed files with 496 additions and 222 deletions
@@ -0,0 +1,95 @@
export const STATS = [
{ num: "27", label: "ЛОР врачей работает в клинике", prefix: "Ежедневно" },
{ num: "6", label: "кандидатов медицинских наук", prefix: "В том числе" },
{ num: "12 000+", label: "успешно проведённых операций", prefix: "Свыше" },
];
export const DOCTORS = [
{
name: "Макарова Людмила Германовна",
spec: "ЛОР врач, сурдолог",
photo: "/doctors/makarova.jpg",
},
{
name: "Семерикова Наталия Александровна",
spec: "ЛОР врач, сурдолог, хирург. К.М.Н. Завед. Центром сурдологии",
photo: "/doctors/semerikova.png",
},
{
name: "Ворончихина Наталия Валерьевна",
spec: "Отоневролог, хирург. К.М.Н., доцент кафедры ПГМУ",
photo: "/doctors/voronchikhina.png",
},
{
name: "Лобанова Ирина Юрьевна",
spec: "ЛОР врач, сурдолог",
photo: "/doctors/lobanova.jpg",
},
{
name: "Торсунова Наталья Сергеевна",
spec: "Специалист по слухопротезированию (сурдоакустик)",
photo: "/doctors/torsunova.jpg",
},
{
name: "Суворова Светлана Викторовна",
spec: "ЛОР врач, сурдолог",
photo: "/doctors/suvorova.jpg",
},
];
export function DoctorsBlock() {
return (
<div className="space-y-8">
{/* Заголовок + описание */}
<div>
<h2 className="text-3xl font-bold mb-3" style={{ color: "#111827" }}>
Приём ведут опытные ЛОР врачи
</h2>
<p className="text-sm" style={{ color: "#374151", lineHeight: 1.7 }}>
Фундаментальная теоретическая подготовка и большой практический опыт в сочетании
с внимательным индивидуальным подходом являются причиной успеха лечения тысяч наших пациентов
</p>
</div>
{/* Статистика — без фона, border-bottom #60959c */}
<div className="grid grid-cols-3 gap-6">
{STATS.map((s) => (
<div key={s.num} className="pb-3" style={{ borderBottom: "3px solid #60959c" }}>
<p className="text-lg font-bold leading-snug" style={{ color: "#60959c" }}>
{s.prefix} {s.num} {s.label}
</p>
</div>
))}
</div>
{/* Сетка врачей — 6 колонок */}
<div className="grid grid-cols-6 gap-3">
{DOCTORS.map((doc) => (
<div key={doc.name} className="flex flex-col items-center text-center gap-1.5">
{/* eslint-disable-next-line @next/next/no-img-element */}
<img
src={doc.photo}
alt={doc.name}
style={{
width: 110,
height: 150,
objectFit: "cover",
objectPosition: "center top",
borderRadius: 4,
display: "block",
}}
/>
<div>
<p className="text-xs font-medium leading-snug" style={{ color: "#60959c" }}>
{doc.name}
</p>
<p className="text-[11px] mt-0.5 leading-snug" style={{ color: "#374151" }}>
{doc.spec}
</p>
</div>
</div>
))}
</div>
</div>
);
}
+101
View File
@@ -0,0 +1,101 @@
export const HERO_CHECKS = [
{ key: "БЕЗОПАСНО", desc: "оперируют хирурги с 15-летним опытом работы" },
{ key: "БЕЗ ВНЕШНИХ РАЗРЕЗОВ", desc: "хирургия сверхмалых размеров" },
{ key: "БЫСТРО", desc: "под наблюдением врача пациент находится 1 сутки" },
];
export function HeroBlock() {
return (
<div className="space-y-3">
{/* H1 страницы */}
<h2
className="text-xl font-bold leading-snug"
style={{ color: "#53514e" }}
>
ЛОР Клиника ухо, горло, нос медицинский центр лечения ЛОР заболеваний у детей и взрослых
</h2>
{/* Баннер — единый светло-кремовый фон */}
<div
className="rounded-xl overflow-hidden flex"
style={{ background: "#f9f4e7", minHeight: 280 }}
>
{/* Левая часть — контент */}
<div
className="flex flex-col justify-center gap-5 p-8"
style={{ width: "50%", flexShrink: 0 }}
>
<p
className="text-base font-bold uppercase leading-snug"
style={{ color: "#111827" }}
>
Эндоскопическое хирургическое лечение ЛОР органов
</p>
<ul className="space-y-3">
{HERO_CHECKS.map((c) => (
<li key={c.key} className="flex items-start gap-2 text-sm">
<span
className="shrink-0 font-bold"
style={{ color: "#bf9975", marginTop: 1 }}
>
</span>
<span>
<span className="font-bold uppercase" style={{ color: "#111827" }}>
{c.key}
</span>{" "}
<span style={{ color: "#374151" }}> {c.desc}</span>
</span>
</li>
))}
</ul>
<div>
<button className="bb-btn bb-btn-md bb-btn-outline">
Узнать стоимость операции
</button>
</div>
</div>
{/* Правая часть — фото врача */}
<div className="flex-1 relative overflow-hidden" style={{ minHeight: 280 }}>
{/* eslint-disable-next-line @next/next/no-img-element */}
<img
src="/hero-doctor.jpg"
alt="Врач на приёме с пациентом"
style={{
width: "100%",
height: "100%",
objectFit: "cover",
objectPosition: "center top",
position: "absolute",
inset: 0,
}}
/>
</div>
</div>
{/* Под баннером: соцсети + просмотры */}
<div className="flex items-center gap-3 pt-1">
<span className="text-xs" style={{ color: "#9ca3af" }}>
Поделиться:
</span>
{["VK", "FB", "TW"].map((s) => (
<button
key={s}
className="text-xs px-2 py-1 rounded"
style={{
background: "#f9fafb",
border: "1px solid #e5e7eb",
color: "#9ca3af",
}}
>
{s}
</button>
))}
<span className="text-xs ml-2" style={{ color: "#9ca3af" }}>
👁 98 573 просмотра
</span>
</div>
</div>
);
}
+2 -1
View File
@@ -48,6 +48,7 @@ const NAV: NavSection[] = [
{
title: "Страницы",
items: [
{ label: "Просмотр страницы", href: "/pages/preview" },
{ label: "Главная", href: "/pages/home", soon: true },
{ label: "Заболевание", href: "/pages/disease", soon: true },
{ label: "Все врачи", href: "/pages/doctors", soon: true },
@@ -166,7 +167,7 @@ export function Sidebar() {
color: "var(--bb-sidebar-text-muted)",
}}
>
Sprint 5 · v0.5.1
Sprint 5.5 · v0.5.5
</div>
</aside>
);