From 8cab28df91c43885ea1c9f16c846a88d53dd1be1 Mon Sep 17 00:00:00 2001 From: VinnyNC Date: Mon, 29 Sep 2025 22:37:40 -0400 Subject: [PATCH] Complete 4.1.1: Transition Library - CSS transition utilities, timing functions, and duration constants --- UI_UPDATE.MD | 19 ++- static/css/utilities.css | 323 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 338 insertions(+), 4 deletions(-) diff --git a/UI_UPDATE.MD b/UI_UPDATE.MD index c1fb21d..94a7213 100644 --- a/UI_UPDATE.MD +++ b/UI_UPDATE.MD @@ -424,10 +424,21 @@ All components now consistently scale and behave appropriately across devices wh ### Sub-task 4.1: Animations and Transitions System -#### 4.1.1: Transition Library -- [ ] Implement CSS transition utilities -- [ ] Create consistent timing functions -- [ ] Define transition duration constants +#### 4.1.1: Transition Library - COMPLETED 9/29/2025 +- [x] Implement CSS transition utilities +- [x] Create consistent timing functions +- [x] Define transition duration constants + +**Notes:** Comprehensive transition and animation utilities library implemented in utilities.css with: +- **CSS Custom Properties**: --duration-fast (150ms), --duration-normal (250ms), --duration-slow (350ms), --animation-duration-fast (200ms), --animation-duration-normal (300ms), --animation-duration-slow (500ms), and timing functions (--timing-linear, --timing-ease, etc.) defined in :root +- **Transition Property Utilities**: .transition-all, .transition-colors, .transition-opacity, .transition-shadow, .transition-transform, and .transition-text classes targeting specific CSS properties +- **Transition Duration Utilities**: .duration-fast, .duration-normal, .duration-slow, and precise durations from .duration-75 to .duration-1000 +- **Timing Function Utilities**: .ease-linear, .ease-in, .ease-out, .ease-in-out, .ease-spring, and .ease-bounce for different animation feels +- **Keyframe Animations**: Comprehensive set of @keyframes for fade, slide, scale, pulse, bounce, spin, ping, and shake animations +- **Animation Utility Classes**: .animate-fade-in, .animate-slide-in-left, .animate-scale-out, .animate-pulse, .animate-spin, etc. using the CSS custom properties for consistent timing +- **Animation Modifiers**: Duration modifiers, timing function modifiers, direction and fill mode controls, and play state controls +- **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 diff --git a/static/css/utilities.css b/static/css/utilities.css index d224e6a..c7319ee 100644 --- a/static/css/utilities.css +++ b/static/css/utilities.css @@ -956,3 +956,326 @@ .content-between { align-content: space-between; } .content-around { align-content: space-around; } .content-stretch { align-content: stretch; } + +/* ================================================================= + TRANSITION AND ANIMATION UTILITIES + ================================================================= */ + +:root { + /* Transition Duration Constants - Using CSS Custom Properties */ + --duration-fast: 150ms; + --duration-normal: 250ms; + --duration-slow: 350ms; + + /* Animation Duration Constants */ + --animation-duration-fast: 200ms; + --animation-duration-normal: 300ms; + --animation-duration-slow: 500ms; + + /* Timing Functions */ + --timing-linear: linear; + --timing-ease: ease; + --timing-ease-in: ease-in; + --timing-ease-out: ease-out; + --timing-ease-in-out: ease-in-out; +} + +/* ===== TRANSITION UTILITIES ===== */ + +/* Transition Property Utilities */ +.transition-all { + transition-property: all; + transition-duration: var(--duration-normal); + transition-timing-function: var(--timing-ease); +} + +.transition-none { + transition-property: none; +} + +.transition-colors { + transition-property: color, background-color, border-color, text-decoration-color, fill, stroke; + transition-duration: var(--duration-normal); + transition-timing-function: var(--timing-ease); +} + +.transition-opacity { + transition-property: opacity; + transition-duration: var(--duration-normal); + transition-timing-function: var(--timing-ease); +} + +.transition-shadow { + transition-property: box-shadow; + transition-duration: var(--duration-normal); + transition-timing-function: var(--timing-ease); +} + +.transition-transform { + transition-property: transform; + transition-duration: var(--duration-normal); + transition-timing-function: var(--timing-ease); +} + +.transition-text { + transition-property: color, font-size, font-weight, letter-spacing, line-height, text-decoration, text-underline-offset; + transition-duration: var(--duration-normal); + transition-timing-function: var(--timing-ease); +} + +/* Transition Duration Utilities */ +.duration-fast { + transition-duration: var(--duration-fast); +} + +.duration-normal { + transition-duration: var(--duration-normal); +} + +.duration-slow { + transition-duration: var(--duration-slow); +} + +.duration-75 { transition-duration: 75ms; } +.duration-100 { transition-duration: 100ms; } +.duration-150 { transition-duration: 150ms; } +.duration-200 { transition-duration: 200ms; } +.duration-300 { transition-duration: 300ms; } +.duration-500 { transition-duration: 500ms; } +.duration-700 { transition-duration: 700ms; } +.duration-1000 { transition-duration: 1000ms; } + +/* Timing Function Utilities */ +.ease-linear { transition-timing-function: var(--timing-linear); } +.ease-in { transition-timing-function: var(--timing-ease-in); } +.ease-out { transition-timing-function: var(--timing-ease-out); } +.ease-in-out { transition-timing-function: var(--timing-ease-in-out); } +.ease-spring { transition-timing-function: cubic-bezier(0.68, -0.55, 0.265, 1.55); } +.ease-bounce { transition-timing-function: cubic-bezier(0.68, -0.55, 0.265, 1.55); } + +/* ===== ANIMATION UTILITIES ===== */ + +/* Keyframe Animations */ + +/* Fade animations */ +@keyframes fadeIn { + from { opacity: 0; } + to { opacity: 1; } +} + +@keyframes fadeOut { + from { opacity: 1; } + to { opacity: 0; } +} + +@keyframes fadeInUp { + from { + opacity: 0; + transform: translateY(10px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +@keyframes fadeInDown { + from { + opacity: 0; + transform: translateY(-10px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +/* Slide animations */ +@keyframes slideInFromLeft { + from { transform: translateX(-100%); } + to { transform: translateX(0); } +} + +@keyframes slideInFromRight { + from { transform: translateX(100%); } + to { transform: translateX(0); } +} + +@keyframes slideOutToLeft { + from { transform: translateX(0); } + to { transform: translateX(-100%); } +} + +@keyframes slideOutToRight { + from { transform: translateX(0); } + to { transform: translateX(100%); } +} + +/* Scale animations */ +@keyframes scaleIn { + from { transform: scale(0.9); opacity: 0; } + to { transform: scale(1); opacity: 1; } +} + +@keyframes scaleOut { + from { transform: scale(1); opacity: 1; } + to { transform: scale(0.9); opacity: 0; } +} + +/* Pulse animation */ +@keyframes pulse { + 0%, 100% { opacity: 1; } + 50% { opacity: .5; } +} + +/* Bounce animation */ +@keyframes bounce { + 0%, 20%, 53%, 80%, 100% { animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); transform: translate3d(0, 0, 0); } + 40%, 43% { animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06); transform: translate3d(0, -30px, 0); } + 70% { animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06); transform: translate3d(0, -15px, 0); } + 90% { transform: translate3d(0, -4px, 0); } +} + +/* Spin animation */ +@keyframes spin { + to { transform: rotate(360deg); } +} + +/* Ping animation */ +@keyframes ping { + 75%, 100% { transform: scale(2); opacity: 0; } +} + +/* Shake animation */ +@keyframes shake { + 0%, 100% { transform: translateX(0); } + 10%, 30%, 50%, 70%, 90% { transform: translateX(-10px); } + 20%, 40%, 60%, 80% { transform: translateX(10px); } +} + +/* Animation Utility Classes */ + +/* Fade animations */ +.animate-fade-in { + animation: fadeIn var(--animation-duration-normal) var(--timing-ease-out); +} + +.animate-fade-out { + animation: fadeOut var(--animation-duration-normal) var(--timing-ease-out); +} + +.animate-fade-in-up { + animation: fadeInUp var(--animation-duration-normal) var(--timing-ease-out); +} + +.animate-fade-in-down { + animation: fadeInDown var(--animation-duration-normal) var(--timing-ease-out); +} + +/* Slide animations */ +.animate-slide-in-left { + animation: slideInFromLeft var(--animation-duration-normal) var(--timing-ease-out); +} + +.animate-slide-in-right { + animation: slideInFromRight var(--animation-duration-normal) var(--timing-ease-out); +} + +.animate-slide-out-left { + animation: slideOutToLeft var(--animation-duration-normal) var(--timing-ease-out); +} + +.animate-slide-out-right { + animation: slideOutToRight var(--animation-duration-normal) var(--timing-ease-out); +} + +/* Scale animations */ +.animate-scale-in { + animation: scaleIn var(--animation-duration-normal) var(--timing-ease-out); +} + +.animate-scale-out { + animation: scaleOut var(--animation-duration-normal) var(--timing-ease-out); +} + +/* Special animations */ +.animate-pulse { + animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite; +} + +.animate-bounce { + animation: bounce 1s infinite; +} + +.animate-spin { + animation: spin 1s linear infinite; +} + +.animate-ping { + animation: ping 1s cubic-bezier(0.215, 0.61, 0.355, 1) infinite; +} + +.animate-shake { + animation: shake 0.5s ease-in-out; +} + +/* Animation Duration Modifiers */ +.animate-duration-fast { animation-duration: var(--animation-duration-fast); } +.animate-duration-normal { animation-duration: var(--animation-duration-normal); } +.animate-duration-slow { animation-duration: var(--animation-duration-slow); } +.animate-duration-75 { animation-duration: 75ms; } +.animate-duration-100 { animation-duration: 100ms; } +.animate-duration-200 { animation-duration: 200ms; } +.animate-duration-300 { animation-duration: 300ms; } +.animate-duration-500 { animation-duration: 500ms; } +.animate-duration-700 { animation-duration: 700ms; } +.animate-duration-1000 { animation-duration: 1000ms; } + +/* Animation Timing Modifiers */ +.animate-ease-linear { animation-timing-function: linear; } +.animate-ease-in { animation-timing-function: ease-in; } +.animate-ease-out { animation-timing-function: ease-out; } +.animate-ease-in-out { animation-timing-function: ease-in-out; } + +/* Animation Direction and Fill Mode */ +.animate-forwards { animation-fill-mode: forwards; } +.animate-backwards { animation-fill-mode: backwards; } +.animate-both { animation-fill-mode: both; } +.animate-alternate { animation-direction: alternate; } +.animate-reverse { animation-direction: reverse; } + +/* Animation States */ +.animate-paused { animation-play-state: paused; } +.animate-running { animation-play-state: running; } + +/* ===== HOVER TRANSITIONS ===== */ + +/* Hover transition triggers for interactive elements */ +.hover-transition { + transition: all var(--duration-normal) var(--timing-ease); +} + +.hover-scale { + transition: transform var(--duration-normal) var(--timing-ease); +} + +.hover-scale:hover { + transform: scale(1.02); +} + +.hover-opacity { + transition: opacity var(--duration-normal) var(--timing-ease); +} + +.hover-opacity:hover { + opacity: 0.8; +} + +.hover-lift { + transition: transform var(--duration-normal) var(--timing-ease), box-shadow var(--duration-normal) var(--timing-ease); +} + +.hover-lift:hover { + transform: translateY(-2px); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); +}