feat(frontend): add dynamic animations to login and admin panel
This commit is contained in:
@@ -134,6 +134,15 @@ body {
|
||||
.nav-item:hover {
|
||||
background: var(--bg-hover);
|
||||
color: var(--text-primary);
|
||||
transform: translateX(4px);
|
||||
}
|
||||
|
||||
.nav-item svg {
|
||||
transition: transform var(--transition);
|
||||
}
|
||||
|
||||
.nav-item:hover svg {
|
||||
transform: scale(1.1);
|
||||
}
|
||||
|
||||
.nav-item.active {
|
||||
@@ -199,12 +208,38 @@ body {
|
||||
}
|
||||
|
||||
/* ===== Cards ===== */
|
||||
@keyframes slideUpCard {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(15px);
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
.card {
|
||||
background: var(--bg-card);
|
||||
border: 1px solid var(--bg-card-border);
|
||||
border-radius: var(--radius-md);
|
||||
padding: 1.5rem;
|
||||
transition: background 0.4s ease, border-color 0.4s ease;
|
||||
animation: slideUpCard 0.4s ease-out both;
|
||||
}
|
||||
|
||||
/* Staggered cards */
|
||||
.card:nth-child(1) {
|
||||
animation-delay: 0.1s;
|
||||
}
|
||||
|
||||
.card:nth-child(2) {
|
||||
animation-delay: 0.2s;
|
||||
}
|
||||
|
||||
.card:nth-child(3) {
|
||||
animation-delay: 0.3s;
|
||||
}
|
||||
|
||||
.card h2 {
|
||||
@@ -298,6 +333,18 @@ body {
|
||||
box-shadow: 0 4px 16px var(--accent-glow);
|
||||
}
|
||||
|
||||
@keyframes slideDownAlert {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(-10px);
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
.form-alert {
|
||||
display: none;
|
||||
padding: 0.6rem 1rem;
|
||||
@@ -311,6 +358,7 @@ body {
|
||||
background: rgba(248, 113, 113, 0.1);
|
||||
border: 1px solid rgba(248, 113, 113, 0.2);
|
||||
color: var(--error);
|
||||
animation: slideDownAlert 0.3s ease-out both;
|
||||
}
|
||||
|
||||
.form-alert.success {
|
||||
@@ -318,6 +366,7 @@ body {
|
||||
background: rgba(52, 211, 153, 0.1);
|
||||
border: 1px solid rgba(52, 211, 153, 0.2);
|
||||
color: var(--success);
|
||||
animation: slideDownAlert 0.3s ease-out both;
|
||||
}
|
||||
|
||||
/* ===== Table ===== */
|
||||
@@ -347,8 +396,45 @@ tbody td {
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.03);
|
||||
}
|
||||
|
||||
@keyframes slideInRow {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateX(-10px);
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateX(0);
|
||||
}
|
||||
}
|
||||
|
||||
tbody tr {
|
||||
transition: background var(--transition);
|
||||
animation: slideInRow 0.3s ease-out both;
|
||||
}
|
||||
|
||||
tbody tr:nth-child(1) {
|
||||
animation-delay: 0.05s;
|
||||
}
|
||||
|
||||
tbody tr:nth-child(2) {
|
||||
animation-delay: 0.1s;
|
||||
}
|
||||
|
||||
tbody tr:nth-child(3) {
|
||||
animation-delay: 0.15s;
|
||||
}
|
||||
|
||||
tbody tr:nth-child(4) {
|
||||
animation-delay: 0.2s;
|
||||
}
|
||||
|
||||
tbody tr:nth-child(5) {
|
||||
animation-delay: 0.25s;
|
||||
}
|
||||
|
||||
tbody tr:nth-child(n+6) {
|
||||
animation-delay: 0.3s;
|
||||
}
|
||||
|
||||
tbody tr:hover {
|
||||
@@ -477,11 +563,29 @@ tbody tr:hover {
|
||||
font-family: inherit;
|
||||
font-size: 0.8rem;
|
||||
cursor: pointer;
|
||||
transition: background var(--transition);
|
||||
transition: background var(--transition), transform var(--transition);
|
||||
}
|
||||
|
||||
.btn-delete:hover {
|
||||
background: rgba(248, 113, 113, 0.2);
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
/* ===== Ripple Effect ===== */
|
||||
.ripple {
|
||||
position: absolute;
|
||||
border-radius: 50%;
|
||||
transform: scale(0);
|
||||
animation: admin-ripple 0.6s linear;
|
||||
background-color: rgba(255, 255, 255, 0.3);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
@keyframes admin-ripple {
|
||||
to {
|
||||
transform: scale(4);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* ===== Mobile Menu Toggle ===== */
|
||||
|
||||
@@ -16,6 +16,30 @@
|
||||
const sidebar = document.querySelector('.sidebar');
|
||||
const sidebarOverlay = document.getElementById('sidebar-overlay');
|
||||
|
||||
// Global Ripple Effect
|
||||
document.addEventListener('click', function (e) {
|
||||
const btn = e.target.closest('.btn-create, .btn-delete, .btn-logout');
|
||||
if (!btn) return;
|
||||
|
||||
const rect = btn.getBoundingClientRect();
|
||||
const x = e.clientX - rect.left;
|
||||
const y = e.clientY - rect.top;
|
||||
|
||||
const ripple = document.createElement('span');
|
||||
ripple.classList.add('ripple');
|
||||
ripple.style.left = `${x}px`;
|
||||
ripple.style.top = `${y}px`;
|
||||
|
||||
if (getComputedStyle(btn).position === 'static') {
|
||||
btn.style.position = 'relative';
|
||||
}
|
||||
btn.style.overflow = 'hidden';
|
||||
|
||||
btn.appendChild(ripple);
|
||||
|
||||
setTimeout(() => ripple.remove(), 600);
|
||||
});
|
||||
|
||||
// Users
|
||||
const usersTbody = document.getElementById('users-tbody');
|
||||
const createForm = document.getElementById('create-form');
|
||||
|
||||
Reference in New Issue
Block a user