fix(forms): update form controls to match real site oclinica.ru styling
- .bb-input: height 50px, padding 10px 12px, border 1px solid #ccc, border-radius 4px (matches entityform input[type=text] from perm.oclinica.ru) - .bb-select: height 50px, padding 10px with arrow, same border/radius - .bb-textarea: same border 1px #ccc, border-radius 4px (was 8px/1.5px teal) - forms/page.tsx v2.0: added "Контекст применения" section with where-used table and realistic form mockup (bg #b8e6ed as on site), added "CSS с сайта" code block, updated LLM block to v2.0 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -86,14 +86,15 @@ function StateCard({
|
||||
}
|
||||
|
||||
const LLM_FORMS_TEXT = `ФОРМ-КОНТРОЛЫ — LLM-спецификация
|
||||
Версия: v1.0 · /components/forms
|
||||
Версия: v2.0 · /components/forms
|
||||
|
||||
ТЕКСТОВОЕ ПОЛЕ (Input)
|
||||
CSS класс: .bb-input
|
||||
Высота: ~40px (padding: 9px 12px)
|
||||
border: 1.5px solid #e5e7eb · border-radius: 8px · font: Fira Sans 14px
|
||||
Высота: 50px · padding: 10px 12px
|
||||
border: 1px solid #ccc · border-radius: 4px · font: Fira Sans 14px
|
||||
Источник: entityform input[type=text] на perm.oclinica.ru
|
||||
Состояния:
|
||||
default: border #e5e7eb
|
||||
default: border #ccc
|
||||
focus: border #7ecfca + box-shadow 0 0 0 3px rgba(126,207,202,0.2)
|
||||
error: border #dc2626 + класс .bb-error
|
||||
disabled: opacity 0.5 + cursor not-allowed + bg #f8f9fa
|
||||
@@ -101,11 +102,13 @@ border: 1.5px solid #e5e7eb · border-radius: 8px · font: Fira Sans 14px
|
||||
МНОГОСТРОЧНЫЙ ТЕКСТ (Textarea)
|
||||
CSS класс: .bb-textarea
|
||||
Те же состояния что у Input
|
||||
min-height: 100px · resize: vertical
|
||||
min-height: 100px · resize: vertical · padding: 10px 12px
|
||||
|
||||
ВЫПАДАЮЩИЙ СПИСОК (Select)
|
||||
CSS класс: .bb-select
|
||||
Стрелка: SVG background-image (data URI) · padding-right: 36px
|
||||
Высота: 50px · padding: 10px 36px 10px 10px
|
||||
Стрелка: SVG background-image (data URI)
|
||||
Источник: .form-control.form-select entityform на сайте
|
||||
Те же состояния что у Input
|
||||
|
||||
ФЛАЖОК (Checkbox)
|
||||
@@ -127,12 +130,20 @@ HTML: <input type="radio" class="bb-radio" name="group" />
|
||||
CSS: .bb-toggle-track / .bb-toggle-thumb
|
||||
HTML-аналог: <input type="checkbox" role="switch" />
|
||||
|
||||
КОНТЕКСТ ПРИМЕНЕНИЯ НА САЙТЕ
|
||||
Input/Select используются в entityform-блоках:
|
||||
#block-entityform-block-lor-form — форма «Запишите меня!» (ЛОР)
|
||||
#block-entityform-block-lor-form-2 — форма «Узнайте стоимость операции»
|
||||
#block-entityform-block-surgery-form — форма хирургии
|
||||
Фон формы: #b8e6ed (светло-бирюзовый)
|
||||
Ширина полей: 302px (фиксированная), кнопка submit: 300px
|
||||
|
||||
ОБЩИЕ ПРАВИЛА
|
||||
✓ Метка (label) всегда над полем, font-weight: 500
|
||||
✓ Обязательные поля помечены * красным цветом (#dc2626)
|
||||
✓ Подсказка (hint) серым текстом под полем — font-size: 12px
|
||||
✓ Сообщение об ошибке красным (#dc2626) под полем вместо hint
|
||||
✓ Focus outline — тёмный бирюзовый #7ecfca (--brand-053m)
|
||||
✓ Focus outline — бирюзовый #7ecfca (--brand-053m)
|
||||
✓ Группы checkbox/radio — вертикальный список с gap: 10px
|
||||
✓ Toggle — для булевых настроек включить/выключить
|
||||
✕ Не использовать placeholder вместо label
|
||||
@@ -207,6 +218,39 @@ export default function FormsPage() {
|
||||
// Заблокирован
|
||||
<Toggle disabled label="Настройка недоступна" />`;
|
||||
|
||||
const codeSiteCSS = `/* ── Реальный CSS с perm.oclinica.ru ─────────────────────────── */
|
||||
|
||||
/* Базовые стили (Bootstrap override) */
|
||||
input[type=text],
|
||||
input[type=email] {
|
||||
padding: 0;
|
||||
height: 30px;
|
||||
border: 1px solid #ccc;
|
||||
}
|
||||
|
||||
/* Entityform-блоки: форма записи на приём / узнать стоимость */
|
||||
#block-entityform-block-lor-form input[type=text],
|
||||
#block-entityform-block-lor-form-2 input[type=text],
|
||||
#block-entityform-block-surgery-form input[type=text] {
|
||||
height: 50px;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
/* Select в entityform */
|
||||
.field-name-field-lor-vrach .form-control.form-select {
|
||||
height: 50px;
|
||||
padding: 10px 16px;
|
||||
font-size: .9em;
|
||||
font-weight: bold;
|
||||
font-family: 'Fira Sans';
|
||||
color: #949290;
|
||||
}
|
||||
|
||||
/* Webform (отдельный вид форм) — скруглений нет */
|
||||
.webform-client-form input[type=text].form-text {
|
||||
border-radius: 0;
|
||||
}`;
|
||||
|
||||
return (
|
||||
<div className="max-w-4xl mx-auto px-8 py-10">
|
||||
{/* Заголовок */}
|
||||
@@ -230,10 +274,10 @@ export default function FormsPage() {
|
||||
<Section
|
||||
id="input"
|
||||
title="Текстовое поле"
|
||||
subtitle="Базовый элемент ввода текста. Класс .bb-input."
|
||||
subtitle="Базовый элемент ввода текста. Класс .bb-input. Высота 50px — как на сайте oclinica.ru."
|
||||
>
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4 mb-4">
|
||||
<StateCard label="Default" hint="Стандартное состояние">
|
||||
<StateCard label="Default" hint="border: 1px solid #ccc · border-radius: 4px · height: 50px">
|
||||
<FieldLabel text="Имя пациента" required />
|
||||
<input className="bb-input" type="text" placeholder="Иван Иванов" readOnly />
|
||||
<FieldHint text="Укажите имя как в паспорте" />
|
||||
@@ -296,10 +340,10 @@ export default function FormsPage() {
|
||||
<Section
|
||||
id="textarea"
|
||||
title="Многострочный текст"
|
||||
subtitle="Поле для длинного ввода. Класс .bb-textarea."
|
||||
subtitle="Поле для длинного ввода. Класс .bb-textarea. border: 1px solid #ccc · border-radius: 4px."
|
||||
>
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||
<StateCard label="Default" hint="Стандартное состояние · resize: vertical">
|
||||
<StateCard label="Default" hint="min-height: 100px · resize: vertical">
|
||||
<FieldLabel text="Комментарий к записи" />
|
||||
<textarea
|
||||
className="bb-textarea"
|
||||
@@ -329,10 +373,10 @@ export default function FormsPage() {
|
||||
<Section
|
||||
id="select"
|
||||
title="Выпадающий список"
|
||||
subtitle="Выбор из предопределённых вариантов. Класс .bb-select."
|
||||
subtitle="Выбор из предопределённых вариантов. Класс .bb-select. Высота 50px — как в entityform на сайте."
|
||||
>
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||
<StateCard label="Default" hint="Нативный select с кастомной стрелкой">
|
||||
<StateCard label="Default" hint="height: 50px · кастомная стрелка SVG">
|
||||
<FieldLabel text="Специализация" />
|
||||
<select className="bb-select">
|
||||
<option value="">Выберите специализацию</option>
|
||||
@@ -520,7 +564,96 @@ export default function FormsPage() {
|
||||
</div>
|
||||
</Section>
|
||||
|
||||
{/* 7. Примеры кода */}
|
||||
{/* 7. Контекст на сайте */}
|
||||
<Section
|
||||
id="context"
|
||||
title="Контекст применения"
|
||||
subtitle="Как форм-контролы выглядят на сайте oclinica.ru — в реальных entityform-блоках."
|
||||
>
|
||||
<div className="overflow-x-auto mb-6">
|
||||
<table className="w-full text-sm border-collapse">
|
||||
<thead>
|
||||
<tr style={{ background: "var(--bb-sidebar-bg)" }}>
|
||||
{["Контрол", "CSS класс", "Где на сайте", "CSS-блок на сайте"].map((h) => (
|
||||
<th
|
||||
key={h}
|
||||
className="text-left px-3 py-2 font-semibold text-xs uppercase tracking-wide"
|
||||
style={{ color: "var(--bb-text-muted)", borderBottom: "1px solid var(--bb-border)" }}
|
||||
>
|
||||
{h}
|
||||
</th>
|
||||
))}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{[
|
||||
["Input (text)", ".bb-input", "Форма записи ЛОР, форма хирургии, «Узнайте стоимость»", "#block-entityform-block-lor-form input[type=text]"],
|
||||
["Select", ".bb-select", "Выбор врача в форме записи", ".field-name-field-lor-vrach .form-control.form-select"],
|
||||
["Checkbox", ".bb-checkbox", "Согласие на обработку данных в entityform", ".form-type-checkbox.checkbox label"],
|
||||
["Textarea", ".bb-textarea", "Комментарии (в ряде форм)", "Без специального CSS на сайте (Bootstrap)"],
|
||||
["Toggle", ".bb-toggle-track", "Не используется на сайте (UI-компонент брендбука)", "—"],
|
||||
].map(([ctrl, cls, where, block]) => (
|
||||
<tr key={ctrl} style={{ borderBottom: "1px solid var(--bb-border)" }}>
|
||||
<td className="px-3 py-2.5 font-medium" style={{ color: "var(--bb-text)" }}>{ctrl}</td>
|
||||
<td className="px-3 py-2.5">
|
||||
<code className="text-xs px-1.5 py-0.5 rounded" style={{ background: "var(--bb-sidebar-bg)", color: "var(--brand-073m)" }}>{cls}</code>
|
||||
</td>
|
||||
<td className="px-3 py-2.5 text-xs" style={{ color: "var(--bb-text-muted)" }}>{where}</td>
|
||||
<td className="px-3 py-2.5">
|
||||
<code className="text-xs" style={{ color: "var(--bb-text-muted)" }}>{block}</code>
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
{/* Макет формы как на сайте */}
|
||||
<div className="rounded-xl overflow-hidden border" style={{ borderColor: "var(--bb-border)" }}>
|
||||
<div className="px-4 py-2 text-xs font-semibold uppercase tracking-widest" style={{ background: "var(--bb-sidebar-bg)", color: "var(--bb-text-muted)" }}>
|
||||
Макет — entityform «Узнайте стоимость операции» (oclinica.ru/lor)
|
||||
</div>
|
||||
<div style={{ background: "#b8e6ed", padding: "32px 24px" }}>
|
||||
<div
|
||||
className="mx-auto"
|
||||
style={{
|
||||
maxWidth: 340,
|
||||
background: "#b8e6ed",
|
||||
textAlign: "center",
|
||||
}}
|
||||
>
|
||||
<p className="text-sm font-semibold mb-4" style={{ color: "#333", fontFamily: "var(--font-web)" }}>
|
||||
Узнайте стоимость операции
|
||||
</p>
|
||||
<div className="flex flex-col gap-3" style={{ alignItems: "center" }}>
|
||||
<input
|
||||
className="bb-input"
|
||||
type="text"
|
||||
placeholder="Ваше имя"
|
||||
style={{ width: 302 }}
|
||||
readOnly
|
||||
/>
|
||||
<input
|
||||
className="bb-input"
|
||||
type="text"
|
||||
placeholder="Ваш телефон"
|
||||
style={{ width: 302 }}
|
||||
readOnly
|
||||
/>
|
||||
<select className="bb-select" style={{ width: 302 }}>
|
||||
<option>Выберите врача</option>
|
||||
<option>Иванов И.И.</option>
|
||||
</select>
|
||||
<button className="bb-btn bb-btn-lg bb-btn-primary" style={{ width: 300 }}>
|
||||
Запишите меня!
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Section>
|
||||
|
||||
{/* 8. Примеры кода */}
|
||||
<Section
|
||||
id="code"
|
||||
title="Примеры кода"
|
||||
@@ -533,18 +666,19 @@ export default function FormsPage() {
|
||||
<CodeCopy lang="HTML — Checkbox" code={codeCheckbox} />
|
||||
<CodeCopy lang="HTML — Radio" code={codeRadio} />
|
||||
<CodeCopy lang="JSX (React) — Toggle" code={codeToggle} />
|
||||
<CodeCopy lang="CSS с сайта (perm.oclinica.ru)" code={codeSiteCSS} />
|
||||
</div>
|
||||
</Section>
|
||||
|
||||
{/* LLM-блок */}
|
||||
<LlmBlock path="/components/forms" version="v1.0" specText={LLM_FORMS_TEXT}>
|
||||
<LlmBlock path="/components/forms" version="v2.0" specText={LLM_FORMS_TEXT}>
|
||||
<LlmSection title="Элементы ввода" />
|
||||
<LlmTable
|
||||
headers={["Элемент", "CSS класс", "Тег", "Высота", "Описание"]}
|
||||
rows={[
|
||||
["Input", ".bb-input", "<input>", "~40px", "Текстовое поле, email, password"],
|
||||
["Input", ".bb-input", "<input>", "50px", "Текстовое поле, email, password · как на сайте"],
|
||||
["Textarea", ".bb-textarea", "<textarea>", "≥100px", "Многострочный ввод, resize:vertical"],
|
||||
["Select", ".bb-select", "<select>", "~40px", "Выбор из списка, кастомная стрелка"],
|
||||
["Select", ".bb-select", "<select>", "50px", "Выбор из списка, кастомная стрелка · как на сайте"],
|
||||
["Checkbox", ".bb-checkbox", "<input type=checkbox>", "16×16px", "Независимый выбор"],
|
||||
["Radio", ".bb-radio", "<input type=radio>", "16×16px", "Выбор одного из группы"],
|
||||
["Toggle", ".bb-toggle-track", "React-компонент", "24px", "Булев переключатель"],
|
||||
@@ -554,7 +688,7 @@ export default function FormsPage() {
|
||||
<LlmTable
|
||||
headers={["Состояние", "Стиль"]}
|
||||
rows={[
|
||||
["default", "border: 1.5px solid #e5e7eb"],
|
||||
["default", "border: 1px solid #ccc · border-radius: 4px"],
|
||||
["focus", "border: #7ecfca + box-shadow: 0 0 0 3px rgba(126,207,202,0.2)"],
|
||||
["error", "border: #dc2626 (+ класс .bb-error)"],
|
||||
["disabled", "opacity: 0.5 + cursor: not-allowed + bg: #f8f9fa"],
|
||||
|
||||
@@ -75,7 +75,7 @@ body {
|
||||
|
||||
/* Варианты — цвета и радиус по реальному сайту oclinica.ru */
|
||||
|
||||
/* primary — коралловая форм-кнопка «Запишите меня!» */
|
||||
/* primary — коралловая форм-кнопка «Запишите меня!» — #FFA39C */
|
||||
.bb-btn-primary {
|
||||
background: #FFA39C;
|
||||
color: #fff;
|
||||
@@ -117,14 +117,15 @@ body {
|
||||
font-size: 14px;
|
||||
color: var(--bb-text);
|
||||
background: #fff;
|
||||
border: 1.5px solid var(--bb-border);
|
||||
border-radius: 8px;
|
||||
padding: 9px 12px;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
padding: 10px 12px;
|
||||
width: 100%;
|
||||
transition: border-color 0.15s, box-shadow 0.15s;
|
||||
outline: none;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
.bb-input { height: 50px; }
|
||||
.bb-input:focus,
|
||||
.bb-textarea:focus,
|
||||
.bb-select:focus {
|
||||
@@ -145,10 +146,11 @@ body {
|
||||
.bb-select {
|
||||
cursor: pointer;
|
||||
appearance: none;
|
||||
height: 50px;
|
||||
padding: 10px 36px 10px 10px;
|
||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%236b7280' stroke-width='2'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
|
||||
background-repeat: no-repeat;
|
||||
background-position: right 10px center;
|
||||
padding-right: 36px;
|
||||
}
|
||||
|
||||
.bb-checkbox,
|
||||
|
||||
Reference in New Issue
Block a user