reviewed epic 9 stories

This commit is contained in:
Naser Mansour 2025-12-21 13:26:15 +02:00
parent 261a528578
commit 8431194c9a
11 changed files with 1651 additions and 251 deletions

View File

@ -2,6 +2,10 @@
## Epic Reference
**Epic 9:** Design & Branding Implementation
**Epic File:** `docs/epics/epic-9-design-branding.md`
## Dependencies
- **Epic 1:** Base Tailwind/Flux setup must be complete (Tailwind CSS 4, Flux UI installed)
## User Story
As a **developer**,
@ -27,40 +31,88 @@ So that **brand colors are consistently applied throughout the application**.
- [ ] Color variables for easy maintenance
- [ ] Semantic color aliases (primary, accent, etc.)
### Dark Mode
- [ ] Dark mode is **deferred** to a future story
- [ ] Document that dark mode will require additional color mappings later
## Technical Notes
```css
/* resources/css/app.css */
@import "tailwindcss";
### Existing Code Context
The file `resources/css/app.css` already exists with:
- Tailwind and Flux CSS imports (PRESERVE these)
- Zinc color palette (can be REMOVED - not used in brand)
- Accent color variables using neutral-800 (REPLACE with brand colors)
- Flux field/label/control selectors (PRESERVE these)
### Merge Strategy
- Keep all `@import` statements at the top
- Keep `@source` directives
- Keep `@custom-variant dark` definition
- Replace the `@theme` block content with brand colors below
- Keep `@layer theme`, `@layer base`, and Flux selectors intact
### Color Implementation
```css
/* resources/css/app.css - REPLACE the @theme block with this content */
@theme {
/* Primary */
/* Keep existing font if needed, or update in typography story */
--font-sans: 'Instrument Sans', ui-sans-serif, system-ui, sans-serif;
/* Primary Brand Colors */
--color-navy: #0A1F44;
--color-gold: #D4AF37;
/* Supporting */
/* Supporting Colors */
--color-gold-light: #F4E4B8;
--color-cream: #F9F7F4;
--color-charcoal: #2C3E50;
/* Status */
/* Status Colors */
--color-success: #27AE60;
--color-danger: #E74C3C;
--color-warning: #F39C12;
/* Semantic aliases */
/* Semantic Aliases - used by components */
--color-primary: var(--color-navy);
--color-accent: var(--color-gold);
--color-accent-content: var(--color-gold);
--color-accent-foreground: var(--color-navy);
--color-background: var(--color-cream);
--color-text: var(--color-charcoal);
}
```
**Note:** The `--color-accent-content` and `--color-accent-foreground` variables are used by Flux UI components and must be updated to use brand colors.
## Testing Requirements
### Build Verification
- [ ] Run `npm run build` - must complete without errors
- [ ] Verify CSS output contains the new color variables
### Utility Class Verification
Create a temporary test view or use browser dev tools to verify:
- [ ] `bg-navy` applies background color #0A1F44
- [ ] `text-gold` applies text color #D4AF37
- [ ] `bg-cream` applies background color #F9F7F4
- [ ] `text-charcoal` applies text color #2C3E50
- [ ] `bg-success` applies background color #27AE60
- [ ] `bg-danger` applies background color #E74C3C
- [ ] `bg-warning` applies background color #F39C12
- [ ] Semantic aliases work: `bg-primary`, `text-accent`, `bg-background`
### Regression Check
- [ ] Existing Flux UI components still render correctly
- [ ] No visual regressions on existing pages
## Definition of Done
- [ ] All colors defined in Tailwind
- [ ] Colors work with utility classes (bg-navy, text-gold)
- [ ] Dark mode consideration documented
- [ ] Tests pass
- [ ] All colors defined in Tailwind @theme block
- [ ] Colors work with utility classes (bg-navy, text-gold, etc.)
- [ ] Semantic aliases configured (primary, accent, background, text)
- [ ] Dark mode explicitly documented as deferred
- [ ] Existing Flux UI styling preserved
- [ ] `npm run build` succeeds
- [ ] Manual verification of utility classes complete
- [ ] Code formatted with Pint
## Estimation

View File

@ -3,6 +3,18 @@
## Epic Reference
**Epic 9:** Design & Branding Implementation
## Dependencies
- **Story 9.1:** Color System Implementation (provides `gold`, `navy` Tailwind color classes used in focus styles)
- **Stories 9.4-9.7:** Component Styling (all styled components require accessibility review)
- **Story 9.8:** RTL/LTR Layout (accessibility must work in both directions)
## Scope
This story applies to **all pages and components**:
- Public pages (landing, posts, booking)
- Authentication pages (login, register, password reset)
- Client dashboard and all client-facing views
- Admin dashboard and all admin-facing views
## User Story
As a **user with disabilities**,
I want **the platform to be accessible**,
@ -10,10 +22,12 @@ So that **I can use it regardless of my abilities**.
## Acceptance Criteria
### Color Contrast
- [ ] Body text: 4.5:1 minimum
- [ ] Large text: 3:1 minimum
- [ ] UI elements: 3:1 minimum
### Color Contrast (WCAG AA Standard)
- [ ] Body text: 4.5:1 minimum contrast ratio
- [ ] Large text (18px+ bold or 24px+ regular): 3:1 minimum
- [ ] UI elements (buttons, form borders, icons): 3:1 minimum
- [ ] Verify gold (#D4AF37) on navy (#0A1F44) meets requirements
- [ ] Verify text colors on cream (#F9F7F4) backgrounds
### Focus Indicators
- [ ] Visible focus outline (gold)
@ -34,8 +48,27 @@ So that **I can use it regardless of my abilities**.
- [ ] Respect prefers-reduced-motion
- [ ] No auto-playing animations
## Files to Modify
| File | Changes |
|------|---------|
| `resources/css/app.css` | Add global focus styles and reduced-motion media query |
| `resources/views/components/layouts/app.blade.php` | Add skip link and `<main id="main-content">` landmark |
| `resources/views/components/layouts/guest.blade.php` | Add skip link and main landmark for auth pages |
| `lang/en/accessibility.php` | Add translation: `'skip_to_content' => 'Skip to main content'` |
| `lang/ar/accessibility.php` | Add translation: `'skip_to_content' => 'تخطي إلى المحتوى الرئيسي'` |
### Components to Audit
- All Flux UI form components (verify label associations)
- All image usages (verify alt text present)
- Navigation components (verify logical tab order)
- Modal components (verify focus trapping)
## Technical Notes
### Global Accessibility Styles
Add to `resources/css/app.css`:
```css
/* Focus styles */
:focus-visible {
@ -80,10 +113,40 @@ So that **I can use it regardless of my abilities**.
```
### Testing Tools
- axe DevTools
- WAVE
- Lighthouse
- Screen reader (VoiceOver/NVDA)
- **axe DevTools** - Browser extension for automated accessibility testing
- **WAVE** - Web accessibility evaluation tool
- **Lighthouse** - Chrome DevTools accessibility audit (target: >90 score)
- **Screen reader** - VoiceOver (macOS) or NVDA (Windows) for manual testing
### Test Scenarios
1. **Keyboard Navigation Test:**
- Tab through entire booking form without mouse
- Verify all buttons, links, and inputs are reachable
- Confirm focus order is logical (top-to-bottom, start-to-end)
2. **Skip Link Test:**
- Press Tab on page load
- Skip link should appear and be focusable
- Activating skip link jumps to main content
3. **Screen Reader Test:**
- Navigate landing page with VoiceOver/NVDA
- Verify headings announced in correct order (h1 → h2 → h3)
- Verify form labels read correctly
- Verify images have meaningful alt text
4. **Color Contrast Test:**
- Run Lighthouse on: `/`, `/login`, `/dashboard`, `/admin`
- All pages must score >90 accessibility
5. **Reduced Motion Test:**
- Enable "Reduce motion" in OS settings
- Verify no animations play on page load or interactions
6. **RTL Accessibility Test:**
- Switch to Arabic language
- Verify skip link position (start = right in RTL)
- Verify tab order follows RTL reading direction
## Definition of Done
- [ ] Color contrast passes
@ -95,5 +158,17 @@ So that **I can use it regardless of my abilities**.
- [ ] Lighthouse accessibility > 90
- [ ] Tests pass
## References
- **PRD Section 7.1:** Brand Identity - Accessibility Compliance subsection
- **Epic 9:** `docs/epics/epic-9-design-branding.md` - Story 9.10 acceptance criteria
- **Story 9.1:** Color values defined (gold: #D4AF37, navy: #0A1F44)
- **WCAG 2.1 AA Guidelines:** https://www.w3.org/WAI/WCAG21/quickref/
## Estimation
**Complexity:** Medium | **Effort:** 4-5 hours
## Notes for Developer
- Flux UI components generally have good accessibility built-in; focus on custom components
- If Flux components don't meet contrast requirements, create custom CSS overrides
- The `!important` in reduced-motion CSS is intentional to override all animations
- Use `focus:start-4` (not `focus:left-4`) for RTL compatibility

View File

@ -3,6 +3,13 @@
## 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**,
@ -38,6 +45,26 @@ So that **the interface feels polished and responsive**.
## 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** (`<flux:button>`): 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 `<x-spinner />` component with `wire:loading` directive
- **Toast Notifications**: Integrate with Livewire event dispatch for flash messages
### Animation CSS
```css
/* Base transitions */
.transition-default {
@ -95,6 +122,29 @@ So that **the interface feels polished and responsive**.
.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
@ -117,6 +167,42 @@ So that **the interface feels polished and responsive**.
</div>
```
## 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
@ -125,7 +211,8 @@ So that **the interface feels polished and responsive**.
- [ ] Toast animations work
- [ ] All animations subtle
- [ ] Reduced motion respected
- [ ] Tests pass
- [ ] Pest browser tests pass
- [ ] Cross-browser tested (Chrome, Firefox, Safari)
## Estimation
**Complexity:** Medium | **Effort:** 4 hours

View File

@ -3,6 +3,12 @@
## Epic Reference
**Epic 9:** Design & Branding Implementation
## Dependencies
- **Story 9.1 (Color System)** must be complete - this story extends the existing `@theme` block in `resources/css/app.css`
## PRD Reference
- **Section 7.1.C:** Typography specifications (font families, weights, hierarchy)
## User Story
As a **user**,
I want **professional, readable typography**,
@ -32,8 +38,12 @@ So that **the platform feels polished and content is easy to read**.
## Technical Notes
**Target File:** `resources/css/app.css`
**Implementation:** Add the font imports and extend the existing `@theme` block from Story 9.1 with typography variables.
```css
/* Google Fonts import */
/* Google Fonts import - add at top of file */
@import url('https://fonts.googleapis.com/css2?family=Cairo:wght@300;400;600;700&family=Montserrat:wght@300;400;600;700&display=swap');
@theme {
@ -60,13 +70,48 @@ html[lang="en"] body {
}
```
## Testing Approach
### Visual Verification
- [ ] Font hierarchy renders at correct sizes (H1=40px, H2=32px, H3=24px, Body=16px, Small=14px)
- [ ] Line heights display correctly (1.6 for body, 1.3 for headings)
- [ ] Font weights display correctly (Light 300, Regular 400, SemiBold 600, Bold 700)
### RTL/LTR Testing
- [ ] Arabic pages (`html[lang="ar"]`) use Cairo/Tajawal font family
- [ ] English pages (`html[lang="en"]`) use Montserrat/Lato font family
- [ ] Language toggle switches fonts correctly without page reload issues
### Performance Testing
- [ ] Network tab confirms `font-display=swap` in Google Fonts URL
- [ ] No FOIT (Flash of Invisible Text) - text displays with fallback then swaps
- [ ] Font files load from Google Fonts CDN successfully
### Browser Compatibility
- [ ] Fonts render correctly in Chrome, Firefox, Safari, Edge
- [ ] Fallback fonts (`sans-serif`) work if Google Fonts fails to load
## Definition of Done
- [ ] Fonts load correctly
- [ ] Arabic fonts work with RTL
- [ ] English fonts work with LTR
- [ ] Font hierarchy applied
- [ ] Performance optimized
- [ ] Tests pass
- [ ] Font imports added to `resources/css/app.css`
- [ ] Typography variables added to `@theme` block
- [ ] Dynamic font selection CSS rules implemented
- [ ] Arabic fonts render correctly with RTL layout
- [ ] English fonts render correctly with LTR layout
- [ ] Font hierarchy visually verified on test pages
- [ ] Performance optimized (font-display: swap confirmed)
- [ ] All testing scenarios above pass
- [ ] Code formatted with Pint
- [ ] Assets rebuilt with `npm run build`
## Assumptions
- Google Fonts CDN is acceptable for font hosting (no self-hosting requirement)
- The `html[lang]` attribute is already set by the existing i18n system
- Story 9.1's `@theme` block is in place and working
## Notes for Developer
- **Extend, don't replace:** Add font variables to the existing `@theme` block from Story 9.1
- **Import order matters:** Place Google Fonts `@import` before the `@import "tailwindcss"` statement
- **Fallback fonts:** The CSS includes fallbacks (`'Tajawal'`, `'Lato'`, `sans-serif`) - these are intentional for graceful degradation
## Estimation
**Complexity:** Medium | **Effort:** 3 hours

View File

@ -8,45 +8,67 @@ As a **visitor**,
I want **to see the Libra scales logo prominently displayed**,
So that **I recognize the firm's branding**.
## Dependencies
- **Story 9.1:** Color System Implementation (for brand colors)
- **Prerequisite:** Logo SVG/PNG assets must be provided or placeholder created
- **Note:** Footer integration deferred to Story 9.7; Email templates to Epic 8
## Acceptance Criteria
### Logo Placement
- [ ] Navigation: Top left (desktop), centered (mobile)
- [ ] Footer: Smaller version
- [ ] Email templates: Header
- [ ] PDF exports: Header
- [ ] Footer: Smaller version (integrated when footer created in Story 9.7)
- [ ] Email templates: Header (integrated when email templates created in Epic 8)
- [ ] PDF exports: Header (integrated when PDF exports created)
### Logo Specifications
- [ ] Minimum size: 120px (desktop), 80px (mobile)
- [ ] Clear space: 20px padding minimum
- [ ] Minimum size: 120px width (desktop), 80px width (mobile)
- [ ] Clear space: 20px padding minimum around logo
### Format Support
- [ ] SVG primary (scalable)
- [ ] PNG fallback
- [ ] SVG primary (scalable, preferred)
- [ ] PNG fallback (for email clients that don't support SVG)
### Color Variations
- [ ] Full color (gold on navy)
- [ ] Reversed (navy on light)
- [ ] Monochrome gold
- [ ] **Full color:** Gold (#D4AF37) logo on Navy (#0A1F44) background
- [ ] **Reversed:** Navy (#0A1F44) logo on light/cream (#F9F7F4) background
- [ ] **Monochrome:** Single-color gold (#D4AF37) version
### Features
- [ ] Responsive sizing
- [ ] Accessible alt text
- [ ] Responsive sizing based on viewport
- [ ] Accessible alt text: "Libra Law Firm" (translatable)
## Technical Notes
### Existing Component
An `app-logo.blade.php` component already exists at `resources/views/components/app-logo.blade.php`. This story will **replace** it with a more robust implementation supporting variants and sizes.
**Files to modify:**
- `resources/views/components/app-logo.blade.php` - Replace with new implementation
- `resources/views/components/app-logo-icon.blade.php` - Update or remove
- `resources/views/components/layouts/app/header.blade.php` - Update logo usage (lines 11, 96)
**Files to create:**
- `public/images/logo.svg` - Full color logo
- `public/images/logo-reversed.svg` - Reversed color logo
- `public/images/logo-mono.svg` - Monochrome logo
- `public/images/logo.png` - PNG fallback
### Logo Component Implementation
```blade
<!-- resources/views/components/logo.blade.php -->
<!-- resources/views/components/app-logo.blade.php -->
@props([
'size' => 'default',
'variant' => 'full'
'variant' => 'full',
'showText' => true
])
@php
$sizes = [
'small' => 'h-8',
'default' => 'h-12',
'large' => 'h-16',
'small' => 'h-8 min-w-[80px]', // Mobile minimum
'default' => 'h-12 min-w-[120px]', // Desktop default
'large' => 'h-16 min-w-[160px]', // Large displays
];
$variants = [
@ -54,23 +76,116 @@ $variants = [
'reversed' => 'logo-reversed.svg',
'mono' => 'logo-mono.svg',
];
$sizeClass = $sizes[$size] ?? $sizes['default'];
$logoFile = $variants[$variant] ?? $variants['full'];
@endphp
<img
src="{{ asset('images/' . $variants[$variant]) }}"
alt="{{ __('Libra Law Firm') }}"
{{ $attributes->merge(['class' => $sizes[$size]]) }}
/>
<div {{ $attributes->merge(['class' => 'flex items-center gap-2 p-5']) }}>
<img
src="{{ asset('images/' . $logoFile) }}"
alt="{{ __('Libra Law Firm') }}"
class="{{ $sizeClass }} w-auto object-contain"
onerror="this.onerror=null; this.src='{{ asset('images/logo.png') }}';"
/>
@if($showText)
<span class="font-semibold text-sm truncate">{{ __('Libra Law Firm') }}</span>
@endif
</div>
```
### Logo Asset Fallback Strategy
If final logo assets are not yet available:
1. Create a placeholder SVG using Libra scales icon from Heroicons or similar
2. Use the brand colors (Gold #D4AF37, Navy #0A1F44)
3. Replace with final assets when provided
### Color Reference (from Story 9.1)
| Color | Hex | Usage |
|-------|-----|-------|
| Dark Navy Blue | #0A1F44 | Primary background |
| Gold/Brass | #D4AF37 | Primary accent, logo |
| Off-White/Cream | #F9F7F4 | Light backgrounds |
## Testing Requirements
### Unit Tests
Create `tests/Feature/Components/LogoComponentTest.php`:
```php
<?php
use function Pest\Laravel\get;
test('logo component renders with default props', function () {
$view = $this->blade('<x-app-logo />');
$view->assertSee('Libra Law Firm');
$view->assertSee('logo.svg');
});
test('logo component renders small size variant', function () {
$view = $this->blade('<x-app-logo size="small" />');
$view->assertSee('h-8');
});
test('logo component renders reversed color variant', function () {
$view = $this->blade('<x-app-logo variant="reversed" />');
$view->assertSee('logo-reversed.svg');
});
test('logo component renders without text when showText is false', function () {
$view = $this->blade('<x-app-logo :showText="false" />');
$view->assertDontSee('<span');
});
test('logo has accessible alt text', function () {
$view = $this->blade('<x-app-logo />');
$view->assertSee('alt="Libra Law Firm"', false);
});
```
### Browser Tests (Pest v4)
Create `tests/Browser/LogoTest.php`:
```php
<?php
it('displays logo in navigation on desktop', function () {
$page = visit('/');
$page->assertVisible('img[alt="Libra Law Firm"]')
->assertNoJavascriptErrors();
});
it('logo is responsive on mobile viewport', function () {
$page = visit('/')
->viewport(375, 812); // iPhone viewport
$page->assertVisible('img[alt="Libra Law Firm"]');
});
```
## Definition of Done
- [ ] Logo displays in navigation
- [ ] Logo displays in footer
- [ ] Logo in email templates
- [ ] Responsive sizing works
- [ ] All color variants available
- [ ] Alt text correct
- [ ] Tests pass
- [ ] Logo component created with size and variant props
- [ ] Logo displays correctly in navigation header
- [ ] All three color variants available and working
- [ ] PNG fallback works when SVG fails to load
- [ ] Responsive sizing works across breakpoints
- [ ] Alt text is present and translatable
- [ ] Existing header.blade.php updated to use new component
- [ ] Unit tests pass
- [ ] Browser tests pass
- [ ] Code formatted with Pint
## Out of Scope (Deferred)
- Footer logo placement → Story 9.7
- Email template logo → Epic 8 (Story 8.1+)
- PDF export logo → Future story
## Estimation
**Complexity:** Low | **Effort:** 2 hours
**Complexity:** Low | **Effort:** 2-3 hours

View File

@ -3,25 +3,38 @@
## Epic Reference
**Epic 9:** Design & Branding Implementation
## Dependencies
- **Story 9.1: Color System Implementation** - Must be complete (this story uses the color variables defined there)
## User Story
As a **user**,
I want **consistent, professional button styling**,
So that **interactive elements are clear and visually appealing**.
## Context
This story implements the button styling system that will be used throughout the application. Buttons appear in:
- Forms (submit, cancel actions)
- Modals (confirm, dismiss)
- Navigation (CTAs)
- Admin dashboards (CRUD operations)
- Client booking flow
The implementation extends Flux UI's button component with brand colors rather than replacing it, ensuring we maintain Flux's built-in accessibility and functionality.
## Acceptance Criteria
### Primary Button
- [ ] Background: Gold (#D4AF37)
- [ ] Text: Dark Navy Blue
- [ ] Hover: Light Gold (#F4E4B8)
- [ ] Border-radius: 6px
- [ ] Padding: 12px 24px
- [ ] Background: Gold (`bg-gold` / #D4AF37)
- [ ] Text: Dark Navy Blue (`text-navy`)
- [ ] Hover: Light Gold (`hover:bg-gold-light` / #F4E4B8)
- [ ] Border-radius: 6px (`rounded-md`)
- [ ] Padding: 12px 24px (`px-6 py-3`)
### Secondary Button
- [ ] Background: Transparent
- [ ] Border: 2px solid Gold
- [ ] Text: Gold
- [ ] Hover: Gold background, Navy text
- [ ] Border: 2px solid Gold (`border-2 border-gold`)
- [ ] Text: Gold (`text-gold`)
- [ ] Hover: Gold background, Navy text (`hover:bg-gold hover:text-navy`)
### Disabled State
- [ ] Background: #CCCCCC
@ -30,50 +43,178 @@ So that **interactive elements are clear and visually appealing**.
- [ ] Cursor: not-allowed
### Danger Button
- [ ] Background: #E74C3C
- [ ] Background: #E74C3C (`bg-danger`)
- [ ] Text: White
- [ ] Hover: Slightly darker (`hover:bg-danger/90`)
### Button Sizes
- [ ] Small: `px-4 py-2 text-sm` (for compact UI areas)
- [ ] Default: `px-6 py-3 text-base` (standard usage)
- [ ] Large: `px-8 py-4 text-lg` (hero CTAs)
### Features
- [ ] Loading states with spinner
- [ ] Focus states for accessibility
- [ ] Flux UI button integration
- [ ] Loading states with Flux spinner component
- [ ] Focus states: Gold outline ring for accessibility (`focus:ring-2 focus:ring-gold focus:ring-offset-2`)
- [ ] Icon support: Buttons with leading/trailing icons
- [ ] Full-width variant for mobile forms
- [ ] Button groups with proper border-radius handling
## Files to Create/Modify
| File | Action | Purpose |
|------|--------|---------|
| `resources/css/app.css` | Modify | Add button variant styles in @theme or as Tailwind components |
## Technical Notes
### Flux UI Integration Approach
Flux UI buttons accept a `variant` prop. We extend Flux by:
1. Using Flux's `<flux:button>` component as-is for structure
2. Applying brand colors via the `variant` prop or custom CSS classes
3. NOT creating wrapper components unless absolutely necessary
Reference: Use `search-docs` tool with query "button" and package "livewire/flux" for current Flux button API.
### CSS Implementation
```css
/* Extend Flux UI buttons */
/* resources/css/app.css - Add after @import "tailwindcss" and @theme block */
/* Primary button - Gold background */
.btn-primary {
@apply bg-gold text-navy hover:bg-gold-light rounded-md px-6 py-3 font-semibold transition-colors;
@apply focus:outline-none focus:ring-2 focus:ring-gold focus:ring-offset-2;
}
/* Secondary button - Outlined */
.btn-secondary {
@apply bg-transparent border-2 border-gold text-gold hover:bg-gold hover:text-navy rounded-md px-6 py-3 font-semibold transition-colors;
@apply bg-transparent border-2 border-gold text-gold rounded-md px-6 py-3 font-semibold transition-colors;
@apply hover:bg-gold hover:text-navy;
@apply focus:outline-none focus:ring-2 focus:ring-gold focus:ring-offset-2;
}
/* Danger button */
.btn-danger {
@apply bg-danger text-white hover:bg-danger/90 rounded-md px-6 py-3 font-semibold transition-colors;
@apply focus:outline-none focus:ring-2 focus:ring-danger focus:ring-offset-2;
}
/* Disabled state - applies to all variants */
.btn-disabled,
button:disabled,
[disabled] {
@apply bg-gray-300 text-gray-500 cursor-not-allowed;
@apply hover:bg-gray-300; /* Override hover */
}
/* Size variants */
.btn-sm { @apply px-4 py-2 text-sm; }
.btn-lg { @apply px-8 py-4 text-lg; }
/* Full width for mobile */
.btn-full { @apply w-full; }
/* Loading state */
.btn-loading {
@apply relative pointer-events-none;
@apply relative pointer-events-none opacity-75;
}
.btn-loading::after {
content: '';
@apply absolute inset-0 flex items-center justify-center;
/* Spinner styles */
}
/* Icon spacing within buttons */
.btn-icon-left { @apply flex items-center gap-2; }
.btn-icon-right { @apply flex items-center gap-2 flex-row-reverse; }
```
### Usage Examples
```blade
{{-- Primary button with Flux --}}
<flux:button variant="primary" class="btn-primary">
{{ __('Submit') }}
</flux:button>
{{-- Secondary button --}}
<flux:button variant="ghost" class="btn-secondary">
{{ __('Cancel') }}
</flux:button>
{{-- Danger button --}}
<flux:button variant="danger" class="btn-danger">
{{ __('Delete') }}
</flux:button>
{{-- Button with icon --}}
<flux:button class="btn-primary btn-icon-left">
<flux:icon name="plus" class="w-4 h-4" />
{{ __('Add New') }}
</flux:button>
{{-- Loading state --}}
<flux:button class="btn-primary" wire:loading.class="btn-loading">
<span wire:loading.remove>{{ __('Save') }}</span>
<span wire:loading>{{ __('Saving...') }}</span>
</flux:button>
{{-- Full width on mobile --}}
<flux:button class="btn-primary btn-full sm:w-auto">
{{ __('Book Consultation') }}
</flux:button>
```
### Edge Cases to Handle
- **Icon-only buttons**: Ensure adequate touch target (44px minimum)
- **Long button text**: Text should not overflow; consider truncation or wrapping
- **RTL layout**: Icons should flip position appropriately (use logical `start`/`end` if needed)
- **Button groups**: First/last buttons need adjusted border-radius
## Testing Requirements
### Test Approach
- **Visual testing**: Verify all button states render correctly
- **Accessibility testing**: Validate focus states and contrast ratios
- **RTL testing**: Confirm buttons display correctly in Arabic mode
### Test Scenarios
```php
// tests/Feature/Components/ButtonStylingTest.php
test('primary button has correct styling classes', function () {
$this->get('/')
->assertSee('btn-primary');
});
test('disabled button prevents interaction', function () {
// Verify disabled state renders with correct cursor and no hover
});
test('buttons are keyboard accessible', function () {
// Verify focus states are visible
});
test('buttons render correctly in RTL mode', function () {
// Set locale to Arabic and verify button layout
});
```
### Accessibility Checklist
- [ ] Focus indicator visible (gold ring)
- [ ] Color contrast meets WCAG AA (4.5:1 for text)
- [ ] Touch targets minimum 44x44px on mobile
- [ ] Disabled state communicated to screen readers
## Definition of Done
- [ ] Primary button styled
- [ ] Secondary button styled
- [ ] Danger button styled
- [ ] Disabled states work
- [ ] Loading states work
- [ ] Focus states accessible
- [ ] Primary button styled per acceptance criteria
- [ ] Secondary button styled per acceptance criteria
- [ ] Danger button styled per acceptance criteria
- [ ] Disabled states work correctly
- [ ] Loading states work with Flux spinner
- [ ] Focus states visible and accessible
- [ ] Size variants (sm, default, lg) implemented
- [ ] Icon buttons work correctly
- [ ] Full-width variant works on mobile
- [ ] RTL layout tested
- [ ] Tests pass
- [ ] Code formatted with Pint
## Estimation
**Complexity:** Medium | **Effort:** 3 hours

View File

@ -8,45 +8,82 @@ As a **user**,
I want **consistent, accessible form styling**,
So that **data entry is intuitive and error states are clear**.
## Dependencies
- **Story 9.1 (Color System)** - Must be completed first; provides Tailwind color aliases used below
- **Story 9.2 (Typography System)** - Font weights for labels
## Color Reference (from Story 9.1)
For quick reference, this story uses these colors defined in the Tailwind theme:
- `gold` (#D4AF37) - Focus states, checkbox accents
- `charcoal` (#2C3E50) - Default borders, label text
- `danger` (#E74C3C) - Error states
- `cream` (#F9F7F4) - Input backgrounds (if needed)
## Acceptance Criteria
### Input Fields
- [ ] Border: Charcoal Gray
- [ ] Focus: Gold border
- [ ] Border-radius: 6px
- [ ] Padding: 12px 16px
- [ ] Border: Charcoal Gray (`border-charcoal/30`)
- [ ] Focus: Gold border with subtle ring (`focus:border-gold focus:ring-gold/20`)
- [ ] Border-radius: 6px (`rounded-md`)
- [ ] Padding: 12px 16px (`px-4 py-3`)
### Textareas
- [ ] Same styling as inputs
- [ ] Minimum height: 120px
- [ ] Minimum height: 120px (`min-h-[120px]`)
### Select Dropdowns
- [ ] Custom styled (not native)
- [ ] Consistent with inputs
- [ ] Custom styled using Flux UI (not native browser)
- [ ] Consistent border/focus styling with inputs
### Checkboxes & Radios
- [ ] Custom styled with gold accent
- [ ] Clear checked state
- [ ] Custom styled with gold accent when checked
- [ ] Clear visual distinction between checked/unchecked states
### Labels
- [ ] SemiBold weight
- [ ] Required indicator (*)
- [ ] SemiBold weight (`font-semibold`)
- [ ] Required indicator (*) in danger color
### Error States
- [ ] Red border
- [ ] Error message below field
- [ ] Red border (`border-danger`)
- [ ] Error message displayed below field
- [ ] Error ring on focus (`focus:ring-danger/20`)
### RTL Support
- [ ] All fields align correctly in RTL
- [ ] Labels align to the right in RTL mode
- [ ] Input text direction follows locale
- [ ] Error messages align correctly
- [ ] Padding swaps appropriately (use `ps-4 pe-4` instead of `px-4` if needed)
## Technical Notes
## Files to Create/Modify
### Primary Files
- `resources/css/app.css` - Add form component utility classes
### Flux UI Integration
Flux UI Free includes these form components that need styling customization:
- `flux:input` - Text inputs
- `flux:textarea` - Multiline text
- `flux:select` - Dropdown selects
- `flux:checkbox` - Checkboxes
- `flux:radio` - Radio buttons
- `flux:field` - Field wrapper with label/error support
### Existing Forms to Audit
Review and update existing forms in:
- `resources/views/livewire/` - Any Volt components with forms
- Authentication views (login, register, password reset)
- Contact/booking forms
## Technical Implementation
### CSS Classes (add to `resources/css/app.css`)
```css
/* Form field styling */
.input-field {
@apply w-full border border-charcoal/30 rounded-md px-4 py-3
focus:border-gold focus:ring-2 focus:ring-gold/20
transition-colors outline-none;
transition-colors outline-none bg-white;
}
.input-error {
@ -66,21 +103,158 @@ So that **data entry is intuitive and error states are clear**.
@apply text-sm text-danger mt-1;
}
/* Textarea specific */
.textarea-field {
@apply input-field min-h-[120px] resize-y;
}
/* Custom checkbox */
.checkbox-custom {
@apply w-5 h-5 rounded border-charcoal/30 text-gold
focus:ring-gold focus:ring-offset-0;
}
/* Custom radio */
.radio-custom {
@apply w-5 h-5 border-charcoal/30 text-gold
focus:ring-gold focus:ring-offset-0;
}
```
### Flux UI Component Usage Examples
```blade
{{-- Basic input with label --}}
<flux:field>
<flux:label class="form-label">Email</flux:label>
<flux:input type="email" wire:model="email" class="input-field" />
</flux:field>
{{-- Required field with error --}}
<flux:field>
<flux:label class="form-label form-label-required">Name</flux:label>
<flux:input
wire:model="name"
class="input-field @error('name') input-error @enderror"
/>
@error('name')
<span class="error-message">{{ $message }}</span>
@enderror
</flux:field>
{{-- Textarea --}}
<flux:field>
<flux:label class="form-label">Message</flux:label>
<flux:textarea wire:model="message" class="textarea-field" />
</flux:field>
{{-- Select dropdown --}}
<flux:field>
<flux:label class="form-label">Category</flux:label>
<flux:select wire:model="category" class="input-field">
<flux:select.option value="">Select...</flux:select.option>
<flux:select.option value="legal">Legal</flux:select.option>
<flux:select.option value="general">General</flux:select.option>
</flux:select>
</flux:field>
{{-- Checkbox with gold accent --}}
<flux:field>
<flux:checkbox wire:model="agree" class="checkbox-custom" />
<flux:label class="form-label inline ms-2">I agree to the terms</flux:label>
</flux:field>
{{-- Radio group --}}
<flux:field>
<flux:label class="form-label form-label-required">Preferred Contact</flux:label>
<div class="flex gap-4 mt-2">
<label class="flex items-center gap-2">
<flux:radio wire:model="contact" value="email" class="radio-custom" />
<span>Email</span>
</label>
<label class="flex items-center gap-2">
<flux:radio wire:model="contact" value="phone" class="radio-custom" />
<span>Phone</span>
</label>
</div>
</flux:field>
```
### RTL Considerations
- Use logical properties where possible (`ps-`, `pe-`, `ms-`, `me-` instead of `pl-`, `pr-`, `ml-`, `mr-`)
- Flux components should handle RTL automatically with `dir="rtl"` on the HTML element
- Test label positioning in Arabic locale
## Testing Requirements
### Manual Testing Checklist
1. **Visual Inspection (both locales)**
- [ ] Switch to Arabic - verify RTL alignment
- [ ] Switch to English - verify LTR alignment
- [ ] All form elements match design specs
2. **Interactive States**
- [ ] Click into each field type - verify gold focus ring appears
- [ ] Tab through form - verify focus order is logical
- [ ] Submit with errors - verify error styling appears
3. **Accessibility**
- [ ] Labels are associated with inputs (clicking label focuses input)
- [ ] Error messages are announced to screen readers
- [ ] Focus indicators are clearly visible
### Automated Tests
Create feature test for form styling verification:
```php
// tests/Feature/FormStylingTest.php
test('form fields render with correct classes', function () {
// Test that forms include the expected CSS classes
$this->get('/contact')
->assertSee('input-field')
->assertSee('form-label');
});
test('form error states display correctly', function () {
// Submit form with invalid data and check error styling
Livewire::test('contact-form')
->set('email', 'invalid')
->call('submit')
->assertSee('input-error')
->assertSee('error-message');
});
```
### Browser Testing (RTL Verification)
```php
// tests/Browser/FormRtlTest.php
it('displays form labels on the right in RTL mode', function () {
visit('/ar/contact')
->assertPresent('[dir="rtl"]')
->assertVisible('.form-label');
// Visual inspection for alignment
});
```
## Definition of Done
- [ ] Input styling consistent
- [ ] Textarea styling consistent
- [ ] Select styling works
- [ ] Checkbox/radio styled
- [ ] Error states clear
- [ ] RTL alignment correct
- [ ] Tests pass
- [ ] CSS classes added to `resources/css/app.css`
- [ ] Input styling matches specs (border, focus, padding, radius)
- [ ] Textarea styling consistent with inputs, min-height 120px
- [ ] Select dropdowns styled consistently (not native)
- [ ] Checkboxes show gold accent when checked
- [ ] Radio buttons show gold accent when selected
- [ ] Labels are semibold with required indicator working
- [ ] Error states show red border and message below
- [ ] RTL alignment verified in Arabic locale
- [ ] LTR alignment verified in English locale
- [ ] Existing forms updated to use new classes
- [ ] Feature tests pass
- [ ] Code formatted with Pint
## Estimation
**Complexity:** Medium | **Effort:** 3-4 hours
## Dev Notes
- Check Flux UI docs for any built-in theming options before adding custom CSS
- If Flux components don't accept className props well, may need to use CSS selectors targeting Flux's rendered HTML
- Run `npm run build` after CSS changes to see updates

View File

@ -3,6 +3,9 @@
## Epic Reference
**Epic 9:** Design & Branding Implementation
## Dependencies
- **Story 9.1:** Color System Implementation (required - provides Tailwind color classes used in this story)
## User Story
As a **user**,
I want **consistent card and container styling**,
@ -38,6 +41,19 @@ So that **content is well-organized and visually appealing**.
## Technical Notes
### Color Classes Reference (from Story 9.1)
| Class | Color | Hex |
|-------|-------|-----|
| `bg-cream` | Off-white/Cream | #F9F7F4 |
| `text-gold` / `border-gold` | Gold | #D4AF37 |
| `bg-gold/10` | Gold at 10% opacity | - |
| `text-navy` | Dark Navy Blue | #0A1F44 |
| `text-charcoal` | Charcoal Gray | #2C3E50 |
| `text-success` | Success Green | #27AE60 |
| `text-danger` | Warning Red | #E74C3C |
### Component Implementation
```blade
<!-- resources/views/components/card.blade.php -->
@props([
@ -79,6 +95,35 @@ So that **content is well-organized and visually appealing**.
</x-card>
```
### Edge Cases
- **Null/Zero Trend:** Stat card should gracefully handle `null` trend (hidden) and `0` trend (show as neutral)
- **RTL Layout:** Cards with `border-s-4` will automatically flip border to right side in RTL mode
- **Container Overflow:** Content exceeding max-width should be contained; consider horizontal scroll for tables
- **Missing Icon:** Handle gracefully if Flux icon name doesn't exist (fallback or hide icon container)
- **Empty Cards:** Ensure cards maintain minimum height even with minimal content
## Testing Requirements
### Unit Tests
- [ ] Card component renders with default variant
- [ ] Card component renders with `elevated` variant
- [ ] Card component applies hover classes when `hover=true`
- [ ] Card component applies highlight border when `highlight=true`
- [ ] Stat card displays value and label correctly
- [ ] Stat card shows positive trend with `+` prefix and success color
- [ ] Stat card shows negative trend with danger color
- [ ] Stat card hides trend indicator when `trend=null`
### Visual/Browser Tests
- [ ] Hover lift effect animates smoothly
- [ ] Shadow transitions on hover
- [ ] Cards display correctly in RTL layout
- [ ] Container centers content and respects max-width
- [ ] Responsive behavior at all breakpoints
### Test File Location
`tests/Feature/Components/CardComponentTest.php`
## Definition of Done
- [ ] Card component created
- [ ] Shadow and radius consistent

View File

@ -3,6 +3,12 @@
## Epic Reference
**Epic 9:** Design & Branding Implementation
## Story Dependencies
- **Story 9.1:** Color System Implementation (provides `bg-navy`, `text-gold`, `text-cream` classes)
- **Story 9.3:** Logo Integration (provides `<x-logo>` component with variants)
- **Story 1.3:** Bilingual Infrastructure (provides language toggle mechanism)
- **Story 1.4:** Base UI Navigation (provides existing header structure)
## User Story
As a **user**,
I want **professional navigation and footer styling**,
@ -11,94 +17,376 @@ So that **I can easily navigate the site and find information**.
## Acceptance Criteria
### Navigation Bar
- [ ] Fixed top position
- [ ] Navy blue background
- [ ] Fixed top position with `z-50`
- [ ] Navy blue background (`bg-navy`)
- [ ] Logo left (desktop), centered (mobile)
- [ ] Gold text for links
- [ ] Active link indicator
- [ ] Language toggle styled
- [ ] Gold text for links (`text-gold`)
- [ ] Active link indicator (gold underline or background)
- [ ] Language toggle styled consistently
- [ ] Responsive mobile menu
### Mobile Menu
- [ ] Full-width dropdown/slide
- [ ] Navy background
- [ ] Clear touch targets (44px+)
- [ ] Smooth animation
- [ ] Full-width dropdown/slide from left
- [ ] Navy background (`bg-navy`)
- [ ] Clear touch targets (44px+ minimum)
- [ ] Smooth animation (200-300ms)
- [ ] Close button visible
### Footer
- [ ] Navy blue background
- [ ] Logo and firm info
- [ ] Contact details
- [ ] Links to Terms/Privacy
- [ ] Copyright notice
- [ ] Sticky footer (always at bottom)
- [ ] Navy blue background (`bg-navy`)
- [ ] Logo and firm info (using `<x-logo variant="reversed">`)
- [ ] Contact details section
- [ ] Links to Terms/Privacy pages
- [ ] Copyright notice with dynamic year
- [ ] Sticky footer (always at bottom even on short pages)
## Technical Notes
### Edge Cases
- [ ] Guest navigation: Show Home, Posts, Contact, Login/Register
- [ ] Authenticated navigation: Show Home, Dashboard, Posts, user menu
- [ ] RTL layout: Logo moves to right, menu items reverse order
- [ ] Empty page content: Footer stays at viewport bottom
## Technical Implementation
### Files to Modify
| File | Action | Purpose |
|------|--------|---------|
| `resources/views/components/layouts/app/header.blade.php` | Modify | Update nav styling to brand colors |
| `resources/views/components/layouts/app.blade.php` | Modify | Add footer component, ensure sticky footer |
| `resources/views/components/layouts/auth.blade.php` | Modify | Add footer for auth pages |
| `resources/css/app.css` | Modify | Add nav-specific utilities if needed |
### Files to Create
| File | Purpose |
|------|---------|
| `resources/views/components/footer.blade.php` | Reusable footer component |
| `resources/views/components/nav-link.blade.php` | Styled navigation link with active state |
| `resources/views/components/mobile-menu.blade.php` | Mobile navigation drawer (optional - can inline) |
### Color Reference (from Story 9.1)
```
Navy Blue: bg-navy (#0A1F44) - nav/footer background
Gold: text-gold (#D4AF37) - links, accents
Light Gold: text-gold-light (#F4E4B8) - hover states
Cream: text-cream (#F9F7F4) - footer text
```
### Navigation Structure
```blade
<!-- Navigation -->
<nav class="fixed top-0 inset-x-0 bg-navy z-50">
<div class="container mx-auto px-4">
<div class="flex items-center justify-between h-16">
<!-- Logo -->
<a href="/" class="flex items-center">
<x-logo size="small" />
</a>
<!-- resources/views/components/layouts/app/header.blade.php -->
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}" dir="{{ app()->getLocale() === 'ar' ? 'rtl' : 'ltr' }}">
<head>
@include('partials.head')
</head>
<body class="min-h-screen flex flex-col bg-cream">
<!-- Fixed Navigation -->
<nav class="fixed top-0 inset-x-0 bg-navy z-50" x-data="{ mobileMenu: false }">
<div class="container mx-auto px-4">
<div class="flex items-center justify-between h-16">
<!-- Logo -->
<a href="{{ route('home') }}" class="flex items-center" wire:navigate>
<x-logo size="small" />
</a>
<!-- Desktop Links -->
<div class="hidden md:flex items-center gap-6">
<x-nav-link href="/" :active="request()->is('/')">
{{ __('nav.home') }}
</x-nav-link>
<x-nav-link href="/posts" :active="request()->is('posts*')">
{{ __('nav.posts') }}
</x-nav-link>
<!-- More links -->
<!-- Desktop Links -->
<div class="hidden md:flex items-center gap-6">
<x-nav-link href="{{ route('home') }}" :active="request()->routeIs('home')">
{{ __('nav.home') }}
</x-nav-link>
<x-nav-link href="{{ route('posts.index') }}" :active="request()->routeIs('posts.*')">
{{ __('nav.posts') }}
</x-nav-link>
@guest
<x-nav-link href="{{ route('login') }}" :active="request()->routeIs('login')">
{{ __('nav.login') }}
</x-nav-link>
@else
<x-nav-link href="{{ route('dashboard') }}" :active="request()->routeIs('dashboard')">
{{ __('nav.dashboard') }}
</x-nav-link>
@endguest
<!-- Language Toggle -->
<x-language-toggle />
</div>
<!-- Mobile Toggle -->
<button
class="md:hidden text-gold p-2 min-h-[44px] min-w-[44px] flex items-center justify-center"
x-on:click="mobileMenu = !mobileMenu"
aria-label="{{ __('Toggle menu') }}"
>
<flux:icon name="bars-3" class="w-6 h-6" x-show="!mobileMenu" />
<flux:icon name="x-mark" class="w-6 h-6" x-show="mobileMenu" x-cloak />
</button>
</div>
</div>
<!-- Mobile Toggle -->
<button class="md:hidden text-gold" x-on:click="mobileMenu = !mobileMenu">
<flux:icon name="bars-3" class="w-6 h-6" />
</button>
</div>
</div>
</nav>
<!-- Mobile Menu -->
<div
class="md:hidden bg-navy border-t border-gold/20"
x-show="mobileMenu"
x-transition:enter="transition ease-out duration-200"
x-transition:enter-start="opacity-0 -translate-y-2"
x-transition:enter-end="opacity-100 translate-y-0"
x-transition:leave="transition ease-in duration-150"
x-transition:leave-start="opacity-100 translate-y-0"
x-transition:leave-end="opacity-0 -translate-y-2"
x-cloak
>
<div class="container mx-auto px-4 py-4 space-y-2">
<x-nav-link href="{{ route('home') }}" :active="request()->routeIs('home')" mobile>
{{ __('nav.home') }}
</x-nav-link>
<x-nav-link href="{{ route('posts.index') }}" :active="request()->routeIs('posts.*')" mobile>
{{ __('nav.posts') }}
</x-nav-link>
@guest
<x-nav-link href="{{ route('login') }}" :active="request()->routeIs('login')" mobile>
{{ __('nav.login') }}
</x-nav-link>
<x-nav-link href="{{ route('register') }}" :active="request()->routeIs('register')" mobile>
{{ __('nav.register') }}
</x-nav-link>
@else
<x-nav-link href="{{ route('dashboard') }}" :active="request()->routeIs('dashboard')" mobile>
{{ __('nav.dashboard') }}
</x-nav-link>
@endguest
</div>
</div>
</nav>
<!-- Footer -->
<!-- Spacer for fixed nav -->
<div class="h-16"></div>
<!-- Main Content -->
<main class="flex-1">
{{ $slot }}
</main>
<!-- Footer -->
<x-footer />
@fluxScripts
</body>
</html>
```
### Nav Link Component
```blade
<!-- resources/views/components/nav-link.blade.php -->
@props(['active' => false, 'mobile' => false])
@php
$baseClasses = $mobile
? 'block px-4 py-3 min-h-[44px] text-base font-medium transition-colors duration-150'
: 'text-sm font-medium transition-colors duration-150';
$activeClasses = $active
? 'text-gold-light'
: 'text-gold hover:text-gold-light';
@endphp
<a {{ $attributes->merge(['class' => "$baseClasses $activeClasses"]) }} wire:navigate>
{{ $slot }}
</a>
```
### Footer Component
```blade
<!-- resources/views/components/footer.blade.php -->
<footer class="bg-navy text-cream mt-auto">
<div class="container mx-auto px-4 py-12">
<div class="grid md:grid-cols-3 gap-8">
<!-- Logo & Description -->
<div>
<x-logo variant="reversed" />
<p class="mt-4 text-sm opacity-80">{{ __('footer.description') }}</p>
<p class="mt-4 text-sm opacity-80">
{{ __('footer.description') }}
</p>
</div>
<!-- Quick Links -->
<div>
<h4 class="font-semibold text-gold mb-4">{{ __('footer.links') }}</h4>
<ul class="space-y-2 text-sm">
<li><a href="{{ route('page.show', 'terms') }}" class="hover:text-gold">{{ __('footer.terms') }}</a></li>
<li><a href="{{ route('page.show', 'privacy') }}" class="hover:text-gold">{{ __('footer.privacy') }}</a></li>
<li>
<a href="{{ route('page.show', 'terms') }}" class="hover:text-gold transition-colors duration-150" wire:navigate>
{{ __('footer.terms') }}
</a>
</li>
<li>
<a href="{{ route('page.show', 'privacy') }}" class="hover:text-gold transition-colors duration-150" wire:navigate>
{{ __('footer.privacy') }}
</a>
</li>
</ul>
</div>
<!-- Contact Info -->
<div>
<h4 class="font-semibold text-gold mb-4">{{ __('footer.contact') }}</h4>
<!-- Contact info -->
<ul class="space-y-2 text-sm opacity-80">
<li class="flex items-center gap-2 rtl:flex-row-reverse">
<flux:icon name="envelope" class="w-4 h-4 text-gold" />
<span>{{ config('libra.contact.email', 'info@libra.ps') }}</span>
</li>
<li class="flex items-center gap-2 rtl:flex-row-reverse">
<flux:icon name="phone" class="w-4 h-4 text-gold" />
<span dir="ltr">{{ config('libra.contact.phone', '+970 2 123 4567') }}</span>
</li>
<li class="flex items-start gap-2 rtl:flex-row-reverse">
<flux:icon name="map-pin" class="w-4 h-4 text-gold mt-0.5" />
<span>{{ config('libra.contact.address', 'Ramallah, Palestine') }}</span>
</li>
</ul>
</div>
</div>
<!-- Copyright -->
<div class="border-t border-cream/20 mt-8 pt-8 text-sm text-center opacity-60">
&copy; {{ date('Y') }} {{ __('footer.copyright') }}
&copy; {{ date('Y') }} {{ __('footer.copyright', ['name' => config('app.name')]) }}
</div>
</div>
</footer>
```
### Sticky Footer CSS (if needed)
```css
/* resources/css/app.css - add if flex approach insufficient */
body {
display: flex;
flex-direction: column;
min-height: 100vh;
}
main {
flex: 1;
}
```
## RTL Considerations
1. **Logo Position:** Use `rtl:order-last` if logo should move to right in RTL
2. **Menu Items:** Flex containers with `rtl:flex-row-reverse` or use logical properties
3. **Icons:** Some icons (arrows, chevrons) may need flipping with `rtl:scale-x-[-1]`
4. **Spacing:** Use `ms-*`/`me-*` (margin-start/end) instead of `ml-*`/`mr-*`
5. **Text Alignment:** Use `text-start`/`text-end` instead of `text-left`/`text-right`
## Translation Keys Required
```php
// resources/lang/en/nav.php
return [
'home' => 'Home',
'posts' => 'Posts',
'login' => 'Login',
'register' => 'Register',
'dashboard' => 'Dashboard',
];
// resources/lang/en/footer.php
return [
'description' => 'Professional legal services in Palestine.',
'links' => 'Quick Links',
'terms' => 'Terms of Service',
'privacy' => 'Privacy Policy',
'contact' => 'Contact Us',
'copyright' => 'All rights reserved. :name',
];
```
## Definition of Done
- [ ] Navigation styled correctly
- [ ] Mobile menu works
- [ ] Footer styled correctly
- [ ] Sticky footer works
- [ ] Links functional
- [ ] RTL layout works
- [ ] Navigation styled with navy background and gold links
- [ ] Mobile menu works with smooth animation
- [ ] Footer styled and positioned correctly
- [ ] Sticky footer works on short-content pages
- [ ] All navigation links functional
- [ ] RTL layout mirrors correctly (logo right, reversed order)
- [ ] Guest vs authenticated nav items display correctly
- [ ] Language toggle integrated and styled
- [ ] Touch targets meet 44px minimum on mobile
- [ ] Tests pass
## Testing Requirements
### Feature Tests
```php
// tests/Feature/NavigationTest.php
test('navigation displays home link', function () {
$this->get('/')
->assertSee(__('nav.home'));
});
test('guest sees login link in navigation', function () {
$this->get('/')
->assertSee(__('nav.login'));
});
test('authenticated user sees dashboard link', function () {
$user = User::factory()->create();
$this->actingAs($user)
->get('/')
->assertSee(__('nav.dashboard'))
->assertDontSee(__('nav.login'));
});
test('footer displays on all pages', function () {
$this->get('/')
->assertSee(__('footer.copyright'));
});
test('footer links to terms and privacy', function () {
$this->get('/')
->assertSee(__('footer.terms'))
->assertSee(__('footer.privacy'));
});
```
### Browser Tests (Pest v4)
```php
// tests/Browser/NavigationTest.php
it('mobile menu toggles correctly', function () {
visit('/')
->resize(375, 812) // iPhone viewport
->assertNotVisible('[x-show="mobileMenu"]')
->click('[aria-label="Toggle menu"]')
->assertVisible('[x-show="mobileMenu"]')
->click('[aria-label="Toggle menu"]')
->assertNotVisible('[x-show="mobileMenu"]');
});
it('navigation renders correctly in RTL', function () {
visit('/?lang=ar')
->assertAttribute('html', 'dir', 'rtl');
});
```
### Manual Testing Checklist
- [ ] Desktop: Nav links visible, hover states work
- [ ] Mobile: Menu toggle works, touch targets adequate
- [ ] RTL (Arabic): Layout mirrors correctly
- [ ] LTR (English): Standard layout
- [ ] Short page: Footer at viewport bottom
- [ ] Long page: Footer at content bottom
- [ ] Guest user: Login/Register visible
- [ ] Logged in: Dashboard/user menu visible
## Estimation
**Complexity:** Medium | **Effort:** 4 hours
## References
- Epic 9 Definition: `docs/epics/epic-9-design-branding.md`
- Color System: Story 9.1
- Logo Component: Story 9.3
- Existing Header: `resources/views/components/layouts/app/header.blade.php`
- PRD Design Section: `docs/prd.md#design-requirements`

View File

@ -3,88 +3,286 @@
## Epic Reference
**Epic 9:** Design & Branding Implementation
## Story Dependencies
- **Story 9.1** (Color System) - Must be complete; RTL audit needs final color variables
- **Story 9.4** (Button Styling) - Buttons must use logical properties
- **Story 9.5** (Form Styling) - Forms require RTL label/error positioning
- **Story 9.6** (Cards & Containers) - Cards need directional border handling
- **Story 9.7** (Navigation & Footer) - Navigation mirroring depends on this work
## User Story
As a **user**,
I want **perfect RTL layout for Arabic and LTR for English**,
So that **the content is natural to read in my language**.
## Background Context
### Current State (from codebase analysis)
The application already has partial RTL support:
- `app()->getLocale()` sets `lang` attribute on `<html>`
- Some logical properties already in use: `border-e`, `me-5`, `rtl:space-x-reverse`
- **Missing:** `dir` attribute is NOT set on `<html>` element
- **Missing:** Systematic RTL audit of all components
### PRD Requirements (Section 4.2)
- Primary Language: Arabic (default) with RTL layout
- Secondary Language: English with LTR layout
- Full site language toggle
- All UI elements in both languages
## Acceptance Criteria
### RTL (Arabic)
- [ ] Text aligns right
- [ ] Navigation mirrors (logo right)
- [ ] Form labels on right
- [ ] Icons/arrows flip appropriately
- [ ] Margins/paddings swap
- [ ] `dir="rtl"` dynamically set on `<html>` when locale is `ar`
- [ ] Text aligns right naturally
- [ ] Navigation mirrors (sidebar on right for RTL)
- [ ] Form labels on right side of inputs
- [ ] Icons/arrows flip appropriately (chevrons, arrows)
- [ ] Margins/paddings swap using logical properties
### LTR (English)
- [ ] `dir="ltr"` set on `<html>` when locale is `en`
- [ ] Standard left-to-right layout
- [ ] Proper text alignment
### Transitions
- [ ] Seamless language toggle
- [ ] Seamless language toggle without page reload issues
- [ ] No layout breaks on switch
- [ ] No flash of wrong direction on page load
### Component Support
- [ ] Calendar RTL support
- [ ] Tables RTL support
- [ ] All components tested in both modes
- [ ] Calendar component RTL support (date picker)
- [ ] Tables RTL support (horizontal scroll direction)
- [ ] Dropdowns open in correct direction
- [ ] Modals position correctly
- [ ] All Flux UI components tested in both modes
## Technical Notes
## Technical Implementation
```css
/* Use logical properties */
.card {
margin-inline-start: 1rem; /* margin-left in LTR, margin-right in RTL */
padding-inline-end: 1rem; /* padding-right in LTR, padding-left in RTL */
}
### Key Files to Modify
/* RTL-aware utilities */
[dir="rtl"] .flip-rtl {
transform: scaleX(-1);
}
/* Tailwind RTL plugin configuration */
@theme {
/* Use logical properties by default */
}
#### 1. Layout Files (Add `dir` attribute)
```
resources/views/components/layouts/app/sidebar.blade.php
resources/views/components/layouts/auth/simple.blade.php
resources/views/components/layouts/auth/card.blade.php
resources/views/components/layouts/auth/split.blade.php
```
**Change:** Update `<html>` tag in each layout:
```blade
<html
lang="{{ str_replace('_', '-', app()->getLocale()) }}"
dir="{{ app()->getLocale() === 'ar' ? 'rtl' : 'ltr' }}"
class="dark"
>
```
#### 2. CSS Configuration
```
resources/css/app.css
```
**Add RTL utilities in `@theme` or `@layer`:**
```css
/* RTL-aware icon flipping */
[dir="rtl"] .flip-rtl {
transform: scaleX(-1);
}
/* Force LTR for numbers/code */
.ltr-content {
direction: ltr;
unicode-bidi: embed;
}
```
#### 3. Navigation Component
```
resources/views/components/layouts/app/sidebar.blade.php
```
**Audit and update:**
- Sidebar position (currently uses `border-e` - good)
- Logo placement
- Menu item icons
- Dropdown positions
#### 4. Form Components (Flux UI overrides if needed)
```
resources/views/livewire/auth/*.blade.php
resources/views/livewire/settings/*.blade.php
```
**Ensure all forms use:**
- `text-start` instead of `text-left`
- `ms-*` / `me-*` instead of `ml-*` / `mr-*`
- `ps-*` / `pe-*` instead of `pl-*` / `pr-*`
- `start-*` / `end-*` instead of `left-*` / `right-*`
### Tailwind CSS 4 RTL Approach
Tailwind CSS 4 supports logical properties natively. **Do NOT install a separate RTL plugin.**
**Logical Property Mapping:**
| Physical | Logical (Use This) |
|----------|-------------------|
| `left-*` | `start-*` |
| `right-*` | `end-*` |
| `ml-*` | `ms-*` |
| `mr-*` | `me-*` |
| `pl-*` | `ps-*` |
| `pr-*` | `pe-*` |
| `text-left` | `text-start` |
| `text-right` | `text-end` |
| `border-l-*` | `border-s-*` |
| `border-r-*` | `border-e-*` |
| `rounded-l-*` | `rounded-s-*` |
| `rounded-r-*` | `rounded-e-*` |
**For directional icons that must flip:**
```blade
<!-- RTL-aware icon -->
<flux:icon
name="arrow-right"
@class(['flip-rtl' => app()->getLocale() === 'ar'])
name="chevron-right"
class="{{ app()->getLocale() === 'ar' ? 'flip-rtl' : '' }}"
/>
```
<!-- RTL-aware positioning -->
<div class="{{ app()->getLocale() === 'ar' ? 'right-0' : 'left-0' }} absolute">
<!-- Content -->
</div>
**Better: Use bidirectional-aware icons when available:**
- Use `chevron-end` concept or flip via CSS
<!-- Better: Use logical properties -->
<div class="start-0 absolute">
<!-- Content -->
### Edge Cases to Handle
#### Numbers in RTL
Numbers should remain LTR even in Arabic context:
```blade
<span class="ltr-content">{{ $consultation->id }}</span>
```
#### Mixed Content (Arabic with English)
Wrap English phrases in LTR spans when embedded in Arabic:
```blade
<p>{{ __('Contact us at') }} <span class="ltr-content">info@libra.ps</span></p>
```
#### Form Validation Errors
Ensure error messages appear on the correct side:
```blade
<!-- Flux handles this, but verify -->
<flux:field>
<flux:label>{{ __('Email') }}</flux:label>
<flux:input type="email" wire:model="email" />
<flux:error name="email" /> <!-- Should align with field direction -->
</flux:field>
```
#### Toast Notifications
Verify toast position respects direction:
- LTR: Appear from right
- RTL: Appear from left (or respect `start`/`end`)
#### Tables with Horizontal Scroll
```blade
<div class="overflow-x-auto" dir="ltr"> <!-- Force LTR scroll -->
<table>
<!-- Table content inherits document direction for text -->
</table>
</div>
```
### Testing Checklist
- [ ] Navigation layout
- [ ] Form layouts
- [ ] Card layouts
- [ ] Table layouts
- [ ] Modal layouts
- [ ] Dropdown menus
- [ ] Pagination
## Testing Checklist
### Manual Visual Testing (Required)
Test each in **both Arabic and English**:
- [ ] **Navigation layout**
- Sidebar appears on correct side
- Logo position correct
- Menu items align properly
- Dropdown menus open correct direction
- [ ] **Form layouts**
- Labels align correctly
- Input text direction correct
- Error messages position correctly
- Submit buttons align properly
- [ ] **Card layouts**
- Content aligns correctly
- Border highlights on correct side
- Action buttons position correctly
- [ ] **Table layouts**
- Headers align correctly
- Cell content respects direction
- Horizontal scroll works
- [ ] **Modal layouts**
- Close button position correct
- Content alignment correct
- Action buttons order correct (Cancel/Confirm)
- [ ] **Dropdown menus**
- Open in correct direction
- Items align correctly
- [ ] **Pagination**
- Previous/Next arrows correct
- Page numbers display correctly
### Automated Testing (Recommended)
Create Pest browser tests for critical RTL scenarios:
```php
// tests/Browser/RtlLayoutTest.php
it('displays RTL layout for Arabic locale', function () {
// Set locale to Arabic
// Visit dashboard
// Assert dir="rtl" on html element
// Assert sidebar is on right side
});
```
### Browser Testing
Test in:
- [ ] Chrome (Windows/Mac)
- [ ] Firefox
- [ ] Safari
- [ ] Mobile Safari (iOS)
- [ ] Chrome Mobile (Android)
## Definition of Done
- [ ] RTL renders correctly
- [ ] LTR renders correctly
- [ ] Language switch seamless
- [ ] Icons flip correctly
- [ ] All components tested
- [ ] No layout breaks
- [ ] `dir` attribute dynamically set based on locale
- [ ] RTL renders correctly in Arabic
- [ ] LTR renders correctly in English
- [ ] Language switch is seamless (no layout flash)
- [ ] Icons flip correctly where appropriate
- [ ] All components from Testing Checklist verified
- [ ] No layout breaks on language switch
- [ ] Numbers and emails display correctly (LTR in RTL context)
- [ ] Code formatted with Pint
- [ ] Tests pass
## Dev Notes
### Flux UI RTL Support
Flux UI components generally support RTL well when `dir="rtl"` is set on `<html>`. However, audit each component for:
- Icon positions
- Dropdown directions
- Border placements
### Avoid These Patterns
```blade
<!-- BAD: Physical properties -->
<div class="ml-4 text-left border-l-2">
<!-- GOOD: Logical properties -->
<div class="ms-4 text-start border-s-2">
```
### Resources
- Tailwind CSS Logical Properties: Check `search-docs` for latest Tailwind 4 docs
- Flux UI RTL: Test each component, file issues if needed
## Estimation
**Complexity:** High | **Effort:** 5-6 hours

View File

@ -3,52 +3,138 @@
## Epic Reference
**Epic 9:** Design & Branding Implementation
## Dependencies
- **Story 9.1:** Color System Implementation (colors must be defined)
- **Story 9.2:** Typography System (fonts and hierarchy must be in place)
- **Story 9.4-9.6:** Component Styling (buttons, forms, cards must be styled)
- **Story 9.7:** Navigation & Footer Styling (navigation responsive behavior)
- **Story 9.8:** RTL/LTR Layout Perfection (responsive must work in both directions)
## References
- **PRD Section 7.4:** Responsive Breakpoints (`docs/prd.md#74-responsive-breakpoints`)
- **PRD Section 5.1:** Landing page responsive requirements
- **PRD Section 5.7-5.8:** Dashboard responsive requirements (admin/client)
- **Epic 9:** Full acceptance criteria (`docs/epics/epic-9-design-branding.md`)
## User Story
As a **user**,
I want **the platform to work perfectly on all device sizes**,
So that **I can use it on my phone, tablet, or desktop**.
## Scope
### Pages/Components Requiring Responsive Work
1. **Public Pages:**
- Landing page (hero, about sections, booking form)
- Posts/blog listing and detail pages
- Login page
- Terms of Service / Privacy Policy pages
2. **Client Dashboard:**
- Overview/stats cards
- Consultations list and detail views
- Case timelines view
- Booking form with calendar
- Profile view
3. **Admin Dashboard:**
- Statistics cards and charts
- User management tables
- Booking management views
- Timeline management
- Posts management
- Working hours configuration
- Settings pages
4. **Shared Components:**
- Navigation bar (already handled in 9.7, verify integration)
- Footer
- Modal dialogs
- Form components
- Tables
- Cards
## Acceptance Criteria
### Breakpoints
- [ ] Mobile: < 576px
- [ ] Tablet: 576px - 991px
- [ ] Desktop: 992px - 1199px
- [ ] Large Desktop: >= 1200px
### Breakpoints (per PRD Section 7.4)
- [ ] Mobile: < 576px (single column, stacked layouts)
- [ ] Tablet: 576px - 991px (two columns where appropriate)
- [ ] Desktop: 992px - 1199px (full layouts with sidebars)
- [ ] Large Desktop: >= 1200px (max-width container: 1200px)
### Mobile Optimizations
- [ ] Touch-friendly targets (44px+)
- [ ] Readable font sizes
- [ ] Single column layouts
- [ ] Collapsible sections
### Mobile Optimizations (< 576px)
- [ ] Touch-friendly targets minimum 44px height/width for all interactive elements
- [ ] Font sizes remain readable (minimum 16px for body text to prevent iOS zoom)
- [ ] Single column layouts for all content sections
- [ ] Collapsible/accordion sections for long content
- [ ] Navigation collapses to hamburger menu
- [ ] Forms stack labels above inputs
- [ ] Cards display full-width
### Tablet Optimizations
- [ ] Two-column where appropriate
- [ ] Sidebar collapsible
### Tablet Optimizations (576px - 991px)
- [ ] Two-column grid layouts where appropriate (dashboard stats, post listings)
- [ ] Sidebar collapsible via toggle (not permanently visible)
- [ ] Tables may show reduced columns or scroll horizontally
- [ ] Calendar shows week view or scrollable month
### Desktop Optimizations
- [ ] Full layouts with sidebars
- [ ] Multi-column grids
### Desktop Optimizations (992px+)
- [ ] Full layouts with persistent sidebars
- [ ] Multi-column grids (3-4 columns for dashboard stats)
- [ ] Tables show all columns
- [ ] Calendar shows full month view
- [ ] Max container width: 1200px centered
### Specific Features
- [ ] All forms usable on mobile
- [ ] Calendar usable on mobile
- [ ] Tables scroll horizontally
- [ ] No horizontal scroll on any viewport
### Specific Feature Requirements
- [ ] **Forms:** All forms (booking, login, user management) fully usable on mobile with proper input sizing
- [ ] **Calendar:** Booking calendar functional on mobile (touch-friendly date selection, scrollable)
- [ ] **Tables:** All data tables have horizontal scroll wrapper, pinned first column if needed
- [ ] **No horizontal scroll:** Page-level horizontal scroll must never occur on any viewport
- [ ] **Modals:** Modal dialogs responsive (full-screen on mobile, centered on desktop)
- [ ] **Charts:** Dashboard charts resize appropriately or stack on mobile
### RTL Considerations
- [ ] All responsive layouts tested in both LTR (English) and RTL (Arabic)
- [ ] Sidebar collapses from correct side (start-0 not left-0)
- [ ] Horizontal scroll direction correct for RTL
## Technical Notes
### Technology Stack
- **Tailwind CSS 4:** Using CSS-first configuration with `@theme` directive
- **Flux UI Free:** Leverage built-in responsive behavior for available components
- **Alpine.js:** For mobile menu toggles and collapsible sections (included with Livewire)
### Key Files to Modify
```
resources/css/app.css # Responsive utility classes
resources/views/components/layouts/ # Layout templates
- app.blade.php # Main layout wrapper
- guest.blade.php # Public pages layout
resources/views/livewire/
- Various dashboard components # Component-specific responsive styles
resources/views/components/
- card.blade.php # Card responsive variants
- table.blade.php # Table wrapper component
```
### Tailwind 4 Responsive Approach
Use mobile-first with Tailwind's responsive prefixes:
```css
/* Mobile-first approach */
/* In resources/css/app.css - add to @theme if needed */
/* Mobile-first grid example */
.dashboard-grid {
@apply grid gap-4;
@apply grid-cols-1; /* Mobile */
@apply sm:grid-cols-2; /* Tablet */
@apply lg:grid-cols-3; /* Desktop */
@apply xl:grid-cols-4; /* Large */
@apply grid-cols-1; /* Mobile: single column */
@apply sm:grid-cols-2; /* Tablet: 2 columns */
@apply lg:grid-cols-3; /* Desktop: 3 columns */
@apply xl:grid-cols-4; /* Large: 4 columns */
}
/* Touch targets */
/* Touch-friendly targets */
.touch-target {
@apply min-h-[44px] min-w-[44px];
}
@ -56,36 +142,130 @@ So that **I can use it on my phone, tablet, or desktop**.
/* Responsive table wrapper */
.table-responsive {
@apply overflow-x-auto -mx-4 px-4;
@apply sm:mx-0 sm:px-0; /* Remove negative margin on larger screens */
}
/* Collapsible sidebar */
/* Collapsible sidebar - uses logical properties for RTL */
@media (max-width: 991px) {
.sidebar {
@apply fixed inset-y-0 start-0 w-64 transform -translate-x-full transition-transform z-40;
@apply fixed inset-y-0 start-0 w-64;
@apply transform -translate-x-full transition-transform duration-200;
@apply z-40 bg-navy-900;
}
.sidebar.open {
@apply translate-x-0;
}
/* RTL: sidebar comes from right */
[dir="rtl"] .sidebar {
@apply end-0 start-auto translate-x-full;
}
[dir="rtl"] .sidebar.open {
@apply translate-x-0;
}
}
```
### Testing Devices
- iPhone SE (375px)
- iPhone 14 (390px)
- iPad (768px)
- iPad Pro (1024px)
- Desktop (1280px)
- Large Desktop (1920px)
### Flux UI Responsive Behavior
- Flux UI components have built-in responsive behavior
- `<flux:modal>` automatically handles responsive sizing
- `<flux:dropdown>` positions correctly on mobile
- Override with Tailwind classes when Flux defaults insufficient
### Preventing Horizontal Scroll
```css
/* Add to base styles */
html, body {
@apply overflow-x-hidden;
}
/* Ensure images/media don't overflow */
img, video, iframe {
@apply max-w-full h-auto;
}
```
## Testing Strategy
### Testing Approach
1. **Browser DevTools:** Primary method for rapid iteration
2. **Real Devices:** Final verification on actual phones/tablets
3. **Both Languages:** Test each breakpoint in English (LTR) AND Arabic (RTL)
### Test Devices/Viewports
| Device | Width | Type |
|--------|-------|------|
| iPhone SE | 375px | Mobile |
| iPhone 14 | 390px | Mobile |
| iPhone 14 Pro Max | 430px | Mobile (large) |
| iPad | 768px | Tablet |
| iPad Pro | 1024px | Tablet (large) |
| Desktop | 1280px | Desktop |
| Large Desktop | 1920px | Large Desktop |
### Key Test Scenarios
**Mobile (375px - English & Arabic):**
- [ ] Navigate from landing page to login
- [ ] Complete full booking flow (select date, fill form, submit)
- [ ] View consultation list and detail
- [ ] View case timeline
- [ ] Open and close mobile navigation menu
- [ ] Submit a form with validation errors
- [ ] Scroll through long table (user list)
**Tablet (768px - English & Arabic):**
- [ ] Toggle sidebar open/closed
- [ ] View dashboard with 2-column stat cards
- [ ] Use calendar in booking flow
- [ ] Manage users in table view
**Desktop (1280px - English & Arabic):**
- [ ] Verify sidebar is persistent
- [ ] Dashboard shows 3-4 column grids
- [ ] Full table columns visible
- [ ] Calendar shows month view
### Automated Testing (Optional)
Consider Pest browser tests for critical flows:
```php
it('booking form works on mobile', function () {
$this->browse(function ($browser) {
$browser->resize(375, 667)
->visit('/booking')
->assertVisible('.booking-form')
->type('summary', 'Test consultation')
->press('Submit')
->assertSee('Request submitted');
});
});
```
## Definition of Done
- [ ] Mobile layout works
- [ ] Tablet layout works
- [ ] Desktop layout works
- [ ] No horizontal scroll
- [ ] Touch targets 44px+
- [ ] Forms usable on mobile
- [ ] Calendar usable on mobile
- [ ] Tests pass
- [ ] All pages render correctly at mobile breakpoint (375px) in both LTR and RTL
- [ ] All pages render correctly at tablet breakpoint (768px) in both LTR and RTL
- [ ] All pages render correctly at desktop breakpoint (1280px) in both LTR and RTL
- [ ] No horizontal page scroll at any viewport width from 320px to 1920px
- [ ] All interactive elements meet 44px minimum touch target
- [ ] Booking form with calendar fully functional on mobile
- [ ] All data tables horizontally scrollable without breaking layout
- [ ] Mobile navigation menu opens/closes smoothly
- [ ] Sidebar collapses correctly on tablet (from correct side for RTL)
- [ ] Modal dialogs display correctly on all breakpoints
- [ ] Code formatted with `vendor/bin/pint --dirty`
- [ ] Manual testing completed on at least one real mobile device
## Out of Scope
- Native mobile app development
- Print stylesheets
- Email template responsiveness (covered in separate story)
- Performance optimization (separate concern)
## Estimation
**Complexity:** High | **Effort:** 5-6 hours
## Notes for Developer
- Start with mobile layouts, then progressively enhance for larger screens
- Use Tailwind's responsive prefixes (`sm:`, `md:`, `lg:`, `xl:`) consistently
- Prefer logical properties (`start-`, `end-`, `ms-`, `me-`) over directional (`left-`, `right-`, `ml-`, `mr-`) for RTL compatibility
- Test frequently in browser DevTools during development
- If a component from Flux UI doesn't behave responsively as expected, check Flux docs first before overriding