# Story 9.11: Animations & Micro-interactions ## Epic Reference **Epic 9:** Design & Branding Implementation ## Dependencies - **Story 9.4** (Buttons): Button components must be styled before adding transitions - **Story 9.5** (Forms): Form components must be complete for error shake animations - **Story 9.6** (Cards): Card components must be styled before adding hover/lift effects - **Story 9.7** (Navigation): Navigation must be complete for link transitions - **Story 9.10** (Accessibility): Coordinates with `prefers-reduced-motion` requirements ## User Story As a **user**, I want **subtle, professional animations**, So that **the interface feels polished and responsive**. ## Acceptance Criteria ### Transitions - [ ] Button hover: 150ms ease - [ ] Card hover: 200ms ease - [ ] Modal open/close: 200ms - [ ] Page transitions (optional) ### Loading States - [ ] Skeleton loaders for content - [ ] Spinner for actions - [ ] Progress indicators ### Feedback Animations - [ ] Success checkmark - [ ] Error shake - [ ] Toast slide-in ### Hover Effects - [ ] Links: Color transition - [ ] Cards: Lift effect - [ ] Buttons: Background transition ### Requirements - [ ] All animations subtle, professional - [ ] Under 300ms duration - [ ] Respect prefers-reduced-motion ## Technical Notes ### Files to Create/Modify | File | Action | Purpose | |------|--------|---------| | `resources/css/app.css` | Modify | Add animation utility classes and keyframes | | `resources/views/components/skeleton.blade.php` | Create | Skeleton loader component | | `resources/views/components/spinner.blade.php` | Create | Loading spinner component | | `resources/views/components/toast.blade.php` | Create | Toast notification with slide-in animation | | `resources/views/components/icons/checkmark.blade.php` | Create | Animated success checkmark SVG | ### Component Integration Points - **Buttons** (``): Add `transition-colors duration-150` to existing button styles - **Cards**: Apply `.card-hover` class to interactive card components - **Forms**: Use `.shake` class on form fields when validation fails (triggered via Alpine.js) - **Livewire Loading**: Use `` component with `wire:loading` directive - **Toast Notifications**: Integrate with Livewire event dispatch for flash messages ### Animation CSS ```css /* Base transitions */ .transition-default { @apply transition-all duration-150 ease-in-out; } .transition-slow { @apply transition-all duration-200 ease-in-out; } /* Button hover */ .btn { @apply transition-colors duration-150; } /* Card lift */ .card-hover { @apply transition-all duration-200; } .card-hover:hover { @apply -translate-y-0.5 shadow-md; } /* Skeleton loader */ .skeleton { @apply animate-pulse bg-charcoal/10 rounded; } /* Toast animation */ .toast-enter { @apply transform translate-x-full opacity-0; } .toast-enter-active { @apply transform translate-x-0 opacity-100 transition-all duration-200; } /* Success checkmark */ @keyframes checkmark { 0% { stroke-dashoffset: 100; } 100% { stroke-dashoffset: 0; } } .checkmark-animated path { stroke-dasharray: 100; animation: checkmark 0.3s ease-in-out forwards; } /* Error shake */ @keyframes shake { 0%, 100% { transform: translateX(0); } 25% { transform: translateX(-5px); } 75% { transform: translateX(5px); } } .shake { animation: shake 0.3s ease-in-out; } /* Reduced motion support - REQUIRED for accessibility */ @media (prefers-reduced-motion: reduce) { .transition-default, .transition-slow, .card-hover, .btn { transition: none !important; } .skeleton { animation: none !important; } .checkmark-animated path, .shake { animation: none !important; } .toast-enter-active { transition: none !important; } } ``` ```blade @props(['lines' => 3])
@for($i = 0; $i < $lines; $i++)
@endfor
{{ __('common.loading') }}
``` ## Testing Requirements ### Testing Approach - **Visual Inspection**: Manual browser testing for animation smoothness and timing - **Pest Browser Tests**: Automated tests to verify animation classes are applied - **Cross-Browser Testing**: Chrome, Firefox, Safari (animations can vary) - **Reduced Motion Testing**: Verify animations disabled when preference is set ### Key Test Scenarios | Scenario | Expected Result | |----------|-----------------| | Hover over button | Background color transitions smoothly (150ms) | | Hover over card | Card lifts slightly with shadow increase (200ms) | | Form validation fails | Input field shakes briefly | | Content loading | Skeleton pulses until content loads | | Action in progress | Spinner displays with `wire:loading` | | Toast notification triggered | Toast slides in from right edge | | `prefers-reduced-motion: reduce` enabled | All animations/transitions disabled | ### Pest Browser Test Example ```php // tests/Browser/AnimationsTest.php it('applies hover transition to buttons', function () { visit('/login') ->assertPresent('button.transition-colors'); }); it('respects reduced motion preference', function () { visit('/') ->withReducedMotion() ->assertStyleContains('.btn', 'transition', 'none'); }); ``` ## Definition of Done - [ ] Button transitions work - [ ] Card hover effects work - [ ] Skeleton loaders work - [ ] Spinners work - [ ] Toast animations work - [ ] All animations subtle - [ ] Reduced motion respected - [ ] Pest browser tests pass - [ ] Cross-browser tested (Chrome, Firefox, Safari) ## Estimation **Complexity:** Medium | **Effort:** 4 hours