Public Access
feat(ui): close 3 P2 audit findings + a11y sweep (Sprint 3)
- lib/toast.tsx (renamed from .ts for JSX): new showToast.undo(message, onUndo, ms=5000) helper. Inline 'Undo' button dismisses the toast and fires onUndo. Note: react-hot-toast 2.6 lacks onClose/onDismiss, so expiry is silent — same effective behavior as confirm() declined. - Dashboard.handleDelete: captures the full MealPlanItem before the DELETE so Undo can re-fire meals.generateItem(planId, dayOfWeek, mealType) and refill the slot (recipe may differ — see plan R4). - Pantry.handleRemove: fully reversible — Undo re-fires pantry.add with the original ingredient_id, quantity, and unit. New removeId state scopes the spinner to the clicked row. - Both confirm() call sites removed. - App.tsx Navigation: whitespace-nowrap + px-2 sm:px-3 so all 4 links fit on one line down to 360 px. aria-current='page' on the active link. <nav aria-label='Primary'>, <main id='main-content'>. - components/ui/Badge: optional icon and aria-label props. Dashboard approval-status Badge passes aria-label='Approval status: approved' (or the current value) so screen readers don't rely on color alone. - ErrorBoundary already mounted at App.tsx:42 — verified, no code change. - Review/sprint3-verification.md (new) + Review/ui-nielsen-audit.md and fix-ui-audit.md updated with Sprint 3 status and deploy steps. Build: npm run build (tsc + vite) green. tsc 0 errors.
This commit is contained in:
@@ -18,20 +18,20 @@ function Navigation() {
|
||||
const isActive = (prefix: string) => path === prefix || path.startsWith(prefix + '/')
|
||||
|
||||
const linkClass = (prefix: string) =>
|
||||
`inline-flex items-center px-3 py-2 text-sm font-medium rounded-lg transition-colors ${
|
||||
`inline-flex items-center px-2 sm:px-3 py-2 text-sm font-medium rounded-lg transition-colors whitespace-nowrap ${
|
||||
isActive(prefix)
|
||||
? 'text-primary-700 bg-primary-50'
|
||||
: 'text-surface-600 hover:bg-surface-100'
|
||||
}`
|
||||
|
||||
return (
|
||||
<nav className="bg-white border-b border-surface-200 sticky top-0 z-50">
|
||||
<nav className="bg-white border-b border-surface-200 sticky top-0 z-50" aria-label="Primary">
|
||||
<div className="max-w-7xl mx-auto px-3 sm:px-6 lg:px-8">
|
||||
<div className="flex items-center gap-1 min-h-14 py-2">
|
||||
<Link to="/" className={linkClass('/')}>MealPlanner</Link>
|
||||
<Link to="/recipes" className={linkClass('/recipes')}>Recipes</Link>
|
||||
<Link to="/pantry" className={linkClass('/pantry')}>Pantry</Link>
|
||||
<Link to="/shopping-list" className={linkClass('/shopping-list')}>Shopping List</Link>
|
||||
<Link to="/" className={linkClass('/')} aria-current={isActive('/') ? 'page' : undefined}>MealPlanner</Link>
|
||||
<Link to="/recipes" className={linkClass('/recipes')} aria-current={isActive('/recipes') ? 'page' : undefined}>Recipes</Link>
|
||||
<Link to="/pantry" className={linkClass('/pantry')} aria-current={isActive('/pantry') ? 'page' : undefined}>Pantry</Link>
|
||||
<Link to="/shopping-list" className={linkClass('/shopping-list')} aria-current={isActive('/shopping-list') ? 'page' : undefined}>Shopping List</Link>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
@@ -45,7 +45,7 @@ function App() {
|
||||
<BrowserRouter>
|
||||
<div className="min-h-screen bg-surface-50">
|
||||
<Navigation />
|
||||
<main className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
|
||||
<main className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8" id="main-content">
|
||||
<Routes>
|
||||
<Route path="/" element={<Dashboard />} />
|
||||
<Route path="/meals/:id" element={<MealDetail />} />
|
||||
|
||||
Reference in New Issue
Block a user