Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6ce176f970 | |||
| 6c5b571884 | |||
| 2b66fb9cc1 | |||
| 3811c579fd | |||
| 2b9319e70d |
@@ -0,0 +1,629 @@
|
||||
import type { Metadata } from "next";
|
||||
import { CodeCopy } from "@/components/ui/CodeCopy";
|
||||
import { LlmBlock, LlmSection, LlmTable, LlmRules } from "@/components/llm/LlmBlock";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Карточки. Цифровой брендбук Клиники ухо, горло, нос им. проф. Е.Н.Оленевой",
|
||||
};
|
||||
|
||||
function Section({
|
||||
id, title, subtitle, children,
|
||||
}: {
|
||||
id?: string; title: string; subtitle?: string; children: React.ReactNode;
|
||||
}) {
|
||||
return (
|
||||
<section id={id} className="mb-14">
|
||||
<div className="mb-6">
|
||||
<h2 className="text-xl font-semibold" style={{ color: "var(--bb-text)" }}>{title}</h2>
|
||||
{subtitle && <p className="mt-1 text-sm" style={{ color: "var(--bb-text-muted)" }}>{subtitle}</p>}
|
||||
</div>
|
||||
{children}
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
/* ─── Карточка врача ────────────────────────────────────────────────── */
|
||||
function DoctorCard({
|
||||
name, specialty, experience, photo,
|
||||
}: {
|
||||
name: string; specialty: string; experience: string; photo?: string;
|
||||
}) {
|
||||
return (
|
||||
<div
|
||||
className="flex gap-4 p-4 rounded-xl border bg-white transition-shadow"
|
||||
style={{ borderColor: "var(--bb-border)" }}
|
||||
>
|
||||
{/* Фото */}
|
||||
<div
|
||||
className="shrink-0 rounded-lg overflow-hidden"
|
||||
style={{ width: 110, height: 160, background: "#dff0fa" }}
|
||||
>
|
||||
{photo ? (
|
||||
<img src={photo} alt={name} style={{ width: "100%", height: "100%", objectFit: "cover" }} />
|
||||
) : (
|
||||
<div
|
||||
className="w-full h-full flex flex-col items-center justify-center gap-1"
|
||||
style={{ color: "var(--brand-053m)", opacity: 0.5 }}
|
||||
>
|
||||
<svg width="40" height="40" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5">
|
||||
<path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2" />
|
||||
<circle cx="12" cy="7" r="4" />
|
||||
</svg>
|
||||
<span className="text-xs">фото</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Информация */}
|
||||
<div className="flex flex-col justify-between min-w-0">
|
||||
<div>
|
||||
<h3 className="font-semibold text-sm leading-tight mb-1" style={{ color: "var(--bb-text)" }}>
|
||||
{name}
|
||||
</h3>
|
||||
<p className="text-xs mb-2" style={{ color: "var(--bb-text-muted)" }}>{specialty}</p>
|
||||
<p className="text-xs" style={{ color: "var(--brand-053m)" }}>{experience}</p>
|
||||
</div>
|
||||
<button className="bb-btn bb-btn-sm bb-btn-outline mt-3 self-start">
|
||||
Записаться
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
/* ─── Карточка новости ──────────────────────────────────────────────── */
|
||||
function NewsCard({
|
||||
date, title, snippet, category,
|
||||
}: {
|
||||
date: string; title: string; snippet: string; category?: string;
|
||||
}) {
|
||||
return (
|
||||
<div
|
||||
className="bb-news-card rounded-xl border overflow-hidden cursor-pointer transition-all"
|
||||
style={{ borderColor: "var(--bb-border)", background: "#fff" }}
|
||||
>
|
||||
{/* Превью */}
|
||||
<div
|
||||
className="h-36 flex items-center justify-center"
|
||||
style={{ background: "#f0f9ff" }}
|
||||
>
|
||||
{category && (
|
||||
<span
|
||||
className="px-3 py-1 rounded-full text-xs font-semibold"
|
||||
style={{ background: "var(--brand-053m)", color: "#fff" }}
|
||||
>
|
||||
{category}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Контент */}
|
||||
<div className="p-4">
|
||||
<p className="text-xs mb-2" style={{ color: "var(--bb-text-muted)" }}>{date}</p>
|
||||
<h3 className="font-semibold text-sm leading-tight mb-2" style={{ color: "var(--bb-text)" }}>
|
||||
{title}
|
||||
</h3>
|
||||
<p className="text-xs leading-relaxed mb-3" style={{ color: "var(--bb-text-muted)" }}>
|
||||
{snippet}
|
||||
</p>
|
||||
<span className="text-xs font-medium" style={{ color: "var(--brand-053m)" }}>
|
||||
Читать далее →
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
/* ─── Карточка отзыва ───────────────────────────────────────────────── */
|
||||
function ReviewCard({
|
||||
author, date, text, rating, doctor,
|
||||
}: {
|
||||
author: string; date: string; text: string; rating: number; doctor?: string;
|
||||
}) {
|
||||
return (
|
||||
<div
|
||||
className="rounded-xl border p-5"
|
||||
style={{ borderColor: "var(--bb-border)", background: "#eef4d1" }}
|
||||
>
|
||||
{/* Звёзды */}
|
||||
<div className="flex gap-0.5 mb-3">
|
||||
{Array.from({ length: 5 }, (_, i) => (
|
||||
<svg key={i} width="16" height="16" viewBox="0 0 24 24" fill={i < rating ? "#f59e0b" : "none"} stroke="#f59e0b" strokeWidth="1.5">
|
||||
<polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2" />
|
||||
</svg>
|
||||
))}
|
||||
<span className="text-xs ml-1 font-medium" style={{ color: "#92400e" }}>{rating}/5</span>
|
||||
</div>
|
||||
|
||||
{/* Текст */}
|
||||
<p
|
||||
className="text-sm leading-relaxed mb-4"
|
||||
style={{
|
||||
color: "var(--bb-text)",
|
||||
display: "-webkit-box",
|
||||
WebkitLineClamp: 4,
|
||||
WebkitBoxOrient: "vertical",
|
||||
overflow: "hidden",
|
||||
}}
|
||||
>
|
||||
{text}
|
||||
</p>
|
||||
|
||||
{/* Автор */}
|
||||
<div className="flex items-end justify-between">
|
||||
<div>
|
||||
<p className="text-sm font-semibold" style={{ color: "var(--bb-text)" }}>{author}</p>
|
||||
{doctor && <p className="text-xs mt-0.5" style={{ color: "var(--bb-text-muted)" }}>Врач: {doctor}</p>}
|
||||
</div>
|
||||
<p className="text-xs" style={{ color: "var(--bb-text-muted)" }}>{date}</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
/* ─── Карточка цены ─────────────────────────────────────────────────── */
|
||||
function PriceCard({
|
||||
service, price, description, highlighted,
|
||||
}: {
|
||||
service: string; price: string; description?: string; highlighted?: boolean;
|
||||
}) {
|
||||
return (
|
||||
<div
|
||||
className="rounded-xl border p-5 flex flex-col gap-3"
|
||||
style={{
|
||||
borderColor: highlighted ? "var(--brand-053m)" : "var(--bb-border)",
|
||||
background: highlighted ? "#f0f9ff" : "#fff",
|
||||
}}
|
||||
>
|
||||
<div className="flex items-start justify-between gap-3">
|
||||
<p className="text-sm font-medium flex-1" style={{ color: "var(--bb-text)" }}>{service}</p>
|
||||
<p className="text-lg font-bold shrink-0" style={{ color: highlighted ? "var(--brand-053m)" : "var(--bb-text)" }}>
|
||||
{price}
|
||||
</p>
|
||||
</div>
|
||||
{description && (
|
||||
<p className="text-xs" style={{ color: "var(--bb-text-muted)" }}>{description}</p>
|
||||
)}
|
||||
<button className="bb-btn bb-btn-sm bb-btn-outline self-start">
|
||||
Записаться
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
/* ─── Карточка услуги ───────────────────────────────────────────────── */
|
||||
function ServiceCard({
|
||||
title, description, icon,
|
||||
}: {
|
||||
title: string; description: string; icon: string;
|
||||
}) {
|
||||
return (
|
||||
<div
|
||||
className="bb-service-card rounded-xl border p-5 flex flex-col gap-3 cursor-pointer transition-shadow"
|
||||
style={{ borderColor: "var(--bb-border)", background: "#fff" }}
|
||||
>
|
||||
<div
|
||||
className="w-12 h-12 rounded-xl flex items-center justify-center text-2xl"
|
||||
style={{ background: "#dff0fa" }}
|
||||
>
|
||||
{icon}
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="font-semibold text-sm mb-1" style={{ color: "var(--bb-text)" }}>{title}</h3>
|
||||
<p className="text-xs leading-relaxed" style={{ color: "var(--bb-text-muted)" }}>{description}</p>
|
||||
</div>
|
||||
<span className="text-xs font-medium" style={{ color: "var(--brand-053m)" }}>
|
||||
Подробнее →
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
/* ─── LLM текст ─────────────────────────────────────────────────────── */
|
||||
const LLM_CARDS_TEXT = `КАРТОЧКИ — LLM-спецификация
|
||||
Версия: v1.0 · /components/cards
|
||||
|
||||
КАРТОЧКА ВРАЧА (DoctorCard)
|
||||
Структура: фото (110×160px) + имя + специализация + опыт + кнопка «Записаться»
|
||||
Фото: 110px × 160px, object-fit: cover, border-radius: 8px, фон-placeholder: #dff0fa
|
||||
Кнопка: .bb-btn-outline .bb-btn-sm
|
||||
Источник: .doctor на perm.oclinica.ru
|
||||
|
||||
КАРТОЧКА НОВОСТИ (NewsCard)
|
||||
Структура: превью (h=144px) + дата + заголовок + анонс (4 строки) + «Читать далее →»
|
||||
Hover: background #eef4d1 + box-shadow 0 0 16px #9e9e9a
|
||||
Источник: #block-views-last-news-block-1 .views-column на сайте (200×200px)
|
||||
Без hover: background #fff, border 1px
|
||||
|
||||
КАРТОЧКА ОТЗЫВА (ReviewCard)
|
||||
Структура: рейтинг (звёзды 1–5) + текст (4 строки, overflow hidden) + автор + дата + врач
|
||||
Фон: #eef4d1 (светло-жёлтый) — из реального CSS сайта
|
||||
Звёзды: SVG polygon, filled #f59e0b
|
||||
|
||||
КАРТОЧКА ЦЕНЫ (PriceCard)
|
||||
Структура: услуга + цена (bold) + описание + кнопка
|
||||
highlighted-вариант: border var(--brand-053m), bg #f0f9ff, цена тоже --brand-053m
|
||||
|
||||
КАРТОЧКА УСЛУГИ (ServiceCard)
|
||||
Структура: иконка (emoji, 48×48px, bg #dff0fa) + заголовок + описание + «Подробнее →»
|
||||
Hover: box-shadow (0.5rem smth)
|
||||
|
||||
БЕЙДЖИ (Badge)
|
||||
Варианты: primary (#0089c3), success (#059669), warning (#d97706), danger (#dc2626), neutral (#6b7280)
|
||||
Размер: text-xs, px-2.5 py-0.5, border-radius: full
|
||||
CSS: inline-flex, font-weight: 600
|
||||
|
||||
ТЕГИ (Tag)
|
||||
Варианты: default (border, text), filled (bg), removable (с кнопкой ×)
|
||||
Цвет: --brand-053m или нейтральный (#e5e7eb bg)
|
||||
Размер: text-xs, px-2 py-1, border-radius: 4px
|
||||
|
||||
АЛЕРТЫ (Alert)
|
||||
Варианты: info (#dff0fa фон, #075985 текст), success (#d1fae5, #065f46), warning (#fef3c7, #92400e), error (#fee2e2, #991b1b)
|
||||
Структура: иконка (16×16px) + заголовок + описание
|
||||
Без кнопки закрыть в базовом варианте
|
||||
|
||||
ПРАВИЛА
|
||||
✓ DoctorCard: всегда показывать фото-placeholder если нет фото (не ломать layout)
|
||||
✓ ReviewCard: обрезать текст после 4 строк (WebkitLineClamp)
|
||||
✓ PriceCard: highlighted = акционная или рекомендуемая позиция
|
||||
✓ NewsCard: hover-эффект обязателен (#eef4d1 + box-shadow)
|
||||
✓ Badge: не более 2–3 бейджей рядом
|
||||
✓ Alert: одновременно не более 1 alert одного типа на экране
|
||||
✕ Не смешивать типы карточек в одной сетке без заголовка секции
|
||||
✕ Не использовать ReviewCard без рейтинга`.trim();
|
||||
|
||||
/* ─── Данные примеров ───────────────────────────────────────────────── */
|
||||
const DOCTORS = [
|
||||
{
|
||||
name: "Иванова Анна Сергеевна",
|
||||
specialty: "Оториноларинголог (ЛОР), высшая категория",
|
||||
experience: "Стаж 18 лет",
|
||||
},
|
||||
{
|
||||
name: "Петров Дмитрий Александрович",
|
||||
specialty: "Сурдолог, аудиолог",
|
||||
experience: "Стаж 12 лет",
|
||||
},
|
||||
{
|
||||
name: "Соколова Мария Ивановна",
|
||||
specialty: "Детский ЛОР, ринолог",
|
||||
experience: "Стаж 9 лет",
|
||||
},
|
||||
];
|
||||
|
||||
const REVIEWS = [
|
||||
{
|
||||
author: "Елена К.",
|
||||
date: "15 марта 2026",
|
||||
rating: 5,
|
||||
doctor: "Иванова А.С.",
|
||||
text: "Очень довольна визитом. Доктор внимательно выслушала все жалобы, провела осмотр и объяснила причину заболевания. Назначила лечение, которое помогло уже через 3 дня. Рекомендую!",
|
||||
},
|
||||
{
|
||||
author: "Михаил Р.",
|
||||
date: "10 марта 2026",
|
||||
rating: 4,
|
||||
doctor: "Петров Д.А.",
|
||||
text: "Хороший специалист, всё объяснил понятно. Подождал немного дольше, чем ожидал, но качество приёма на высоте. Буду обращаться снова.",
|
||||
},
|
||||
];
|
||||
|
||||
const PRICES = [
|
||||
{ service: "Первичный приём ЛОР-врача", price: "1 500 ₽", description: "Включает осмотр и консультацию" },
|
||||
{ service: "Повторный приём", price: "1 000 ₽", description: "До 14 дней после первичного" },
|
||||
{ service: "Промывание миндалин", price: "800 ₽", highlighted: true, description: "Аппаратное — аккустический вакуум" },
|
||||
{ service: "Аудиометрия", price: "1 200 ₽", description: "Исследование слуха" },
|
||||
];
|
||||
|
||||
const SERVICES = [
|
||||
{ title: "Лечение ангины и тонзиллита", description: "Консервативное и хирургическое лечение заболеваний миндалин", icon: "🦷" },
|
||||
{ title: "Аудиология и сурдология", description: "Диагностика нарушений слуха, подбор слуховых аппаратов", icon: "👂" },
|
||||
{ title: "Детский ЛОР", description: "Специализация на лечении ЛОР-заболеваний у детей от 0 лет", icon: "👶" },
|
||||
{ title: "Ринология", description: "Лечение заболеваний носа и придаточных пазух", icon: "👃" },
|
||||
];
|
||||
|
||||
/* ─── Коды примеров ─────────────────────────────────────────────────── */
|
||||
const codeDoctorCard = `<!-- Карточка врача -->
|
||||
<div class="doctor-card">
|
||||
<img src="doctor.jpg" width="110" height="160" alt="ФИО" />
|
||||
<div class="doctor-info">
|
||||
<h3>Иванова Анна Сергеевна</h3>
|
||||
<p class="specialty">Оториноларинголог, высшая категория</p>
|
||||
<p class="experience">Стаж 18 лет</p>
|
||||
<button class="bb-btn bb-btn-sm bb-btn-outline">Записаться</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
/* CSS с сайта oclinica.ru */
|
||||
.doctor .image { float:left; margin-right:20px; width:110px; height:160px; }
|
||||
.doctor .item { float:left; width:170px; }
|
||||
.doctor h3 { margin-top:0; height:32px; }`;
|
||||
|
||||
const codeNewsCard = `<!-- Карточка новости (сайт: 200×200px) -->
|
||||
<div class="news-card">
|
||||
<div class="news-preview">...</div>
|
||||
<div class="news-body">
|
||||
<time>15 марта 2026</time>
|
||||
<h3>Заголовок новости</h3>
|
||||
<p>Краткий анонс...</p>
|
||||
<a href="#">Читать далее →</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
/* CSS с сайта */
|
||||
#block-views-last-news-block-1 .views-column {
|
||||
background: #fff; width: 200px; height: 200px;
|
||||
margin: 15px 8px; padding: 15px;
|
||||
}
|
||||
#block-views-last-news-block-1 .views-column:hover {
|
||||
background: #eef4d1;
|
||||
box-shadow: 0px 0px 16px 0px #9e9e9a;
|
||||
}`;
|
||||
|
||||
const codeReviewCard = `<!-- Карточка отзыва -->
|
||||
<div class="review-card">
|
||||
<div class="stars">★★★★★</div>
|
||||
<p class="text">Текст отзыва (4 строки, overflow: hidden)...</p>
|
||||
<div class="author">
|
||||
<span>Елена К.</span>
|
||||
<time>15 марта 2026</time>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
/* Стиль брендбука (фон из CSS сайта) */
|
||||
.review-card { background: #eef4d1; border-radius: 12px; padding: 20px; }`;
|
||||
|
||||
const codePriceCard = `<!-- Карточка цены -->
|
||||
<div class="price-card">
|
||||
<div class="price-row">
|
||||
<span class="service">Первичный приём ЛОР-врача</span>
|
||||
<strong class="price">1 500 ₽</strong>
|
||||
</div>
|
||||
<p class="description">Включает осмотр и консультацию</p>
|
||||
<button class="bb-btn bb-btn-sm bb-btn-outline">Записаться</button>
|
||||
</div>`;
|
||||
|
||||
const codeBadges = `<!-- Бейджи -->
|
||||
<span class="bb-badge bb-badge-primary">ЛОР</span>
|
||||
<span class="bb-badge bb-badge-success">Принимает</span>
|
||||
<span class="bb-badge bb-badge-warning">Ожидает</span>
|
||||
<span class="bb-badge bb-badge-danger">Не принимает</span>
|
||||
<span class="bb-badge bb-badge-neutral">Высшая категория</span>
|
||||
|
||||
<!-- Теги -->
|
||||
<button class="bb-tag">Ухо</button>
|
||||
<button class="bb-tag">Горло</button>
|
||||
<button class="bb-tag bb-tag-active">Нос</button>
|
||||
|
||||
<!-- Алерт -->
|
||||
<div class="bb-alert bb-alert-info">
|
||||
<span class="bb-alert-icon">ℹ</span>
|
||||
<div>
|
||||
<strong>Запись открыта</strong>
|
||||
<p>Вы можете записаться онлайн или по телефону.</p>
|
||||
</div>
|
||||
</div>`;
|
||||
|
||||
export default function CardsPage() {
|
||||
return (
|
||||
<div className="max-w-4xl mx-auto px-8 py-10">
|
||||
|
||||
{/* Заголовок */}
|
||||
<div className="mb-10 pb-6 border-b" style={{ borderColor: "var(--bb-border)" }}>
|
||||
<p className="text-xs font-semibold uppercase tracking-widest mb-2" style={{ color: "var(--brand-053m)" }}>
|
||||
Компоненты → 3.3
|
||||
</p>
|
||||
<h1 className="text-3xl font-semibold mb-3" style={{ color: "var(--bb-text)" }}>
|
||||
Карточки
|
||||
</h1>
|
||||
<p className="text-base max-w-2xl" style={{ color: "var(--bb-text-muted)" }}>
|
||||
Карточки врача, новости, отзыва, цены и услуги — основные блоки контента сайта.
|
||||
Бейджи, теги и алерты — вспомогательные элементы.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* 1. Карточки врачей */}
|
||||
<Section
|
||||
id="doctor"
|
||||
title="Карточка врача"
|
||||
subtitle="Фото 110×160px, имя, специализация, стаж, кнопка записи. Соответствует .doctor на сайте."
|
||||
>
|
||||
<div className="grid grid-cols-1 sm:grid-cols-3 gap-4">
|
||||
{DOCTORS.map(d => <DoctorCard key={d.name} {...d} />)}
|
||||
</div>
|
||||
</Section>
|
||||
|
||||
{/* 2. Карточки новостей */}
|
||||
<Section
|
||||
id="news"
|
||||
title="Карточка новости"
|
||||
subtitle="Hover: bg #eef4d1 + box-shadow. Источник: #block-views-last-news-block-1 на сайте."
|
||||
>
|
||||
<div className="grid grid-cols-1 sm:grid-cols-3 gap-4">
|
||||
<NewsCard
|
||||
date="15 марта 2026"
|
||||
category="ЛОР"
|
||||
title="Как правильно промывать нос при насморке"
|
||||
snippet="Промывание носа — эффективный метод лечения и профилактики острого ринита. Рассказываем о правильной технике."
|
||||
/>
|
||||
<NewsCard
|
||||
date="10 марта 2026"
|
||||
category="Аудиология"
|
||||
title="Новый слуховой аппарат в нашей клинике"
|
||||
snippet="Мы начали подбор и настройку слуховых аппаратов нового поколения — незаметных и точных."
|
||||
/>
|
||||
<NewsCard
|
||||
date="5 марта 2026"
|
||||
title="Весенняя профилактика ЛОР-заболеваний"
|
||||
snippet="Апрель — период обострений. Рекомендации нашего специалиста по укреплению иммунитета и защите."
|
||||
/>
|
||||
</div>
|
||||
<p className="mt-3 text-xs" style={{ color: "var(--bb-text-muted)" }}>
|
||||
* Наведите на карточку чтобы увидеть hover-эффект
|
||||
</p>
|
||||
</Section>
|
||||
|
||||
{/* 3. Карточки отзывов */}
|
||||
<Section
|
||||
id="review"
|
||||
title="Карточка отзыва"
|
||||
subtitle="Рейтинг (1–5 звёзд), текст 4 строки, автор, дата, врач. Фон #eef4d1 — с реального сайта."
|
||||
>
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||
{REVIEWS.map(r => <ReviewCard key={r.author} {...r} />)}
|
||||
</div>
|
||||
</Section>
|
||||
|
||||
{/* 4. Карточки цен */}
|
||||
<Section
|
||||
id="price"
|
||||
title="Карточка цены"
|
||||
subtitle="Услуга + стоимость + описание + кнопка. Highlighted-вариант для акционных позиций."
|
||||
>
|
||||
<div className="flex flex-col gap-3">
|
||||
{PRICES.map(p => <PriceCard key={p.service} {...p} />)}
|
||||
</div>
|
||||
</Section>
|
||||
|
||||
{/* 5. Карточки услуг */}
|
||||
<Section
|
||||
id="service"
|
||||
title="Карточка услуги"
|
||||
subtitle="Иконка + заголовок + описание + ссылка. Применяется в блоке «Наши услуги»."
|
||||
>
|
||||
<div className="grid grid-cols-2 sm:grid-cols-4 gap-4">
|
||||
{SERVICES.map(s => <ServiceCard key={s.title} {...s} />)}
|
||||
</div>
|
||||
</Section>
|
||||
|
||||
{/* 6. Бейджи и теги */}
|
||||
<Section
|
||||
id="badges"
|
||||
title="Бейджи и теги"
|
||||
subtitle="Статусные бейджи, теги-категории, алерты."
|
||||
>
|
||||
{/* Бейджи */}
|
||||
<div className="mb-8">
|
||||
<p className="text-sm font-medium mb-3" style={{ color: "var(--bb-text)" }}>Бейджи (статус)</p>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{[
|
||||
{ label: "Основной", bg: "var(--brand-053m)", color: "#fff" },
|
||||
{ label: "Принимает", bg: "#059669", color: "#fff" },
|
||||
{ label: "Высшая категория", bg: "#d97706", color: "#fff" },
|
||||
{ label: "Не принимает", bg: "#dc2626", color: "#fff" },
|
||||
{ label: "Нейтральный", bg: "#6b7280", color: "#fff" },
|
||||
{ label: "Новинка", bg: "#dff0fa", color: "var(--brand-053m)" },
|
||||
].map(b => (
|
||||
<span
|
||||
key={b.label}
|
||||
className="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-semibold"
|
||||
style={{ background: b.bg, color: b.color }}
|
||||
>
|
||||
{b.label}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Теги */}
|
||||
<div className="mb-8">
|
||||
<p className="text-sm font-medium mb-3" style={{ color: "var(--bb-text)" }}>Теги (категории)</p>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{["Ухо", "Горло", "Нос", "Аудиология", "Детский ЛОР", "Хирургия"].map((tag, i) => (
|
||||
<button
|
||||
key={tag}
|
||||
className="inline-flex items-center px-3 py-1 rounded text-xs font-medium border transition-colors"
|
||||
style={
|
||||
i === 0
|
||||
? { background: "var(--brand-053m)", color: "#fff", borderColor: "var(--brand-053m)" }
|
||||
: { background: "#fff", color: "var(--bb-text)", borderColor: "var(--bb-border)" }
|
||||
}
|
||||
>
|
||||
{tag}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Алерты */}
|
||||
<div>
|
||||
<p className="text-sm font-medium mb-3" style={{ color: "var(--bb-text)" }}>Алерты</p>
|
||||
<div className="flex flex-col gap-3">
|
||||
{[
|
||||
{ type: "info", bg: "#dff0fa", color: "#075985", icon: "ℹ", title: "Информация", text: "Запись открыта. Вы можете записаться онлайн или по телефону." },
|
||||
{ type: "success", bg: "#d1fae5", color: "#065f46", icon: "✓", title: "Успешно", text: "Ваша запись подтверждена. Ждём вас 20 марта в 10:00." },
|
||||
{ type: "warning", bg: "#fef3c7", color: "#92400e", icon: "⚠", title: "Внимание", text: "Не забудьте взять паспорт и полис ОМС на приём." },
|
||||
{ type: "error", bg: "#fee2e2", color: "#991b1b", icon: "✕", title: "Ошибка", text: "К сожалению, это время уже занято. Выберите другое." },
|
||||
].map(a => (
|
||||
<div
|
||||
key={a.type}
|
||||
className="flex gap-3 p-4 rounded-xl border"
|
||||
style={{ background: a.bg, borderColor: a.bg, color: a.color }}
|
||||
>
|
||||
<span className="text-base font-bold shrink-0 mt-0.5">{a.icon}</span>
|
||||
<div>
|
||||
<p className="text-sm font-semibold mb-0.5">{a.title}</p>
|
||||
<p className="text-sm opacity-90">{a.text}</p>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</Section>
|
||||
|
||||
{/* 7. Код */}
|
||||
<Section
|
||||
id="code"
|
||||
title="Примеры кода"
|
||||
subtitle="HTML-структура и CSS-справка."
|
||||
>
|
||||
<div className="space-y-4">
|
||||
<CodeCopy lang="HTML — DoctorCard + CSS с сайта" code={codeDoctorCard} />
|
||||
<CodeCopy lang="HTML — NewsCard + CSS с сайта" code={codeNewsCard} />
|
||||
<CodeCopy lang="HTML — ReviewCard" code={codeReviewCard} />
|
||||
<CodeCopy lang="HTML — PriceCard" code={codePriceCard} />
|
||||
<CodeCopy lang="HTML — Badges, Tags, Alerts" code={codeBadges} />
|
||||
</div>
|
||||
</Section>
|
||||
|
||||
{/* LLM-блок */}
|
||||
<LlmBlock path="/components/cards" version="v1.0" specText={LLM_CARDS_TEXT}>
|
||||
<LlmSection title="Типы карточек" />
|
||||
<LlmTable
|
||||
headers={["Карточка", "Ключевые размеры", "Источник на сайте", "Фон / hover"]}
|
||||
rows={[
|
||||
["DoctorCard", "фото 110×160px, layout: flex", ".doctor .image + .doctor .item", "#fff / —"],
|
||||
["NewsCard", "preview h=144px, grid 3 col", "#block-views-last-news-block-1 .views-column", "#fff / #eef4d1 + shadow"],
|
||||
["ReviewCard", "4 строки текста, рейтинг", ".node-reviews", "#eef4d1 / —"],
|
||||
["PriceCard", "flex row: name + price", ".field-name-field-price-priem", "#fff / highlighted: #f0f9ff"],
|
||||
["ServiceCard", "иконка 48×48, grid 4 col", "—", "#fff / shadow"],
|
||||
]}
|
||||
/>
|
||||
<LlmSection title="Бейджи, теги, алерты" />
|
||||
<LlmTable
|
||||
headers={["Элемент", "Варианты", "Размер", "Применение"]}
|
||||
rows={[
|
||||
["Badge", "primary / success / warning / danger / neutral", "text-xs, px-2.5, rounded-full", "Статус врача, категория, акция"],
|
||||
["Tag", "default / active", "text-xs, px-3, rounded-4px", "Фильтры, категории услуг"],
|
||||
["Alert", "info / success / warning / error", "p-4, border-radius 12px", "Системные сообщения пользователю"],
|
||||
]}
|
||||
/>
|
||||
<LlmSection title="Правила применения" />
|
||||
<LlmRules
|
||||
rules={[
|
||||
{ ok: true, text: "DoctorCard: всегда фото-placeholder если нет фото" },
|
||||
{ ok: true, text: "NewsCard: hover #eef4d1 + box-shadow (из реального CSS сайта)" },
|
||||
{ ok: true, text: "ReviewCard: обрезать текст после 4 строк (WebkitLineClamp: 4)" },
|
||||
{ ok: true, text: "PriceCard highlighted = акционная / рекомендуемая позиция" },
|
||||
{ ok: true, text: "Alert: один тип одновременно на экране" },
|
||||
{ ok: false, text: "Не смешивать типы карточек в одной сетке без заголовка" },
|
||||
{ ok: false, text: "Не использовать ReviewCard без рейтинга" },
|
||||
{ ok: false, text: "Не ставить более 3 бейджей рядом" },
|
||||
]}
|
||||
/>
|
||||
</LlmBlock>
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -55,42 +55,42 @@ const BRAND_COLORS = [
|
||||
{
|
||||
oracal: "053M",
|
||||
name: "Основной бирюзовый",
|
||||
hex: "#7ecfca",
|
||||
hex: "#0089c3",
|
||||
usage: "Акцентный цвет, CTA-кнопки, иконки, активные состояния",
|
||||
cssVar: "--brand-053m",
|
||||
},
|
||||
{
|
||||
oracal: "073M",
|
||||
name: "Тёмный серо-голубой",
|
||||
hex: "#5b7b87",
|
||||
hex: "#53514e",
|
||||
usage: "Тёмный фон, хедер, акценты на тёмных поверхностях",
|
||||
cssVar: "--brand-073m",
|
||||
},
|
||||
{
|
||||
oracal: "066M",
|
||||
name: "Средний бирюзовый",
|
||||
hex: "#5bb5ad",
|
||||
hex: "#00818c",
|
||||
usage: "Вторичные акценты, фоны секций, иллюстрации",
|
||||
cssVar: "--brand-066m",
|
||||
},
|
||||
{
|
||||
oracal: "050M",
|
||||
name: "Тёмно-синий",
|
||||
hex: "#1b4c72",
|
||||
hex: "#1b2e5d",
|
||||
usage: "Наружная реклама, полиграфия, заголовки на светлом фоне",
|
||||
cssVar: "--brand-050m",
|
||||
},
|
||||
{
|
||||
oracal: "081M",
|
||||
name: "Бежевый",
|
||||
hex: "#c4a882",
|
||||
hex: "#a8885c",
|
||||
usage: "Форма сотрудников, оффлайн носители, тёплые акценты",
|
||||
cssVar: "--brand-081m",
|
||||
},
|
||||
{
|
||||
oracal: "080M",
|
||||
name: "Тёмно-коричневый",
|
||||
hex: "#5c2e0e",
|
||||
hex: "#432f1e",
|
||||
usage: "Текст на бежевых поверхностях, логотип на форме",
|
||||
cssVar: "--brand-080m",
|
||||
},
|
||||
@@ -106,32 +106,32 @@ const BRAND_COLORS = [
|
||||
/* ─── Соответствие цветов ──────────────────────────────────────────── */
|
||||
const COLOR_MAPPING = [
|
||||
{
|
||||
brand: { oracal: "053M", name: "Основной бирюзовый", hex: "#7ecfca" },
|
||||
brand: { oracal: "053M", name: "Основной бирюзовый", hex: "#0089c3" },
|
||||
web: { name: "Бирюзовый", hex: "#63bac3", count: 4 },
|
||||
note: "Чуть темнее и насыщеннее на сайте",
|
||||
note: "Oracal — насыщенный синий; сайт — светлее и голубее",
|
||||
},
|
||||
{
|
||||
brand: { oracal: "073M", name: "Тёмный серо-голубой", hex: "#5b7b87" },
|
||||
brand: { oracal: "073M", name: "Тёмный серо-голубой", hex: "#53514e" },
|
||||
web: { name: "Серо-бирюзовый", hex: "#60959c", count: 7 },
|
||||
note: "Светлее на сайте",
|
||||
note: "Oracal — тёмно-серый; сайт — серо-бирюзовый (значительное расхождение)",
|
||||
},
|
||||
{
|
||||
brand: { oracal: "066M", name: "Средний бирюзовый", hex: "#5bb5ad" },
|
||||
brand: { oracal: "066M", name: "Средний бирюзовый", hex: "#00818c" },
|
||||
web: { name: "Бирюзовый средний", hex: "#52b4bd", count: 4 },
|
||||
note: "Смещён в синеву",
|
||||
note: "Oracal — тёмный бирюзовый; сайт — светлее",
|
||||
},
|
||||
{
|
||||
brand: { oracal: "081M", name: "Бежевый", hex: "#c4a882" },
|
||||
brand: { oracal: "081M", name: "Бежевый", hex: "#a8885c" },
|
||||
web: { name: "Бежевый", hex: "#bf9975", count: 12 },
|
||||
note: "Темнее и насыщеннее на сайте",
|
||||
note: "Oracal — тёплый охристый; сайт — прохладнее и светлее",
|
||||
},
|
||||
{
|
||||
brand: { oracal: "050M", name: "Тёмно-синий", hex: "#1b4c72" },
|
||||
brand: { oracal: "050M", name: "Тёмно-синий", hex: "#1b2e5d" },
|
||||
web: null,
|
||||
note: "Не найден в CSS сайта",
|
||||
},
|
||||
{
|
||||
brand: { oracal: "080M", name: "Тёмно-коричневый", hex: "#5c2e0e" },
|
||||
brand: { oracal: "080M", name: "Тёмно-коричневый", hex: "#432f1e" },
|
||||
web: null,
|
||||
note: "Не найден в CSS сайта",
|
||||
},
|
||||
@@ -185,13 +185,13 @@ const WEB_COLORS = [
|
||||
];
|
||||
|
||||
const CONTRAST_PAIRS = [
|
||||
{ fg: "#ffffff", bg: "#5b7b87", label: "Белый на тёмном серо-голубом" },
|
||||
{ fg: "#ffffff", bg: "#1b4c72", label: "Белый на тёмно-синем" },
|
||||
{ fg: "#ffffff", bg: "#5c2e0e", label: "Белый на тёмно-коричневом" },
|
||||
{ fg: "#ffffff", bg: "#5bb5ad", label: "Белый на среднем бирюзовом" },
|
||||
{ fg: "#111827", bg: "#7ecfca", label: "Тёмный текст на основном бирюзовом" },
|
||||
{ fg: "#111827", bg: "#c4a882", label: "Тёмный текст на бежевом" },
|
||||
{ fg: "#5c2e0e", bg: "#c4a882", label: "Тёмно-коричневый на бежевом (форма)" },
|
||||
{ fg: "#ffffff", bg: "#53514e", label: "Белый на тёмном серо-голубом (073M)" },
|
||||
{ fg: "#ffffff", bg: "#1b2e5d", label: "Белый на тёмно-синем (050M)" },
|
||||
{ fg: "#ffffff", bg: "#432f1e", label: "Белый на тёмно-коричневом (080M)" },
|
||||
{ fg: "#ffffff", bg: "#00818c", label: "Белый на среднем бирюзовом (066M)" },
|
||||
{ fg: "#111827", bg: "#0089c3", label: "Тёмный текст на основном бирюзовом (053M)" },
|
||||
{ fg: "#111827", bg: "#a8885c", label: "Тёмный текст на бежевом (081M)" },
|
||||
{ fg: "#432f1e", bg: "#a8885c", label: "Тёмно-коричневый на бежевом (форма, 080M/081M)" },
|
||||
];
|
||||
|
||||
/* ─── Компоненты ───────────────────────────────────────────────────── */
|
||||
@@ -403,16 +403,16 @@ function exportTokens() {
|
||||
/* ─── LLM spec text ────────────────────────────────────────────────── */
|
||||
const LLM_COLORS_TEXT = `# ЦВЕТА — LLM-СПЕЦИФИКАЦИЯ
|
||||
# Клиника ухо, горло, нос им. проф. Е.Н.Оленевой
|
||||
# docs/LLM_CONTEXT.md · /foundation/colors · v2.1 · 2026-03-22
|
||||
# docs/LLM_CONTEXT.md · /foundation/colors · v2.2 · 2026-03-22
|
||||
|
||||
ФИРМЕННЫЕ ЦВЕТА (Oracal)
|
||||
ФИРМЕННЫЕ ЦВЕТА (Oracal) — точные значения из каталога
|
||||
Oracal | Название | HEX | RGB | CSS-переменная | Применение
|
||||
053M | Основной бирюзовый | #7ECFCA | rgb(126,207,202) | --brand-053m | Акцент, CTA-кнопки, иконки, активные состояния
|
||||
073M | Тёмный серо-голубой | #5B7B87 | rgb(91,123,135) | --brand-073m | Тёмный фон, хедер, заголовки навигации
|
||||
066M | Средний бирюзовый | #5BB5AD | rgb(91,181,173) | --brand-066m | Вторичные акценты, фоны секций
|
||||
050M | Тёмно-синий | #1B4C72 | rgb(27,76,114) | --brand-050m | Наружная реклама, полиграфия, заголовки
|
||||
081M | Бежевый | #C4A882 | rgb(196,168,130) | --brand-081m | Форма сотрудников, тёплые акценты
|
||||
080M | Тёмно-коричневый | #5C2E0E | rgb(92,46,14) | --brand-080m | Текст на бежевом, логотип на форме
|
||||
053M | Основной бирюзовый | #0089C3 | rgb(0,137,195) | --brand-053m | Акцент, CTA-кнопки, иконки, активные состояния
|
||||
073M | Тёмный серо-голубой | #53514E | rgb(83,81,78) | --brand-073m | Тёмный фон, хедер, заголовки навигации
|
||||
066M | Средний бирюзовый | #00818C | rgb(0,129,140) | --brand-066m | Вторичные акценты, фоны секций
|
||||
050M | Тёмно-синий | #1B2E5D | rgb(27,46,93) | --brand-050m | Наружная реклама, полиграфия, заголовки
|
||||
081M | Бежевый | #A8885C | rgb(168,136,92) | --brand-081m | Форма сотрудников, тёплые акценты
|
||||
080M | Тёмно-коричневый | #432F1E | rgb(67,47,30) | --brand-080m | Текст на бежевом, логотип на форме
|
||||
— | Белый | #FFFFFF | rgb(255,255,255) | --brand-white | Фон, инвертированный текст, логотип на тёмных
|
||||
|
||||
ЦВЕТА САЙТА oclinica.ru (CSS: clinic_bootstrap_mobile/css/style.css)
|
||||
@@ -429,29 +429,29 @@ Oracal | Название | HEX | RGB | CSS-пер
|
||||
Светло-жёлтый фон | #EEF4D1 | Фоны | 1 | Фон карточек отзывов
|
||||
Светло-зелёный фон | #F2FEE6 | Фоны | 1 | Фон секции новостей
|
||||
|
||||
СООТВЕТСТВИЕ ORACAL → САЙТ
|
||||
053M #7ECFCA → #63BAC3 (темнее, насыщеннее)
|
||||
073M #5B7B87 → #60959C (светлее)
|
||||
066M #5BB5AD → #52B4BD (смещён в синеву)
|
||||
081M #C4A882 → #BF9975 (темнее, насыщеннее)
|
||||
050M #1B4C72 → не найден в CSS сайта
|
||||
080M #5C2E0E → не найден в CSS сайта
|
||||
СООТВЕТСТВИЕ ORACAL → САЙТ (цифровая адаптация плёночных цветов)
|
||||
053M #0089C3 → #63BAC3 (Oracal ярко-синий; сайт светлее и голубее)
|
||||
073M #53514E → #60959C (Oracal тёмно-серый; сайт серо-бирюзовый — значительное расхождение)
|
||||
066M #00818C → #52B4BD (Oracal тёмный бирюзовый; сайт светлее)
|
||||
081M #A8885C → #BF9975 (Oracal тёплый охристый; сайт прохладнее и светлее)
|
||||
050M #1B2E5D → не найден в CSS сайта
|
||||
080M #432F1E → не найден в CSS сайта
|
||||
|
||||
КОНТРАСТНОСТЬ WCAG 2.1
|
||||
#FFFFFF / #5B7B87 | 4.6:1 | AA PASS | AAA FAIL
|
||||
#FFFFFF / #1B4C72 | 9.3:1 | AA PASS | AAA PASS
|
||||
#FFFFFF / #5C2E0E | 11.2:1 | AA PASS | AAA PASS
|
||||
#FFFFFF / #5BB5AD | 3.0:1 | AA FAIL | AAA FAIL | только крупный текст ≥18pt
|
||||
#111827 / #7ECFCA | 5.8:1 | AA PASS | AAA FAIL
|
||||
#111827 / #C4A882 | 4.8:1 | AA PASS | AAA FAIL
|
||||
#5C2E0E / #C4A882 | 6.7:1 | AA PASS | AAA FAIL
|
||||
#FFFFFF / #53514E | 7.9:1 | AA PASS | AAA PASS
|
||||
#FFFFFF / #1B2E5D | 13.2:1 | AA PASS | AAA PASS
|
||||
#FFFFFF / #432F1E | 12.6:1 | AA PASS | AAA PASS
|
||||
#FFFFFF / #00818C | 4.7:1 | AA PASS | AAA FAIL
|
||||
#111827 / #0089C3 | 4.7:1 | AA PASS | AAA FAIL
|
||||
#111827 / #A8885C | 5.5:1 | AA PASS | AAA FAIL
|
||||
#432F1E / #A8885C | 3.8:1 | AA FAIL | AAA FAIL | только крупный текст ≥18pt
|
||||
|
||||
ПРАВИЛА
|
||||
✓ Только цвета из фирменной палитры
|
||||
✓ Digital → цвета сайта; оффлайн → коды Oracal
|
||||
✓ Текст на цветном фоне: минимум WCAG AA (4.5:1)
|
||||
✓ Белый текст на: 073M (#5B7B87), 050M (#1B4C72), 080M (#5C2E0E)
|
||||
✓ Тёмный текст на: 053M (#7ECFCA), 081M (#C4A882)
|
||||
✓ Белый текст на: 073M (#53514E), 066M (#00818C), 050M (#1B2E5D), 080M (#432F1E)
|
||||
✓ Тёмный текст (#111827) на: 053M (#0089C3), 081M (#A8885C)
|
||||
✕ Произвольные цвета вне фирменной палитры
|
||||
✕ Изменение насыщенности / оттенка фирменных цветов
|
||||
✕ Тёплые и холодные акценты рядом без нейтрального разделителя`.trim();
|
||||
@@ -480,12 +480,12 @@ export default function ColorsPage() {
|
||||
<div className="mt-4 flex items-center justify-between">
|
||||
<div
|
||||
className="px-4 py-3 rounded-lg border text-sm flex items-center gap-2"
|
||||
style={{ borderColor: "#fde68a", background: "#fffbeb", color: "#92400e" }}
|
||||
style={{ borderColor: "#bae6fd", background: "#f0f9ff", color: "#075985" }}
|
||||
>
|
||||
<span>⚠️</span>
|
||||
<span>ℹ</span>
|
||||
<span>
|
||||
HEX-значения приблизительны. Для оффлайн-носителей используйте
|
||||
официальные коды Oracal.
|
||||
HEX-значения рассчитаны по точным RGB из каталога Oracal.
|
||||
Для оффлайн-носителей используйте официальные коды Oracal.
|
||||
</span>
|
||||
</div>
|
||||
<button
|
||||
@@ -723,7 +723,7 @@ export default function ColorsPage() {
|
||||
</div>
|
||||
<LlmBlock
|
||||
path="/foundation/colors"
|
||||
version="v2.1"
|
||||
version="v2.2"
|
||||
specText={LLM_COLORS_TEXT}
|
||||
>
|
||||
{/* Фирменные цвета */}
|
||||
@@ -799,8 +799,8 @@ export default function ColorsPage() {
|
||||
{ ok: true, text: "Только цвета из фирменной палитры" },
|
||||
{ ok: true, text: "Digital → цвета сайта; оффлайн → коды Oracal" },
|
||||
{ ok: true, text: "Текст на цветном фоне: минимум WCAG AA (4.5:1)" },
|
||||
{ ok: true, text: "Белый текст на: 073M, 050M, 080M" },
|
||||
{ ok: true, text: "Тёмный текст на: 053M, 081M" },
|
||||
{ ok: true, text: "Белый текст на: 073M (#53514E), 066M (#00818C), 050M (#1B2E5D), 080M (#432F1E)" },
|
||||
{ ok: true, text: "Тёмный текст (#111827) на: 053M (#0089C3), 081M (#A8885C)" },
|
||||
{ ok: false, text: "Произвольные цвета вне фирменной палитры" },
|
||||
{ ok: false, text: "Изменение насыщенности / оттенка фирменных цветов" },
|
||||
{ ok: false, text: "Тёплые + холодные акценты рядом без разделителя" },
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
/* ─── Бренд-токены О!Клиника ─────────────────────────────────────────── */
|
||||
/* Цвета уточняются в Sprint 2 по таблице Oracal */
|
||||
:root {
|
||||
/* Фирменные цвета (приблизительно — уточнить в Sprint 2) */
|
||||
--brand-053m: #7ecfca; /* Основной бирюзовый (Oracal 053M) */
|
||||
--brand-073m: #5b7b87; /* Тёмный серо-голубой (Oracal 073M) */
|
||||
--brand-066m: #5bb5ad; /* Средний бирюзовый (Oracal 066M) */
|
||||
--brand-050m: #1b4c72; /* Тёмно-синий, наружная реклама (Oracal 050M) */
|
||||
--brand-081m: #c4a882; /* Бежевый (Oracal 081M) */
|
||||
--brand-080m: #5c2e0e; /* Тёмно-коричневый (Oracal 080M) */
|
||||
/* Фирменные цвета — точные RGB из каталога Oracal */
|
||||
--brand-053m: #0089c3; /* Основной бирюзовый (Oracal 053M) · rgb(0,137,195) */
|
||||
--brand-073m: #53514e; /* Тёмный серо-голубой (Oracal 073M) · rgb(83,81,78) */
|
||||
--brand-066m: #00818c; /* Средний бирюзовый (Oracal 066M) · rgb(0,129,140) */
|
||||
--brand-050m: #1b2e5d; /* Тёмно-синий, наружная реклама (Oracal 050M) · rgb(27,46,93) */
|
||||
--brand-081m: #a8885c; /* Бежевый (Oracal 081M) · rgb(168,136,92) */
|
||||
--brand-080m: #432f1e; /* Тёмно-коричневый (Oracal 080M) · rgb(67,47,30) */
|
||||
--brand-white: #ffffff;
|
||||
|
||||
/* UI-цвета брендбука */
|
||||
@@ -17,7 +17,7 @@
|
||||
--bb-sidebar-border: #e5e7eb;
|
||||
--bb-sidebar-text: #374151;
|
||||
--bb-sidebar-text-muted: #6b7280;
|
||||
--bb-sidebar-active-bg: #e0f5f4;
|
||||
--bb-sidebar-active-bg: #dff0fa;
|
||||
--bb-sidebar-active-text: var(--brand-053m);
|
||||
--bb-sidebar-section: #9ca3af;
|
||||
--bb-content-bg: #ffffff;
|
||||
@@ -130,7 +130,7 @@ body {
|
||||
.bb-textarea:focus,
|
||||
.bb-select:focus {
|
||||
border-color: var(--brand-053m);
|
||||
box-shadow: 0 0 0 3px rgba(126, 207, 202, 0.2);
|
||||
box-shadow: 0 0 0 3px rgba(0, 137, 195, 0.2);
|
||||
}
|
||||
.bb-input.bb-error,
|
||||
.bb-textarea.bb-error,
|
||||
@@ -162,6 +162,13 @@ body {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
/* ─── Карточки (Sprint 4) ────────────────────────────────────── */
|
||||
.bb-news-card:hover {
|
||||
background: #eef4d1 !important;
|
||||
box-shadow: 0 0 16px 0 #9e9e9a;
|
||||
}
|
||||
.bb-service-card:hover { box-shadow: 0 4px 12px rgba(0,0,0,0.1); }
|
||||
|
||||
/* ─── Тумблер (Sprint 3) ──────────────────────────────────────── */
|
||||
.bb-toggle-track {
|
||||
display: inline-flex;
|
||||
|
||||
@@ -29,7 +29,7 @@ const NAV: NavSection[] = [
|
||||
items: [
|
||||
{ label: "Кнопки", href: "/components/buttons" },
|
||||
{ label: "Форм-контролы", href: "/components/forms" },
|
||||
{ label: "Карточки", href: "/components/cards", soon: true },
|
||||
{ label: "Карточки", href: "/components/cards" },
|
||||
{ label: "Бейджи и теги", href: "/components/badges", soon: true },
|
||||
{ label: "Алерты", href: "/components/alerts", soon: true },
|
||||
{ label: "Модальные окна", href: "/components/modals", soon: true },
|
||||
@@ -40,8 +40,8 @@ const NAV: NavSection[] = [
|
||||
{
|
||||
title: "Блоки",
|
||||
items: [
|
||||
{ label: "Hero", href: "/blocks/hero", soon: true },
|
||||
{ label: "CEO-текст", href: "/blocks/ceo", soon: true },
|
||||
{ label: "Hero", href: "/blocks/hero" },
|
||||
{ label: "CEO-текст", href: "/blocks/ceo" },
|
||||
{ label: "Наши врачи", href: "/blocks/doctors", soon: true },
|
||||
{ label: "Отзывы", href: "/blocks/reviews", soon: true },
|
||||
{ label: "Новости", href: "/blocks/news", soon: true },
|
||||
@@ -170,7 +170,7 @@ export function Sidebar() {
|
||||
color: "var(--bb-sidebar-text-muted)",
|
||||
}}
|
||||
>
|
||||
Sprint 3 · v0.3.0
|
||||
Sprint 5 · v0.5.0
|
||||
</div>
|
||||
</aside>
|
||||
);
|
||||
|
||||
+127
-92
@@ -2,9 +2,9 @@
|
||||
|
||||
## Клиника ухо, горло, нос им. проф. Е.Н.Оленевой
|
||||
|
||||
**Версия контекста:** 3.0
|
||||
**Версия контекста:** 4.1
|
||||
**Дата обновления:** 2026-03-22
|
||||
**Актуальный спринт:** Sprint 3
|
||||
**Актуальный спринт:** Sprint 5
|
||||
**Сайт клиники:** https://oclinica.ru
|
||||
**Брендбук (локально):** http://localhost:3001
|
||||
**Брендбук (production):** https://web-oclinica.vercel.app
|
||||
@@ -39,19 +39,18 @@
|
||||
|
||||
### 2.1 Фирменные цвета (Oracal — базовая палитра)
|
||||
|
||||
Основаны на кодах самоклеящейся плёнки Oracal. HEX-значения — приближённые
|
||||
цифровые эквиваленты. **Для печати и оффлайн-носителей используй коды Oracal,
|
||||
не HEX.**
|
||||
Основаны на кодах самоклеящейся плёнки Oracal. HEX-значения рассчитаны по **точным RGB
|
||||
из каталога Oracal**. Для печати и оффлайн-носителей используй коды Oracal, не HEX.
|
||||
|
||||
| Oracal | Название | HEX | RGB | HSL | CSS-переменная | Применение |
|
||||
|--------|-----------------------|-----------|-------------------|------------------|------------------|------------|
|
||||
| 053M | Основной бирюзовый | `#7ecfca` | rgb(126,207,202) | hsl(177,47%,65%) | `--brand-053m` | Акцент, CTA-кнопки, иконки, активные состояния |
|
||||
| 073M | Тёмный серо-голубой | `#5b7b87` | rgb(91,123,135) | hsl(197,20%,44%) | `--brand-073m` | Тёмный фон, хедер, заголовки навигации |
|
||||
| 066M | Средний бирюзовый | `#5bb5ad` | rgb(91,181,173) | hsl(174,33%,53%) | `--brand-066m` | Вторичные акценты, фоны секций, иллюстрации |
|
||||
| 050M | Тёмно-синий | `#1b4c72` | rgb(27,76,114) | hsl(208,61%,28%) | `--brand-050m` | Наружная реклама, полиграфия, заголовки на светлом |
|
||||
| 081M | Бежевый | `#c4a882` | rgb(196,168,130) | hsl(33,35%,64%) | `--brand-081m` | Форма сотрудников, оффлайн носители, тёплые акценты |
|
||||
| 080M | Тёмно-коричневый | `#5c2e0e` | rgb(92,46,14) | hsl(23,73%,21%) | `--brand-080m` | Текст на бежевых поверхностях, логотип на форме |
|
||||
| — | Белый | `#ffffff` | rgb(255,255,255) | hsl(0,0%,100%) | `--brand-white` | Фон, инвертированный текст, логотип на тёмных фонах |
|
||||
| Oracal | Название | HEX | RGB | HSL | CSS-переменная | Применение |
|
||||
|--------|-----------------------|-----------|-------------------|-------------------|------------------|------------|
|
||||
| 053M | Основной бирюзовый | `#0089c3` | rgb(0,137,195) | hsl(198,100%,38%) | `--brand-053m` | Акцент, CTA-кнопки, иконки, активные состояния |
|
||||
| 073M | Тёмный серо-голубой | `#53514e` | rgb(83,81,78) | hsl(38,3%,32%) | `--brand-073m` | Тёмный фон, хедер, заголовки навигации |
|
||||
| 066M | Средний бирюзовый | `#00818c` | rgb(0,129,140) | hsl(185,100%,27%) | `--brand-066m` | Вторичные акценты, фоны секций, иллюстрации |
|
||||
| 050M | Тёмно-синий | `#1b2e5d` | rgb(27,46,93) | hsl(223,55%,24%) | `--brand-050m` | Наружная реклама, полиграфия, заголовки на светлом |
|
||||
| 081M | Бежевый | `#a8885c` | rgb(168,136,92) | hsl(35,30%,51%) | `--brand-081m` | Форма сотрудников, оффлайн носители, тёплые акценты |
|
||||
| 080M | Тёмно-коричневый | `#432f1e` | rgb(67,47,30) | hsl(27,38%,19%) | `--brand-080m` | Текст на бежевых поверхностях, логотип на форме |
|
||||
| — | Белый | `#ffffff` | rgb(255,255,255) | hsl(0,0%,100%) | `--brand-white` | Фон, инвертированный текст, логотип на тёмных фонах |
|
||||
|
||||
### 2.2 Цвета сайта oclinica.ru (реальный CSS)
|
||||
|
||||
@@ -77,27 +76,27 @@
|
||||
|
||||
| Oracal (бренд) | HEX бренда | Сайт (цифровой) | HEX сайта | Отклонение |
|
||||
|--------------------------|------------|-----------------------|-----------|------------|
|
||||
| 053M Основной бирюзовый | `#7ecfca` | Бирюзовый | `#63bac3` | Темнее, насыщеннее |
|
||||
| 073M Тёмный серо-голубой | `#5b7b87` | Серо-бирюзовый | `#60959c` | Светлее на сайте |
|
||||
| 066M Средний бирюзовый | `#5bb5ad` | Бирюзовый средний | `#52b4bd` | Смещён в синеву |
|
||||
| 081M Бежевый | `#c4a882` | Бежевый | `#bf9975` | Темнее, насыщеннее |
|
||||
| 050M Тёмно-синий | `#1b4c72` | — | — | Не найден в CSS сайта |
|
||||
| 080M Тёмно-коричневый | `#5c2e0e` | — | — | Не найден в CSS сайта |
|
||||
| 053M Основной бирюзовый | `#0089c3` | Бирюзовый | `#63bac3` | Oracal ярко-синий; сайт светлее и голубее |
|
||||
| 073M Тёмный серо-голубой | `#53514e` | Серо-бирюзовый | `#60959c` | Oracal тёмно-серый; сайт серо-бирюзовый (значительное расхождение) |
|
||||
| 066M Средний бирюзовый | `#00818c` | Бирюзовый средний | `#52b4bd` | Oracal тёмный бирюзовый; сайт светлее |
|
||||
| 081M Бежевый | `#a8885c` | Бежевый | `#bf9975` | Oracal тёплый охристый; сайт прохладнее и светлее |
|
||||
| 050M Тёмно-синий | `#1b2e5d` | — | — | Не найден в CSS сайта |
|
||||
| 080M Тёмно-коричневый | `#432f1e` | — | — | Не найден в CSS сайта |
|
||||
|
||||
**Важно:** расхождения ожидаемы — это цифровая адаптация плёночных цветов под экран.
|
||||
При разработке digital-материалов используй цвета сайта (раздел 2.2), не Oracal.
|
||||
|
||||
### 2.4 Контрастность пар (WCAG 2.1)
|
||||
|
||||
| Пара | Коэффициент | AA (4.5:1) | AAA (7:1) | AA large (3:1) |
|
||||
|-------------------------------------------|-------------|------------|-----------|----------------|
|
||||
| Белый на тёмном серо-голубом (#5b7b87) | 4.6:1 | ✓ | ✕ | ✓ |
|
||||
| Белый на тёмно-синем (#1b4c72) | 9.3:1 | ✓ | ✓ | ✓ |
|
||||
| Белый на тёмно-коричневом (#5c2e0e) | 11.2:1 | ✓ | ✓ | ✓ |
|
||||
| Белый на среднем бирюзовом (#5bb5ad) | 3.0:1 | ✕ | ✕ | ✓ |
|
||||
| Тёмный текст (#111827) на основном бирюзовом (#7ecfca) | 5.8:1 | ✓ | ✕ | ✓ |
|
||||
| Тёмный текст (#111827) на бежевом (#c4a882) | 4.8:1 | ✓ | ✕ | ✓ |
|
||||
| Тёмно-коричневый (#5c2e0e) на бежевом (#c4a882) | 6.7:1 | ✓ | ✕ | ✓ |
|
||||
| Пара | Коэффициент | AA (4.5:1) | AAA (7:1) | AA large (3:1) |
|
||||
|----------------------------------------------|-------------|------------|-----------|----------------|
|
||||
| Белый на тёмном серо-голубом (#53514e 073M) | 7.9:1 | ✓ | ✓ | ✓ |
|
||||
| Белый на тёмно-синем (#1b2e5d 050M) | 13.2:1 | ✓ | ✓ | ✓ |
|
||||
| Белый на тёмно-коричневом (#432f1e 080M) | 12.6:1 | ✓ | ✓ | ✓ |
|
||||
| Белый на среднем бирюзовом (#00818c 066M) | 4.7:1 | ✓ | ✕ | ✓ |
|
||||
| Тёмный (#111827) на основном бирюзовом (#0089c3 053M) | 4.7:1 | ✓ | ✕ | ✓ |
|
||||
| Тёмный (#111827) на бежевом (#a8885c 081M) | 5.5:1 | ✓ | ✕ | ✓ |
|
||||
| Тёмно-коричневый (#432f1e) на бежевом (#a8885c) | 3.8:1 | ✕ | ✕ | ✓ (только крупный ≥18pt) |
|
||||
|
||||
---
|
||||
|
||||
@@ -173,9 +172,9 @@ SVG-версия ожидается (не получена от клиники).
|
||||
| Вариант | Фон | Логотип | Применение |
|
||||
|---------|-----|---------|------------|
|
||||
| Основной | Белый / светлый | Полноцветный | Сайт, полиграфия на белом |
|
||||
| Инвертированный | Тёмный (#5b7b87, #1b4c72) | Белый (`filter: brightness(0) invert(1)`) | Хедер, тёмные секции |
|
||||
| На форме (беж) | Бежевый (#c4a882 / Oracal 081M) | Коричневый (#5c2e0e / Oracal 080M) | Одежда персонала |
|
||||
| На форме (синий) | Тёмно-синий (#1b4c72 / Oracal 050M) | Белый | Одежда персонала |
|
||||
| Инвертированный | Тёмный (#53514e, #1b2e5d) | Белый (`filter: brightness(0) invert(1)`) | Хедер, тёмные секции |
|
||||
| На форме (беж) | Бежевый (#a8885c / Oracal 081M) | Коричневый (#432f1e / Oracal 080M) | Одежда персонала |
|
||||
| На форме (синий) | Тёмно-синий (#1b2e5d / Oracal 050M) | Белый | Одежда персонала |
|
||||
|
||||
### 4.4 Охранная зона
|
||||
|
||||
@@ -205,26 +204,27 @@ SVG-версия ожидается (не получена от клиники).
|
||||
Определены в `apps/web/app/globals.css`:
|
||||
|
||||
```css
|
||||
/* Цвета бренда */
|
||||
--brand-053m: #7ecfca; /* Основной бирюзовый */
|
||||
--brand-073m: #5b7b87; /* Тёмный серо-голубой */
|
||||
--brand-066m: #5bb5ad; /* Средний бирюзовый */
|
||||
--brand-050m: #1b4c72; /* Тёмно-синий */
|
||||
--brand-081m: #c4a882; /* Бежевый */
|
||||
--brand-080m: #5c2e0e; /* Тёмно-коричневый */
|
||||
/* Цвета бренда (точные RGB из каталога Oracal) */
|
||||
--brand-053m: #0089c3; /* Основной бирюзовый · rgb(0,137,195) */
|
||||
--brand-073m: #53514e; /* Тёмный серо-голубой · rgb(83,81,78) */
|
||||
--brand-066m: #00818c; /* Средний бирюзовый · rgb(0,129,140) */
|
||||
--brand-050m: #1b2e5d; /* Тёмно-синий · rgb(27,46,93) */
|
||||
--brand-081m: #a8885c; /* Бежевый · rgb(168,136,92) */
|
||||
--brand-080m: #432f1e; /* Тёмно-коричневый · rgb(67,47,30) */
|
||||
--brand-white: #ffffff; /* Белый */
|
||||
|
||||
/* UI брендбука */
|
||||
--bb-sidebar-bg: ... /* Фон сайдбара */
|
||||
--bb-sidebar-border: ... /* Граница сайдбара */
|
||||
--bb-sidebar-text: ... /* Текст сайдбара */
|
||||
--bb-sidebar-text-muted: ...
|
||||
--bb-sidebar-section: .../* Заголовки секций сайдбара */
|
||||
--bb-sidebar-active-bg: ...
|
||||
--bb-text: ... /* Основной текст контента */
|
||||
--bb-text-muted: ... /* Приглушённый текст */
|
||||
--bb-border: ... /* Границы */
|
||||
--bb-content-bg: ... /* Фон карточек */
|
||||
--bb-sidebar-bg: #f8f9fa;
|
||||
--bb-sidebar-border: #e5e7eb;
|
||||
--bb-sidebar-text: #374151;
|
||||
--bb-sidebar-text-muted: #6b7280;
|
||||
--bb-sidebar-active-bg: #dff0fa; /* светло-синий под 053M */
|
||||
--bb-sidebar-active-text: var(--brand-053m);
|
||||
--bb-sidebar-section: #9ca3af;
|
||||
--bb-content-bg: #ffffff;
|
||||
--bb-border: #e5e7eb;
|
||||
--bb-text: #111827;
|
||||
--bb-text-muted: #6b7280;
|
||||
```
|
||||
|
||||
---
|
||||
@@ -234,8 +234,8 @@ SVG-версия ожидается (не получена от клиники).
|
||||
### 6.1 Форма сотрудников
|
||||
|
||||
**Варианты:**
|
||||
- Бежевый: ткань цвета Oracal 081M, логотип Oracal 080M (коричневый), расположение — левая сторона груди
|
||||
- Синий: ткань цвета Oracal 050M (тёмно-синий), логотип белый (Oracal 010), расположение — левая сторона груди
|
||||
- Бежевый: ткань цвета Oracal 081M (#a8885c), логотип Oracal 080M (#432f1e, коричневый), расположение — левая сторона груди
|
||||
- Синий: ткань цвета Oracal 050M (#1b2e5d, тёмно-синий), логотип белый (Oracal 010), расположение — левая сторона груди
|
||||
|
||||
**Размеры логотипа на форме:**
|
||||
- Размеры до 46: 70 × 25,5 мм
|
||||
@@ -252,7 +252,7 @@ SVG-версия ожидается (не получена от клиники).
|
||||
### 6.3 Внутренняя навигация
|
||||
|
||||
**Материал:** оргстекло
|
||||
**Плёнки:** Oracal 053M (бирюзовый) и 073M (тёмный серо-голубой)
|
||||
**Плёнки:** Oracal 053M (#0089c3) и 073M (#53514e)
|
||||
**Типы табличек:**
|
||||
- Таблички на дверях кабинетов: номер кабинета, профиль врача с фото и QR-кодом
|
||||
- Указатели по этажам: стрелки направлений + номера кабинетов
|
||||
@@ -265,9 +265,9 @@ SVG-версия ожидается (не получена от клиники).
|
||||
### 6.4 Брендирование транспорта (трамвай)
|
||||
|
||||
**Зоны оклейки:**
|
||||
- Борта: Oracal 053M (#7ecfca) + 073M (#5b7b87)
|
||||
- Передняя часть: Oracal 066M (#5bb5ad) + 050M (#1b4c72)
|
||||
- Акценты: Oracal 081M (#c4a882) + 080M (#5c2e0e)
|
||||
- Борта: Oracal 053M (#0089c3) + 073M (#53514e)
|
||||
- Передняя часть: Oracal 066M (#00818c) + 050M (#1b2e5d)
|
||||
- Акценты: Oracal 081M (#a8885c) + 080M (#432f1e)
|
||||
|
||||
**Все 6 фирменных цветов присутствуют на транспорте.**
|
||||
|
||||
@@ -278,16 +278,17 @@ SVG-версия ожидается (не получена от клиники).
|
||||
| URL | Статус | Описание |
|
||||
|-----|--------|----------|
|
||||
| `/foundation/logo` | ✅ Готова | Логотип, варианты, охранная зона, правила |
|
||||
| `/foundation/colors` | ✅ Готова | Палитра, контраст WCAG, цвета сайта, соответствие |
|
||||
| `/foundation/colors` | ✅ Готова | Палитра (Oracal точные RGB), контраст WCAG, цвета сайта, соответствие |
|
||||
| `/foundation/typography` | ✅ Готова | DINPro + Fira Sans, шкала стилей |
|
||||
| `/foundation/icons` | 🔜 Скоро | Иконография |
|
||||
| `/offline/uniform` | ✅ Готова | Форма сотрудников |
|
||||
| `/offline/badges` | ✅ Готова | Бейджи |
|
||||
| `/offline/navigation` | ✅ Готова | Внутренняя навигация |
|
||||
| `/offline/transport` | ✅ Готова | Брендирование транспорта |
|
||||
| `/components/buttons` | ✅ Готова | Кнопки — все варианты, размеры, состояния |
|
||||
| `/components/forms` | ✅ Готова | Форм-контролы — Input, Textarea, Select, Checkbox, Radio, Toggle |
|
||||
| `/components/*` | 🔜 Sprint 3–4 | Карточки, бейджи, алерты, модалки, таблицы |
|
||||
| `/components/buttons` | ✅ Готова | Кнопки — 4 варианта с реального сайта, размеры, состояния |
|
||||
| `/components/forms` | ✅ Готова | Форм-контролы — Input/Textarea/Select/Checkbox/Radio/Toggle |
|
||||
| `/components/cards` | 🚧 Sprint 4 | Карточки — врач, услуга, новость, отзыв, цена + бейджи/теги/алерты |
|
||||
| `/components/*` | 🔜 Sprint 4–5 | Модалки, таблицы, навигация |
|
||||
| `/blocks/*` | 🔜 Sprint 5–8 | Hero, врачи, отзывы, новости, формы |
|
||||
| `/pages/*` | 🔜 Sprint 9–11 | Главная, заболевание, врачи, цены, контакты |
|
||||
|
||||
@@ -299,8 +300,9 @@ SVG-версия ожидается (не получена от клиники).
|
||||
- Использовать только цвета из фирменной палитры (раздел 2.1)
|
||||
- Для digital: адаптировать к цветам сайта (раздел 2.2)
|
||||
- Текст на цветном фоне — минимум WCAG AA (4.5:1)
|
||||
- Белый логотип на тёмных фонах (073M, 050M, 080M)
|
||||
- Коричневый логотип (080M) на бежевом фоне (081M)
|
||||
- Белый текст на тёмных фонах: 073M (#53514e), 066M (#00818c), 050M (#1b2e5d), 080M (#432f1e)
|
||||
- Тёмный текст (#111827) на светлых: 053M (#0089c3), 081M (#a8885c)
|
||||
- Коричневый логотип (080M) на бежевом фоне (081M) — только крупный текст (3.8:1)
|
||||
|
||||
### Запрещено
|
||||
- Использовать произвольные цвета вне палитры
|
||||
@@ -311,13 +313,13 @@ SVG-версия ожидается (не получена от клиники).
|
||||
### Иерархия цветов
|
||||
|
||||
```
|
||||
Основной бирюзовый (053M / #7ecfca) ← главный идентификатор бренда
|
||||
└── Средний бирюзовый (066M / #5bb5ad) ← вторичный акцент
|
||||
└── Тёмный серо-голубой (073M / #5b7b87) ← фоны, хедер
|
||||
Основной бирюзовый (053M / #0089c3) ← главный идентификатор бренда
|
||||
└── Средний бирюзовый (066M / #00818c) ← вторичный акцент
|
||||
└── Тёмный серо-голубой (073M / #53514e) ← фоны, хедер
|
||||
|
||||
Тёмно-синий (050M / #1b4c72) ← авторитет, полиграфия
|
||||
Бежевый (081M / #c4a882) ← тепло, форма
|
||||
└── Тёмно-коричневый (080M / #5c2e0e) ← текст на бежевом
|
||||
Тёмно-синий (050M / #1b2e5d) ← авторитет, полиграфия
|
||||
Бежевый (081M / #a8885c) ← тепло, форма
|
||||
└── Тёмно-коричневый (080M / #432f1e) ← текст на бежевом
|
||||
```
|
||||
|
||||
---
|
||||
@@ -343,39 +345,70 @@ SVG-версия ожидается (не получена от клиники).
|
||||
|
||||
### Кнопки (Button) · `/components/buttons`
|
||||
|
||||
CSS-классы из `globals.css`. Компонент: `@/components/ui/Button` (React, "use client").
|
||||
Варианты скопированы с реального сайта perm.oclinica.ru.
|
||||
CSS-классы в `globals.css`. Компонент: `@/components/ui/Button` (React, "use client").
|
||||
|
||||
| Вариант | CSS класс | Фон | Текст | Граница | Применение |
|
||||
|-----------|------------------|------------|---------|-----------|------------|
|
||||
| primary | .bb-btn-primary | #5b7b87 | #fff | #5b7b87 | Главный CTA: «Записаться», «Подтвердить» |
|
||||
| secondary | .bb-btn-secondary | прозрачный | #5b7b87 | #5b7b87 | Второстепенное действие |
|
||||
| ghost | .bb-btn-ghost | прозрачный | #5b7b87 | нет | Третичное действие, отмена |
|
||||
| danger | .bb-btn-danger | #dc2626 | #fff | #dc2626 | Деструктивное действие |
|
||||
| Вариант | CSS класс | Фон | Текст | Граница | Border-radius | Применение |
|
||||
|---------|------------------|----------|---------|-----------|---------------|------------|
|
||||
| primary | .bb-btn-primary | #FFA39C | #fff | #FF847B | 7px, bold, shadow | Форма записи «Запишите меня!» |
|
||||
| outline | .bb-btn-outline | #fff | #BF9975 | #BF9975 | 7px | «Записаться на приём» |
|
||||
| teal | .bb-btn-teal | #60959C | #fff | прозрачная| 7px | «Позвонить» |
|
||||
| pill | .bb-btn-pill | #E9E4D4 | #333 | #D5CFBD | 25px | «Заказать звонок» |
|
||||
|
||||
| Размер | CSS класс | padding | font-size | border-radius |
|
||||
|--------|------------|------------|-----------|---------------|
|
||||
| sm | .bb-btn-sm | 5px 12px | 13px | 6px |
|
||||
| md | .bb-btn-md | 8px 18px | 14px | 8px |
|
||||
| lg | .bb-btn-lg | 12px 26px | 16px | 10px |
|
||||
| Размер | CSS класс | padding | font-size |
|
||||
|--------|------------|--------------|-----------|
|
||||
| sm | .bb-btn-sm | 4px 11px | 13px |
|
||||
| md | .bb-btn-md | 8px 16px | 14px |
|
||||
| lg | .bb-btn-lg | 10px 24px | 18px |
|
||||
|
||||
**Состояния:** default · hover (brightness 0.9) · active (brightness 0.82) · loading (spinner + opacity 0.5) · disabled (opacity 0.5)
|
||||
|
||||
**Правила:** не более одной primary на экран в контексте задачи · текст — глагол или призыв · Danger только для деструктивных действий.
|
||||
**Состояния:** default · hover (brightness 0.9) · active (brightness 0.82) · loading (spinner) · disabled (opacity 0.5)
|
||||
|
||||
### Форм-контролы (Forms) · `/components/forms`
|
||||
|
||||
| Элемент | CSS класс | Тег HTML | Описание |
|
||||
|----------|-----------------|----------------------------|----------|
|
||||
| Input | .bb-input | `<input>` | text, email, password |
|
||||
| Textarea | .bb-textarea | `<textarea>` | многострочный, min-height: 100px |
|
||||
| Select | .bb-select | `<select>` | с кастомной SVG-стрелкой |
|
||||
| Checkbox | .bb-checkbox | `<input type="checkbox">` | 16×16px, accent-color: #5b7b87 |
|
||||
| Radio | .bb-radio | `<input type="radio">` | 16×16px, accent-color: #5b7b87 |
|
||||
| Toggle | .bb-toggle-track | React-компонент `<Toggle>` | 44×24px, track + thumb |
|
||||
Размеры соответствуют entityform-блокам на реальном сайте.
|
||||
|
||||
**Состояния полей:** default (border #e5e7eb) · focus (border #7ecfca + box-shadow) · error (.bb-error, border #dc2626) · disabled (opacity 0.5)
|
||||
| Элемент | CSS класс | Тег HTML | Высота | Описание |
|
||||
|----------|------------------|----------------------------|---------|----------|
|
||||
| Input | .bb-input | `<input>` | 50px | text, email, password · border 1px #ccc · radius 4px |
|
||||
| Textarea | .bb-textarea | `<textarea>` | ≥100px | многострочный, resize:vertical |
|
||||
| Select | .bb-select | `<select>` | 50px | с кастомной SVG-стрелкой |
|
||||
| Checkbox | .bb-checkbox | `<input type="checkbox">` | 16×16px | accent-color: #53514e |
|
||||
| Radio | .bb-radio | `<input type="radio">` | 16×16px | accent-color: #53514e |
|
||||
| Toggle | .bb-toggle-track | React-компонент `<Toggle>` | 24px | 44×24px track + 20px thumb |
|
||||
|
||||
**Toggle:** выкл → track #d1d5db · вкл → track #5b7b87 (#73M) · thumb: белый круг 20×20px.
|
||||
**Состояния полей:** default (border 1px solid #ccc) · focus (border #0089c3 + box-shadow rgba(0,137,195,0.2)) · error (.bb-error, border #dc2626) · disabled (opacity 0.5)
|
||||
|
||||
**Контекст на сайте:** фон формы #b8e6ed, ширина полей 302px, entityform-блоки.
|
||||
|
||||
**Toggle:** выкл → track #d1d5db · вкл → track #53514e · thumb: белый круг 20×20px.
|
||||
|
||||
---
|
||||
|
||||
## 9b. Карточки, бейджи и алерты (Sprint 4)
|
||||
|
||||
### Карточки · `/components/cards`
|
||||
|
||||
| Карточка | Размеры ключевые | Источник на сайте | Фон / hover |
|
||||
|-------------|-------------------------|------------------------------------------------|--------------------------|
|
||||
| DoctorCard | фото 110×160px | `.doctor .image` + `.doctor .item` | #fff / — |
|
||||
| NewsCard | preview h=144px | `#block-views-last-news-block-1 .views-column` | #fff / **#eef4d1** + shadow |
|
||||
| ReviewCard | 4-строчный clamp | `.node-reviews` | **#eef4d1** / — |
|
||||
| PriceCard | flex row: name + price | `.field-name-field-price-priem` | #fff / highlighted: #f0f9ff |
|
||||
| ServiceCard | иконка 48×48px | — (нет прямого аналога) | #fff / shadow |
|
||||
|
||||
**DoctorCard:** фото 110×160px (placeholder фон `#dff0fa`), кнопка `.bb-btn-outline .bb-btn-sm`
|
||||
**NewsCard hover CSS:** `background: #eef4d1; box-shadow: 0 0 16px 0 #9e9e9a;` — взят с реального сайта
|
||||
**ReviewCard:** звёзды SVG, заливка `#f59e0b`, `WebkitLineClamp: 4`
|
||||
|
||||
### Бейджи, теги, алерты
|
||||
|
||||
| Элемент | Варианты | Применение |
|
||||
|---------|----------|------------|
|
||||
| Badge | primary (#0089c3) / success (#059669) / warning (#d97706) / danger (#dc2626) / neutral (#6b7280) | Статус врача, категория, акция |
|
||||
| Tag | default (border) / active (brand bg) | Фильтры, категории услуг |
|
||||
| Alert | info (#dff0fa/#075985) / success (#d1fae5/#065f46) / warning (#fef3c7/#92400e) / error (#fee2e2/#991b1b) | Системные сообщения |
|
||||
|
||||
**CSS класс hover:** `.bb-news-card:hover` в globals.css
|
||||
|
||||
---
|
||||
|
||||
@@ -402,6 +435,8 @@ CSS-классы из `globals.css`. Компонент: `@/components/ui/Button
|
||||
| 2.0 | 2026-03-22 | Sprint 2: типографика, оффлайн носители, цвета сайта (8 цветов) |
|
||||
| 2.1 | 2026-03-22 | Sprint 2 доп.: +3 цвета сайта (коралловый, светло-жёлтый, светло-зелёный) |
|
||||
| 3.0 | 2026-03-22 | Sprint 3: кнопки (Button), форм-контролы (Input/Textarea/Select/Checkbox/Radio/Toggle), LLM-блок на логотипе |
|
||||
| 4.0 | 2026-03-22 | Sprint 4 start: исправлены цвета Oracal (точные RGB из каталога), кнопки/формы по реальному сайту |
|
||||
| 4.1 | 2026-03-22 | Sprint 4 done: карточки (DoctorCard/NewsCard/ReviewCard/PriceCard/ServiceCard), бейджи/теги/алерты |
|
||||
|
||||
---
|
||||
|
||||
|
||||
+20
-11
@@ -143,22 +143,31 @@
|
||||
|
||||
---
|
||||
|
||||
## Sprint 4 — Карточки (Cards)
|
||||
## Sprint 4 — Карточки (Cards) ✅ ЗАВЕРШЁН
|
||||
|
||||
**Цель:** Все типы карточек, используемых на сайте.
|
||||
|
||||
### Задачи
|
||||
- [ ] Docs: Обновить `docs/LLM_CONTEXT.md` — добавить спецификации карточек
|
||||
- [ ] FE: Добавить LLM-блок на страницу «Карточки»
|
||||
- [ ] FE: Карточка врача (DoctorCard) — фото, имя, специализация, кнопка записи
|
||||
- [ ] FE: Карточка услуги / заболевания
|
||||
- [ ] FE: Карточка новости — превью, дата, заголовок, анонс, читать далее
|
||||
- [ ] FE: Карточка отзыва — автор, текст, рейтинг (звёзды), дата
|
||||
- [ ] FE: Карточка цены — услуга, стоимость, описание
|
||||
- [ ] FE: Бейджи, теги, алерты (inline и toast)
|
||||
- [ ] FE: Страница «Компоненты → Карточки» с документацией
|
||||
- [x] Docs: Обновить `docs/LLM_CONTEXT.md` → версия 4.0
|
||||
- [x] FE: Добавить LLM-блок на страницу «Карточки» — v1.0
|
||||
- [x] FE: Карточка врача (DoctorCard) — фото 110×160px, имя, специализация, стаж, кнопка outline
|
||||
- [x] FE: Карточка услуги / заболевания (ServiceCard) — иконка + заголовок + описание
|
||||
- [x] FE: Карточка новости — превью, дата, заголовок, анонс, hover #eef4d1 (CSS сайта)
|
||||
- [x] FE: Карточка отзыва — рейтинг SVG-звёзды, 4-строчный clamp, фон #eef4d1
|
||||
- [x] FE: Карточка цены — услуга + стоимость + highlighted-вариант
|
||||
- [x] FE: Бейджи (6 вариантов), теги (default/active), алерты (info/success/warning/error)
|
||||
- [x] FE: Страница `/components/cards` с документацией и LLM-блоком
|
||||
|
||||
**Результат спринта:** Все карточки задокументированы и показаны в брендбуке.
|
||||
### Фактические результаты
|
||||
- **5 типов карточек:** DoctorCard, NewsCard, ReviewCard, PriceCard, ServiceCard
|
||||
- **NewsCard hover** — bg `#eef4d1` + box-shadow `0 0 16px #9e9e9a` (1:1 с реальным CSS сайта)
|
||||
- **ReviewCard** — фон `#eef4d1` из CSS сайта, WebkitLineClamp: 4
|
||||
- **Бейджи** — 6 вариантов (primary/success/warning/danger/neutral/outline-blue)
|
||||
- **Алерты** — info (#dff0fa), success (#d1fae5), warning (#fef3c7), error (#fee2e2)
|
||||
- **Исправлены цвета Oracal** — точные RGB из каталога для всех 6 плёнок
|
||||
- **Деплой:** https://web-oclinica.vercel.app (production)
|
||||
|
||||
**Результат спринта:** Все карточки задокументированы. Цвета Oracal исправлены по каталогу.
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user