feat: Добавить анимации и улучшения UX/UI в компоненты приложения, включая плавные переходы, эффекты при наведении и анимации для модальных окон. Обновить карточки и таблицы с новыми анимациями для улучшения визуального восприятия и доступности.
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 2m42s
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 2m42s
This commit is contained in:
@@ -300,3 +300,224 @@
|
||||
border-color: var(--tblr-border-color);
|
||||
}
|
||||
}
|
||||
|
||||
/* ===== UX/UI Enhancement Animations ===== */
|
||||
|
||||
/* Плавные переходы для всех интерактивных элементов */
|
||||
.transition-all {
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
/* Анимация появления карточек */
|
||||
@keyframes fadeInUp {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(20px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
.card.animate-in {
|
||||
animation: fadeInUp 0.3s ease-out;
|
||||
}
|
||||
|
||||
/* Анимация при добавлении элемента в таблицу */
|
||||
@keyframes slideInRight {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateX(-20px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateX(0);
|
||||
}
|
||||
}
|
||||
|
||||
.table tbody tr.new-item {
|
||||
animation: slideInRight 0.3s ease-out;
|
||||
background-color: rgba(32, 107, 196, 0.1);
|
||||
}
|
||||
|
||||
/* Пульсация при обновлении */
|
||||
@keyframes pulse {
|
||||
0%, 100% {
|
||||
box-shadow: 0 0 0 0 rgba(32, 107, 196, 0.4);
|
||||
}
|
||||
50% {
|
||||
box-shadow: 0 0 0 6px rgba(32, 107, 196, 0);
|
||||
}
|
||||
}
|
||||
|
||||
.badge.updating {
|
||||
animation: pulse 1.5s infinite;
|
||||
}
|
||||
|
||||
/* Hover эффекты для интерактивных карточек */
|
||||
.card.interactive {
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.card.interactive:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
/* Ripple effect для кнопок */
|
||||
@keyframes ripple {
|
||||
to {
|
||||
transform: scale(4);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-ripple {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.btn-ripple::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-radius: 50%;
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
transform: translate(-50%, -50%);
|
||||
transition: width 0.6s, height 0.6s;
|
||||
}
|
||||
|
||||
.btn-ripple:active::after {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
transition: 0s;
|
||||
animation: ripple 0.6s ease-out;
|
||||
}
|
||||
|
||||
/* Улучшенная анимация skeleton loader */
|
||||
@keyframes shimmer {
|
||||
0% {
|
||||
background-position: -1000px 0;
|
||||
}
|
||||
100% {
|
||||
background-position: 1000px 0;
|
||||
}
|
||||
}
|
||||
|
||||
.placeholder-glow .placeholder {
|
||||
animation: shimmer 2s infinite linear;
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
#f8f9fa 0%,
|
||||
#e9ecef 50%,
|
||||
#f8f9fa 100%
|
||||
);
|
||||
background-size: 1000px 100%;
|
||||
}
|
||||
|
||||
/* Анимация модальных окон */
|
||||
.modal.fade.show .modal-dialog {
|
||||
animation: modalSlideIn 0.3s ease-out;
|
||||
}
|
||||
|
||||
@keyframes modalSlideIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: scale(0.95) translateY(-20px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: scale(1) translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Плавный скролл */
|
||||
html {
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
|
||||
/* Улучшенные focus rings для доступности */
|
||||
*:focus-visible {
|
||||
outline: 2px solid var(--tblr-primary, #206bc4);
|
||||
outline-offset: 2px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
button:focus-visible,
|
||||
.btn:focus-visible {
|
||||
box-shadow: 0 0 0 3px rgba(32, 107, 196, 0.3);
|
||||
}
|
||||
|
||||
/* Skip link для клавиатурных пользователей */
|
||||
.skip-link {
|
||||
position: absolute;
|
||||
top: -40px;
|
||||
left: 0;
|
||||
background: var(--tblr-primary, #206bc4);
|
||||
color: white;
|
||||
padding: 8px 16px;
|
||||
text-decoration: none;
|
||||
z-index: 10000;
|
||||
border-radius: 0 0 4px 0;
|
||||
transition: top 0.2s;
|
||||
}
|
||||
|
||||
.skip-link:focus {
|
||||
top: 0;
|
||||
}
|
||||
|
||||
/* Hover эффект для строк таблицы с focus */
|
||||
.table tr:focus-within {
|
||||
background-color: rgba(32, 107, 196, 0.05);
|
||||
}
|
||||
|
||||
/* Pulse для кнопок загрузки */
|
||||
.btn.loading {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.btn.loading::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: inherit;
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
transform: translate(-50%, -50%);
|
||||
animation: pulse-button 1.5s infinite;
|
||||
}
|
||||
|
||||
@keyframes pulse-button {
|
||||
0%, 100% {
|
||||
opacity: 0;
|
||||
transform: translate(-50%, -50%) scale(1);
|
||||
}
|
||||
50% {
|
||||
opacity: 1;
|
||||
transform: translate(-50%, -50%) scale(1.05);
|
||||
}
|
||||
}
|
||||
|
||||
/* Анимация badge появления */
|
||||
.badge.animate {
|
||||
animation: badgePop 0.3s cubic-bezier(0.68, -0.55, 0.265, 1.55);
|
||||
}
|
||||
|
||||
@keyframes badgePop {
|
||||
0% {
|
||||
transform: scale(0);
|
||||
}
|
||||
50% {
|
||||
transform: scale(1.1);
|
||||
}
|
||||
100% {
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user