73 KiB
VidConf — Дизайн-система
Дизайн зафиксирован как обязательный референс для реализации; изменения —
только через обновление этого документа и макетов design/mockups/. Оболочка
поддерживает светлую и тёмную тему с переключателем и автодетектом системной
темы (см. §0.1 и §1.2b ниже).
Референсы: referens.png (стиль/layout светлой оболочки), collor_ico.png (цвета/иконография тёмной комнаты конференции).
Все hex-значения взяты пипеткой непосредственно из референсов (см. таблицы ниже)
и проверены на контраст по формуле WCAG 2.1 (относительная светимость sRGB);
тёмная оболочка (§1.2b) — производная от уже утверждённой палитры комнаты
(hex переиспользованы 1:1, без повторной пипетки, см. таблицу происхождения).
0. Принцип тем
Оболочка (auth, лобби, календарь, «Мои конференции», join, админка, профиль, email) имеет две темы — светлую (дефолт) и тёмную, с ручным переключателем и автодетектом системной темы (см. §0.1). Комната конференции — всегда тёмная, отдельная тема без переключателя.
| Экраны | Референс | Характер | |
|---|---|---|---|
| Оболочка, светлая | auth, лобби (хаб действий), календарь (менеджер конференций), «Мои конференции», подключение по ссылке/номеру, админка, профиль, email | referens.png |
светлый фон, глубокий индиго в типографике, крупные скругления (20–32px), pill-кнопки с обводкой, пастельно-мятный CTA, glass-панели |
| Оболочка, тёмная | те же экраны оболочки | design/mockups/dark/ (утв. 2026-07-18), палитра — производная от collor_ico.png (см. §1.2b) |
графитовый фон, пастельная мята вместо индиго (бренд/заголовки/ссылки/CTA), розовый danger, янтарный warning/focus, те же формы/скругления/типографика, что у светлой оболочки — меняется только цвет |
| Комната (всегда тёмная) | room (конференция) | collor_ico.png |
графитовый фон, тёмно-серые плитки участников, зелёный/красный микрофон, жёлто-оранжевая рамка активного спикера, контурные иконки тулбара |
Темы не смешиваются на одном экране: комната конференции — единственный экран с собственной несменяемой тёмной темой; всё остальное — оболочка, которая целиком переключается между светлым и тёмным вариантом (пользователь никогда не видит светлую панель внутри тёмной оболочки или наоборот).
0.1 Механизм переключения (оболочка)
Контракт для frontend-dev (реализовано в design/tokens.css):
- Атрибут на корне —
data-theme="dark"/data-theme="light"на<html>(или другом предке:root-скоупа приложения) — явный выбор пользователя, сохраняется (localStorage/настройка профиля), имеет приоритет над системной темой. - Дефолт по ОС — если
data-themeне проставлен вообще, действует@media (prefers-color-scheme: dark): тёмная палитра активируется автоматически при тёмной системной теме, светлая — при светлой/отсутствии поддержки. Как только пользователь явно переключил тему, автодетект отключается для этого выбора (селектор:root:not([data-theme])вtokens.cssперестаёт совпадать). - Оба триггера переопределяют один и тот же набор переменных, что и
светлый
:root(--color-bg,--color-ink-900,--color-accentи т.д.) — весь остальной CSS оболочки (компоненты,frontend/) ссылается на них черезvar()и не нуждается в собственнойdark:-логике. [data-theme="room"](комната) — независимый третий скоуп с отдельным неймспейсом--color-room-*; не активируется ни атрибутомdark, ниprefers-color-scheme, и не участвует в переключателе оболочки.
Предустановленных переговорных комнат нет — конференции создаются динамически
(мгновенно из лобби или планово из календаря), закрепляются с повторением и
видны в «Мои конференции»; вход — по ссылке или номеру, гости входят через
«представиться». Макеты:
design/mockups/lobby.html, calendar.html, my-conferences.html, join.html.
1. Цветовые токены
Все значения продублированы 1:1 в tokens.css. Контраст текста проверен и
везде ≥ 4.5:1 (см. колонку «контраст»), кроме специально помеченных
декоративных/крупных элементов (правило WCAG для large text ≥ 3:1, отмечено ⚠︎).
1.1 Светлая тема (оболочка)
| Токен | Hex | Назначение | Контраст |
|---|---|---|---|
--color-bg |
#F1F1F1 |
фон страницы (пипетка referens.png, фон вокруг карточек) | — |
--color-bg-alt |
#F7F7F8 |
альтернативный фон секций / подложка полей | — |
--color-surface |
#FFFFFF |
карточки, модалки, поля ввода | — |
--color-surface-glass |
rgba(255,255,255,.55) |
glass-панели (стат-карточки в стиле referens.png), с backdrop-filter: blur(16px) |
— |
--color-border |
#E1E3E9 |
базовая обводка карточек/инпутов | — |
--color-border-strong |
#C7CCDC |
обводка при hover | — |
--color-border-pill |
#4A5A9E |
обводка pill-кнопок (пипетка контура «НАПРАВЛЕНИЕ») | — |
--color-ink-900 |
#2E3454 |
основной текст (параграфы), текст на CTA (--color-accent-text, см. ниже) |
11.3:1 на --color-bg-alt |
--color-ink-700 |
#3B4D95 |
брендовый индиго — дисплейные заголовки, ссылки (пипетка «X'FLOW GYM») | 6.9:1 на --color-bg |
--color-ink-500 |
#535F94 |
вторичный текст (подписи, мета) | 5.7:1 на --color-bg-alt |
--color-ink-400 |
#6976AC |
third-tier — только крупный/жирный текст (эйбрау-подписи в [скобках], ≥ 20px) | 4.1:1 ⚠︎ large-text-only |
--color-ink-300 |
#A6AECB |
плейсхолдеры, disabled-текст | — |
--color-accent |
#D4F2E3 |
пастельная мята CTA (заливка primary-кнопки; токен переименован из --color-accent-green, т.к. акцент больше не обязан быть зелёным) |
— |
--color-accent-hover |
#C7EBD9 |
hover CTA (переименовано из --color-accent-green-hover; осветлена на 50%, было #8FD6B2) |
— |
--color-accent-active |
#BAE4CE |
active/pressed CTA (переименовано из --color-accent-green-active; осветлена на 50%, было #74C89D) |
— |
--color-accent-text |
#2E3454 |
текст на мятной заливке — тёмный индиго, равен --color-ink-900 (переименовано из --color-accent-green-text) |
10.15:1 (default) / 9.40:1 (hover) / 8.69:1 (active) |
--color-success |
#0A7A4C |
текст статуса «свободна» | 5.38:1 на белом |
--color-success-bg |
#E4F7ED |
подложка бейджа «свободна» | — |
--color-success-dot |
#46916B |
индикатор-точка (пастелизирована, была неоновой #1BC46B; не единственный носитель статуса) |
3.80:1 на белом (нетекст) |
--color-danger |
#C7364F |
текст статуса «отменена», кнопки удаления | 5.16:1 на белом |
--color-danger-bg |
#FCE7EB |
подложка бейджа «отменена» | — |
--color-danger-dot |
#C65366 |
индикатор-точка (пастелизирована, была #E0526B) |
4.35:1 на белом (нетекст) |
--color-warning |
#7F560D |
текст статуса «запланирована» | 6.48:1 на белом |
--color-warning-bg |
#FBF0DC |
подложка бейджа «запланирована» | — |
--color-warning-dot |
#B58A26 |
индикатор-точка (углублена с #D6A83D ради контраста 3:1 на белом; рамка спикера в тёмной теме — отдельный токен, тот же исходный тон, оставлена без изменений) |
3.17:1 на белом (нетекст) |
--color-focus-ring |
#3B4D95 |
focus-visible обводка | — |
1.2a Тёмная тема — комната конференции
| Токен | Hex | Назначение | Контраст |
|---|---|---|---|
--color-room-bg |
#1E1E1E |
фон канвы конференции (пипетка collor_ico.png) | — |
--color-room-surface |
#2A2A2A |
топбар, нижний тулбар, всплывающие панели | — |
--color-room-surface-raised |
#333333 |
дропдауны, поповеры, панель чата | — |
--color-room-tile |
#363636 |
плитка участника (пипетка тёмно-серых плиток) | — |
--color-room-tile-border |
#3F3F3F |
обводка плитки в покое | — |
--color-room-tile-hover |
#3D3D3D |
плитка при hover/фокусе | — |
--color-room-text-primary |
#E8E8E8 |
имя участника, основной текст | 9.9:1 на tile |
--color-room-text-secondary |
#B0B0B0 |
вторичный текст (время, статус) | 5.6:1 на tile |
--color-room-text-tertiary |
#7A7A7A |
таймстемпы чата (декоративно, не единственный носитель смысла) | — |
--color-room-mic-on |
#7FDDA8 |
микрофон активен, пастельная мята (была неоновая #46D97A, тот же зелёный вектор, что и --color-accent в оболочке) |
8.76:1 на surface / 7.37:1 на tile (нетекст) |
--color-room-mic-off |
#EB93A1 |
микрофон выключен / mute, пастельный розово-красный (была #F2778C) |
6.30:1 на surface / 5.31:1 на tile (нетекст) |
--color-room-speaker-ring |
#D6A83D |
рамка активного спикера, жёлто-оранжевая (пипетка collor_ico.png) | 6.51:1 ⚠︎ декоративная рамка |
--color-room-danger |
#EB93A1 |
иконка «выйти», деструктивные контуры (пастелизирована вместе с mic-off) | 6.30:1 (нетекст) |
--color-room-danger-bg |
#B85468 |
заливка кнопки «Выйти» (hover/подтверждение), пастельная роза (была #B3384E) |
4.66:1 (белый текст) |
--color-room-danger-bg-hover |
#B9495F |
hover заливки danger (была #C24363) |
5.02:1 (белый текст) |
--color-room-focus-ring |
#D6A83D |
focus-visible обводка в тёмной теме | — |
Статусы никогда не передаются только цветом: у микрофона есть форма иконки
(перечёркнутый микрофон = mute), у бейджей лобби — иконка + текст, у активного
спикера — рамка + подпись, у конфликта брони — иконка AlertTriangle + текст.
1.2b Тёмная тема — оболочка
Макеты: design/mockups/dark/*.html (6
экранов, 1:1 разметка со светлыми прообразами design/mockups/*.html,
меняется только цвет — см. design/mockups/dark/README.md, полное
обоснование подбора палитры). Механизм переключения — §0.1.
Принцип. Тёмная оболочка не изобретает новых цветов, а переиспользует уже утверждённые токены комнаты (§1.2a) в новых ролях — так тёмное лобби и тёмная комната конференции читаются как одна система при переходе пользователя между ними. Там, где у комнаты нет готового аналога (бренд-панель, формы, glass- карточки — компоненты, которых в комнате не существует), значения получены подмешиванием уже утверждённых цветов комнаты к графитовому фону/друг к другу, а не придуманы независимо.
Токены, переиспользованные из комнаты 1:1 (тот же hex, что и --color-room-*, §1.2a):
Токен оболочки ([data-theme='dark']) |
= токен комнаты | Hex | Новая роль в оболочке |
|---|---|---|---|
--color-bg |
--color-room-bg |
#1E1E1E |
фон страницы |
--color-surface |
--color-room-surface |
#2A2A2A |
карточки, топбар, поля |
--color-border |
--color-room-tile-border |
#3F3F3F |
базовая обводка |
--color-ink-900 |
--color-room-text-primary |
#E8E8E8 |
основной текст |
--color-ink-500 |
--color-room-text-secondary |
#B0B0B0 |
вторичный текст |
--color-ink-300 |
--color-room-text-tertiary |
#7A7A7A |
плейсхолдеры/disabled |
--color-ink-700, --color-accent, --color-border-pill, --color-success, --color-success-dot |
--color-room-mic-on |
#7FDDA8 |
мята: бренд/заголовки/ссылки/CTA/«успех» — единая пастельно-зелёная роль (см. ниже) |
--color-danger, --color-danger-dot |
--color-room-mic-off |
#EB93A1 |
розово-красный: текст/иконки/обводка статуса «отменена»/ошибки |
--color-warning, --color-warning-dot |
--color-room-speaker-ring |
#D6A83D |
янтарь: статус «запланирована» |
--color-focus-ring |
--color-room-focus-ring |
#D6A83D |
кольцо :focus-visible |
--color-danger-solid, --color-danger-solid-hover |
--color-room-danger-bg(-hover) |
#B85468 / #B9495F |
заливка сплошных danger-кнопок (.btn-danger) — отдельная пара, см. ниже почему |
Одна мята — три роли. В светлой оболочке бренд-индиго (--color-ink-700)
и мятный CTA (--color-accent) — два разных токена/hex. В тёмной оболочке они
сведены к одному и тому же #7FDDA8 (= --color-room-mic-on), как и в
самой комнате, где одна пастельная мята уже покрывает всё «позитивное»
(микрофон вкл, демонстрация экрана, счётчик участников, отправка в чате).
Различие ролей (бренд-текст vs интерактивная заливка) остаётся читаемым за
счёт контекста, а не второго оттенка.
Почему заливка danger-кнопок — отдельный токен. В светлой теме один hex
(--color-danger, #C7364F) одинаково хорошо работает и как текст на белом,
и как заливка кнопки с белым текстом. В тёмной теме роли расходятся:
--color-danger (#EB93A1, светлый пастельный тон) отлично читается как
текст на тёмном фоне (6.30:1 на #2A2A2A), но слишком светлый для белого
текста кнопки поверх него (≈1.9:1, провал). Поэтому у тёмной оболочки
заведена отдельная пара --color-danger-solid / --color-danger-solid-hover
(#B85468 / #B9495F, контраст с белым текстом 4.66:1 / 5.02:1) — только для
сплошных danger-кнопок (.btn-danger: «Отменить все повторения» в календаре,
«Удалить» в админке). В светлой теме этот токен не заведён — компонент
.btn-danger там по-прежнему ссылается на --color-danger напрямую (§4.3),
т.к. проблема специфична для тёмной палитры.
Новые токены (введены там, где у комнаты нет готового компонента-аналога — формы, бренд-панель, glass-карточки; получены смешиванием уже утверждённых цветов комнаты, не придуманы независимо):
| Токен | Hex | Как получен | Контраст | Роль |
|---|---|---|---|---|
--color-bg-alt |
#242424 |
между --color-room-bg и --color-room-surface |
— | альт-фон секций, инпуты, disabled-поля |
--color-surface-glass |
rgba(51,51,51,.55) |
--color-room-surface-raised (#333333) с прозрачностью, по образцу светлой --color-surface-glass |
— | glass-панели (стат-виджеты) |
--color-border-strong |
#585858 |
осветление --color-border |
2.02:1 на surface (нетекст, декоративный hover-акцент, задублирован тенью — не единственный носитель состояния) | обводка при hover |
--color-ink-400 |
#5D9A78 |
мята #7FDDA8 × фон #1E1E1E, смешение 35% |
5.05:1 на bg / 4.35:1 на surface | эйбрау-подписи [ В СКОБКАХ ], крупные подписи |
--color-accent-hover |
#75CA9A |
мята × фон, смешение 10% | текст #10331F на заливке: 7.04:1 |
hover CTA |
--color-accent-active |
#6CB78C |
мята × фон, смешение 20% | текст #10331F на заливке: 5.80:1 |
active/pressed CTA |
--color-accent-text |
#10331F |
буквальный hex, уже встречающийся инлайн в room.html (.chat-input-row button, .tb-btn.is-positive-active, .badge-count) как цвет текста на --color-room-mic-on |
8.45:1 на мяте | текст на CTA/бренд-заливках мятой |
--color-success-bg |
rgba(127,221,168,.14) |
мята, низкая непрозрачность поверх тёмной поверхности | — | подложка бейджей «идёт сейчас»/«свободна»/«активен» |
--color-danger-bg |
rgba(235,147,161,.14) |
розовый (mic-off), низкая непрозрачность | — | подложка бейджей «отменена» |
--color-warning-bg |
rgba(214,168,61,.16) |
янтарь (speaker-ring), низкая непрозрачность | — | подложка бейджей «запланирована» |
--shadow-sm/md/lg/glass |
rgba(0,0,0,.35–.5) |
по образцу --shadow-room-panel комнаты (тёмные тени вместо индиго-тонированных) |
— | тени карточек/модалок/glass-панелей |
Компонентные исключения (не токены, точечные правки в самих макетах).
Пять мест, где CSS светлого макета использовал литеральный hex/rgba вместо
var() и поэтому не мог автоматически перекраситься — задокументированы в
design/mockups/dark/README.md (раздел «Точечные правки поверх скопированного
CSS»), в tokens.css не заводились как отдельные токены:
- Аватары/
.weekday-chip.is-selected/.badge-role-admin— заливкаvar(--color-ink-700)+ жёсткийcolor: #fffзаменены наvar(--color-accent-text)(белый на мятной заливке нечитаем). .btn-danger— заливкаvar(--color-danger-solid)вместоvar(--color-danger)(см. таблицу выше)..copy-toast(тултип «Скопировано») — фон былvar(--color-ink-900)(тёмный в светлой теме → стал бы светлым в тёмной, ломая тёмный чип- тултип); в макетах заменён на буквальный#333333(=--color-room-surface-raised). При переносе вfrontend/(реальный компонент на React, не статичная копия страницы) рекомендуется завести токен-алиас--color-surface-raisedпод обе темы, а не повторять этот литерал — тултип не единственное будущее место такой потребности.- Декоративные градиенты/rgba-подложки (бренд-панель
login.html, фонbodyвlobby.html,.day-col.is-today/.cancel-alertвcalendar.html, box-shadow фокуса/ошибки форм, glass-обводка) — тональные аналоги новой палитры (мятное свечение вместо индигового, янтарный focus-glow вместо индигового, розовый error-glow); та же практика уже используется в светлых макетах (см.auth.html— там эти значения тоже не токенизированы). color-scheme: dark— добавлен в активационный блокtokens.css(см. §0.1), чтобы нативные элементы форм (скроллбар, чекбоксы) тоже рендерились в тёмной палитре браузера.
Доступность. Текст ≥ 4.5:1 везде, кроме крупных/декоративных элементов
(правило §5, порог 3:1). Статус не передаётся только цветом (см. §1.2a).
Палитра пастельная, той же светлоты, что и утверждённая палитра комнаты —
неоновых/кислотных акцентов не вводилось. Регрессия — design/tools/contrast.py.
1.3 Проверка контраста
Палитра пастельная (не неоновая) во всей системе — все текстовые пары
проходят WCAG 2.1 (≥4.5:1, кроме отмеченных ⚠︎ декоративных/крупных
элементов, ≥3:1). Регрессионная проверка — скрипт design/tools/contrast.py
(явный список пар с ratio и порогом), запуск: python3 design/tools/contrast.py
— 24/24 пар PASS.
1.4 Логотип
Логотип — стилизованный объектив камеры, отсылка к видео как сути продукта.
Файлы:
design/logo.svg— мастер-версия, квадратный viewBox0 0 64 64, масштабируется без искажений. Для крупных начертаний: центральный медальон лобби, промо-материалы, шапка письма при экспорте в PNG высокого разрешения.design/favicon.svg— упрощённая версия для мелких размеров (16–32px): меньше колец, толще штрихи, чтобы силуэт не «замыливался». Используется как иконка в топбаре рядом со словом «VidConf» во всех макетах, а также как browser favicon / app-иконка продакшен-сборки.
Конструкция (обе версии):
- центр — плоский шестигранник (
polygon), закрытая диафрагма объектива, залита сплошным цветом; - вокруг — концентрические окружности (4 в мастер-версии, 1 в favicon),
каждая нарисована как
<circle>соstroke-dasharray/stroke-dashoffset, что даёт разорванные на сегменты дуги неровной длины и разной толщины штриха — техно/HUD-эстетика, ощущение вращения диафрагменных лепестков.
Цвет: строго монохром, один тон — currentColor, наследующий цвет
текста в месте использования (в проекте это всегда var(--color-ink-700),
#3B4D95). Никаких градиентов, бликов или цветов из референса-эскиза.
Контраст #3B4D95 на --color-bg (#F1F1F1) — 6.93:1, на --color-surface
(#FFFFFF) — 7.83:1 (обе пары — в design/tools/contrast.py, порог для
графики 3:1 — проходят с большим запасом даже как текстовый).
Использование в макетах:
- топбар/сайдбар (
.brand-mark) —favicon.svgинлайн,22×22px(соразмерно высоте строки словесного знака, заменяет прежний.logo-dot) во всех макетахdesign/mockups/*.html, где есть слово «VidConf»; - центральный медальон лобби (
.hub-logo) — полнаяlogo.svg,56×56pxвнутри медальона156×156px, вместе со словом «VidConf» под знаком (см. §4.12 «Карточка-действие хаба (лобби)» — геометрия перекрытия медальона); email-summary.html— инлайн SVG допустим только для HTML-макета; в продакшен-письме обязателен растровый PNG (почтовые клиенты в массе не рендерят инлайн-SVG), см. комментарий в файле рядом с разметкой.
1.5 Аватары (инициалы)
Круглый аватар с инициалами (.avatar, компонент Avatar §4) — заливка
всегда var(--color-ink-700) (основной, current-user — user-pill топбара,
сайдбар админки) либо var(--color-ink-500) (второстепенные, списки
участников — таблицы админки, участники встречи в письме-саммари). Текст
инициалов — всегда светлый, #FFFFFF, никогда не тёмный ink-900/
ink-700: тёмные инициалы на индиго-заливке дают нечитаемый, «слипшийся»
результат. Правило зафиксировано как регрессионные пары в
design/tools/contrast.py:
| Заливка | Текст | Контраст |
|---|---|---|
--color-ink-700 (#3B4D95) |
#FFFFFF |
7.83:1 |
--color-ink-500 (#535F94) |
#FFFFFF |
6.12:1 |
Обе пары — с большим запасом выше порога 4.5:1 для текста. Дополнительно:
font-weight инициалов — не ниже 600 (используется --text-caption,
600 12px), text-transform: none (кириллические инициалы не должны
проходить через uppercase-трансформацию родителя).
⚠ Предупреждение о каскаде CSS-специфичности. В
calendar.html и my-conferences.html правило .avatar-btn span { color: var(--color-ink-900); } (специфичность 0,1,1 — класс + тип-селектор) имело
специфичность ВЫШЕ, чем .avatar { color: #fff; } (0,1,0 — один класс), и
перебивало белый цвет у <span class="avatar"> (он тоже span внутри
.avatar-btn, значит попадал под общее правило .avatar-btn span) —
инициалы рендерились тёмным ink-900 на индиго-заливке, нечитаемо.
Специфичность решает независимо от порядка правил в файле, поэтому простое
переупорядочивание CSS не спасает. Правило на будущее: имя рядом с
аватаром — всегда через адресный класс (.user-name, не голый span),
никогда .wrapper span без уточнения — такой селектор непреднамеренно
задевает <span class="avatar">, если он лежит в той же обёртке. Проверено
headless-рендером (getComputedStyle(...).color) после фикса — rgb(255, 255, 255) в обоих файлах; заодно проверены admin.html, lobby.html
(структура другая — .avatar-btn div span/.user-pill .avatar, коллизии не
было) — там уже было rgb(255, 255, 255) и до правки.
2. Типографика
| Роль | Шрифт | Fallback-стек | Где |
|---|---|---|---|
| Дисплей (display) | Unbounded | 'Arial Rounded MT Bold', -apple-system, 'Segoe UI', sans-serif |
H1 лендинг-подобных блоков, крупные цифры дашборда, логотип |
| Текст (body/UI) | Inter | -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif |
вся UI-типографика: формы, таблицы, кнопки, параграфы |
| Моно (mono) | JetBrains Mono | 'SFMono-Regular', Menlo, Consolas, monospace |
код комнаты, ID брони, таймер конференции, .ics-детали |
Шрифты подключаются как самостоятельно захостенные (frontend/public/fonts,
@font-face с относительным путём), CDN Google Fonts не используется нигде
(в т.ч. в макетах) согласно правилу проекта «секреты и зависимости — не из
внешних сетей на рантайме». В tokens.css объявлены @font-face с путями
../fonts/..., отсутствие файлов в макетах безопасно деградирует в fallback-стек
без сетевых запросов.
Unbounded выбран за геометричные, слегка скруглённые формы букв — это то же
семейство характера, что у дисплейного заголовка в referens.png (широкие O/G/W,
единая толщина штриха). Inter — для плотного кириллического текста интерфейса
(отличная читаемость в мелких кеглях, стандарт де-факто для shadcn/ui).
Шкала
| Токен | Размер / line-height | Начертание | Применение |
|---|---|---|---|
--text-display-2xl |
64px / 1.05 | Unbounded 700 | Hero-заголовок (не используется в MVP-экранах, зарезервировано) |
--text-display-xl |
48px / 1.1 | Unbounded 700 | Крупные цифры (админ-дашборд, счётчики) |
--text-display-lg |
34px / 1.2 | Unbounded 600 | H1 экрана (заголовок лобби, «VidConf» в auth) |
--text-h1 |
28px / 1.25 | Inter 700 | заголовок карточки/секции |
--text-h2 |
22px / 1.3 | Inter 600 | подзаголовок |
--text-h3 |
18px / 1.35 | Inter 600 | заголовок компонента (карточка комнаты, панель) |
--text-body-lg |
16px / 1.5 | Inter 400/500 | основной текст форм |
--text-body |
14px / 1.5 | Inter 400/500 | таблицы, списки, вторичный UI |
--text-caption |
12px / 1.4, uppercase, letter-spacing: .04em |
Inter 600 | эйбрау-подписи [ В КВАДРАТНЫХ СКОБКАХ ], статус-бейджи |
--text-mono-sm |
13px / 1.4 | JetBrains Mono 500 | код комнаты/брони |
3. Spacing, радиусы, тени, границы
Spacing (8pt-грид с базой 4px)
--space-1: 4px · --space-2: 8px · --space-3: 12px · --space-4: 16px · --space-5: 20px · --space-6: 24px · --space-8: 32px · --space-10: 40px · --space-12: 48px · --space-16: 64px · --space-20: 80px · --space-24: 96px
Радиусы
Крупные скругления карточек взяты из referens.png (визуально 24–32px).
--radius-sm: 8px (инпуты, чипы) · --radius-md: 12px (кнопки не-pill, теги) ·
--radius-lg: 16px (плитки участников в комнате, пипетка collor_ico.png) ·
--radius-xl: 20px (малые карточки) · --radius-2xl: 24px (карточки комнат/лобби) ·
--radius-3xl: 32px (крупные панели, hero-блоки) · --radius-full: 999px
(pill-кнопки, аватары, бейджи-статусы)
Тени
--shadow-sm0 1px 2px rgba(46,52,84,.06)— лёгкий отрыв карточки от фона.--shadow-md0 4px 16px rgba(46,52,84,.08)— карточка при hover.--shadow-lg0 12px 32px rgba(46,52,84,.12)— модалки, поповеры.--shadow-glass0 8px 24px rgba(59,77,149,.15)+backdrop-filter: blur(16px)— glass-панели (стат-виджеты).--shadow-speaker-glow0 0 0 3px var(--color-room-speaker-ring), 0 0 24px rgba(214,168,61,.35)— свечение активного спикера (доп. к рамке).--shadow-room-panel0 8px 24px rgba(0,0,0,.4)— панель чата/поповеры в тёмной теме.
Границы
--border-thin: 1px (базовая) · --border-md: 1.5px (pill-кнопки) ·
--border-thick: 2px (hover/focus состояния) · --border-speaker: 3px
(рамка активного спикера).
Breakpoints (desktop-first)
--bp-desktop: 1440px — расчётная ширина макета. --bp-min: 1280px — минимальная
поддерживаемая ширина (контент перетекает, колонки не ломаются
до 1280px; мобильная адаптация — вне скоупа).
Motion
Только микро-переходы состояний (hover/focus/toggle), без декоративных
анимаций: --transition-fast: 120ms ease, --transition-base: 200ms ease.
4. Компоненты и их состояния
4.1 Кнопка Primary (pill CTA, светлая тема)
Форма: --radius-full, паддинг 12px 24px, шрифт --text-body-lg / Inter 600.
| Состояние | Фон | Текст | Обводка |
|---|---|---|---|
| default | --color-accent |
--color-accent-text |
нет |
| hover | --color-accent-hover |
тот же | нет, --shadow-md |
| active/pressed | --color-accent-active |
тот же | нет |
| focus-visible | как default | тот же | 2px --color-focus-ring, offset 2px |
| disabled | --color-ink-300 фон 40% |
--color-surface |
нет, cursor: not-allowed |
4.2 Кнопка Secondary (pill outline, светлая тема)
Прозрачный фон, обводка 1.5px --color-border-pill, текст --color-ink-700.
Hover: фон --color-bg-alt, обводка --color-ink-700. Focus-visible: кольцо
--color-focus-ring. Disabled: обводка --color-border, текст --color-ink-300.
4.3 Кнопка Danger (светлая тема, напр. «Удалить комнату» в админке)
Фон --color-danger, текст #FFFFFF, форма --radius-full. Hover — темнее на 8%.
Всегда сопровождается иконкой (Trash2), не только цветом.
4.4 Инпут / форма
Фон --color-surface, обводка 1px --color-border, радиус --radius-md,
паддинг 10px 14px, текст --text-body-lg.
| Состояние | Обводка | Доп. |
|---|---|---|
| default | --color-border |
— |
| hover | --color-border-strong |
— |
| focus | 2px --color-focus-ring |
подпись-хинт индиго |
| error | 2px --color-danger |
текст ошибки под полем, иконка AlertCircle слева |
| disabled | --color-border, фон --color-bg-alt |
текст --color-ink-300 |
4.5 Карточка (светлая тема)
Фон --color-surface, радиус --radius-2xl, обводка 1px --color-border,
тень --shadow-sm (по умолчанию) → --shadow-md (hover, если карточка кликабельна).
Glass-вариант (стат-виджеты): --color-surface-glass + backdrop-filter: blur(16px)
--shadow-glass, обводка1px rgba(255,255,255,.6).
4.6 Бейдж статуса конференции (календарь, «Мои конференции»)
Бейдж описывает жизненный цикл КОНФЕРЕНЦИИ (комнат в системе нет). Pill (--radius-full),
паддинг 4px 12px (мелкий вариант в сетке календаря — 2px 9px, font-size: 11px),
--text-caption, иконка 12–14px слева от текста.
| Статус | Фон | Текст | Иконка |
|---|---|---|---|
| Запланирована (разовая) | --color-warning-bg |
--color-warning |
Clock |
| Закреплена · повторяется | --color-bg-alt, обводка 1px --color-border-strong |
--color-ink-700 |
Repeat |
| Идёт сейчас | --color-success-bg |
--color-success |
Play |
| Завершена | --color-bg-alt |
--color-ink-500 |
CheckCircle2 |
| Отменена | --color-danger-bg |
--color-danger |
X, заголовок карточки — line-through |
Закрытость паролем — НЕ отдельный статус жизненного цикла (ортогональна ему:
запланированная, закреплённая или идущая сейчас конференция может быть
закрытой одновременно). Отображается отдельно — маленькая иконка Lock
(13–15px, --color-ink-700/--color-room-text-secondary) инлайном перед
названием конференции, не бейджем.
4.7 Плитка участника (комната, тёмная тема)
Фон --color-room-tile, радиус --radius-lg, обводка 1px --color-room-tile-border.
Имя — верхний левый угол, --text-body / --color-room-text-primary, поверх
полупрозрачной подложки-градиента снизу-вверх для читаемости на видео.
Иконка микрофона — нижний левый угол, 20px, круглая подложка rgba(0,0,0,.35).
| Состояние | Обводка/эффект | Микрофон |
|---|---|---|
| default (не говорит) | --color-room-tile-border |
Mic зелёный, если не muted |
| активный спикер | --border-speaker --color-room-speaker-ring + --shadow-speaker-glow |
форма рамки — единственный, кто её имеет |
| muted | обводка как default | MicOff --color-room-mic-off, иконка перечёркнута (не только цвет) |
| видео выключено | вместо видео — аватар-заглушка на --color-room-tile-hover |
значок VideoOff в углу |
| pinned/развёрнута | увеличенный размер в сетке, иконка Pin активна |
— |
| hover (крупная плитка) | показывается toolbar-оверлей (Maximize2, MoreVertical) |
— |
4.8 Нижний тулбар комнаты (тёмная тема)
Фон --color-room-surface, высота 72px, иконки контурные 24px, подпись под
иконкой --text-caption --color-room-text-secondary.
| Кнопка | Цвет по умолчанию | Toggled-off/mute | Позитивное действие |
|---|---|---|---|
| Микрофон | --color-room-text-primary outline |
фон --color-room-mic-off заливка, иконка MicOff |
— |
| Камера | --color-room-text-primary outline |
фон --color-room-mic-off, иконка VideoOff |
— |
| Демонстрация экрана | --color-room-text-primary outline |
— | active-состояние: иконка/подпись --color-room-mic-on |
| Чат | --color-room-text-primary outline |
— | активна (панель открыта): подложка --color-room-surface-raised |
| Участники | --color-room-text-primary outline |
— | бейдж-счётчик --color-room-mic-on |
| Выйти | обводка --color-room-danger |
— | всегда красная, hover → заливка --color-room-danger-bg |
4.9 Панель чата (комната)
Свёрнута: не занимает места, доступна кнопкой в тулбаре (см. 4.8).
Развёрнута: правая колонка 320px, фон --color-room-surface-raised,
разделитель 1px --color-room-tile-border, сетка участников сужается.
Сообщения — пузыри --color-room-tile, имя автора --color-room-mic-on
(лёгкий акцент, не критично для контраста т.к. декоративно), текст
--color-room-text-primary.
4.10 Ячейка календаря-менеджера
Календарь не бронирует переговорные (нет привязки к комнате, нет конфликтов
брони по EXCLUDE-констрейнту БД) — это менеджер запланированных/закреплённых
КОНФЕРЕНЦИЙ. Единица сетки —
дневная колонка (--radius-lg, фон --color-bg-alt, min-height: 460px),
внутри — стопка карточек-конференций («чипов», --radius-md, --text-body).
| Состояние | Фон/обводка | Текст/иконка |
|---|---|---|
| День без конференций | колонка --color-bg-alt |
подпись-заглушка --color-ink-300 по центру («Свободный день» / «Ещё нет конференций») |
| Сегодняшняя колонка | лёгкая подсветка rgba(212,242,227,.16) (тон --color-accent) |
заголовок дня --color-ink-700 |
| Чип конференции (default) | --color-surface, обводка 1px --color-border |
бейдж статуса §4.6 сверху, hover → --shadow-sm + --color-border-strong |
| Чип отменённой конференции | как default, opacity: .6 |
заголовок line-through, --color-ink-500 |
| Закрытая паролем | как default | иконка Lock инлайн перед названием (см. §4.6) |
4.11 Таблица (админка)
Заголовок --color-bg-alt, --text-caption uppercase --color-ink-500.
Строки — разделитель 1px --color-border, hover-строка --color-bg-alt.
Действия — icon-button (Pencil, Trash2, Mail) 32px, --radius-md.
4.12 Карточка-действие хаба (лобби)
Лобби — хаб из 4 плиток-действий вокруг медальона VidConf
(design/mockups/lobby.html), а не список комнат. Фон --color-surface,
радиус --radius-3xl, обводка 1px --color-border, тень --shadow-sm.
Фиксированная высота (не min-height) у всех 4 плиток — обязательное
условие строгой симметрии сетки 2×2 независимо от длины текста внутри.
Тайл 816×340px (при доступной ширине ≥ ~1728px; на меньших вьюпортах,
вплоть до --bp-min: 1280px, сетка пропорционально сжимается через
width: min(1664px, 100%) на контейнере .hub, оставаясь строго
симметричной 2×2, без переполнения); контейнер .hub — 1664px, gap между
тайлами — --space-8 (32px). Типографика внутри: заголовок 40px/1.2
(54px/1.1 для акцентной плитки «Создать»), подпись-объект 21px,
примечание 17px.
Медальон-иконка (68px, круг, обводка --border-thick --color-ink-700)
вынесен на верхнюю кромку карточки (position: absolute; top: -34px),
под него на самой карточке зарезервирован margin-top: 34px. Заголовок
--color-ink-700, uppercase; подзаголовок-объект --color-ink-900;
примечание --color-ink-500.
Главное действие («Создать») — акцентный вариант на пастельной мяте
(--color-accent), текст и медальон — --color-accent-text.
| Состояние | Фон (обычная / акцентная) | Эффект |
|---|---|---|
| default | --color-surface / --color-accent |
--shadow-sm |
| hover | тот же / --color-accent-hover |
--shadow-lg, translateY(-4px) |
| active | тот же / --color-accent-active |
translateY(-1px) |
| focus-visible | тот же | кольцо --color-focus-ring, offset 2px |
Медальон VidConf в центре — декоративный (pointer-events: none,
aria-hidden), диаметр 156px, фон --color-surface
(непрозрачный), обводка --border-thick --color-ink-700, тень
--shadow-lg, z-index: 20 (гарантированно поверх карточек). Содержимое —
знак объектива logo.svg (56×56px, §1.4) + слово «VidConf» под ним
(600 16px var(--font-display), --color-ink-700).
Медальон не просто сидит в промежутке сетки, а лежит поверх равных по
величине частей видимых углов всех 4 карточек. Геометрия фиксированная (в пикселях,
не в процентах — высота .hub всегда 2×340 + 32 = 712px, независимо от
ширины вьюпорта):
- по горизонтали асимметрии нет — центр строго на границе колонок,
16px(половинаgap) до ближнего края каждой карточки; - по вертикали — видимый низ карточек ряда 1 на
y = 340pxот верха.hub, видимый верх карточек ряда 2 наy = 406px(gap32px +margin-top34px карточки под собственный медальон-иконку); равноудалённая от обеих точка —y = 373px(33pxдо каждой), а не геометрический центр сетки356px(712 / 2), — из-за несимметричного резерва под action-icon только у нижнего ряда.
Медальон центрирован в (50%, 373px) (top: 373px; left: 50%; transform: translate(-50%, -50%)), а не (50%, 50%). Такая точка —
зеркально-симметричная по обеим осям относительно всех 4 карточек (что
подтверждается тем, что сдвиг 16px/33px — общий для обеих карточек по
каждой оси, а не индивидуальный для одной), поэтому перекрытие получается
одинаковым на все 4 угла по построению, без ручной подгонки под каждый
угол. Проверено headless-рендером (Playwright/Chromium, 1280/1440/1728px):
перекрытие видимой (с учётом скругления --radius-3xl, 32px) части каждой
из 4 карточек — 29.2px, идентично на всех четырёх и на всех проверенных
ширинах вьюпорта (симметрия по x/y — расхождение 0px).
4.13 Карточка создания конференции (календарь)
Фон --color-surface, радиус --radius-2xl, паддинг --space-6, sticky
в двухколоночном layout календаря. Поля «Название / Дата / Время /
Участники» — стандартный инпут §4.4. Два тумблера общего компонента
.switch/.slider (заливка --color-accent-active во включённом состоянии):
- «Закрытая по паролю» — раскрывает поле пароля под тумблером.
- «Закрепить постоянную конференцию» — раскрывает блок повторений (§4.14) со всеми 4 вариантами сразу.
Оба раскрытия — чистый CSS через :has() (без JS): тумблер и раскрываемый
блок — сиблинги внутри общего .pin-block/.toggle-block,
:has(input:checked) .sub-block { display: … }. При адаптации на
frontend/ — то же поведение через useState/controlled-компонент.
4.14 Блок повторений (recurrence)
Раскрывается под тумблером «Закрепить постоянную конференцию» (§4.13),
отделён 1px dashed --color-border. Список из 4 вариантов
(.recurrence-option, radio-группа — выбран ровно один):
| Вариант | Доп. поля | Обязательная подсказка (edge cases) |
|---|---|---|
| По дням недели, еженедельно | 7 круглых чипов дней недели (34px, множественный выбор) | ближайшие 2 даты вхождения |
| Раз в 2 недели | дата начала + день недели | ближайшие 2 даты вхождения |
| Раз в месяц | число месяца (1–31) | «если в месяце нет такого числа — переносится на последний день месяца» (31-е число, 29 февраля) |
| Каждые N дней | целое N + дата начала | ближайшие даты вхождения («через N, 2N, 3N дней») |
Строка варианта: --radius-md, обводка 1px --color-border → при выборе
обводка --color-ink-700 + фон --color-bg-alt (через :has(input:checked),
см. §4.13). Под-поля выбранного варианта раскрываются тем же CSS-приёмом;
у невыбранных — скрыты (display: none), а не задизейблены — чтобы список
из 4 строк был виден целиком сразу после раскрытия тумблера. Выбранный день недели/чип — заливка --color-ink-700, текст
белый. Подсказки — 12px, --color-ink-500.
4.15 Пилюли «ссылка / номер» с копированием
Новый компонент «Моих конференций»: у каждой конференции есть постоянная
ссылка и человеко-диктуемый номер, доступные для копирования одним кликом.
Подпись-заголовок над пилюлей — --text-caption, --color-ink-400
(«Ссылка» / «Номер»). Пилюля — --radius-full, фон --color-bg-alt,
обводка 1px --color-border; значение — --text-mono-sm --color-ink-700,
обрезается text-overflow: ellipsis (для длинных ссылок). Кнопка
копирования — круг 28px справа внутри пилюли.
| Состояние кнопки копирования | Иконка | Доп. |
|---|---|---|
| default | Copy, --color-ink-500 |
— |
| hover | Copy, --color-ink-700 |
--shadow-sm |
| скопировано (~1.5s) | Check, --color-success |
всплывающая подсказка «Скопировано» над кнопкой |
| focus-visible | как default | кольцо --color-focus-ring |
Статус «скопировано» не передаётся только сменой цвета иконки — обязательно
дублируется сменой формы иконки (Copy → Check) и текстовым тултипом.
4.16 Селект (кастомный выпадающий список)
Заменяет нативный <select> в полях
«Рассылка саммари» (карточка создания/редактирования конференции, §4.13) и
«Получатели по умолчанию» (настройки админки), а также любой будущий
одиночный выбор из списка. Собран из уже утверждённых примитивов — триггер
переиспользует геометрию инпута (§4.4), дроплист переиспользует паттерн
.menu (выпадающее меню бургера лобби, design/mockups/lobby.html), пункт
списка — паттерн .menu a. Ничего нового в токенах не заводится.
Триггер (закрытое состояние). Высота 44px (паддинг 10px 14px +
--text-body-lg при line-height: 1.5 — идентично инпуту §4.4, чтобы
селект и текстовые поля в одной форме были на одной высоте), фон
--color-surface, обводка 1px --color-border, радиус --radius-md.
Значение слева, шеврон ChevronDown (18px, --color-ink-500) прижат
вправо. Текст — --text-body-lg --color-ink-900; если значение не
выбрано — плейсхолдер --color-ink-300 (та же роль токена, что у
плейсхолдера инпута).
| Состояние | Обводка/фон | Текст/шеврон | Доп. |
|---|---|---|---|
| default | --color-border |
--color-ink-900 / шеврон --color-ink-500 |
— |
| hover | --color-border-strong |
те же | курсор pointer |
| focus-visible (закрыт) | 2px --color-focus-ring |
те же | как фокус инпута §4.4 |
| открыт | 2px --color-focus-ring, нижние углы дроплиста продолжают радиус триггера визуально (панель — отдельный блок, см. ниже) |
шеврон повёрнут rotate(180deg), --transition-fast |
aria-expanded="true" |
| error | 2px --color-danger |
текст --color-ink-900 |
текст ошибки под полем + AlertCircle слева от значения, как у инпута §4.4 |
| disabled | --color-border, фон --color-bg-alt |
текст и шеврон --color-ink-300 |
курсор not-allowed, aria-disabled="true" |
Дроплист (открытое состояние). position: absolute, top: calc(100% + 6px),
ширина равна триггеру (width: 100%, в отличие от .menu, у которого
min-width фиксирован — селект обязан совпадать по ширине с полем, иначе
теряется визуальная связь триггер↔панель). Фон --color-surface, обводка
1px --color-border, радиус --radius-lg, тень --shadow-lg, внутренний
паддинг --space-2 (8px), z-index: 30 (над соседними карточками формы).
Список длиннее ~7 пунктов — max-height: 280px; overflow-y: auto со
стандартным скроллбаром (не кастомизируется, см. color-scheme в
tokens.css, влияет на нативный скроллбар браузера в обеих темах).
Пункт списка (role="option"): паддинг 10px 14px, радиус --radius-sm,
--text-body-lg 400, текст --color-ink-900, display: flex; justify-content: space-between
(значение слева, место под иконку Check справа).
| Состояние пункта | Фон | Текст | Доп. индикатор |
|---|---|---|---|
| default (не выбран, не наведён) | прозрачный | --color-ink-900 |
— |
hover / клавиатурная подсветка (aria-activedescendant) |
--color-bg-alt |
--color-ink-700 |
— |
выбран (aria-selected="true") |
прозрачный (или --color-bg-alt, если одновременно наведён/подсвечен — состояния комбинируются аддитивно) |
--color-ink-900, font-weight: 600 |
иконка Check (16px, --color-ink-700) справа — «выбрано» никогда не передаётся только фоном/цветом |
| disabled-пункт | прозрачный | --color-ink-300 |
cursor: not-allowed, aria-disabled="true", без hover-эффекта |
Опциональный разделитель групп внутри списка — тот же приём, что
.menu-divider: 1px --color-border, margin: var(--space-2) 6px.
Клавиатурная доступность и ARIA. Паттерн — listbox-combobox
(role="combobox" на триггере + role="listbox" на панели), без нативного
<select>, чтобы стилизация дроплиста была полностью в токенах проекта.
| Действие | Клавиша | Поведение |
|---|---|---|
| Открыть список | Enter, Space, ArrowDown, ArrowUp (фокус на триггере, список закрыт) |
раскрывает дроплист; подсветка ставится на выбранный пункт (если значения ещё нет — на первый) |
| Навигация | ArrowDown / ArrowUp (список открыт) |
двигает клавиатурную подсветку на следующий/предыдущий пункт (циклически не переходит с последнего на первый), обновляет aria-activedescendant триггера — фокус физически остаётся на триггере |
| К началу/концу | Home / End |
подсветка на первый/последний доступный (не disabled) пункт |
| Быстрый переход | ввод буквы | подсветка прыгает на ближайший следующий пункт, начинающийся с введённого символа (стандартное ожидание пользователей от <select>) |
| Выбрать и закрыть | Enter, Space (на подсвеченном пункте) |
фиксирует значение, закрывает панель, фокус остаётся на триггере, aria-expanded="false" |
| Закрыть без изменений | Esc |
закрывает панель, значение не меняется, фокус остаётся на триггере |
| Закрыть без изменений | клик вне триггера/панели, Tab |
панель закрывается, значение не меняется (если пункт не был явно выбран через Enter/клик) |
ARIA-контракт: триггер — role="combobox", aria-haspopup="listbox",
aria-expanded, aria-controls="<id панели>", aria-labelledby/aria-label
(подпись поля, как у инпута §4.4); панель — role="listbox",
aria-activedescendant на триггере указывает на id текущего подсвеченного
role="option"; каждый пункт — aria-selected, disabled-пункты —
aria-disabled="true" и исключены из навигации стрелками/type-ahead.
Обе темы. Компонент целиком собран из уже описанных выше токенов
(--color-surface, --color-border(-strong), --color-ink-*,
--color-focus-ring, --color-danger, --shadow-lg, --radius-md/lg/sm),
которые уже переключаются между светлой и тёмной оболочкой по механизму
§0.1 — отдельной тёмной версии спеки не требуется. Прецедент — .menu
(дроплист бургер-меню лобби): его CSS в design/mockups/lobby.html и
design/mockups/dark/lobby.html побайтово идентичен, меняется только
подстановка переменных из tokens.css; Select использует ту же панель
целиком на var(), поэтому корректно рендерится в тёмной теме без правок.
В тёмной оболочке фон панели/триггера — графитовый --color-surface
(#2A2A2A), подсветка пункта — --color-bg-alt (#242424), выбранный
пункт и hover-текст — пастельная мята --color-ink-700 (#7FDDA8), кольцо
фокуса — янтарь --color-focus-ring (#D6A83D), см. §1.2b.
5. Доступность
- Текст ≥ 4.5:1 везде, кроме крупных декоративных элементов (отмечены ⚠︎ выше, ≥ 3:1 по правилу WCAG для large text).
- Статус всегда дублируется не цветом: иконка (статус конференции §4.6, mic on/off, «скопировано» при копировании ссылки/номера) + текстовая подпись.
:focus-visible— везде видимое кольцо (--color-focus-ringсветлая тема,--color-room-focus-ringтёмная), никогдаoutline: noneбез замены.- Интерактивные элементы ≥ 40×40px области клика (кнопки тулбара — 48×48px).
- Все декоративные SVG-иконки —
aria-hidden="true", интерактивные — сaria-labelна кнопке-обёртке. - Логотип (§1.4) в топбаре —
role="img" aria-label="VidConf"на SVG внутри.brand-mark, где рядом уже есть текстовое «VidConf» — SVG физически декоративен (aria-hidden="true"в разметке), словесный знак читает скринридер. Медальон лобби — весь блокaria-hidden="true"(дублирует бренд, не несёт уникальной информации). - Аватары с инициалами (§1.5) — текст инициалов всегда светлый (
#FFFFFF) на заливке--color-ink-700/--color-ink-500, ≥ 4.5:1 (см.design/tools/contrast.py).
6. Имплементация для frontend-dev
shadcn/ui
Тема подключается через CSS-переменные tokens.css, а не через хардкод в
tailwind.config. Компоненты shadcn/ui кастомизировать так:
| shadcn/ui компонент | Что переопределить | Токены |
|---|---|---|
Button |
варианты default (pill CTA), outline (pill secondary), destructive, ghost (иконки тулбара) |
--color-accent*, --color-border-pill, --color-danger*, --radius-full |
Input, Textarea |
border/focus/error-состояния | --color-border, --color-focus-ring, --color-danger |
Card |
радиус, тень, glass-вариант отдельным классом .card-glass |
--radius-2xl, --shadow-sm/md, --shadow-glass |
Badge |
варианты success / danger / warning / neutral под статусы конференций (§4.6) |
цвета из 1.1 |
Dialog / Sheet |
модалка брони, панель чата (Sheet справа в тёмной теме) | --shadow-lg, --color-room-surface-raised |
Select (кастомный, §4.16, не нативный <select>) |
триггер как Input (§4.4), дроплист — паттерн .menu (лобби) |
триггер --radius-md; панель --radius-lg + --shadow-lg; пункт --radius-sm; --color-border, --color-focus-ring |
Tabs |
Вход/Регистрация на auth | --color-ink-700 активная вкладка, подчёркивание --color-accent-active |
Table |
админка | --color-bg-alt заголовок, --color-border разделители |
Toggle/ToggleGroup |
переключатель layout сетки в комнате, кнопки mic/camera | активное состояние --color-room-mic-on / --color-room-mic-off |
Calendar (FullCalendar, не shadcn) |
обёртка токенами, ячейки — см. 4.10 | — |
Avatar |
участники комнаты, аватары в лобби/админке | --radius-full; заливка/текст инициалов — см. §1.5 (заливка ink-700/ink-500, текст всегда #FFFFFF) |
Tooltip |
подсказки тулбара | --color-room-surface-raised |
Тёмная тема room включается локальным скоупом (напр. data-theme="room" на
контейнере страницы конференции), а не глобальным dark: — остальная оболочка
всегда светлая независимо от системной темы ОС.
Иконки — lucide-react, контурные, stroke-width: 2
| Экран | Иконки |
|---|---|
| auth | Mail, Lock, Eye/EyeOff, User, CheckCircle2 (подтверждён email), ArrowRight |
| lobby (хаб действий) | Video («Создать»), CalendarDays («Календарь»), Link2 («Подключиться»), User («Мои»), бургер-меню: Download, Info, LayoutDashboard, LogOut |
| room | Mic, MicOff, Video, VideoOff, ScreenShare, MessageSquare, PhoneOff (выход), Users, Settings, LayoutGrid, Columns, Grid2x2, Maximize2, MoreVertical, Pin, Send, ChevronLeft/ChevronRight (лента превью) |
| calendar (менеджер конференций) | ChevronLeft/ChevronRight, CalendarDays, Clock, Lock, AlertTriangle, Check, Plus, Repeat (закреплена), Play (идёт сейчас), X (отменена/отмена), ChevronDown (селект «Рассылка саммари», §4.16) |
| my-conferences | Repeat, Clock, CheckCircle2, Users, Copy/Check (копирование), Play («Войти»), Pencil, FileText (саммари), Lock |
| join | Link2, Hash, User, Mail, Lock, Eye/EyeOff, ArrowRight, AlertCircle, Video (карточка целевой конференции) |
| admin | LayoutDashboard, Video, Lock, Users, Mail, Trash2, Pencil, Search, Plus, Send, ChevronDown/Check (селект «Получатели по умолчанию», §4.16) |
| email-summary | инлайн-SVG (email-клиенты не грузят icon-шрифты/JS): CheckCircle2, ListChecks, HelpCircle, BarChart3, стрелка CTA |
В HTML-макетах иконки встроены как инлайн-SVG (без иконных шрифтов и CDN);
во frontend — заменяются на lucide-react компоненты 1:1 по смыслу.
Файлы
design/tokens.css — источник истины по значениям (используется напрямую или
транслируется в tailwind.config.*, см. design/tailwind.md).
Макеты (design/mockups/, единый источник истины по разметке)
auth.html— форма входа/регистрацииlobby.html— хаб действий (2×2 плитки)calendar.html— менеджер запланированных конференцийmy-conferences.html— мои конференции (закреплённые и предстоящие)join.html— подключение по ссылке/номеру → представиться → парольroom.html— конференция (тёмная тема)admin.html— администрированиеemail-summary.html— экспорт-письмо с транскриптом и резюме (всегда светлое — почтовые клиенты в массе не поддерживают тёмную тему/CSS-переменные, не участвует в переключателе тем оболочки)dark/*.html— тёмный вариант оболочки (6 экранов:login,lobby,calendar,join,my-conferences,admin); палитра — §1.2b, см.dark/README.mdза происхождением цветов