reviewed epic 9 stories
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user