Files
chatballs/apps/internal-ui/src/layout/styles.css
T
AndreyandClaude Opus 5 1cff9e2183 ✨ feat(onboarding): визард «Начало работы» вместо блока «Запуск»
Онбординг из восьми шагов: приветствие, визард с точным путём и превью
результата на каждом шаге, тур «Показать где» с подсветкой реального
элемента и финальный экран. Точки возврата — ссылка внизу субменю
«Настроек» и пилюля в углу рабочей области. Вёрстка по макету
design/baseline/Онбординг.

Признак «закрыл» и «прошёл» живёт на членстве человека в организации, а
не в localStorage: требование — показать визард всем, кто его ещё не
закрывал, включая тех, кто работает в установке давно. У каждого он свой,
поэтому один администратор не прячет визард команде. Прогресс шагов
считается по факту настройки, ручное «Далее» его не подменяет.

Заодно все селекты приложения переведены на общее меню: SelectMenu в
shared/ui-controls, поверх него FilterDropdown (фильтры списков) и
SelectField (поля форм). Нативных <select> не осталось, вместе с ними
ушли пять копий скина селекта. Изменения переплетены с онбордингом через
общие файлы (словари, e2e-сценарии), поэтому одним коммитом.

Устаревший design/design-system удалён: источник истины по интерфейсу —
макеты design/baseline/<фича>/*.dc.html.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-13 07:22:35 +03:00

739 lines
14 KiB
CSS

.hub-shell {
position: relative;
height: 100vh;
display: flex;
overflow: hidden;
background: var(--n-11);
}
/* Страницы вне чата не адаптированы под мобильный — держат десктопную ширину.
Чат (кадры M1/M2) адаптивен и ограничение снимает. */
.hub-shell:not(.is-chat-route) {
min-width: 1024px;
}
/* Сайдбар 220px (дизайн-базлайн v2, решение 1): фон surface2, без верхней панели. */
.hub-sidebar {
position: relative;
width: var(--sidebar-width, 220px);
height: 100vh;
display: flex;
flex: none;
flex-direction: column;
background: var(--surface-sidebar);
border-right: 1px solid var(--n-8);
}
/* Ручка изменения ширины панели (сайдбар, список диалогов): невидимая полоса
на правом крае, подсвечивается при наведении и во время перетаскивания. */
.pane-resizer {
position: absolute;
top: 0;
right: -3px;
bottom: 0;
width: 6px;
z-index: 5;
cursor: col-resize;
}
.pane-resizer::after {
content: "";
position: absolute;
top: 0;
bottom: 0;
left: 2px;
width: 2px;
background: var(--primary);
opacity: 0;
transition: opacity 0.12s;
}
.pane-resizer:hover::after,
.is-resizing > .pane-resizer::after {
opacity: 1;
}
@media (max-width: 1024px) {
.pane-resizer {
display: none;
}
}
.hub-sidebar-body {
flex: 1;
min-height: 0;
display: flex;
flex-direction: column;
}
/* Рейка 60px (дизайн-базлайн v2, кадр S2): показывается только на ≤1024px. */
.hub-rail {
display: none;
flex-direction: column;
align-items: center;
gap: 8px;
padding: 14px 0 12px;
height: 100%;
}
.hub-rail .hub-brand-mark {
margin-bottom: 8px;
}
.hub-rail-button {
width: 38px;
height: 38px;
display: flex;
align-items: center;
justify-content: center;
border: 0;
border-radius: 9px;
color: var(--n-4);
background: transparent;
}
.hub-rail-button:hover {
background: var(--n-9);
}
.hub-rail-button.is-active {
color: var(--primary-text);
background: var(--primary-bg);
}
.hub-rail-spacer {
flex: 1;
}
.hub-rail-avatar {
width: 34px;
height: 34px;
display: flex;
align-items: center;
justify-content: center;
border: 0;
border-radius: 50%;
color: #ffffff;
background: var(--primary);
font-size: 12px;
font-weight: 600;
}
.hub-rail-backdrop {
display: none;
position: fixed;
inset: 0;
z-index: 19;
border: 0;
background: rgba(0, 0, 0, 0.25);
}
@media (max-width: 1024px) {
.hub-sidebar {
width: 60px !important;
}
.hub-rail {
display: flex;
}
.hub-sidebar-body {
display: none;
}
.hub-sidebar.is-rail-expanded .hub-rail-backdrop {
display: block;
}
.hub-sidebar.is-rail-expanded .hub-sidebar-body {
display: flex;
position: fixed;
left: 0;
top: 0;
bottom: 0;
width: 248px;
z-index: 20;
background: var(--surface-card);
border-right: 1px solid var(--n-8);
box-shadow: 8px 0 24px rgba(0, 0, 0, 0.1);
}
}
.hub-brand {
width: 100%;
height: 56px;
display: flex;
align-items: center;
flex: none;
gap: 10px;
padding: 14px 14px 10px;
}
.hub-brand-mark {
border: 0;
padding: 0;
}
/* Переключатель организации (A1): имя + шеврон, 32px. */
.hub-brand-switch {
flex: 1;
min-width: 0;
height: 32px;
display: flex;
align-items: center;
justify-content: space-between;
gap: 6px;
padding: 0 6px 0 8px;
border: 0;
border-radius: 8px;
background: transparent;
color: var(--n-1);
font-size: 14px;
font-weight: 700;
text-align: left;
}
.hub-brand-switch:hover {
background: var(--n-9);
}
.hub-brand-switch span {
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.hub-brand-switch svg {
flex: none;
color: var(--n-4);
}
/* «Добавить организацию» в переключателе (A1): такая же строка, как у
организаций, только на месте значка — пунктирная плитка с плюсом, как у
«пустого» слота. Ничего залитого: строка читается как действие, а не как
ещё одна организация, и не спорит с отмеченной текущей. */
.app-dropdown .ant-dropdown-menu-item button.hub-brand-add {
color: var(--n-3);
}
.app-dropdown .ant-dropdown-menu-item button.hub-brand-add:hover {
color: var(--primary-text);
}
/* Селектор длиннее общего «button span { display: block }» из menu.css:
иначе плюс прижимается к левому верхнему углу плитки. */
.app-dropdown .ant-dropdown-menu-item button .hub-brand-add-icon {
width: 17px;
height: 17px;
display: inline-flex;
align-items: center;
justify-content: center;
flex: none;
color: var(--n-4);
border: 1.5px dashed var(--n-6);
border-radius: 6px;
transition: color 0.15s ease, border-color 0.15s ease;
}
.hub-brand-add-icon svg {
display: block;
}
.app-dropdown .ant-dropdown-menu-item button.hub-brand-add:hover .hub-brand-add-icon {
color: var(--primary-text);
border-color: var(--primary);
}
/* Логотип — сам по себе, без подложки: цвет текста темы. */
.hub-brand-mark {
width: 28px;
height: 28px;
display: flex;
align-items: center;
justify-content: center;
flex: none;
color: var(--n-1);
background: transparent;
border-radius: 8px;
}
.hub-brand-mark svg {
width: 26px;
height: 26px;
}
.hub-brand-mark.has-logo {
overflow: hidden;
color: inherit;
background: var(--surface-card);
border: 1px solid var(--n-7);
}
.hub-brand-mark img {
width: 100%;
height: 100%;
display: block;
object-fit: contain;
}
.profile-link strong {
display: block;
overflow: hidden;
color: var(--n-1);
font-size: 13px;
font-weight: 600;
line-height: 1.3;
text-overflow: ellipsis;
white-space: nowrap;
}
.profile-link small {
display: block;
overflow: hidden;
color: var(--n-4);
font-size: 11.5px;
font-weight: 400;
line-height: 1.3;
text-overflow: ellipsis;
white-space: nowrap;
}
.hub-nav {
flex: 1;
display: flex;
flex-direction: column;
gap: 2px;
overflow-y: auto;
padding: 4px 10px 8px;
}
.hub-nav-item {
position: relative;
width: 100%;
display: flex;
align-items: center;
flex: none;
gap: 10px;
height: 36px;
padding: 0 10px;
color: var(--n-2);
background: transparent;
border: none;
border-radius: 8px;
font-size: 13.5px;
font-weight: 500;
text-align: left;
text-decoration: none;
}
.profile-link {
position: relative;
width: 100%;
display: flex;
align-items: center;
gap: 10px;
color: var(--n-3);
background: transparent;
border: none;
text-align: left;
}
.hub-nav-item:not(:disabled):hover,
.profile-link:hover {
color: var(--n-2);
background: var(--n-9);
}
.hub-nav-item.is-active,
.profile-link.is-active {
color: var(--primary-text);
background: var(--primary-bg);
font-weight: 600;
}
.hub-subnav {
display: flex;
flex-direction: column;
gap: 2px;
padding: 2px 0 2px 30px;
}
.hub-subnav-item {
width: 100%;
display: flex;
align-items: center;
padding: 6px 12px;
border: 0;
border-radius: 7px;
color: var(--n-3);
background: transparent;
font-size: 13px;
font-weight: 500;
line-height: 1.4;
text-align: left;
}
.hub-subnav-item:not(:disabled):hover {
color: var(--n-2);
background: var(--n-9);
}
.hub-subnav-item.is-active {
color: var(--primary-text);
background: var(--primary-bg);
font-weight: 600;
}
.hub-subnav-item:disabled {
color: var(--n-5);
cursor: not-allowed;
}
.hub-nav-chevron {
display: inline-flex;
margin-left: auto;
transition: transform 0.15s ease;
}
.hub-nav-section-toggle[aria-expanded="false"] .hub-nav-chevron {
transform: rotate(-90deg);
}
.hub-subnav-item b {
min-width: 20px;
height: 20px;
display: inline-flex;
align-items: center;
justify-content: center;
margin-left: auto;
padding: 0 6px;
color: #ffffff;
background: var(--warning);
border-radius: 10px;
font-size: 11px;
font-weight: 700;
}
/* Бейдж очереди у «Чат» (A1): жёлтая плашка 20px. */
.hub-nav-badge {
min-width: 20px;
height: 20px;
display: inline-flex;
align-items: center;
justify-content: center;
margin-left: auto;
padding: 0 6px;
color: var(--warning-text);
background: var(--warning-bg);
border: 1px solid var(--warning-border);
border-radius: 10px;
font-size: 11px;
font-weight: 700;
}
.hub-nav-group {
padding: 14px 12px 6px;
color: var(--n-5);
font-size: 11px;
font-weight: 600;
letter-spacing: 0.06em;
}
.hub-nav-divider {
flex: none;
height: 1px;
margin: 8px 2px 4px;
background: var(--n-8);
}
/* Дерево «Диалоги» сотрудника (дизайн-базлайн v2 §3): сайдбар = фильтр чата. */
.chat-scope-tree {
padding-bottom: 12px;
}
.chat-scope-head {
display: flex;
align-items: center;
gap: 9px;
height: 34px;
padding: 0 8px;
color: var(--n-1);
font-size: 13.5px;
font-weight: 700;
}
.chat-scope-section {
display: flex;
align-items: center;
gap: 8px;
height: 30px;
margin: 6px 0 0 16px;
padding: 0 10px 0 12px;
color: var(--n-4);
font-size: 12.5px;
font-weight: 600;
}
.chat-scope-item {
display: flex;
align-items: center;
gap: 9px;
height: 32px;
padding: 0 10px 0 12px;
border: 0;
border-radius: 8px;
color: var(--n-2);
background: transparent;
font-size: 13px;
font-weight: 500;
text-align: left;
}
.chat-scope-item.is-top {
height: 34px;
margin-left: 16px;
}
.chat-scope-item.is-nested {
margin-left: 34px;
}
.chat-scope-item:hover {
background: var(--n-9);
}
.chat-scope-item.is-active {
color: var(--primary-text);
background: var(--primary-bg);
font-weight: 600;
}
.chat-scope-item > span:not(.chat-scope-agent) {
flex: 1;
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.chat-scope-item small {
color: var(--n-5);
font-size: 11.5px;
font-weight: 600;
}
.chat-scope-item.is-active small {
color: var(--primary-text);
}
.chat-scope-dot {
flex: none;
width: 8px;
height: 8px;
border-radius: 50%;
background: var(--primary);
}
.chat-scope-dot.is-muted {
background: var(--n-5);
}
.chat-scope-agent {
flex: none;
display: inline-flex;
align-items: center;
justify-content: center;
width: 18px;
height: 18px;
border-radius: 5px;
color: var(--ai);
background: color-mix(in srgb, var(--ai) 14%, var(--surface-card));
}
.profile-link {
margin: 0;
padding: 12px 14px;
border-top: 1px solid var(--n-8);
border-radius: 0;
}
.profile-link:hover {
background: var(--n-9);
}
.profile-link > span:nth-child(2) {
min-width: 0;
flex: 1;
}
.profile-avatar {
position: relative;
flex: none;
display: inline-flex;
}
.profile-avatar .avatar {
width: 34px;
height: 34px;
}
/* Онлайн-точка: сотрудник в системе. */
.profile-avatar i {
position: absolute;
right: -1px;
bottom: -1px;
width: 10px;
height: 10px;
border: 2px solid var(--surface-sidebar);
border-radius: 50%;
background: var(--success);
}
.profile-more {
flex: none;
display: inline-flex;
align-items: center;
justify-content: center;
width: 28px;
height: 28px;
color: var(--n-4);
border-radius: 7px;
}
.profile-link:hover .profile-more {
background: var(--n-8);
}
.profile-more {
position: relative;
}
/* Непрочитанные уведомления — точка на кнопке меню профиля. */
.profile-unread {
position: absolute;
top: 4px;
right: 4px;
width: 7px;
height: 7px;
background: var(--error);
border: 1.5px solid var(--surface-sidebar);
border-radius: 50%;
}
.profile-menu-badge {
min-width: 18px;
height: 18px;
display: inline-flex;
align-items: center;
justify-content: center;
margin-left: auto;
padding: 0 5px;
color: #ffffff;
background: var(--error);
border-radius: 9px;
font-size: 10.5px;
font-weight: 700;
}
.avatar {
width: 32px;
height: 32px;
display: inline-flex;
align-items: center;
justify-content: center;
flex: none;
overflow: hidden;
color: #ffffff;
background: var(--primary);
border-radius: 50%;
font-size: 13px;
font-weight: 600;
}
.avatar.has-photo {
background: var(--n-9);
}
.avatar img {
width: 100%;
height: 100%;
display: block;
object-fit: cover;
}
.hub-main {
min-width: 0;
height: 100vh;
display: flex;
flex: 1;
flex-direction: column;
}
/* Полоса установки демо-данных: пока worker наполняет организацию, человек
видит причину пустых разделов, а не гадает. */
.demo-install-banner {
display: flex;
flex: none;
align-items: center;
gap: 9px;
padding: 9px 20px;
border-bottom: 1px solid var(--n-8);
background: var(--primary-bg);
color: var(--primary-text);
font-size: 13px;
font-weight: 500;
}
.demo-install-banner.is-done {
background: var(--success-bg);
color: var(--success-text);
}
.demo-install-banner.is-failed {
background: var(--error-bg);
color: var(--error-text);
}
.update-banner a.link {
flex: none;
font-size: 13px;
}
.demo-install-banner > svg {
flex: none;
}
.demo-install-banner > span {
flex: 1;
min-width: 0;
}
.demo-install-banner button {
height: 26px;
padding: 0 11px;
border: 1px solid currentColor;
border-radius: 7px;
background: transparent;
color: inherit;
font-family: inherit;
font-size: 12.5px;
font-weight: 600;
cursor: pointer;
}
.demo-install-banner .demo-install-close {
display: flex;
width: 24px;
height: 24px;
align-items: center;
justify-content: center;
padding: 0;
border: 0;
opacity: 0.65;
}
.demo-install-banner .demo-install-close:hover { opacity: 1; }