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:
@@ -1,57 +1,20 @@
|
|||||||
import type { Metadata } from "next";
|
import type { Metadata } from "next";
|
||||||
import { LlmBlock, LlmSection, LlmTable, LlmRules } from "@/components/llm/LlmBlock";
|
import { LlmBlock, LlmSection, LlmTable, LlmRules } from "@/components/llm/LlmBlock";
|
||||||
|
import { DoctorsBlock, STATS, DOCTORS } from "@/components/blocks/DoctorsBlock";
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: "Блок «Наши врачи». Цифровой брендбук Клиники ухо, горло, нос им. проф. Е.Н.Оленевой",
|
title: "Блок «Наши врачи». Цифровой брендбук Клиники ухо, горло, нос им. проф. Е.Н.Оленевой",
|
||||||
};
|
};
|
||||||
|
|
||||||
const STATS = [
|
|
||||||
{ num: "27", label: "ЛОР врачей работает в клинике", prefix: "Ежедневно" },
|
|
||||||
{ num: "6", label: "кандидатов медицинских наук", prefix: "В том числе" },
|
|
||||||
{ num: "12 000+", label: "успешно проведённых операций", prefix: "Свыше" },
|
|
||||||
];
|
|
||||||
|
|
||||||
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",
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const LLM_DOCTORS_TEXT = `
|
const LLM_DOCTORS_TEXT = `
|
||||||
БЛОК: Наши врачи
|
БЛОК: Наши врачи
|
||||||
Источник: perm.oclinica.ru/lor — блок под CEO-текстом
|
Источник: perm.oclinica.ru/lor — блок под CEO-текстом
|
||||||
Версия: v1.0
|
Версия: v1.1
|
||||||
|
|
||||||
СТРУКТУРА БЛОКА:
|
СТРУКТУРА БЛОКА:
|
||||||
1. ЗАГОЛОВОК H2: «Приём ведут опытные ЛОР врачи»
|
1. ЗАГОЛОВОК H2: «Приём ведут опытные ЛОР врачи»
|
||||||
Подзаголовок: описание принципа работы врачей клиники
|
Подзаголовок: описание принципа работы врачей клиники
|
||||||
|
Размер: ~30px (text-3xl), font-bold, #111827
|
||||||
|
|
||||||
2. БЛОК СТАТИСТИКИ (3 показателя в ряд):
|
2. БЛОК СТАТИСТИКИ (3 показателя в ряд):
|
||||||
— «Ежедневно 27 ЛОР врачей работают в клинике»
|
— «Ежедневно 27 ЛОР врачей работают в клинике»
|
||||||
@@ -75,8 +38,8 @@ const LLM_DOCTORS_TEXT = `
|
|||||||
|
|
||||||
ПРАВИЛА:
|
ПРАВИЛА:
|
||||||
✓ Заголовок H2 + описание обязательны
|
✓ Заголовок H2 + описание обязательны
|
||||||
✓ 3 stat-блока в ряд
|
✓ 3 stat-блока в ряд, без фоновых блоков
|
||||||
✓ Сетка 3 колонки, 2 ряда (6 карточек)
|
✓ Сетка 6 колонок (6 карточек в ряд)
|
||||||
✕ Не отображать более 6 врачей в основном блоке
|
✕ Не отображать более 6 врачей в основном блоке
|
||||||
✕ Не убирать статистику
|
✕ Не убирать статистику
|
||||||
`.trim();
|
`.trim();
|
||||||
@@ -106,69 +69,14 @@ export default function DoctorsBlockPage() {
|
|||||||
Живой пример
|
Живой пример
|
||||||
</h2>
|
</h2>
|
||||||
<div
|
<div
|
||||||
className="rounded-xl p-8 space-y-8"
|
className="rounded-xl p-8"
|
||||||
style={{ background: "#fff", border: "1px solid var(--bb-border)" }}
|
style={{ background: "#fff", border: "1px solid var(--bb-border)" }}
|
||||||
>
|
>
|
||||||
{/* Заголовок */}
|
<DoctorsBlock />
|
||||||
<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>
|
|
||||||
|
|
||||||
{/* Статистика — текст тёмно-бирюзовым, без фоновых блоков */}
|
|
||||||
<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>
|
|
||||||
|
|
||||||
{/* Сетка врачей — плотнее, имена тёмно-бирюзовым */}
|
|
||||||
<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>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
{/* Стат-блоки */}
|
{/* Стат-блоки — разбор */}
|
||||||
<section className="space-y-3">
|
<section className="space-y-3">
|
||||||
<h2 className="font-semibold text-base" style={{ color: "var(--bb-text)" }}>
|
<h2 className="font-semibold text-base" style={{ color: "var(--bb-text)" }}>
|
||||||
Блок статистики
|
Блок статистики
|
||||||
@@ -217,17 +125,17 @@ export default function DoctorsBlockPage() {
|
|||||||
<LlmTable
|
<LlmTable
|
||||||
headers={["Поле", "Размер / Стиль"]}
|
headers={["Поле", "Размер / Стиль"]}
|
||||||
rows={[
|
rows={[
|
||||||
["Фото", "88×120px (в блоке) или 110×160px (на странице врачей), object-fit: cover"],
|
["Фото", "110×150px, object-fit: cover, object-position: center top, border-radius 4px"],
|
||||||
["Имя", "12–14px, font-weight 500, #111827"],
|
["Имя", "12px, font-weight 500, #60959c"],
|
||||||
["Специализация", "11–12px, #6b7280"],
|
["Специализация", "11px, #374151"],
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
<LlmSection title="Правила" />
|
<LlmSection title="Правила" />
|
||||||
<LlmRules
|
<LlmRules
|
||||||
rules={[
|
rules={[
|
||||||
{ ok: true, text: "H2 + описание обязательны" },
|
{ ok: true, text: "H2 + описание обязательны" },
|
||||||
{ ok: true, text: "3 stat-блока в ряд, фон #dff0fa" },
|
{ ok: true, text: "3 stat-блока в ряд, без фоновых рамок" },
|
||||||
{ ok: true, text: "Сетка 6 карточек (3 колонки)" },
|
{ ok: true, text: "Сетка 6 карточек в 1 ряд (6 колонок)" },
|
||||||
{ ok: false, text: "Не показывать более 6 врачей в основном блоке" },
|
{ ok: false, text: "Не показывать более 6 врачей в основном блоке" },
|
||||||
{ ok: false, text: "Не убирать статистику" },
|
{ ok: false, text: "Не убирать статистику" },
|
||||||
]}
|
]}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import type { Metadata } from "next";
|
import type { Metadata } from "next";
|
||||||
import { LlmBlock, LlmSection, LlmTable, LlmRules } from "@/components/llm/LlmBlock";
|
import { LlmBlock, LlmSection, LlmTable, LlmRules } from "@/components/llm/LlmBlock";
|
||||||
|
import { HeroBlock, HERO_CHECKS } from "@/components/blocks/HeroBlock";
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: "Hero-баннер. Цифровой брендбук Клиники ухо, горло, нос им. проф. Е.Н.Оленевой",
|
title: "Hero-баннер. Цифровой брендбук Клиники ухо, горло, нос им. проф. Е.Н.Оленевой",
|
||||||
@@ -18,7 +19,7 @@ const LLM_HERO_TEXT = `
|
|||||||
Левая колонка (~50%):
|
Левая колонка (~50%):
|
||||||
— Заголовок: «ЭНДОСКОПИЧЕСКОЕ ХИРУРГИЧЕСКОЕ ЛЕЧЕНИЕ ЛОР ОРГАНОВ»
|
— Заголовок: «ЭНДОСКОПИЧЕСКОЕ ХИРУРГИЧЕСКОЕ ЛЕЧЕНИЕ ЛОР ОРГАНОВ»
|
||||||
Шрифт: Fira Sans, ~18px, weight 700, uppercase, цвет #111827
|
Шрифт: Fira Sans, ~18px, weight 700, uppercase, цвет #111827
|
||||||
— 3 пункта с галочками (✓ зелёный):
|
— 3 пункта с галочками (✓ бежевый #bf9975):
|
||||||
1. «БЕЗОПАСНО – оперируют хирурги с 15-летним опытом работы»
|
1. «БЕЗОПАСНО – оперируют хирурги с 15-летним опытом работы»
|
||||||
2. «БЕЗ ВНЕШНИХ РАЗРЕЗОВ – хирургия сверхмалых размеров»
|
2. «БЕЗ ВНЕШНИХ РАЗРЕЗОВ – хирургия сверхмалых размеров»
|
||||||
3. «БЫСТРО – под наблюдением врача пациент находится 1 сутки»
|
3. «БЫСТРО – под наблюдением врача пациент находится 1 сутки»
|
||||||
@@ -29,7 +30,7 @@ const LLM_HERO_TEXT = `
|
|||||||
— Изображение занимает всю высоту блока
|
— Изображение занимает всю высоту блока
|
||||||
|
|
||||||
ПОД БАННЕРОМ:
|
ПОД БАННЕРОМ:
|
||||||
— Кнопки соцсетей (Facebook, VK, Twitter/X), цвет #6b7280
|
— Кнопки соцсетей (VK, FB, TW), цвет #9ca3af
|
||||||
— Счётчик просмотров
|
— Счётчик просмотров
|
||||||
|
|
||||||
ЦВЕТА:
|
ЦВЕТА:
|
||||||
@@ -37,7 +38,7 @@ const LLM_HERO_TEXT = `
|
|||||||
Кнопка CTA: outline-стиль (светлая), не коралловая
|
Кнопка CTA: outline-стиль (светлая), не коралловая
|
||||||
Заголовок блока: #111827
|
Заголовок блока: #111827
|
||||||
Пункты: ключевое слово #111827 bold, описание #374151
|
Пункты: ключевое слово #111827 bold, описание #374151
|
||||||
Галочка: цвет бренда (бежевый/золотой ~#bf9975)
|
Галочка: #bf9975 (бежевый)
|
||||||
|
|
||||||
ПРАВИЛА:
|
ПРАВИЛА:
|
||||||
✓ Фон баннера всегда #f9f4e7 (светло-кремовый) — единый, без разделения на зоны
|
✓ Фон баннера всегда #f9f4e7 (светло-кремовый) — единый, без разделения на зоны
|
||||||
@@ -48,21 +49,6 @@ const LLM_HERO_TEXT = `
|
|||||||
✕ Не убирать три пункта с галочками
|
✕ Не убирать три пункта с галочками
|
||||||
`.trim();
|
`.trim();
|
||||||
|
|
||||||
const HERO_CHECKS = [
|
|
||||||
{
|
|
||||||
key: "БЕЗОПАСНО",
|
|
||||||
desc: "оперируют хирурги с 15-летним опытом работы",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "БЕЗ ВНЕШНИХ РАЗРЕЗОВ",
|
|
||||||
desc: "хирургия смяткими размерами",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "БЫСТРО",
|
|
||||||
desc: "под наблюдением врача пациент находится 1 сутки",
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
export default function HeroPage() {
|
export default function HeroPage() {
|
||||||
return (
|
return (
|
||||||
<div className="p-8 max-w-5xl mx-auto space-y-10">
|
<div className="p-8 max-w-5xl mx-auto space-y-10">
|
||||||
@@ -78,7 +64,8 @@ export default function HeroPage() {
|
|||||||
Hero-баннер
|
Hero-баннер
|
||||||
</h1>
|
</h1>
|
||||||
<p className="text-sm" style={{ color: "var(--bb-text-muted)" }}>
|
<p className="text-sm" style={{ color: "var(--bb-text-muted)" }}>
|
||||||
Главный баннер страницы раздела ЛОР — perm.oclinica.ru/lor. Двухколоночный блок, единый светло-кремовый фон <strong>#f9f4e7</strong>.
|
Главный баннер страницы раздела ЛОР — perm.oclinica.ru/lor. Двухколоночный блок, единый светло-кремовый фон{" "}
|
||||||
|
<strong>#f9f4e7</strong>.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -87,99 +74,7 @@ export default function HeroPage() {
|
|||||||
<h2 className="font-semibold text-base" style={{ color: "var(--bb-text)" }}>
|
<h2 className="font-semibold text-base" style={{ color: "var(--bb-text)" }}>
|
||||||
Живой пример
|
Живой пример
|
||||||
</h2>
|
</h2>
|
||||||
|
<HeroBlock />
|
||||||
{/* 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: "var(--bb-text-muted)" }}>
|
|
||||||
Поделиться:
|
|
||||||
</span>
|
|
||||||
{["VK", "FB", "TW"].map((s) => (
|
|
||||||
<button
|
|
||||||
key={s}
|
|
||||||
className="text-xs px-2 py-1 rounded"
|
|
||||||
style={{
|
|
||||||
background: "var(--bb-sidebar-bg)",
|
|
||||||
border: "1px solid var(--bb-border)",
|
|
||||||
color: "var(--bb-text-muted)",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{s}
|
|
||||||
</button>
|
|
||||||
))}
|
|
||||||
<span className="text-xs ml-2" style={{ color: "var(--bb-text-muted)" }}>
|
|
||||||
👁 98 573 просмотра
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
{/* Анатомия */}
|
{/* Анатомия */}
|
||||||
@@ -210,7 +105,7 @@ export default function HeroPage() {
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
{/* Пункты с галочками */}
|
{/* Три пункта с галочками */}
|
||||||
<section className="space-y-3">
|
<section className="space-y-3">
|
||||||
<h2 className="font-semibold text-base" style={{ color: "var(--bb-text)" }}>
|
<h2 className="font-semibold text-base" style={{ color: "var(--bb-text)" }}>
|
||||||
Три пункта баннера
|
Три пункта баннера
|
||||||
@@ -222,7 +117,7 @@ export default function HeroPage() {
|
|||||||
className="flex items-start gap-3 p-3 rounded-lg"
|
className="flex items-start gap-3 p-3 rounded-lg"
|
||||||
style={{ background: "var(--bb-sidebar-bg)", border: "1px solid var(--bb-border)" }}
|
style={{ background: "var(--bb-sidebar-bg)", border: "1px solid var(--bb-border)" }}
|
||||||
>
|
>
|
||||||
<span className="font-bold text-lg shrink-0" style={{ color: "#22c55e" }}>
|
<span className="font-bold text-lg shrink-0" style={{ color: "#bf9975" }}>
|
||||||
✓
|
✓
|
||||||
</span>
|
</span>
|
||||||
<div>
|
<div>
|
||||||
@@ -237,7 +132,7 @@ export default function HeroPage() {
|
|||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
<p className="text-xs" style={{ color: "var(--bb-text-muted)" }}>
|
<p className="text-xs" style={{ color: "var(--bb-text-muted)" }}>
|
||||||
Ключевое слово: uppercase + bold. Описание: обычный текст. Галочка: #22c55e.
|
Ключевое слово: uppercase + bold. Описание: обычный текст. Галочка: #bf9975 (бежевый).
|
||||||
</p>
|
</p>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
@@ -265,7 +160,7 @@ export default function HeroPage() {
|
|||||||
["Фон баннера (единый)", "#f9f4e7", "Светло-кремовый фон"],
|
["Фон баннера (единый)", "#f9f4e7", "Светло-кремовый фон"],
|
||||||
["Кнопка CTA", "outline-стиль", "bb-btn-outline"],
|
["Кнопка CTA", "outline-стиль", "bb-btn-outline"],
|
||||||
["Заголовок блока", "#111827", "—"],
|
["Заголовок блока", "#111827", "—"],
|
||||||
["Галочка ✓", "#bf9975", "Бежевый (--brand-081m approx.)"],
|
["Галочка ✓", "#bf9975", "Бежевый"],
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
<LlmSection title="Правила" />
|
<LlmSection title="Правила" />
|
||||||
|
|||||||
@@ -0,0 +1,200 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { useState, useEffect } from "react";
|
||||||
|
import { HeroBlock } from "@/components/blocks/HeroBlock";
|
||||||
|
import { DoctorsBlock } from "@/components/blocks/DoctorsBlock";
|
||||||
|
|
||||||
|
const STORAGE_KEY = "bb-preview-created";
|
||||||
|
|
||||||
|
function BlockPlaceholder({ name, href }: { name: string; href: string }) {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className="w-full py-14 flex flex-col items-center justify-center rounded-xl gap-2"
|
||||||
|
style={{
|
||||||
|
border: "2px dashed #d1d5db",
|
||||||
|
background: "#f9fafb",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<p className="text-sm font-medium" style={{ color: "#6b7280" }}>
|
||||||
|
{name}
|
||||||
|
</p>
|
||||||
|
<a
|
||||||
|
href={href}
|
||||||
|
className="text-xs underline"
|
||||||
|
style={{ color: "var(--brand-053m)" }}
|
||||||
|
>
|
||||||
|
Открыть в брендбуке →
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const BLOCKS: Array<{
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
href: string;
|
||||||
|
ready: boolean;
|
||||||
|
component?: React.ReactNode;
|
||||||
|
}> = [
|
||||||
|
{
|
||||||
|
id: "hero",
|
||||||
|
name: "Hero-баннер",
|
||||||
|
href: "/blocks/hero",
|
||||||
|
ready: true,
|
||||||
|
component: <HeroBlock />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "ceo",
|
||||||
|
name: "Вводный текст (CEO-блок)",
|
||||||
|
href: "/blocks/ceo",
|
||||||
|
ready: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "doctors",
|
||||||
|
name: "Наши врачи",
|
||||||
|
href: "/blocks/doctors",
|
||||||
|
ready: true,
|
||||||
|
component: <DoctorsBlock />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "reviews",
|
||||||
|
name: "Отзывы",
|
||||||
|
href: "/blocks/reviews",
|
||||||
|
ready: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "contact-forms",
|
||||||
|
name: "Формы записи",
|
||||||
|
href: "/blocks/contact-forms",
|
||||||
|
ready: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "news",
|
||||||
|
name: "Новости",
|
||||||
|
href: "/blocks/news",
|
||||||
|
ready: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "footer",
|
||||||
|
name: "Подвал / Контакт",
|
||||||
|
href: "/blocks/contact",
|
||||||
|
ready: false,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const READY_COUNT = BLOCKS.filter((b) => b.ready).length;
|
||||||
|
|
||||||
|
export function PreviewClient() {
|
||||||
|
const [created, setCreated] = useState(false);
|
||||||
|
const [mounted, setMounted] = useState(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setMounted(true);
|
||||||
|
if (localStorage.getItem(STORAGE_KEY) === "true") {
|
||||||
|
setCreated(true);
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
function handleCreate() {
|
||||||
|
localStorage.setItem(STORAGE_KEY, "true");
|
||||||
|
setCreated(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleRebuild() {
|
||||||
|
localStorage.removeItem(STORAGE_KEY);
|
||||||
|
setCreated(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Avoid hydration mismatch — render nothing until mounted
|
||||||
|
if (!mounted) return null;
|
||||||
|
|
||||||
|
/* ── ПУСТОЕ СОСТОЯНИЕ ── */
|
||||||
|
if (!created) {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className="flex flex-col items-center justify-center min-h-screen"
|
||||||
|
style={{ background: "var(--bb-bg)" }}
|
||||||
|
>
|
||||||
|
<div className="text-center max-w-md space-y-5 p-8">
|
||||||
|
<p
|
||||||
|
className="text-xs font-semibold uppercase tracking-widest"
|
||||||
|
style={{ color: "var(--brand-053m)" }}
|
||||||
|
>
|
||||||
|
Страницы
|
||||||
|
</p>
|
||||||
|
<h1 className="text-2xl font-bold" style={{ color: "var(--bb-text)" }}>
|
||||||
|
Просмотр текущей страницы
|
||||||
|
</h1>
|
||||||
|
<p className="text-sm" style={{ color: "var(--bb-text-muted)", lineHeight: 1.7 }}>
|
||||||
|
Нажмите «Создать», чтобы собрать главную страницу{" "}
|
||||||
|
<span className="font-mono text-xs">perm.oclinica.ru/lor</span> из блоков,
|
||||||
|
задокументированных в брендбуке.
|
||||||
|
</p>
|
||||||
|
<div
|
||||||
|
className="flex items-center justify-center gap-2 text-xs px-4 py-2 rounded-lg"
|
||||||
|
style={{ background: "var(--bb-sidebar-bg)", border: "1px solid var(--bb-border)" }}
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
className="inline-block w-2 h-2 rounded-full"
|
||||||
|
style={{ background: "#22c55e" }}
|
||||||
|
/>
|
||||||
|
<span style={{ color: "var(--bb-text-muted)" }}>
|
||||||
|
Готово блоков: {READY_COUNT} из {BLOCKS.length}
|
||||||
|
</span>
|
||||||
|
<span style={{ color: "var(--bb-text-muted)" }}>·</span>
|
||||||
|
<span style={{ color: "var(--bb-text-muted)" }}>
|
||||||
|
{BLOCKS.length - READY_COUNT} плейсхолдеров
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<button onClick={handleCreate} className="bb-btn bb-btn-md bb-btn-primary">
|
||||||
|
Создать
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ── СОЗДАННОЕ СОСТОЯНИЕ ── */
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
{/* Топ-бар */}
|
||||||
|
<div
|
||||||
|
className="sticky top-0 z-10 flex items-center justify-between px-6 py-3 border-b"
|
||||||
|
style={{
|
||||||
|
background: "var(--bb-sidebar-bg)",
|
||||||
|
borderColor: "var(--bb-border)",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<p
|
||||||
|
className="text-xs font-semibold uppercase tracking-widest"
|
||||||
|
style={{ color: "var(--brand-053m)" }}
|
||||||
|
>
|
||||||
|
Просмотр текущей страницы
|
||||||
|
</p>
|
||||||
|
<p className="text-xs mt-0.5" style={{ color: "var(--bb-text-muted)" }}>
|
||||||
|
perm.oclinica.ru/lor · {READY_COUNT}/{BLOCKS.length} блоков готово
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<button onClick={handleRebuild} className="bb-btn bb-btn-sm bb-btn-outline">
|
||||||
|
Пересобрать
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Собранная страница */}
|
||||||
|
<div className="max-w-5xl mx-auto px-8 py-8 space-y-12">
|
||||||
|
{BLOCKS.map((block) =>
|
||||||
|
block.ready && block.component ? (
|
||||||
|
<section key={block.id}>{block.component}</section>
|
||||||
|
) : (
|
||||||
|
<section key={block.id}>
|
||||||
|
<BlockPlaceholder name={block.name} href={block.href} />
|
||||||
|
</section>
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
import type { Metadata } from "next";
|
||||||
|
import { PreviewClient } from "./PreviewClient";
|
||||||
|
|
||||||
|
export const metadata: Metadata = {
|
||||||
|
title:
|
||||||
|
"Просмотр текущей страницы. Цифровой брендбук Клиники ухо, горло, нос им. проф. Е.Н.Оленевой",
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function PreviewPage() {
|
||||||
|
return <PreviewClient />;
|
||||||
|
}
|
||||||
@@ -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>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -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>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -48,6 +48,7 @@ const NAV: NavSection[] = [
|
|||||||
{
|
{
|
||||||
title: "Страницы",
|
title: "Страницы",
|
||||||
items: [
|
items: [
|
||||||
|
{ label: "Просмотр страницы", href: "/pages/preview" },
|
||||||
{ label: "Главная", href: "/pages/home", soon: true },
|
{ label: "Главная", href: "/pages/home", soon: true },
|
||||||
{ label: "Заболевание", href: "/pages/disease", soon: true },
|
{ label: "Заболевание", href: "/pages/disease", soon: true },
|
||||||
{ label: "Все врачи", href: "/pages/doctors", soon: true },
|
{ label: "Все врачи", href: "/pages/doctors", soon: true },
|
||||||
@@ -166,7 +167,7 @@ export function Sidebar() {
|
|||||||
color: "var(--bb-sidebar-text-muted)",
|
color: "var(--bb-sidebar-text-muted)",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Sprint 5 · v0.5.1
|
Sprint 5.5 · v0.5.5
|
||||||
</div>
|
</div>
|
||||||
</aside>
|
</aside>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -229,6 +229,68 @@
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## Sprint 5.5 — «Просмотр текущей страницы» (внеочередной)
|
||||||
|
|
||||||
|
**Цель:** Добавить интерактивный раздел брендбука, который собирает главную страницу из уже задокументированных блоков.
|
||||||
|
Показывает живой превью того, как выглядит сайт на основе данных брендбука.
|
||||||
|
|
||||||
|
### Концепция UX
|
||||||
|
|
||||||
|
**Маршрут:** `/pages/preview`
|
||||||
|
**Сайдбар:** добавить в раздел «Страницы» с пометкой (если ещё нет блоков — показывает заглушку с кнопкой)
|
||||||
|
|
||||||
|
**Два состояния страницы:**
|
||||||
|
|
||||||
|
1. **Пустое состояние** (первый вход, или если превью не создавалось):
|
||||||
|
- Заголовок «Просмотр текущей страницы»
|
||||||
|
- Описание: «Здесь будет собрана главная страница из задокументированных блоков»
|
||||||
|
- Активная кнопка «Создать» (`.bb-btn bb-btn-primary`)
|
||||||
|
- После нажатия → переход в «созданное» состояние
|
||||||
|
|
||||||
|
2. **Созданное состояние** (после нажатия «Создать»):
|
||||||
|
- Превью главной страницы из всех доступных блоков в порядке сверху вниз, как на perm.oclinica.ru/lor
|
||||||
|
- Кнопка «Пересобрать» в шапке (сбрасывает до исходного состояния)
|
||||||
|
- Сборка только из блоков, у которых есть готовый компонент (не mock-заглушки)
|
||||||
|
- Блоки рендерятся как реальные React-компоненты внутри `<section>`
|
||||||
|
|
||||||
|
**Порядок блоков в превью** (по perm.oclinica.ru/lor, только готовые):
|
||||||
|
1. Hero-баннер (`/blocks/hero` → компонент HeroBlock)
|
||||||
|
2. Блок врачей (`/blocks/doctors` → компонент DoctorsBlock)
|
||||||
|
3. Блок отзывов (`/blocks/reviews` → когда будет готов)
|
||||||
|
4. Форма записи (`/blocks/contact-forms` → когда будет готова)
|
||||||
|
5. Блок новостей (`/blocks/news` → когда будет готов)
|
||||||
|
6. Footer (`/blocks/contact` → когда будет готов)
|
||||||
|
|
||||||
|
**Техническая реализация (FE only, без бэкенда):**
|
||||||
|
- Состояние сохраняется в `localStorage` (`preview-created: true/false`)
|
||||||
|
- Каждый задокументированный блок выносится в переиспользуемый React-компонент
|
||||||
|
- Страница `/pages/preview` импортирует компоненты и рендерит их в нужном порядке
|
||||||
|
- Блоки, которых ещё нет → показывается placeholder с текстом «Блок в разработке»
|
||||||
|
|
||||||
|
### Задачи
|
||||||
|
|
||||||
|
- [ ] FE: Страница `/pages/preview` — пустое состояние с кнопкой «Создать»
|
||||||
|
- [ ] FE: Логика `localStorage` — сохранение/сброс состояния превью
|
||||||
|
- [ ] FE: Рефактор `/blocks/hero/page.tsx` — вынести баннер в компонент `HeroBlock` (переиспользуемый)
|
||||||
|
- [ ] FE: Рефактор `/blocks/doctors/page.tsx` — вынести в компонент `DoctorsBlock`
|
||||||
|
- [ ] FE: Placeholder-компонент для блоков, которые ещё не готовы (серая рамка с названием блока)
|
||||||
|
- [ ] FE: Сборка превью: рендер всех доступных компонентов в порядке реального сайта
|
||||||
|
- [ ] FE: Sidebar — добавить «Просмотр страницы» в раздел «Страницы»
|
||||||
|
- [ ] FE: Кнопка «Пересобрать» в созданном состоянии
|
||||||
|
- [ ] Docs: Добавить `/pages/preview` v1.0 в LLM_CONTEXT.md
|
||||||
|
|
||||||
|
### Зависимости
|
||||||
|
- Зависит от: Sprint 5 (блоки hero и doctors уже готовы — ✅)
|
||||||
|
- По мере добавления новых блоков в Sprint 5 — они автоматически подключаются к превью
|
||||||
|
|
||||||
|
### Ожидаемый результат
|
||||||
|
- Раздел «Просмотр текущей страницы» работает в браузере
|
||||||
|
- Кнопка «Создать» собирает главную страницу из задокументированных блоков
|
||||||
|
- Отсутствующие блоки отображаются как плейсхолдеры
|
||||||
|
- Кнопка «Пересобрать» позволяет сбросить и пересоздать
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Sprint 6 — Страницы (сборки из блоков)
|
## Sprint 6 — Страницы (сборки из блоков)
|
||||||
|
|
||||||
**Цель:** Задокументировать полные страницы как сборки уже готовых блоков.
|
**Цель:** Задокументировать полные страницы как сборки уже готовых блоков.
|
||||||
@@ -355,6 +417,7 @@
|
|||||||
| 3 | Кнопки и форм-контролы | FE | CSS реального сайта |
|
| 3 | Кнопки и форм-контролы | FE | CSS реального сайта |
|
||||||
| 4 | Карточки, бейджи, алерты | FE | CSS реального сайта |
|
| 4 | Карточки, бейджи, алерты | FE | CSS реального сайта |
|
||||||
| 5 | ВСЕ блоки сайта | FE | Все блоки /lor, mock-данные |
|
| 5 | ВСЕ блоки сайта | FE | Все блоки /lor, mock-данные |
|
||||||
|
| 5.5 | Просмотр текущей страницы | FE | Кнопка «Создать», сборка из блоков, localStorage |
|
||||||
| 6 | Все страницы (сборки) | FE | Сборки из блоков, mock-данные |
|
| 6 | Все страницы (сборки) | FE | Сборки из блоков, mock-данные |
|
||||||
| 7 | Авторизация (viewer / editor) | BE + FE | JWT, роли, login-страница, шапка с именем |
|
| 7 | Авторизация (viewer / editor) | BE + FE | JWT, роли, login-страница, шапка с именем |
|
||||||
| 8 | Реальные данные | BE + FE | NestJS прокси → oclinica.ru, кэш 15 мин |
|
| 8 | Реальные данные | BE + FE | NestJS прокси → oclinica.ru, кэш 15 мин |
|
||||||
|
|||||||
Reference in New Issue
Block a user