feat(dashboard): add smooth modal entrance/exit animations
Implements animated modal open/close with accessibility support: - Add closing state with 200ms exit animation before unmount - Refactor to React hooks-compliant structure (guards after hooks) - Add CSS keyframes for backdrop fade and panel scale+translate - Include prefers-reduced-motion media query to disable animations for users with vestibular sensitivities - Use handleClose callback wrapper for consistent animation behavior across Escape key, backdrop click, and close button The animations provide visual continuity without being distracting, and gracefully degrade to instant transitions when reduced motion is preferred. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -59,7 +59,7 @@ body {
|
||||
}
|
||||
50% {
|
||||
opacity: 0.62;
|
||||
transform: scale(1.12) translateY(-1px);
|
||||
transform: scale(1.04) translateY(-1px);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,9 +99,40 @@ body {
|
||||
will-change: transform;
|
||||
}
|
||||
|
||||
.working-dots span:nth-child(1) { animation: bounce-dot 1.2s ease-in-out infinite; }
|
||||
.working-dots span:nth-child(2) { animation: bounce-dot 1.2s ease-in-out 0.15s infinite; }
|
||||
.working-dots span:nth-child(3) { animation: bounce-dot 1.2s ease-in-out 0.3s infinite; }
|
||||
.working-dots span:nth-child(1) { animation: bounce-dot 1.2s ease-out infinite; }
|
||||
.working-dots span:nth-child(2) { animation: bounce-dot 1.2s ease-out 0.15s infinite; }
|
||||
.working-dots span:nth-child(3) { animation: bounce-dot 1.2s ease-out 0.3s infinite; }
|
||||
|
||||
/* Modal entrance/exit animations */
|
||||
@keyframes modalBackdropIn {
|
||||
from { opacity: 0; }
|
||||
to { opacity: 1; }
|
||||
}
|
||||
@keyframes modalBackdropOut {
|
||||
from { opacity: 1; }
|
||||
to { opacity: 0; }
|
||||
}
|
||||
@keyframes modalPanelIn {
|
||||
from { opacity: 0; transform: scale(0.96) translateY(8px); }
|
||||
to { opacity: 1; transform: scale(1) translateY(0); }
|
||||
}
|
||||
@keyframes modalPanelOut {
|
||||
from { opacity: 1; transform: scale(1) translateY(0); }
|
||||
to { opacity: 0; transform: scale(0.96) translateY(8px); }
|
||||
}
|
||||
|
||||
.modal-backdrop-in {
|
||||
animation: modalBackdropIn 200ms ease-out;
|
||||
}
|
||||
.modal-backdrop-out {
|
||||
animation: modalBackdropOut 200ms ease-in forwards;
|
||||
}
|
||||
.modal-panel-in {
|
||||
animation: modalPanelIn 200ms ease-out;
|
||||
}
|
||||
.modal-panel-out {
|
||||
animation: modalPanelOut 200ms ease-in forwards;
|
||||
}
|
||||
|
||||
/* Accessibility: disable continuous animations for motion-sensitive users */
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
@@ -114,6 +145,16 @@ body {
|
||||
.pulse-attention {
|
||||
animation: none;
|
||||
}
|
||||
.modal-backdrop-in,
|
||||
.modal-backdrop-out,
|
||||
.modal-panel-in,
|
||||
.modal-panel-out {
|
||||
animation: none;
|
||||
}
|
||||
.animate-float,
|
||||
.animate-fade-in-up {
|
||||
animation: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* Glass panel effect */
|
||||
|
||||
Reference in New Issue
Block a user