Compare commits
11 Commits
develop
...
0198947c4e
| Author | SHA1 | Date | |
|---|---|---|---|
| 0198947c4e | |||
| 6648f16bcb | |||
| 761347ed85 | |||
| 52acdc98e2 | |||
| 0570b50d9f | |||
| 789f436be1 | |||
| 5298f8c1cd | |||
| ff3f6acc03 | |||
| 39ecd72fde | |||
| a715503ca5 | |||
| 657cc26d3e |
@@ -1,6 +1,7 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useState, useCallback } from "react";
|
import { useState, useCallback } from "react";
|
||||||
|
import { LlmBlock, LlmSection, LlmTable, LlmRules } from "@/components/llm/LlmBlock";
|
||||||
import type { Metadata } from "next";
|
import type { Metadata } from "next";
|
||||||
|
|
||||||
/* ─── Утилиты конвертации ──────────────────────────────────────────── */
|
/* ─── Утилиты конвертации ──────────────────────────────────────────── */
|
||||||
@@ -102,6 +103,87 @@ const BRAND_COLORS = [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
/* ─── Соответствие цветов ──────────────────────────────────────────── */
|
||||||
|
const COLOR_MAPPING = [
|
||||||
|
{
|
||||||
|
brand: { oracal: "053M", name: "Основной бирюзовый", hex: "#7ecfca" },
|
||||||
|
web: { name: "Бирюзовый", hex: "#63bac3", count: 4 },
|
||||||
|
note: "Чуть темнее и насыщеннее на сайте",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
brand: { oracal: "073M", name: "Тёмный серо-голубой", hex: "#5b7b87" },
|
||||||
|
web: { name: "Серо-бирюзовый", hex: "#60959c", count: 7 },
|
||||||
|
note: "Светлее на сайте",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
brand: { oracal: "066M", name: "Средний бирюзовый", hex: "#5bb5ad" },
|
||||||
|
web: { name: "Бирюзовый средний", hex: "#52b4bd", count: 4 },
|
||||||
|
note: "Смещён в синеву",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
brand: { oracal: "081M", name: "Бежевый", hex: "#c4a882" },
|
||||||
|
web: { name: "Бежевый", hex: "#bf9975", count: 12 },
|
||||||
|
note: "Темнее и насыщеннее на сайте",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
brand: { oracal: "050M", name: "Тёмно-синий", hex: "#1b4c72" },
|
||||||
|
web: null,
|
||||||
|
note: "Не найден в CSS сайта",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
brand: { oracal: "080M", name: "Тёмно-коричневый", hex: "#5c2e0e" },
|
||||||
|
web: null,
|
||||||
|
note: "Не найден в CSS сайта",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
brand: null,
|
||||||
|
web: { name: "Основной текст", hex: "#464646", count: 3 },
|
||||||
|
note: "Только на сайте — нет Oracal-аналога",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
brand: null,
|
||||||
|
web: { name: "Второстепенный текст", hex: "#949290", count: 4 },
|
||||||
|
note: "Только на сайте — нет Oracal-аналога",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
brand: null,
|
||||||
|
web: { name: "Кремовый фон", hex: "#e9e4d4", count: 1 },
|
||||||
|
note: "Только на сайте — нет Oracal-аналога",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
brand: null,
|
||||||
|
web: { name: "Коралловый", hex: "#ffa39c", count: 2 },
|
||||||
|
note: "Только на сайте — CTA-кнопки, нет в оффлайн-палитре",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
brand: null,
|
||||||
|
web: { name: "Светло-жёлтый фон", hex: "#eef4d1", count: 1 },
|
||||||
|
note: "Только на сайте — фон карточек отзывов",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
brand: null,
|
||||||
|
web: { name: "Светло-зелёный фон", hex: "#f2fee6", count: 1 },
|
||||||
|
note: "Только на сайте — фон секции новостей",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
/* ─── Цвета с сайта ────────────────────────────────────────────────── */
|
||||||
|
// Источник: https://perm.oclinica.ru/sites/all/themes/clinic_bootstrap_mobile/css/style.css
|
||||||
|
// Извлечены парсингом CSS: grep + python Counter по property/value, 2026-03-22
|
||||||
|
const WEB_COLORS = [
|
||||||
|
{ name: "Бежевый", hex: "#bf9975", usage: "Основной тёплый акцент, фоны, рамки, текст", count: 12, group: "Акценты" },
|
||||||
|
{ name: "Серо-бирюзовый", hex: "#60959c", usage: "Основной холодный акцент, ссылки", count: 7, group: "Акценты" },
|
||||||
|
{ name: "Бирюзовый", hex: "#63bac3", usage: "Фоны акцентных блоков, иконки", count: 4, group: "Акценты" },
|
||||||
|
{ name: "Бирюзовый средний", hex: "#52b4bd", usage: "Вторичные цветовые акценты", count: 4, group: "Акценты" },
|
||||||
|
{ name: "Основной текст", hex: "#464646", usage: "Цвет основного текста на сайте", count: 3, group: "Текст" },
|
||||||
|
{ name: "Второстепенный текст", hex: "#949290", usage: "Подписи, второстепенный контент", count: 4, group: "Текст" },
|
||||||
|
{ name: "Светло-бирюзовый фон", hex: "#b8e6ed", usage: "Фоны светлых секций с акцентом", count: 1, group: "Фоны" },
|
||||||
|
{ name: "Кремовый фон", hex: "#e9e4d4", usage: "Тёплые фоны секций", count: 1, group: "Фоны" },
|
||||||
|
{ name: "Коралловый", hex: "#ffa39c", usage: "CTA-кнопки («Запишите меня!»), акцентные призывы к действию", count: 2, group: "Акценты" },
|
||||||
|
{ name: "Светло-жёлтый фон", hex: "#eef4d1", usage: "Фон карточек отзывов (секция «Отзывы о нас»)", count: 1, group: "Фоны" },
|
||||||
|
{ name: "Светло-зелёный фон", hex: "#f2fee6", usage: "Фон секции новостей", count: 1, group: "Фоны" },
|
||||||
|
];
|
||||||
|
|
||||||
const CONTRAST_PAIRS = [
|
const CONTRAST_PAIRS = [
|
||||||
{ fg: "#ffffff", bg: "#5b7b87", label: "Белый на тёмном серо-голубом" },
|
{ fg: "#ffffff", bg: "#5b7b87", label: "Белый на тёмном серо-голубом" },
|
||||||
{ fg: "#ffffff", bg: "#1b4c72", label: "Белый на тёмно-синем" },
|
{ fg: "#ffffff", bg: "#1b4c72", label: "Белый на тёмно-синем" },
|
||||||
@@ -245,9 +327,59 @@ function ContrastRow({ pair }: { pair: typeof CONTRAST_PAIRS[0] }) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function WebColorCard({ color }: { color: typeof WEB_COLORS[0] }) {
|
||||||
|
const { r, g, b } = hexToRgb(color.hex);
|
||||||
|
const { h, s, l } = rgbToHsl(r, g, b);
|
||||||
|
const isLight = l > 60;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className="rounded-xl overflow-hidden border"
|
||||||
|
style={{ borderColor: "var(--bb-border)" }}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="h-24 flex items-end justify-between px-4 pb-3"
|
||||||
|
style={{ background: color.hex }}
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
className="text-xs font-semibold px-2 py-0.5 rounded"
|
||||||
|
style={{
|
||||||
|
background: isLight ? "rgba(0,0,0,0.12)" : "rgba(255,255,255,0.18)",
|
||||||
|
color: isLight ? "rgba(0,0,0,0.75)" : "rgba(255,255,255,0.9)",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{color.group}
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
className="text-xs px-2 py-0.5 rounded font-mono"
|
||||||
|
style={{
|
||||||
|
background: isLight ? "rgba(0,0,0,0.12)" : "rgba(255,255,255,0.18)",
|
||||||
|
color: isLight ? "rgba(0,0,0,0.75)" : "rgba(255,255,255,0.9)",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
×{color.count}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div className="p-4" style={{ background: "var(--bb-content-bg)" }}>
|
||||||
|
<p className="font-medium text-sm mb-1" style={{ color: "var(--bb-text)" }}>
|
||||||
|
{color.name}
|
||||||
|
</p>
|
||||||
|
<p className="text-xs mb-3" style={{ color: "var(--bb-text-muted)" }}>
|
||||||
|
{color.usage}
|
||||||
|
</p>
|
||||||
|
<div className="flex flex-wrap gap-1.5">
|
||||||
|
<CopyBadge value={color.hex.toUpperCase()} label="HEX" />
|
||||||
|
<CopyBadge value={`rgb(${r}, ${g}, ${b})`} label="RGB" />
|
||||||
|
<CopyBadge value={`hsl(${h}, ${s}%, ${l}%)`} label="HSL" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/* ─── Экспорт токенов ──────────────────────────────────────────────── */
|
/* ─── Экспорт токенов ──────────────────────────────────────────────── */
|
||||||
function exportTokens() {
|
function exportTokens() {
|
||||||
const tokens: Record<string, Record<string, string>> = { colors: {} };
|
const tokens: Record<string, Record<string, unknown>> = { colors: {} };
|
||||||
BRAND_COLORS.forEach(c => {
|
BRAND_COLORS.forEach(c => {
|
||||||
const key = c.oracal !== "—" ? `brand-${c.oracal.toLowerCase()}` : "brand-white";
|
const key = c.oracal !== "—" ? `brand-${c.oracal.toLowerCase()}` : "brand-white";
|
||||||
const { r, g, b } = hexToRgb(c.hex);
|
const { r, g, b } = hexToRgb(c.hex);
|
||||||
@@ -268,6 +400,62 @@ function exportTokens() {
|
|||||||
URL.revokeObjectURL(url);
|
URL.revokeObjectURL(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ─── LLM spec text ────────────────────────────────────────────────── */
|
||||||
|
const LLM_COLORS_TEXT = `# ЦВЕТА — LLM-СПЕЦИФИКАЦИЯ
|
||||||
|
# Клиника ухо, горло, нос им. проф. Е.Н.Оленевой
|
||||||
|
# docs/LLM_CONTEXT.md · /foundation/colors · v2.1 · 2026-03-22
|
||||||
|
|
||||||
|
ФИРМЕННЫЕ ЦВЕТА (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 | Текст на бежевом, логотип на форме
|
||||||
|
— | Белый | #FFFFFF | rgb(255,255,255) | --brand-white | Фон, инвертированный текст, логотип на тёмных
|
||||||
|
|
||||||
|
ЦВЕТА САЙТА oclinica.ru (CSS: clinic_bootstrap_mobile/css/style.css)
|
||||||
|
Название | HEX | Группа | × | Применение
|
||||||
|
Бежевый | #BF9975 | Акценты | 12| Тёплый акцент, фоны, рамки, текст
|
||||||
|
Серо-бирюзовый | #60959C | Акценты | 7 | Холодный акцент, ссылки
|
||||||
|
Бирюзовый | #63BAC3 | Акценты | 4 | Фоны акцентных блоков, иконки
|
||||||
|
Бирюзовый средний | #52B4BD | Акценты | 4 | Вторичные цветовые акценты
|
||||||
|
Коралловый | #FFA39C | Акценты | 2 | CTA-кнопки («Запишите меня!»)
|
||||||
|
Основной текст | #464646 | Текст | 3 | Цвет основного текста сайта
|
||||||
|
Второстепенный текст | #949290 | Текст | 4 | Подписи, второстепенный контент
|
||||||
|
Светло-бирюзовый фон | #B8E6ED | Фоны | 1 | Фоны светлых секций
|
||||||
|
Кремовый фон | #E9E4D4 | Фоны | 1 | Тёплые фоны секций
|
||||||
|
Светло-жёлтый фон | #EEF4D1 | Фоны | 1 | Фон карточек отзывов
|
||||||
|
Светло-зелёный фон | #F2FEE6 | Фоны | 1 | Фон секции новостей
|
||||||
|
|
||||||
|
СООТВЕТСТВИЕ ORACAL → САЙТ
|
||||||
|
053M #7ECFCA → #63BAC3 (темнее, насыщеннее)
|
||||||
|
073M #5B7B87 → #60959C (светлее)
|
||||||
|
066M #5BB5AD → #52B4BD (смещён в синеву)
|
||||||
|
081M #C4A882 → #BF9975 (темнее, насыщеннее)
|
||||||
|
050M #1B4C72 → не найден в CSS сайта
|
||||||
|
080M #5C2E0E → не найден в 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
|
||||||
|
|
||||||
|
ПРАВИЛА
|
||||||
|
✓ Только цвета из фирменной палитры
|
||||||
|
✓ Digital → цвета сайта; оффлайн → коды Oracal
|
||||||
|
✓ Текст на цветном фоне: минимум WCAG AA (4.5:1)
|
||||||
|
✓ Белый текст на: 073M (#5B7B87), 050M (#1B4C72), 080M (#5C2E0E)
|
||||||
|
✓ Тёмный текст на: 053M (#7ECFCA), 081M (#C4A882)
|
||||||
|
✕ Произвольные цвета вне фирменной палитры
|
||||||
|
✕ Изменение насыщенности / оттенка фирменных цветов
|
||||||
|
✕ Тёплые и холодные акценты рядом без нейтрального разделителя`.trim();
|
||||||
|
|
||||||
/* ─── Страница ─────────────────────────────────────────────────────── */
|
/* ─── Страница ─────────────────────────────────────────────────────── */
|
||||||
export default function ColorsPage() {
|
export default function ColorsPage() {
|
||||||
return (
|
return (
|
||||||
@@ -348,8 +536,120 @@ export default function ColorsPage() {
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
{/* 3. Применение */}
|
{/* 3. Цвета с сайта */}
|
||||||
<section className="mb-12">
|
<section className="mb-12">
|
||||||
|
<div className="mb-6">
|
||||||
|
<h2 className="text-xl font-semibold" style={{ color: "var(--bb-text)" }}>
|
||||||
|
Цвета с сайта
|
||||||
|
</h2>
|
||||||
|
<p className="mt-1 text-sm" style={{ color: "var(--bb-text-muted)" }}>
|
||||||
|
Реальные цвета, используемые на сайте oclinica.ru. Извлечены из CSS темы сайта.
|
||||||
|
Число применений показано в правом углу карточки.
|
||||||
|
</p>
|
||||||
|
<div
|
||||||
|
className="mt-3 flex items-center gap-2 px-3 py-2 rounded-lg text-xs w-fit font-mono"
|
||||||
|
style={{ background: "var(--bb-sidebar-bg)", color: "var(--bb-text-muted)", border: "1px solid var(--bb-border)" }}
|
||||||
|
>
|
||||||
|
<span style={{ color: "var(--brand-053m)" }}>CSS</span>
|
||||||
|
perm.oclinica.ru/sites/all/themes/clinic_bootstrap_mobile/css/style.css
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4">
|
||||||
|
{WEB_COLORS.map(c => (
|
||||||
|
<WebColorCard key={c.hex} color={c} />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* 4. Соответствие */}
|
||||||
|
<section className="mb-12">
|
||||||
|
<div className="mb-6">
|
||||||
|
<h2 className="text-xl font-semibold" style={{ color: "var(--bb-text)" }}>
|
||||||
|
Соответствие: Oracal → Сайт
|
||||||
|
</h2>
|
||||||
|
<p className="mt-1 text-sm" style={{ color: "var(--bb-text-muted)" }}>
|
||||||
|
Сравнение фирменной палитры (Oracal, брендбук) с реальными цветами, применёнными на сайте.
|
||||||
|
Расхождения ожидаемы — цифровая адаптация плёночных цветов под экран.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-col gap-3">
|
||||||
|
{COLOR_MAPPING.map((row, i) => (
|
||||||
|
<div
|
||||||
|
key={i}
|
||||||
|
className="flex items-center gap-3 p-4 rounded-xl border"
|
||||||
|
style={{ borderColor: "var(--bb-border)", background: "var(--bb-content-bg)" }}
|
||||||
|
>
|
||||||
|
{/* Левая сторона — Oracal */}
|
||||||
|
<div className="flex items-center gap-3 w-56 shrink-0">
|
||||||
|
{row.brand ? (
|
||||||
|
<>
|
||||||
|
<div
|
||||||
|
className="w-10 h-10 rounded-lg shrink-0 border"
|
||||||
|
style={{ background: row.brand.hex, borderColor: "var(--bb-border)" }}
|
||||||
|
/>
|
||||||
|
<div>
|
||||||
|
<p className="text-xs font-semibold font-mono" style={{ color: "var(--bb-text)" }}>
|
||||||
|
{row.brand.hex.toUpperCase()}
|
||||||
|
</p>
|
||||||
|
<p className="text-xs" style={{ color: "var(--bb-text-muted)" }}>
|
||||||
|
Oracal {row.brand.oracal}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<div
|
||||||
|
className="w-10 h-10 rounded-lg shrink-0 flex items-center justify-center text-lg border"
|
||||||
|
style={{ borderColor: "var(--bb-border)", background: "var(--bb-sidebar-bg)" }}
|
||||||
|
>
|
||||||
|
—
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Стрелка */}
|
||||||
|
<div className="shrink-0 text-sm font-bold" style={{ color: "var(--bb-text-muted)" }}>→</div>
|
||||||
|
|
||||||
|
{/* Правая сторона — Сайт */}
|
||||||
|
<div className="flex items-center gap-3 w-56 shrink-0">
|
||||||
|
{row.web ? (
|
||||||
|
<>
|
||||||
|
<div
|
||||||
|
className="w-10 h-10 rounded-lg shrink-0 border"
|
||||||
|
style={{ background: row.web.hex, borderColor: "var(--bb-border)" }}
|
||||||
|
/>
|
||||||
|
<div>
|
||||||
|
<p className="text-xs font-semibold font-mono" style={{ color: "var(--bb-text)" }}>
|
||||||
|
{row.web.hex.toUpperCase()}
|
||||||
|
</p>
|
||||||
|
<p className="text-xs" style={{ color: "var(--bb-text-muted)" }}>
|
||||||
|
{row.web.name} · ×{row.web.count}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<div
|
||||||
|
className="w-10 h-10 rounded-lg shrink-0 flex items-center justify-center text-lg border"
|
||||||
|
style={{ borderColor: "var(--bb-border)", background: "var(--bb-sidebar-bg)" }}
|
||||||
|
>
|
||||||
|
—
|
||||||
|
</div>
|
||||||
|
<p className="text-xs" style={{ color: "var(--bb-text-muted)" }}>Нет на сайте</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Примечание */}
|
||||||
|
<p className="flex-1 text-xs" style={{ color: "var(--bb-text-muted)" }}>
|
||||||
|
{row.note}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* 5. Применение */}
|
||||||
|
<section className="mb-10">
|
||||||
<div className="mb-6">
|
<div className="mb-6">
|
||||||
<h2 className="text-xl font-semibold" style={{ color: "var(--bb-text)" }}>
|
<h2 className="text-xl font-semibold" style={{ color: "var(--bb-text)" }}>
|
||||||
Правила применения
|
Правила применения
|
||||||
@@ -410,6 +710,105 @@ export default function ColorsPage() {
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
{/* 6. LLM-спецификация */}
|
||||||
|
<section className="mb-8">
|
||||||
|
<div className="mb-6">
|
||||||
|
<h2 className="text-xl font-semibold" style={{ color: "var(--bb-text)" }}>
|
||||||
|
LLM-спецификация
|
||||||
|
</h2>
|
||||||
|
<p className="mt-1 text-sm" style={{ color: "var(--bb-text-muted)" }}>
|
||||||
|
Машиночитаемые данные раздела для использования AI-ассистентами при разработке
|
||||||
|
дизайна, макетов и кода. Нажмите «Скопировать» чтобы получить полный текст.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<LlmBlock
|
||||||
|
path="/foundation/colors"
|
||||||
|
version="v2.1"
|
||||||
|
specText={LLM_COLORS_TEXT}
|
||||||
|
>
|
||||||
|
{/* Фирменные цвета */}
|
||||||
|
<div className="space-y-2">
|
||||||
|
<LlmSection title="Фирменные цвета (Oracal)" />
|
||||||
|
<LlmTable
|
||||||
|
headers={["Oracal", "HEX", "RGB", "CSS-переменная", "Применение"]}
|
||||||
|
rows={BRAND_COLORS.map(c => {
|
||||||
|
const { r, g, b } = hexToRgb(c.hex);
|
||||||
|
return [
|
||||||
|
<span key="o" className="flex items-center gap-1.5">
|
||||||
|
<span className="w-3 h-3 rounded-sm shrink-0 border inline-block" style={{ background: c.hex, borderColor: "var(--bb-border)" }} />
|
||||||
|
{c.oracal}
|
||||||
|
</span>,
|
||||||
|
<span key="h" style={{ color: "var(--bb-text)" }}>{c.hex.toUpperCase()}</span>,
|
||||||
|
`rgb(${r},${g},${b})`,
|
||||||
|
<span key="v" style={{ color: "var(--brand-073m)" }}>{c.cssVar}</span>,
|
||||||
|
c.usage,
|
||||||
|
];
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Цвета сайта */}
|
||||||
|
<div className="space-y-2">
|
||||||
|
<LlmSection title="Цвета сайта oclinica.ru" />
|
||||||
|
<LlmTable
|
||||||
|
headers={["Название", "HEX", "Группа", "×", "Применение"]}
|
||||||
|
rows={WEB_COLORS.map(c => [
|
||||||
|
<span key="n" className="flex items-center gap-1.5">
|
||||||
|
<span className="w-3 h-3 rounded-sm shrink-0 border inline-block" style={{ background: c.hex, borderColor: "var(--bb-border)" }} />
|
||||||
|
{c.name}
|
||||||
|
</span>,
|
||||||
|
<span key="h" style={{ color: "var(--bb-text)" }}>{c.hex.toUpperCase()}</span>,
|
||||||
|
c.group,
|
||||||
|
String(c.count),
|
||||||
|
c.usage,
|
||||||
|
])}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Контрастность */}
|
||||||
|
<div className="space-y-2">
|
||||||
|
<LlmSection title="Контрастность WCAG 2.1" />
|
||||||
|
<LlmTable
|
||||||
|
headers={["Пара (fg / bg)", "Ratio", "AA (4.5:1)", "AAA (7:1)", "AA large (3:1)"]}
|
||||||
|
rows={CONTRAST_PAIRS.map(p => {
|
||||||
|
const ratio = contrastRatio(p.fg, p.bg);
|
||||||
|
const aa = ratio >= 4.5, aaa = ratio >= 7, aal = ratio >= 3;
|
||||||
|
const badge = (pass: boolean) => (
|
||||||
|
<span key={String(pass)} style={{ color: pass ? "#059669" : "#dc2626", fontWeight: 700 }}>
|
||||||
|
{pass ? "PASS" : "FAIL"}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
return [
|
||||||
|
<span key="pair" className="flex items-center gap-1.5">
|
||||||
|
<span className="w-3 h-3 rounded-sm border inline-block shrink-0" style={{ background: p.bg, borderColor: "var(--bb-border)" }} />
|
||||||
|
{p.fg} / {p.bg}
|
||||||
|
</span>,
|
||||||
|
`${ratio}:1`,
|
||||||
|
badge(aa),
|
||||||
|
badge(aaa),
|
||||||
|
badge(aal),
|
||||||
|
];
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Правила */}
|
||||||
|
<div className="space-y-2">
|
||||||
|
<LlmSection title="Правила применения" />
|
||||||
|
<LlmRules rules={[
|
||||||
|
{ 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: false, text: "Произвольные цвета вне фирменной палитры" },
|
||||||
|
{ ok: false, text: "Изменение насыщенности / оттенка фирменных цветов" },
|
||||||
|
{ ok: false, text: "Тёплые + холодные акценты рядом без разделителя" },
|
||||||
|
]} />
|
||||||
|
</div>
|
||||||
|
</LlmBlock>
|
||||||
|
</section>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import type { Metadata } from "next";
|
|||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: "Логотип | Брендбук О!Клиника",
|
title: "Логотип. Цифровой брендбук Клиники ухо, горло, нос им. проф. Е.Н.Оленевой",
|
||||||
};
|
};
|
||||||
|
|
||||||
function RuleTag({ children }: { children: React.ReactNode }) {
|
function RuleTag({ children }: { children: React.ReactNode }) {
|
||||||
@@ -132,31 +132,119 @@ export default function LogoPage() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* 1. Иерархия */}
|
{/* 1. Логотип */}
|
||||||
<Section
|
<Section
|
||||||
id="hierarchy"
|
id="hierarchy"
|
||||||
title="Иерархия и версии"
|
title="Логотип"
|
||||||
subtitle="Клиника использует два варианта логотипа в зависимости от контекста применения."
|
subtitle="Единый логотип клиники. Применяется на всех носителях."
|
||||||
>
|
>
|
||||||
<div className="grid grid-cols-1 gap-8 md:grid-cols-2">
|
<LogoCard
|
||||||
<LogoCard
|
src="/logo/logo-transparent.png"
|
||||||
src="/logo/logo-transparent.png"
|
alt="Логотип Клиника ухо, горло, нос им. проф. Е.Н. Оленевой"
|
||||||
alt="Основной логотип Клиника УХО ГОРЛО НОС им. проф. Е.Н. Оленевой"
|
label="Логотип клиники"
|
||||||
label="Основной логотип"
|
description="Применяется в точках контакта с клиентами, на лендингах и сайтах направлений. Применяется для онлайн и оффлайн коммуникаций с клиентами, во внутренней документации."
|
||||||
description="Локальные версии по направлениям (ЛОР, аллергология и др.). Применяется в точках контакта с клиентами, на лендингах и сайтах направлений."
|
tag="Онлайн · Оффлайн · Документация"
|
||||||
tag="Точки контакта с клиентом"
|
/>
|
||||||
/>
|
</Section>
|
||||||
<LogoCard
|
|
||||||
src="/logo/logo-transparent.png"
|
{/* 2. Символика знака */}
|
||||||
alt="Общий логотип сети клиник"
|
<Section
|
||||||
label="Общий логотип"
|
id="symbol"
|
||||||
description="Версия сети клиник. Применяется для онлайн и оффлайн коммуникаций с клиентами, во внутренней документации. Допустимо на общем сайте."
|
title="Символика знака"
|
||||||
tag="Сеть клиник · Документация · Сайт"
|
subtitle="О том, что стоит за формой логотипа."
|
||||||
/>
|
>
|
||||||
|
{/* Главный тезис */}
|
||||||
|
<div
|
||||||
|
className="rounded-xl border p-6 mb-6"
|
||||||
|
style={{ borderColor: "var(--bb-border)", background: "var(--bb-sidebar-bg)" }}
|
||||||
|
>
|
||||||
|
<p className="text-sm leading-relaxed" style={{ color: "var(--bb-text)" }}>
|
||||||
|
В знаке клиники — три округлых элемента, расположенных с равной дистанцией от центра.
|
||||||
|
Это создаёт ощущение симметрии, порядка и движения, но без завершённой формы (звезды или круга).
|
||||||
|
</p>
|
||||||
|
<div className="mt-4 flex flex-col gap-2">
|
||||||
|
{[
|
||||||
|
"Сохраняет баланс и лёгкость",
|
||||||
|
"Намекает на естественность и органику",
|
||||||
|
"Не замыкает символ — оставляет «дыхание», открытость",
|
||||||
|
].map(item => (
|
||||||
|
<div key={item} className="flex items-start gap-2.5">
|
||||||
|
<div
|
||||||
|
className="w-1.5 h-1.5 rounded-full mt-1.5 shrink-0"
|
||||||
|
style={{ background: "var(--brand-053m)" }}
|
||||||
|
/>
|
||||||
|
<p className="text-sm" style={{ color: "var(--bb-text-muted)" }}>{item}</p>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Три значения */}
|
||||||
|
<div className="grid grid-cols-1 gap-4 sm:grid-cols-3 mb-6">
|
||||||
|
{[
|
||||||
|
{
|
||||||
|
num: "1",
|
||||||
|
title: "Незамкнутая симметрия",
|
||||||
|
text: "Это процесс, а не результат. Знак говорит: «мы развиваемся, мы живые, мы не идеальны, но гармоничны».",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
num: "2",
|
||||||
|
title: "Три элемента",
|
||||||
|
text: "Классическая структура уха–горла–носа. Триада равновесия, ритм дыхания, символ доверия и открытости.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
num: "3",
|
||||||
|
title: "Отсутствие замкнутости",
|
||||||
|
text: "Нет барьера — есть приглашение. Открытая форма передаёт заботу, доступность и человечность.",
|
||||||
|
},
|
||||||
|
].map(item => (
|
||||||
|
<div
|
||||||
|
key={item.num}
|
||||||
|
className="rounded-xl border p-5"
|
||||||
|
style={{ borderColor: "var(--bb-border)" }}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="w-7 h-7 rounded-full flex items-center justify-center text-xs font-bold mb-3"
|
||||||
|
style={{ background: "#e0f5f4", color: "var(--brand-073m)" }}
|
||||||
|
>
|
||||||
|
{item.num}
|
||||||
|
</div>
|
||||||
|
<p className="font-medium text-sm mb-2" style={{ color: "var(--bb-text)" }}>
|
||||||
|
{item.title}
|
||||||
|
</p>
|
||||||
|
<p className="text-sm leading-relaxed" style={{ color: "var(--bb-text-muted)" }}>
|
||||||
|
{item.text}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Почему не звезда */}
|
||||||
|
<div
|
||||||
|
className="rounded-xl border p-5 flex gap-4"
|
||||||
|
style={{ borderColor: "#e0f5f4", background: "#f8fffe" }}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="w-8 h-8 rounded-full flex items-center justify-center shrink-0 mt-0.5"
|
||||||
|
style={{ background: "#e0f5f4" }}
|
||||||
|
>
|
||||||
|
<span className="text-base leading-none">○</span>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p className="font-medium text-sm mb-1.5" style={{ color: "var(--bb-text)" }}>
|
||||||
|
Почему нет законченной звезды
|
||||||
|
</p>
|
||||||
|
<p className="text-sm leading-relaxed" style={{ color: "var(--bb-text-muted)" }}>
|
||||||
|
Звезда — символ завершённости и сакрального порядка. Знак клиники — символ жизни
|
||||||
|
и взаимодействия. Он ближе по духу к живой биоморфной форме (капли, клетки, лепестки),
|
||||||
|
чем к идеальной математической фигуре. Такой дизайн передаёт не «власть формы»,
|
||||||
|
а заботу, мягкость и человечность.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Section>
|
</Section>
|
||||||
|
|
||||||
{/* 2. Цветовые варианты */}
|
{/* 3. Цветовые варианты */}
|
||||||
<Section
|
<Section
|
||||||
id="variants"
|
id="variants"
|
||||||
title="Цветовые варианты"
|
title="Цветовые варианты"
|
||||||
@@ -237,8 +325,7 @@ export default function LogoPage() {
|
|||||||
{/* 4. Минимальные размеры */}
|
{/* 4. Минимальные размеры */}
|
||||||
<Section
|
<Section
|
||||||
id="sizes"
|
id="sizes"
|
||||||
title="Минимальные размеры"
|
title="Размеры логотипа для размещения на форме сотрудников"
|
||||||
subtitle="Размеры логотипа для размещения на форме сотрудников."
|
|
||||||
>
|
>
|
||||||
<div className="overflow-hidden rounded-xl border" style={{ borderColor: "var(--bb-border)" }}>
|
<div className="overflow-hidden rounded-xl border" style={{ borderColor: "var(--bb-border)" }}>
|
||||||
<table className="w-full text-sm">
|
<table className="w-full text-sm">
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import type { Metadata } from "next";
|
import type { Metadata } from "next";
|
||||||
|
import { LlmBlock, LlmSection, LlmTable, LlmRules } from "@/components/llm/LlmBlock";
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: "Типографика | Брендбук О!Клиника",
|
title: "Типографика. Цифровой брендбук Клиники ухо, горло, нос им. проф. Е.Н.Оленевой",
|
||||||
};
|
};
|
||||||
|
|
||||||
/* ─── Шкала типографики ────────────────────────────────────────────── */
|
/* ─── Шкала типографики ────────────────────────────────────────────── */
|
||||||
@@ -28,6 +29,60 @@ const FIRA_SCALE = [
|
|||||||
{ token: "overline", size: "10px / 0.625rem",weight: "600", lh: "1.4", sample: "ФУНДАМЕНТ → 1.4" },
|
{ token: "overline", size: "10px / 0.625rem",weight: "600", lh: "1.4", sample: "ФУНДАМЕНТ → 1.4" },
|
||||||
];
|
];
|
||||||
|
|
||||||
|
/* ─── LLM spec text ────────────────────────────────────────────────── */
|
||||||
|
const LLM_TYPOGRAPHY_TEXT = `# ТИПОГРАФИКА — LLM-СПЕЦИФИКАЦИЯ
|
||||||
|
# Клиника ухо, горло, нос им. проф. Е.Н.Оленевой
|
||||||
|
# docs/LLM_CONTEXT.md · /foundation/typography · v2.0 · 2026-03-22
|
||||||
|
|
||||||
|
ШРИФТЫ БРЕНДА
|
||||||
|
Шрифт | Тип | Применение | CSS
|
||||||
|
DINPro | Бренд | Оффлайн, физические носители (бейджи, таблички, транспорт, форма) | font-family: 'DINPro', Arial, sans-serif
|
||||||
|
Fira Sans| Веб | Сайт, цифровые материалы, брендбук | font-family: 'Fira Sans', sans-serif; Google Fonts; weights: 300/400/500/600
|
||||||
|
|
||||||
|
ПРАВИЛО ВЫБОРА: носитель цифровой → Fira Sans; физический/печатный → DINPro
|
||||||
|
|
||||||
|
DINPro — ШКАЛА (оффлайн)
|
||||||
|
Стиль | font-size | rem | weight | line-height
|
||||||
|
h1 | 40px | 2.5rem | 700 | 1.20
|
||||||
|
h2 | 32px | 2rem | 700 | 1.25
|
||||||
|
h3 | 24px | 1.5rem | 700 | 1.30
|
||||||
|
h4 | 20px | 1.25rem | 700 | 1.35
|
||||||
|
h5 | 16px | 1rem | 700 | 1.40
|
||||||
|
h6 | 14px | 0.875rem | 700 | 1.40
|
||||||
|
|
||||||
|
Fira Sans — ШКАЛА (веб)
|
||||||
|
Стиль | font-size | rem | weight | line-height | letter-spacing
|
||||||
|
h1 | 40px | 2.5rem | 600 | 1.20 | -0.025em
|
||||||
|
h2 | 32px | 2rem | 600 | 1.25 | -0.020em
|
||||||
|
h3 | 24px | 1.5rem | 600 | 1.30 | -0.010em
|
||||||
|
h4 | 20px | 1.25rem | 500 | 1.35 | 0em
|
||||||
|
h5 | 16px | 1rem | 500 | 1.40 | 0em
|
||||||
|
h6 | 14px | 0.875rem | 500 | 1.40 | +0.010em
|
||||||
|
body | 16px | 1rem | 400 | 1.60 | 0em
|
||||||
|
body-sm | 14px | 0.875rem | 400 | 1.60 | 0em
|
||||||
|
caption | 12px | 0.75rem | 400 | 1.50 | +0.020em
|
||||||
|
label | 12px | 0.75rem | 500 | 1.40 | +0.030em
|
||||||
|
overline | 10px | 0.625rem | 600 | 1.40 | +0.100em (uppercase)
|
||||||
|
|
||||||
|
ПРИМЕНЕНИЕ ПО НОСИТЕЛЮ
|
||||||
|
Носитель | Шрифт
|
||||||
|
Сайт, цифровые материалы, брендбук | Fira Sans
|
||||||
|
Форма сотрудников, бейджи | DINPro
|
||||||
|
Вывески, таблички, навигация | DINPro
|
||||||
|
Брендирование транспорта | DINPro
|
||||||
|
Визитки, листовки, полиграфия | DINPro
|
||||||
|
Telegram-бот, пуш-уведомления | Fira Sans (системный)
|
||||||
|
|
||||||
|
ПРАВИЛА
|
||||||
|
✓ H1 — только один на странице
|
||||||
|
✓ Не пропускать уровни заголовков (h1 → h2 → h3)
|
||||||
|
✓ Минимальный размер текста на экране: 12px
|
||||||
|
✓ Кириллица → Fira Sans (не DINPro)
|
||||||
|
✓ Fira Sans: доступные веса 300 / 400 / 500 / 600
|
||||||
|
✕ DINPro на сайте без явного согласования дизайнера
|
||||||
|
✕ Light (300) для текста < 14px
|
||||||
|
✕ Смешивать DINPro и Fira Sans на одном носителе`.trim();
|
||||||
|
|
||||||
/* ─── Компоненты ───────────────────────────────────────────────────── */
|
/* ─── Компоненты ───────────────────────────────────────────────────── */
|
||||||
function Section({
|
function Section({
|
||||||
title,
|
title,
|
||||||
@@ -344,6 +399,110 @@ export default function TypographyPage() {
|
|||||||
</div>
|
</div>
|
||||||
</Section>
|
</Section>
|
||||||
|
|
||||||
|
{/* LLM-спецификация */}
|
||||||
|
<section className="mb-8">
|
||||||
|
<div className="mb-6">
|
||||||
|
<h2 className="text-xl font-semibold" style={{ color: "var(--bb-text)" }}>
|
||||||
|
LLM-спецификация
|
||||||
|
</h2>
|
||||||
|
<p className="mt-1 text-sm" style={{ color: "var(--bb-text-muted)" }}>
|
||||||
|
Машиночитаемые данные раздела для использования AI-ассистентами при разработке
|
||||||
|
дизайна, макетов и кода. Нажмите «Скопировать» чтобы получить полный текст.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<LlmBlock
|
||||||
|
path="/foundation/typography"
|
||||||
|
version="v2.0"
|
||||||
|
specText={LLM_TYPOGRAPHY_TEXT}
|
||||||
|
>
|
||||||
|
{/* Шрифты */}
|
||||||
|
<div className="space-y-2">
|
||||||
|
<LlmSection title="Шрифты бренда" />
|
||||||
|
<LlmTable
|
||||||
|
headers={["Шрифт", "Тип", "Применение", "CSS font-family"]}
|
||||||
|
rows={[
|
||||||
|
[
|
||||||
|
<span key="d" style={{ color: "var(--bb-text)", fontWeight: 600 }}>DINPro</span>,
|
||||||
|
"Бренд",
|
||||||
|
"Оффлайн, физические носители (бейджи, таблички, транспорт, форма)",
|
||||||
|
"'DINPro', Arial, sans-serif",
|
||||||
|
],
|
||||||
|
[
|
||||||
|
<span key="f" style={{ color: "var(--bb-text)", fontWeight: 600 }}>Fira Sans</span>,
|
||||||
|
"Веб",
|
||||||
|
"Сайт, цифровые материалы, брендбук",
|
||||||
|
"'Fira Sans', sans-serif · Google Fonts · 300/400/500/600",
|
||||||
|
],
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* DINPro шкала */}
|
||||||
|
<div className="space-y-2">
|
||||||
|
<LlmSection title="DINPro — шкала (оффлайн)" />
|
||||||
|
<LlmTable
|
||||||
|
headers={["Стиль", "font-size", "rem", "weight", "line-height"]}
|
||||||
|
rows={DIN_SCALE.map(r => {
|
||||||
|
const [px, rem] = r.size.split(" / ");
|
||||||
|
return [r.token, px, rem, r.weight, r.lh];
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Fira Sans шкала */}
|
||||||
|
<div className="space-y-2">
|
||||||
|
<LlmSection title="Fira Sans — шкала (веб)" />
|
||||||
|
<LlmTable
|
||||||
|
headers={["Стиль", "font-size", "rem", "weight", "line-height", "letter-spacing"]}
|
||||||
|
rows={[
|
||||||
|
["h1", "40px", "2.5rem", "600", "1.20", "-0.025em"],
|
||||||
|
["h2", "32px", "2rem", "600", "1.25", "-0.020em"],
|
||||||
|
["h3", "24px", "1.5rem", "600", "1.30", "-0.010em"],
|
||||||
|
["h4", "20px", "1.25rem", "500", "1.35", "0em"],
|
||||||
|
["h5", "16px", "1rem", "500", "1.40", "0em"],
|
||||||
|
["h6", "14px", "0.875rem", "500", "1.40", "+0.010em"],
|
||||||
|
["body", "16px", "1rem", "400", "1.60", "0em"],
|
||||||
|
["body-sm", "14px", "0.875rem", "400", "1.60", "0em"],
|
||||||
|
["caption", "12px", "0.75rem", "400", "1.50", "+0.020em"],
|
||||||
|
["label", "12px", "0.75rem", "500", "1.40", "+0.030em"],
|
||||||
|
["overline", "10px", "0.625rem", "600", "1.40", "+0.100em"],
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Применение */}
|
||||||
|
<div className="space-y-2">
|
||||||
|
<LlmSection title="Применение по носителю" />
|
||||||
|
<LlmTable
|
||||||
|
headers={["Носитель", "Шрифт"]}
|
||||||
|
rows={[
|
||||||
|
["Сайт, цифровые материалы, брендбук", <span key="fs" style={{ color: "var(--brand-073m)" }}>Fira Sans</span>],
|
||||||
|
["Форма сотрудников, бейджи", <span key="d1" style={{ color: "var(--brand-073m)" }}>DINPro</span>],
|
||||||
|
["Вывески, таблички, навигация", <span key="d2" style={{ color: "var(--brand-073m)" }}>DINPro</span>],
|
||||||
|
["Брендирование транспорта", <span key="d3" style={{ color: "var(--brand-073m)" }}>DINPro</span>],
|
||||||
|
["Визитки, листовки, полиграфия", <span key="d4" style={{ color: "var(--brand-073m)" }}>DINPro</span>],
|
||||||
|
["Telegram-бот, пуш-уведомления", <span key="fs2" style={{ color: "var(--brand-073m)" }}>Fira Sans (системный)</span>],
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Правила */}
|
||||||
|
<div className="space-y-2">
|
||||||
|
<LlmSection title="Правила применения" />
|
||||||
|
<LlmRules rules={[
|
||||||
|
{ ok: true, text: "H1 — только один на странице" },
|
||||||
|
{ ok: true, text: "Не пропускать уровни заголовков (h1 → h2 → h3)" },
|
||||||
|
{ ok: true, text: "Минимальный размер текста на экране: 12px" },
|
||||||
|
{ ok: true, text: "Кириллица → Fira Sans (не DINPro)" },
|
||||||
|
{ ok: true, text: "Fira Sans: доступные веса 300 / 400 / 500 / 600" },
|
||||||
|
{ ok: false, text: "DINPro на сайте без явного согласования дизайнера" },
|
||||||
|
{ ok: false, text: "Light (300) для текста < 14px" },
|
||||||
|
{ ok: false, text: "Смешивать DINPro и Fira Sans на одном носителе" },
|
||||||
|
]} />
|
||||||
|
</div>
|
||||||
|
</LlmBlock>
|
||||||
|
</section>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,79 +31,6 @@ function Section({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Компонент бейджа (масштабированный макет) */
|
|
||||||
function BadgeMockup({
|
|
||||||
variant,
|
|
||||||
name,
|
|
||||||
role,
|
|
||||||
}: {
|
|
||||||
variant: "light" | "dark";
|
|
||||||
name: string;
|
|
||||||
role: string;
|
|
||||||
}) {
|
|
||||||
const isDark = variant === "dark";
|
|
||||||
/* 70×30 мм → пропорция 7:3. Отображаем в 280×120px */
|
|
||||||
return (
|
|
||||||
<div className="flex flex-col items-center gap-3">
|
|
||||||
<div
|
|
||||||
className="rounded-lg flex items-center px-5 gap-4"
|
|
||||||
style={{
|
|
||||||
width: 280,
|
|
||||||
height: 120,
|
|
||||||
background: isDark ? "var(--brand-073m)" : "var(--brand-081m)",
|
|
||||||
border: isDark ? "none" : "1px solid #d1d5db",
|
|
||||||
flexShrink: 0,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{/* Логотип */}
|
|
||||||
<Image
|
|
||||||
src="/logo/logo-transparent.png"
|
|
||||||
alt="Логотип"
|
|
||||||
width={72}
|
|
||||||
height={26}
|
|
||||||
className="object-contain shrink-0"
|
|
||||||
style={{
|
|
||||||
filter: isDark
|
|
||||||
? "brightness(0) invert(1)"
|
|
||||||
: "brightness(0) sepia(1) saturate(2) hue-rotate(330deg) brightness(0.45)",
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
{/* Разделитель */}
|
|
||||||
<div
|
|
||||||
className="self-stretch w-px mx-1"
|
|
||||||
style={{ background: isDark ? "rgba(255,255,255,0.25)" : "rgba(92,46,14,0.2)" }}
|
|
||||||
/>
|
|
||||||
{/* Текст */}
|
|
||||||
<div>
|
|
||||||
<p
|
|
||||||
className="font-bold leading-tight"
|
|
||||||
style={{
|
|
||||||
fontFamily: "'DINPro', Arial, sans-serif",
|
|
||||||
fontSize: 13,
|
|
||||||
color: isDark ? "#ffffff" : "#5c2e0e",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{name}
|
|
||||||
</p>
|
|
||||||
<p
|
|
||||||
className="leading-tight mt-0.5"
|
|
||||||
style={{
|
|
||||||
fontFamily: "'DINPro', Arial, sans-serif",
|
|
||||||
fontSize: 10,
|
|
||||||
color: isDark ? "rgba(255,255,255,0.7)" : "rgba(92,46,14,0.7)",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{role}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<p className="text-xs" style={{ color: "var(--bb-text-muted)" }}>
|
|
||||||
{isDark ? "Тёмный вариант (серо-голубой)" : "Светлый вариант (бежевый)"}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function BadgesPage() {
|
export default function BadgesPage() {
|
||||||
return (
|
return (
|
||||||
<div className="max-w-4xl mx-auto px-8 py-10">
|
<div className="max-w-4xl mx-auto px-8 py-10">
|
||||||
@@ -120,24 +47,76 @@ export default function BadgesPage() {
|
|||||||
Бейджи сотрудников
|
Бейджи сотрудников
|
||||||
</h1>
|
</h1>
|
||||||
<p className="text-base max-w-2xl" style={{ color: "var(--bb-text-muted)" }}>
|
<p className="text-base max-w-2xl" style={{ color: "var(--bb-text-muted)" }}>
|
||||||
Именные бейджи для идентификации сотрудников клиники. Размер 70×30 мм.
|
Именные бейджи для идентификации сотрудников клиники. Размер 70×30 мм,
|
||||||
Два цветовых варианта в зависимости от должности.
|
магнитное крепление. Белый фон, чёрный текст.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Размеры и технические требования */}
|
{/* Фотографии */}
|
||||||
|
<Section
|
||||||
|
title="Образцы бейджей"
|
||||||
|
subtitle="Фотографии реальных бейджей из брендбука клиники."
|
||||||
|
>
|
||||||
|
<div className="grid grid-cols-1 gap-6 sm:grid-cols-2">
|
||||||
|
{/* Лицевая сторона */}
|
||||||
|
<div>
|
||||||
|
<div
|
||||||
|
className="rounded-xl overflow-hidden border mb-4"
|
||||||
|
style={{ borderColor: "var(--bb-border)" }}
|
||||||
|
>
|
||||||
|
<Image
|
||||||
|
src="/offline/badges/badge-2.jpeg"
|
||||||
|
alt="Лицевая сторона бейджа: Лебединская Елена Александровна, врач оториноларинголог"
|
||||||
|
width={690}
|
||||||
|
height={347}
|
||||||
|
className="w-full object-cover"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<p className="font-medium text-sm mb-1" style={{ color: "var(--bb-text)" }}>
|
||||||
|
Лицевая сторона
|
||||||
|
</p>
|
||||||
|
<p className="text-sm" style={{ color: "var(--bb-text-muted)" }}>
|
||||||
|
Белый фон, скруглённые углы. ФИО — крупный шрифт,
|
||||||
|
должности — мелкий. Металлическая рамка.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Оборотная сторона */}
|
||||||
|
<div>
|
||||||
|
<div
|
||||||
|
className="rounded-xl overflow-hidden border mb-4"
|
||||||
|
style={{ borderColor: "var(--bb-border)" }}
|
||||||
|
>
|
||||||
|
<Image
|
||||||
|
src="/offline/badges/badge-1.jpeg"
|
||||||
|
alt="Оборотная сторона бейджа с магнитным креплением"
|
||||||
|
width={657}
|
||||||
|
height={369}
|
||||||
|
className="w-full object-cover"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<p className="font-medium text-sm mb-1" style={{ color: "var(--bb-text)" }}>
|
||||||
|
Оборотная сторона
|
||||||
|
</p>
|
||||||
|
<p className="text-sm" style={{ color: "var(--bb-text-muted)" }}>
|
||||||
|
Чёрный пластик, магнитное крепление (CAUTION MAGNETIC).
|
||||||
|
Не требует проколов в одежде.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Section>
|
||||||
|
|
||||||
|
{/* Технические параметры */}
|
||||||
<Section
|
<Section
|
||||||
title="Технические параметры"
|
title="Технические параметры"
|
||||||
subtitle="Единый стандарт для всех сотрудников клиники."
|
subtitle="Единый стандарт для всех сотрудников клиники."
|
||||||
>
|
>
|
||||||
<div
|
<div className="grid grid-cols-2 gap-4 sm:grid-cols-4 mb-6">
|
||||||
className="grid grid-cols-2 gap-4 sm:grid-cols-4 mb-6"
|
|
||||||
>
|
|
||||||
{[
|
{[
|
||||||
{ label: "Ширина", value: "70 мм" },
|
{ label: "Ширина", value: "70 мм" },
|
||||||
{ label: "Высота", value: "30 мм" },
|
{ label: "Высота", value: "30 мм" },
|
||||||
{ label: "Материал", value: "ПВХ / металл" },
|
{ label: "Материал", value: "Металл / ПВХ" },
|
||||||
{ label: "Крепление", value: "Булавка / клипса" },
|
{ label: "Крепление", value: "Магнитное" },
|
||||||
].map(({ label, value }) => (
|
].map(({ label, value }) => (
|
||||||
<div
|
<div
|
||||||
key={label}
|
key={label}
|
||||||
@@ -155,29 +134,10 @@ export default function BadgesPage() {
|
|||||||
</div>
|
</div>
|
||||||
</Section>
|
</Section>
|
||||||
|
|
||||||
{/* Варианты */}
|
|
||||||
<Section
|
|
||||||
title="Варианты бейджей"
|
|
||||||
subtitle="Макет бейджа (масштаб: 4× от реального размера 70×30 мм)."
|
|
||||||
>
|
|
||||||
<div className="flex flex-wrap gap-8 items-start">
|
|
||||||
<BadgeMockup
|
|
||||||
variant="light"
|
|
||||||
name="Иванова А.В."
|
|
||||||
role="Врач-оториноларинголог"
|
|
||||||
/>
|
|
||||||
<BadgeMockup
|
|
||||||
variant="dark"
|
|
||||||
name="Петров К.С."
|
|
||||||
role="Главный врач"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</Section>
|
|
||||||
|
|
||||||
{/* Состав текста */}
|
{/* Состав текста */}
|
||||||
<Section
|
<Section
|
||||||
title="Состав текста на бейдже"
|
title="Состав текста на бейдже"
|
||||||
subtitle="Строгий порядок элементов. Шрифт — DINPro."
|
subtitle="Строгий порядок элементов."
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="overflow-hidden rounded-xl border"
|
className="overflow-hidden rounded-xl border"
|
||||||
@@ -186,7 +146,7 @@ export default function BadgesPage() {
|
|||||||
<table className="w-full text-sm">
|
<table className="w-full text-sm">
|
||||||
<thead>
|
<thead>
|
||||||
<tr style={{ background: "var(--bb-sidebar-bg)" }}>
|
<tr style={{ background: "var(--bb-sidebar-bg)" }}>
|
||||||
{["Элемент", "Содержание", "Шрифт / Размер", "Позиция"].map(h => (
|
{["Элемент", "Содержание", "Оформление"].map(h => (
|
||||||
<th
|
<th
|
||||||
key={h}
|
key={h}
|
||||||
className="text-left px-5 py-3 font-medium"
|
className="text-left px-5 py-3 font-medium"
|
||||||
@@ -199,11 +159,10 @@ export default function BadgesPage() {
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{[
|
{[
|
||||||
["Логотип", "Логотип клиники", "PNG / SVG", "Левая часть, по центру по высоте"],
|
["ФИО", "Фамилия Имя Отчество", "Крупный шрифт, первая строка"],
|
||||||
["Разделитель", "Вертикальная линия", "1px, 40% прозрачность", "Между логотипом и текстом"],
|
["Должность", "Основная должность", "Мелкий шрифт, вторая строка"],
|
||||||
["ФИО", "Фамилия И.О.", "DINPro Bold 13px", "Правая часть, верхняя строка"],
|
["Специализация", "Специализация / учёная степень (если есть)", "Мелкий шрифт, третья строка"],
|
||||||
["Должность", "Полное название должности", "DINPro Regular 10px", "Правая часть, нижняя строка"],
|
].map(([el, content, style]) => (
|
||||||
].map(([el, content, font, pos]) => (
|
|
||||||
<tr
|
<tr
|
||||||
key={el}
|
key={el}
|
||||||
className="border-t"
|
className="border-t"
|
||||||
@@ -211,60 +170,33 @@ export default function BadgesPage() {
|
|||||||
>
|
>
|
||||||
<td className="px-5 py-3 font-medium" style={{ color: "var(--bb-text)" }}>{el}</td>
|
<td className="px-5 py-3 font-medium" style={{ color: "var(--bb-text)" }}>{el}</td>
|
||||||
<td className="px-5 py-3" style={{ color: "var(--bb-text-muted)" }}>{content}</td>
|
<td className="px-5 py-3" style={{ color: "var(--bb-text-muted)" }}>{content}</td>
|
||||||
<td className="px-5 py-3 font-mono text-xs" style={{ color: "var(--bb-text-muted)" }}>{font}</td>
|
<td className="px-5 py-3" style={{ color: "var(--bb-text-muted)" }}>{style}</td>
|
||||||
<td className="px-5 py-3" style={{ color: "var(--bb-text-muted)" }}>{pos}</td>
|
|
||||||
</tr>
|
</tr>
|
||||||
))}
|
))}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</Section>
|
|
||||||
|
|
||||||
{/* Цветовые варианты */}
|
{/* Пример из фото */}
|
||||||
<Section
|
<div
|
||||||
title="Применение вариантов"
|
className="mt-4 rounded-xl border p-4 flex items-start gap-3"
|
||||||
subtitle="Выбор варианта зависит от должности сотрудника."
|
style={{ borderColor: "var(--bb-border)", background: "var(--bb-sidebar-bg)" }}
|
||||||
>
|
>
|
||||||
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2">
|
<div
|
||||||
{[
|
className="w-1.5 self-stretch rounded-full shrink-0"
|
||||||
{
|
style={{ background: "var(--brand-053m)" }}
|
||||||
variant: "Светлый (бежевый)",
|
/>
|
||||||
color: "#c4a882",
|
<div>
|
||||||
usage: "Медицинский персонал, санитарки, технический персонал",
|
<p className="text-xs font-medium mb-1" style={{ color: "var(--bb-text-muted)" }}>
|
||||||
oracal: "081M",
|
Пример из брендбука
|
||||||
},
|
</p>
|
||||||
{
|
<p className="text-sm font-semibold" style={{ color: "var(--bb-text)" }}>
|
||||||
variant: "Тёмный (серо-голубой)",
|
Лебединская Елена Александровна
|
||||||
color: "#5b7b87",
|
</p>
|
||||||
usage: "Административный персонал, менеджеры, главный врач",
|
<p className="text-xs mt-0.5" style={{ color: "var(--bb-text-muted)" }}>
|
||||||
oracal: "073M",
|
врач оториноларинголог · ведущий хирург · кандидат медицинских наук
|
||||||
},
|
</p>
|
||||||
].map(item => (
|
</div>
|
||||||
<div
|
|
||||||
key={item.variant}
|
|
||||||
className="flex gap-4 p-4 rounded-xl border"
|
|
||||||
style={{ borderColor: "var(--bb-border)" }}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className="w-8 h-8 rounded-lg shrink-0 mt-0.5"
|
|
||||||
style={{ background: item.color }}
|
|
||||||
/>
|
|
||||||
<div>
|
|
||||||
<p className="font-medium text-sm mb-1" style={{ color: "var(--bb-text)" }}>
|
|
||||||
{item.variant}
|
|
||||||
</p>
|
|
||||||
<p className="text-xs mb-1.5" style={{ color: "var(--bb-text-muted)" }}>
|
|
||||||
{item.usage}
|
|
||||||
</p>
|
|
||||||
<span
|
|
||||||
className="text-[10px] font-mono px-1.5 py-0.5 rounded"
|
|
||||||
style={{ background: "#f3f4f6", color: "#374151" }}
|
|
||||||
>
|
|
||||||
Oracal {item.oracal}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
</div>
|
||||||
</Section>
|
</Section>
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import type { Metadata } from "next";
|
import type { Metadata } from "next";
|
||||||
|
import Image from "next/image";
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: "Внутренняя навигация | Брендбук О!Клиника",
|
title: "Внутренняя навигация. Цифровой брендбук Клиники ухо, горло, нос им. проф. Е.Н.Оленевой",
|
||||||
};
|
};
|
||||||
|
|
||||||
function Section({
|
function Section({
|
||||||
@@ -30,74 +31,6 @@ function Section({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Макет настенной таблички */
|
|
||||||
function SignMockup({
|
|
||||||
type,
|
|
||||||
text,
|
|
||||||
subtext,
|
|
||||||
bgColor,
|
|
||||||
textColor,
|
|
||||||
accentColor,
|
|
||||||
size,
|
|
||||||
}: {
|
|
||||||
type: string;
|
|
||||||
text: string;
|
|
||||||
subtext?: string;
|
|
||||||
bgColor: string;
|
|
||||||
textColor: string;
|
|
||||||
accentColor: string;
|
|
||||||
size: string;
|
|
||||||
}) {
|
|
||||||
return (
|
|
||||||
<div className="flex flex-col items-start gap-2">
|
|
||||||
<div
|
|
||||||
className="rounded-lg px-6 py-4 flex items-center gap-4"
|
|
||||||
style={{
|
|
||||||
background: bgColor,
|
|
||||||
width: 260,
|
|
||||||
border: bgColor === "#ffffff" ? "1px solid #e5e7eb" : "none",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{/* Цветовая полоса */}
|
|
||||||
<div
|
|
||||||
className="w-1.5 self-stretch rounded-full"
|
|
||||||
style={{ background: accentColor, minHeight: 32 }}
|
|
||||||
/>
|
|
||||||
<div>
|
|
||||||
<p
|
|
||||||
style={{
|
|
||||||
fontFamily: "'DINPro', Arial, sans-serif",
|
|
||||||
fontSize: 14,
|
|
||||||
fontWeight: 700,
|
|
||||||
color: textColor,
|
|
||||||
lineHeight: 1.3,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{text}
|
|
||||||
</p>
|
|
||||||
{subtext && (
|
|
||||||
<p
|
|
||||||
style={{
|
|
||||||
fontFamily: "'DINPro', Arial, sans-serif",
|
|
||||||
fontSize: 10,
|
|
||||||
color: textColor,
|
|
||||||
opacity: 0.65,
|
|
||||||
marginTop: 3,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{subtext}
|
|
||||||
</p>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="pl-1">
|
|
||||||
<p className="text-xs font-medium" style={{ color: "var(--bb-text)" }}>{type}</p>
|
|
||||||
<p className="text-xs" style={{ color: "var(--bb-text-muted)" }}>{size}</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function NavigationPage() {
|
export default function NavigationPage() {
|
||||||
return (
|
return (
|
||||||
<div className="max-w-4xl mx-auto px-8 py-10">
|
<div className="max-w-4xl mx-auto px-8 py-10">
|
||||||
@@ -115,52 +48,111 @@ export default function NavigationPage() {
|
|||||||
</h1>
|
</h1>
|
||||||
<p className="text-base max-w-2xl" style={{ color: "var(--bb-text-muted)" }}>
|
<p className="text-base max-w-2xl" style={{ color: "var(--bb-text-muted)" }}>
|
||||||
Система навигационных табличек и указателей внутри клиники.
|
Система навигационных табличек и указателей внутри клиники.
|
||||||
Единый стиль с фирменными цветами и шрифтом DINPro.
|
На оргстекле, наклейки из плёнок Оракл 053M и 073M.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Шаблоны табличек */}
|
{/* Макеты таблечек */}
|
||||||
<Section
|
<Section
|
||||||
title="Типы табличек"
|
title="Макеты навигационных табличек"
|
||||||
subtitle="Четыре базовых шаблона для разных зон клиники."
|
subtitle="Два типа: табличка кабинета с бирюзовым заголовком и карточка врача с логотипом и QR-кодом."
|
||||||
>
|
>
|
||||||
<div className="flex flex-wrap gap-6">
|
<div className="max-w-lg">
|
||||||
<SignMockup
|
<div
|
||||||
type="Кабинет врача"
|
className="rounded-xl overflow-hidden border mb-4"
|
||||||
text="Кабинет № 101"
|
style={{ borderColor: "var(--bb-border)" }}
|
||||||
subtext="Оториноларингология"
|
>
|
||||||
bgColor="#ffffff"
|
<Image
|
||||||
textColor="#1b4c72"
|
src="/offline/navigation/nav-mockup-signs.jpeg"
|
||||||
accentColor="#7ecfca"
|
alt="Макеты навигационных табличек: Кабинет 04 с бирюзовым заголовком и карточка врача Лебединской"
|
||||||
size="200 × 80 мм"
|
width={620}
|
||||||
/>
|
height={570}
|
||||||
<SignMockup
|
className="w-full object-cover"
|
||||||
type="Направляющий указатель"
|
/>
|
||||||
text="→ Регистратура"
|
</div>
|
||||||
subtext="2-й этаж"
|
<p className="font-medium text-sm mb-1" style={{ color: "var(--bb-text)" }}>
|
||||||
bgColor="#5b7b87"
|
Макет из брендбука
|
||||||
textColor="#ffffff"
|
</p>
|
||||||
accentColor="#7ecfca"
|
<p className="text-sm" style={{ color: "var(--bb-text-muted)" }}>
|
||||||
size="300 × 80 мм"
|
Табличка «Кабинет 04»: бирюзовый заголовок (Oracal 053M), специализация и ФИО врачей.
|
||||||
/>
|
Карточка врача: логотип клиники, имя, должности, QR-код на страницу врача.
|
||||||
<SignMockup
|
</p>
|
||||||
type="Зона ожидания"
|
</div>
|
||||||
text="Зона ожидания"
|
</Section>
|
||||||
subtext="Пожалуйста, соблюдайте тишину"
|
|
||||||
bgColor="#e0f5f4"
|
{/* Нумерация дверей */}
|
||||||
textColor="#1b4c72"
|
<Section
|
||||||
accentColor="#5bb5ad"
|
title="Нумерация кабинетов на дверях"
|
||||||
size="250 × 80 мм"
|
subtitle="Номер кабинета размещается непосредственно на двери — крупный шрифт, плёнка Oracal."
|
||||||
/>
|
>
|
||||||
<SignMockup
|
<div className="grid grid-cols-1 gap-6 sm:grid-cols-2">
|
||||||
type="Запрещающий"
|
<div>
|
||||||
text="Вход только для персонала"
|
<div
|
||||||
bgColor="#1b4c72"
|
className="rounded-xl overflow-hidden border mb-4"
|
||||||
textColor="#ffffff"
|
style={{ borderColor: "var(--bb-border)" }}
|
||||||
accentColor="#c4a882"
|
>
|
||||||
size="250 × 60 мм"
|
<Image
|
||||||
|
src="/offline/navigation/nav-door-31.png"
|
||||||
|
alt="Белая дверь кабинета 31 с крупным номером из плёнки"
|
||||||
|
width={770}
|
||||||
|
height={963}
|
||||||
|
className="w-full object-cover"
|
||||||
|
style={{ maxHeight: 420, objectPosition: "top" }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<p className="font-medium text-sm mb-1" style={{ color: "var(--bb-text)" }}>
|
||||||
|
Кабинет 31 — белая дверь
|
||||||
|
</p>
|
||||||
|
<p className="text-sm" style={{ color: "var(--bb-text-muted)" }}>
|
||||||
|
Крупный номер в верхней части двери. Тёмная плёнка на белом фоне.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<div
|
||||||
|
className="rounded-xl overflow-hidden border mb-4"
|
||||||
|
style={{ borderColor: "var(--bb-border)" }}
|
||||||
|
>
|
||||||
|
<Image
|
||||||
|
src="/offline/navigation/nav-3.jpeg"
|
||||||
|
alt="Серая дверь кабинета 13 с крупным номером"
|
||||||
|
width={800}
|
||||||
|
height={463}
|
||||||
|
className="w-full object-cover"
|
||||||
|
style={{ maxHeight: 420, objectPosition: "left" }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<p className="font-medium text-sm mb-1" style={{ color: "var(--bb-text)" }}>
|
||||||
|
Кабинет 13 — серая дверь
|
||||||
|
</p>
|
||||||
|
<p className="text-sm" style={{ color: "var(--bb-text-muted)" }}>
|
||||||
|
Тёмная дверь с крупным номером. Рядом — табличка кабинета на стене.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Section>
|
||||||
|
|
||||||
|
{/* Указатели по этажам */}
|
||||||
|
<Section
|
||||||
|
title="Указатели по этажам"
|
||||||
|
subtitle="Навигационные панели в холлах — показывают расположение кабинетов и специализации на каждом этаже."
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="rounded-xl overflow-hidden border"
|
||||||
|
style={{ borderColor: "var(--bb-border)" }}
|
||||||
|
>
|
||||||
|
<Image
|
||||||
|
src="/offline/navigation/nav-render-p13.jpeg"
|
||||||
|
alt="Навигационные панели по этажам: кабинеты 01-06, 21-25, 31-37, 41-45"
|
||||||
|
width={2105}
|
||||||
|
height={1489}
|
||||||
|
className="w-full"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<p className="mt-3 text-sm" style={{ color: "var(--bb-text-muted)" }}>
|
||||||
|
Слева — указатель с этажом и направлением, справа — панель с полным перечнем кабинетов.
|
||||||
|
Активный этаж выделяется бирюзовым фоном (Oracal 053M).
|
||||||
|
</p>
|
||||||
</Section>
|
</Section>
|
||||||
|
|
||||||
{/* Технические требования */}
|
{/* Технические требования */}
|
||||||
@@ -188,12 +180,10 @@ export default function NavigationPage() {
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{[
|
{[
|
||||||
["Основной материал", "ПВХ 3мм / ПС зеркальный / акрил"],
|
["Основной материал", "Оргстекло"],
|
||||||
["Покрытие фона", "Oracal плёнка (053M / 073M / 050M)"],
|
["Покрытие", "Наклейка из плёнок Oracal"],
|
||||||
["Шрифт", "DINPro Bold / Regular (DXF для фрезеровки)"],
|
["Шрифт", "DINPro Bold / Regular"],
|
||||||
["Крепление", "Двусторонний скотч / шурупы с дистанционным держателем"],
|
["Крепление", "Дистанционные держатели"],
|
||||||
["Толщина букв (фрезеровка)", "3 мм от основы"],
|
|
||||||
["Минимальный размер текста", "10 мм по высоте"],
|
|
||||||
].map(([param, value]) => (
|
].map(([param, value]) => (
|
||||||
<tr
|
<tr
|
||||||
key={param}
|
key={param}
|
||||||
@@ -218,24 +208,25 @@ export default function NavigationPage() {
|
|||||||
title="Цвета Oracal для навигации"
|
title="Цвета Oracal для навигации"
|
||||||
subtitle="Допустимые цвета плёнки по коду Oracal."
|
subtitle="Допустимые цвета плёнки по коду Oracal."
|
||||||
>
|
>
|
||||||
<div className="grid grid-cols-2 gap-4 sm:grid-cols-4">
|
<div className="flex gap-6">
|
||||||
{[
|
{[
|
||||||
{ code: "053M", hex: "#7ecfca", name: "Акцент / полоса" },
|
{ code: "053M", hex: "#7ecfca", name: "Заголовок таблички / активный этаж" },
|
||||||
{ code: "073M", hex: "#5b7b87", name: "Фон указателей" },
|
{ code: "073M", hex: "#5b7b87", name: "Дополнительный акцент" },
|
||||||
{ code: "050M", hex: "#1b4c72", name: "Фон запрещающих" },
|
|
||||||
{ code: "081M", hex: "#c4a882", name: "Акцент на тёмном" },
|
|
||||||
].map(c => (
|
].map(c => (
|
||||||
<div
|
<div
|
||||||
key={c.code}
|
key={c.code}
|
||||||
className="rounded-xl overflow-hidden border"
|
className="flex items-center gap-4 rounded-xl border p-4"
|
||||||
style={{ borderColor: "var(--bb-border)" }}
|
style={{ borderColor: "var(--bb-border)", background: "var(--bb-sidebar-bg)" }}
|
||||||
>
|
>
|
||||||
<div className="h-16" style={{ background: c.hex }} />
|
<div
|
||||||
<div className="p-3">
|
className="w-12 h-12 rounded-lg shrink-0"
|
||||||
<p className="font-medium text-xs" style={{ color: "var(--bb-text)" }}>
|
style={{ background: c.hex }}
|
||||||
|
/>
|
||||||
|
<div>
|
||||||
|
<p className="font-medium text-sm" style={{ color: "var(--bb-text)" }}>
|
||||||
Oracal {c.code}
|
Oracal {c.code}
|
||||||
</p>
|
</p>
|
||||||
<p className="text-xs" style={{ color: "var(--bb-text-muted)" }}>
|
<p className="text-xs mt-0.5" style={{ color: "var(--bb-text-muted)" }}>
|
||||||
{c.name}
|
{c.name}
|
||||||
</p>
|
</p>
|
||||||
<p className="font-mono text-xs mt-1" style={{ color: "var(--bb-text-muted)" }}>
|
<p className="font-mono text-xs mt-1" style={{ color: "var(--bb-text-muted)" }}>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import type { Metadata } from "next";
|
|||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: "Печатные материалы | Брендбук О!Клиника",
|
title: "Печатные материалы. Цифровой брендбук Клиники ухо, горло, нос им. проф. Е.Н.Оленевой",
|
||||||
};
|
};
|
||||||
|
|
||||||
function Section({
|
function Section({
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import type { Metadata } from "next";
|
|||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: "Брендирование транспорта | Брендбук О!Клиника",
|
title: "Брендирование транспорта. Цифровой брендбук Клиники ухо, горло, нос им. проф. Е.Н.Оленевой",
|
||||||
};
|
};
|
||||||
|
|
||||||
function Section({
|
function Section({
|
||||||
@@ -31,101 +31,6 @@ function Section({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Макет трамвая (упрощённый силуэт) */
|
|
||||||
function TramMockup() {
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className="relative rounded-2xl overflow-hidden"
|
|
||||||
style={{
|
|
||||||
background: "#f8f9fa",
|
|
||||||
border: "1px solid var(--bb-border)",
|
|
||||||
padding: "32px 24px",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{/* Кузов трамвая */}
|
|
||||||
<div
|
|
||||||
className="relative mx-auto rounded-xl overflow-hidden"
|
|
||||||
style={{
|
|
||||||
width: "100%",
|
|
||||||
maxWidth: 560,
|
|
||||||
height: 160,
|
|
||||||
background: "#ffffff",
|
|
||||||
border: "2px solid #e5e7eb",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{/* Верхняя полоса — бирюзовая */}
|
|
||||||
<div
|
|
||||||
className="absolute top-0 left-0 right-0"
|
|
||||||
style={{ height: 28, background: "#7ecfca" }}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{/* Основная бежевая полоса */}
|
|
||||||
<div
|
|
||||||
className="absolute left-0 right-0"
|
|
||||||
style={{ top: 28, height: 76, background: "#c4a882" }}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{/* Нижняя полоса — серо-голубая */}
|
|
||||||
<div
|
|
||||||
className="absolute left-0 right-0"
|
|
||||||
style={{ top: 104, height: 56, background: "#5b7b87" }}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{/* Логотип по центру бежевой полосы */}
|
|
||||||
<div
|
|
||||||
className="absolute flex items-center justify-center"
|
|
||||||
style={{ top: 28, left: 0, right: 0, height: 76 }}
|
|
||||||
>
|
|
||||||
<Image
|
|
||||||
src="/logo/logo-transparent.png"
|
|
||||||
alt="Логотип на трамвае"
|
|
||||||
width={180}
|
|
||||||
height={64}
|
|
||||||
className="object-contain"
|
|
||||||
style={{
|
|
||||||
filter: "brightness(0) sepia(1) saturate(2) hue-rotate(330deg) brightness(0.45)",
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Окна (декоративные) */}
|
|
||||||
{[80, 180, 280, 380, 460].map(x => (
|
|
||||||
<div
|
|
||||||
key={x}
|
|
||||||
className="absolute rounded"
|
|
||||||
style={{
|
|
||||||
left: x,
|
|
||||||
top: 40,
|
|
||||||
width: 50,
|
|
||||||
height: 44,
|
|
||||||
background: "rgba(255,255,255,0.6)",
|
|
||||||
border: "1px solid rgba(255,255,255,0.8)",
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
|
|
||||||
{/* Колёса (декоративные) */}
|
|
||||||
{[60, 200, 360, 500].map(x => (
|
|
||||||
<div
|
|
||||||
key={x}
|
|
||||||
className="absolute rounded-full"
|
|
||||||
style={{
|
|
||||||
left: x,
|
|
||||||
bottom: -8,
|
|
||||||
width: 24,
|
|
||||||
height: 24,
|
|
||||||
background: "#374151",
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<p className="mt-4 text-center text-xs" style={{ color: "var(--bb-text-muted)" }}>
|
|
||||||
Схема цветового решения (превью, не финальный макет)
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function TransportPage() {
|
export default function TransportPage() {
|
||||||
return (
|
return (
|
||||||
@@ -151,9 +56,20 @@ export default function TransportPage() {
|
|||||||
{/* Макет */}
|
{/* Макет */}
|
||||||
<Section
|
<Section
|
||||||
title="Макет трамвая"
|
title="Макет трамвая"
|
||||||
subtitle="Трёхполосная схема брендирования: верхняя бирюзовая, центральная бежевая с логотипом, нижняя серо-голубая."
|
subtitle="Вид с обеих сторон: бирюзовая полоса, логотип клиники, фотографии пациентов и врачей, контактная информация."
|
||||||
>
|
>
|
||||||
<TramMockup />
|
<div
|
||||||
|
className="rounded-xl overflow-hidden border"
|
||||||
|
style={{ borderColor: "var(--bb-border)" }}
|
||||||
|
>
|
||||||
|
<Image
|
||||||
|
src="/offline/transport/tram-mockup.jpeg"
|
||||||
|
alt="Макет брендирования трамвая: вид спереди и сзади с логотипом Клиники ухо горло нос им. проф. Е.Н.Оленевой"
|
||||||
|
width={1884}
|
||||||
|
height={977}
|
||||||
|
className="w-full"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</Section>
|
</Section>
|
||||||
|
|
||||||
{/* Цветовая схема */}
|
{/* Цветовая схема */}
|
||||||
|
|||||||
@@ -47,92 +47,113 @@ export default function UniformPage() {
|
|||||||
Форма сотрудников
|
Форма сотрудников
|
||||||
</h1>
|
</h1>
|
||||||
<p className="text-base max-w-2xl" style={{ color: "var(--bb-text-muted)" }}>
|
<p className="text-base max-w-2xl" style={{ color: "var(--bb-text-muted)" }}>
|
||||||
Фирменная медицинская одежда сотрудников клиники. Бежевый костюм
|
Фирменная медицинская одежда сотрудников клиники. Два цветовых варианта:
|
||||||
с логотипом клиники на левой стороне груди.
|
бежевый с коричневым логотипом и синий с белым логотипом.
|
||||||
|
Логотип размещается на левой стороне груди.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Описание костюма */}
|
{/* Фотографии вариантов */}
|
||||||
<Section
|
<Section
|
||||||
title="Описание комплекта"
|
title="Варианты формы"
|
||||||
subtitle="Стандартная форма для всех сотрудников клиники."
|
subtitle="Фотографии реальной формы сотрудников с логотипом клиники."
|
||||||
>
|
>
|
||||||
<div
|
<div className="grid grid-cols-1 gap-6 sm:grid-cols-2">
|
||||||
className="rounded-xl border p-6"
|
{/* Бежевый вариант */}
|
||||||
style={{ borderColor: "var(--bb-border)", background: "var(--bb-sidebar-bg)" }}
|
<div>
|
||||||
>
|
<div
|
||||||
<div className="grid grid-cols-1 gap-6 sm:grid-cols-2">
|
className="rounded-xl overflow-hidden border mb-4"
|
||||||
<div>
|
style={{ borderColor: "var(--bb-border)" }}
|
||||||
<p className="font-medium text-sm mb-3" style={{ color: "var(--bb-text)" }}>
|
>
|
||||||
Состав формы
|
<Image
|
||||||
</p>
|
src="/offline/uniform/uniform-1.jpeg"
|
||||||
<ul className="space-y-2">
|
alt="Бежевая форма сотрудника клиники с коричневым логотипом"
|
||||||
{["Медицинский костюм (куртка + брюки)", "Цвет: бежевый (Oracal 081M)", "Материал: медицинская ткань", "Логотип вышит или нанесён термопечатью"].map(item => (
|
width={742}
|
||||||
<li key={item} className="flex items-start gap-2 text-sm" style={{ color: "var(--bb-text-muted)" }}>
|
height={990}
|
||||||
<span style={{ color: "var(--brand-053m)" }}>•</span> {item}
|
className="w-full object-cover"
|
||||||
</li>
|
style={{ maxHeight: 480, objectPosition: "top" }}
|
||||||
))}
|
/>
|
||||||
</ul>
|
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<p className="font-medium text-sm mb-1" style={{ color: "var(--bb-text)" }}>
|
||||||
<p className="font-medium text-sm mb-3" style={{ color: "var(--bb-text)" }}>
|
Бежевый вариант
|
||||||
Цветовая схема
|
</p>
|
||||||
</p>
|
<p className="text-sm mb-3" style={{ color: "var(--bb-text-muted)" }}>
|
||||||
<div className="flex gap-3">
|
Основная форма для медицинского персонала. Логотип — тёмно-коричневый.
|
||||||
<div className="text-center">
|
</p>
|
||||||
<div className="w-12 h-12 rounded-lg border mb-1"
|
<div className="flex gap-2">
|
||||||
style={{ background: "#c4a882", borderColor: "var(--bb-border)" }} />
|
<div className="flex items-center gap-1.5">
|
||||||
<p className="text-xs" style={{ color: "var(--bb-text-muted)" }}>081M</p>
|
<div
|
||||||
<p className="text-xs font-mono" style={{ color: "var(--bb-text-muted)" }}>#c4a882</p>
|
className="w-4 h-4 rounded"
|
||||||
</div>
|
style={{ background: "#c4a882", border: "1px solid #e5e7eb" }}
|
||||||
<div className="text-center">
|
/>
|
||||||
<div className="w-12 h-12 rounded-lg border mb-1"
|
<span className="text-xs font-mono" style={{ color: "var(--bb-text-muted)" }}>
|
||||||
style={{ background: "#5c2e0e", borderColor: "var(--bb-border)" }} />
|
Oracal 081M
|
||||||
<p className="text-xs" style={{ color: "var(--bb-text-muted)" }}>080M</p>
|
</span>
|
||||||
<p className="text-xs font-mono" style={{ color: "var(--bb-text-muted)" }}>#5c2e0e</p>
|
</div>
|
||||||
</div>
|
<span style={{ color: "var(--bb-text-muted)" }}>·</span>
|
||||||
|
<div className="flex items-center gap-1.5">
|
||||||
|
<div
|
||||||
|
className="w-4 h-4 rounded"
|
||||||
|
style={{ background: "#5c2e0e", border: "1px solid #e5e7eb" }}
|
||||||
|
/>
|
||||||
|
<span className="text-xs font-mono" style={{ color: "var(--bb-text-muted)" }}>
|
||||||
|
Логотип 080M
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Синий вариант */}
|
||||||
|
<div>
|
||||||
|
<div
|
||||||
|
className="rounded-xl overflow-hidden border mb-4"
|
||||||
|
style={{ borderColor: "var(--bb-border)" }}
|
||||||
|
>
|
||||||
|
<Image
|
||||||
|
src="/offline/uniform/uniform-2.jpeg"
|
||||||
|
alt="Синяя форма сотрудника клиники с белым логотипом"
|
||||||
|
width={580}
|
||||||
|
height={773}
|
||||||
|
className="w-full object-cover"
|
||||||
|
style={{ maxHeight: 480, objectPosition: "top" }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<p className="font-medium text-sm mb-1" style={{ color: "var(--bb-text)" }}>
|
||||||
|
Синий вариант
|
||||||
|
</p>
|
||||||
|
<p className="text-sm mb-3" style={{ color: "var(--bb-text-muted)" }}>
|
||||||
|
Альтернативный вариант. Логотип — белый инвертированный.
|
||||||
|
</p>
|
||||||
|
<div className="flex gap-2">
|
||||||
|
<div className="flex items-center gap-1.5">
|
||||||
|
<div
|
||||||
|
className="w-4 h-4 rounded"
|
||||||
|
style={{ background: "#4a90c4", border: "1px solid #e5e7eb" }}
|
||||||
|
/>
|
||||||
|
<span className="text-xs font-mono" style={{ color: "var(--bb-text-muted)" }}>
|
||||||
|
Синий медицинский
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<span style={{ color: "var(--bb-text-muted)" }}>·</span>
|
||||||
|
<div className="flex items-center gap-1.5">
|
||||||
|
<div
|
||||||
|
className="w-4 h-4 rounded"
|
||||||
|
style={{ background: "#ffffff", border: "1px solid #e5e7eb" }}
|
||||||
|
/>
|
||||||
|
<span className="text-xs font-mono" style={{ color: "var(--bb-text-muted)" }}>
|
||||||
|
Логотип белый
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Section>
|
</Section>
|
||||||
|
|
||||||
{/* Логотип на форме */}
|
{/* Размеры логотипа */}
|
||||||
<Section
|
<Section
|
||||||
title="Размещение логотипа"
|
title="Размеры логотипа для размещения на форме сотрудников"
|
||||||
subtitle="Логотип располагается на левой стороне груди. Размер зависит от размера одежды."
|
subtitle="Логотип располагается на левой стороне груди. Размер зависит от размера одежды."
|
||||||
>
|
>
|
||||||
{/* Визуализация размещения */}
|
|
||||||
<div
|
|
||||||
className="rounded-xl border p-8 mb-6 flex flex-col items-center justify-center"
|
|
||||||
style={{ background: "#c4a882", borderColor: "transparent", minHeight: 200 }}
|
|
||||||
>
|
|
||||||
<div className="relative w-64 h-48 flex items-center justify-center">
|
|
||||||
{/* Силуэт куртки (упрощённая схема) */}
|
|
||||||
<div className="absolute inset-0 rounded-xl opacity-20"
|
|
||||||
style={{ border: "2px dashed #5c2e0e" }} />
|
|
||||||
{/* Зона логотипа — левая грудь */}
|
|
||||||
<div className="absolute top-6 left-10 flex flex-col items-center gap-2">
|
|
||||||
<Image
|
|
||||||
src="/logo/logo-transparent.png"
|
|
||||||
alt="Логотип на форме"
|
|
||||||
width={100}
|
|
||||||
height={36}
|
|
||||||
className="object-contain"
|
|
||||||
style={{ filter: "brightness(0) sepia(1) saturate(2) hue-rotate(330deg) brightness(0.45)" }}
|
|
||||||
/>
|
|
||||||
<div className="border border-dashed rounded px-1"
|
|
||||||
style={{ borderColor: "#5c2e0e50" }}>
|
|
||||||
<p className="text-xs" style={{ color: "#5c2e0e80" }}>← Левая грудь</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<p className="mt-4 text-sm" style={{ color: "rgba(92,46,14,0.7)" }}>
|
|
||||||
Схема размещения логотипа (превью)
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Таблица размеров */}
|
|
||||||
<div
|
<div
|
||||||
className="overflow-hidden rounded-xl border"
|
className="overflow-hidden rounded-xl border"
|
||||||
style={{ borderColor: "var(--bb-border)" }}
|
style={{ borderColor: "var(--bb-border)" }}
|
||||||
@@ -178,7 +199,7 @@ export default function UniformPage() {
|
|||||||
{[
|
{[
|
||||||
{ ok: true, text: "Носить комплект в полном составе" },
|
{ ok: true, text: "Носить комплект в полном составе" },
|
||||||
{ ok: true, text: "Поддерживать чистоту и опрятность формы" },
|
{ ok: true, text: "Поддерживать чистоту и опрятность формы" },
|
||||||
{ ok: true, text: "Логотип — только тёмно-коричневый на бежевом" },
|
{ ok: true, text: "Логотип только в утверждённых цветовых вариантах" },
|
||||||
{ ok: false, text: "Носить форму без логотипа" },
|
{ ok: false, text: "Носить форму без логотипа" },
|
||||||
{ ok: false, text: "Изменять цвет или материал формы" },
|
{ ok: false, text: "Изменять цвет или материал формы" },
|
||||||
{ ok: false, text: "Добавлять сторонние нашивки и знаки" },
|
{ ok: false, text: "Добавлять сторонние нашивки и знаки" },
|
||||||
|
|||||||
@@ -68,7 +68,6 @@ const NAV: NavSection[] = [
|
|||||||
{ label: "Бейджи", href: "/offline/badges" },
|
{ label: "Бейджи", href: "/offline/badges" },
|
||||||
{ label: "Навигация", href: "/offline/navigation" },
|
{ label: "Навигация", href: "/offline/navigation" },
|
||||||
{ label: "Транспорт", href: "/offline/transport" },
|
{ label: "Транспорт", href: "/offline/transport" },
|
||||||
{ label: "Печать", href: "/offline/print" },
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,175 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { useState } from "react";
|
||||||
|
|
||||||
|
interface LlmBlockProps {
|
||||||
|
/** Путь страницы, например "/foundation/colors" */
|
||||||
|
path: string;
|
||||||
|
/** Версия данных, например "v2.1" */
|
||||||
|
version: string;
|
||||||
|
/** Плоский текст для копирования */
|
||||||
|
specText: string;
|
||||||
|
/** Содержимое блока — таблицы, правила */
|
||||||
|
children: React.ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* LlmBlock — переиспользуемый блок LLM-спецификации.
|
||||||
|
* Добавляется в конец каждой страницы брендбука, содержащей дизайн-стандарты.
|
||||||
|
* Требование: ФТ-03-LLM (TZ.md) · docs/LLM_CONTEXT.md
|
||||||
|
*/
|
||||||
|
export function LlmBlock({ path, version, specText, children }: LlmBlockProps) {
|
||||||
|
const [copied, setCopied] = useState(false);
|
||||||
|
|
||||||
|
function handleCopy(e: React.MouseEvent) {
|
||||||
|
e.preventDefault();
|
||||||
|
navigator.clipboard.writeText(specText);
|
||||||
|
setCopied(true);
|
||||||
|
setTimeout(() => setCopied(false), 2000);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<details
|
||||||
|
open
|
||||||
|
className="rounded-xl overflow-hidden"
|
||||||
|
style={{
|
||||||
|
border: "2px dashed var(--brand-053m)",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{/* Заголовок */}
|
||||||
|
<summary
|
||||||
|
className="flex items-center justify-between px-5 py-3 cursor-pointer select-none list-none"
|
||||||
|
style={{ background: "rgba(126,207,202,0.07)" }}
|
||||||
|
>
|
||||||
|
<div className="flex items-center gap-2 min-w-0">
|
||||||
|
<span
|
||||||
|
className="shrink-0 text-[10px] font-bold px-1.5 py-0.5 rounded tracking-wider"
|
||||||
|
style={{ background: "var(--brand-053m)", color: "#fff" }}
|
||||||
|
>
|
||||||
|
LLM
|
||||||
|
</span>
|
||||||
|
<span className="font-semibold text-sm" style={{ color: "var(--bb-text)" }}>
|
||||||
|
LLM-спецификация
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
className="text-xs truncate hidden sm:inline"
|
||||||
|
style={{ color: "var(--bb-text-muted)" }}
|
||||||
|
>
|
||||||
|
· машиночитаемые данные · docs/LLM_CONTEXT.md
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex items-center gap-3 shrink-0 ml-3">
|
||||||
|
<span
|
||||||
|
className="text-[10px] font-mono hidden md:inline"
|
||||||
|
style={{ color: "var(--bb-text-muted)" }}
|
||||||
|
>
|
||||||
|
{path} · {version}
|
||||||
|
</span>
|
||||||
|
<button
|
||||||
|
onClick={handleCopy}
|
||||||
|
className="text-xs px-3 py-1 rounded font-medium transition-colors shrink-0"
|
||||||
|
style={{
|
||||||
|
background: copied ? "#d1fae5" : "var(--brand-053m)",
|
||||||
|
color: copied ? "#065f46" : "#fff",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{copied ? "✓ Скопировано" : "Скопировать"}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</summary>
|
||||||
|
|
||||||
|
{/* Содержимое */}
|
||||||
|
<div
|
||||||
|
className="px-5 py-5 space-y-6 border-t"
|
||||||
|
style={{
|
||||||
|
borderColor: "var(--brand-053m)",
|
||||||
|
borderStyle: "dashed",
|
||||||
|
background: "var(--bb-content-bg)",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
</details>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ─── Утилиты для содержимого блока ──────────────────────────── */
|
||||||
|
|
||||||
|
/** Заголовок подсекции внутри LLM-блока */
|
||||||
|
export function LlmSection({ title }: { title: string }) {
|
||||||
|
return (
|
||||||
|
<p
|
||||||
|
className="text-[10px] font-semibold uppercase tracking-widest pb-1 border-b"
|
||||||
|
style={{ color: "var(--bb-text-muted)", borderColor: "var(--bb-border)" }}
|
||||||
|
>
|
||||||
|
{title}
|
||||||
|
</p>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Компактная таблица для LLM-блока */
|
||||||
|
export function LlmTable({
|
||||||
|
headers,
|
||||||
|
rows,
|
||||||
|
}: {
|
||||||
|
headers: string[];
|
||||||
|
rows: (string | React.ReactNode)[][];
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<div className="overflow-x-auto">
|
||||||
|
<table className="w-full text-xs border-collapse font-mono">
|
||||||
|
<thead>
|
||||||
|
<tr style={{ background: "var(--bb-sidebar-bg)" }}>
|
||||||
|
{headers.map((h) => (
|
||||||
|
<th
|
||||||
|
key={h}
|
||||||
|
className="text-left px-2 py-1.5 font-medium border whitespace-nowrap"
|
||||||
|
style={{ color: "var(--bb-text-muted)", borderColor: "var(--bb-border)" }}
|
||||||
|
>
|
||||||
|
{h}
|
||||||
|
</th>
|
||||||
|
))}
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{rows.map((row, ri) => (
|
||||||
|
<tr key={ri} style={{ borderTop: `1px solid var(--bb-border)` }}>
|
||||||
|
{row.map((cell, ci) => (
|
||||||
|
<td
|
||||||
|
key={ci}
|
||||||
|
className="px-2 py-1 border"
|
||||||
|
style={{
|
||||||
|
borderColor: "var(--bb-border)",
|
||||||
|
color: "var(--bb-text-muted)",
|
||||||
|
maxWidth: "240px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{cell}
|
||||||
|
</td>
|
||||||
|
))}
|
||||||
|
</tr>
|
||||||
|
))}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Список правил ✓ / ✕ */
|
||||||
|
export function LlmRules({ rules }: { rules: { ok: boolean; text: string }[] }) {
|
||||||
|
return (
|
||||||
|
<div className="grid grid-cols-1 sm:grid-cols-2 gap-x-8 gap-y-0.5">
|
||||||
|
{rules.map((r) => (
|
||||||
|
<div key={r.text} className="flex items-start gap-1.5 py-0.5 text-xs font-mono">
|
||||||
|
<span
|
||||||
|
style={{ color: r.ok ? "#059669" : "#dc2626", fontWeight: 700, flexShrink: 0 }}
|
||||||
|
>
|
||||||
|
{r.ok ? "✓" : "✕"}
|
||||||
|
</span>
|
||||||
|
<span style={{ color: "var(--bb-text-muted)" }}>{r.text}</span>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,10 +1,14 @@
|
|||||||
import type { NextConfig } from "next";
|
import type { NextConfig } from "next";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
|
|
||||||
|
const isDev = process.env.NODE_ENV === "development";
|
||||||
|
|
||||||
const nextConfig: NextConfig = {
|
const nextConfig: NextConfig = {
|
||||||
turbopack: {
|
...(isDev && {
|
||||||
root: path.resolve(__dirname, "../.."),
|
turbopack: {
|
||||||
},
|
root: path.resolve(__dirname, "../.."),
|
||||||
|
},
|
||||||
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
export default nextConfig;
|
export default nextConfig;
|
||||||
|
|||||||
|
After Width: | Height: | Size: 103 KiB |
|
After Width: | Height: | Size: 135 KiB |
|
After Width: | Height: | Size: 72 KiB |
|
After Width: | Height: | Size: 871 KiB |
|
After Width: | Height: | Size: 51 KiB |
|
After Width: | Height: | Size: 217 KiB |
|
After Width: | Height: | Size: 249 KiB |
|
After Width: | Height: | Size: 303 KiB |
|
After Width: | Height: | Size: 224 KiB |
|
After Width: | Height: | Size: 2.3 MiB |
@@ -0,0 +1,156 @@
|
|||||||
|
# Деплой — oclinica-brandbook
|
||||||
|
|
||||||
|
## Текущее состояние
|
||||||
|
|
||||||
|
| Сервис | Статус | URL | Платформа |
|
||||||
|
|------------|-------------|----------------------------------------|---------------|
|
||||||
|
| Фронтенд | ✅ Активен | https://web-oclinica.vercel.app | Vercel Hobby |
|
||||||
|
| Бэкенд | локально | http://localhost:3001 | Docker Compose |
|
||||||
|
| База данных | локально | localhost:5433 | PostgreSQL 16 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Фронтенд — Vercel
|
||||||
|
|
||||||
|
### Первоначальная настройка (уже выполнена)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. Установить Vercel CLI
|
||||||
|
npm install -g vercel
|
||||||
|
|
||||||
|
# 2. Войти в аккаунт (однократно, открывает браузер)
|
||||||
|
vercel login
|
||||||
|
|
||||||
|
# 3. Первый деплой из директории apps/web
|
||||||
|
cd apps/web
|
||||||
|
vercel --yes
|
||||||
|
```
|
||||||
|
|
||||||
|
### Деплой обновлений
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd apps/web
|
||||||
|
vercel --prod --yes
|
||||||
|
```
|
||||||
|
|
||||||
|
Деплой занимает ~30 секунд. После завершения изменения сразу доступны по адресу:
|
||||||
|
**https://web-oclinica.vercel.app**
|
||||||
|
|
||||||
|
### Как это работает
|
||||||
|
|
||||||
|
- Vercel автоматически определяет Next.js и использует pnpm для сборки
|
||||||
|
- Каждый `vercel --prod` создаёт новый immutable deployment и привязывает его к production URL
|
||||||
|
- Предыдущие деплои остаются доступны по уникальным preview URL
|
||||||
|
- Логи билда: https://vercel.com/oclinica/web
|
||||||
|
|
||||||
|
### Ограничения Vercel Hobby (бесплатный план)
|
||||||
|
|
||||||
|
| Параметр | Лимит |
|
||||||
|
|-----------------------|-------------------------|
|
||||||
|
| Bandwidth | 100 GB / месяц |
|
||||||
|
| Builds | 6000 минут / месяц |
|
||||||
|
| Serverless Functions | 100 GB-hours / месяц |
|
||||||
|
| Тип использования | Только некоммерческие |
|
||||||
|
|
||||||
|
Для брендбука (внутренний инструмент) лимитов более чем достаточно.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Локальная разработка
|
||||||
|
|
||||||
|
### Запуск фронтенда
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Из корня monorepo
|
||||||
|
pnpm dev
|
||||||
|
|
||||||
|
# Или только фронтенд
|
||||||
|
cd apps/web && pnpm dev
|
||||||
|
```
|
||||||
|
|
||||||
|
Доступен на: http://localhost:3001
|
||||||
|
|
||||||
|
### Запуск бэкенда + БД
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Запустить PostgreSQL
|
||||||
|
docker compose up -d
|
||||||
|
|
||||||
|
# Запустить NestJS
|
||||||
|
cd apps/api && pnpm dev
|
||||||
|
```
|
||||||
|
|
||||||
|
### .env файлы
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Скопировать и заполнить
|
||||||
|
cp .env.example .env
|
||||||
|
```
|
||||||
|
|
||||||
|
Содержимое `.env.example`:
|
||||||
|
```
|
||||||
|
DATABASE_URL="postgresql://brandbook:brandbook@localhost:5433/brandbook"
|
||||||
|
API_PORT=3001
|
||||||
|
NEXT_PUBLIC_API_URL=http://localhost:3001
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Автодеплой через Gitea Actions (планируется в Sprint 12)
|
||||||
|
|
||||||
|
Для автоматического деплоя при пуше в ветку `main` создать файл
|
||||||
|
`.gitea/workflows/deploy-frontend.yml`:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
name: Deploy Frontend to Vercel
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [main]
|
||||||
|
paths:
|
||||||
|
- 'apps/web/**'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
deploy:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup pnpm
|
||||||
|
uses: pnpm/action-setup@v4
|
||||||
|
with:
|
||||||
|
version: 10
|
||||||
|
|
||||||
|
- name: Setup Node.js
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: 20
|
||||||
|
cache: 'pnpm'
|
||||||
|
cache-dependency-path: apps/web/pnpm-lock.yaml
|
||||||
|
|
||||||
|
- name: Install Vercel CLI
|
||||||
|
run: npm install -g vercel
|
||||||
|
|
||||||
|
- name: Deploy to Vercel
|
||||||
|
run: cd apps/web && vercel --prod --yes --token ${{ secrets.VERCEL_TOKEN }}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Настройка:**
|
||||||
|
1. Получить Vercel Token: https://vercel.com/account/tokens
|
||||||
|
2. Добавить в Gitea: Settings → Secrets → `VERCEL_TOKEN`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Хостинг бэкенда (планируется к Sprint 11)
|
||||||
|
|
||||||
|
Бэкенд (NestJS + PostgreSQL) потребуется для экспериментальной секции (Sprint 11).
|
||||||
|
Варианты для рассмотрения:
|
||||||
|
|
||||||
|
| Платформа | PostgreSQL | Бесплатно | Карта |
|
||||||
|
|-----------|-----------|-----------|-------|
|
||||||
|
| Railway | ✅ | $5 кредит / месяц | нужна |
|
||||||
|
| Supabase | ✅ | ✅ (PostgreSQL managed) | нет |
|
||||||
|
| Fly.io | ✅ | ✅ ограниченно | нет |
|
||||||
|
| VPS клиники | ✅ | ✅ (если есть) | нет |
|
||||||
|
|
||||||
|
Рекомендация: **Supabase** для БД (бесплатно, managed PostgreSQL) + **Railway** или VPS для NestJS.
|
||||||
@@ -0,0 +1,376 @@
|
|||||||
|
# LLM Context — Цифровой брендбук Клиники
|
||||||
|
|
||||||
|
## Клиника ухо, горло, нос им. проф. Е.Н.Оленевой
|
||||||
|
|
||||||
|
**Версия контекста:** 2.1
|
||||||
|
**Дата обновления:** 2026-03-22
|
||||||
|
**Актуальный спринт:** Sprint 3
|
||||||
|
**Сайт клиники:** https://oclinica.ru
|
||||||
|
**Брендбук (локально):** http://localhost:3001
|
||||||
|
**Брендбук (production):** https://web-oclinica.vercel.app
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Назначение файла
|
||||||
|
|
||||||
|
Этот файл — единый источник дизайн-данных клиники в машиночитаемом формате.
|
||||||
|
Используется как контекст для LLM при:
|
||||||
|
- разработке страниц и компонентов сайта
|
||||||
|
- создании макетов и прототипов
|
||||||
|
- разработке мобильных приложений
|
||||||
|
- проектировании новых носителей бренда
|
||||||
|
- генерации CSS / Tailwind / Figma Tokens
|
||||||
|
|
||||||
|
При работе с любым материалом клиники **всегда загружай этот файл первым**.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. О клинике
|
||||||
|
|
||||||
|
**Полное название:** Клиника ухо, горло, нос им. проф. Е.Н.Оленевой
|
||||||
|
**Тип:** Медицинская клиника, отоларингология (ЛОР)
|
||||||
|
**Город:** Пермь
|
||||||
|
**Платформа сайта:** Drupal (тема `clinic_bootstrap_mobile`)
|
||||||
|
**Аудитория:** Пациенты, врачи клиники, подрядчики
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Цветовая палитра
|
||||||
|
|
||||||
|
### 2.1 Фирменные цвета (Oracal — базовая палитра)
|
||||||
|
|
||||||
|
Основаны на кодах самоклеящейся плёнки Oracal. HEX-значения — приближённые
|
||||||
|
цифровые эквиваленты. **Для печати и оффлайн-носителей используй коды 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` | Фон, инвертированный текст, логотип на тёмных фонах |
|
||||||
|
|
||||||
|
### 2.2 Цвета сайта oclinica.ru (реальный CSS)
|
||||||
|
|
||||||
|
Извлечены из CSS темы Drupal:
|
||||||
|
`https://perm.oclinica.ru/sites/all/themes/clinic_bootstrap_mobile/css/style.css`
|
||||||
|
Метод: python + regex + Counter, 2026-03-22
|
||||||
|
|
||||||
|
| Название | HEX | RGB | Группа | Вхождений | Применение на сайте |
|
||||||
|
|-----------------------|-----------|-------------------|----------|-----------|---------------------|
|
||||||
|
| Бежевый | `#bf9975` | rgb(191,153,117) | Акценты | 12 | Основной тёплый акцент, фоны, рамки, текст |
|
||||||
|
| Серо-бирюзовый | `#60959c` | rgb(96,149,156) | Акценты | 7 | Основной холодный акцент, ссылки |
|
||||||
|
| Бирюзовый | `#63bac3` | rgb(99,186,195) | Акценты | 4 | Фоны акцентных блоков, иконки |
|
||||||
|
| Бирюзовый средний | `#52b4bd` | rgb(82,180,189) | Акценты | 4 | Вторичные цветовые акценты |
|
||||||
|
| Коралловый | `#ffa39c` | rgb(255,163,156) | Акценты | 2 | CTA-кнопки («Запишите меня!») |
|
||||||
|
| Основной текст | `#464646` | rgb(70,70,70) | Текст | 3 | Цвет основного текста на сайте |
|
||||||
|
| Второстепенный текст | `#949290` | rgb(148,146,144) | Текст | 4 | Подписи, второстепенный контент |
|
||||||
|
| Светло-бирюзовый фон | `#b8e6ed` | rgb(184,230,237) | Фоны | 1 | Фоны светлых секций с акцентом |
|
||||||
|
| Кремовый фон | `#e9e4d4` | rgb(233,228,212) | Фоны | 1 | Тёплые фоны секций |
|
||||||
|
| Светло-жёлтый фон | `#eef4d1` | rgb(238,244,209) | Фоны | 1 | Фон карточек отзывов |
|
||||||
|
| Светло-зелёный фон | `#f2fee6` | rgb(242,254,230) | Фоны | 1 | Фон секции новостей |
|
||||||
|
|
||||||
|
### 2.3 Соответствие Oracal → Сайт
|
||||||
|
|
||||||
|
| Oracal (бренд) | HEX бренда | Сайт (цифровой) | HEX сайта | Отклонение |
|
||||||
|
|--------------------------|------------|-----------------------|-----------|------------|
|
||||||
|
| 053M Основной бирюзовый | `#7ecfca` | Бирюзовый | `#63bac3` | Темнее, насыщеннее |
|
||||||
|
| 073M Тёмный серо-голубой | `#5b7b87` | Серо-бирюзовый | `#60959c` | Светлее на сайте |
|
||||||
|
| 066M Средний бирюзовый | `#5bb5ad` | Бирюзовый средний | `#52b4bd` | Смещён в синеву |
|
||||||
|
| 081M Бежевый | `#c4a882` | Бежевый | `#bf9975` | Темнее, насыщеннее |
|
||||||
|
| 050M Тёмно-синий | `#1b4c72` | — | — | Не найден в CSS сайта |
|
||||||
|
| 080M Тёмно-коричневый | `#5c2e0e` | — | — | Не найден в 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 | ✓ | ✕ | ✓ |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Типографика
|
||||||
|
|
||||||
|
### 3.1 DINPro — фирменный шрифт (оффлайн)
|
||||||
|
|
||||||
|
**Применение:** логотип, оффлайн-носители (бейджи, навигационные таблички, транспорт,
|
||||||
|
форма сотрудников, полиграфия).
|
||||||
|
**Не использовать** на веб-сайте и в digital-материалах (лицензионный шрифт,
|
||||||
|
нет легального встраивания в веб).
|
||||||
|
**Веса:** Regular, Medium, Bold
|
||||||
|
|
||||||
|
| Стиль | font-weight | font-size | line-height | letter-spacing | Применение |
|
||||||
|
|----------|-------------|-----------|-------------|----------------|------------|
|
||||||
|
| Display | 700 | 48px | 1.15 | -0.5px | Крупные заголовки носителей |
|
||||||
|
| H1 | 700 | 36px | 1.2 | -0.3px | Основной заголовок печатных материалов |
|
||||||
|
| H2 | 700 | 28px | 1.25 | -0.2px | Подзаголовки носителей |
|
||||||
|
| H3 | 500 | 22px | 1.3 | 0px | Подзаголовки третьего уровня |
|
||||||
|
| Body | 400 | 16px | 1.5 | 0px | Основной текст оффлайн |
|
||||||
|
| Small | 400 | 12px | 1.4 | 0.2px | Подписи, бейджи, таблички |
|
||||||
|
| Caption | 400 | 10px | 1.3 | 0.4px | Сноски, технические пометки |
|
||||||
|
|
||||||
|
### 3.2 Fira Sans — веб-шрифт (digital)
|
||||||
|
|
||||||
|
**Применение:** сайт oclinica.ru, цифровые коммуникации, digital-баннеры, email.
|
||||||
|
**Источник:** Google Fonts (`https://fonts.google.com/specimen/Fira+Sans`)
|
||||||
|
**Поддержка кириллицы:** да
|
||||||
|
**Используемые веса:** 300 (Light), 400 (Regular), 500 (Medium), 600 (SemiBold)
|
||||||
|
**CSS:** `font-family: 'Fira Sans', sans-serif;`
|
||||||
|
|
||||||
|
| Стиль | font-weight | font-size | line-height | letter-spacing | Применение |
|
||||||
|
|----------------|-------------|---------------|-------------|----------------|------------|
|
||||||
|
| h1 | 600 | 2.25rem (36px)| 1.25 | -0.025em | Заголовок страницы |
|
||||||
|
| h2 | 600 | 1.875rem (30px)| 1.3 | -0.02em | Заголовок секции |
|
||||||
|
| h3 | 500 | 1.5rem (24px) | 1.375 | -0.01em | Подзаголовок |
|
||||||
|
| h4 | 500 | 1.25rem (20px)| 1.4 | 0em | Заголовок компонента |
|
||||||
|
| h5 | 500 | 1.125rem (18px)| 1.45 | 0em | Подзаголовок компонента |
|
||||||
|
| h6 | 500 | 1rem (16px) | 1.5 | 0.01em | Метка секции |
|
||||||
|
| body-large | 400 | 1.125rem (18px)| 1.6 | 0em | Лид-текст, вводный абзац |
|
||||||
|
| body | 400 | 1rem (16px) | 1.625 | 0em | Основной текст |
|
||||||
|
| body-small | 400 | 0.875rem (14px)| 1.5 | 0em | Дополнительный текст, подписи |
|
||||||
|
| caption | 300 | 0.75rem (12px)| 1.4 | 0.02em | Подписи к изображениям, сноски |
|
||||||
|
| label | 500 | 0.875rem (14px)| 1.2 | 0.03em | Метки форм |
|
||||||
|
| overline | 600 | 0.6875rem (11px)| 1.2 | 0.1em | Надписи над заголовками (uppercase) |
|
||||||
|
|
||||||
|
**Принцип выбора шрифта:**
|
||||||
|
- Носитель цифровой → Fira Sans
|
||||||
|
- Носитель печатный / физический → DINPro
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Логотип
|
||||||
|
|
||||||
|
### 4.1 Версии логотипа
|
||||||
|
|
||||||
|
**Основной логотип** — включает название специализации («ухо, горло, нос»).
|
||||||
|
Используется на всех основных носителях: сайт, навигация, транспорт, форма.
|
||||||
|
|
||||||
|
**Общий логотип** — без специализации, только название клиники или сеть.
|
||||||
|
Используется для обозначения сети клиник, в корпоративных материалах.
|
||||||
|
|
||||||
|
### 4.2 Файлы
|
||||||
|
|
||||||
|
| Файл | Описание | Путь в проекте |
|
||||||
|
|------|----------|----------------|
|
||||||
|
| `logo-transparent.png` | Логотип с прозрачным фоном | `apps/web/public/logo/logo-transparent.png` |
|
||||||
|
|
||||||
|
SVG-версия ожидается (не получена от клиники).
|
||||||
|
|
||||||
|
### 4.3 Цветовые варианты
|
||||||
|
|
||||||
|
| Вариант | Фон | Логотип | Применение |
|
||||||
|
|---------|-----|---------|------------|
|
||||||
|
| Основной | Белый / светлый | Полноцветный | Сайт, полиграфия на белом |
|
||||||
|
| Инвертированный | Тёмный (#5b7b87, #1b4c72) | Белый (`filter: brightness(0) invert(1)`) | Хедер, тёмные секции |
|
||||||
|
| На форме (беж) | Бежевый (#c4a882 / Oracal 081M) | Коричневый (#5c2e0e / Oracal 080M) | Одежда персонала |
|
||||||
|
| На форме (синий) | Тёмно-синий (#1b4c72 / Oracal 050M) | Белый | Одежда персонала |
|
||||||
|
|
||||||
|
### 4.4 Охранная зона
|
||||||
|
|
||||||
|
Минимальный отступ вокруг логотипа = **высота буквы «К»** в названии.
|
||||||
|
Запрещено размещать другие элементы в охранной зоне.
|
||||||
|
|
||||||
|
### 4.5 Минимальные размеры
|
||||||
|
|
||||||
|
| Носитель | Размер логотипа |
|
||||||
|
|----------|----------------|
|
||||||
|
| Одежда до р.46 | 70 × 25,5 мм |
|
||||||
|
| Одежда от р.48 | 90 × 32,8 мм |
|
||||||
|
|
||||||
|
### 4.6 Запрещено
|
||||||
|
|
||||||
|
- Искажать пропорции
|
||||||
|
- Менять цвета на нефирменные
|
||||||
|
- Добавлять тени, обводки, эффекты
|
||||||
|
- Размещать на пёстром или плохо контрастном фоне
|
||||||
|
- Использовать низкое разрешение (< 150 dpi для печати)
|
||||||
|
- Переворачивать или отражать
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. CSS-переменные брендбука
|
||||||
|
|
||||||
|
Определены в `apps/web/app/globals.css`:
|
||||||
|
|
||||||
|
```css
|
||||||
|
/* Цвета бренда */
|
||||||
|
--brand-053m: #7ecfca; /* Основной бирюзовый */
|
||||||
|
--brand-073m: #5b7b87; /* Тёмный серо-голубой */
|
||||||
|
--brand-066m: #5bb5ad; /* Средний бирюзовый */
|
||||||
|
--brand-050m: #1b4c72; /* Тёмно-синий */
|
||||||
|
--brand-081m: #c4a882; /* Бежевый */
|
||||||
|
--brand-080m: #5c2e0e; /* Тёмно-коричневый */
|
||||||
|
--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: ... /* Фон карточек */
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. Оффлайн носители
|
||||||
|
|
||||||
|
### 6.1 Форма сотрудников
|
||||||
|
|
||||||
|
**Варианты:**
|
||||||
|
- Бежевый: ткань цвета Oracal 081M, логотип Oracal 080M (коричневый), расположение — левая сторона груди
|
||||||
|
- Синий: ткань цвета Oracal 050M (тёмно-синий), логотип белый (Oracal 010), расположение — левая сторона груди
|
||||||
|
|
||||||
|
**Размеры логотипа на форме:**
|
||||||
|
- Размеры до 46: 70 × 25,5 мм
|
||||||
|
- Размеры от 48: 90 × 32,8 мм
|
||||||
|
|
||||||
|
### 6.2 Бейджи
|
||||||
|
|
||||||
|
**Размер:** 70 × 30 мм
|
||||||
|
**Варианты:** серый (светлый) и белый
|
||||||
|
**Состав текста:** имя, должность, учёная степень (при наличии)
|
||||||
|
**Шрифт:** DINPro
|
||||||
|
**Логотип:** левый верхний угол или левая часть
|
||||||
|
|
||||||
|
### 6.3 Внутренняя навигация
|
||||||
|
|
||||||
|
**Материал:** оргстекло
|
||||||
|
**Плёнки:** Oracal 053M (бирюзовый) и 073M (тёмный серо-голубой)
|
||||||
|
**Типы табличек:**
|
||||||
|
- Таблички на дверях кабинетов: номер кабинета, профиль врача с фото и QR-кодом
|
||||||
|
- Указатели по этажам: стрелки направлений + номера кабинетов
|
||||||
|
|
||||||
|
**Нумерация кабинетов:**
|
||||||
|
- Двузначное число, крупный шрифт (DINPro Bold)
|
||||||
|
- Фон: бирюзовый (053M), номер: белый
|
||||||
|
- Пример реализации: кабинеты 13, 31, «Кабинет 04»
|
||||||
|
|
||||||
|
### 6.4 Брендирование транспорта (трамвай)
|
||||||
|
|
||||||
|
**Зоны оклейки:**
|
||||||
|
- Борта: Oracal 053M (#7ecfca) + 073M (#5b7b87)
|
||||||
|
- Передняя часть: Oracal 066M (#5bb5ad) + 050M (#1b4c72)
|
||||||
|
- Акценты: Oracal 081M (#c4a882) + 080M (#5c2e0e)
|
||||||
|
|
||||||
|
**Все 6 фирменных цветов присутствуют на транспорте.**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. Структура брендбука (страницы)
|
||||||
|
|
||||||
|
| URL | Статус | Описание |
|
||||||
|
|-----|--------|----------|
|
||||||
|
| `/foundation/logo` | ✅ Готова | Логотип, варианты, охранная зона, правила |
|
||||||
|
| `/foundation/colors` | ✅ Готова | Палитра, контраст WCAG, цвета сайта, соответствие |
|
||||||
|
| `/foundation/typography` | ✅ Готова | DINPro + Fira Sans, шкала стилей |
|
||||||
|
| `/foundation/icons` | 🔜 Скоро | Иконография |
|
||||||
|
| `/offline/uniform` | ✅ Готова | Форма сотрудников |
|
||||||
|
| `/offline/badges` | ✅ Готова | Бейджи |
|
||||||
|
| `/offline/navigation` | ✅ Готова | Внутренняя навигация |
|
||||||
|
| `/offline/transport` | ✅ Готова | Брендирование транспорта |
|
||||||
|
| `/components/buttons` | 🔜 Sprint 3 | Кнопки |
|
||||||
|
| `/components/forms` | 🔜 Sprint 3 | Форм-контролы |
|
||||||
|
| `/components/*` | 🔜 Sprint 3–4 | Карточки, бейджи, алерты, модалки, таблицы |
|
||||||
|
| `/blocks/*` | 🔜 Sprint 5–8 | Hero, врачи, отзывы, новости, формы |
|
||||||
|
| `/pages/*` | 🔜 Sprint 9–11 | Главная, заболевание, врачи, цены, контакты |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. Правила применения цветов
|
||||||
|
|
||||||
|
### Разрешено
|
||||||
|
- Использовать только цвета из фирменной палитры (раздел 2.1)
|
||||||
|
- Для digital: адаптировать к цветам сайта (раздел 2.2)
|
||||||
|
- Текст на цветном фоне — минимум WCAG AA (4.5:1)
|
||||||
|
- Белый логотип на тёмных фонах (073M, 050M, 080M)
|
||||||
|
- Коричневый логотип (080M) на бежевом фоне (081M)
|
||||||
|
|
||||||
|
### Запрещено
|
||||||
|
- Использовать произвольные цвета вне палитры
|
||||||
|
- Осветлять, затемнять или менять оттенок фирменных цветов
|
||||||
|
- Текст с контрастом ниже 3:1 (даже для крупного текста)
|
||||||
|
- Размещать тёплые и холодные акценты рядом без разделителя
|
||||||
|
|
||||||
|
### Иерархия цветов
|
||||||
|
|
||||||
|
```
|
||||||
|
Основной бирюзовый (053M / #7ecfca) ← главный идентификатор бренда
|
||||||
|
└── Средний бирюзовый (066M / #5bb5ad) ← вторичный акцент
|
||||||
|
└── Тёмный серо-голубой (073M / #5b7b87) ← фоны, хедер
|
||||||
|
|
||||||
|
Тёмно-синий (050M / #1b4c72) ← авторитет, полиграфия
|
||||||
|
Бежевый (081M / #c4a882) ← тепло, форма
|
||||||
|
└── Тёмно-коричневый (080M / #5c2e0e) ← текст на бежевом
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 9. Правила применения типографики
|
||||||
|
|
||||||
|
### Веб (Fira Sans)
|
||||||
|
- H1 только один на странице
|
||||||
|
- Заголовки не пропускать по уровням (h1→h2→h3)
|
||||||
|
- Основной текст: 16px / 400 / 1.625
|
||||||
|
- Минимальный размер текста на экране: 12px
|
||||||
|
- Кириллица: только Fira Sans, не DINPro
|
||||||
|
|
||||||
|
### Оффлайн (DINPro)
|
||||||
|
- Все физические носители: DINPro
|
||||||
|
- Логотип: DINPro Bold
|
||||||
|
- Таблички: DINPro Medium / Bold
|
||||||
|
- Не использовать light (300) для текста < 14pt
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 10. Технический стек проекта
|
||||||
|
|
||||||
|
| Слой | Технология | Версия |
|
||||||
|
|------|-----------|--------|
|
||||||
|
| Фронтенд | Next.js App Router | 16.x |
|
||||||
|
| Стилизация | Tailwind CSS | 4.x |
|
||||||
|
| Язык | TypeScript | 5.x |
|
||||||
|
| Шрифты | next/font/google | — |
|
||||||
|
| Бэкенд | NestJS | 11.x |
|
||||||
|
| БД | PostgreSQL + Prisma | 16.x / 7.x |
|
||||||
|
| Деплой | Vercel Hobby | — |
|
||||||
|
| Пакетный менеджер | pnpm | 10.x |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 11. История изменений контекста
|
||||||
|
|
||||||
|
| Версия | Дата | Что добавлено |
|
||||||
|
|--------|------|---------------|
|
||||||
|
| 1.0 | 2026-03-22 | Sprint 1: логотип, базовые цвета |
|
||||||
|
| 2.0 | 2026-03-22 | Sprint 2: типографика, оффлайн носители, цвета сайта (8 цветов) |
|
||||||
|
| 2.1 | 2026-03-22 | Sprint 2 доп.: +3 цвета сайта (коралловый, светло-жёлтый, светло-зелёный) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 12. Что обновлять в этом файле
|
||||||
|
|
||||||
|
При каждом спринте добавляй:
|
||||||
|
- Новые компоненты и их спецификации (цвета, размеры, состояния)
|
||||||
|
- Новые правила применения, выявленные при разработке
|
||||||
|
- Изменения в палитре или типографике
|
||||||
|
- Новые паттерны и примеры кода
|
||||||
|
|
||||||
|
**Соответствующий раздел в TZ.md:** ФТ-03-LLM
|
||||||
|
**Соответствующий раздел в SPRINTS.md:** задача «LLM-блок» в каждом спринте
|
||||||
@@ -81,40 +81,55 @@
|
|||||||
### Фактические результаты
|
### Фактические результаты
|
||||||
- Страница `/foundation/colors` — 7 цветов с HEX/RGB/HSL/CSS-var и копированием, WCAG-контраст 7 пар, экспорт JSON
|
- Страница `/foundation/colors` — 7 цветов с HEX/RGB/HSL/CSS-var и копированием, WCAG-контраст 7 пар, экспорт JSON
|
||||||
- Страница `/foundation/typography` — DINPro (оффлайн) + Fira Sans (веб), таблица применения, полные шкалы, живой пример
|
- Страница `/foundation/typography` — DINPro (оффлайн) + Fira Sans (веб), таблица применения, полные шкалы, живой пример
|
||||||
- Страница `/offline/uniform` — схема формы, таблица размеров логотипа, правила использования
|
- Страница `/offline/uniform` — реальные фото из PDF (беж + синий вариант), таблица размеров, правила
|
||||||
- Страница `/offline/badges` — макеты бейджей 70×30 мм (светлый/тёмный), состав текста, применение
|
- Страница `/offline/badges` — реальные фото из PDF (лицевая + оборотная), состав текста, пример
|
||||||
- Страница `/offline/navigation` — 4 шаблона табличек, технические требования, цвета Oracal
|
- Страница `/offline/navigation` — макеты из PDF (Кабинет 04, карточка врача), фото дверей с номерами (13, 31), указатели по этажам
|
||||||
- Страница `/offline/transport` — CSS-макет трамвая с трёхполосной схемой, таблица зон
|
- Страница `/offline/transport` — макет трамвая из PDF (оба вида, реальный рендер), таблица зон, цвета Oracal
|
||||||
- Страница `/offline/print` — макеты визитки (лицо/оборот) и листовки А5, Telegram-бот
|
- Страница `/offline/print` — убрана из навигации (нет данных из брендбука)
|
||||||
- Sidebar: убраны «скоро» для Цветов, Типографики и всех 5 страниц Оффлайн
|
- Sidebar: убраны «скоро» для Цветов, Типографики и всех страниц Оффлайн кроме Печати
|
||||||
- Версия обновлена до **Sprint 2 · v0.2.0**
|
- Версия обновлена до **Sprint 2 · v0.2.0**
|
||||||
|
- **Деплой на Vercel:** https://web-oclinica.vercel.app (production, бесплатно)
|
||||||
|
- **Тайтлы страниц:** единый формат «Раздел. Цифровой брендбук Клиники ухо, горло, нос им. проф. Е.Н.Оленевой»
|
||||||
|
|
||||||
### Технические решения Sprint 2
|
### Технические решения Sprint 2
|
||||||
- Страница «Цвета» — `"use client"` для clipboard API и экспорта JSON
|
- Страница «Цвета» — `"use client"` для clipboard API и экспорта JSON
|
||||||
- WCAG relative luminance вычисляется на клиенте, без зависимостей
|
- WCAG relative luminance вычисляется на клиенте, без зависимостей
|
||||||
- DINPro отображается с фоллбэком Arial (лицензионный шрифт)
|
- DINPro отображается с фоллбэком Arial (лицензионный шрифт)
|
||||||
- Макеты (бейджи, трамвай, визитки) — чистый CSS/Tailwind без внешних зависимостей
|
- Реальные фото и макеты из PDF: PyMuPDF (fitz) — извлечение растровых изображений и рендер векторных страниц
|
||||||
|
- Рендер PDF страниц: 2.5–3.0x масштаб → JPEG, кроп до нужной области через Pillow
|
||||||
|
|
||||||
**Результат спринта:** Разделы «Цвета», «Типографика» и «Оффлайн элементы» полностью готовы.
|
### Ретроспектива Sprint 2 — LLM-контекст
|
||||||
|
- [x] Docs: Создан `docs/LLM_CONTEXT.md` — сводный файл дизайн-данных для LLM (v2.1)
|
||||||
|
- [x] TZ: Добавлено требование ФТ-03-LLM — LLM-блок на каждой странице брендбука
|
||||||
|
- [ ] FE: Добавить LLM-блоки на страницы Sprint 1–2 (логотип, цвета, типографика, оффлайн) — перенесено в Sprint 3
|
||||||
|
|
||||||
|
**Результат спринта:** Разделы «Цвета», «Типографика» и «Оффлайн элементы» полностью готовы с реальными материалами из брендбука.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Sprint 3 — Базовые компоненты: кнопки и поля ввода
|
## Sprint 3 — Базовые компоненты: кнопки и поля ввода
|
||||||
|
|
||||||
**Цель:** Все варианты кнопок и форм-контролов в брендбуке.
|
**Цель:** Все варианты кнопок и форм-контролов в брендбуке. LLM-блоки на страницах.
|
||||||
|
|
||||||
### Задачи
|
### Задачи — LLM-контекст
|
||||||
|
- [ ] FE: Добавить LLM-блок на страницу «Логотип» (`/foundation/logo`)
|
||||||
|
- [x] FE: Добавить LLM-блок на страницу «Цвета» (`/foundation/colors`) — v2.1
|
||||||
|
- [x] FE: Добавить LLM-блок на страницу «Типографика» (`/foundation/typography`) — v2.0
|
||||||
|
- [x] FE: Создать переиспользуемый компонент `components/llm/LlmBlock.tsx` (LlmBlock, LlmSection, LlmTable, LlmRules)
|
||||||
|
- [ ] Docs: Обновить `docs/LLM_CONTEXT.md` по итогам спринта (версия 3.x)
|
||||||
|
|
||||||
|
### Задачи — компоненты
|
||||||
- [ ] FE: Компонент Button (все варианты: primary/secondary/ghost/danger, размеры, состояния)
|
- [ ] FE: Компонент Button (все варианты: primary/secondary/ghost/danger, размеры, состояния)
|
||||||
- [ ] FE: Компонент Input (text, password, focus/error/disabled)
|
- [ ] FE: Компонент Input (text, password, focus/error/disabled)
|
||||||
- [ ] FE: Компонент Textarea
|
- [ ] FE: Компонент Textarea
|
||||||
- [ ] FE: Компонент Select
|
- [ ] FE: Компонент Select
|
||||||
- [ ] FE: Компонент Checkbox и Radio
|
- [ ] FE: Компонент Checkbox и Radio
|
||||||
- [ ] FE: Компонент Toggle/Switch
|
- [ ] FE: Компонент Toggle/Switch
|
||||||
- [ ] FE: Страница брендбука «Компоненты → Кнопки» с документацией
|
- [ ] FE: Страница брендбука «Компоненты → Кнопки» с документацией + LLM-блок
|
||||||
- [ ] FE: Страница брендбука «Компоненты → Форм-контролы»
|
- [ ] FE: Страница брендбука «Компоненты → Форм-контролы» + LLM-блок
|
||||||
- [ ] FE: Копирование HTML/CSS кода компонента в один клик
|
- [ ] FE: Копирование HTML/CSS кода компонента в один клик
|
||||||
|
|
||||||
**Результат спринта:** Раздел «Базовые компоненты — кнопки и ввод» готов.
|
**Результат спринта:** Раздел «Базовые компоненты — кнопки и ввод» готов. LLM-блоки добавлены на страницы Фундамента.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -123,6 +138,8 @@
|
|||||||
**Цель:** Все типы карточек, используемых на сайте.
|
**Цель:** Все типы карточек, используемых на сайте.
|
||||||
|
|
||||||
### Задачи
|
### Задачи
|
||||||
|
- [ ] Docs: Обновить `docs/LLM_CONTEXT.md` — добавить спецификации карточек
|
||||||
|
- [ ] FE: Добавить LLM-блок на страницу «Карточки»
|
||||||
- [ ] FE: Карточка врача (DoctorCard) — фото, имя, специализация, кнопка записи
|
- [ ] FE: Карточка врача (DoctorCard) — фото, имя, специализация, кнопка записи
|
||||||
- [ ] FE: Карточка услуги / заболевания
|
- [ ] FE: Карточка услуги / заболевания
|
||||||
- [ ] FE: Карточка новости — превью, дата, заголовок, анонс, читать далее
|
- [ ] FE: Карточка новости — превью, дата, заголовок, анонс, читать далее
|
||||||
@@ -140,6 +157,8 @@
|
|||||||
**Цель:** Ключевые верхние блоки страниц.
|
**Цель:** Ключевые верхние блоки страниц.
|
||||||
|
|
||||||
### Задачи
|
### Задачи
|
||||||
|
- [ ] Docs: Обновить `docs/LLM_CONTEXT.md` — добавить спецификации Hero и CEO-блоков
|
||||||
|
- [ ] FE: Добавить LLM-блоки на страницы Hero и CEO-текст
|
||||||
- [ ] FE: Hero-блок вариант 1 — фон + заголовок + CTA
|
- [ ] FE: Hero-блок вариант 1 — фон + заголовок + CTA
|
||||||
- [ ] FE: Hero-блок вариант 2 — иллюстрация сбоку
|
- [ ] FE: Hero-блок вариант 2 — иллюстрация сбоку
|
||||||
- [ ] FE: Hero-блок вариант 3 — с встроенной формой записи
|
- [ ] FE: Hero-блок вариант 3 — с встроенной формой записи
|
||||||
@@ -157,6 +176,8 @@
|
|||||||
**Цель:** Блоки и компоненты, связанные с врачами.
|
**Цель:** Блоки и компоненты, связанные с врачами.
|
||||||
|
|
||||||
### Задачи
|
### Задачи
|
||||||
|
- [ ] Docs: Обновить `docs/LLM_CONTEXT.md` — добавить спецификации блоков врачей
|
||||||
|
- [ ] FE: Добавить LLM-блок на страницу «Блоки → Врачи»
|
||||||
- [ ] FE: Блок «Наши врачи» — сетка карточек с фильтром по специализации
|
- [ ] FE: Блок «Наши врачи» — сетка карточек с фильтром по специализации
|
||||||
- [ ] FE: Блок «Врач — профиль» (полная страница): фото, биография, специализации, расписание
|
- [ ] FE: Блок «Врач — профиль» (полная страница): фото, биография, специализации, расписание
|
||||||
- [ ] FE: Компонент «Расписание / слоты записи»
|
- [ ] FE: Компонент «Расписание / слоты записи»
|
||||||
@@ -173,6 +194,8 @@
|
|||||||
**Цель:** Контентные блоки сайта.
|
**Цель:** Контентные блоки сайта.
|
||||||
|
|
||||||
### Задачи
|
### Задачи
|
||||||
|
- [ ] Docs: Обновить `docs/LLM_CONTEXT.md` — добавить спецификации блоков отзывов и новостей
|
||||||
|
- [ ] FE: Добавить LLM-блок на страницу «Блоки → Отзывы и новости»
|
||||||
- [ ] FE: Блок отзывов — карусель
|
- [ ] FE: Блок отзывов — карусель
|
||||||
- [ ] FE: Блок отзывов — статичная сетка
|
- [ ] FE: Блок отзывов — статичная сетка
|
||||||
- [ ] FE: Блок рейтинга (звёзды + количество отзывов)
|
- [ ] FE: Блок рейтинга (звёзды + количество отзывов)
|
||||||
@@ -191,6 +214,8 @@
|
|||||||
**Цель:** Все формы и диалоги взаимодействия с пациентом.
|
**Цель:** Все формы и диалоги взаимодействия с пациентом.
|
||||||
|
|
||||||
### Задачи
|
### Задачи
|
||||||
|
- [ ] Docs: Обновить `docs/LLM_CONTEXT.md` — добавить спецификации форм и модальных окон
|
||||||
|
- [ ] FE: Добавить LLM-блок на страницу «Блоки → Формы и контакты»
|
||||||
- [ ] FE: Форма записи — короткая (имя, телефон)
|
- [ ] FE: Форма записи — короткая (имя, телефон)
|
||||||
- [ ] FE: Форма записи — расширенная (имя, телефон, специализация, врач, дата)
|
- [ ] FE: Форма записи — расширенная (имя, телефон, специализация, врач, дата)
|
||||||
- [ ] FE: Форма записи в модальном окне
|
- [ ] FE: Форма записи в модальном окне
|
||||||
@@ -252,20 +277,25 @@
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Sprint 12 — Деплой, полировка, документация
|
## Sprint 12 — Полировка, финальный деплой и документация
|
||||||
|
|
||||||
**Цель:** Финальный релиз и публикация.
|
**Цель:** Финальный релиз. Фронтенд уже живёт на Vercel с Sprint 2, Sprint 12 — финальная полировка и production-готовность бэкенда.
|
||||||
|
|
||||||
### Задачи
|
### Задачи
|
||||||
- [ ] BE + FE: Полный smoke-тест всего брендбука
|
- [ ] BE + FE: Полный smoke-тест всего брендбука
|
||||||
- [ ] FE: Мобильная адаптация — финальная проверка всех страниц
|
- [ ] FE: Мобильная адаптация — финальная проверка всех страниц
|
||||||
- [ ] FE: Accessibility-аудит (WCAG AA)
|
- [ ] FE: Accessibility-аудит (WCAG AA)
|
||||||
- [ ] Деплой: настройка CI/CD, публикация на сервере
|
- [ ] Деплой BE: выбрать и настроить хостинг для NestJS + PostgreSQL
|
||||||
- [ ] Docs: Создание `docs/deployment.md`
|
- [ ] Деплой: настроить автоматический деплой через Gitea Actions → Vercel (при пуше в `main`)
|
||||||
- [ ] Docs: Обновление README.md финальными инструкциями
|
- [ ] Docs: Обновление `docs/DEPLOY.md` финальными инструкциями
|
||||||
- [ ] Design: Финальный ревью брендбука
|
- [ ] Design: Финальный ревью брендбука
|
||||||
|
|
||||||
**Результат спринта:** Брендбук задеплоен и доступен по URL.
|
### Текущий статус деплоя
|
||||||
|
- **Фронтенд:** https://web-oclinica.vercel.app (Vercel Hobby, задеплоен в Sprint 2)
|
||||||
|
- **Команда деплоя:** `cd apps/web && vercel --prod --yes`
|
||||||
|
- **Бэкенд:** локально (Docker Compose), хостинг выбирается в Sprint 12
|
||||||
|
|
||||||
|
**Результат спринта:** Брендбук полностью готов, оба сервиса задеплоены, автодеплой настроен.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -37,9 +37,10 @@
|
|||||||
| Краткое название | oclinica-brandbook |
|
| Краткое название | oclinica-brandbook |
|
||||||
| Сайт клиники | https://oclinica.ru |
|
| Сайт клиники | https://oclinica.ru |
|
||||||
| Тип системы | Веб-приложение (Living Styleguide) |
|
| Тип системы | Веб-приложение (Living Styleguide) |
|
||||||
| Режим работы | Локальная разработка + деплой на сервер |
|
| Режим работы | Локальная разработка + Vercel (preview + production) |
|
||||||
| Аудитория | Внутренние дизайнеры клиники, внешние подрядчики |
|
| Аудитория | Внутренние дизайнеры клиники, внешние подрядчики |
|
||||||
| Хостинг | TBD — будет прописан отдельно |
|
| Хостинг (фронтенд) | Vercel Hobby (бесплатно) — https://web-oclinica.vercel.app |
|
||||||
|
| Хостинг (бэкенд + БД) | TBD — уточняется при переходе к Sprint 11 (экспериментальная секция) |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -152,6 +153,17 @@
|
|||||||
- HTML-код компонента с кнопкой «Скопировать»
|
- HTML-код компонента с кнопкой «Скопировать»
|
||||||
- Краткое описание и правила применения
|
- Краткое описание и правила применения
|
||||||
|
|
||||||
|
**ФТ-03-LLM.** На каждой странице брендбука, содержащей дизайн-стандарты (цвета, типографика,
|
||||||
|
компоненты, блоки, страницы), должен присутствовать **LLM-блок** — свёрнутая или отдельная
|
||||||
|
секция с машиночитаемым описанием стандарта для использования языковыми моделями при
|
||||||
|
разработке дизайна, макетов, сайта и приложений. LLM-блок содержит:
|
||||||
|
- Все токены и значения в табличном формате
|
||||||
|
- Правила применения в формате «разрешено / запрещено»
|
||||||
|
- Взаимосвязи с другими стандартами (ссылки на разделы)
|
||||||
|
- Примеры корректного и некорректного использования
|
||||||
|
|
||||||
|
Сводный LLM-контекст всего брендбука хранится в файле: **`docs/LLM_CONTEXT.md`**
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### 5.2 Раздел «Цвета»
|
### 5.2 Раздел «Цвета»
|
||||||
@@ -393,17 +405,18 @@
|
|||||||
|
|
||||||
| Слой | Технология | Версия | Обоснование |
|
| Слой | Технология | Версия | Обоснование |
|
||||||
|-------------------|-----------------------|----------|--------------------------------------------------|
|
|-------------------|-----------------------|----------|--------------------------------------------------|
|
||||||
| Фронтенд | Next.js (App Router) | 15.x | SSR/SSG, оптимизация, экосистема React |
|
| Фронтенд | Next.js (App Router) | 16.x | SSR/SSG, оптимизация, экосистема React |
|
||||||
| Бэкенд | NestJS | 10.x | Типизированный Node.js фреймворк, DI, модули |
|
| Бэкенд | NestJS | 11.x | Типизированный Node.js фреймворк, DI, модули |
|
||||||
| База данных | PostgreSQL | 16.x | Надёжная реляционная БД, JSON-поля для атрибутов |
|
| База данных | PostgreSQL | 16.x | Надёжная реляционная БД, JSON-поля для атрибутов |
|
||||||
| ORM | Prisma | 5.x | Type-safe запросы, миграции, seed |
|
| ORM | Prisma | 7.x | Type-safe запросы, миграции, seed |
|
||||||
| Стилизация | CSS Modules | — | Изоляция стилей, нет рантайм-зависимостей |
|
| Стилизация | Tailwind CSS | 4.x | Utility-first, CSS-переменные, нет рантайм-overhead |
|
||||||
| Дизайн-токены | CSS Custom Properties | — | Нативно поддерживается всеми браузерами |
|
| Дизайн-токены | CSS Custom Properties | — | Нативно поддерживается всеми браузерами |
|
||||||
| Шрифт (бренд) | DINPro | — | Фирменный шрифт бренда, оффлайн-носители |
|
| Шрифт (бренд) | DINPro | — | Фирменный шрифт бренда, оффлайн-носители |
|
||||||
| Шрифт (веб) | Fira Sans | — | Google Fonts, кириллица, веса 300 и 400, сайт |
|
| Шрифт (веб) | Fira Sans | — | Google Fonts, кириллица, веса 300/400/500/600 |
|
||||||
| Авторизация | JWT + httpOnly cookie | — | Безопасное хранение токена |
|
| Авторизация | JWT + httpOnly cookie | — | Безопасное хранение токена |
|
||||||
| Пакетный менеджер | pnpm | 9.x | Monorepo workspaces, скорость |
|
| Пакетный менеджер | pnpm | 10.x | Monorepo workspaces, скорость |
|
||||||
| Контейнеризация | Docker + Compose | — | Единообразное окружение dev/prod |
|
| Контейнеризация | Docker + Compose | — | Единообразное окружение локальной разработки |
|
||||||
|
| Хостинг фронтенда | Vercel | — | Нативная поддержка Next.js, бесплатный Hobby-план |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -480,16 +493,29 @@ oclinica-brandbook/
|
|||||||
| Docker | >= 24 |
|
| Docker | >= 24 |
|
||||||
| Docker Compose | >= 2 |
|
| Docker Compose | >= 2 |
|
||||||
|
|
||||||
### 12.2 Production-сервер
|
### 12.2 Деплой фронтенда (Vercel)
|
||||||
|
|
||||||
> TBD — параметры хостинга будут прописаны отдельно.
|
Фронтенд (`apps/web`) деплоится на Vercel Hobby (бесплатно).
|
||||||
|
|
||||||
Минимальные ожидаемые требования:
|
**Production URL:** https://web-oclinica.vercel.app
|
||||||
- ОС: Ubuntu 22.04+
|
|
||||||
- RAM: 2 GB
|
**Команда деплоя** (из директории `apps/web`):
|
||||||
- Disk: 20 GB
|
```bash
|
||||||
- PostgreSQL 16 (или managed database)
|
vercel --prod --yes
|
||||||
- Node.js 20 LTS
|
```
|
||||||
|
|
||||||
|
**Требования:**
|
||||||
|
- Vercel CLI установлен глобально: `npm install -g vercel`
|
||||||
|
- Выполнен `vercel login` (однократно)
|
||||||
|
|
||||||
|
**Деплой занимает ~30 секунд.** После команды изменения сразу доступны по production URL.
|
||||||
|
|
||||||
|
### 12.3 Бэкенд и база данных
|
||||||
|
|
||||||
|
> TBD — параметры хостинга бэкенда (NestJS + PostgreSQL) будут определены к Sprint 11,
|
||||||
|
> когда потребуется работающий API для экспериментальной секции.
|
||||||
|
|
||||||
|
Варианты для рассмотрения: Railway, Render, VPS клиники.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -511,11 +537,12 @@ oclinica-brandbook/
|
|||||||
| № | Вопрос | Ответственный | Срок |
|
| № | Вопрос | Ответственный | Срок |
|
||||||
|----|--------------------------------------------------------------------------------------|---------------|----------|
|
|----|--------------------------------------------------------------------------------------|---------------|----------|
|
||||||
| ОВ-01 | Доступен ли JSON API или REST API на oclinica.ru? Каков формат ответов? | Клиника | Sprint 1 |
|
| ОВ-01 | Доступен ли JSON API или REST API на oclinica.ru? Каков формат ответов? | Клиника | Sprint 1 |
|
||||||
| ОВ-02 | Параметры хостинга для production-деплоя | Клиника | TBD |
|
| ОВ-02 | ~~Параметры хостинга для production-деплоя~~ **Закрыт:** фронтенд — Vercel Hobby (https://web-oclinica.vercel.app); бэкенд — TBD к Sprint 11 | — | Частично закрыт |
|
||||||
| ОВ-03 | Нужна ли страница «Заболевание» как отдельный тип, или это подвид страницы «Услуга»? | Клиника | Sprint 9 |
|
| ОВ-03 | Нужна ли страница «Заболевание» как отдельный тип, или это подвид страницы «Услуга»? | Клиника | Sprint 9 |
|
||||||
| ОВ-04 | Список иконок — какую стороннюю библиотеку утвердить? (Lucide, Heroicons, и др.) | Совместно | Sprint 2 |
|
| ОВ-04 | Список иконок — какую стороннюю библиотеку утвердить? (Lucide, Heroicons, и др.) | Совместно | Sprint 2 |
|
||||||
| ОВ-05 | ~~Нужен ли раздел «Логотип» в v1.0 или ждём вектор?~~ **Закрыт:** страница логотипа реализуется в Sprint 1 с PNG-версией; вектор будет добавлен позже | — | Закрыт |
|
| ОВ-05 | ~~Нужен ли раздел «Логотип» в v1.0 или ждём вектор?~~ **Закрыт:** страница логотипа реализуется в Sprint 1 с PNG-версией; вектор будет добавлен позже | — | Закрыт |
|
||||||
| ОВ-06 | HEX-эквиваленты цветов Oracal (053M, 073M, 066M, 050M, 081M, 080M) для использования в токенах | Совместно | Sprint 2 |
|
| ОВ-06 | ~~HEX-эквиваленты цветов Oracal~~ **Закрыт:** приблизительные HEX зафиксированы в Sprint 2 (053M=#7ecfca, 073M=#5b7b87, 066M=#5bb5ad, 050M=#1b4c72, 081M=#c4a882, 080M=#5c2e0e). Дополнительно — реальные цвета сайта извлечены из CSS (см. ОВ-07). Точная калибровка Oracal — при получении физических образцов. | — | Закрыт |
|
||||||
|
| ОВ-07 | **Цвета сайта oclinica.ru** — CSS тема Drupal доступна по адресу: `https://perm.oclinica.ru/sites/all/themes/clinic_bootstrap_mobile/css/style.css`. Тема: `clinic_bootstrap_mobile`. Ключевые цвета извлечены парсингом (python + regex + Counter), 2026-03-22. Добавлены в раздел «Цвета с сайта» в брендбуке (`/foundation/colors`). Расхождение с Oracal-палитрой ожидаемо — цифровые адаптации под экран. | — | Закрыт |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||