Corp/backend/static/css/components/page-header.css
Игорь Надеин a6cc9b7beb feat(chat): рефакторинг мобильной навигации и шапки чата
- Реализован современный нижний navbar для мобильных (5 кнопок)
- Скрытие нижнего navbar на странице чата
- Новая шапка чата с аватарами и бейджами типа чата
- Переработана HTML структура чата (убраны лишние Bootstrap контейнеры)
- Добавлены стили для аватаров и бейджей типов чатов
- Условное отображение: аватар OR иконка категории
2026-01-12 10:14:16 +03:00

484 lines
11 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.

/**
* Page Header Component
*
* Универсальная шапка для страниц списков с:
* - Полупрозрачным фоном (sticky positioning)
* - Иконкой и заголовком
* - Счётчиком элементов
* - Переключателем области (Мои/Все)
* - Кнопкой фильтров
* - Кнопкой создания (вытянутая на десктопе, иконка на мобильных)
* - Поиском iOS-стиль
*
* Использование:
* {% include "includes/components/page_header.html" with ... %}
* <link rel="stylesheet" href="{% static 'css/components/page-header.css' %}">
*/
/* ===== ОСНОВНОЙ КОНТЕЙНЕР ШАПКИ ===== */
.page-header {
position: sticky;
top: var(--navbar-h, 60px);
z-index: 10;
padding: var(--space-2) 0; /* 8px сверху/снизу */
margin-bottom: var(--space-3); /* 12px отступ снизу */
/* Полупрозрачный фон с градиентом */
background: linear-gradient(
to bottom,
color-mix(in srgb, var(--bs-body-bg) 90%, transparent) 0%,
color-mix(in srgb, var(--bs-body-bg) 85%, transparent) 30%,
color-mix(in srgb, var(--bs-body-bg) 70%, transparent) 50%,
color-mix(in srgb, var(--bs-body-bg) 40%, transparent) 70%,
transparent 100%
);
/* Убрана border-bottom - линия не нужна */
/* Анимация появления при скролле */
transition: background 0.2s ease, box-shadow 0.2s ease;
}
/* Псевдоэлемент для градиентного размытия */
.page-header::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
backdrop-filter: saturate(180%) blur(12px);
-webkit-backdrop-filter: saturate(180%) blur(12px);
mask-image: linear-gradient(
to bottom,
black 0%,
black 30%,
rgba(0, 0, 0, 0.7) 50%,
rgba(0, 0, 0, 0.4) 70%,
transparent 100%
);
-webkit-mask-image: linear-gradient(
to bottom,
black 0%,
black 30%,
rgba(0, 0, 0, 0.7) 50%,
rgba(0, 0, 0, 0.4) 70%,
transparent 100%
);
pointer-events: none;
z-index: -1;
}
/* Контент должен быть выше псевдоэлемента */
.page-header > * {
position: relative;
z-index: 1;
}
/* ===== CHAT AVATAR WITH TYPE BADGE ===== */
.chat-avatar-wrapper {
position: relative;
width: 48px;
height: 48px;
flex-shrink: 0;
}
.chat-avatar {
width: 100%;
height: 100%;
border-radius: 12px;
object-fit: cover;
display: block;
border: 1px solid var(--bs-border-color);
}
.chat-type-badge {
position: absolute;
bottom: -2px;
right: -2px;
width: 20px;
height: 20px;
border-radius: 50%;
background: var(--bs-primary);
color: white;
display: flex;
align-items: center;
justify-content: center;
font-size: 10px;
border: 2px solid var(--bs-body-bg);
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.chat-type-badge i {
line-height: 1;
}
[data-bs-theme="dark"] .chat-type-badge {
border-color: var(--bs-body-bg);
}
/* При скролле - более выраженный фон */
.page-header.scrolled {
background: linear-gradient(
to bottom,
color-mix(in srgb, var(--bs-body-bg) 95%, transparent) 0%,
color-mix(in srgb, var(--bs-body-bg) 90%, transparent) 30%,
color-mix(in srgb, var(--bs-body-bg) 75%, transparent) 50%,
color-mix(in srgb, var(--bs-body-bg) 45%, transparent) 70%,
transparent 100%
);
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
}
/* ===== TOP BAR (заголовок + действия) ===== */
.page-header-top {
display: flex;
align-items: center;
justify-content: space-between;
gap: var(--space-2);
width: 100%;
}
.page-header-title {
display: flex;
align-items: center;
gap: var(--space-2);
flex: 1;
min-width: 0;
}
.page-header-title h1 {
font-size: 1.5rem;
font-weight: 700;
margin: 0;
color: var(--bs-body-color);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.page-header-title i {
font-size: 1.75rem;
flex-shrink: 0;
}
.page-header-actions {
display: flex;
align-items: center;
gap: var(--space-1);
flex-shrink: 0;
}
@media (max-width: 767.98px) {
.page-header-title h1 {
font-size: 1.25rem;
}
.page-header-title i {
font-size: 1.5rem;
}
}
/* ===== ЗАГОЛОВОК ===== */
.page-title {
font-weight: 800;
font-size: 1.75rem;
letter-spacing: -0.01em;
line-height: 1.2;
color: var(--bs-body-color);
flex-shrink: 0;
}
/* ===== СЧЁТЧИК ===== */
.page-count {
font-size: 0.875rem;
color: var(--bs-secondary-color);
white-space: nowrap;
flex-shrink: 0;
}
.page-count .count-value {
font-weight: 600;
color: var(--bs-body-color);
}
/* ===== ПЕРЕКЛЮЧАТЕЛЬ ОБЛАСТИ (МОИ/ВСЕ) ===== */
.page-scope-switch {
flex-shrink: 0;
}
.page-scope-switch .btn {
min-width: 60px;
font-size: 0.875rem;
border-radius: 999px;
padding: 0.375rem 0.75rem;
transition: all 0.2s ease;
}
.page-scope-switch .btn:first-child {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
.page-scope-switch .btn:last-child {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
.page-scope-switch .btn.active {
background-color: var(--bs-primary);
border-color: var(--bs-primary);
color: white;
font-weight: 600;
}
/* ===== КНОПКА ФИЛЬТРОВ ===== */
/* Использует класс .btn-circle из buttons.css */
.page-filter-toggle:hover {
background-color: color-mix(in srgb, var(--bs-primary), transparent 85%);
border-color: var(--bs-primary);
color: var(--bs-primary);
}
.page-filter-toggle[aria-expanded="true"] {
background-color: var(--bs-primary);
border-color: var(--bs-primary);
color: white;
}
/* ===== КНОПКА СОЗДАНИЯ ===== */
/* Использует классы .btn-pill и .btn-icon из buttons.css */
.page-create-btn {
font-weight: 600;
font-size: 0.875rem;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
transition: all 0.2s ease;
}
.page-create-btn:hover {
transform: translateY(-1px);
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
}
.page-create-btn:active {
transform: translateY(0);
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
}
/* ===== ПОИСК ===== */
.page-search {
flex-shrink: 1;
min-width: 200px;
max-width: 400px;
flex-grow: 1;
}
/* На мобильных поиск на всю ширину */
@media (max-width: 991.98px) {
.page-search {
flex-basis: 100%;
max-width: none;
margin-top: var(--space-2);
order: 10;
}
/* Кнопка фильтров переносится под поиск и прижимается к правому краю */
.page-filter-toggle {
order: 11;
margin-top: var(--space-2);
margin-left: auto;
margin-right: 0 !important;
}
/* Родительский контейнер должен переносить элементы */
.page-header .d-flex.align-items-center {
flex-wrap: wrap;
}
}
/* ===== БЛОК ФИЛЬТРОВ ===== */
.page-filters-collapse {
margin-top: var(--space-2);
width: 100%;
}
.page-filters {
border-radius: var(--radius-lg, 14px);
border: 1px solid color-mix(in srgb, var(--bs-border-color), transparent 10%);
background: var(--bs-body-bg);
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
padding: var(--space-3);
animation: slideDown 0.3s ease;
}
/* Адаптивность кнопок внутри фильтров */
.page-filters .btn {
white-space: nowrap;
min-width: fit-content;
}
.page-filters .d-flex.gap-2 {
flex-wrap: wrap;
}
@keyframes slideDown {
from {
opacity: 0;
transform: translateY(-10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* ===== АДАПТИВНОСТЬ ===== */
/* Планшеты */
@media (max-width: 991.98px) {
.page-title {
font-size: 1.5rem;
}
.page-header {
padding: var(--space-2) 0;
}
}
/* Мобильные */
@media (max-width: 575.98px) {
.page-header {
margin-bottom: var(--space-2);
padding: var(--space-1) 0;
top: var(--navbar-h, 60px);
}
.page-title {
font-size: 1.125rem;
font-weight: 700;
}
.page-count {
font-size: 0.7rem;
}
.page-scope-switch {
gap: 0.25rem;
}
.page-scope-switch .btn {
min-width: auto;
font-size: 0.7rem;
padding: 0.2rem 0.4rem;
}
.page-filters {
margin-top: 0.5rem;
}
.page-filters .btn {
padding: 0.4rem 0.75rem;
font-size: 0.85rem;
}
.page-search {
margin-top: 0.5rem;
}
/* Скрываем счётчик на очень маленьких экранах */
@media (max-width: 480px) {
.page-count {
display: none;
}
.page-header .card {
margin-top: 0;
width: 100%;
}
.page-header .card button.dept-row,
.page-header .card a.dept-row {
padding: var(--space-1) var(--space-1);
font-size: 0.9rem;
}
}
}
/* ===== ИНТЕГРАЦИЯ С IOS-SEARCH ===== */
/* ios-search уже определён в ios-search.css, здесь только позиционирование */
.page-search .ios-search {
width: 100%;
}
/* ===== КНОПКА СОЗДАНИЯ В ВИДЕ КАРТОЧКИ (для модала) ===== */
/* Кнопка должна выглядеть как ссылка в card */
.page-header .card {
margin-top: var(--space-2);
width: 100%;
}
.page-header .card button.dept-row,
.page-header .card a.dept-row {
cursor: pointer;
transition: background-color 0.2s ease;
width: 100%;
padding: var(--space-1) var(--space-2);
text-align: center;
}
/* Текст кнопки должен быть как card-title */
.page-header .card button.dept-row .card-title,
.page-header .card a.dept-row .card-title {
font-weight: 700;
color: var(--bs-body-color);
}
/* Иконка должна быть синей как в оригинале */
.page-header .card button.dept-row i,
.page-header .card a.dept-row i {
color: var(--bs-primary);
}
.page-header .card button.dept-row:hover,
.page-header .card a.dept-row:hover {
background-color: var(--bs-light);
}
@media (prefers-color-scheme: dark) {
.page-header .card button.dept-row:hover,
.page-header .card a.dept-row:hover {
background-color: color-mix(in srgb, var(--bs-body-bg) 95%, white);
}
}
/* ===== ТЕМНАЯ ТЕМА ===== */
@media (prefers-color-scheme: dark) {
.page-header {
background: linear-gradient(
to bottom,
color-mix(in srgb, var(--bs-body-bg) 85%, transparent) 0%,
color-mix(in srgb, var(--bs-body-bg) 80%, transparent) 45%,
color-mix(in srgb, var(--bs-body-bg) 65%, transparent) 50%,
color-mix(in srgb, var(--bs-body-bg) 35%, transparent) 70%,
transparent 100%
);
border-bottom-color: color-mix(in srgb, var(--bs-border-color), transparent 60%);
}
.page-header.scrolled {
background: linear-gradient(
to bottom,
color-mix(in srgb, var(--bs-body-bg) 90%, transparent) 0%,
color-mix(in srgb, var(--bs-body-bg) 80%, transparent) 30%,
color-mix(in srgb, var(--bs-body-bg) 72%, transparent) 50%,
color-mix(in srgb, var(--bs-body-bg) 40%, transparent) 70%,
transparent 100%
);
}
.page-filters {
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.3);
}
}