Corp/backend/static/css/components/chat-detail.css
Игорь Надеин aba011731f feat: implement Telegram-style badges system
- Created comprehensive badges-telegram-style.css (240 lines) based on Telegram Web K
- Updated all badge markup in templates (navbar, sidebar, chat_list, chat_detail, chat_title)
- Replaced Bootstrap badge classes with .badge-telegram classes
- Implemented Telegram specifications: 20px height, 10px radius, 11px font, 600 weight
- Added smooth animations: pulse (on update), animate-in (on mount), animate-out (on unmount)
- Updated JavaScript: replaced .d-none with style.display for badge visibility
- Updated 5 JS files: bottom-navbar, notification-manager, chatBadgeHandler, chatBadgeManager, chatListRealtime
- Added pulse animation on badge value increase
- Improved shadows and transitions with cubic-bezier easing
- Added badges-telegram-style.css to base.html for global availability
- Created documentation: TELEGRAM_BADGES_GUIDE.md, TELEGRAM_BADGES_UPDATE.md

Technical details:
- Research: Analyzed 50+ files from Telegram Web K GitHub repository
- Perfect circles: border-radius: 10px (not 50%)
- Spring animation: cubic-bezier(0.175, 0.885, 0.32, 1.275)
- Auto-hide: :empty and [data-count='0'] selectors
- Responsive design + dark theme support
2026-01-12 17:37:41 +03:00

647 lines
16 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.

