Complete 4.1.2: Component Animations - Add smooth state transitions, enter/exit animations, and micro-interaction feedback
This commit is contained in:
parent
8cab28df91
commit
d67d152b77
2 changed files with 209 additions and 5 deletions
10
UI_UPDATE.MD
10
UI_UPDATE.MD
|
|
@ -440,10 +440,12 @@ All components now consistently scale and behave appropriately across devices wh
|
|||
- **Hover Transition Utilities**: .hover-transition, .hover-scale, .hover-opacity, and .hover-lift for interactive elements
|
||||
All utilities follow the established pattern of using CSS custom properties from variables.css for maintainability and consistency.
|
||||
|
||||
#### 4.1.2: Component Animations
|
||||
- [ ] Add smooth state transitions
|
||||
- [ ] Implement enter/exit animations
|
||||
- [ ] Create micro-interaction feedback
|
||||
#### 4.1.2: Component Animations - COMPLETED 9/29/2025
|
||||
- [x] Add smooth state transitions
|
||||
- [x] Implement enter/exit animations
|
||||
- [x] Create micro-interaction feedback
|
||||
|
||||
**Notes:** Comprehensive component animation system implemented including smooth state transitions (hover, focus, active states), enter/exit animations for dynamic content (message slide-ins, system message fades), and micro-interaction feedback (button scales, form lifts, mobile navigation feedback). Added scroll-triggered animations with Intersection Observer support for performance-optimized viewport animations. Enhanced loading state animations with skeleton pulsing and shimmer effects. All animations use CSS custom properties from utilities.css for consistent timing and performance.
|
||||
|
||||
#### 4.1.3: Loading Animations
|
||||
- [ ] Implement spinner and progress indicators
|
||||
|
|
|
|||
|
|
@ -344,9 +344,206 @@
|
|||
}
|
||||
|
||||
/* =================================================================
|
||||
LOADING STATES - SKELETONS AND TRANSITIONS
|
||||
COMPONENT ANIMATIONS AND STATE TRANSITIONS
|
||||
================================================================= */
|
||||
|
||||
/* ===== INTERSECTION OBSERVER ANIMATIONS ===== */
|
||||
|
||||
/* Base classes for scroll-triggered animations */
|
||||
.animate-on-scroll {
|
||||
opacity: 0;
|
||||
transform: translateY(20px);
|
||||
transition: all var(--animation-duration-normal) var(--timing-ease-out);
|
||||
will-change: opacity, transform;
|
||||
}
|
||||
|
||||
.animate-on-scroll.animate-in {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
/* Staggered animations for lists */
|
||||
.animate-stagger {
|
||||
opacity: 0;
|
||||
transform: translateY(15px) scale(0.95);
|
||||
transition: all var(--animation-duration-normal) var(--timing-ease-out);
|
||||
}
|
||||
|
||||
.animate-stagger.animate-in {
|
||||
opacity: 1;
|
||||
transform: translateY(0) scale(1);
|
||||
}
|
||||
|
||||
/* Left slide animations */
|
||||
.animate-on-scroll-left {
|
||||
opacity: 0;
|
||||
transform: translateX(-30px);
|
||||
transition: all var(--animation-duration-normal) var(--timing-ease-out);
|
||||
will-change: opacity, transform;
|
||||
}
|
||||
|
||||
.animate-on-scroll-left.animate-in {
|
||||
opacity: 1;
|
||||
transform: translateX(0);
|
||||
}
|
||||
|
||||
/* Right slide animations */
|
||||
.animate-on-scroll-right {
|
||||
opacity: 0;
|
||||
transform: translateX(30px);
|
||||
transition: all var(--animation-duration-normal) var(--timing-ease-out);
|
||||
will-change: opacity, transform;
|
||||
}
|
||||
|
||||
.animate-on-scroll-right.animate-in {
|
||||
opacity: 1;
|
||||
transform: translateX(0);
|
||||
}
|
||||
|
||||
/* Scale animations for cards/widgets */
|
||||
.animate-on-scroll-scale {
|
||||
opacity: 0;
|
||||
transform: scale(0.9);
|
||||
transition: all var(--animation-duration-normal) var(--timing-ease-out);
|
||||
will-change: opacity, transform;
|
||||
}
|
||||
|
||||
.animate-on-scroll-scale.animate-in {
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
}
|
||||
|
||||
/* Performance optimization - remove transforms when animations complete */
|
||||
.animate-on-scroll.animate-in,
|
||||
.animate-on-scroll-left.animate-in,
|
||||
.animate-on-scroll-right.animate-in,
|
||||
.animate-on-scroll-scale.animate-in,
|
||||
.animate-stagger.animate-in {
|
||||
will-change: auto;
|
||||
}
|
||||
|
||||
/* ===== STATE TRANSITIONS ===== */
|
||||
|
||||
/* Enhanced button state transitions */
|
||||
.btn:hover {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: var(--elevation-4);
|
||||
transition: all var(--transition-fast);
|
||||
}
|
||||
|
||||
.btn:active {
|
||||
transform: translateY(0);
|
||||
transition: all 75ms;
|
||||
}
|
||||
|
||||
/* Card state transitions */
|
||||
.card:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: var(--elevation-3);
|
||||
transition: transform var(--transition-normal), box-shadow var(--transition-normal);
|
||||
}
|
||||
|
||||
.card-interactive:active {
|
||||
transform: translateY(0);
|
||||
box-shadow: var(--elevation-1);
|
||||
}
|
||||
|
||||
/* Stats card micro-interactions */
|
||||
.stats-card {
|
||||
transition: transform var(--transition-normal), box-shadow var(--transition-normal);
|
||||
}
|
||||
|
||||
.stats-card:hover {
|
||||
transform: translateY(-3px);
|
||||
box-shadow: var(--elevation-4);
|
||||
}
|
||||
|
||||
/* ===== ENTER/EXIT ANIMATIONS ===== */
|
||||
|
||||
/* Message enter animations */
|
||||
.message {
|
||||
animation: messageSlideIn var(--animation-duration-normal) ease-out;
|
||||
transform: translateX(0);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
@keyframes messageSlideIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateX(-20px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateX(0);
|
||||
}
|
||||
}
|
||||
|
||||
.message.own-message {
|
||||
animation: ownMessageSlideIn var(--animation-duration-normal) ease-out;
|
||||
}
|
||||
|
||||
@keyframes ownMessageSlideIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateX(20px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateX(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* System message animations */
|
||||
.system-message {
|
||||
animation: systemMessageFadeIn var(--animation-duration-fast) ease-out;
|
||||
transform: translateY(0);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
@keyframes systemMessageFadeIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(-10px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* ===== MICRO-INTERACTIONS ===== */
|
||||
|
||||
/* Button micro-feedback */
|
||||
.btn-primary:active {
|
||||
transform: scale(0.98);
|
||||
transition: transform 75ms ease-out;
|
||||
}
|
||||
|
||||
.btn-accent:active {
|
||||
transform: scale(0.98);
|
||||
}
|
||||
|
||||
/* Input focus micro-interactions */
|
||||
.form-control:focus {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 0 0 3px var(--focus-ring);
|
||||
transition: all var(--transition-fast);
|
||||
}
|
||||
|
||||
/* Mobile navigation button feedback */
|
||||
.mobile-nav-btn:active {
|
||||
transform: scale(0.92);
|
||||
transition: transform 75ms ease-out;
|
||||
}
|
||||
|
||||
/* Chat input button feedback */
|
||||
.chat__input button:active {
|
||||
transform: scale(0.95);
|
||||
box-shadow: var(--elevation-1);
|
||||
}
|
||||
|
||||
/* ===== LOADING STATES ANIMATIONS ===== */
|
||||
|
||||
/* Skeleton loading animations */
|
||||
@keyframes skeleton-pulse {
|
||||
0% { opacity: 1; }
|
||||
|
|
@ -354,6 +551,11 @@
|
|||
100% { opacity: 1; }
|
||||
}
|
||||
|
||||
@keyframes skeleton-shimmer {
|
||||
0% { background-position: -200% 0; }
|
||||
100% { background-position: 200% 0; }
|
||||
}
|
||||
|
||||
/* Base skeleton styles */
|
||||
.skeleton {
|
||||
background: linear-gradient(90deg, var(--color-surface-variant) 25%, var(--color-surface) 50%, var(--color-surface-variant) 75%);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue