diff --git a/apps/web/app/foundation/colors/page.tsx b/apps/web/app/foundation/colors/page.tsx new file mode 100644 index 0000000..0988078 --- /dev/null +++ b/apps/web/app/foundation/colors/page.tsx @@ -0,0 +1,415 @@ +"use client"; + +import { useState, useCallback } from "react"; +import type { Metadata } from "next"; + +/* ─── Утилиты конвертации ──────────────────────────────────────────── */ +function hexToRgb(hex: string): { r: number; g: number; b: number } { + const m = /^#([0-9a-f]{6})$/i.exec(hex); + if (!m) return { r: 0, g: 0, b: 0 }; + return { + r: parseInt(m[1].slice(0, 2), 16), + g: parseInt(m[1].slice(2, 4), 16), + b: parseInt(m[1].slice(4, 6), 16), + }; +} + +function rgbToHsl(r: number, g: number, b: number): { h: number; s: number; l: number } { + r /= 255; g /= 255; b /= 255; + const max = Math.max(r, g, b), min = Math.min(r, g, b); + let h = 0, s = 0; + const l = (max + min) / 2; + if (max !== min) { + const d = max - min; + s = l > 0.5 ? d / (2 - max - min) : d / (max + min); + switch (max) { + case r: h = ((g - b) / d + (g < b ? 6 : 0)) / 6; break; + case g: h = ((b - r) / d + 2) / 6; break; + case b: h = ((r - g) / d + 4) / 6; break; + } + } + return { h: Math.round(h * 360), s: Math.round(s * 100), l: Math.round(l * 100) }; +} + +function luminance(r: number, g: number, b: number): number { + const a = [r, g, b].map(v => { + v /= 255; + return v <= 0.03928 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4); + }); + return a[0] * 0.2126 + a[1] * 0.7152 + a[2] * 0.0722; +} + +function contrastRatio(hex1: string, hex2: string): number { + const { r: r1, g: g1, b: b1 } = hexToRgb(hex1); + const { r: r2, g: g2, b: b2 } = hexToRgb(hex2); + const l1 = luminance(r1, g1, b1); + const l2 = luminance(r2, g2, b2); + const lighter = Math.max(l1, l2); + const darker = Math.min(l1, l2); + return Math.round(((lighter + 0.05) / (darker + 0.05)) * 10) / 10; +} + +/* ─── Данные цветов ────────────────────────────────────────────────── */ +const BRAND_COLORS = [ + { + oracal: "053M", + name: "Основной бирюзовый", + hex: "#7ecfca", + usage: "Акцентный цвет, CTA-кнопки, иконки, активные состояния", + cssVar: "--brand-053m", + }, + { + oracal: "073M", + name: "Тёмный серо-голубой", + hex: "#5b7b87", + usage: "Тёмный фон, хедер, акценты на тёмных поверхностях", + cssVar: "--brand-073m", + }, + { + oracal: "066M", + name: "Средний бирюзовый", + hex: "#5bb5ad", + usage: "Вторичные акценты, фоны секций, иллюстрации", + cssVar: "--brand-066m", + }, + { + oracal: "050M", + name: "Тёмно-синий", + hex: "#1b4c72", + usage: "Наружная реклама, полиграфия, заголовки на светлом фоне", + cssVar: "--brand-050m", + }, + { + oracal: "081M", + name: "Бежевый", + hex: "#c4a882", + usage: "Форма сотрудников, оффлайн носители, тёплые акценты", + cssVar: "--brand-081m", + }, + { + oracal: "080M", + name: "Тёмно-коричневый", + hex: "#5c2e0e", + usage: "Текст на бежевых поверхностях, логотип на форме", + cssVar: "--brand-080m", + }, + { + oracal: "—", + name: "Белый", + hex: "#ffffff", + usage: "Фон, инвертированный текст, логотип на тёмных фонах", + cssVar: "--brand-white", + }, +]; + +const CONTRAST_PAIRS = [ + { fg: "#ffffff", bg: "#5b7b87", label: "Белый на тёмном серо-голубом" }, + { fg: "#ffffff", bg: "#1b4c72", label: "Белый на тёмно-синем" }, + { fg: "#ffffff", bg: "#5c2e0e", label: "Белый на тёмно-коричневом" }, + { fg: "#ffffff", bg: "#5bb5ad", label: "Белый на среднем бирюзовом" }, + { fg: "#111827", bg: "#7ecfca", label: "Тёмный текст на основном бирюзовом" }, + { fg: "#111827", bg: "#c4a882", label: "Тёмный текст на бежевом" }, + { fg: "#5c2e0e", bg: "#c4a882", label: "Тёмно-коричневый на бежевом (форма)" }, +]; + +/* ─── Компоненты ───────────────────────────────────────────────────── */ +function CopyBadge({ value, label }: { value: string; label: string }) { + const [copied, setCopied] = useState(false); + const copy = useCallback(() => { + navigator.clipboard.writeText(value); + setCopied(true); + setTimeout(() => setCopied(false), 1500); + }, [value]); + return ( + + ); +} + +function ColorCard({ color }: { color: typeof BRAND_COLORS[0] }) { + const { r, g, b } = hexToRgb(color.hex); + const { h, s, l } = rgbToHsl(r, g, b); + const isLight = l > 55; + + return ( +
+ {/* Свотч */} +
+ {color.oracal !== "—" && ( + + Oracal {color.oracal} + + )} +
+ + {/* Информация */} +
+

+ {color.name} +

+

+ {color.usage} +

+ + {/* Коды */} +
+ + + + +
+
+
+ ); +} + +function ContrastRow({ pair }: { pair: typeof CONTRAST_PAIRS[0] }) { + const ratio = contrastRatio(pair.fg, pair.bg); + const aa = ratio >= 4.5; + const aaa = ratio >= 7; + const aaLarge = ratio >= 3; + + return ( +
+ {/* Превью */} +
+ Aa Бб Вв +
+ + {/* Описание */} +
+

+ {pair.label} +

+
+ + {pair.fg} / {pair.bg} + +
+
+ + {/* Ratio и бейджи */} +
+ + {ratio}:1 + +
+ {[ + { label: "AA", pass: aa }, + { label: "AAA", pass: aaa }, + { label: "AA large", pass: aaLarge }, + ].map(({ label, pass }) => ( + + {pass ? "✓" : "✕"} {label} + + ))} +
+
+
+ ); +} + +/* ─── Экспорт токенов ──────────────────────────────────────────────── */ +function exportTokens() { + const tokens: Record> = { colors: {} }; + BRAND_COLORS.forEach(c => { + const key = c.oracal !== "—" ? `brand-${c.oracal.toLowerCase()}` : "brand-white"; + const { r, g, b } = hexToRgb(c.hex); + const { h, s, l } = rgbToHsl(r, g, b); + tokens.colors[key] = { + oracal: c.oracal, + name: c.name, + hex: c.hex.toUpperCase(), + rgb: `rgb(${r}, ${g}, ${b})`, + hsl: `hsl(${h}, ${s}%, ${l}%)`, + cssVar: c.cssVar, + }; + }); + const blob = new Blob([JSON.stringify(tokens, null, 2)], { type: "application/json" }); + const url = URL.createObjectURL(blob); + const a = document.createElement("a"); + a.href = url; a.download = "oclinica-brand-tokens.json"; a.click(); + URL.revokeObjectURL(url); +} + +/* ─── Страница ─────────────────────────────────────────────────────── */ +export default function ColorsPage() { + return ( +
+ + {/* Заголовок */} +
+

+ Фундамент → 1.3 +

+

+ Цвета +

+

+ Фирменная цветовая палитра основана на кодах плёнки Oracal. HEX-значения + подобраны как ближайшие эквиваленты. Для точной печати используйте коды Oracal. +

+ +
+
+ ⚠️ + + HEX-значения приблизительны. Для оффлайн-носителей используйте + официальные коды Oracal. + +
+ +
+
+ + {/* 1. Палитра */} +
+
+

+ Фирменные цвета +

+

+ Нажмите на значение, чтобы скопировать его в буфер обмена. +

+
+
+ {BRAND_COLORS.map(c => ( + + ))} +
+
+ + {/* 2. Контрастность */} +
+
+

+ Контрастность пар (WCAG) +

+

+ Проверка соответствия требованиям доступности для основных комбинаций цветов. + AA = 4.5:1 для обычного текста, 3:1 для крупного (>18pt). +

+
+
+ {CONTRAST_PAIRS.map(pair => ( + + ))} +
+
+ + {/* 3. Применение */} +
+
+

+ Правила применения +

+
+
+ {[ + { + icon: "✓", + color: "#d1fae5", + textColor: "#065f46", + title: "Используйте фирменные цвета", + text: "Только цвета из палитры обеспечивают узнаваемость бренда на всех носителях.", + }, + { + icon: "✓", + color: "#d1fae5", + textColor: "#065f46", + title: "Соблюдайте контрастность", + text: "Текст на цветном фоне должен соответствовать минимум AA по WCAG 2.1.", + }, + { + icon: "✕", + color: "#fee2e2", + textColor: "#991b1b", + title: "Не смешивайте произвольно", + text: "Не используйте фирменные цвета с посторонними цветами без согласования.", + }, + { + icon: "✕", + color: "#fee2e2", + textColor: "#991b1b", + title: "Не изменяйте насыщенность", + text: "Осветление, затемнение или изменение оттенка недопустимо без необходимости.", + }, + ].map(item => ( +
+ + {item.icon} + +
+

+ {item.title} +

+

+ {item.text} +

+
+
+ ))} +
+
+ +
+ ); +} diff --git a/apps/web/app/foundation/typography/page.tsx b/apps/web/app/foundation/typography/page.tsx new file mode 100644 index 0000000..a88571a --- /dev/null +++ b/apps/web/app/foundation/typography/page.tsx @@ -0,0 +1,349 @@ +import type { Metadata } from "next"; + +export const metadata: Metadata = { + title: "Типографика | Брендбук О!Клиника", +}; + +/* ─── Шкала типографики ────────────────────────────────────────────── */ +const DIN_SCALE = [ + { token: "h1", size: "40px / 2.5rem", weight: "700", lh: "1.2", sample: "Клиника ухо, горло, нос" }, + { token: "h2", size: "32px / 2rem", weight: "700", lh: "1.25", sample: "Наши специалисты" }, + { token: "h3", size: "24px / 1.5rem", weight: "700", lh: "1.3", sample: "Запись на приём" }, + { token: "h4", size: "20px / 1.25rem",weight: "700", lh: "1.35", sample: "Расписание врачей" }, + { token: "h5", size: "16px / 1rem", weight: "700", lh: "1.4", sample: "Услуги и цены" }, + { token: "h6", size: "14px / 0.875rem",weight:"700", lh: "1.4", sample: "Контакты клиники" }, +]; + +const FIRA_SCALE = [ + { token: "h1", size: "40px / 2.5rem", weight: "600", lh: "1.2", sample: "Клиника ухо, горло, нос" }, + { token: "h2", size: "32px / 2rem", weight: "600", lh: "1.25", sample: "Наши специалисты" }, + { token: "h3", size: "24px / 1.5rem", weight: "600", lh: "1.3", sample: "Запись на приём" }, + { token: "h4", size: "20px / 1.25rem", weight: "500", lh: "1.35", sample: "Расписание врачей" }, + { token: "h5", size: "16px / 1rem", weight: "500", lh: "1.4", sample: "Услуги и цены" }, + { token: "h6", size: "14px / 0.875rem",weight: "500", lh: "1.4", sample: "Контакты клиники" }, + { token: "body", size: "16px / 1rem", weight: "400", lh: "1.6", sample: "ЛОР-клиника предоставляет полный спектр услуг по диагностике и лечению заболеваний уха, горла и носа." }, + { token: "body-sm", size: "14px / 0.875rem",weight: "400", lh: "1.6", sample: "Запись по телефону или через форму на сайте. Работаем без выходных." }, + { token: "caption", size: "12px / 0.75rem", weight: "400", lh: "1.5", sample: "Лицензия № ЛО-77-01-018234 от 12.01.2022" }, + { token: "label", size: "12px / 0.75rem", weight: "500", lh: "1.4", sample: "СПЕЦИАЛИЗАЦИЯ ВРАЧА" }, + { token: "overline", size: "10px / 0.625rem",weight: "600", lh: "1.4", sample: "ФУНДАМЕНТ → 1.4" }, +]; + +/* ─── Компоненты ───────────────────────────────────────────────────── */ +function Section({ + title, + subtitle, + children, +}: { + title: string; + subtitle?: string; + children: React.ReactNode; +}) { + return ( +
+
+

+ {title} +

+ {subtitle && ( +

+ {subtitle} +

+ )} +
+ {children} +
+ ); +} + +function UsageBadge({ label, color }: { label: string; color: string }) { + return ( + + {label} + + ); +} + +function TypeRow({ + token, + size, + weight, + lh, + sample, + fontFamily, +}: { + token: string; + size: string; + weight: string; + lh: string; + sample: string; + fontFamily: string; +}) { + const [sizeVal] = size.split(" / "); + const pxSize = parseInt(sizeVal); + + return ( +
+ {/* Токен */} +
+ + {token} + +
+ + {/* Образец */} +
+ {sample} +
+ + {/* Метаданные */} +
+

+ {size} +

+

+ w{weight} · lh{lh} +

+
+
+ ); +} + +/* ─── Страница ─────────────────────────────────────────────────────── */ +export default function TypographyPage() { + return ( +
+ + {/* Заголовок */} +
+

+ Фундамент → 1.4 +

+

+ Типографика +

+

+ Бренд использует два шрифта с чётким разделением по контексту применения. + Никогда не смешивайте их в одном носителе без необходимости. +

+
+ + {/* Карточки шрифтов */} +
+

+ Шрифты бренда +

+
+ {/* DINPro */} +
+
+
+

+ DINPro +

+

+ Бренд-шрифт · не Google Fonts +

+
+ +
+
+ Aa Бб Вв +
+

+ Применяется на: форме сотрудников, бейджах, вывесках, транспорте, + полиграфии. Лицензионный шрифт — передаётся дизайнером. +

+

+ --font-brand +

+
+ + {/* Fira Sans */} +
+
+
+

+ Fira Sans +

+

+ Веб-шрифт · Google Fonts +

+
+ +
+
+ Aa Бб Вв +
+

+ Применяется на: сайте oclinica.ru, в цифровом брендбуке, онлайн-материалах. + Подключён через next/font/google (кириллица + латиница). +

+

+ --font-web +

+
+
+
+ + {/* Таблица применения */} +
+

+ Правило применения +

+
+ + + + {["Носитель", "Шрифт"].map(h => ( + + ))} + + + + {[ + ["Сайт, цифровые материалы, брендбук", "Fira Sans"], + ["Форма сотрудников, бейджи", "DINPro"], + ["Вывески, таблички, навигация", "DINPro"], + ["Брендирование транспорта", "DINPro"], + ["Визитки, листовки, полиграфия", "DINPro"], + ["Telegram-бот, пуш-уведомления", "Fira Sans (системный)"], + ].map(([media, font]) => ( + + + + + ))} + +
+ {h} +
{media} + {font} +
+
+
+ + {/* DINPro Scale */} +
+
+ {DIN_SCALE.map(row => ( + + ))} +
+
+ + {/* Fira Sans Scale */} +
+
+ {FIRA_SCALE.map(row => ( + + ))} +
+
+ + {/* Живой пример */} +
+
+

+ Наши специалисты +

+

+ Запись к ЛОР-врачу
без очереди и ожидания +

+

+ В нашей клинике работают специалисты высшей категории с опытом от 15 лет. + Диагностика и лечение заболеваний уха, горла, носа и смежных органов. +

+

+ Лицензия № ЛО-77-01-018234 · Москва, ул. Примерная, д. 1 +

+
+
+ +
+ ); +} diff --git a/apps/web/app/offline/badges/page.tsx b/apps/web/app/offline/badges/page.tsx new file mode 100644 index 0000000..b749a2c --- /dev/null +++ b/apps/web/app/offline/badges/page.tsx @@ -0,0 +1,273 @@ +import type { Metadata } from "next"; +import Image from "next/image"; + +export const metadata: Metadata = { + title: "Бейджи | Брендбук О!Клиника", +}; + +function Section({ + title, + subtitle, + children, +}: { + title: string; + subtitle?: string; + children: React.ReactNode; +}) { + return ( +
+
+

+ {title} +

+ {subtitle && ( +

+ {subtitle} +

+ )} +
+ {children} +
+ ); +} + +/* Компонент бейджа (масштабированный макет) */ +function BadgeMockup({ + variant, + name, + role, +}: { + variant: "light" | "dark"; + name: string; + role: string; +}) { + const isDark = variant === "dark"; + /* 70×30 мм → пропорция 7:3. Отображаем в 280×120px */ + return ( +
+
+ {/* Логотип */} + Логотип + {/* Разделитель */} +
+ {/* Текст */} +
+

+ {name} +

+

+ {role} +

+
+
+

+ {isDark ? "Тёмный вариант (серо-голубой)" : "Светлый вариант (бежевый)"} +

+
+ ); +} + +export default function BadgesPage() { + return ( +
+ + {/* Заголовок */} +
+

+ Оффлайн элементы → 6.2 +

+

+ Бейджи сотрудников +

+

+ Именные бейджи для идентификации сотрудников клиники. Размер 70×30 мм. + Два цветовых варианта в зависимости от должности. +

+
+ + {/* Размеры и технические требования */} +
+
+ {[ + { label: "Ширина", value: "70 мм" }, + { label: "Высота", value: "30 мм" }, + { label: "Материал", value: "ПВХ / металл" }, + { label: "Крепление", value: "Булавка / клипса" }, + ].map(({ label, value }) => ( +
+

+ {value} +

+

+ {label} +

+
+ ))} +
+
+ + {/* Варианты */} +
+
+ + +
+
+ + {/* Состав текста */} +
+
+ + + + {["Элемент", "Содержание", "Шрифт / Размер", "Позиция"].map(h => ( + + ))} + + + + {[ + ["Логотип", "Логотип клиники", "PNG / SVG", "Левая часть, по центру по высоте"], + ["Разделитель", "Вертикальная линия", "1px, 40% прозрачность", "Между логотипом и текстом"], + ["ФИО", "Фамилия И.О.", "DINPro Bold 13px", "Правая часть, верхняя строка"], + ["Должность", "Полное название должности", "DINPro Regular 10px", "Правая часть, нижняя строка"], + ].map(([el, content, font, pos]) => ( + + + + + + + ))} + +
+ {h} +
{el}{content}{font}{pos}
+
+
+ + {/* Цветовые варианты */} +
+
+ {[ + { + variant: "Светлый (бежевый)", + color: "#c4a882", + usage: "Медицинский персонал, санитарки, технический персонал", + oracal: "081M", + }, + { + variant: "Тёмный (серо-голубой)", + color: "#5b7b87", + usage: "Административный персонал, менеджеры, главный врач", + oracal: "073M", + }, + ].map(item => ( +
+
+
+

+ {item.variant} +

+

+ {item.usage} +

+ + Oracal {item.oracal} + +
+
+ ))} +
+
+ +
+ ); +} diff --git a/apps/web/app/offline/navigation/page.tsx b/apps/web/app/offline/navigation/page.tsx new file mode 100644 index 0000000..b8f02ac --- /dev/null +++ b/apps/web/app/offline/navigation/page.tsx @@ -0,0 +1,252 @@ +import type { Metadata } from "next"; + +export const metadata: Metadata = { + title: "Внутренняя навигация | Брендбук О!Клиника", +}; + +function Section({ + title, + subtitle, + children, +}: { + title: string; + subtitle?: string; + children: React.ReactNode; +}) { + return ( +
+
+

+ {title} +

+ {subtitle && ( +

+ {subtitle} +

+ )} +
+ {children} +
+ ); +} + +/* Макет настенной таблички */ +function SignMockup({ + type, + text, + subtext, + bgColor, + textColor, + accentColor, + size, +}: { + type: string; + text: string; + subtext?: string; + bgColor: string; + textColor: string; + accentColor: string; + size: string; +}) { + return ( +
+
+ {/* Цветовая полоса */} +
+
+

+ {text} +

+ {subtext && ( +

+ {subtext} +

+ )} +
+
+
+

{type}

+

{size}

+
+
+ ); +} + +export default function NavigationPage() { + return ( +
+ + {/* Заголовок */} +
+

+ Оффлайн элементы → 6.3 +

+

+ Внутренняя навигация +

+

+ Система навигационных табличек и указателей внутри клиники. + Единый стиль с фирменными цветами и шрифтом DINPro. +

+
+ + {/* Шаблоны табличек */} +
+
+ + + + +
+
+ + {/* Технические требования */} +
+
+ + + + {["Параметр", "Значение"].map(h => ( + + ))} + + + + {[ + ["Основной материал", "ПВХ 3мм / ПС зеркальный / акрил"], + ["Покрытие фона", "Oracal плёнка (053M / 073M / 050M)"], + ["Шрифт", "DINPro Bold / Regular (DXF для фрезеровки)"], + ["Крепление", "Двусторонний скотч / шурупы с дистанционным держателем"], + ["Толщина букв (фрезеровка)", "3 мм от основы"], + ["Минимальный размер текста", "10 мм по высоте"], + ].map(([param, value]) => ( + + + + + ))} + +
+ {h} +
+ {param} + + {value} +
+
+
+ + {/* Цвета Oracal */} +
+
+ {[ + { code: "053M", hex: "#7ecfca", name: "Акцент / полоса" }, + { code: "073M", hex: "#5b7b87", name: "Фон указателей" }, + { code: "050M", hex: "#1b4c72", name: "Фон запрещающих" }, + { code: "081M", hex: "#c4a882", name: "Акцент на тёмном" }, + ].map(c => ( +
+
+
+

+ Oracal {c.code} +

+

+ {c.name} +

+

+ {c.hex} +

+
+
+ ))} +
+
+ +
+ ); +} diff --git a/apps/web/app/offline/print/page.tsx b/apps/web/app/offline/print/page.tsx new file mode 100644 index 0000000..bfbe2b5 --- /dev/null +++ b/apps/web/app/offline/print/page.tsx @@ -0,0 +1,331 @@ +import type { Metadata } from "next"; +import Image from "next/image"; + +export const metadata: Metadata = { + title: "Печатные материалы | Брендбук О!Клиника", +}; + +function Section({ + title, + subtitle, + children, +}: { + title: string; + subtitle?: string; + children: React.ReactNode; +}) { + return ( +
+
+

+ {title} +

+ {subtitle && ( +

+ {subtitle} +

+ )} +
+ {children} +
+ ); +} + +/* Макет визитки */ +function BusinessCardMockup({ side }: { side: "front" | "back" }) { + /* 90×50 мм → пропорция 9:5. Отображаем 288×160px */ + if (side === "front") { + return ( +
+ {/* Верхняя бирюзовая полоса */} +
+ +
+ {/* Левая колонка с логотипом */} +
+ Логотип +
+ + {/* Правая колонка с данными */} +
+

+ Иванова Анна Викторовна +

+

+ Врач-оториноларинголог +

+
+ {["+7 (495) 000-00-00", "oclinica.ru"].map(line => ( +

+ {line} +

+ ))} +
+
+
+
+ ); + } + + return ( +
+ Логотип на обороте +
+ ); +} + +/* Макет листовки */ +function LeafletMockup() { + /* А5 = 148×210 мм → пропорция ≈ 1:1.42. Отображаем 180×256px */ + return ( +
+ {/* Шапка */} +
+ Логотип +
+ + {/* Тело */} +
+ {/* Плейсхолдер фото */} +
+ {/* Заголовок */} +
+
+ {/* Текст-заглушка */} + {[100, 90, 95, 80].map((w, i) => ( +
+ ))} + {/* CTA-кнопка */} +
+

+ ЗАПИСАТЬСЯ НА ПРИЁМ +

+
+
+
+ ); +} + +export default function PrintPage() { + return ( +
+ + {/* Заголовок */} +
+

+ Оффлайн элементы → 6.5 +

+

+ Печатные материалы +

+

+ Листовки, визитки и digital-каналы клиники. Все материалы следуют + единому фирменному стилю с использованием шрифта DINPro и цветов Oracal. +

+
+ + {/* Визитки */} +
+
+
+ +

Лицевая сторона

+
+
+ +

Оборотная сторона

+
+
+ +
+ + + + {["Элемент", "Содержание"].map(h => ( + + ))} + + + + {[ + ["Лицевая — логотип", "Белый инвертированный на тёмно-серо-голубом фоне"], + ["Лицевая — ФИО", "DINPro Bold, 10pt, белый"], + ["Лицевая — должность", "DINPro Regular, 8pt, белый 70%"], + ["Лицевая — контакты", "DINPro Regular, 7pt, белый 60%"], + ["Оборотная", "Логотип тёмно-коричневый на бежевом фоне (081M)"], + ["Размер", "90 × 50 мм, 4+4 офсет или цифровая печать"], + ].map(([el, content]) => ( + + + + + ))} + +
{h}
{el}{content}
+
+
+ + {/* Листовки */} +
+
+ +
+

+ Структура листовки +

+
+ {[ + { zone: "Шапка", desc: "Логотип белый на тёмно-серо-голубом (073M)" }, + { zone: "Фото", desc: "Фото врача или процедуры, 70% ширины" }, + { zone: "Заголовок", desc: "DINPro Bold, тёмно-синий (050M), 18–22pt" }, + { zone: "Текст", desc: "DINPro Regular, 9–10pt, серый #374151" }, + { zone: "CTA-кнопка", desc: "Основной бирюзовый (053M), DINPro Bold белый" }, + ].map(({ zone, desc }) => ( +
+ + {zone} + +

{desc}

+
+ ))} +
+
+
+
+ + {/* Telegram-бот */} +
+
+
+ {[ + { icon: "🤖", title: "Запись на приём", desc: "Выбор врача, даты и времени через бот" }, + { icon: "📋", title: "Результаты анализов", desc: "Уведомления и просмотр результатов" }, + { icon: "💬", title: "Напоминания", desc: "Напоминание о предстоящем визите" }, + ].map(({ icon, title, desc }) => ( +
+ {icon} +
+

+ {title} +

+

{desc}

+
+
+ ))} +
+
+ В Telegram-боте используется системный шрифт Telegram. Логотип и цвета бренда + применяются в аватаре, приветственном изображении и кнопках меню. +
+
+
+ +
+ ); +} diff --git a/apps/web/app/offline/transport/page.tsx b/apps/web/app/offline/transport/page.tsx new file mode 100644 index 0000000..c63ce26 --- /dev/null +++ b/apps/web/app/offline/transport/page.tsx @@ -0,0 +1,262 @@ +import type { Metadata } from "next"; +import Image from "next/image"; + +export const metadata: Metadata = { + title: "Брендирование транспорта | Брендбук О!Клиника", +}; + +function Section({ + title, + subtitle, + children, +}: { + title: string; + subtitle?: string; + children: React.ReactNode; +}) { + return ( +
+
+

+ {title} +

+ {subtitle && ( +

+ {subtitle} +

+ )} +
+ {children} +
+ ); +} + +/* Макет трамвая (упрощённый силуэт) */ +function TramMockup() { + return ( +
+ {/* Кузов трамвая */} +
+ {/* Верхняя полоса — бирюзовая */} +
+ + {/* Основная бежевая полоса */} +
+ + {/* Нижняя полоса — серо-голубая */} +
+ + {/* Логотип по центру бежевой полосы */} +
+ Логотип на трамвае +
+ + {/* Окна (декоративные) */} + {[80, 180, 280, 380, 460].map(x => ( +
+ ))} + + {/* Колёса (декоративные) */} + {[60, 200, 360, 500].map(x => ( +
+ ))} +
+ +

+ Схема цветового решения (превью, не финальный макет) +

+
+ ); +} + +export default function TransportPage() { + return ( +
+ + {/* Заголовок */} +
+

+ Оффлайн элементы → 6.4 +

+

+ Брендирование транспорта +

+

+ Схема нанесения фирменной символики на трамвай и другой общественный транспорт. + Трёхполосная структура с логотипом клиники по центру. +

+
+ + {/* Макет */} +
+ +
+ + {/* Цветовая схема */} +
+
+ + + + {["Зона", "Цвет", "Oracal", "Высота", "Содержимое"].map(h => ( + + ))} + + + + {[ + ["Верхняя полоса", "#7ecfca", "053M", "~17% высоты", "Декоративная"], + ["Центральная полоса", "#c4a882", "081M", "~48% высоты", "Логотип клиники (по центру)"], + ["Нижняя полоса", "#5b7b87", "073M", "~35% высоты", "Декоративная / контактная информация"], + ].map(([zone, hex, oracal, height, content]) => ( + + + + + + + + ))} + +
+ {h} +
+ {zone} + +
+
+ + {hex} + +
+
+ {oracal} + {height}{content}
+
+
+ + {/* Логотип на транспорте */} +
+
+ {[ + { label: "Минимальная длина логотипа", value: "600 мм" }, + { label: "Отступ от краёв борта", value: "≥ 400 мм" }, + { label: "Вертикальное выравнивание", value: "По центру полосы" }, + { label: "Цвет логотипа", value: "Тёмно-коричневый (080M)" }, + ].map(({ label, value }) => ( +
+
+
+

{label}

+

{value}

+
+
+ ))} +
+
+ +
+ ⚠️ +

+ Финальные макеты для производства предоставляются дизайнером в форматах AI / PDF с + реальными размерами конкретного транспортного средства. +

+
+ +
+ ); +} diff --git a/apps/web/app/offline/uniform/page.tsx b/apps/web/app/offline/uniform/page.tsx new file mode 100644 index 0000000..062c12b --- /dev/null +++ b/apps/web/app/offline/uniform/page.tsx @@ -0,0 +1,207 @@ +import type { Metadata } from "next"; +import Image from "next/image"; + +export const metadata: Metadata = { + title: "Форма сотрудников | Брендбук О!Клиника", +}; + +function Section({ + title, + subtitle, + children, +}: { + title: string; + subtitle?: string; + children: React.ReactNode; +}) { + return ( +
+
+

+ {title} +

+ {subtitle && ( +

+ {subtitle} +

+ )} +
+ {children} +
+ ); +} + +export default function UniformPage() { + return ( +
+ + {/* Заголовок */} +
+

+ Оффлайн элементы → 6.1 +

+

+ Форма сотрудников +

+

+ Фирменная медицинская одежда сотрудников клиники. Бежевый костюм + с логотипом клиники на левой стороне груди. +

+
+ + {/* Описание костюма */} +
+
+
+
+

+ Состав формы +

+
    + {["Медицинский костюм (куртка + брюки)", "Цвет: бежевый (Oracal 081M)", "Материал: медицинская ткань", "Логотип вышит или нанесён термопечатью"].map(item => ( +
  • + {item} +
  • + ))} +
+
+
+

+ Цветовая схема +

+
+
+
+

081M

+

#c4a882

+
+
+
+

080M

+

#5c2e0e

+
+
+
+
+
+
+ + {/* Логотип на форме */} +
+ {/* Визуализация размещения */} +
+
+ {/* Силуэт куртки (упрощённая схема) */} +
+ {/* Зона логотипа — левая грудь */} +
+ Логотип на форме +
+

← Левая грудь

+
+
+
+

+ Схема размещения логотипа (превью) +

+
+ + {/* Таблица размеров */} +
+ + + + {["Размер одежды", "Длина логотипа", "Высота логотипа", "Расположение"].map(h => ( + + ))} + + + + {[ + ["До 46 р. включительно", "70 мм", "25,5 мм", "Левая сторона груди"], + ["От 48 р.", "90 мм", "32,8 мм", "Левая сторона груди"], + ].map(([size, w, h, pos]) => ( + + + + + + + ))} + +
+ {h} +
{size}{w}{h}{pos}
+
+
+ + {/* Правила */} +
+
+ {[ + { ok: true, text: "Носить комплект в полном составе" }, + { ok: true, text: "Поддерживать чистоту и опрятность формы" }, + { ok: true, text: "Логотип — только тёмно-коричневый на бежевом" }, + { ok: false, text: "Носить форму без логотипа" }, + { ok: false, text: "Изменять цвет или материал формы" }, + { ok: false, text: "Добавлять сторонние нашивки и знаки" }, + ].map(item => ( +
+ + {item.ok ? "✓" : "✕"} + +

+ {item.text} +

+
+ ))} +
+
+ +
+ ); +} diff --git a/apps/web/components/layout/Sidebar.tsx b/apps/web/components/layout/Sidebar.tsx index 429f157..f8c382a 100644 --- a/apps/web/components/layout/Sidebar.tsx +++ b/apps/web/components/layout/Sidebar.tsx @@ -19,8 +19,8 @@ const NAV: NavSection[] = [ title: "Фундамент", items: [ { label: "Логотип", href: "/foundation/logo" }, - { label: "Цвета", href: "/foundation/colors", soon: true }, - { label: "Типографика", href: "/foundation/typography", soon: true }, + { label: "Цвета", href: "/foundation/colors" }, + { label: "Типографика", href: "/foundation/typography" }, { label: "Иконография", href: "/foundation/icons", soon: true }, ], }, @@ -64,11 +64,11 @@ const NAV: NavSection[] = [ { title: "Оффлайн элементы", items: [ - { label: "Форма сотрудников", href: "/offline/uniform", soon: true }, - { label: "Бейджи", href: "/offline/badges", soon: true }, - { label: "Навигация", href: "/offline/navigation", soon: true }, - { label: "Транспорт", href: "/offline/transport", soon: true }, - { label: "Печать", href: "/offline/print", soon: true }, + { label: "Форма сотрудников", href: "/offline/uniform" }, + { label: "Бейджи", href: "/offline/badges" }, + { label: "Навигация", href: "/offline/navigation" }, + { label: "Транспорт", href: "/offline/transport" }, + { label: "Печать", href: "/offline/print" }, ], }, { @@ -171,7 +171,7 @@ export function Sidebar() { color: "var(--bb-sidebar-text-muted)", }} > - Sprint 1 · v0.1.0 + Sprint 2 · v0.2.0
); diff --git a/docs/SPRINTS.md b/docs/SPRINTS.md index 4a58168..1091079 100644 --- a/docs/SPRINTS.md +++ b/docs/SPRINTS.md @@ -53,30 +53,47 @@ --- -## Sprint 2 — Цвета, типографика и оффлайн элементы (Brand Foundation) +## Sprint 2 — Цвета, типографика и оффлайн элементы (Brand Foundation) ✅ ЗАВЕРШЁН **Цель:** Секция «Фундамент бренда» — цвета, оба шрифта, а также первый оффлайн-раздел. ### Задачи — цвета -- [ ] Design: Зафиксировать HEX-эквиваленты всех цветов бренда (053M, 073M, 066M, 050M, 081M, 080M) -- [ ] FE: Создать CSS-переменные / дизайн-токены для всей цветовой палитры -- [ ] FE: Страница «Цвета» — палитра с кодами Oracal/Pantone, HEX, RGB, HSL, копирование в клик -- [ ] FE: Проверка контрастности пар цветов (WCAG AA/AAA) -- [ ] FE: Экспорт токенов в JSON (Figma-compatible) +- [x] Design: Зафиксировать HEX-эквиваленты всех цветов бренда (053M, 073M, 066M, 050M, 081M, 080M) +- [x] FE: Создать CSS-переменные / дизайн-токены для всей цветовой палитры +- [x] FE: Страница «Цвета» — палитра с кодами Oracal/Pantone, HEX, RGB, HSL, копирование в клик +- [x] FE: Проверка контрастности пар цветов (WCAG AA/AAA) +- [x] FE: Экспорт токенов в JSON (Figma-compatible) ### Задачи — типографика -- [ ] FE: Страница «Типографика» — раздел DINPro (бренд/оффлайн) + раздел Fira Sans (веб) -- [ ] FE: Шкала размеров для обоих шрифтов: h1–h6, body, caption, label, overline -- [ ] FE: Чёткое указание: где DINPro, где Fira Sans -- [ ] FE: Живые примеры текста обоими шрифтами +- [x] FE: Страница «Типографика» — раздел DINPro (бренд/оффлайн) + раздел Fira Sans (веб) +- [x] FE: Шкала размеров для обоих шрифтов: h1–h6, body, caption, label, overline +- [x] FE: Чёткое указание: где DINPro, где Fira Sans +- [x] FE: Живые примеры текста обоими шрифтами ### Задачи — оффлайн элементы (справочный раздел) -- [ ] FE: Раздел «Оффлайн элементы» в навигации брендбука -- [ ] FE: Страница «Форма сотрудников» — фото, правила размещения логотипа, таблица размеров -- [ ] FE: Страница «Бейджи» — размеры 70×30 мм, варианты, состав текста -- [ ] FE: Страница «Внутренняя навигация» — шаблоны табличек, материалы, цвета Oracal -- [ ] FE: Страница «Брендирование транспорта» — макет трамвая, цветовая схема -- [ ] FE: Страница «Печатные материалы» — листовки, визитки, Telegram-бот +- [x] FE: Раздел «Оффлайн элементы» в навигации брендбука +- [x] FE: Страница «Форма сотрудников» — схема размещения логотипа, таблица размеров +- [x] FE: Страница «Бейджи» — размеры 70×30 мм, варианты (светлый/тёмный), состав текста +- [x] FE: Страница «Внутренняя навигация» — шаблоны табличек, материалы, цвета Oracal +- [x] FE: Страница «Брендирование транспорта» — макет трамвая, цветовая схема +- [x] FE: Страница «Печатные материалы» — листовки, визитки, Telegram-бот + +### Фактические результаты +- Страница `/foundation/colors` — 7 цветов с HEX/RGB/HSL/CSS-var и копированием, WCAG-контраст 7 пар, экспорт JSON +- Страница `/foundation/typography` — DINPro (оффлайн) + Fira Sans (веб), таблица применения, полные шкалы, живой пример +- Страница `/offline/uniform` — схема формы, таблица размеров логотипа, правила использования +- Страница `/offline/badges` — макеты бейджей 70×30 мм (светлый/тёмный), состав текста, применение +- Страница `/offline/navigation` — 4 шаблона табличек, технические требования, цвета Oracal +- Страница `/offline/transport` — CSS-макет трамвая с трёхполосной схемой, таблица зон +- Страница `/offline/print` — макеты визитки (лицо/оборот) и листовки А5, Telegram-бот +- Sidebar: убраны «скоро» для Цветов, Типографики и всех 5 страниц Оффлайн +- Версия обновлена до **Sprint 2 · v0.2.0** + +### Технические решения Sprint 2 +- Страница «Цвета» — `"use client"` для clipboard API и экспорта JSON +- WCAG relative luminance вычисляется на клиенте, без зависимостей +- DINPro отображается с фоллбэком Arial (лицензионный шрифт) +- Макеты (бейджи, трамвай, визитки) — чистый CSS/Tailwind без внешних зависимостей **Результат спринта:** Разделы «Цвета», «Типографика» и «Оффлайн элементы» полностью готовы.