/**
* chat-detail.css
* Чистая архитектура чата в Telegram/WhatsApp стиле
*/
/* ═══════════════════════════════════════════════════════════
БАЗОВАЯ СТРУКТУРА
═══════════════════════════════════════════════════════════ */
/* КРИТИЧНО: Убираем все внешние скроллы */
body:has(.chat-page) {
overflow: hidden !important;
padding-bottom: 0 !important;
}
body:has(.chat-page) main {
overflow: hidden !important;
padding: 0 !important;
margin: 0 !important;
}
/* Скрываем bottom navbar на странице чата */
body:has(.chat-page) .bottom-navbar {
display: none;
}
/* Страница чата на всю высоту экрана */
.chat-page {
display: flex;
flex-direction: column;
height: calc(100vh - var(--navbar-h));
width: 100%;
max-width: 100%;
overflow: hidden;
background: var(--bs-body-bg);
position: relative;
}
@supports(height: 100svh) {
.chat-page {
height: calc(100svh - var(--navbar-h));
}
}
.chat-header,
.chat-container {
max-width: 1200px;
margin: 0 auto;
width: 100%;
}
.chat-container {
border-radius: var(--bs-border-radius-lg);
border: 1px solid var(--bs-border-color);
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
}
}
/* ═══════════════════════════════════════════════════════════
ШАПКА ЧАТА
═══════════════════════════════════════════════════════════ */
.chat-header {
flex-shrink: 0;
background: var(--bs-body-bg);
padding: var(--space-2) var(--space-3);
position: sticky;
top: 0;
z-index: 1020;
border-bottom: 1px solid var(--bs-border-color);
}
@media (min-width: 768px) {
.chat-header {
padding: var(--space-3) var(--space-4);
border-bottom: none;
}
}
@media (max-width: 767.98px) {
.chat-header {
padding: var(--space-1) var(--space-2);
}
}
.chat-header-content {
display: flex;
align-items: center;
justify-content: space-between;
gap: var(--space-2);
}
.chat-header-title {
display: flex;
align-items: center;
gap: var(--space-2);
flex: 1;
min-width: 0;
}
.chat-header-title h1 {
font-size: 1.25rem;
font-weight: 700;
margin: 0;
color: var(--bs-body-color);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.chat-header-title i {
font-size: 1.5rem;
flex-shrink: 0;
}
.chat-header-actions {
display: flex;
align-items: center;
gap: var(--space-1);
flex-shrink: 0;
}
/* Аватар чата с бейджем */
.chat-avatar-wrapper {
position: relative;
width: 40px;
height: 40px;
flex-shrink: 0;
}
.chat-avatar {
width: 100%;
height: 100%;
border-radius: 10px;
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: 10px; /* Идеальный круг как в Telegram */
background: var(--bs-danger); /* Красный как непрочитанные */
color: #fff;
display: flex;
align-items: center;
justify-content: center;
font-size: 11px;
font-weight: 600;
line-height: 1;
border: 2px solid var(--bs-body-bg);
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.15); /* Мягкая тень */
transition: transform 0.2s ease, background-color 0.2s ease;
}
.chat-type-badge:empty {
display: none;
}
.chat-type-badge.badge-primary {
background: var(--bs-primary);
}
.chat-type-badge.badge-muted {
background: var(--bs-secondary);
}
/* Анимация появления как в Telegram */
@keyframes badge-scale-in {
from {
transform: scale(0);
opacity: 0;
}
to {
transform: scale(1);
opacity: 1;
}
}
.chat-type-badge.new {
animation: badge-scale-in 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275);
}
@media (max-width: 767.98px) {
.chat-header {
padding: var(--space-1) var(--space-2);
}
.chat-header-title h1 {
font-size: 1.1rem;
}
.chat-header-title i {
font-size: 1.25rem;
}
.chat-header-actions .btn-sm span {
display: none;
}
}
/* ═══════════════════════════════════════════════════════════
КОНТЕЙНЕР ЧАТА
═══════════════════════════════════════════════════════════ */
.chat-container {
flex: 1;
display: flex;
flex-direction: column;
min-height: 0;
overflow: hidden;
position: relative;
}
/* ═══════════════════════════════════════════════════════════
EMOJI PICKER
═══════════════════════════════════════════════════════════ */
.chat-emoji-picker {
position: absolute;
bottom: 100%;
right: 0;
margin-bottom: var(--space-2);
z-index: 1050;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
border-radius: var(--bs-border-radius-lg);
max-width: 90vw;
}
@media (min-width: 768px) {
.chat-emoji-picker {
right: var(--space-3);
}
}
/* Скрываем по умолчанию, показываем через JS */
.chat-emoji-picker:not([data-visible="true"]) {
display: none;
}
/* ═══════════════════════════════════════════════════════════
ОБЛАСТЬ СООБЩЕНИЙ
═══════════════════════════════════════════════════════════ */
.chat-messages-scroll {
flex: 1;
overflow-y: auto;
overflow-x: hidden;
padding: var(--space-3);
scroll-behavior: smooth;
-webkit-overflow-scrolling: touch;
scrollbar-width: thin;
scrollbar-color: color-mix(in srgb, var(--bs-body-color), transparent 70%) transparent;
/* CSS Containment для оптимизации (как в Telegram) */
contain: layout style paint;
will-change: scroll-position;
/* GPU acceleration для плавного scroll */
transform: translateZ(0);
backface-visibility: hidden;
perspective: 1000px;
}
.chat-messages-scroll:hover {
scrollbar-color: color-mix(in srgb, var(--bs-body-color), transparent 55%) transparent;
}
.chat-messages-scroll::-webkit-scrollbar {
width: 8px;
}
.chat-messages-scroll::-webkit-scrollbar-track {
background: transparent;
}
.chat-messages-scroll::-webkit-scrollbar-thumb {
background-color: color-mix(in srgb, var(--bs-body-color), transparent 75%);
border-radius: 4px;
}
.chat-messages-scroll:hover::-webkit-scrollbar-thumb {
background-color: color-mix(in srgb, var(--bs-body-color), transparent 55%);
}
@media (hover: none), (pointer: coarse) {
.chat-messages-scroll {
scrollbar-width: none;
}
.chat-messages-scroll::-webkit-scrollbar {
display: none;
}
}
@media (max-width: 767.98px) {
.chat-messages-scroll {
padding: var(--space-2);
}
}
/* ═══════════════════════════════════════════════════════════
ИНДИКАТОР ПЕЧАТИ
═══════════════════════════════════════════════════════════ */
.chat-typing-indicator {
flex-shrink: 0;
padding: var(--space-1) var(--space-3);
font-size: 0.875rem;
color: var(--bs-secondary);
min-height: 32px;
display: flex;
align-items: center;
gap: var(--space-1);
}
.chat-typing-indicator.d-none {
display: none !important;
}
/* ═══════════════════════════════════════════════════════════
КОМПОЗЕР (ФОРМА ВВОДА)
═══════════════════════════════════════════════════════════ */
.chat-composer-wrapper {
flex-shrink: 0;
padding: var(--space-3) var(--space-3);
padding-bottom: calc(var(--space-4) + env(safe-area-inset-bottom, 0px));
background: var(--bs-body-bg);
border-top: 1px solid var(--bs-border-color);
position: relative;
z-index: 1010;
}
@media (min-width: 768px) {
.chat-composer-wrapper {
padding: var(--space-3) var(--space-4);
padding-bottom: var(--space-3);
border-radius: 0 0 var(--bs-border-radius-lg) var(--bs-border-radius-lg);
}
}
@media (max-width: 767.98px) {
.chat-composer-wrapper {
padding: var(--space-2) var(--space-2);
.message-field {
display: flex;
align-items: flex-end;
gap: var(--space-1);
width: 100%;
}
.composer-input-group {
flex: 1;
display: flex;
align-items: flex-end;
gap: var(--space-1);
background: var(--bs-tertiary-bg);
border-radius: var(--bs-border-radius-lg);
padding: var(--space-1);
border: 1px solid color-mix(in srgb, var(--bs-border-color), transparent 50%);
transition: border-color 0.2s;
}
.composer-input-group:focus-within {
border-color: var(--bs-primary);
}
.message-input {
flex: 1;
resize: none;
border: none;
background: transparent;
outline: none;
font-size: 1rem;
line-height: 1.5;
padding: var(--space-1);
max-height: 120px;
overflow-y: auto;
scrollbar-width: thin;
color: var(--bs-body-color);
}
.message-input::placeholder {
color: var(--bs-secondary-color);
}
.message-input::-webkit-scrollbar {
width: 4px;
}
.message-input::-webkit-scrollbar-thumb {
background-color: color-mix(in srgb, var(--bs-body-color), transparent 70%);
border-radius: 2px;
}
.composer-actions {
display: flex;
gap: 2px;
align-items: center;
}
.btn-send {
background: var(--bs-primary);
color: white;
border: none;
border-radius: 50%;
width: 36px;
height: 36px;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.2s;
flex-shrink: 0;
padding: 0;
}
.btn-send:hover:not(:disabled) {
background: color-mix(in srgb, var(--bs-primary), black 10%);
transform: scale(1.05);
color: white;
}
.btn-send:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.btn-attachment,
.message-icon-btn {
width: 36px;
height: 36px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.2s;
color: var(--bs-body-color);
background: transparent;
border: none;
padding: 0;
}
.btn-attachment:hover,
.message-icon-btn:hover {
background: color-mix(in srgb, var(--bs-body-color), transparent 90%);
}
/* ═══════════════════════════════════════════════════════════
СООБЩЕНИЯ (BUBBLES)
═══════════════════════════════════════════════════════════ */
.bubble {
border-radius: 16px;
padding: var(--space-1) var(--space-2);
word-break: break-word;
white-space: pre-wrap;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.06);
max-width: 75%;
}
@media (max-width: 767.98px) {
.bubble {
max-width: 85%;
}
}
.bubble-me {
background: color-mix(in srgb, var(--bs-primary) 92%, #fff 0%);
color: #fff;
}
.bubble-other {
background: var(--bs-secondary-bg);
color: var(--bs-body-color);
}
.mini-ava {
width: 32px;
height: 32px;
border-radius: 9999px;
overflow: hidden;
display: grid;
place-items: center;
background: var(--bs-secondary-bg);
flex-shrink: 0;
}
.mini-ava img {
width: 100%;
height: 100%;
object-fit: cover;
display: block;
}
/* ═══════════════════════════════════════════════════════════
ВЛОЖЕНИЯ
═══════════════════════════════════════════════════════════ */
.message-attachments {
margin-top: var(--space-1);
}
.attachment-preview {
padding: var(--space-1) 0;
max-height: 200px;
overflow-y: auto;
}
.attachment-item {
background: var(--bs-secondary-bg);
border-radius: var(--bs-border-radius);
padding: var(--space-1);
transition: background-color 0.15s;
}
.attachment-item:hover {
background: var(--bs-tertiary-bg);
}
.chat-media {
max-width: 100%;
max-height: 400px;
border-radius: 12px;
}
/* ═══════════════════════════════════════════════════════════
РАЗДЕЛИТЕЛИ
═══════════════════════════════════════════════════════════ */
.day-divider,
.unread-divider {
display: flex;
align-items: center;
justify-content: center;
gap: var(--space-1);
margin: var(--space-1) 0 var(--space-2);
font-size: .85rem;
line-height: 1;
font-weight: 700;
pointer-events: none;
user-select: none;
}
.day-divider::before,
.day-divider::after,
.unread-divider::before,
.unread-divider::after {
content: "";
flex: 1 1 auto;
height: 1px;
background: color-mix(in srgb, var(--bs-border-color), transparent 30%);
}
.day-divider > span,
.unread-divider > span {
flex: 0 0 auto;
padding: 0 var(--space-1);
background: transparent;
}
.day-divider {
color: var(--bs-secondary-color);
}
.unread-divider {
color: var(--bs-danger);
}
/* ═══════════════════════════════════════════════════════════
КНОПКА "ВНИЗ"
═══════════════════════════════════════════════════════════ */
.scroll-to-bottom {
position: absolute;
right: var(--space-2);
bottom: calc(80px + var(--space-2));
z-index: 2;
display: none;
width: 40px;
height: 40px;
border-radius: 50%;
background: var(--bs-primary);
color: white;
border: none;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
transition: all 0.2s;
}
@media (max-width: 767.98px) {
.scroll-to-bottom {
bottom: calc(var(--space-5) + 80px + env(safe-area-inset-bottom, 12px));
}
}
.scroll-to-bottom.show {
display: flex;
align-items: center;
justify-content: center;
}
.scroll-to-bottom:hover {
transform: scale(1.1);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
}
/* ═══════════════════════════════════════════════════════════
ИНДИКАТОР ЗАГРУЗКИ
═══════════════════════════════════════════════════════════ */
.history-loader {
display: flex;
align-items: center;
justify-content: center;
gap: var(--space-1);
padding: var(--space-2) 0;
color: var(--bs-secondary);
}
.history-loader .spinner-border {
width: 1rem;
height: 1rem;
}
/* ═══════════════════════════════════════════════════════════
ТЕМНАЯ ТЕМА
═══════════════════════════════════════════════════════════ */
[data-bs-theme="dark"] .chat-messages-scroll {
scrollbar-color: color-mix(in srgb, var(--bs-body-color), transparent 78%) transparent;
}
[data-bs-theme="dark"] .chat-messages-scroll:hover {
scrollbar-color: color-mix(in srgb, var(--bs-body-color), transparent 60%) transparent;
}
[data-bs-theme="dark"] .chat-type-badge {
border-color: var(--bs-body-bg);
}