Changeset 3390988
- Timestamp:
- 11/06/2025 10:19:27 AM (4 months ago)
- Location:
- serend-animations
- Files:
-
- 1 added
- 2 deleted
- 15 edited
-
assets/banner-1544x500-de.png (deleted)
-
assets/banner-1544x500.png (modified) (previous)
-
assets/banner-772x250-de.png (deleted)
-
assets/banner-772x250.png (modified) (previous)
-
assets/screenshot-1.png (modified) (previous)
-
assets/screenshot-2.png (modified) (previous)
-
assets/screenshot-3.png (modified) (previous)
-
trunk/CHANGELOG.md (modified) (1 diff)
-
trunk/includes/assets/css/animations.css (modified) (11 diffs)
-
trunk/includes/assets/css/editor.css (added)
-
trunk/includes/assets/img/picture-admin.png (modified) (previous)
-
trunk/includes/assets/js/animations.js (modified) (3 diffs)
-
trunk/includes/assets/js/editor.js (modified) (5 diffs)
-
trunk/includes/serend-animations-functions.php (modified) (4 diffs)
-
trunk/languages/serend-animations-de_DE.mo (modified) (previous)
-
trunk/languages/serend-animations-de_DE.po (modified) (2 diffs)
-
trunk/readme.txt (modified) (9 diffs)
-
trunk/serend-animations.php (modified) (10 diffs)
Legend:
- Unmodified
- Added
- Removed
-
serend-animations/trunk/CHANGELOG.md
r3368477 r3390988 5 5 The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 6 6 and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 7 8 ## [1.0.3] - 2025-01-29 9 10 ### Added 11 - **Direction buttons for ALL animations**: Visual arrow buttons to select animation direction (top, right, bottom, left) 12 - **Slow Motion toggle**: Make any animation 1.5x slower with a simple toggle switch 13 - **Universal direction support**: All animation types (Fade, Zoom, Rotate, Bounce, Flip) now support all 4 directions 14 - **20 new animation variants**: Each animation type now has 4 directional variants 15 - Zoom: zoom-in, zoom-in-left, zoom-in-right, zoom-in-top 16 - Rotate: rotate-in, rotate-in-left, rotate-in-right, rotate-in-top 17 - Bounce: bounce-in, bounce-in-left, bounce-in-right, bounce-in-top 18 - Flip: flip-in (X-axis), flip-in-left (Y-axis), flip-in-right (Y-axis), flip-in-top (X-axis) 19 - **Visual direction picker**: Intuitive icon-based buttons with rotated arrow SVGs 20 - **Slow modifier class**: New `animation-slow` class works across all animations 21 22 ### Changed 23 - **Simplified UI**: Cleaner dropdown with base animation types (Fade, Zoom, Rotate, Bounce, Flip) 24 - **Direction selection**: Moved from dropdown to visual button grid for better UX 25 - **Removed "Fade In Slow"**: Replaced with universal "Slow Motion" toggle for all animations 26 - **Delay behavior**: Animation delay no longer triggers editor preview (frontend-only) 27 - **Future-proof selectors**: Frontend JavaScript now uses attribute selectors for better maintainability 28 29 ### Fixed 30 - Fixed `scroll-fade-in-top` and other directional variants not triggering `fade-in-visible` class 31 - Frontend animation detection now works with all new animation variants 32 - Editor preview optimization (delay changes don't re-trigger preview) 33 34 ### Technical Improvements 35 - **CSS architecture**: Organized animations by type with clear section comments 36 - **Universal slow modifier**: Single `animation-slow` class affects all animation types 37 - **Optimized CSS selectors**: Wildcard selectors for performance (`[class*="scroll-"]`) 38 - **Reduced code duplication**: Eliminated need for separate "slow" animation variants 39 - **Better scalability**: New direction system makes adding animations easier 40 - **Smarter JavaScript**: Attribute-based selectors catch all current and future animation variants 41 - **Enhanced keyframes**: Complete set of directional keyframes for editor preview 42 - **Improved class management**: Better handling of animation-slow and direction classes 43 44 ## [1.0.2] - 2025-01-28 45 46 ### Added 47 - Live animation preview in Gutenberg editor with "Show Animation" button 48 - Automatic animation preview when selecting or changing animations 49 - Automatic animation preview when changing delay values 50 - Support for all third-party blocks (Yoast SEO, Rank Math, etc.) 51 - Animation preview works in iframe editor context 52 53 ### Fixed 54 - Animation classes now properly cleaned up when switching animations 55 - No more orphaned class fragments (like `-left`, `-right`, `-slow`) 56 - Correct animation detection for compound classes (e.g., `scroll-fade-in-left`) 57 - Elements remain visible in editor while supporting animation previews 58 - Animation dropdown now shows correct selection after changing animations 59 - Fade In animations now work correctly across all variants 60 61 ### Changed 62 - Improved className management with array-based filtering 63 - Animation class extraction now prioritizes longest matches first 64 - Simplified animation preview logic (always animates block element) 65 - Removed debug console logs for production-ready code 66 - Enhanced editor CSS with `:not()` selectors for better performance 67 68 ### Technical Improvements 69 - Uses `className` attribute directly (WordPress standard) 70 - Compatible with server-side rendered blocks 71 - Cleaner code structure with reduced complexity 72 - Better iframe handling for editor context 73 - Optimized CSS specificity for editor styles 7 74 8 75 ## [1.0.1] - 2025-01-27 -
serend-animations/trunk/includes/assets/css/animations.css
r3368477 r3390988 1 1 /* Gutenberg Animations CSS */ 2 2 3 /* Scroll Fade-In Animation (Standard - von unten) */ 4 .scroll-fade-in { 3 /* ============================================ 4 FADE ANIMATIONS 5 ============================================ */ 6 7 /* Fade-In from bottom (default) */ 8 body:not(.block-editor-page) .scroll-fade-in { 5 9 opacity: 0; 6 10 transform: translateY(30px); … … 8 12 } 9 13 10 .scroll-fade-in.fade-in-visible {14 body:not(.block-editor-page) .scroll-fade-in.fade-in-visible { 11 15 opacity: 1; 12 16 transform: translateY(0); … … 14 18 15 19 /* Fade-In from left */ 16 .scroll-fade-in-left {20 body:not(.block-editor-page) .scroll-fade-in-left { 17 21 opacity: 0; 18 22 transform: translateX(-30px); … … 20 24 } 21 25 22 .scroll-fade-in-left.fade-in-visible {26 body:not(.block-editor-page) .scroll-fade-in-left.fade-in-visible { 23 27 opacity: 1; 24 28 transform: translateX(0); … … 26 30 27 31 /* Fade-In from right */ 28 .scroll-fade-in-right {32 body:not(.block-editor-page) .scroll-fade-in-right { 29 33 opacity: 0; 30 34 transform: translateX(30px); … … 32 36 } 33 37 34 .scroll-fade-in-right.fade-in-visible {38 body:not(.block-editor-page) .scroll-fade-in-right.fade-in-visible { 35 39 opacity: 1; 36 40 transform: translateX(0); 37 41 } 38 42 39 /* Slower animation (from bottom)*/40 .scroll-fade-in-slow{41 opacity: 0; 42 transform: translateY( 30px);43 transition: opacity 1.2s ease-out, transform 1.2s ease-out;44 } 45 46 .scroll-fade-in-slow.fade-in-visible {43 /* Fade-In from top */ 44 body:not(.block-editor-page) .scroll-fade-in-top { 45 opacity: 0; 46 transform: translateY(-30px); 47 transition: opacity 0.8s ease-out, transform 0.8s ease-out; 48 } 49 50 body:not(.block-editor-page) .scroll-fade-in-top.fade-in-visible { 47 51 opacity: 1; 48 52 transform: translateY(0); 49 53 } 50 54 51 /* Additional animations */ 52 53 /* Zoom-In Effekt */ 54 .scroll-zoom-in { 55 opacity: 0; 56 transform: scale(0.8); 57 transition: opacity 0.8s ease-out, transform 0.8s ease-out; 58 } 59 60 .scroll-zoom-in.fade-in-visible { 61 opacity: 1; 62 transform: scale(1); 63 } 64 65 /* Rotation Effekt */ 66 .scroll-rotate-in { 67 opacity: 0; 68 transform: rotate(10deg) scale(0.9); 69 transition: opacity 0.8s ease-out, transform 0.8s ease-out; 70 } 71 72 .scroll-rotate-in.fade-in-visible { 73 opacity: 1; 74 transform: rotate(0deg) scale(1); 75 } 76 77 /* Bounce Effekt */ 78 .scroll-bounce-in { 55 /* ============================================ 56 ZOOM ANIMATIONS 57 ============================================ */ 58 59 /* Zoom-In from bottom (default) */ 60 body:not(.block-editor-page) .scroll-zoom-in { 61 opacity: 0; 62 transform: scale(0.8) translateY(30px); 63 transition: opacity 0.8s ease-out, transform 0.8s ease-out; 64 } 65 66 body:not(.block-editor-page) .scroll-zoom-in.fade-in-visible { 67 opacity: 1; 68 transform: scale(1) translateY(0); 69 } 70 71 /* Zoom-In from left */ 72 body:not(.block-editor-page) .scroll-zoom-in-left { 73 opacity: 0; 74 transform: scale(0.8) translateX(-30px); 75 transition: opacity 0.8s ease-out, transform 0.8s ease-out; 76 } 77 78 body:not(.block-editor-page) .scroll-zoom-in-left.fade-in-visible { 79 opacity: 1; 80 transform: scale(1) translateX(0); 81 } 82 83 /* Zoom-In from right */ 84 body:not(.block-editor-page) .scroll-zoom-in-right { 85 opacity: 0; 86 transform: scale(0.8) translateX(30px); 87 transition: opacity 0.8s ease-out, transform 0.8s ease-out; 88 } 89 90 body:not(.block-editor-page) .scroll-zoom-in-right.fade-in-visible { 91 opacity: 1; 92 transform: scale(1) translateX(0); 93 } 94 95 /* Zoom-In from top */ 96 body:not(.block-editor-page) .scroll-zoom-in-top { 97 opacity: 0; 98 transform: scale(0.8) translateY(-30px); 99 transition: opacity 0.8s ease-out, transform 0.8s ease-out; 100 } 101 102 body:not(.block-editor-page) .scroll-zoom-in-top.fade-in-visible { 103 opacity: 1; 104 transform: scale(1) translateY(0); 105 } 106 107 /* ============================================ 108 ROTATE ANIMATIONS 109 ============================================ */ 110 111 /* Rotate-In from bottom (default) */ 112 body:not(.block-editor-page) .scroll-rotate-in { 113 opacity: 0; 114 transform: rotate(-10deg) scale(0.9) translateY(30px); 115 transition: opacity 0.8s ease-out, transform 0.8s ease-out; 116 } 117 118 body:not(.block-editor-page) .scroll-rotate-in.fade-in-visible { 119 opacity: 1; 120 transform: rotate(0deg) scale(1) translateY(0); 121 } 122 123 /* Rotate-In from left */ 124 body:not(.block-editor-page) .scroll-rotate-in-left { 125 opacity: 0; 126 transform: rotate(-10deg) scale(0.9) translateX(-30px); 127 transition: opacity 0.8s ease-out, transform 0.8s ease-out; 128 } 129 130 body:not(.block-editor-page) .scroll-rotate-in-left.fade-in-visible { 131 opacity: 1; 132 transform: rotate(0deg) scale(1) translateX(0); 133 } 134 135 /* Rotate-In from right */ 136 body:not(.block-editor-page) .scroll-rotate-in-right { 137 opacity: 0; 138 transform: rotate(10deg) scale(0.9) translateX(30px); 139 transition: opacity 0.8s ease-out, transform 0.8s ease-out; 140 } 141 142 body:not(.block-editor-page) .scroll-rotate-in-right.fade-in-visible { 143 opacity: 1; 144 transform: rotate(0deg) scale(1) translateX(0); 145 } 146 147 /* Rotate-In from top */ 148 body:not(.block-editor-page) .scroll-rotate-in-top { 149 opacity: 0; 150 transform: rotate(-10deg) scale(0.9) translateY(-30px); 151 transition: opacity 0.8s ease-out, transform 0.8s ease-out; 152 } 153 154 body:not(.block-editor-page) .scroll-rotate-in-top.fade-in-visible { 155 opacity: 1; 156 transform: rotate(0deg) scale(1) translateY(0); 157 } 158 159 /* ============================================ 160 BOUNCE ANIMATIONS 161 ============================================ */ 162 163 /* Bounce-In from bottom (default) */ 164 body:not(.block-editor-page) .scroll-bounce-in { 79 165 opacity: 0; 80 166 transform: translateY(50px); … … 82 168 } 83 169 84 .scroll-bounce-in.fade-in-visible {170 body:not(.block-editor-page) .scroll-bounce-in.fade-in-visible { 85 171 opacity: 1; 86 172 transform: translateY(0); 87 173 } 88 174 89 /* Flip Effekt */ 90 .scroll-flip-in { 175 /* Bounce-In from left */ 176 body:not(.block-editor-page) .scroll-bounce-in-left { 177 opacity: 0; 178 transform: translateX(-50px); 179 transition: opacity 0.6s ease-out, transform 0.6s cubic-bezier(0.68, -0.55, 0.265, 1.55); 180 } 181 182 body:not(.block-editor-page) .scroll-bounce-in-left.fade-in-visible { 183 opacity: 1; 184 transform: translateX(0); 185 } 186 187 /* Bounce-In from right */ 188 body:not(.block-editor-page) .scroll-bounce-in-right { 189 opacity: 0; 190 transform: translateX(50px); 191 transition: opacity 0.6s ease-out, transform 0.6s cubic-bezier(0.68, -0.55, 0.265, 1.55); 192 } 193 194 body:not(.block-editor-page) .scroll-bounce-in-right.fade-in-visible { 195 opacity: 1; 196 transform: translateX(0); 197 } 198 199 /* Bounce-In from top */ 200 body:not(.block-editor-page) .scroll-bounce-in-top { 201 opacity: 0; 202 transform: translateY(-50px); 203 transition: opacity 0.6s ease-out, transform 0.6s cubic-bezier(0.68, -0.55, 0.265, 1.55); 204 } 205 206 body:not(.block-editor-page) .scroll-bounce-in-top.fade-in-visible { 207 opacity: 1; 208 transform: translateY(0); 209 } 210 211 /* ============================================ 212 FLIP ANIMATIONS 213 ============================================ */ 214 215 /* Flip-In from bottom (default - rotateX) */ 216 body:not(.block-editor-page) .scroll-flip-in { 217 opacity: 0; 218 transform: perspective(400px) rotateX(90deg); 219 transition: opacity 0.8s ease-out, transform 0.8s ease-out; 220 } 221 222 body:not(.block-editor-page) .scroll-flip-in.fade-in-visible { 223 opacity: 1; 224 transform: perspective(400px) rotateX(0deg); 225 } 226 227 /* Flip-In from left (rotateY) */ 228 body:not(.block-editor-page) .scroll-flip-in-left { 229 opacity: 0; 230 transform: perspective(400px) rotateY(-90deg); 231 transition: opacity 0.8s ease-out, transform 0.8s ease-out; 232 } 233 234 body:not(.block-editor-page) .scroll-flip-in-left.fade-in-visible { 235 opacity: 1; 236 transform: perspective(400px) rotateY(0deg); 237 } 238 239 /* Flip-In from right (rotateY) */ 240 body:not(.block-editor-page) .scroll-flip-in-right { 91 241 opacity: 0; 92 242 transform: perspective(400px) rotateY(90deg); … … 94 244 } 95 245 96 .scroll-flip-in.fade-in-visible {246 body:not(.block-editor-page) .scroll-flip-in-right.fade-in-visible { 97 247 opacity: 1; 98 248 transform: perspective(400px) rotateY(0deg); 249 } 250 251 /* Flip-In from top (rotateX) */ 252 body:not(.block-editor-page) .scroll-flip-in-top { 253 opacity: 0; 254 transform: perspective(400px) rotateX(-90deg); 255 transition: opacity 0.8s ease-out, transform 0.8s ease-out; 256 } 257 258 body:not(.block-editor-page) .scroll-flip-in-top.fade-in-visible { 259 opacity: 1; 260 transform: perspective(400px) rotateX(0deg); 261 } 262 263 /* ============================================ 264 SLOW MODIFIER 265 Macht alle Animationen langsamer (1.5x) 266 ============================================ */ 267 268 body:not(.block-editor-page) [class*="scroll-"].animation-slow { 269 transition-duration: 1.2s !important; 270 } 271 272 body:not(.block-editor-page) .scroll-bounce-in.animation-slow, 273 body:not(.block-editor-page) .scroll-bounce-in-left.animation-slow, 274 body:not(.block-editor-page) .scroll-bounce-in-right.animation-slow, 275 body:not(.block-editor-page) .scroll-bounce-in-top.animation-slow { 276 transition-duration: 0.9s !important; 99 277 } 100 278 … … 124 302 125 303 /* Performance optimizations */ 126 .scroll-fade-in, 127 .scroll-fade-in-left, 128 .scroll-fade-in-right, 129 .scroll-fade-in-slow, 130 .scroll-zoom-in, 131 .scroll-rotate-in, 132 .scroll-bounce-in, 133 .scroll-flip-in { 304 [class*="scroll-fade-"], 305 [class*="scroll-zoom-"], 306 [class*="scroll-rotate-"], 307 [class*="scroll-bounce-"], 308 [class*="scroll-flip-"] { 134 309 will-change: opacity, transform; 135 310 } … … 137 312 /* Respect reduced motion */ 138 313 @media (prefers-reduced-motion: reduce) { 139 .scroll-fade-in, 140 .scroll-fade-in-left, 141 .scroll-fade-in-right, 142 .scroll-fade-in-slow, 143 .scroll-zoom-in, 144 .scroll-rotate-in, 145 .scroll-bounce-in, 146 .scroll-flip-in { 314 [class*="scroll-fade-"], 315 [class*="scroll-zoom-"], 316 [class*="scroll-rotate-"], 317 [class*="scroll-bounce-"], 318 [class*="scroll-flip-"] { 147 319 transition: opacity 0.3s ease-out; 148 320 transition-delay: 0s !important; … … 150 322 } 151 323 152 .scroll-fade-in.fade-in-visible, 153 .scroll-fade-in-left.fade-in-visible, 154 .scroll-fade-in-right.fade-in-visible, 155 .scroll-fade-in-slow.fade-in-visible, 156 .scroll-zoom-in.fade-in-visible, 157 .scroll-rotate-in.fade-in-visible, 158 .scroll-bounce-in.fade-in-visible, 159 .scroll-flip-in.fade-in-visible { 324 [class*="scroll-fade-"].fade-in-visible, 325 [class*="scroll-zoom-"].fade-in-visible, 326 [class*="scroll-rotate-"].fade-in-visible, 327 [class*="scroll-bounce-"].fade-in-visible, 328 [class*="scroll-flip-"].fade-in-visible { 160 329 opacity: 1; 161 330 transform: none !important; 162 331 } 163 332 } 333 334 /* Editor Styles - Make animations visible and triggerable in Gutenberg */ 335 /* Override frontend styles completely to keep elements visible */ 336 /* Only apply when NOT animating (no .serend-preview-animate class) */ 337 .block-editor [class*="scroll-"]:not(.serend-preview-animate), 338 .block-editor-block-list__layout [class*="scroll-"]:not(.serend-preview-animate) { 339 /* Keep elements visible in editor - override frontend opacity: 0 */ 340 opacity: 1 !important; 341 transform: none !important; 342 visibility: visible !important; 343 transition: none !important; 344 } 345 346 347 /* Animation classes for editor preview */ 348 /* These animations are triggered when the user clicks "Show Animation" */ 349 350 /* Fade animations */ 351 .block-editor .scroll-fade-in.serend-preview-animate, 352 .block-editor-block-list__layout .scroll-fade-in.serend-preview-animate { 353 animation: fadeInUp 0.8s ease-out forwards; 354 } 355 .block-editor .scroll-fade-in-left.serend-preview-animate, 356 .block-editor-block-list__layout .scroll-fade-in-left.serend-preview-animate { 357 animation: fadeInLeft 0.8s ease-out forwards; 358 } 359 .block-editor .scroll-fade-in-right.serend-preview-animate, 360 .block-editor-block-list__layout .scroll-fade-in-right.serend-preview-animate { 361 animation: fadeInRight 0.8s ease-out forwards; 362 } 363 .block-editor .scroll-fade-in-top.serend-preview-animate, 364 .block-editor-block-list__layout .scroll-fade-in-top.serend-preview-animate { 365 animation: fadeInTop 0.8s ease-out forwards; 366 } 367 368 /* Zoom animations */ 369 .block-editor .scroll-zoom-in.serend-preview-animate, 370 .block-editor-block-list__layout .scroll-zoom-in.serend-preview-animate { 371 animation: zoomInUp 0.8s ease-out forwards; 372 } 373 .block-editor .scroll-zoom-in-left.serend-preview-animate, 374 .block-editor-block-list__layout .scroll-zoom-in-left.serend-preview-animate { 375 animation: zoomInLeft 0.8s ease-out forwards; 376 } 377 .block-editor .scroll-zoom-in-right.serend-preview-animate, 378 .block-editor-block-list__layout .scroll-zoom-in-right.serend-preview-animate { 379 animation: zoomInRight 0.8s ease-out forwards; 380 } 381 .block-editor .scroll-zoom-in-top.serend-preview-animate, 382 .block-editor-block-list__layout .scroll-zoom-in-top.serend-preview-animate { 383 animation: zoomInTop 0.8s ease-out forwards; 384 } 385 386 /* Rotate animations */ 387 .block-editor .scroll-rotate-in.serend-preview-animate, 388 .block-editor-block-list__layout .scroll-rotate-in.serend-preview-animate { 389 animation: rotateInUp 0.8s ease-out forwards; 390 } 391 .block-editor .scroll-rotate-in-left.serend-preview-animate, 392 .block-editor-block-list__layout .scroll-rotate-in-left.serend-preview-animate { 393 animation: rotateInLeft 0.8s ease-out forwards; 394 } 395 .block-editor .scroll-rotate-in-right.serend-preview-animate, 396 .block-editor-block-list__layout .scroll-rotate-in-right.serend-preview-animate { 397 animation: rotateInRight 0.8s ease-out forwards; 398 } 399 .block-editor .scroll-rotate-in-top.serend-preview-animate, 400 .block-editor-block-list__layout .scroll-rotate-in-top.serend-preview-animate { 401 animation: rotateInTop 0.8s ease-out forwards; 402 } 403 404 /* Bounce animations */ 405 .block-editor .scroll-bounce-in.serend-preview-animate, 406 .block-editor-block-list__layout .scroll-bounce-in.serend-preview-animate { 407 animation: bounceInUp 0.8s ease-out forwards; 408 } 409 .block-editor .scroll-bounce-in-left.serend-preview-animate, 410 .block-editor-block-list__layout .scroll-bounce-in-left.serend-preview-animate { 411 animation: bounceInLeft 0.8s ease-out forwards; 412 } 413 .block-editor .scroll-bounce-in-right.serend-preview-animate, 414 .block-editor-block-list__layout .scroll-bounce-in-right.serend-preview-animate { 415 animation: bounceInRight 0.8s ease-out forwards; 416 } 417 .block-editor .scroll-bounce-in-top.serend-preview-animate, 418 .block-editor-block-list__layout .scroll-bounce-in-top.serend-preview-animate { 419 animation: bounceInTop 0.8s ease-out forwards; 420 } 421 422 /* Flip animations */ 423 .block-editor .scroll-flip-in.serend-preview-animate, 424 .block-editor-block-list__layout .scroll-flip-in.serend-preview-animate { 425 animation: flipInUp 0.8s ease-out forwards; 426 } 427 .block-editor .scroll-flip-in-left.serend-preview-animate, 428 .block-editor-block-list__layout .scroll-flip-in-left.serend-preview-animate { 429 animation: flipInLeft 0.8s ease-out forwards; 430 } 431 .block-editor .scroll-flip-in-right.serend-preview-animate, 432 .block-editor-block-list__layout .scroll-flip-in-right.serend-preview-animate { 433 animation: flipInRight 0.8s ease-out forwards; 434 } 435 .block-editor .scroll-flip-in-top.serend-preview-animate, 436 .block-editor-block-list__layout .scroll-flip-in-top.serend-preview-animate { 437 animation: flipInTop 0.8s ease-out forwards; 438 } 439 440 /* Slow modifier for editor animations */ 441 .block-editor .animation-slow.serend-preview-animate, 442 .block-editor-block-list__layout .animation-slow.serend-preview-animate { 443 animation-duration: 1.2s !important; 444 } 445 446 /* Animation keyframes for editor preview */ 447 448 /* Fade keyframes */ 449 @keyframes fadeInUp { 450 from { opacity: 0; transform: translateY(30px); } 451 to { opacity: 1; transform: translateY(0); } 452 } 453 @keyframes fadeInLeft { 454 from { opacity: 0; transform: translateX(-30px); } 455 to { opacity: 1; transform: translateX(0); } 456 } 457 @keyframes fadeInRight { 458 from { opacity: 0; transform: translateX(30px); } 459 to { opacity: 1; transform: translateX(0); } 460 } 461 @keyframes fadeInTop { 462 from { opacity: 0; transform: translateY(-30px); } 463 to { opacity: 1; transform: translateY(0); } 464 } 465 466 /* Zoom keyframes */ 467 @keyframes zoomInUp { 468 from { opacity: 0; transform: scale(0.8) translateY(30px); } 469 to { opacity: 1; transform: scale(1) translateY(0); } 470 } 471 @keyframes zoomInLeft { 472 from { opacity: 0; transform: scale(0.8) translateX(-30px); } 473 to { opacity: 1; transform: scale(1) translateX(0); } 474 } 475 @keyframes zoomInRight { 476 from { opacity: 0; transform: scale(0.8) translateX(30px); } 477 to { opacity: 1; transform: scale(1) translateX(0); } 478 } 479 @keyframes zoomInTop { 480 from { opacity: 0; transform: scale(0.8) translateY(-30px); } 481 to { opacity: 1; transform: scale(1) translateY(0); } 482 } 483 484 /* Rotate keyframes */ 485 @keyframes rotateInUp { 486 from { opacity: 0; transform: rotate(-10deg) scale(0.9) translateY(30px); } 487 to { opacity: 1; transform: rotate(0deg) scale(1) translateY(0); } 488 } 489 @keyframes rotateInLeft { 490 from { opacity: 0; transform: rotate(-10deg) scale(0.9) translateX(-30px); } 491 to { opacity: 1; transform: rotate(0deg) scale(1) translateX(0); } 492 } 493 @keyframes rotateInRight { 494 from { opacity: 0; transform: rotate(10deg) scale(0.9) translateX(30px); } 495 to { opacity: 1; transform: rotate(0deg) scale(1) translateX(0); } 496 } 497 @keyframes rotateInTop { 498 from { opacity: 0; transform: rotate(-10deg) scale(0.9) translateY(-30px); } 499 to { opacity: 1; transform: rotate(0deg) scale(1) translateY(0); } 500 } 501 502 /* Bounce keyframes */ 503 @keyframes bounceInUp { 504 from { opacity: 0; transform: translateY(50px); } 505 to { opacity: 1; transform: translateY(0); } 506 } 507 @keyframes bounceInLeft { 508 from { opacity: 0; transform: translateX(-50px); } 509 to { opacity: 1; transform: translateX(0); } 510 } 511 @keyframes bounceInRight { 512 from { opacity: 0; transform: translateX(50px); } 513 to { opacity: 1; transform: translateX(0); } 514 } 515 @keyframes bounceInTop { 516 from { opacity: 0; transform: translateY(-50px); } 517 to { opacity: 1; transform: translateY(0); } 518 } 519 520 /* Flip keyframes */ 521 @keyframes flipInUp { 522 from { opacity: 0; transform: perspective(400px) rotateX(90deg); } 523 to { opacity: 1; transform: perspective(400px) rotateX(0deg); } 524 } 525 @keyframes flipInLeft { 526 from { opacity: 0; transform: perspective(400px) rotateY(-90deg); } 527 to { opacity: 1; transform: perspective(400px) rotateY(0deg); } 528 } 529 @keyframes flipInRight { 530 from { opacity: 0; transform: perspective(400px) rotateY(90deg); } 531 to { opacity: 1; transform: perspective(400px) rotateY(0deg); } 532 } 533 @keyframes flipInTop { 534 from { opacity: 0; transform: perspective(400px) rotateX(-90deg); } 535 to { opacity: 1; transform: perspective(400px) rotateX(0deg); } 536 } -
serend-animations/trunk/includes/assets/js/animations.js
r3368477 r3390988 14 14 function initScrollAnimations() { 15 15 // Find all elements with animation classes. 16 const animationSelectors = [ 17 '.scroll-fade-in', 18 '.scroll-fade-in-left', 19 '.scroll-fade-in-right', 20 '.scroll-fade-in-slow', 21 '.scroll-zoom-in', 22 '.scroll-rotate-in', 23 '.scroll-bounce-in', 24 '.scroll-flip-in' 25 ]; 26 27 const animationElements = document.querySelectorAll( animationSelectors.join( ', ' ) ); 16 // Use attribute selector to catch all scroll-* classes (more flexible and future-proof). 17 const animationElements = document.querySelectorAll( '[class*="scroll-fade-"], [class*="scroll-zoom-"], [class*="scroll-rotate-"], [class*="scroll-bounce-"], [class*="scroll-flip-"]' ); 28 18 29 19 // If no elements were found, exit the function. … … 68 58 } else { 69 59 // Fallback for older browsers - show all elements immediately. 70 const animationElements = document.querySelectorAll( [ 71 '.scroll-fade-in', 72 '.scroll-fade-in-left', 73 '.scroll-fade-in-right', 74 '.scroll-fade-in-slow', 75 '.scroll-zoom-in', 76 '.scroll-rotate-in', 77 '.scroll-bounce-in', 78 '.scroll-flip-in' 79 ].join( ', ' ) ); 60 const animationElements = document.querySelectorAll( '[class*="scroll-fade-"], [class*="scroll-zoom-"], [class*="scroll-rotate-"], [class*="scroll-bounce-"], [class*="scroll-flip-"]' ); 80 61 81 62 animationElements.forEach( element => { … … 110 91 111 92 window.debugAnimations = function() { 112 const elements = document.querySelectorAll( [ 113 '.scroll-fade-in', 114 '.scroll-fade-in-left', 115 '.scroll-fade-in-right', 116 '.scroll-fade-in-slow', 117 '.scroll-zoom-in', 118 '.scroll-rotate-in', 119 '.scroll-bounce-in', 120 '.scroll-flip-in' 121 ].join( ', ' ) ); 93 const elements = document.querySelectorAll( '[class*="scroll-fade-"], [class*="scroll-zoom-"], [class*="scroll-rotate-"], [class*="scroll-bounce-"], [class*="scroll-flip-"]' ); 122 94 123 95 console.log( 'Animation elements found:', elements.length ); -
serend-animations/trunk/includes/assets/js/editor.js
r3368477 r3390988 11 11 const { __, _x, _n, _nx } = wp.i18n; 12 12 const { addFilter } = wp.hooks; 13 const { Fragment } = wp.element;13 const { Fragment, useState, useEffect } = wp.element; 14 14 const { InspectorControls } = wp.blockEditor; 15 const { PanelBody, SelectControl, RangeControl } = wp.components;15 const { PanelBody, SelectControl, RangeControl, Button, ToggleControl } = wp.components; 16 16 const { createHigherOrderComponent } = wp.compose; 17 17 18 18 /** 19 * Add animation attributes to all blocks. 20 */ 21 function addAnimationAttribute( settings, name ) { 22 // Skip certain core blocks that don't need animations. 23 const skipBlocks = [ 24 'core/html', 25 'core/shortcode', 26 'core/spacer', 27 'core/more', 28 'core/nextpage' 19 * Extract animation class from className string. 20 * 21 * @param {string} className The className string to parse. 22 * @return {string} The animation class found, or empty string. 23 */ 24 function extractAnimationClass( className ) { 25 if ( ! className || typeof className !== 'string' ) { 26 return ''; 27 } 28 29 // Split className into array of classes 30 const classes = className.split( /\s+/ ).filter( cls => cls.length > 0 ); 31 32 // All possible animation base classes with their direction variants. 33 const animationPrefixes = [ 34 'scroll-flip-in', 35 'scroll-bounce-in', 36 'scroll-rotate-in', 37 'scroll-zoom-in', 38 'scroll-fade-in' 29 39 ]; 30 40 31 if ( skipBlocks.includes( name ) ) { 32 return settings; 33 } 34 35 // Add animation attributes. 36 if ( ! settings.attributes ) { 37 settings.attributes = {}; 38 } 39 40 settings.attributes.animationClass = { 41 type: 'string', 42 default: '' 43 }; 44 45 settings.attributes.animationDelay = { 46 type: 'number', 47 default: 0 48 }; 49 50 return settings; 41 // Check each prefix (longest first to match most specific). 42 for ( let i = 0; i < animationPrefixes.length; i++ ) { 43 const prefix = animationPrefixes[ i ]; 44 45 // Check for direction variants first. 46 if ( classes.includes( prefix + '-left' ) ) { 47 return prefix + '-left'; 48 } 49 if ( classes.includes( prefix + '-right' ) ) { 50 return prefix + '-right'; 51 } 52 if ( classes.includes( prefix + '-top' ) ) { 53 return prefix + '-top'; 54 } 55 // Check for base class. 56 if ( classes.includes( prefix ) ) { 57 return prefix; 58 } 59 } 60 61 return ''; 62 } 63 64 /** 65 * Extract animation type from animation class. 66 * 67 * @param {string} animationClass The animation class (e.g., 'scroll-fade-in-left'). 68 * @return {string} The animation type (e.g., 'fade', 'zoom'). 69 */ 70 function extractAnimationType( animationClass ) { 71 if ( ! animationClass ) { 72 return ''; 73 } 74 75 // Map animation classes to types. 76 if ( animationClass.startsWith( 'scroll-fade-in' ) ) { 77 return 'fade'; 78 } 79 if ( animationClass.startsWith( 'scroll-zoom-in' ) ) { 80 return 'zoom'; 81 } 82 if ( animationClass.startsWith( 'scroll-rotate-in' ) ) { 83 return 'rotate'; 84 } 85 if ( animationClass.startsWith( 'scroll-bounce-in' ) ) { 86 return 'bounce'; 87 } 88 if ( animationClass.startsWith( 'scroll-flip-in' ) ) { 89 return 'flip'; 90 } 91 92 return ''; 93 } 94 95 /** 96 * Extract animation direction from animation class. 97 * 98 * @param {string} animationClass The animation class (e.g., 'scroll-fade-in-left'). 99 * @return {string} The direction ('top', 'bottom', 'left', 'right'). 100 */ 101 function extractAnimationDirection( animationClass ) { 102 if ( ! animationClass ) { 103 return 'bottom'; 104 } 105 106 if ( animationClass.includes( '-left' ) ) { 107 return 'left'; 108 } 109 if ( animationClass.includes( '-right' ) ) { 110 return 'right'; 111 } 112 if ( animationClass.includes( '-top' ) ) { 113 return 'top'; 114 } 115 116 // Default is bottom. 117 return 'bottom'; 118 } 119 120 /** 121 * Build animation class from type and direction. 122 * 123 * @param {string} type The animation type (e.g., 'fade', 'zoom'). 124 * @param {string} direction The direction ('top', 'bottom', 'left', 'right'). 125 * @return {string} The complete animation class. 126 */ 127 function buildAnimationClass( type, direction ) { 128 if ( ! type || type === '' ) { 129 return ''; 130 } 131 132 // Build class based on type and direction. 133 let baseClass = ''; 134 135 if ( type === 'fade' ) { 136 baseClass = 'scroll-fade-in'; 137 } else if ( type === 'zoom' ) { 138 baseClass = 'scroll-zoom-in'; 139 } else if ( type === 'rotate' ) { 140 baseClass = 'scroll-rotate-in'; 141 } else if ( type === 'bounce' ) { 142 baseClass = 'scroll-bounce-in'; 143 } else if ( type === 'flip' ) { 144 baseClass = 'scroll-flip-in'; 145 } 146 147 if ( ! baseClass ) { 148 return ''; 149 } 150 151 // Add direction suffix if not bottom. 152 if ( direction === 'left' ) { 153 return baseClass + '-left'; 154 } 155 if ( direction === 'right' ) { 156 return baseClass + '-right'; 157 } 158 if ( direction === 'top' ) { 159 return baseClass + '-top'; 160 } 161 162 // Default: bottom (no suffix). 163 return baseClass; 164 } 165 166 /** 167 * Extract slow modifier from className string. 168 * 169 * @param {string} className The className string to parse. 170 * @return {boolean} True if animation-slow class is present. 171 */ 172 function extractSlowModifier( className ) { 173 if ( ! className || typeof className !== 'string' ) { 174 return false; 175 } 176 177 return className.includes( 'animation-slow' ); 178 } 179 180 /** 181 * Extract animation delay from className string. 182 * 183 * @param {string} className The className string to parse. 184 * @return {number} The delay value found, or 0. 185 */ 186 function extractAnimationDelay( className ) { 187 if ( ! className || typeof className !== 'string' ) { 188 return 0; 189 } 190 191 // Match animation-delay-{number} pattern. 192 const delayMatch = className.match( /\banimation-delay-(\d+)\b/ ); 193 if ( delayMatch && delayMatch[ 1 ] ) { 194 const delay = parseInt( delayMatch[ 1 ], 10 ); 195 return isNaN( delay ) ? 0 : delay; 196 } 197 198 return 0; 51 199 } 52 200 … … 56 204 const withAnimationControl = createHigherOrderComponent( ( BlockEdit ) => { 57 205 return ( props ) => { 58 const { attributes, setAttributes, name } = props; 59 const { animationClass, animationDelay, className } = attributes; 60 61 // Skip certain core blocks that don't need animations. 62 const skipBlocks = [ 63 'core/html', 64 'core/shortcode', 65 'core/spacer', 66 'core/more', 67 'core/nextpage' 68 ]; 69 70 if ( skipBlocks.includes( name ) ) { 206 // Ensure props is valid. 207 if ( ! props || typeof props !== 'object' ) { 71 208 return wp.element.createElement( BlockEdit, props ); 72 209 } 73 210 74 const animationOptions = Object.keys( serendAnimations.animations ).map( key => ( { 75 label: serendAnimations.animations[ key ], 211 const { attributes, setAttributes, name, clientId } = props; 212 213 // Ensure attributes exists and is an object. 214 if ( ! attributes || typeof attributes !== 'object' ) { 215 return wp.element.createElement( BlockEdit, props ); 216 } 217 218 // Ensure setAttributes is a function. 219 if ( ! setAttributes || typeof setAttributes !== 'function' ) { 220 return wp.element.createElement( BlockEdit, props ); 221 } 222 223 // Get className - this is the only attribute we need. 224 // Note: Even if className is not in attributes, WordPress may add it automatically. 225 const className = attributes.className || ''; 226 227 // Ensure serendAnimations exists and has animationTypes. 228 if ( typeof serendAnimations === 'undefined' || ! serendAnimations.animationTypes || typeof serendAnimations.animationTypes !== 'object' ) { 229 return wp.element.createElement( BlockEdit, props ); 230 } 231 232 const animationTypeOptions = Object.keys( serendAnimations.animationTypes ).map( key => ( { 233 label: serendAnimations.animationTypes[ key ], 76 234 value: key 77 235 } ) ); 78 236 79 // Function to set animation and delay. 80 const updateAnimationClasses = ( newAnimationClass, newDelay ) => { 81 let newClassName = className || ''; 82 83 // Remove all existing animation classes and delay classes. 84 const animationClasses = Object.keys( serendAnimations.animations ).filter( key => key !== '' ); 85 animationClasses.forEach( animClass => { 86 newClassName = newClassName.replace( new RegExp( '\\b' + animClass.replace( /[-\/\\^$*+?.()|[\]{}]/g, '\\$&' ) + '\\b', 'g' ), '' ).trim(); 237 // Extract current animation values from className. 238 const animationClass = extractAnimationClass( className ); 239 const animationType = extractAnimationType( animationClass ); 240 const animationDirection = extractAnimationDirection( animationClass ); 241 const animationSlow = extractSlowModifier( className ); 242 const animationDelay = extractAnimationDelay( className ); 243 244 // State for animation preview. 245 const [ isAnimating, setIsAnimating ] = useState( false ); 246 247 // Function to get the editor document (handles iframe). 248 const getEditorDocument = () => { 249 // Try to find the editor canvas iframe. 250 const iframe = document.querySelector( 'iframe[name="editor-canvas"]' ); 251 if ( iframe && iframe.contentDocument ) { 252 return iframe.contentDocument; 253 } 254 // Fallback to current document. 255 return document; 256 }; 257 258 // Function to trigger animation preview in editor. 259 const triggerAnimationPreview = () => { 260 if ( ! animationClass || animationClass === '' || ! clientId ) { 261 return; 262 } 263 264 // Get the correct document (might be in iframe). 265 const editorDoc = getEditorDocument(); 266 267 // Find the block element in the editor. 268 // Use data-block attribute to find the correct block. 269 let blockElement = editorDoc.querySelector( `[data-block="${ clientId }"]` ); 270 271 // If not found, try without iframe. 272 if ( ! blockElement && editorDoc !== document ) { 273 blockElement = document.querySelector( `[data-block="${ clientId }"]` ); 274 } 275 276 if ( ! blockElement ) { 277 return; 278 } 279 280 // Always animate the blockElement itself. 281 const targetElement = blockElement; 282 283 if ( targetElement ) { 284 // Set animating state. 285 setIsAnimating( true ); 286 287 // Add the animation class if not present 288 if ( ! targetElement.classList.contains( animationClass ) ) { 289 targetElement.classList.add( animationClass ); 290 } 291 292 // Remove the preview animate class first to reset. 293 targetElement.classList.remove( 'serend-preview-animate' ); 294 295 // Force reflow to restart animation. 296 void targetElement.offsetHeight; 297 298 // Add the preview animate class to trigger animation. 299 requestAnimationFrame( () => { 300 targetElement.classList.add( 'serend-preview-animate' ); 301 302 // Remove the class after animation completes. 303 setTimeout( () => { 304 if ( targetElement ) { 305 targetElement.classList.remove( 'serend-preview-animate' ); 306 } 307 setIsAnimating( false ); 308 }, 1500 ); // Max animation duration + buffer. 309 } ); 310 } 311 }; 312 313 // Function to set animation, slow modifier and delay. 314 const updateAnimationClasses = ( newAnimationClass, newSlow, newDelay ) => { 315 // Ensure newAnimationClass is a string. 316 const safeAnimationClass = typeof newAnimationClass === 'string' ? newAnimationClass : ''; 317 // Ensure newSlow is a boolean. 318 const safeSlow = typeof newSlow === 'boolean' ? newSlow : false; 319 // Ensure newDelay is a number. 320 const safeDelay = typeof newDelay === 'number' && ! isNaN( newDelay ) ? Math.max( 0, newDelay ) : 0; 321 322 // Get current className from attributes to ensure we have the latest value. 323 const currentClassName = ( attributes && typeof attributes.className === 'string' ) ? attributes.className : ''; 324 325 // Split className into array and filter out animation-related classes 326 let classArray = currentClassName.split( /\s+/ ).filter( cls => cls.length > 0 ); 327 328 // Remove all animation classes (scroll-*) 329 classArray = classArray.filter( cls => ! cls.startsWith( 'scroll-' ) ); 330 331 // Remove animation-slow class 332 classArray = classArray.filter( cls => cls !== 'animation-slow' ); 333 334 // Remove all delay classes (animation-delay-*) 335 classArray = classArray.filter( cls => ! cls.startsWith( 'animation-delay-' ) ); 336 337 // Remove orphaned direction classes (-left, -right, -slow, etc.) 338 classArray = classArray.filter( cls => { 339 // These are incomplete class fragments that should be removed 340 return cls !== '-left' && 341 cls !== '-right' && 342 cls !== '-top' && 343 cls !== '-slow' && 344 cls !== '-in' && 345 cls !== '-in-left' && 346 cls !== '-in-right' && 347 cls !== '-in-top'; 87 348 } ); 88 349 89 // Remove old delay classes.90 newClassName = newClassName.replace( /\banimation-delay-\d+\b/g, '' ).trim();91 92 350 // Add new animation class (if not empty). 93 if ( newAnimationClass && newAnimationClass !== '' ) { 94 newClassName = newClassName ? newClassName + ' ' + newAnimationClass : newAnimationClass; 351 if ( safeAnimationClass && safeAnimationClass !== '' ) { 352 classArray.push( safeAnimationClass ); 353 354 // Add slow modifier if enabled. 355 if ( safeSlow ) { 356 classArray.push( 'animation-slow' ); 357 } 95 358 96 359 // Add delay class if > 0. 97 if ( newDelay > 0 ) {98 newClassName += ' animation-delay-' + newDelay;360 if ( safeDelay > 0 ) { 361 classArray.push( 'animation-delay-' + safeDelay ); 99 362 } 100 363 } 101 364 102 // Clean up whitespace. 103 newClassName = newClassName.replace( /\s+/g, ' ' ).trim(); 104 105 // Set attributes. 106 setAttributes( { 107 animationClass: newAnimationClass, 108 animationDelay: newDelay, 109 className: newClassName || undefined 110 } ); 111 }; 112 113 // Handler for animation change. 114 const setAnimationClass = ( newAnimationClass ) => { 115 updateAnimationClasses( newAnimationClass, animationDelay ); 365 // Join classes and clean up whitespace 366 const newClassName = classArray.join( ' ' ).trim(); 367 368 // Set className attribute safely (this works for all blocks that support className). 369 try { 370 // Only update className if it changed. 371 if ( newClassName !== currentClassName ) { 372 setAttributes( { 373 className: newClassName || undefined 374 } ); 375 } 376 } catch ( e ) { 377 // Silently fail if setAttributes doesn't work. 378 } 379 }; 380 381 // Handler for animation type change. 382 const setAnimationType = ( newType ) => { 383 // Keep current direction. 384 const newAnimationClass = buildAnimationClass( newType, animationDirection ); 385 updateAnimationClasses( newAnimationClass, animationSlow, animationDelay ); 386 }; 387 388 // Handler for direction change. 389 const setAnimationDirection = ( newDirection ) => { 390 const newAnimationClass = buildAnimationClass( animationType, newDirection ); 391 updateAnimationClasses( newAnimationClass, animationSlow, animationDelay ); 392 }; 393 394 // Handler for slow toggle change. 395 const setAnimationSlow = ( newSlow ) => { 396 updateAnimationClasses( animationClass, newSlow, animationDelay ); 116 397 }; 117 398 118 399 // Handler for delay change. 119 400 const setAnimationDelay = ( newDelay ) => { 120 updateAnimationClasses( animationClass, newDelay ); 401 updateAnimationClasses( animationClass, animationSlow, newDelay ); 402 }; 403 404 // Auto-trigger animation preview when animation or slow changes. 405 // Note: Delay is intentionally excluded - it should only affect frontend, not editor preview. 406 useEffect( () => { 407 // Only trigger if an animation is selected. 408 if ( animationClass && animationClass !== '' ) { 409 // Trigger animation immediately. 410 triggerAnimationPreview(); 411 } 412 }, [ animationClass, animationSlow ] ); 413 414 // Create direction button helper. 415 const createDirectionButton = ( direction, rotation ) => { 416 const isActive = animationDirection === direction; 417 return wp.element.createElement( 418 Button, 419 { 420 variant: isActive ? 'primary' : 'secondary', 421 className: 'serend-direction-button', 422 onClick: () => setAnimationDirection( direction ), 423 style: { 424 flex: 1, 425 display: 'flex', 426 alignItems: 'center', 427 justifyContent: 'center', 428 minHeight: '36px', 429 padding: '8px', 430 backgroundColor: isActive ? '#000' : 'transparent', 431 color: isActive ? '#fff' : '#000' 432 } 433 }, 434 wp.element.createElement( 435 'svg', 436 { 437 xmlns: 'http://www.w3.org/2000/svg', 438 width: '20', 439 height: '20', 440 viewBox: '0 0 24 24', 441 fill: 'none', 442 stroke: 'currentColor', 443 strokeWidth: '2', 444 strokeLinecap: 'round', 445 strokeLinejoin: 'round', 446 style: { transform: `rotate(${ rotation }deg)` } 447 }, 448 wp.element.createElement( 'path', { d: 'm9 6-6 6 6 6' } ), 449 wp.element.createElement( 'path', { d: 'M3 12h14' } ), 450 wp.element.createElement( 'path', { d: 'M21 19V5' } ) 451 ) 452 ); 121 453 }; 122 454 … … 151 483 initialOpen: true 152 484 }, 485 // Animation Type Dropdown 153 486 wp.element.createElement( SelectControl, { 154 label: ( typeof serendAnimations !== 'undefined' && serendAnimations.i18n ) ? serendAnimations.i18n. scrollAnimation : 'Scroll Animation',155 value: animation Class|| '',156 options: animation Options,157 onChange: setAnimation Class,487 label: ( typeof serendAnimations !== 'undefined' && serendAnimations.i18n ) ? serendAnimations.i18n.animationType : 'Animation Type', 488 value: animationType || '', 489 options: animationTypeOptions, 490 onChange: setAnimationType, 158 491 help: ( typeof serendAnimations !== 'undefined' && serendAnimations.i18n ) ? serendAnimations.i18n.animationHelp : 'Choose an animation that triggers when scrolling.' 159 492 } ), 160 animationClass && animationClass !== '' && wp.element.createElement( RangeControl, { 493 // Direction Buttons (show when animation is selected) 494 animationType && animationType !== '' && wp.element.createElement( 495 'div', 496 { style: { marginBottom: '16px' } }, 497 wp.element.createElement( 498 'div', 499 { 500 style: { 501 marginBottom: '8px', 502 fontSize: '11px', 503 fontWeight: '500', 504 textTransform: 'uppercase', 505 color: '#1e1e1e' 506 } 507 }, 508 ( typeof serendAnimations !== 'undefined' && serendAnimations.i18n ) ? serendAnimations.i18n.directionLabel : 'Direction' 509 ), 510 wp.element.createElement( 511 'div', 512 { 513 style: { 514 display: 'grid', 515 gridTemplateColumns: 'repeat(4, 1fr)', 516 gap: '8px' 517 } 518 }, 519 createDirectionButton( 'top', -90 ), 520 createDirectionButton( 'right', 0 ), 521 createDirectionButton( 'bottom', 90 ), 522 createDirectionButton( 'left', 180 ) 523 ), 524 wp.element.createElement( 525 'p', 526 { 527 style: { 528 marginTop: '8px', 529 marginBottom: 0, 530 fontSize: '12px', 531 fontStyle: 'normal', 532 color: '#757575' 533 } 534 }, 535 ( typeof serendAnimations !== 'undefined' && serendAnimations.i18n ) ? serendAnimations.i18n.directionHelp : 'Select the direction from which the animation starts.' 536 ) 537 ), 538 // Slow Motion Toggle (only show when animation is selected) 539 animationType && animationType !== '' && wp.element.createElement( 540 'div', 541 { 542 style: { marginBottom: '16px' }, 543 className: 'serend-toggle-wrapper' 544 }, 545 wp.element.createElement( ToggleControl, { 546 label: ( typeof serendAnimations !== 'undefined' && serendAnimations.i18n ) ? serendAnimations.i18n.slowLabel : 'Slow Motion', 547 checked: animationSlow, 548 onChange: setAnimationSlow, 549 help: ( typeof serendAnimations !== 'undefined' && serendAnimations.i18n ) ? serendAnimations.i18n.slowHelp : 'Makes the animation play slower (1.5x duration).' 550 } ) 551 ), 552 // Delay Control (only show when animation is selected) 553 animationType && animationType !== '' && wp.element.createElement( RangeControl, { 554 className: 'serend-delay-control', 161 555 label: ( typeof serendAnimations !== 'undefined' && serendAnimations.i18n ) ? serendAnimations.i18n.delayLabel : 'Delay (ms)', 162 556 value: animationDelay, … … 166 560 step: 100, 167 561 help: ( typeof serendAnimations !== 'undefined' && serendAnimations.i18n ) ? serendAnimations.i18n.delayHelp : 'Delay in milliseconds before the animation starts. Useful for staggered animations.' 168 } ) 562 } ), 563 // Preview Button (only show when animation is selected) 564 animationType && animationType !== '' && wp.element.createElement( Button, { 565 variant: 'secondary', 566 className: 'serend-preview-button', 567 onClick: triggerAnimationPreview, 568 disabled: isAnimating, 569 style: { width: '100%', marginTop: '12px' } 570 }, isAnimating ? __( 'Animating...', 'serend-animations' ) : __( 'Show Animation', 'serend-animations' ) ) 169 571 ) 170 572 ) … … 174 576 175 577 // Register Filters. 176 addFilter( 177 'blocks.registerBlockType', 178 'serend-animations/add-animation-attribute', 179 addAnimationAttribute 180 ); 181 578 // Note: We don't add animation attributes to blocks anymore. 579 // We work purely with className, which is supported by all blocks. 182 580 addFilter( 183 581 'editor.BlockEdit', -
serend-animations/trunk/includes/serend-animations-functions.php
r3368477 r3390988 71 71 function serend_animations_admin_page() { 72 72 // Handle form submission. 73 if ( isset( $_POST['serend_animations_settings_nonce'] ) && wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['serend_animations_settings_nonce'] ) ), 'serend_animations_settings' ) ) { 73 if ( isset( $_POST['serend_animations_settings_nonce'] ) && 74 check_admin_referer( 'serend_animations_settings', 'serend_animations_settings_nonce' ) ) { 74 75 if ( isset( $_POST['debug_mode'] ) ) { 75 76 update_option( 'serend_animations_debug_mode', '1' ); … … 110 111 <li><?php echo esc_html__( 'Open any block in the Gutenberg editor', 'serend-animations' ); ?></li> 111 112 <li><?php echo esc_html__( 'Look in the right sidebar under "Serend Animation"', 'serend-animations' ); ?></li> 112 <li><?php echo esc_html__( 'Choose an animation from the dropdown list', 'serend-animations' ); ?></li> 113 <li><strong><?php echo esc_html__( 'NEW:', 'serend-animations' ); ?></strong> <?php echo esc_html__( 'Use the delay slider for staggered animations', 'serend-animations' ); ?></li> 113 <li><?php echo esc_html__( 'Choose an animation type from the dropdown (Fade, Zoom, Rotate, Bounce, Flip)', 'serend-animations' ); ?></li> 114 <li><strong><?php echo esc_html__( 'NEW:', 'serend-animations' ); ?></strong> <?php echo esc_html__( 'Select animation direction with visual arrow buttons', 'serend-animations' ); ?></li> 115 <li><strong><?php echo esc_html__( 'NEW:', 'serend-animations' ); ?></strong> <?php echo esc_html__( 'Enable Slow Motion toggle for 1.5x slower animations', 'serend-animations' ); ?></li> 116 <li><?php echo esc_html__( 'Use the delay slider for staggered animations', 'serend-animations' ); ?></li> 114 117 <li><?php echo esc_html__( 'The animation class is automatically added to "Additional CSS class(es)"', 'serend-animations' ); ?></li> 115 118 <li><?php echo esc_html__( 'Save the page and view the result on the frontend', 'serend-animations' ); ?></li> … … 128 131 <div class="serend-column"> 129 132 <div class="serend-card"> 130 <h2><?php echo esc_html__( 'Available Animations', 'serend-animations' ); ?></h2> 131 <ul> 132 <li><strong><?php echo esc_html__( 'Fade In (from bottom):', 'serend-animations' ); ?></strong> <?php echo esc_html__( 'Element fades in from bottom to top', 'serend-animations' ); ?></li> 133 <li><strong><?php echo esc_html__( 'Fade In (from left):', 'serend-animations' ); ?></strong> <?php echo esc_html__( 'Element fades in from the left', 'serend-animations' ); ?></li> 134 <li><strong><?php echo esc_html__( 'Fade In (from right):', 'serend-animations' ); ?></strong> <?php echo esc_html__( 'Element fades in from the right', 'serend-animations' ); ?></li> 135 <li><strong><?php echo esc_html__( 'Fade In Slow:', 'serend-animations' ); ?></strong> <?php echo esc_html__( 'Slower fade-in animation from bottom', 'serend-animations' ); ?></li> 136 <li><strong><?php echo esc_html__( 'Zoom In:', 'serend-animations' ); ?></strong> <?php echo esc_html__( 'Element zooms from small to normal size', 'serend-animations' ); ?></li> 137 <li><strong><?php echo esc_html__( 'Rotate In:', 'serend-animations' ); ?></strong> <?php echo esc_html__( 'Element rotates while fading in', 'serend-animations' ); ?></li> 138 <li><strong><?php echo esc_html__( 'Bounce In:', 'serend-animations' ); ?></strong> <?php echo esc_html__( 'Element "bounces" in from bottom', 'serend-animations' ); ?></li> 139 <li><strong><?php echo esc_html__( 'Flip In:', 'serend-animations' ); ?></strong> <?php echo esc_html__( 'Element flips in with 3D rotation', 'serend-animations' ); ?></li> 133 <h2><?php echo esc_html__( 'Animation Types', 'serend-animations' ); ?></h2> 134 <ul> 135 <li><strong><?php echo esc_html__( 'Fade:', 'serend-animations' ); ?></strong> <?php echo esc_html__( 'Element fades in smoothly', 'serend-animations' ); ?></li> 136 <li><strong><?php echo esc_html__( 'Zoom:', 'serend-animations' ); ?></strong> <?php echo esc_html__( 'Element zooms from small to normal size', 'serend-animations' ); ?></li> 137 <li><strong><?php echo esc_html__( 'Rotate:', 'serend-animations' ); ?></strong> <?php echo esc_html__( 'Element rotates while fading in', 'serend-animations' ); ?></li> 138 <li><strong><?php echo esc_html__( 'Bounce:', 'serend-animations' ); ?></strong> <?php echo esc_html__( 'Element bounces in playfully', 'serend-animations' ); ?></li> 139 <li><strong><?php echo esc_html__( 'Flip:', 'serend-animations' ); ?></strong> <?php echo esc_html__( 'Element flips in with 3D rotation', 'serend-animations' ); ?></li> 140 </ul> 141 <p style="margin-top: 15px; padding: 10px; background: #e7f3ff; border-left: 4px solid #2271b1;"> 142 <strong><?php echo esc_html__( 'Universal Direction Support:', 'serend-animations' ); ?></strong><br> 143 <?php echo esc_html__( 'All animation types support 4 directions (bottom, left, right, top) via visual arrow buttons.', 'serend-animations' ); ?> 144 </p> 145 </div> 146 147 <div class="serend-card" style="margin-top: 20px;"> 148 <h2><?php echo esc_html__( 'Direction & Slow Motion', 'serend-animations' ); ?></h2> 149 <p><?php echo esc_html__( 'Enhanced animation controls:', 'serend-animations' ); ?></p> 150 <ul> 151 <li><strong><?php echo esc_html__( 'Direction Buttons:', 'serend-animations' ); ?></strong> <?php echo esc_html__( 'Visual arrow buttons to select animation direction', 'serend-animations' ); ?></li> 152 <li><strong><?php echo esc_html__( 'Slow Motion:', 'serend-animations' ); ?></strong> <?php echo esc_html__( 'Toggle to make any animation 1.5x slower', 'serend-animations' ); ?></li> 153 <li><strong><?php echo esc_html__( '20 Variants:', 'serend-animations' ); ?></strong> <?php echo esc_html__( 'Each animation type × 4 directions', 'serend-animations' ); ?></li> 140 154 </ul> 141 155 </div> … … 153 167 </ul> 154 168 <p><strong><?php echo esc_html__( 'Tip:', 'serend-animations' ); ?></strong> <?php echo esc_html__( 'For beautiful staggered effects use 200-400ms intervals between blocks.', 'serend-animations' ); ?></p> 169 </div> 170 171 <div class="serend-card" style="margin-top: 20px;"> 172 <h2><?php echo esc_html__( 'Example Combinations', 'serend-animations' ); ?></h2> 173 <ul> 174 <li><?php echo esc_html__( 'Fade + Left direction + Slow Motion', 'serend-animations' ); ?></li> 175 <li><?php echo esc_html__( 'Zoom + Top direction + 200ms delay', 'serend-animations' ); ?></li> 176 <li><?php echo esc_html__( 'Bounce + Bottom direction (default)', 'serend-animations' ); ?></li> 177 <li><?php echo esc_html__( 'Rotate + Right direction + Slow Motion', 'serend-animations' ); ?></li> 178 <li><?php echo esc_html__( 'Flip + Any direction + 400ms delay', 'serend-animations' ); ?></li> 179 </ul> 180 <p style="margin-top: 10px; font-size: 12px; color: #666;"> 181 <?php echo esc_html__( 'Mix and match direction, slow motion, and delay for endless creative possibilities!', 'serend-animations' ); ?> 182 </p> 155 183 </div> 156 184 </div> -
serend-animations/trunk/languages/serend-animations-de_DE.po
r3368477 r3390988 70 70 msgstr "Schaue im rechten Sidebar unter \"Serend Animation\"" 71 71 72 msgid "Choose an animation from the dropdown list"73 msgstr "Wähle eine Animation aus der Dropdown-Liste"72 msgid "Choose an animation type from the dropdown (Fade, Zoom, Rotate, Bounce, Flip)" 73 msgstr "Wähle einen Animationstyp aus der Dropdown-Liste (Fade, Zoom, Rotate, Bounce, Flip)" 74 74 75 75 msgid "NEW:" 76 76 msgstr "NEU:" 77 77 78 msgid "Select animation direction with visual arrow buttons" 79 msgstr "Wähle die Animationsrichtung mit visuellen Pfeil-Buttons" 80 81 msgid "Enable Slow Motion toggle for 1.5x slower animations" 82 msgstr "Aktiviere Slow Motion für 1,5x langsamere Animationen" 83 78 84 msgid "Use the delay slider for staggered animations" 79 85 msgstr "Nutze den Verzögerungs-Slider für gestaffelte Animationen" … … 88 94 msgstr "Screenshot der die Verwendung von Serend Animations zeigt" 89 95 90 # Admin page - Available Animations section 91 msgid "Available Animations" 92 msgstr "Verfügbare Animationen" 93 94 msgid "Fade In (from bottom):" 95 msgstr "Fade In (von unten):" 96 97 msgid "Element fades in from bottom to top" 98 msgstr "Element faded von unten nach oben ein" 99 100 msgid "Fade In (from left):" 101 msgstr "Fade In (von links):" 102 103 msgid "Element fades in from the left" 104 msgstr "Element faded von links ein" 105 106 msgid "Fade In (from right):" 107 msgstr "Fade In (von rechts):" 108 109 msgid "Element fades in from the right" 110 msgstr "Element faded von rechts ein" 111 112 msgid "Fade In Slow:" 113 msgstr "Fade In Langsam:" 114 115 msgid "Slower fade-in animation from bottom" 116 msgstr "Langsamere Fade-In Animation von unten" 117 118 msgid "Zoom In:" 119 msgstr "Zoom In:" 96 # Admin page - Animation Types section 97 msgid "Animation Types" 98 msgstr "Animationstypen" 99 100 msgid "Fade:" 101 msgstr "Fade:" 102 103 msgid "Element fades in smoothly" 104 msgstr "Element wird sanft eingeblendet" 105 106 msgid "Zoom:" 107 msgstr "Zoom:" 120 108 121 109 msgid "Element zooms from small to normal size" 122 110 msgstr "Element zoomt von klein zu normal" 123 111 124 msgid "Rotate In:"125 msgstr "Rotate In:"112 msgid "Rotate:" 113 msgstr "Rotate:" 126 114 127 115 msgid "Element rotates while fading in" 128 116 msgstr "Element rotiert während es eingeblendet wird" 129 117 130 msgid "Bounce In:"131 msgstr "Bounce In:"132 133 msgid "Element \"bounces\" in from bottom"134 msgstr "Element \"hüpft\" von untenherein"135 136 msgid "Flip In:"137 msgstr "Flip In:"118 msgid "Bounce:" 119 msgstr "Bounce:" 120 121 msgid "Element bounces in playfully" 122 msgstr "Element hüpft spielerisch herein" 123 124 msgid "Flip:" 125 msgstr "Flip:" 138 126 139 127 msgid "Element flips in with 3D rotation" 140 128 msgstr "Element dreht sich in 3D herein" 129 130 msgid "Universal Direction Support:" 131 msgstr "Universelle Richtungsunterstützung:" 132 133 msgid "All animation types support 4 directions (bottom, left, right, top) via visual arrow buttons." 134 msgstr "Alle Animationstypen unterstützen 4 Richtungen (unten, links, rechts, oben) über visuelle Pfeil-Buttons." 135 136 # Admin page - Direction & Slow Motion section 137 msgid "Direction & Slow Motion" 138 msgstr "Richtung & Slow Motion" 139 140 msgid "Enhanced animation controls:" 141 msgstr "Erweiterte Animations-Steuerungen:" 142 143 msgid "Direction Buttons:" 144 msgstr "Richtungs-Buttons:" 145 146 msgid "Visual arrow buttons to select animation direction" 147 msgstr "Visuelle Pfeil-Buttons zur Auswahl der Animationsrichtung" 148 149 msgid "Slow Motion:" 150 msgstr "Slow Motion:" 151 152 msgid "Toggle to make any animation 1.5x slower" 153 msgstr "Toggle um jede Animation 1,5x langsamer zu machen" 154 155 msgid "20 Variants:" 156 msgstr "20 Varianten:" 157 158 msgid "Each animation type × 4 directions" 159 msgstr "Jeder Animationstyp × 4 Richtungen" 160 161 # Admin page - Example Combinations section 162 msgid "Example Combinations" 163 msgstr "Beispiel-Kombinationen" 164 165 msgid "Fade + Left direction + Slow Motion" 166 msgstr "Fade + Linke Richtung + Slow Motion" 167 168 msgid "Zoom + Top direction + 200ms delay" 169 msgstr "Zoom + Obere Richtung + 200ms Verzögerung" 170 171 msgid "Bounce + Bottom direction (default)" 172 msgstr "Bounce + Untere Richtung (Standard)" 173 174 msgid "Rotate + Right direction + Slow Motion" 175 msgstr "Rotate + Rechte Richtung + Slow Motion" 176 177 msgid "Flip + Any direction + 400ms delay" 178 msgstr "Flip + Beliebige Richtung + 400ms Verzögerung" 179 180 msgid "Mix and match direction, slow motion, and delay for endless creative possibilities!" 181 msgstr "Kombiniere Richtung, Slow Motion und Verzögerung für endlose kreative Möglichkeiten!" 141 182 142 183 # Admin page - Staggered Animations section -
serend-animations/trunk/readme.txt
r3368477 r3390988 5 5 Tested up to: 6.8 6 6 Requires PHP: 7.4 7 Stable tag: 1.0. 17 Stable tag: 1.0.3 8 8 License: GPLv2 or later 9 9 License URI: https://www.gnu.org/licenses/gpl-2.0.html … … 13 13 == Description == 14 14 15 Serend Animations makes it incredibly easy to add stunning scroll animations to any Gutenberg block. Simply select a block, choose an animation from the dropdown, and watch your content come to life as visitors scroll through your page. 15 Serend Animations makes it incredibly easy to add stunning scroll animations to any Gutenberg block. Choose an animation type, select a direction with intuitive arrow buttons, optionally enable slow motion, and watch your content come to life as visitors scroll through your page. 16 17 **NEW in v1.0.3:** Visual direction picker with arrow buttons! All animation types now support all 4 directions (top, right, bottom, left), plus a universal Slow Motion toggle for dramatic effects. 16 18 17 19 Why choose Serend Animations? 18 20 21 - **Visual Direction Control**: Intuitive arrow buttons to select animation direction - no more guessing! 22 - **20 Animation Variants**: 5 animation types × 4 directions = endless creative possibilities 23 - **Slow Motion Toggle**: Make any animation 1.5x slower for more dramatic effects 19 24 - Ultra Lightweight: Pure CSS animations with minimal JavaScript - only 8KB total 20 25 - GDPR Friendly: No tracking, no cookies, no external connections - 100% privacy compliant … … 27 32 = Features = 28 33 29 - 8 Beautiful Animation Types: Fade In (from bottom, left, right), Fade In Slow, Zoom In, Rotate In, Bounce In, and Flip In 34 - 5 Animation Types with 4 Directions Each: 20 beautiful animation variants to choose from 35 - Visual Direction Picker: Intuitive arrow buttons to select animation direction (top, right, bottom, left) 36 - Slow Motion Toggle: Make any animation 1.5x slower for more dramatic effects 30 37 - Staggered Animations: Use the delay slider to create cascading animation effects 31 - One-Click Integration: No code required - just select an animation from the dropdown38 - One-Click Integration: No code required - just select an animation and direction 32 39 - Performance Optimized: Uses native Intersection Observer API for smooth performance 33 40 - Works with All Blocks: Compatible with every Gutenberg block … … 38 45 1. Open any block in the Gutenberg editor 39 46 2. Look for "Serend Animation" in the block inspector panel 40 3. Choose an animation from the dropdown 41 4. Optionally set a delay for staggered effects 42 5. Save and view your animated content on the frontend 47 3. Choose an animation type (Fade, Zoom, Rotate, Bounce, or Flip) 48 4. Select a direction using the visual arrow buttons 49 5. Optionally enable "Slow Motion" for a more dramatic effect 50 6. Optionally set a delay for staggered effects 51 7. Click "Show Animation" to preview in the editor 52 8. Save and view your animated content on the frontend 43 53 44 54 = Animation Types = 45 55 46 - Fade In (from bottom): Elements gracefully fade in from below 47 - Fade In (from left): Elements slide in from the left side 48 - Fade In (from right): Elements slide in from the right side 49 - Fade In Slow: A slower, more elegant fade from below 50 - Zoom In: Elements scale up from smaller size 51 - Rotate In: Elements rotate while fading in 52 - Bounce In: Elements bounce in with elastic effect 53 - Flip In: Elements flip in with 3D rotation effect 56 Each animation type supports 4 directions (top, right, bottom, left): 57 58 - **Fade**: Elements gracefully fade in while sliding from the selected direction 59 - **Zoom**: Elements scale up from smaller size while moving from the selected direction 60 - **Rotate**: Elements rotate while scaling and moving from the selected direction 61 - **Bounce**: Elements bounce in with elastic effect from the selected direction 62 - **Flip**: Elements flip in with 3D rotation (X-axis for top/bottom, Y-axis for left/right) 63 64 Plus, every animation can be made slower with the "Slow Motion" toggle for more dramatic effects! 54 65 55 66 = Perfect For = … … 84 95 == Frequently Asked Questions == 85 96 97 = How do the direction buttons work? = 98 99 Instead of selecting from a long dropdown list, you now get 4 intuitive arrow buttons that visually show the direction your animation will come from. Click the up arrow for animations from the top, right arrow for right, etc. It's much more intuitive and visual! 100 101 = Can I make animations slower? = 102 103 Yes! The new "Slow Motion" toggle makes any animation 1.5x slower. This works for all animation types (Fade, Zoom, Rotate, Bounce, Flip) and creates more dramatic, elegant effects. 104 86 105 = Does this work with all Gutenberg blocks? = 87 106 … … 98 117 = Can I use multiple animations on the same page? = 99 118 100 Absolutely! You can use different animations on different blocks, and even create staggered effects using the delay slider.119 Absolutely! You can use different animations on different blocks, mix directions, combine slow motion effects, and even create staggered effects using the delay slider. With 20 animation variants, the creative possibilities are endless! 101 120 102 121 = Does this work on mobile devices? = … … 112 131 Yes, 100%! The plugin is fully GDPR compliant as it doesn't collect any user data, doesn't use cookies, doesn't make external connections, and doesn't track users in any way. It's pure CSS and JavaScript that runs entirely on your website. 113 132 133 = Can I preview animations in the editor? = 134 135 Yes! Click the "Show Animation" button in the block inspector to see a live preview of your animation in the Gutenberg editor. The preview automatically plays when you change the animation type, direction, or enable slow motion. 136 114 137 = Can I customize the animations? = 115 138 116 Absolutely! The plugin provides 8 carefully crafted animations out of the box, but you can easilyextend or customize them with your own CSS. The code is clean and well-documented for easy customization.139 Absolutely! The plugin provides 20 carefully crafted animation variants (5 types × 4 directions) out of the box, plus the slow motion modifier. You can also extend or customize them with your own CSS. The code is clean and well-documented for easy customization. 117 140 118 141 = How do I enable debug mode? = … … 132 155 133 156 == Changelog == 157 158 = 1.0.3 = 159 * **NEW:** Visual direction picker with arrow buttons for all animations 160 * **NEW:** Slow Motion toggle - make any animation 1.5x slower 161 * **NEW:** All animation types now support all 4 directions (top, right, bottom, left) 162 * **NEW:** 20 animation variants total (5 types × 4 directions) 163 * Simplified UI - cleaner animation type dropdown 164 * Direction selection moved from dropdown to intuitive button grid 165 * Delay changes no longer trigger editor preview (frontend-only) 166 * Fixed scroll-fade-in-top and other directional variants not animating 167 * Frontend JavaScript now uses future-proof attribute selectors 168 * Better CSS organization with clear section comments 169 * Universal animation-slow modifier class 170 * Enhanced editor preview with all directional keyframes 171 * Improved class management for slow modifier and directions 172 173 = 1.0.2 = 174 * Added live animation preview in Gutenberg editor with "Show Animation" button 175 * Automatic animation preview when selecting or changing animations 176 * Automatic preview when changing delay values 177 * Full support for all third-party blocks (Yoast SEO, Rank Math, WooCommerce, etc.) 178 * Fixed animation class cleanup - no more orphaned fragments 179 * Fixed correct animation detection for compound classes 180 * Elements now remain visible in editor while supporting previews 181 * Animation dropdown now shows correct selection 182 * All Fade In variants now work correctly 183 * Improved className management with better filtering 184 * Production-ready code (removed debug logs) 185 * Better iframe handling for modern WordPress editor 134 186 135 187 = 1.0.1 = … … 157 209 == Upgrade Notice == 158 210 211 = 1.0.3 = 212 Major feature update! Visual direction picker with arrow buttons for ALL animations, universal Slow Motion toggle, and 20 animation variants (5 types × 4 directions). Much more flexible and intuitive animation control. Highly recommended update! 213 214 = 1.0.2 = 215 Major editor improvements! Live animation preview, automatic previews when changing animations, full third-party block support, and better animation class management. Highly recommended update. 216 159 217 = 1.0.1 = 160 218 Code quality improvements and WordPress standards compliance. No new features, but better maintainability and performance. -
serend-animations/trunk/serend-animations.php
r3368477 r3390988 4 4 * Plugin URI: https://wordpress.org/plugins/serend-animations/ 5 5 * Description: Add beautiful scroll animations to Gutenberg blocks with a simple dropdown. Choose from fade, zoom, rotate, bounce and flip effects. 6 * Version: 1.0. 16 * Version: 1.0.3 7 7 * Author: serend.design 8 8 * Author URI: https://serend.design … … 12 12 * Domain Path: /languages 13 13 * Requires at least: 6.0 14 * Tested up to: 6. 614 * Tested up to: 6.8 15 15 * Requires PHP: 7.4 16 16 * … … 44 44 45 45 /** 46 * Plugin version. 47 * 48 * @var string 49 */ 50 const VERSION = '1.0.3'; 51 52 /** 46 53 * Constructor. 47 54 */ 48 55 public function __construct() { 56 add_action( 'plugins_loaded', array( $this, 'load_textdomain' ) ); 49 57 add_action( 'init', array( $this, 'init' ) ); 50 58 } 51 59 52 60 /** 61 * Load plugin text domain for translations. 62 */ 63 public function load_textdomain() { 64 load_plugin_textdomain( 65 'serend-animations', 66 false, 67 dirname( plugin_basename( __FILE__ ) ) . '/languages' 68 ); 69 } 70 71 /** 53 72 * Initialize plugin. 54 73 */ 55 74 public function init() { 75 // Register Block Assets (loads in both editor and frontend). 76 add_action( 'enqueue_block_assets', array( $this, 'enqueue_block_assets' ) ); 77 56 78 // Register Block Editor Assets. 57 79 add_action( 'enqueue_block_editor_assets', array( $this, 'enqueue_block_editor_assets' ) ); … … 62 84 63 85 /** 86 * Load Block Assets (both editor and frontend). 87 * This ensures CSS is loaded in the iframe editor. 88 */ 89 public function enqueue_block_assets() { 90 // Only in admin/editor context. 91 if ( is_admin() ) { 92 wp_enqueue_style( 93 'serend-animations-editor-css', 94 plugin_dir_url( __FILE__ ) . 'includes/assets/css/animations.css', 95 array(), 96 self::VERSION 97 ); 98 } 99 } 100 101 /** 64 102 * Load Block Editor Assets. 65 103 */ 66 104 public function enqueue_block_editor_assets() { 105 // Enqueue editor-specific CSS for custom styling 106 wp_enqueue_style( 107 'serend-animations-editor-styles', 108 plugin_dir_url( __FILE__ ) . 'includes/assets/css/editor.css', 109 array(), 110 self::VERSION 111 ); 112 67 113 wp_enqueue_script( 68 114 'serend-animations-editor', 69 115 plugin_dir_url( __FILE__ ) . 'includes/assets/js/editor.js', 70 116 array( 'wp-blocks', 'wp-element', 'wp-editor', 'wp-components', 'wp-compose', 'wp-data', 'wp-hooks', 'wp-i18n' ), 71 '1.0.0',117 self::VERSION, 72 118 true 73 119 ); 74 120 75 121 // Set up script translations for JavaScript. 76 wp_set_script_translations( 'serend-animations-editor', 'serend-animations', __DIR__ . '/languages' );122 wp_set_script_translations( 'serend-animations-editor', 'serend-animations', plugin_dir_path( __FILE__ ) . 'languages' ); 77 123 78 124 // Localize strings for the editor. … … 81 127 'serendAnimations', 82 128 array( 83 'animations' => array( 84 '' => __( 'No Animation', 'serend-animations' ), 85 'scroll-fade-in' => __( 'Fade In (from bottom)', 'serend-animations' ), 86 'scroll-fade-in-left' => __( 'Fade In (from left)', 'serend-animations' ), 87 'scroll-fade-in-right' => __( 'Fade In (from right)', 'serend-animations' ), 88 'scroll-fade-in-slow' => __( 'Fade In Slow (from bottom)', 'serend-animations' ), 89 'scroll-zoom-in' => __( 'Zoom In', 'serend-animations' ), 90 'scroll-rotate-in' => __( 'Rotate In', 'serend-animations' ), 91 'scroll-bounce-in' => __( 'Bounce In', 'serend-animations' ), 92 'scroll-flip-in' => __( 'Flip In', 'serend-animations' ), 129 'animationTypes' => array( 130 '' => __( 'No Animation', 'serend-animations' ), 131 'fade' => __( 'Fade', 'serend-animations' ), 132 'zoom' => __( 'Zoom', 'serend-animations' ), 133 'rotate' => __( 'Rotate', 'serend-animations' ), 134 'bounce' => __( 'Bounce', 'serend-animations' ), 135 'flip' => __( 'Flip', 'serend-animations' ), 93 136 ), 94 137 'i18n' => array( 95 138 'panelTitle' => __( 'Serend Animation', 'serend-animations' ), 96 ' scrollAnimation' => __( 'Scroll Animation', 'serend-animations' ),139 'animationType' => __( 'Animation Type', 'serend-animations' ), 97 140 'animationHelp' => __( 'Choose an animation that triggers when scrolling.', 'serend-animations' ), 141 'directionLabel' => __( 'Direction', 'serend-animations' ), 142 'directionHelp' => __( 'Select the direction from which the animation starts.', 'serend-animations' ), 143 'slowLabel' => __( 'Slow Motion', 'serend-animations' ), 144 'slowHelp' => __( 'Makes the animation play slower (1.5x duration).', 'serend-animations' ), 98 145 'delayLabel' => __( 'Delay (ms)', 'serend-animations' ), 99 146 'delayHelp' => __( 'Delay in milliseconds before the animation starts. Useful for staggered animations.', 'serend-animations' ), … … 111 158 plugin_dir_url( __FILE__ ) . 'includes/assets/css/animations.css', 112 159 array(), 113 '1.0.0'160 self::VERSION 114 161 ); 115 162 … … 118 165 plugin_dir_url( __FILE__ ) . 'includes/assets/js/animations.js', 119 166 array(), 120 '1.0.0',167 self::VERSION, 121 168 true 122 169 ); … … 145 192 'scroll-fade-in-left', 146 193 'scroll-fade-in-right', 147 'scroll-fade-in- slow',194 'scroll-fade-in-top', 148 195 'scroll-zoom-in', 196 'scroll-zoom-in-left', 197 'scroll-zoom-in-right', 198 'scroll-zoom-in-top', 149 199 'scroll-rotate-in', 200 'scroll-rotate-in-left', 201 'scroll-rotate-in-right', 202 'scroll-rotate-in-top', 150 203 'scroll-bounce-in', 204 'scroll-bounce-in-left', 205 'scroll-bounce-in-right', 206 'scroll-bounce-in-top', 151 207 'scroll-flip-in', 152 ); 153 154 // Build the debug script as a string. 208 'scroll-flip-in-left', 209 'scroll-flip-in-right', 210 'scroll-flip-in-top', 211 'animation-slow', 212 ); 213 214 // Build the debug script as a string using safer DOM methods. 155 215 $debug_script = 'document.addEventListener("DOMContentLoaded", function() { 156 216 // Create debug overlay … … 158 218 debugDiv.style.cssText = "position: fixed; top: 10px; right: 10px; background: #fff; border: 1px solid #ccc; padding: 10px; z-index: 9999; font-family: monospace; font-size: 12px; max-width: 300px; box-shadow: 0 2px 10px rgba(0,0,0,0.1);"; 159 219 160 var content = "<h4 style=\"margin: 0 0 8px 0;\">' . esc_js( __( 'Animation Classes Debug', 'serend-animations' ) ) . '</h4>"; 161 content += "<p style=\"margin: 0 0 8px 0; font-size: 11px;\">' . esc_js( __( 'Live count from rendered HTML:', 'serend-animations' ) ) . '</p>"; 220 // Create header 221 var header = document.createElement("h4"); 222 header.style.cssText = "margin: 0 0 8px 0;"; 223 header.textContent = ' . wp_json_encode( __( 'Animation Classes Debug', 'serend-animations' ) ) . '; 224 debugDiv.appendChild(header); 225 226 // Create description 227 var desc = document.createElement("p"); 228 desc.style.cssText = "margin: 0 0 8px 0; font-size: 11px;"; 229 desc.textContent = ' . wp_json_encode( __( 'Live count from rendered HTML:', 'serend-animations' ) ) . '; 230 debugDiv.appendChild(desc); 162 231 '; 163 232 … … 165 234 $safe_var_name = str_replace( '-', '_', $class ); 166 235 $debug_script .= 'var elements_' . esc_js( $safe_var_name ) . ' = document.querySelectorAll(".' . esc_js( $class ) . '"); 167 content += "<div>' . esc_js( $class ) . ': " + elements_' . esc_js( $safe_var_name ) . '.length + " ' . esc_js( __( 'times used', 'serend-animations' ) ) . '</div>"; 236 var row_' . esc_js( $safe_var_name ) . ' = document.createElement("div"); 237 row_' . esc_js( $safe_var_name ) . '.textContent = "' . esc_js( $class ) . ': " + elements_' . esc_js( $safe_var_name ) . '.length + " ' . esc_js( __( 'times used', 'serend-animations' ) ) . '"; 238 debugDiv.appendChild(row_' . esc_js( $safe_var_name ) . '); 168 239 '; 169 240 } 170 241 171 $debug_script .= 'debugDiv.innerHTML = content; 172 document.body.appendChild(debugDiv); 242 $debug_script .= 'document.body.appendChild(debugDiv); 173 243 });'; 174 244
Note: See TracChangeset
for help on using the changeset viewer.