Files
vidconf/frontend/src/styles/calendar.css

274 lines
18 KiB
CSS
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* VidConf — стили экрана календаря конференций: менеджер
* запланированных/закреплённых конференций (переговорных комнат и их
* занятости в модели нет). Базовая раскладка/токены — 1:1 из design/mockups/calendar.html
* (.layout-grid, .week-card, .create-card, .pin-block, .recurrence-panel).
* Тема FullCalendar адаптирована под dayGrid-«чипы» вместо timeGrid-слотов
* (см. комментарий в ConferenceCalendar.tsx).
*/
/* ---------- Грид: сетка вхождений + карточка создания/редактирования ---------- */
.layout-grid {
display: grid;
grid-template-columns: 1fr 400px;
gap: var(--space-6);
align-items: start;
}
/* min-width:0 — без этого грид-элемент с 1fr-треком не сжимается уже своего
min-content (тут это внутренняя таблица FullCalendar с 5 колонками) —
классический grid blowout: трек и вся страница раздуваются шире вьюпорта,
появляется горизонтальный скролл (см. тот же приём в lobby.css/.action). */
.layout-grid > * { min-width: 0; }
.week-card {
background: var(--color-surface);
border: 1px solid var(--color-border);
border-radius: var(--radius-2xl);
padding: var(--space-6);
}
.week-toolbar { display: flex; align-items: center; justify-content: space-between; margin-bottom: var(--space-5); flex-wrap: wrap; gap: var(--space-3); }
.date-nav { display: flex; align-items: center; gap: var(--space-3); }
.date-nav-arrow {
width: 34px;
height: 34px;
flex-shrink: 0;
border-radius: 50%;
border: 1px solid var(--color-border);
background: var(--color-surface);
color: var(--color-ink-500);
display: flex;
align-items: center;
justify-content: center;
}
.date-nav-arrow:hover { border-color: var(--color-border-strong); color: var(--color-ink-900); }
.date-nav span { font: var(--text-h3); color: var(--color-ink-900); min-width: 200px; text-align: center; text-transform: capitalize; }
.date-nav .btn-secondary { flex-shrink: 0; white-space: nowrap; }
.view-toggle { display: flex; gap: 4px; background: var(--color-bg-alt); border: 1px solid var(--color-border); border-radius: var(--radius-full); padding: 4px; }
.view-toggle button { border: none; background: transparent; border-radius: var(--radius-full); padding: 7px 16px; font: var(--text-body); font-weight: 600; color: var(--color-ink-500); }
.view-toggle button.is-active { background: var(--color-surface); color: var(--color-ink-700); box-shadow: var(--shadow-sm); }
/* ---------- Тема FullCalendar (dayGrid) ---------- */
.vc-calendar { font-family: var(--font-body); }
.vc-calendar .fc { --fc-border-color: var(--color-border); --fc-page-bg-color: var(--color-surface); --fc-neutral-bg-color: var(--color-bg-alt); --fc-today-bg-color: rgba(212,242,227,.16); }
.vc-calendar .fc-theme-standard td, .vc-calendar .fc-theme-standard th { border-color: var(--color-border); }
.vc-calendar .fc-col-header-cell { background: var(--color-bg-alt); padding: 6px 0; }
.vc-calendar .fc-col-header-cell-cushion { font: var(--text-caption); color: var(--color-ink-500); text-decoration: none; padding: 6px 0; }
.vc-calendar .fc-daygrid-day-frame { min-height: 460px; padding: var(--space-2); }
.vc-calendar .fc-daygrid-day-number { font: var(--text-h3); color: var(--color-ink-900); padding: 4px 6px; }
.vc-calendar .fc-day-today { background: rgba(212,242,227,.16) !important; }
.vc-calendar .fc-day-today .fc-daygrid-day-number { color: var(--color-ink-700); }
.vc-calendar .fc-daygrid-day-events { margin: 0; display: flex; flex-direction: column; gap: var(--space-2); }
.vc-calendar .fc-daygrid-event-harness { margin: 0 !important; }
.vc-calendar .fc-daygrid-more-link { font: var(--text-caption); color: var(--color-ink-500); }
/*
* Событие-вхождение конференции — карточка-«чип» в духе .conf-chip мокапа.
* FullCalendar оборачивает событие в .fc-daygrid-event (наследует классы из
* `classNames`) — переопределяем его внешний вид под чип целиком, без
* отдельного контейнера.
*/
.vc-calendar .fc-daygrid-event.conf-chip {
display: flex !important;
flex-direction: column;
gap: 4px;
background: var(--color-surface) !important;
border: 1px solid var(--color-border) !important;
border-radius: var(--radius-md) !important;
padding: var(--space-3);
white-space: normal;
cursor: pointer;
transition: box-shadow var(--transition-fast), border-color var(--transition-fast);
}
.vc-calendar .fc-daygrid-event.conf-chip:hover { box-shadow: var(--shadow-sm); border-color: var(--color-border-strong); }
.vc-calendar .fc-daygrid-event.conf-chip .fc-event-time,
.vc-calendar .fc-daygrid-event.conf-chip .fc-event-title { display: none; } /* заменено собственным eventContent */
.chip-time { display: block; font: var(--text-caption); color: var(--color-ink-500); text-transform: none; letter-spacing: normal; }
.chip-title { display: flex; align-items: center; gap: 6px; font: var(--text-body); font-weight: 700; color: var(--color-ink-900); }
.chip-lock { width: 13px; height: 13px; flex-shrink: 0; }
.conf-badge { display: inline-flex; align-items: center; gap: 4px; padding: 2px 9px; border-radius: var(--radius-full); font: var(--text-caption); font-size: 11px; width: fit-content; }
.conf-badge.scheduled { background: var(--color-warning-bg); color: var(--color-warning); }
.conf-badge.pinned { background: var(--color-bg-alt); color: var(--color-ink-700); border: 1px solid var(--color-border-strong); }
.conf-badge.live { background: var(--color-success-bg); color: var(--color-success); }
.conf-badge.ended { background: var(--color-bg-alt); color: var(--color-ink-500); }
.vc-empty-hint { text-align: center; padding: var(--space-8); color: var(--color-ink-500); font: var(--text-body-lg); }
/* ---------- Карточка создания/редактирования конференции ---------- */
.create-card {
background: var(--color-surface);
border: 1px solid var(--color-border);
border-radius: var(--radius-2xl);
padding: var(--space-6);
position: sticky;
top: 96px;
}
.create-card h2 { font: var(--text-h2); color: var(--color-ink-900); margin: 0 0 var(--space-5); display: flex; align-items: center; gap: 8px; }
.field-row { display: flex; gap: var(--space-3); }
.field-row .field { flex: 1; }
.next-occurrence { display: flex; align-items: center; gap: 8px; background: var(--color-bg-alt); border-radius: var(--radius-md); padding: 10px 14px; font: var(--text-body); color: var(--color-ink-700); font-weight: 600; margin-bottom: var(--space-5); }
/* Тумблер (используется и для «закрытая по паролю», и для «закрепить») */
.toggle-row { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); padding: var(--space-3) 0; border-top: 1px solid var(--color-border); }
.toggle-copy strong { display: block; font: var(--text-body); color: var(--color-ink-900); }
.toggle-copy span { font: 12px var(--font-body); color: var(--color-ink-500); }
.switch { position: relative; width: 44px; height: 24px; flex-shrink: 0; }
.switch input { opacity: 0; width: 0; height: 0; position: absolute; }
.slider { position: absolute; inset: 0; background: var(--color-border-strong); border-radius: var(--radius-full); transition: background var(--transition-fast); cursor: pointer; }
.slider::before { content:""; position:absolute; width:18px; height:18px; left:3px; top:3px; background:#fff; border-radius:50%; transition: transform var(--transition-fast); }
.switch input:checked + .slider { background: var(--color-accent-active); }
.switch input:checked + .slider::before { transform: translateX(20px); }
.switch input:focus-visible + .slider { outline: 2px solid var(--color-focus-ring); outline-offset: 2px; }
/* Disabled-переключатель (напр. анонс записи конференций в «Модулях»
админки) — приглушение вместо hover/checked-цвета. */
.switch input:disabled + .slider { opacity: .5; cursor: not-allowed; }
.password-block { margin-top: var(--space-4); }
/* ---------- Блок повторений (recurrence) ---------- */
.recurrence-panel {
display: flex;
flex-direction: column;
gap: var(--space-2);
margin-top: var(--space-4);
padding-top: var(--space-4);
border-top: 1px dashed var(--color-border);
}
.recurrence-option-row {
display: flex; align-items: center; gap: 10px;
padding: 10px 12px; border: 1px solid var(--color-border); border-radius: var(--radius-md);
cursor: pointer; font: var(--text-body); font-weight: 600; color: var(--color-ink-900);
transition: border-color var(--transition-fast), background var(--transition-fast);
}
.recurrence-option-row:has(input:checked) { border-color: var(--color-ink-700); background: var(--color-bg-alt); }
.recurrence-option-row input[type="radio"] { width: 16px; height: 16px; accent-color: var(--color-ink-700); flex-shrink: 0; }
.recurrence-sub { padding: var(--space-3) 12px 4px 38px; }
.weekday-toggles { display: flex; gap: 6px; flex-wrap: wrap; }
.weekday-chip {
width: 34px; height: 34px; border-radius: 50%;
border: 1.5px solid var(--color-border); background: var(--color-surface);
font: var(--text-caption); color: var(--color-ink-500);
display: flex; align-items: center; justify-content: center;
cursor: pointer;
}
.weekday-chip.is-selected { background: var(--color-ink-700); border-color: var(--color-ink-700); color: #fff; }
.recurrence-hint { font: 12px var(--font-body); color: var(--color-ink-500); margin-top: 8px; }
/* ---------- Кнопки действий карточки редактирования ---------- */
.btn-row { display: flex; gap: var(--space-3); margin-top: var(--space-5); }
.btn-row .btn { flex: 1; justify-content: center; }
.danger-link-row { text-align: center; margin-top: var(--space-4); }
.btn-text { background: none; border: none; color: var(--color-danger); font: var(--text-body); font-weight: 600; padding: 4px; cursor: pointer; }
.btn-text:hover { text-decoration: underline; }
.btn.full { width: 100%; justify-content: center; margin-top: var(--space-5); }
.btn-danger { background: var(--color-danger); color: #fff; font: var(--text-body); font-weight: 700; padding: 9px 18px; border-radius: var(--radius-full); border: none; cursor: pointer; display: inline-flex; align-items: center; gap: 8px; }
.btn-danger:hover:not(:disabled) { filter: brightness(0.92); }
/* ---------- Пикер участников (ParticipantsPicker) ----------
* Новый элемент без готового макета — собран из утверждённых паттернов:
* чипы как `.chip` фильтров «Моих конференций», выпадающий список результатов
* переиспользует классы дроплиста селекта (`.vc-select-panel`/`.vc-select-option`,
* §4.16), поле поиска — как `.search-wrap` админки.
*/
.participants-picker { position: relative; }
.participants-chips { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: var(--space-3); }
.participant-chip {
display: inline-flex; align-items: center; gap: 6px;
padding: 4px 10px 4px 4px; border-radius: var(--radius-full);
border: 1px solid var(--color-border); background: var(--color-bg-alt);
font: var(--text-body); font-weight: 600; color: var(--color-ink-900);
}
.participant-chip.is-organizer { padding-right: 12px; border-color: var(--color-border-strong); }
.participant-chip-role { font: var(--text-caption); color: var(--color-ink-500); font-weight: 600; }
.participant-chip-remove {
width: 18px; height: 18px; flex-shrink: 0; border-radius: 50%; border: none;
background: transparent; color: var(--color-ink-400);
display: flex; align-items: center; justify-content: center; cursor: pointer;
}
.participant-chip-remove:hover:not(:disabled) { background: var(--color-border); color: var(--color-ink-900); }
.participant-chip-remove:disabled { cursor: not-allowed; opacity: .5; }
.participants-search-wrap { position: relative; }
.participants-search-wrap .icon { position: absolute; left: 12px; top: 50%; transform: translateY(-50%); color: var(--color-ink-400); }
.participants-search-wrap input {
width: 100%; font: var(--text-body-lg); color: var(--color-ink-900);
padding: 10px 14px 10px 38px; border-radius: var(--radius-md);
border: 1px solid var(--color-border); background: var(--color-surface); font-family: var(--font-body);
}
.participants-search-wrap input:focus { outline: none; border-color: var(--color-focus-ring); box-shadow: 0 0 0 2px var(--color-focus-ring); }
.participants-search-wrap input:disabled { background: var(--color-bg-alt); color: var(--color-ink-300); cursor: not-allowed; }
.participants-results { top: calc(100% + 6px); max-height: 240px; }
.participant-option-body { display: flex; align-items: center; gap: 8px; font: var(--text-body); color: var(--color-ink-900); }
.participants-results-hint { padding: 10px 14px; font: var(--text-body); color: var(--color-ink-500); }
/* ---------- Диалог быстрого просмотра вхождения (ConferenceOccurrenceDialog) ---------- */
.detail-row { display: flex; align-items: flex-start; gap: 10px; padding: 10px 0; border-bottom: 1px solid var(--color-border); font: var(--text-body); color: var(--color-ink-900); }
.detail-row:last-of-type { border-bottom: none; }
.detail-row svg { color: var(--color-ink-400); margin-top: 2px; flex-shrink: 0; }
.detail-row .label { color: var(--color-ink-500); min-width: 90px; flex-shrink: 0; }
.title-lock { width: 15px; height: 15px; margin-right: 6px; flex-shrink: 0; }
/* =====================================================================
* Тёмная тема: точечные патчи (design/mockups/dark/README.md).
* ===================================================================== */
@media (prefers-color-scheme: dark) {
:root:not([data-theme]) .vc-calendar .fc { --fc-today-bg-color: rgba(127, 221, 168, 0.10); }
:root:not([data-theme]) .vc-calendar .fc-day-today { background: rgba(127, 221, 168, 0.10) !important; }
:root:not([data-theme]) .weekday-chip.is-selected { color: var(--color-accent-text); }
:root:not([data-theme]) .btn-danger { background: var(--color-danger-solid); }
:root:not([data-theme]) .btn-danger:hover:not(:disabled) { background: var(--color-danger-solid-hover); filter: none; }
}
:root[data-theme='dark'] .vc-calendar .fc { --fc-today-bg-color: rgba(127, 221, 168, 0.10); }
:root[data-theme='dark'] .vc-calendar .fc-day-today { background: rgba(127, 221, 168, 0.10) !important; }
:root[data-theme='dark'] .weekday-chip.is-selected { color: var(--color-accent-text); }
:root[data-theme='dark'] .btn-danger { background: var(--color-danger-solid); }
:root[data-theme='dark'] .btn-danger:hover:not(:disabled) { background: var(--color-danger-solid-hover); filter: none; }
/* ---------- Узкие экраны ---------- */
/* ВАЖНО: этот блок должен идти строго ПОСЛЕДНИМ в файле — при равной
специфичности с безусловными правилами выше (`.create-card`, `.field-row`
и т.п. — те же 0,1,0/0,1,1) побеждает порядок в исходнике, а не сам факт
совпадения media query (тот же баг уже ловили в lobby.css/.action, гейт 3
— см. комментарий там). Макет calendar.html — desktop-only
(`html { min-width: 1280px }`, DESIGN_SYSTEM.md §«Breakpoints»), адаптива
в нём нет — раскладка ниже подобрана по здравому смыслу: календарь сверху,
карточка создания/редактирования — под ним (сохраняем порядок вёрстки).
*/
@media (max-width: 960px) {
/* Двухколоночный грид (сетка + сайдбар 400px) → одна колонка, сайдбар
перестаёт быть sticky (в потоке одной колонки залипание при скролле
страницы выглядит и работает хуже, чем простое следование за контентом). */
.layout-grid { grid-template-columns: 1fr; }
.create-card { position: static; top: auto; }
}
@media (max-width: 640px) {
.week-card, .create-card { padding: var(--space-4); }
.week-toolbar { flex-direction: column; align-items: stretch; }
.date-nav { justify-content: space-between; }
.date-nav span { min-width: 0; flex: 1; }
/* Недельная сетка FullCalendar (5 рабочих дней) не помещается на ~360px
содержимого карточки без потери читаемости — даём ей прокручиваться
ГОРИЗОНТАЛЬНО ВНУТРИ карточки (min-width задаёт компактную, но ещё
читаемую ширину колонки), а не раздувать всю страницу (см. min-width:0
на .layout-grid выше — здесь наоборот сознательно возвращаем разумный
min-width самому графику, но уже внутри своего overflow-контейнера). */
.vc-calendar { overflow-x: auto; }
.vc-calendar .fc { min-width: 560px; }
.field-row { flex-wrap: wrap; }
.recurrence-sub { padding-left: var(--space-4); }
}