Created comprehensive Story and Task files for Sprint 4 frontend implementation: Story 1: Story Detail Page Foundation (P0 Critical - 3 days) - 6 tasks: route creation, header, sidebar, data loading, Edit/Delete, responsive design - Fixes critical 404 error when clicking Story cards - Two-column layout consistent with Epic detail page Story 2: Task Management in Story Detail (P0 Critical - 2 days) - 6 tasks: API verification, hooks, TaskList, TaskCard, TaskForm, integration - Complete Task CRUD with checkbox status toggle - Filters, sorting, and optimistic UI updates Story 3: Enhanced Story Form (P1 High - 2 days) - 6 tasks: acceptance criteria, assignee selector, tags, story points, integration - Aligns with UX design specification - Backward compatible with existing Stories Story 4: Quick Add Story Workflow (P1 High - 2 days) - 5 tasks: inline form, keyboard shortcuts, batch creation, navigation - Rapid Story creation with minimal fields - Keyboard shortcut (Cmd/Ctrl + N) Story 5: Story Card Component (P2 Medium - 1 day) - 4 tasks: component variants, visual states, Task count, optimization - Reusable component with list/kanban/compact variants - React.memo optimization Story 6: Kanban Story Creation Enhancement (P2 Optional - 2 days) - 4 tasks: Epic card enhancement, inline form, animation, real-time updates - Contextual Story creation from Kanban - Stretch goal - implement only if ahead of schedule Total: 6 Stories, 31 Tasks, 12 days estimated Priority breakdown: P0 (2), P1 (2), P2 (2 optional) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
11 KiB
11 KiB
task_id, story_id, sprint_id, status, type, assignee, created_date, estimated_hours
| task_id | story_id | sprint_id | status | type | assignee | created_date | estimated_hours |
|---|---|---|---|---|---|---|---|
| sprint_4_story_1_task_6 | sprint_4_story_1 | sprint_4 | not_started | frontend | Frontend Developer 1 | 2025-11-05 | 3 |
Task 6: Implement Responsive Design and Accessibility
Description
Ensure the Story detail page works flawlessly on all screen sizes (mobile, tablet, desktop) and meets WCAG 2.1 Level AA accessibility standards. This includes responsive layout adjustments, keyboard navigation, ARIA labels, and focus management.
What to Do
- Test and fix responsive layout on all breakpoints
- Implement mobile-specific UI adjustments (sidebar to tabs)
- Add keyboard navigation support (Tab, Enter, ESC)
- Add ARIA labels to all interactive elements
- Implement focus management (dialog open/close)
- Ensure proper heading hierarchy (h1 → h2 → h3)
- Test color contrast ratios (WCAG AA: 4.5:1 minimum)
- Test with screen reader (NVDA/JAWS)
- Add skip links for keyboard users
- Run Lighthouse accessibility audit
Files to Modify
app/(dashboard)/stories/[id]/page.tsx(modify, responsive tweaks)components/projects/story-header.tsx(modify, accessibility)components/projects/story-metadata-sidebar.tsx(modify, responsive)- All related components (add ARIA labels)
Implementation Details
Responsive Layout Breakpoints
// app/(dashboard)/stories/[id]/page.tsx
// Adjust grid layout for different screens
<div className="grid grid-cols-1 lg:grid-cols-[1fr_320px] gap-6">
{/* Main content - full width on mobile, 70% on desktop */}
<div className="space-y-6 order-2 lg:order-1">
{/* Story description, acceptance criteria, tasks */}
</div>
{/* Sidebar - full width on mobile (at top), fixed width on desktop */}
<aside className="order-1 lg:order-2">
{/* Metadata sidebar */}
</aside>
</div>
Mobile-Specific Adjustments
// Convert sidebar sections to tabs on mobile
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
function MobileStoryMetadata({ story, parentEpic }: Props) {
return (
<Tabs defaultValue="details" className="lg:hidden">
<TabsList className="w-full">
<TabsTrigger value="details">Details</TabsTrigger>
<TabsTrigger value="time">Time</TabsTrigger>
<TabsTrigger value="epic">Epic</TabsTrigger>
</TabsList>
<TabsContent value="details">
{/* Status, Priority, Assignee */}
</TabsContent>
<TabsContent value="time">
{/* Time tracking, Dates */}
</TabsContent>
<TabsContent value="epic">
{/* Parent Epic card */}
</TabsContent>
</Tabs>
);
}
ARIA Labels and Roles
// Story header with accessibility
<header role="banner" aria-labelledby="story-title">
<h1 id="story-title" className="text-3xl font-bold">
{story.title}
</h1>
<div role="group" aria-label="Story metadata">
<Badge aria-label={`Status: ${story.status}`}>
{story.status}
</Badge>
<Badge aria-label={`Priority: ${story.priority}`}>
{story.priority}
</Badge>
</div>
<div role="group" aria-label="Story actions">
<Button
onClick={onEdit}
aria-label="Edit story details"
aria-describedby="edit-help"
>
<Edit className="h-4 w-4" aria-hidden="true" />
Edit
</Button>
<span id="edit-help" className="sr-only">
Opens a dialog to edit story title, description, and metadata
</span>
<Button
onClick={onDelete}
aria-label="Delete story permanently"
aria-describedby="delete-help"
>
<Trash2 className="h-4 w-4" aria-hidden="true" />
Delete
</Button>
<span id="delete-help" className="sr-only">
Permanently deletes this story and all associated tasks
</span>
</div>
</header>
// Main content sections
<main role="main" aria-labelledby="story-title">
<section aria-labelledby="description-heading">
<h2 id="description-heading">Description</h2>
<div role="document" aria-label="Story description">
{story.description}
</div>
</section>
<section aria-labelledby="criteria-heading">
<h2 id="criteria-heading">Acceptance Criteria</h2>
{/* Criteria list */}
</section>
<section aria-labelledby="tasks-heading">
<h2 id="tasks-heading">Tasks</h2>
{/* Tasks list */}
</section>
</main>
// Sidebar
<aside role="complementary" aria-label="Story metadata">
<h2 className="sr-only">Story Details</h2>
{/* Metadata cards */}
</aside>
Keyboard Navigation
// Add keyboard shortcuts
useEffect(() => {
const handleKeyDown = (e: KeyboardEvent) => {
// ESC - Go back to Epic
if (e.key === 'Escape' && !isEditDialogOpen && !isDeleteDialogOpen) {
router.push(`/epics/${story.epicId}`);
}
// Cmd/Ctrl + E - Edit Story
if ((e.metaKey || e.ctrlKey) && e.key === 'e') {
e.preventDefault();
setIsEditDialogOpen(true);
}
// Cmd/Ctrl + Backspace - Delete Story
if ((e.metaKey || e.ctrlKey) && e.key === 'Backspace') {
e.preventDefault();
setIsDeleteDialogOpen(true);
}
};
window.addEventListener('keydown', handleKeyDown);
return () => window.removeEventListener('keydown', handleKeyDown);
}, [isEditDialogOpen, isDeleteDialogOpen]);
// Add keyboard shortcut hints
<footer className="mt-8 text-xs text-muted-foreground">
<p>Keyboard shortcuts:</p>
<ul className="list-disc list-inside">
<li>ESC - Back to Epic</li>
<li>Cmd/Ctrl + E - Edit Story</li>
<li>Cmd/Ctrl + Backspace - Delete Story</li>
</ul>
</footer>
Focus Management
// Trap focus in dialogs
import { useFocusTrap } from '@/lib/hooks/use-focus-trap';
function EditStoryDialog({ isOpen, onClose }: Props) {
const dialogRef = useRef<HTMLDivElement>(null);
useFocusTrap(dialogRef, isOpen);
// Auto-focus first field when dialog opens
useEffect(() => {
if (isOpen) {
const firstInput = dialogRef.current?.querySelector('input');
firstInput?.focus();
}
}, [isOpen]);
// Return focus to trigger element when dialog closes
const triggerRef = useRef<HTMLButtonElement | null>(null);
const handleOpen = () => {
triggerRef.current = document.activeElement as HTMLButtonElement;
setIsOpen(true);
};
const handleClose = () => {
setIsOpen(false);
triggerRef.current?.focus();
};
return (
<Dialog open={isOpen} onOpenChange={handleClose}>
<DialogContent ref={dialogRef}>
{/* Dialog content */}
</DialogContent>
</Dialog>
);
}
Skip Links
// Add skip link for keyboard users
<a
href="#main-content"
className="sr-only focus:not-sr-only focus:absolute focus:top-4 focus:left-4 focus:z-50 focus:px-4 focus:py-2 focus:bg-primary focus:text-primary-foreground focus:rounded-md"
>
Skip to main content
</a>
<main id="main-content" tabIndex={-1}>
{/* Main content */}
</main>
Acceptance Criteria
Responsive Design
- Desktop (> 1024px): Two-column layout (content + sidebar)
- Tablet (640px - 1024px): Two-column layout with narrower sidebar
- Mobile (< 640px): Single-column layout, sidebar moves to top or tabs
- All buttons and controls accessible on touch devices
- No horizontal scrolling on any screen size
- Text remains readable on all screen sizes (minimum 14px)
Accessibility (WCAG 2.1 Level AA)
- All interactive elements keyboard accessible (Tab navigation)
- Focus indicators visible (2px outline, high contrast)
- ARIA labels on all buttons, links, and form controls
- Proper heading hierarchy (h1 → h2 → h3)
- Color contrast ratio >= 4.5:1 for all text
- Large text (18px+) contrast ratio >= 3:1
- Screen reader announces all content correctly
- Focus trapped in dialogs (cannot Tab outside)
- Focus returns to trigger element when dialog closes
- Skip links available for keyboard users
- Icons have
aria-hidden="true"(text labels present) - Loading states announced to screen readers (
role="status") - Error messages announced (
role="alert")
Keyboard Navigation
- Tab - Navigate through interactive elements
- Enter - Activate buttons and links
- Space - Toggle checkboxes and buttons
- ESC - Close dialogs and navigate back
- Cmd/Ctrl + E - Edit Story (custom shortcut)
- Cmd/Ctrl + Backspace - Delete Story (custom shortcut)
Testing
Manual Testing
Responsive Design:
- Open Story detail page on desktop → Verify two-column layout
- Resize to tablet width (768px) → Verify layout adjusts
- Resize to mobile width (375px) → Verify single-column layout
- Verify sidebar moves to top on mobile
- Test all buttons clickable on touch device
- Verify no horizontal scrolling on any screen
- Test landscape and portrait orientations
Keyboard Navigation:
- Navigate to Story page using only keyboard
- Press Tab → Verify focus moves through all interactive elements
- Verify focus indicator visible (blue outline)
- Press ESC → Verify navigates back to Epic
- Press Cmd/Ctrl + E → Verify Edit dialog opens
- Press Tab in dialog → Verify focus trapped
- Press ESC in dialog → Verify dialog closes and focus returns
Screen Reader (NVDA/JAWS):
- Enable screen reader
- Navigate to Story page
- Verify page structure announced (heading hierarchy)
- Verify all buttons have labels
- Verify badges announced with context ("Status: In Progress")
- Verify loading states announced
- Verify error messages announced
- Open Edit dialog → Verify form fields labeled correctly
Automated Testing
Lighthouse Audit:
# Run Lighthouse accessibility audit
npm run lighthouse
# Expected results:
# Accessibility: >= 90 (ideally 100)
# Best Practices: >= 90
# SEO: >= 90
# Performance: >= 80 (acceptable for dynamic content)
axe DevTools:
# Install axe DevTools browser extension
# Open Story page
# Run axe scan
# Expected: 0 violations
Color Contrast Testing
# Test all text colors
# Use browser DevTools > Accessibility > Color contrast
# Required ratios (WCAG AA):
# Normal text (< 18px): 4.5:1
# Large text (>= 18px): 3:1
# UI components: 3:1
# Test combinations:
Story Title (32px): Should pass (large text)
Description (16px): Should pass 4.5:1
Metadata labels (14px): Should pass 4.5:1
Badges: Should pass 3:1 (UI components)
Buttons: Should pass 3:1 (UI components)
Dependencies
Prerequisites:
- Task 1, 2, 3, 4, 5 (all components must exist)
- ✅ shadcn/ui components with built-in accessibility
- ✅ Tailwind CSS responsive utilities
- ✅ ARIA attributes support
Blocks:
- None (final polish task)
Estimated Time
3 hours
Notes
Testing Tools:
- Chrome DevTools > Lighthouse (accessibility audit)
- axe DevTools browser extension (automated WCAG testing)
- NVDA/JAWS screen reader (manual testing)
- WAVE browser extension (visual accessibility check)
- Contrast Checker (color contrast ratios)
Common Accessibility Issues to Avoid:
- Missing alt text on images
- Insufficient color contrast
- Missing ARIA labels on icon-only buttons
- Broken keyboard navigation (focus trap)
- Missing heading hierarchy (h1 → h3, skip h2)
- Form inputs without labels
- Loading states not announced to screen readers
Responsive Design Checklist:
- Test on real devices (iPhone, Android, tablet)
- Test different orientations (portrait, landscape)
- Test different zoom levels (100%, 150%, 200%)
- Verify touch targets >= 44x44px
- No horizontal scrolling on any screen