|
|
|
|
@ -35,114 +35,184 @@ function Section({
|
|
|
|
|
); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const VARIANT_INFO = [ |
|
|
|
|
const VARIANTS = [ |
|
|
|
|
{ |
|
|
|
|
variant: "primary" as const, |
|
|
|
|
label: "Primary", |
|
|
|
|
name: "Primary", |
|
|
|
|
label: "Запишитесь к нам", |
|
|
|
|
cssClass: ".bb-btn-primary", |
|
|
|
|
bg: "#5b7b87", |
|
|
|
|
text: "#fff", |
|
|
|
|
description: "Основная кнопка призыва к действию. Тёмный бирюзово-серый фон, белый текст.", |
|
|
|
|
useCase: "Записаться · Подтвердить", |
|
|
|
|
bg: "#FFA39C", |
|
|
|
|
border: "#FF847B", |
|
|
|
|
textColor: "#fff", |
|
|
|
|
radius: "7px", |
|
|
|
|
shadow: "да", |
|
|
|
|
where: "Кнопка отправки форм записи", |
|
|
|
|
example: "«Запишите меня!»", |
|
|
|
|
note: "Коралловый — самый заметный акцент на странице. Всегда один в форме.", |
|
|
|
|
}, |
|
|
|
|
{ |
|
|
|
|
variant: "secondary" as const, |
|
|
|
|
label: "Secondary", |
|
|
|
|
cssClass: ".bb-btn-secondary", |
|
|
|
|
bg: "прозрачный", |
|
|
|
|
text: "#5b7b87", |
|
|
|
|
description: "Второстепенное действие. Контурная кнопка с фирменным цветом.", |
|
|
|
|
useCase: "Узнать подробнее · Редактировать", |
|
|
|
|
variant: "outline" as const, |
|
|
|
|
name: "Outline", |
|
|
|
|
label: "Записаться на приём", |
|
|
|
|
cssClass: ".bb-btn-outline", |
|
|
|
|
bg: "#fff", |
|
|
|
|
border: "#BF9975", |
|
|
|
|
textColor: "#BF9975", |
|
|
|
|
radius: "7px", |
|
|
|
|
shadow: "нет", |
|
|
|
|
where: "Хедер, навигация, ссылки-кнопки", |
|
|
|
|
example: "«Записаться на прием», «Все новости»", |
|
|
|
|
note: "Бежевая рамка — ненавязчивый вторичный CTA. Не конкурирует с основной формой.", |
|
|
|
|
}, |
|
|
|
|
{ |
|
|
|
|
variant: "ghost" as const, |
|
|
|
|
label: "Ghost", |
|
|
|
|
cssClass: ".bb-btn-ghost", |
|
|
|
|
bg: "прозрачный", |
|
|
|
|
text: "#5b7b87", |
|
|
|
|
description: "Третичное действие. Без фона и видимой рамки, текстовый акцент.", |
|
|
|
|
useCase: "Отмена · Назад · Ещё...", |
|
|
|
|
variant: "teal" as const, |
|
|
|
|
name: "Teal", |
|
|
|
|
label: "Позвонить", |
|
|
|
|
cssClass: ".bb-btn-teal", |
|
|
|
|
bg: "#60959c", |
|
|
|
|
border: "прозрачный", |
|
|
|
|
textColor: "#fff", |
|
|
|
|
radius: "7px", |
|
|
|
|
shadow: "нет", |
|
|
|
|
where: "Контактные действия — звонок", |
|
|
|
|
example: "«Позвонить»", |
|
|
|
|
note: "Серо-бирюзовый — цвет из реального CSS сайта. Близок к Oracal 066M.", |
|
|
|
|
}, |
|
|
|
|
{ |
|
|
|
|
variant: "danger" as const, |
|
|
|
|
label: "Danger", |
|
|
|
|
cssClass: ".bb-btn-danger", |
|
|
|
|
bg: "#dc2626", |
|
|
|
|
text: "#fff", |
|
|
|
|
description: "Деструктивные и необратимые действия. Красный фон.", |
|
|
|
|
useCase: "Удалить · Отменить запись", |
|
|
|
|
variant: "pill" as const, |
|
|
|
|
name: "Pill", |
|
|
|
|
label: "Заказать звонок", |
|
|
|
|
cssClass: ".bb-btn-pill", |
|
|
|
|
bg: "#e9e4d4", |
|
|
|
|
border: "#d5cfbd", |
|
|
|
|
textColor: "#333", |
|
|
|
|
radius: "25px", |
|
|
|
|
shadow: "нет", |
|
|
|
|
where: "Модальные триггеры, мягкий CTA", |
|
|
|
|
example: "«Заказать звонок»", |
|
|
|
|
note: "Кремовый фон + pill-форма — мягкий стиль. Используется для открытия модальных окон.", |
|
|
|
|
}, |
|
|
|
|
]; |
|
|
|
|
|
|
|
|
|
const LLM_BUTTONS_TEXT = `КНОПКИ — LLM-спецификация
|
|
|
|
|
Версия: v1.0 · /components/buttons |
|
|
|
|
|
|
|
|
|
ВАРИАНТЫ |
|
|
|
|
Вариант | 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 класс | 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 | Главные CTA на Hero-блоках |
|
|
|
|
|
|
|
|
|
СОСТОЯНИЯ |
|
|
|
|
default — без изменений |
|
|
|
|
hover — filter: brightness(0.9) |
|
|
|
|
active — filter: brightness(0.82) |
|
|
|
|
loading — spinner (animation: bb-spin 0.65s linear infinite) + opacity: 0.5 + disabled |
|
|
|
|
disabled — opacity: 0.5, cursor: not-allowed |
|
|
|
|
|
|
|
|
|
CSS BASE (globals.css) |
|
|
|
|
.bb-btn { font-family: Fira Sans; font-weight: 500; display: inline-flex; align-items: center; gap: 7px; transition: filter 0.15s; } |
|
|
|
|
.bb-btn:hover:not(:disabled) { filter: brightness(0.9); } |
|
|
|
|
.bb-btn:active:not(:disabled) { filter: brightness(0.82); } |
|
|
|
|
.bb-btn:disabled { cursor: not-allowed; opacity: 0.5; } |
|
|
|
|
.bb-btn:focus-visible { outline: 2px solid #7ecfca; outline-offset: 2px; } |
|
|
|
|
const LLM_BUTTONS_TEXT = `КНОПКИ — LLM-спецификация (с реального сайта oclinica.ru)
|
|
|
|
|
Версия: v2.0 · /components/buttons |
|
|
|
|
Источник CSS: perm.oclinica.ru/.../style.css |
|
|
|
|
|
|
|
|
|
ВАРИАНТЫ (реальный сайт) |
|
|
|
|
Вариант | CSS класс | Фон | Текст | Граница | Radius | Shadow | Применение |
|
|
|
|
primary | .bb-btn-primary | #FFA39C | #fff | #FF847B | 7px | да | Форм-сабмит «Запишите меня!» |
|
|
|
|
outline | .bb-btn-outline | #fff | #BF9975 | #BF9975 | 7px | нет | Хедер «Записаться на прием», ссылки-кнопки |
|
|
|
|
teal | .bb-btn-teal | #60959c | #fff | нет | 7px | нет | Звонок «Позвонить» |
|
|
|
|
pill | .bb-btn-pill | #e9e4d4 | #333 | #d5cfbd | 25px | нет | Callback «Заказать звонок» |
|
|
|
|
|
|
|
|
|
CSS С САЙТА (точные значения) |
|
|
|
|
/* форм-кнопка «Запишите меня!» */ |
|
|
|
|
button { background:#FFA39C; color:white; font-weight:bold; border:solid 1px #FF847B; |
|
|
|
|
height:42px; font-size:18px; box-shadow:0px 0px 5px rgba(0,0,0,0.5),0px 4px 5px rgba(0,0,0,0.3); } |
|
|
|
|
|
|
|
|
|
/* appointment — «Записаться на прием» */ |
|
|
|
|
.appointment { background:#FFF; border:#BF9975 solid 1px; color:#BF9975; |
|
|
|
|
font-size:14px; line-height:38px; padding:3px 12px; border-radius:7px; } |
|
|
|
|
|
|
|
|
|
/* show-phone — «Позвонить» */ |
|
|
|
|
.show-phone { background:rgb(96,149,156); color:#fff; border-radius:7px; |
|
|
|
|
font-size:14px; line-height:38px; padding:3px 12px; } |
|
|
|
|
|
|
|
|
|
/* callback — «Заказать звонок» */ |
|
|
|
|
a.callback_url { background:#e9e4d4; border:#d5cfbd solid 1px; color:#000; |
|
|
|
|
border-radius:25px; font-size:16px; padding:6px 18px; } |
|
|
|
|
|
|
|
|
|
РАЗМЕРЫ (брендбук-компонент) |
|
|
|
|
Размер | CSS класс | padding | font-size | Применение |
|
|
|
|
sm | .bb-btn-sm | 4px 11px | 13px | Компактные контексты |
|
|
|
|
md | .bb-btn-md | 8px 16px | 14px | Стандарт (appointment, teal, pill) |
|
|
|
|
lg | .bb-btn-lg | 10px 24px | 18px + bold | Форм-сабмит (соответствует реальному сайту) |
|
|
|
|
|
|
|
|
|
ПРАВИЛА ПРИМЕНЕНИЯ |
|
|
|
|
✓ Не более одной primary-кнопки на видимый экран в контексте одной задачи |
|
|
|
|
✓ Текст кнопки — глагол или чёткий призыв: «Записаться», «Узнать цену» |
|
|
|
|
✓ Primary → главное действие (форма записи, подтверждение) |
|
|
|
|
✓ Secondary → второстепенное (подробнее, редактировать) |
|
|
|
|
✓ Ghost → отмена, навигационная ссылка без акцента |
|
|
|
|
✓ Danger → только деструктивные действия (удалить, отменить запись) |
|
|
|
|
✕ Не менять цвета произвольно — только варианты из фирменной палитры |
|
|
|
|
✕ Не добавлять тени к кнопкам |
|
|
|
|
✕ Не использовать Danger для нейтральных действий`.trim();
|
|
|
|
|
✓ primary (коралловый) — только для главного CTA в форме записи |
|
|
|
|
✓ outline (бежевый) — хедер, навигация, ссылки-кнопки на странице |
|
|
|
|
✓ teal (бирюзовый) — контактные действия (звонок, направление) |
|
|
|
|
✓ pill (кремовый) — открытие модальных окон, мягкий callback |
|
|
|
|
✓ Не более одного primary на форму |
|
|
|
|
✕ Не менять цвета вне фирменной палитры сайта |
|
|
|
|
✕ Primary — не для навигационных ссылок |
|
|
|
|
✕ Не накладывать тень на outline/teal/pill`.trim();
|
|
|
|
|
|
|
|
|
|
export default function ButtonsPage() { |
|
|
|
|
const codeHtml = `<!-- HTML — базовые классы из globals.css -->
|
|
|
|
|
<button class="bb-btn bb-btn-md bb-btn-primary">Записаться</button> |
|
|
|
|
<button class="bb-btn bb-btn-md bb-btn-secondary">Узнать подробнее</button> |
|
|
|
|
<button class="bb-btn bb-btn-md bb-btn-ghost">Отмена</button> |
|
|
|
|
<button class="bb-btn bb-btn-md bb-btn-danger">Удалить</button> |
|
|
|
|
const codeHtml = `<!-- Primary — форм-кнопка «Запишите меня!» -->
|
|
|
|
|
<button class="bb-btn bb-btn-lg bb-btn-primary">Запишите меня!</button> |
|
|
|
|
|
|
|
|
|
<!-- Размеры --> |
|
|
|
|
<button class="bb-btn bb-btn-sm bb-btn-primary">Маленькая</button> |
|
|
|
|
<button class="bb-btn bb-btn-md bb-btn-primary">Средняя</button> |
|
|
|
|
<button class="bb-btn bb-btn-lg bb-btn-primary">Большая</button>`;
|
|
|
|
|
<!-- Outline — appointment «Записаться на прием» --> |
|
|
|
|
<a class="bb-btn bb-btn-md bb-btn-outline" href="#form">Записаться на прием</a> |
|
|
|
|
|
|
|
|
|
<!-- Teal — «Позвонить» --> |
|
|
|
|
<a class="bb-btn bb-btn-md bb-btn-teal" href="tel:+73422250662">Позвонить</a> |
|
|
|
|
|
|
|
|
|
<!-- Pill — «Заказать звонок» --> |
|
|
|
|
<a class="bb-btn bb-btn-md bb-btn-pill" href="#callback">Заказать звонок</a>`;
|
|
|
|
|
|
|
|
|
|
const codeReact = `import { Button } from "@/components/ui/Button";
|
|
|
|
|
|
|
|
|
|
// Варианты
|
|
|
|
|
<Button variant="primary">Записаться</Button> |
|
|
|
|
<Button variant="secondary">Узнать подробнее</Button> |
|
|
|
|
<Button variant="ghost">Отмена</Button> |
|
|
|
|
<Button variant="danger">Удалить</Button> |
|
|
|
|
// Форм-кнопка (главный CTA)
|
|
|
|
|
<Button variant="primary" size="lg">Запишите меня!</Button> |
|
|
|
|
|
|
|
|
|
// Запись из хедера / навигации
|
|
|
|
|
<Button variant="outline" size="md">Записаться на прием</Button> |
|
|
|
|
|
|
|
|
|
// Звонок
|
|
|
|
|
<Button variant="teal" size="md">Позвонить</Button> |
|
|
|
|
|
|
|
|
|
// Заказать звонок (открывает модал)
|
|
|
|
|
<Button variant="pill" size="md">Заказать звонок</Button> |
|
|
|
|
|
|
|
|
|
// Размеры
|
|
|
|
|
<Button size="sm">Маленькая</Button> |
|
|
|
|
<Button size="md">Средняя</Button> {/* по умолчанию */} |
|
|
|
|
<Button size="lg">Большая</Button> |
|
|
|
|
// С loading-состоянием
|
|
|
|
|
<Button variant="primary" size="lg" loading>Отправляем...</Button>`;
|
|
|
|
|
|
|
|
|
|
// Состояния
|
|
|
|
|
<Button loading>Загрузка...</Button> |
|
|
|
|
<Button disabled>Недоступно</Button>`;
|
|
|
|
|
const codeSiteExact = `/* Точный CSS с сайта oclinica.ru (style.css) */
|
|
|
|
|
|
|
|
|
|
/* Форм-кнопка — кнопка отправки форм записи */ |
|
|
|
|
#block-entityform-block-feedback button, |
|
|
|
|
#block-entityform-block-lor-form button { |
|
|
|
|
background: #FFA39C; |
|
|
|
|
color: white; |
|
|
|
|
font-weight: bold; |
|
|
|
|
border: solid 1px #FF847B; |
|
|
|
|
width: 300px; |
|
|
|
|
height: 42px; |
|
|
|
|
font-size: 18px; |
|
|
|
|
box-shadow: 0px 0px 5px rgba(0,0,0,0.5), 0px 4px 5px rgba(0,0,0,0.3); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* Кнопка «Записаться на прием» в хедере */ |
|
|
|
|
#block-block-15 .appointment { |
|
|
|
|
background: #FFF; |
|
|
|
|
border: #BF9975 solid 1px; |
|
|
|
|
color: #BF9975; |
|
|
|
|
font-size: 14px; |
|
|
|
|
line-height: 38px; |
|
|
|
|
padding: 3px 12px; |
|
|
|
|
border-radius: 7px; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* Кнопка «Позвонить» */ |
|
|
|
|
.show-phone { |
|
|
|
|
background: rgb(96, 149, 156); /* #60959c */ |
|
|
|
|
color: #fff; |
|
|
|
|
border-radius: 7px; |
|
|
|
|
font-size: 14px; |
|
|
|
|
line-height: 38px; |
|
|
|
|
padding: 3px 12px; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* Кнопка «Заказать звонок» */ |
|
|
|
|
a.callback_url { |
|
|
|
|
background: #e9e4d4; |
|
|
|
|
border: #d5cfbd solid 1px; |
|
|
|
|
color: #000; |
|
|
|
|
border-radius: 25px; |
|
|
|
|
font-size: 16px; |
|
|
|
|
padding: 6px 18px; |
|
|
|
|
}`;
|
|
|
|
|
|
|
|
|
|
return ( |
|
|
|
|
<div className="max-w-4xl mx-auto px-8 py-10"> |
|
|
|
|
@ -158,46 +228,89 @@ export default function ButtonsPage() {
|
|
|
|
|
Кнопки |
|
|
|
|
</h1> |
|
|
|
|
<p className="text-base max-w-2xl" style={{ color: "var(--bb-text-muted)" }}> |
|
|
|
|
Все варианты кнопок, применяемых на сайте клиники. |
|
|
|
|
Кнопки — основной элемент призыва к действию в интерфейсе. |
|
|
|
|
Кнопки скопированы с реального сайта{" "} |
|
|
|
|
<span className="font-mono text-sm" style={{ color: "var(--bb-text)" }}> |
|
|
|
|
oclinica.ru |
|
|
|
|
</span> |
|
|
|
|
. Цвета, размеры и тени взяты напрямую из CSS темы{" "} |
|
|
|
|
<span className="font-mono text-sm" style={{ color: "var(--bb-text)" }}> |
|
|
|
|
clinic_bootstrap_mobile/css/style.css |
|
|
|
|
</span> |
|
|
|
|
. |
|
|
|
|
</p> |
|
|
|
|
<div |
|
|
|
|
className="mt-4 px-4 py-3 rounded-lg border text-sm flex items-center gap-2" |
|
|
|
|
style={{ borderColor: "#e0f5f4", background: "#f8fffe", color: "var(--bb-text-muted)" }} |
|
|
|
|
> |
|
|
|
|
<span style={{ color: "var(--brand-053m)", fontWeight: 600 }}>Источник</span> |
|
|
|
|
<span> |
|
|
|
|
CSS сайта проанализирован 2026-03-22 — 4 типа кнопок с реальными значениями. |
|
|
|
|
</span> |
|
|
|
|
</div> |
|
|
|
|
</div> |
|
|
|
|
|
|
|
|
|
{/* 1. Варианты */} |
|
|
|
|
<Section |
|
|
|
|
id="variants" |
|
|
|
|
title="Варианты" |
|
|
|
|
subtitle="Четыре визуальных типа кнопок для разных контекстов." |
|
|
|
|
subtitle="Четыре типа кнопок с реального сайта клиники." |
|
|
|
|
> |
|
|
|
|
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4 mb-6"> |
|
|
|
|
{VARIANT_INFO.map(({ variant, label, description, useCase }) => ( |
|
|
|
|
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4 mb-6"> |
|
|
|
|
{VARIANTS.map(({ variant, name, label, where, example, note, bg, border, textColor, radius, shadow }) => ( |
|
|
|
|
<div |
|
|
|
|
key={variant} |
|
|
|
|
className="rounded-xl border p-5 flex flex-col gap-4" |
|
|
|
|
style={{ borderColor: "var(--bb-border)" }} |
|
|
|
|
> |
|
|
|
|
{/* Превью */} |
|
|
|
|
<div |
|
|
|
|
className="flex items-center justify-center py-6 rounded-lg" |
|
|
|
|
style={{ background: "var(--bb-sidebar-bg)" }} |
|
|
|
|
> |
|
|
|
|
<Button variant={variant}>{label}</Button> |
|
|
|
|
<Button variant={variant} size="md"> |
|
|
|
|
{label} |
|
|
|
|
</Button> |
|
|
|
|
</div> |
|
|
|
|
|
|
|
|
|
{/* Инфо */} |
|
|
|
|
<div> |
|
|
|
|
<p className="font-medium text-sm mb-1" style={{ color: "var(--bb-text)" }}> |
|
|
|
|
{label} |
|
|
|
|
<p className="font-semibold text-sm mb-1" style={{ color: "var(--bb-text)" }}> |
|
|
|
|
{name} |
|
|
|
|
</p> |
|
|
|
|
<p |
|
|
|
|
className="text-xs mb-3 leading-relaxed" |
|
|
|
|
style={{ color: "var(--bb-text-muted)" }} |
|
|
|
|
> |
|
|
|
|
{description} |
|
|
|
|
<p className="text-xs mb-2 leading-relaxed" style={{ color: "var(--bb-text-muted)" }}> |
|
|
|
|
{note} |
|
|
|
|
</p> |
|
|
|
|
<span |
|
|
|
|
className="inline-block text-[11px] px-2 py-0.5 rounded" |
|
|
|
|
style={{ background: "#e0f5f4", color: "var(--brand-073m)" }} |
|
|
|
|
<div className="flex flex-wrap gap-1.5 mb-2"> |
|
|
|
|
{[ |
|
|
|
|
{ k: "bg", v: bg }, |
|
|
|
|
{ k: "text", v: textColor }, |
|
|
|
|
{ k: "border", v: border }, |
|
|
|
|
{ k: "radius", v: radius }, |
|
|
|
|
...(shadow === "да" ? [{ k: "shadow", v: "да" }] : []), |
|
|
|
|
].map(({ k, v }) => ( |
|
|
|
|
<span |
|
|
|
|
key={k} |
|
|
|
|
className="text-[10px] font-mono px-1.5 py-0.5 rounded" |
|
|
|
|
style={{ background: "#f3f4f6", color: "var(--bb-text-muted)" }} |
|
|
|
|
> |
|
|
|
|
{k}: {v} |
|
|
|
|
</span> |
|
|
|
|
))} |
|
|
|
|
</div> |
|
|
|
|
<div |
|
|
|
|
className="rounded p-2.5 text-xs" |
|
|
|
|
style={{ background: "#f8f9fa", color: "var(--bb-text-muted)" }} |
|
|
|
|
> |
|
|
|
|
{useCase} |
|
|
|
|
</span> |
|
|
|
|
<span className="font-medium" style={{ color: "var(--bb-text)" }}> |
|
|
|
|
Где: |
|
|
|
|
</span>{" "} |
|
|
|
|
{where} |
|
|
|
|
<br /> |
|
|
|
|
<span className="font-medium" style={{ color: "var(--bb-text)" }}> |
|
|
|
|
Пример: |
|
|
|
|
</span>{" "} |
|
|
|
|
{example} |
|
|
|
|
</div> |
|
|
|
|
</div> |
|
|
|
|
</div> |
|
|
|
|
))} |
|
|
|
|
@ -208,7 +321,7 @@ export default function ButtonsPage() {
|
|
|
|
|
<Section |
|
|
|
|
id="sizes" |
|
|
|
|
title="Размеры" |
|
|
|
|
subtitle="Три размера для разных уровней иерархии интерфейса." |
|
|
|
|
subtitle="Три размера для разных контекстов. lg соответствует форм-кнопке на реальном сайте (18px, bold)." |
|
|
|
|
> |
|
|
|
|
<div |
|
|
|
|
className="rounded-xl border overflow-hidden" |
|
|
|
|
@ -219,20 +332,20 @@ export default function ButtonsPage() {
|
|
|
|
|
{ |
|
|
|
|
size: "sm" as const, |
|
|
|
|
label: "Small", |
|
|
|
|
hint: "padding: 5px 12px · font: 13px · radius: 6px", |
|
|
|
|
use: "Компактные интерфейсы, действия в таблицах", |
|
|
|
|
hint: "4px 11px · 13px", |
|
|
|
|
use: "Компактные контексты, таблицы", |
|
|
|
|
}, |
|
|
|
|
{ |
|
|
|
|
size: "md" as const, |
|
|
|
|
label: "Medium", |
|
|
|
|
hint: "padding: 8px 18px · font: 14px · radius: 8px", |
|
|
|
|
use: "Стандартный размер (по умолчанию)", |
|
|
|
|
hint: "8px 16px · 14px", |
|
|
|
|
use: "Appointment, Teal, Pill (соответствует сайту)", |
|
|
|
|
}, |
|
|
|
|
{ |
|
|
|
|
size: "lg" as const, |
|
|
|
|
label: "Large", |
|
|
|
|
hint: "padding: 12px 26px · font: 16px · radius: 10px", |
|
|
|
|
use: "Главные CTA на Hero-блоках", |
|
|
|
|
hint: "10px 24px · 18px bold", |
|
|
|
|
use: "Primary форм-кнопка (соответствует сайту)", |
|
|
|
|
}, |
|
|
|
|
] as const |
|
|
|
|
).map(({ size, label, hint, use }, i) => ( |
|
|
|
|
@ -241,7 +354,7 @@ export default function ButtonsPage() {
|
|
|
|
|
className="flex items-center gap-6 px-5 py-4" |
|
|
|
|
style={{ borderTop: i > 0 ? "1px solid var(--bb-border)" : undefined }} |
|
|
|
|
> |
|
|
|
|
<div className="w-36 shrink-0"> |
|
|
|
|
<div className="w-40 shrink-0"> |
|
|
|
|
<Button variant="primary" size={size}> |
|
|
|
|
Записаться |
|
|
|
|
</Button> |
|
|
|
|
@ -251,12 +364,12 @@ export default function ButtonsPage() {
|
|
|
|
|
{label} |
|
|
|
|
</p> |
|
|
|
|
<p className="text-xs font-mono" style={{ color: "var(--bb-text-muted)" }}> |
|
|
|
|
{hint} |
|
|
|
|
padding: {hint.split("·")[0].trim()} · font-size: {hint.split("·")[1].trim()} |
|
|
|
|
</p> |
|
|
|
|
</div> |
|
|
|
|
<p |
|
|
|
|
className="text-xs hidden lg:block" |
|
|
|
|
style={{ color: "var(--bb-text-muted)", maxWidth: 200 }} |
|
|
|
|
style={{ color: "var(--bb-text-muted)", maxWidth: 220 }} |
|
|
|
|
> |
|
|
|
|
{use} |
|
|
|
|
</p> |
|
|
|
|
@ -269,49 +382,53 @@ export default function ButtonsPage() {
|
|
|
|
|
<Section |
|
|
|
|
id="states" |
|
|
|
|
title="Состояния" |
|
|
|
|
subtitle="Поведение кнопки при разных условиях взаимодействия." |
|
|
|
|
subtitle="Базовые состояния кнопки. На реальном сайте hover/transition не определены в CSS." |
|
|
|
|
> |
|
|
|
|
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4"> |
|
|
|
|
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4"> |
|
|
|
|
{( |
|
|
|
|
[ |
|
|
|
|
{ |
|
|
|
|
label: "Default", |
|
|
|
|
node: <Button variant="primary">Записаться</Button>, |
|
|
|
|
node: <Button variant="primary" size="lg">Записаться</Button>, |
|
|
|
|
hint: "Стандартное состояние", |
|
|
|
|
}, |
|
|
|
|
{ |
|
|
|
|
label: "Hover", |
|
|
|
|
node: ( |
|
|
|
|
<Button variant="primary" style={{ filter: "brightness(0.9)" }}> |
|
|
|
|
<Button |
|
|
|
|
variant="primary" |
|
|
|
|
size="lg" |
|
|
|
|
style={{ filter: "brightness(0.93)" }} |
|
|
|
|
> |
|
|
|
|
Записаться |
|
|
|
|
</Button> |
|
|
|
|
), |
|
|
|
|
hint: "filter: brightness(0.9) при наведении курсора", |
|
|
|
|
hint: "filter: brightness(0.93)", |
|
|
|
|
}, |
|
|
|
|
{ |
|
|
|
|
label: "Loading", |
|
|
|
|
node: <Button variant="primary" loading>Загрузка...</Button>, |
|
|
|
|
hint: "Спиннер + opacity: 0.5 + кнопка заблокирована", |
|
|
|
|
node: <Button variant="primary" size="lg" loading>Отправка...</Button>, |
|
|
|
|
hint: "Спиннер + blocked", |
|
|
|
|
}, |
|
|
|
|
{ |
|
|
|
|
label: "Disabled", |
|
|
|
|
node: <Button variant="primary" disabled>Недоступно</Button>, |
|
|
|
|
hint: "opacity: 0.5, cursor: not-allowed", |
|
|
|
|
node: <Button variant="primary" size="lg" disabled>Записаться</Button>, |
|
|
|
|
hint: "opacity: 0.5", |
|
|
|
|
}, |
|
|
|
|
] as const |
|
|
|
|
).map(({ label, node, hint }) => ( |
|
|
|
|
<div |
|
|
|
|
key={label} |
|
|
|
|
className="rounded-xl border p-5" |
|
|
|
|
className="rounded-xl border p-4" |
|
|
|
|
style={{ borderColor: "var(--bb-border)" }} |
|
|
|
|
> |
|
|
|
|
<div |
|
|
|
|
className="flex items-center justify-center py-6 mb-3 rounded-lg" |
|
|
|
|
className="flex items-center justify-center py-4 mb-3 rounded-lg" |
|
|
|
|
style={{ background: "var(--bb-sidebar-bg)" }} |
|
|
|
|
> |
|
|
|
|
{node} |
|
|
|
|
</div> |
|
|
|
|
<p className="text-sm font-medium mb-1" style={{ color: "var(--bb-text)" }}> |
|
|
|
|
<p className="text-sm font-medium mb-0.5" style={{ color: "var(--bb-text)" }}> |
|
|
|
|
{label} |
|
|
|
|
</p> |
|
|
|
|
<p className="text-xs" style={{ color: "var(--bb-text-muted)" }}> |
|
|
|
|
@ -322,51 +439,81 @@ export default function ButtonsPage() {
|
|
|
|
|
</div> |
|
|
|
|
</Section> |
|
|
|
|
|
|
|
|
|
{/* 4. Все варианты вместе */} |
|
|
|
|
{/* 4. Контекст применения */} |
|
|
|
|
<Section |
|
|
|
|
id="all" |
|
|
|
|
title="Все варианты и размеры" |
|
|
|
|
subtitle="Сводная таблица — визуальное сравнение." |
|
|
|
|
id="context" |
|
|
|
|
title="Где применяется" |
|
|
|
|
subtitle="Таблица: тип кнопки → реальное использование на сайте." |
|
|
|
|
> |
|
|
|
|
<div |
|
|
|
|
className="rounded-xl border overflow-hidden" |
|
|
|
|
style={{ borderColor: "var(--bb-border)" }} |
|
|
|
|
> |
|
|
|
|
<div |
|
|
|
|
className="px-5 py-3 text-xs font-medium border-b" |
|
|
|
|
style={{ |
|
|
|
|
color: "var(--bb-text-muted)", |
|
|
|
|
background: "var(--bb-sidebar-bg)", |
|
|
|
|
borderColor: "var(--bb-border)", |
|
|
|
|
}} |
|
|
|
|
> |
|
|
|
|
Вариант / Размер |
|
|
|
|
</div> |
|
|
|
|
{VARIANT_INFO.map(({ variant, label }, vi) => ( |
|
|
|
|
<div |
|
|
|
|
key={variant} |
|
|
|
|
className="flex items-center gap-5 px-5 py-3" |
|
|
|
|
style={{ borderTop: vi > 0 ? "1px solid var(--bb-border)" : undefined }} |
|
|
|
|
> |
|
|
|
|
<span |
|
|
|
|
className="w-20 text-xs font-mono shrink-0" |
|
|
|
|
style={{ color: "var(--bb-text-muted)" }} |
|
|
|
|
> |
|
|
|
|
{label} |
|
|
|
|
</span> |
|
|
|
|
<div className="flex items-center gap-3 flex-wrap"> |
|
|
|
|
<Button variant={variant} size="sm"> |
|
|
|
|
Маленькая |
|
|
|
|
</Button> |
|
|
|
|
<Button variant={variant} size="md"> |
|
|
|
|
Средняя |
|
|
|
|
</Button> |
|
|
|
|
<Button variant={variant} size="lg"> |
|
|
|
|
Большая |
|
|
|
|
</Button> |
|
|
|
|
</div> |
|
|
|
|
</div> |
|
|
|
|
))} |
|
|
|
|
<table className="w-full text-sm"> |
|
|
|
|
<thead> |
|
|
|
|
<tr style={{ background: "var(--bb-sidebar-bg)" }}> |
|
|
|
|
{["Вариант", "Цвет фона", "Реальный класс/контекст", "Текст кнопки на сайте"].map((h) => ( |
|
|
|
|
<th |
|
|
|
|
key={h} |
|
|
|
|
className="text-left px-4 py-3 font-medium text-xs" |
|
|
|
|
style={{ color: "var(--bb-text-muted)" }} |
|
|
|
|
> |
|
|
|
|
{h} |
|
|
|
|
</th> |
|
|
|
|
))} |
|
|
|
|
</tr> |
|
|
|
|
</thead> |
|
|
|
|
<tbody> |
|
|
|
|
{[ |
|
|
|
|
{ |
|
|
|
|
v: <Button variant="primary" size="sm">Primary</Button>, |
|
|
|
|
bg: "#FFA39C", |
|
|
|
|
ctx: "button в entityform-блоках форм записи", |
|
|
|
|
text: "«Запишите меня!»", |
|
|
|
|
}, |
|
|
|
|
{ |
|
|
|
|
v: <Button variant="outline" size="sm">Outline</Button>, |
|
|
|
|
bg: "#fff / рамка #BF9975", |
|
|
|
|
ctx: ".appointment в хедере (block-block-15, 30, 32, 24)", |
|
|
|
|
text: "«Записаться на прием»", |
|
|
|
|
}, |
|
|
|
|
{ |
|
|
|
|
v: <Button variant="teal" size="sm">Teal</Button>, |
|
|
|
|
bg: "#60959c", |
|
|
|
|
ctx: ".show-phone (block-block-4, 15)", |
|
|
|
|
text: "«Позвонить»", |
|
|
|
|
}, |
|
|
|
|
{ |
|
|
|
|
v: <Button variant="pill" size="sm">Pill</Button>, |
|
|
|
|
bg: "#e9e4d4", |
|
|
|
|
ctx: "a.callback_url (modal trigger)", |
|
|
|
|
text: "«Заказать звонок»", |
|
|
|
|
}, |
|
|
|
|
].map(({ v, bg, ctx, text }, i) => ( |
|
|
|
|
<tr |
|
|
|
|
key={i} |
|
|
|
|
style={{ borderTop: "1px solid var(--bb-border)" }} |
|
|
|
|
> |
|
|
|
|
<td className="px-4 py-3">{v}</td> |
|
|
|
|
<td |
|
|
|
|
className="px-4 py-3 font-mono text-xs" |
|
|
|
|
style={{ color: "var(--bb-text-muted)" }} |
|
|
|
|
> |
|
|
|
|
{bg} |
|
|
|
|
</td> |
|
|
|
|
<td |
|
|
|
|
className="px-4 py-3 font-mono text-xs" |
|
|
|
|
style={{ color: "var(--bb-text-muted)" }} |
|
|
|
|
> |
|
|
|
|
{ctx} |
|
|
|
|
</td> |
|
|
|
|
<td className="px-4 py-3 text-xs" style={{ color: "var(--bb-text)" }}> |
|
|
|
|
{text} |
|
|
|
|
</td> |
|
|
|
|
</tr> |
|
|
|
|
))} |
|
|
|
|
</tbody> |
|
|
|
|
</table> |
|
|
|
|
</div> |
|
|
|
|
</Section> |
|
|
|
|
|
|
|
|
|
@ -374,58 +521,50 @@ export default function ButtonsPage() {
|
|
|
|
|
<Section |
|
|
|
|
id="code" |
|
|
|
|
title="Примеры кода" |
|
|
|
|
subtitle="Скопируйте HTML или JSX для использования в проекте." |
|
|
|
|
subtitle="HTML-классы из globals.css, JSX-компонент, и точный CSS с сайта." |
|
|
|
|
> |
|
|
|
|
<div className="space-y-4"> |
|
|
|
|
<CodeCopy lang="HTML (CSS-классы из globals.css)" code={codeHtml} /> |
|
|
|
|
<CodeCopy lang="HTML (CSS-классы brandbook)" code={codeHtml} /> |
|
|
|
|
<CodeCopy lang="JSX (React / Next.js)" code={codeReact} /> |
|
|
|
|
<CodeCopy lang="CSS — точно с сайта oclinica.ru" code={codeSiteExact} /> |
|
|
|
|
</div> |
|
|
|
|
</Section> |
|
|
|
|
|
|
|
|
|
{/* LLM-блок */} |
|
|
|
|
<LlmBlock path="/components/buttons" version="v1.0" specText={LLM_BUTTONS_TEXT}> |
|
|
|
|
<LlmSection title="Варианты" /> |
|
|
|
|
<LlmBlock path="/components/buttons" version="v2.0" specText={LLM_BUTTONS_TEXT}> |
|
|
|
|
<LlmSection title="Варианты (реальный сайт oclinica.ru)" /> |
|
|
|
|
<LlmTable |
|
|
|
|
headers={["Вариант", "CSS класс", "Фон", "Текст", "Применение"]} |
|
|
|
|
rows={VARIANT_INFO.map((v) => [ |
|
|
|
|
headers={["Вариант", "CSS класс", "Фон", "Текст", "Border", "Radius", "Применение"]} |
|
|
|
|
rows={VARIANTS.map((v) => [ |
|
|
|
|
v.variant, |
|
|
|
|
v.cssClass, |
|
|
|
|
v.bg, |
|
|
|
|
v.text, |
|
|
|
|
v.useCase, |
|
|
|
|
v.textColor, |
|
|
|
|
v.border, |
|
|
|
|
v.radius, |
|
|
|
|
v.where, |
|
|
|
|
])} |
|
|
|
|
/> |
|
|
|
|
<LlmSection title="Размеры" /> |
|
|
|
|
<LlmTable |
|
|
|
|
headers={["Размер", "CSS класс", "padding", "font-size", "radius", "Применение"]} |
|
|
|
|
rows={[ |
|
|
|
|
["sm", ".bb-btn-sm", "5px 12px", "13px", "6px", "Компактные интерфейсы, таблицы"], |
|
|
|
|
["md", ".bb-btn-md", "8px 18px", "14px", "8px", "Стандарт (по умолчанию)"], |
|
|
|
|
["lg", ".bb-btn-lg", "12px 26px", "16px", "10px", "Hero CTA"], |
|
|
|
|
]} |
|
|
|
|
/> |
|
|
|
|
<LlmSection title="Состояния" /> |
|
|
|
|
<LlmSection title="Размеры (брендбук-компонент)" /> |
|
|
|
|
<LlmTable |
|
|
|
|
headers={["Состояние", "CSS / Поведение"]} |
|
|
|
|
headers={["Размер", "padding", "font-size", "Применение"]} |
|
|
|
|
rows={[ |
|
|
|
|
["default", "без изменений"], |
|
|
|
|
["hover", "filter: brightness(0.9)"], |
|
|
|
|
["active", "filter: brightness(0.82)"], |
|
|
|
|
["loading", "spinner bb-spin + opacity: 0.5 + disabled=true"], |
|
|
|
|
["disabled", "opacity: 0.5 + cursor: not-allowed"], |
|
|
|
|
["sm", "4px 11px", "13px", "Компактные контексты"], |
|
|
|
|
["md", "8px 16px", "14px", "Стандарт (outline, teal, pill с сайта)"], |
|
|
|
|
["lg", "10px 24px", "18px bold", "Primary форм-кнопка (соответствует сайту)"], |
|
|
|
|
]} |
|
|
|
|
/> |
|
|
|
|
<LlmSection title="Правила применения" /> |
|
|
|
|
<LlmRules |
|
|
|
|
rules={[ |
|
|
|
|
{ ok: true, text: "Не более одной primary-кнопки на один экран в контексте задачи" }, |
|
|
|
|
{ ok: true, text: "Текст — глагол или призыв: «Записаться», «Узнать цену»" }, |
|
|
|
|
{ ok: true, text: "Primary → главное действие формы или подтверждения" }, |
|
|
|
|
{ ok: true, text: "Ghost → отмена и навигационные ссылки без акцента" }, |
|
|
|
|
{ ok: true, text: "Danger → только деструктивные действия" }, |
|
|
|
|
{ ok: false, text: "Не менять цвета произвольно вне фирменной палитры" }, |
|
|
|
|
{ ok: false, text: "Не добавлять тени к кнопкам" }, |
|
|
|
|
{ ok: false, text: "Не использовать Danger для нейтральных действий" }, |
|
|
|
|
{ ok: true, text: "primary (коралловый) — только для submit в формах записи" }, |
|
|
|
|
{ ok: true, text: "outline (бежевый) — хедер, навигация, второстепенные ссылки" }, |
|
|
|
|
{ ok: true, text: "teal (бирюзовый) — телефонные и контактные действия" }, |
|
|
|
|
{ ok: true, text: "pill (кремовый) — открытие модальных окон / callback" }, |
|
|
|
|
{ ok: true, text: "Не более одного primary на форму" }, |
|
|
|
|
{ ok: false, text: "Не менять цвета вне указанной палитры сайта" }, |
|
|
|
|
{ ok: false, text: "Primary — не для навигационных ссылок" }, |
|
|
|
|
{ ok: false, text: "Не накладывать тень на outline, teal, pill" }, |
|
|
|
|
]} |
|
|
|
|
/> |
|
|
|
|
</LlmBlock> |
|
|
|
|
|