feat: Complete internationalization and code cleanup
## Translation Files - Add 11 new language files (es, de, pt, ru, zh, ja, ko, ar, hi, nl, pl) - Add 100+ missing translation keys across all 15 languages - New sections: notebook, pagination, ai.batchOrganization, ai.autoLabels - Update nav section with workspace, quickAccess, myLibrary keys ## Component Updates - Update 15+ components to use translation keys instead of hardcoded text - Components: notebook dialogs, sidebar, header, note-input, ghost-tags, etc. - Replace 80+ hardcoded English/French strings with t() calls - Ensure consistent UI across all supported languages ## Code Quality - Remove 77+ console.log statements from codebase - Clean up API routes, components, hooks, and services - Keep only essential error handling (no debugging logs) ## UI/UX Improvements - Update Keep logo to yellow post-it style (from-yellow-400 to-amber-500) - Change selection colors to #FEF3C6 (notebooks) and #EFB162 (nav items) - Make "+" button permanently visible in notebooks section - Fix grammar and syntax errors in multiple components ## Bug Fixes - Fix JSON syntax errors in it.json, nl.json, pl.json, zh.json - Fix syntax errors in notebook-suggestion-toast.tsx - Fix syntax errors in use-auto-tagging.ts - Fix syntax errors in paragraph-refactor.service.ts - Fix duplicate "fusion" section in nl.json 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> Ou une version plus courte si vous préférez : feat(i18n): Add 15 languages, remove logs, update UI components - Create 11 new translation files (es, de, pt, ru, zh, ja, ko, ar, hi, nl, pl) - Add 100+ translation keys: notebook, pagination, AI features - Update 15+ components to use translations (80+ strings) - Remove 77+ console.log statements from codebase - Fix JSON syntax errors in 4 translation files - Fix component syntax errors (toast, hooks, services) - Update logo to yellow post-it style - Change selection colors (#FEF3C6, #EFB162) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,15 +1,16 @@
|
||||
---
|
||||
stepsCompleted: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
|
||||
stepsCompleted: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
|
||||
inputDocuments:
|
||||
- _bmad-output/planning-artifacts/prd-phase1-mvp-ai.md
|
||||
- docs/component-inventory.md
|
||||
- docs/project-overview.md
|
||||
workflowType: 'ux-design'
|
||||
lastStep: 11
|
||||
lastStep: 14
|
||||
documentTitle: 'UX Design Specification - Phase 1 MVP AI'
|
||||
focusArea: 'AI-Powered Note Taking Features'
|
||||
status: 'in-progress'
|
||||
status: 'complete'
|
||||
createdAt: '2026-01-10'
|
||||
completedAt: '2026-01-10'
|
||||
---
|
||||
|
||||
# UX Design Specification - Phase 1 MVP AI
|
||||
@@ -2632,3 +2633,945 @@ Build 7 custom components on top of Radix primitives:
|
||||
- **MemoryEchoCard:** Defining "Aha!" experience but most complex (background processing, embeddings, feedback learning)
|
||||
|
||||
---
|
||||
|
||||
## UX Consistency Patterns
|
||||
|
||||
### Button Hierarchy
|
||||
|
||||
**When to Use:**
|
||||
- **Primary Buttons:** Main actions (Save note, Apply suggestion, Create Cahier)
|
||||
- **Secondary Buttons:** Alternative actions (Cancel, Keep original)
|
||||
- **Tertiary Buttons:** Low-emphasis actions (Dismiss, Skip, Later)
|
||||
- **AI Buttons:** AI-specific actions (✨ Reformulate, View Connection)
|
||||
|
||||
**Visual Design:**
|
||||
|
||||
| Button Type | Tailwind Classes | Usage | Example |
|
||||
|-------------|------------------|-------|---------|
|
||||
| Primary | `bg-purple-600 hover:bg-purple-700 text-white font-medium py-2 px-4 rounded-lg` | Main action, high emphasis | "Save Note", "Apply Suggestion" |
|
||||
| Secondary | `bg-gray-100 hover:bg-gray-200 text-gray-700 font-medium py-2 px-4 rounded-lg` | Alternative action | "Cancel", "Keep Original" |
|
||||
| Tertiary | `text-gray-500 hover:text-gray-700 font-medium py-2 px-2` | Low emphasis, text-only | "Dismiss", "Skip" |
|
||||
| AI Action | `bg-purple-50 hover:bg-purple-100 text-purple-600 font-medium py-2 px-4 rounded-lg border border-purple-200` | AI-specific action | "✨ Reformulate", "View Connection" |
|
||||
| Success | `bg-green-600 hover:bg-green-700 text-white font-medium py-2 px-4 rounded-lg` | Positive confirmation | "Link Notes", "Accept" |
|
||||
| Destructive | `bg-red-600 hover:bg-red-700 text-white font-medium py-2 px-4 rounded-lg` | Destructive action | "Delete Note", "Remove" |
|
||||
|
||||
**Behavior:**
|
||||
- **Focus:** 2px purple outline (`focus-visible:ring-2 ring-purple-600`)
|
||||
- **Active:** Slightly darker shade (`active:scale-95`)
|
||||
- **Disabled:** `opacity-50 cursor-not-allowed` with `aria-disabled="true"`
|
||||
- **Loading:** Show spinner, disable button, preserve width
|
||||
|
||||
**Accessibility:**
|
||||
- Minimum touch target: 44×44px (WCAG 2.5.5)
|
||||
- Clear visual labels (no icon-only buttons without labels)
|
||||
- Keyboard: Enter/Space to activate
|
||||
- Focus indicators always visible
|
||||
|
||||
**Mobile Considerations:**
|
||||
- Full-width buttons on mobile for primary actions
|
||||
- Minimum 44px height for touch targets
|
||||
- Adequate spacing between buttons (8px minimum)
|
||||
|
||||
---
|
||||
|
||||
### Feedback Patterns
|
||||
|
||||
**When to Use:**
|
||||
- **Success Feedback:** Actions completed successfully (Note saved, Suggestion applied)
|
||||
- **Error Feedback:** Actions failed (AI unavailable, Connection error)
|
||||
- **Warning Feedback:** Caution needed (Last Cahier, AI limit reached)
|
||||
- **Info Feedback:** Neutral information (AI processing, Feature discovery)
|
||||
|
||||
**Visual Design:**
|
||||
|
||||
**Success Feedback:**
|
||||
```tsx
|
||||
// Toast notification
|
||||
<div className="bg-green-50 border-l-4 border-green-600 text-green-800 p-4 rounded-lg shadow-md">
|
||||
<div className="flex items-center gap-3">
|
||||
<span className="text-green-600">✅</span>
|
||||
<p className="font-medium">Note saved successfully</p>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
**Error Feedback:**
|
||||
```tsx
|
||||
// Toast notification
|
||||
<div className="bg-red-50 border-l-4 border-red-600 text-red-800 p-4 rounded-lg shadow-md">
|
||||
<div className="flex items-center gap-3">
|
||||
<span className="text-red-600">❌</span>
|
||||
<p className="font-medium">AI service unavailable. Please try again.</p>
|
||||
</div>
|
||||
<button className="mt-2 text-sm underline">Retry</button>
|
||||
</div>
|
||||
```
|
||||
|
||||
**Warning Feedback:**
|
||||
```tsx
|
||||
// Modal or banner
|
||||
<div className="bg-amber-50 border-l-4 border-amber-600 text-amber-800 p-4 rounded-lg">
|
||||
<div className="flex items-center gap-3">
|
||||
<span className="text-amber-600">⚠️</span>
|
||||
<p className="font-medium">You've reached your daily AI limit</p>
|
||||
</div>
|
||||
<p className="text-sm mt-1">Upgrade to Pro for unlimited AI features.</p>
|
||||
</div>
|
||||
```
|
||||
|
||||
**Info Feedback (AI Processing):**
|
||||
```tsx
|
||||
// Inline indicator
|
||||
<div className="flex items-center gap-2 text-gray-600">
|
||||
<div className="animate-spin w-4 h-4 border-2 border-amber-500 border-t-transparent rounded-full" />
|
||||
<span className="text-sm">AI thinking...</span>
|
||||
</div>
|
||||
```
|
||||
|
||||
**Behavior:**
|
||||
- **Auto-dismiss:** Success/info toasts auto-dismiss after 5s
|
||||
- **Persistent:** Error/warning toasts require manual dismissal
|
||||
- **Position:** Toasts bottom-right (desktop), bottom-center (mobile)
|
||||
- **Stacking:** Multiple toasts stack vertically with 4px gap
|
||||
|
||||
**Accessibility:**
|
||||
- `role="alert"` for errors/warnings
|
||||
- `role="status"` for success/info
|
||||
- `aria-live="polite"` for non-critical, `aria-live="assertive"` for critical
|
||||
- Screen reader announcements with clear messages
|
||||
|
||||
---
|
||||
|
||||
### Form & Input Patterns
|
||||
|
||||
**When to Use:**
|
||||
- Note editor (main content input)
|
||||
- Title input (with AI suggestions)
|
||||
- Cahier name input
|
||||
- Search bar (unified semantic search)
|
||||
- Settings forms (AI configuration)
|
||||
|
||||
**Visual Design:**
|
||||
|
||||
**Text Input (Title, Cahier Name):**
|
||||
```tsx
|
||||
<input
|
||||
type="text"
|
||||
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-600 focus:border-transparent outline-none transition-all"
|
||||
placeholder="Note title..."
|
||||
/>
|
||||
```
|
||||
|
||||
**Textarea (Note Content):**
|
||||
```tsx
|
||||
<textarea
|
||||
className="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-600 focus:border-transparent outline-none transition-all min-h-[200px] resize-y"
|
||||
placeholder="Start typing..."
|
||||
/>
|
||||
```
|
||||
|
||||
**Search Input (Unified):**
|
||||
```tsx
|
||||
<div className="relative">
|
||||
<input
|
||||
type="search"
|
||||
className="w-full pl-10 pr-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-600 focus:border-transparent outline-none transition-all"
|
||||
placeholder="Search notes..."
|
||||
/>
|
||||
<span className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400">🔍</span>
|
||||
</div>
|
||||
```
|
||||
|
||||
**Behavior:**
|
||||
- **Focus:** Purple ring (`focus:ring-2 focus:ring-purple-600`)
|
||||
- **Error state:** Red border + error message below
|
||||
- **Success state:** Green border (briefly, then normal)
|
||||
- **AI Suggestions:** Show dropdown below input (TitleSuggestionsDropdown)
|
||||
- **Debounce:** Search input debounces 300ms before triggering
|
||||
|
||||
**Validation Patterns:**
|
||||
|
||||
| Field | Validation | Error Message |
|
||||
|-------|-----------|---------------|
|
||||
| Cahier Name | Required, min 2 chars | "Cahier name must be at least 2 characters" |
|
||||
| Title | Optional (AI suggests if empty) | - |
|
||||
| Search | Min 2 chars to trigger | "Enter at least 2 characters to search" |
|
||||
|
||||
**Accessibility:**
|
||||
- `aria-label` or `aria-labelledby` for all inputs
|
||||
- `aria-describedby` for help text/error messages
|
||||
- `aria-invalid="true"` for validation errors
|
||||
- Keyboard navigation: Tab to focus, Enter to submit
|
||||
|
||||
---
|
||||
|
||||
### Navigation Patterns
|
||||
|
||||
**When to Use:**
|
||||
- Cahier switching (sidebar navigation)
|
||||
- Breadcrumb navigation (header)
|
||||
- Tab navigation (settings sections)
|
||||
- Pagination (masonry grid infinite scroll)
|
||||
|
||||
**Visual Design:**
|
||||
|
||||
**Cahier Sidebar Navigation:**
|
||||
```tsx
|
||||
<nav className="w-64 bg-white border-r border-gray-200">
|
||||
<ul className="py-4">
|
||||
<li>
|
||||
<button className="w-full flex items-center gap-3 px-4 py-2 text-left bg-purple-50 text-purple-600 border-l-4 border-purple-600 font-medium">
|
||||
📓 Inbox
|
||||
</button>
|
||||
</li>
|
||||
<li>
|
||||
<button className="w-full flex items-center gap-3 px-4 py-2 text-left text-gray-700 hover:bg-gray-50">
|
||||
📓 Work
|
||||
</button>
|
||||
</li>
|
||||
<li>
|
||||
<button className="w-full flex items-center gap-3 px-4 py-2 text-left text-gray-700 hover:bg-gray-50">
|
||||
📓 Personal
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
```
|
||||
|
||||
**Active State:**
|
||||
- Background: `bg-purple-50`
|
||||
- Text: `text-purple-600`
|
||||
- Left border: `border-l-4 border-purple-600`
|
||||
- Font weight: `font-medium`
|
||||
|
||||
**Hover State (Inactive):**
|
||||
- Background: `hover:bg-gray-50`
|
||||
- Text: `text-gray-700`
|
||||
- No border
|
||||
|
||||
**Breadcrumb Navigation (Header):**
|
||||
```tsx
|
||||
<nav className="flex items-center gap-2 text-sm text-gray-600">
|
||||
<span className="hover:text-purple-600 cursor-pointer">Memento</span>
|
||||
<span>/</span>
|
||||
<span className="hover:text-purple-600 cursor-pointer">Work</span>
|
||||
<span>/</span>
|
||||
<span className="text-gray-900 font-medium">React Performance Tips</span>
|
||||
</nav>
|
||||
```
|
||||
|
||||
**Behavior:**
|
||||
- **Instant switch:** Cahier switching happens < 100ms (no page reload)
|
||||
- **Active indicator:** Current Cahier highlighted with purple left border
|
||||
- **Keyboard navigation:** ↑↓ to navigate Cahiers, Enter to select
|
||||
- **Mobile:** Hamburger menu (sidebar collapses to off-canvas)
|
||||
|
||||
**Accessibility:**
|
||||
- `role="navigation"` with `aria-label="Cahiers navigation"`
|
||||
- `aria-current="page"` for active Cahier
|
||||
- Keyboard focus visible (2px purple outline)
|
||||
- Screen reader announces Cahier names
|
||||
|
||||
---
|
||||
|
||||
### Modal & Overlay Patterns
|
||||
|
||||
**When to Use:**
|
||||
- Reformulation modal (compare original vs AI suggestion)
|
||||
- Memory Echo details modal (view 2-note connection)
|
||||
- Settings modals (AI configuration)
|
||||
- Confirmation dialogs (delete Cahier)
|
||||
|
||||
**Visual Design:**
|
||||
|
||||
**Modal Container:**
|
||||
```tsx
|
||||
<div className="fixed inset-0 z-50 flex items-center justify-center">
|
||||
{/* Backdrop */}
|
||||
<div className="absolute inset-0 bg-black/50 backdrop-blur-sm" />
|
||||
|
||||
{/* Modal */}
|
||||
<div className="relative bg-white rounded-xl shadow-2xl max-w-4xl w-full mx-4 border-2 border-purple-600">
|
||||
{/* Header */}
|
||||
<div className="flex items-center justify-between p-6 border-b border-gray-200">
|
||||
<h2 className="text-2xl font-semibold text-gray-900">✨ Reformulate this Paragraph</h2>
|
||||
<button className="text-gray-400 hover:text-gray-600">✕</button>
|
||||
</div>
|
||||
|
||||
{/* Body */}
|
||||
<div className="p-6">
|
||||
{/* Modal content */}
|
||||
</div>
|
||||
|
||||
{/* Footer */}
|
||||
<div className="flex justify-end gap-3 p-6 border-t border-gray-200">
|
||||
<button>Keep Original</button>
|
||||
<button>Apply Suggestion</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
**Behavior:**
|
||||
- **Opening:** Fade-in backdrop + scale modal (0.2s ease-out)
|
||||
- **Closing:** Fade-out backdrop + scale down (0.1s)
|
||||
- **Focus trap:** Tab stays within modal when open
|
||||
- **ESC to close:** Pressing ESC closes modal
|
||||
- **Click outside:** Clicking backdrop closes modal (optional for confirmation dialogs)
|
||||
|
||||
**Accessibility:**
|
||||
- `role="dialog"` with `aria-modal="true"`
|
||||
- `aria-labelledby` points to modal title
|
||||
- Focus trap (first focusable element receives focus on open)
|
||||
- Returns focus to trigger element on close
|
||||
|
||||
**Mobile Considerations:**
|
||||
- Full-width modals on mobile (mx-0, max-h-screen)
|
||||
- Bottom sheet style for some modals (slide-up from bottom)
|
||||
- Touch-friendly button sizes (min 44px)
|
||||
|
||||
---
|
||||
|
||||
### Search Patterns
|
||||
|
||||
**When to Use:**
|
||||
- Unified semantic search (header search bar)
|
||||
- Cahier-specific search (filtered by current Cahier)
|
||||
- AI-powered semantic matching
|
||||
|
||||
**Visual Design:**
|
||||
|
||||
**Unified Search Bar:**
|
||||
```tsx
|
||||
<div className="relative">
|
||||
<input
|
||||
type="search"
|
||||
className="w-full pl-10 pr-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-600 focus:border-transparent outline-none transition-all"
|
||||
placeholder="Search notes..."
|
||||
value={searchQuery}
|
||||
onChange={(e) => setSearchQuery(e.target.value)}
|
||||
/>
|
||||
<span className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400">🔍</span>
|
||||
|
||||
{/* Loading indicator */}
|
||||
{isSearching && (
|
||||
<div className="absolute right-3 top-1/2 -translate-y-1/2">
|
||||
<div className="animate-spin w-4 h-4 border-2 border-purple-600 border-t-transparent rounded-full" />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
```
|
||||
|
||||
**Search Results with Semantic Badges:**
|
||||
```tsx
|
||||
<div className="space-y-4">
|
||||
{/* Keyword match result */}
|
||||
<div className="p-4 bg-white border border-gray-200 rounded-lg hover:shadow-md transition-shadow">
|
||||
<h3 className="font-semibold text-gray-900">React State Management</h3>
|
||||
</div>
|
||||
|
||||
{/* Semantic match result */}
|
||||
<div className="p-4 bg-white border border-gray-200 rounded-lg hover:shadow-md transition-shadow">
|
||||
<h3 className="font-semibold text-gray-900">Next.js Optimization</h3>
|
||||
<div className="mt-2">
|
||||
<span className="inline-flex items-center gap-1 px-2 py-1 bg-blue-50 text-blue-600 text-xs font-medium rounded">
|
||||
🎯 Semantic Match (Score: 0.82)
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
**Behavior:**
|
||||
- **Debounce:** 300ms debounce before triggering search
|
||||
- **Hybrid search:** Simultaneously runs keyword + semantic search
|
||||
- **Badge indication:** Semantic matches show blue badge with score
|
||||
- **Real-time:** Results update as user types (after debounce)
|
||||
- **No visible toggle:** Users don't choose keyword vs semantic - "it just works"
|
||||
|
||||
**Accessibility:**
|
||||
- `aria-label="Search notes"`
|
||||
- Live region for results: `aria-live="polite"` on results container
|
||||
- Clear announcements: "5 results found, 3 semantic matches"
|
||||
- Keyboard: Enter to navigate to first result
|
||||
|
||||
---
|
||||
|
||||
### Loading & Empty States
|
||||
|
||||
**When to Use:**
|
||||
- AI processing (generating embeddings, reformulating)
|
||||
- Empty Cahiers (no notes yet)
|
||||
- No search results
|
||||
- Loading initial data
|
||||
|
||||
**Visual Design:**
|
||||
|
||||
**AI Processing State:**
|
||||
```tsx
|
||||
<div className="flex flex-col items-center justify-center py-12">
|
||||
<div className="animate-spin w-12 h-12 border-4 border-amber-500 border-t-transparent rounded-full mb-4" />
|
||||
<p className="text-gray-600 font-medium">AI thinking...</p>
|
||||
<p className="text-sm text-gray-500 mt-1">Generating embeddings for semantic search</p>
|
||||
</div>
|
||||
```
|
||||
|
||||
**Empty Cahier State:**
|
||||
```tsx
|
||||
<div className="flex flex-col items-center justify-center py-16 text-center">
|
||||
<div className="text-6xl mb-4">📓</div>
|
||||
<h3 className="text-xl font-semibold text-gray-900 mb-2">No notes in this Cahier yet</h3>
|
||||
<p className="text-gray-600 mb-6">Capture your first idea to get started</p>
|
||||
<button className="bg-purple-600 hover:bg-purple-700 text-white font-medium py-2 px-6 rounded-lg">
|
||||
Create Note
|
||||
</button>
|
||||
</div>
|
||||
```
|
||||
|
||||
**No Search Results:**
|
||||
```tsx
|
||||
<div className="flex flex-col items-center justify-center py-12 text-center">
|
||||
<div className="text-4xl mb-4">🔍</div>
|
||||
<h3 className="text-lg font-semibold text-gray-900 mb-2">No results found</h3>
|
||||
<p className="text-gray-600">Try different keywords or check your spelling</p>
|
||||
</div>
|
||||
```
|
||||
|
||||
**Skeleton Loading (Masonry Grid):**
|
||||
```tsx
|
||||
<div className="grid grid-cols-3 gap-4">
|
||||
{[1, 2, 3, 4, 5, 6].map((i) => (
|
||||
<div key={i} className="h-48 bg-gray-200 rounded-lg animate-pulse" />
|
||||
))}
|
||||
</div>
|
||||
```
|
||||
|
||||
**Behavior:**
|
||||
- **AI Processing:** Show spinner + descriptive text (not just "Loading...")
|
||||
- **Empty States:** Provide clear CTA (Create Note, Browse Other Cahiers)
|
||||
- **Skeleton:** Pulse animation while loading actual content
|
||||
- **Progressive enhancement:** Show content as it loads (not all-or-nothing)
|
||||
|
||||
**Accessibility:**
|
||||
- `role="status"` with `aria-live="polite"` for loading states
|
||||
- `aria-busy="true"` when content is loading
|
||||
- Screen readers announce what's happening and why
|
||||
- Empty states have clear headings and explanations
|
||||
|
||||
---
|
||||
|
||||
### Mobile-Specific Patterns
|
||||
|
||||
**When to Use:**
|
||||
- Responsive navigation (collapsible sidebar)
|
||||
- Touch interactions (swipe, long-press)
|
||||
- Mobile-optimized modals (bottom sheets)
|
||||
- Mobile search (expandable search bar)
|
||||
|
||||
**Visual Design:**
|
||||
|
||||
**Collapsible Sidebar (Mobile):**
|
||||
```tsx
|
||||
{/* Desktop: Always visible sidebar */}
|
||||
{/* Mobile: Hamburger menu */}
|
||||
<div className="md:hidden fixed top-4 left-4 z-50">
|
||||
<button className="p-2 bg-white rounded-lg shadow-md">
|
||||
☰
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Off-canvas sidebar on mobile */}
|
||||
<div className={`fixed inset-y-0 left-0 z-50 w-64 bg-white transform transition-transform ${isOpen ? 'translate-x-0' : '-translate-x-full'} md:translate-x-0`}>
|
||||
{/* Sidebar content */}
|
||||
</div>
|
||||
```
|
||||
|
||||
**Bottom Sheet Modal (Mobile):**
|
||||
```tsx
|
||||
<div className="md:hidden fixed inset-x-0 bottom-0 bg-white rounded-t-2xl shadow-2xl transform transition-transform">
|
||||
<div className="p-6">
|
||||
{/* Modal content */}
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
**Expandable Search (Mobile):**
|
||||
```tsx
|
||||
<div className="relative">
|
||||
<button className="p-2">
|
||||
🔍
|
||||
</button>
|
||||
|
||||
{/* Expands to full-width input on focus/click */}
|
||||
<input
|
||||
type="search"
|
||||
className="fixed inset-x-4 top-16 z-40 px-4 py-3 bg-white border border-gray-300 rounded-lg shadow-lg"
|
||||
placeholder="Search notes..."
|
||||
/>
|
||||
</div>
|
||||
```
|
||||
|
||||
**Touch Interactions:**
|
||||
- **Minimum touch target:** 44×44px (WCAG 2.5.5)
|
||||
- **Swipe to dismiss:** Toast notifications, bottom sheets
|
||||
- **Long-press:** Context menus (show actions on note card)
|
||||
- **Pull-to-refresh:** Refresh masonry grid content
|
||||
|
||||
---
|
||||
|
||||
### Pattern Integration with Radix UI
|
||||
|
||||
**Consistency with Design System:**
|
||||
|
||||
| Pattern Category | Radix Primitive | Custom Styling | Notes |
|
||||
|------------------|-----------------|----------------|-------|
|
||||
| Modals | Dialog | Purple border, AI-specific padding | BaseModal extends Dialog |
|
||||
| Dropdowns | Dropdown Menu | Purple text on hover | Used for TitleSuggestions |
|
||||
| Toasts | Toast | Purple border for AI | AIToast extends Toast |
|
||||
| Navigation | Navigation Menu | Active state = purple left border | Cahiers sidebar |
|
||||
| Forms | - | Custom inputs with purple focus ring | No Radix form primitive |
|
||||
|
||||
**Design Token Integration:**
|
||||
|
||||
```css
|
||||
/* All patterns use consistent design tokens */
|
||||
--primary: #8B5CF6; /* Primary actions, focus rings */
|
||||
--ai-accent: #3B82F6; /* Semantic search badges */
|
||||
--ai-connection: #8B5CF6; /* Memory Echo borders */
|
||||
--success: #10B981; /* Success feedback */
|
||||
--warning: #F59E0B; /* Processing states */
|
||||
--error: #EF4444; /* Error feedback */
|
||||
```
|
||||
|
||||
**Custom Pattern Rules:**
|
||||
|
||||
1. **AI-specific patterns always use purple/blue accent colors**
|
||||
2. **All buttons have 2px purple focus ring** (keyboard navigation)
|
||||
3. **All modals have purple border** (2px solid #8B5CF6)
|
||||
4. **All toasts auto-dismiss after 5s** except errors (manual dismiss)
|
||||
5. **All inputs use purple focus ring** (not default blue)
|
||||
6. **All empty states provide clear CTA** (not just "No results")
|
||||
7. **All loading states show descriptive text** (not just spinners)
|
||||
|
||||
---
|
||||
|
||||
## Responsive Design & Accessibility
|
||||
|
||||
### Responsive Strategy
|
||||
|
||||
**Desktop Strategy (1024px+):**
|
||||
|
||||
- **Layout optimisé:** Sidebar Cahiers (256px) + Masonry grid (3-4 colonnes)
|
||||
- **Espace maximal:** Profiter de l'écran pour afficher plus de notes
|
||||
- **Features desktop:**
|
||||
- Cahier sidebar toujours visible (pas de hamburger)
|
||||
- Masonry grid 4 colonnes (plus de notes visibles)
|
||||
- Memory Echo toast en bas à droite
|
||||
- Hover interactions (✨ Reformulate apparaît au survol)
|
||||
- Drag & drop pour réorganiser les Cahiers (bonus, pas MVP)
|
||||
|
||||
**Tablet Strategy (768px - 1023px):**
|
||||
|
||||
- **Layout adapté:** Sidebar Cahiers réduit (200px) ou collapsible
|
||||
- **Masonry 2 colonnes:** Grid passe de 4 → 2 colonnes
|
||||
- **Touch optimization:**
|
||||
- Cahier sidebar devient collapsible (hamburger menu)
|
||||
- Boutons plus larges (min 44px)
|
||||
- Pas de hover-based interactions (✨ Reformulate bouton permanent)
|
||||
- **Information density:** Moyenne - équilibre entre lisibilité et contenu
|
||||
|
||||
**Mobile Strategy (< 768px):**
|
||||
|
||||
- **Layout simplifié:** Single-column stack
|
||||
- **Navigation:** Hamburger menu (sidebar off-canvas)
|
||||
- **Masonry 1 colonne:** Single column, full-width cards
|
||||
- **Features mobiles:**
|
||||
- Cahier sidebar: Off-canvas (glisse de gauche)
|
||||
- Search: Expandable (icône → input full-width)
|
||||
- Memory Echo: Full-width toast en bas
|
||||
- AI Badge: Compact (✨ icône seule, tap pour menu)
|
||||
- Bottom sheet modals (au lieu de dialogues centrés)
|
||||
- **Critical info only:** Masquer les éléments non-essentiels
|
||||
|
||||
---
|
||||
|
||||
### Breakpoint Strategy
|
||||
|
||||
**Using Tailwind CSS Standard Breakpoints:**
|
||||
|
||||
```javascript
|
||||
// tailwind.config.js
|
||||
module.exports = {
|
||||
theme: {
|
||||
screens: {
|
||||
'sm': '640px', // Mobile large (landscape)
|
||||
'md': '768px', // Tablet portrait
|
||||
'lg': '1024px', // Desktop, laptop
|
||||
'xl': '1280px', // Desktop large
|
||||
'2xl': '1536px', // Extra large desktop
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Layout Adaptations by Breakpoint:**
|
||||
|
||||
| Element | Mobile (< 768px) | Tablet (768-1024px) | Desktop (> 1024px) |
|
||||
|---------|------------------|---------------------|---------------------|
|
||||
| Cahier Sidebar | Off-canvas (hamburger) | 200px or collapsible | 256px always visible |
|
||||
| Masonry Grid | 1 colonne (100%) | 2 colonnes (48% each) | 3-4 colonnes (32-24% each) |
|
||||
| Header | Compact (64px) | Standard (64px) | Standard (64px) |
|
||||
| Search Bar | Expandable on tap | Full-width (standard) | Full-width (standard) |
|
||||
| Memory Echo | Bottom-center toast | Bottom-right toast | Bottom-right toast |
|
||||
| Modals | Bottom sheet | Standard dialog | Standard dialog |
|
||||
|
||||
**Mobile-First Approach:**
|
||||
|
||||
- **Développement:** Commencer par le layout mobile, ajouter des médias queries pour écrans plus larges
|
||||
- **Avantages:** Performance native mobile, progressive enhancement
|
||||
- **Implementation:**
|
||||
```css
|
||||
/* Mobile default: 1 colonne */
|
||||
.masonry-grid { display: grid; grid-template-columns: 1fr; }
|
||||
|
||||
/* Tablet: 2 colonnes */
|
||||
@media (min-width: 768px) {
|
||||
.masonry-grid { grid-template-columns: repeat(2, 1fr); }
|
||||
}
|
||||
|
||||
/* Desktop: 3-4 colonnes */
|
||||
@media (min-width: 1024px) {
|
||||
.masonry-grid { grid-template-columns: repeat(3, 1fr); }
|
||||
}
|
||||
@media (min-width: 1280px) {
|
||||
.masonry-grid { grid-template-columns: repeat(4, 1fr); }
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Accessibility Strategy
|
||||
|
||||
**WCAG Compliance Level: AA (Recommended)**
|
||||
|
||||
**Rationale:**
|
||||
- ✅ **Industry standard:** Niveau attendu pour les applications web modernes
|
||||
- ✅ **Legal compliance:** Conforme aux exigences légales (ADA, European Accessibility Act)
|
||||
- ✅ **User experience:** Balance optimal entre accessibilité et design
|
||||
- ✅ **Feasible:** Atteignable sans compromis majeurs sur le design
|
||||
|
||||
**Key Accessibility Requirements:**
|
||||
|
||||
**1. Color Contrast (WCAG 2.1 Level AA):**
|
||||
- Normal text (16px+): Minimum 4.5:1 contrast ratio
|
||||
- Large text (18px+): Minimum 3:1 contrast ratio
|
||||
- UI components (buttons, borders): Minimum 3:1 contrast ratio
|
||||
|
||||
**Implementation:**
|
||||
- Purple primary (#8B5CF6) on white: 4.8:1 ✅
|
||||
- Blue accent (#3B82F6) on white: 4.5:1 ✅
|
||||
- Green success (#10B981) on white: 3.9:1 ✅ (OK for large text)
|
||||
- Gray text (#6B7280) on white: 4.6:1 ✅
|
||||
|
||||
**2. Keyboard Navigation:**
|
||||
- **Full keyboard support:** Tab, Shift+Tab, Enter, Escape, Arrow keys
|
||||
- **Focus indicators:** 2px purple outline (focus-visible:ring-2 ring-purple-600)
|
||||
- **Skip links:** "Skip to main content" link au début de la page
|
||||
- **Focus order:** Logique et prévisible (header → sidebar → main content → footer)
|
||||
- **No keyboard traps:** ESC ferme tous les modals/toasts
|
||||
|
||||
**3. Screen Reader Support:**
|
||||
- **Semantic HTML:** heading hierarchy (h1 → h2 → h3), proper list structures
|
||||
- **ARIA labels:** Labels descriptifs pour tous les composants interactifs
|
||||
- **Live regions:** `aria-live="polite"` pour toasts et mises à jour dynamiques
|
||||
- **Screen reader testing:** NVDA (Windows), VoiceOver (macOS), TalkBack (Android)
|
||||
|
||||
**4. Touch Target Sizes (WCAG 2.5.5):**
|
||||
- Minimum 44×44px pour tous les éléments interactifs
|
||||
- Espacement minimum 8px entre les éléments tactiles
|
||||
- Tests sur appareils mobiles réels (iOS, Android)
|
||||
|
||||
**5. Focus Management:**
|
||||
- **Focus trap:** Dans les modals (Tab ne quitte pas le modal)
|
||||
- **Focus restoration:** Retour au trigger element après fermeture modal
|
||||
- **Visible focus:** Toujours visible (pas de outline: none sauf :focus-visible)
|
||||
|
||||
**6. Accessibility Features for AI Components:**
|
||||
- **AIToast:** `role="alert"` + `aria-live="polite"`
|
||||
- **TitleSuggestions:** `role="listbox"` + `aria-label="AI-generated title suggestions"`
|
||||
- **MemoryEchoCard:** `aria-label="AI notification: Note connection discovered"`
|
||||
- **ProcessingIndicator:** `role="status"` + `aria-busy="true"`
|
||||
|
||||
---
|
||||
|
||||
### Testing Strategy
|
||||
|
||||
**Responsive Testing:**
|
||||
|
||||
**Device Testing:**
|
||||
- **Real devices:**
|
||||
- iPhone 12/13/14 (375px width)
|
||||
- Samsung Galaxy S21 (360px width)
|
||||
- iPad (768px - 1024px)
|
||||
- Desktop (1920px width)
|
||||
- **Browser testing:**
|
||||
- Chrome (primary)
|
||||
- Safari (iOS, macOS)
|
||||
- Firefox (secondary)
|
||||
- Edge (Windows)
|
||||
|
||||
**Network Performance Testing:**
|
||||
- Test sur 3G (slow network)
|
||||
- Test sur WiFi (normal network)
|
||||
- Optimiser images (WebP, lazy loading)
|
||||
- Minifier CSS/JS pour performance mobile
|
||||
|
||||
**Accessibility Testing:**
|
||||
|
||||
**Automated Tools:**
|
||||
- **axe DevTools** (Chrome extension) - Scan automatique
|
||||
- **WAVE** (WebAIM) - Contrast checker, ARIA validation
|
||||
- **Lighthouse** (Chrome) - Accessibility score
|
||||
|
||||
**Manual Testing:**
|
||||
- **Keyboard navigation:** Navigation clavier complète
|
||||
- **Screen reader:** NVDA, VoiceOver, TalkBack
|
||||
- **Zoom:** Test 200% text zoom (pas de horizontal scroll)
|
||||
- **High contrast mode:** Windows High Contrast Mode
|
||||
|
||||
**User Testing:**
|
||||
- **Include users with disabilities:**
|
||||
- Screen reader users
|
||||
- Low vision users
|
||||
- Motor disability users (keyboard-only)
|
||||
- **Test with real assistive technologies**
|
||||
- **Gather feedback on AI features accessibility**
|
||||
|
||||
---
|
||||
|
||||
### Implementation Guidelines
|
||||
|
||||
**Responsive Development:**
|
||||
|
||||
**1. Use Relative Units:**
|
||||
```css
|
||||
/* ✅ GOOD - Relative units */
|
||||
font-size: 1rem; /* 16px base */
|
||||
padding: 1rem; /* 16px */
|
||||
margin: 0.5rem 0; /* 8px top/bottom, 0 sides */
|
||||
width: 100%; /* Full width */
|
||||
max-width: 1200px; /* Max constraint */
|
||||
|
||||
/* ❌ BAD - Fixed pixels */
|
||||
font-size: 16px; /* Not scalable */
|
||||
padding: 16px;
|
||||
width: 375px; /* Mobile fixed width */
|
||||
```
|
||||
|
||||
**2. Mobile-First Media Queries:**
|
||||
```css
|
||||
/* Mobile default */
|
||||
.masonry-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
/* Tablet+ */
|
||||
@media (min-width: 768px) {
|
||||
.masonry-grid {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
}
|
||||
|
||||
/* Desktop+ */
|
||||
@media (min-width: 1024px) {
|
||||
.masonry-grid {
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**3. Touch Target Testing:**
|
||||
```tsx
|
||||
// ✅ GOOD - Minimum 44x44px
|
||||
<button className="min-h-[44px] min-w-[44px] p-4">
|
||||
Click me
|
||||
</button>
|
||||
|
||||
// ❌ BAD - Too small
|
||||
<button className="h-8 w-8 p-1">
|
||||
Click me
|
||||
</button>
|
||||
```
|
||||
|
||||
**4. Image Optimization:**
|
||||
```tsx
|
||||
// Responsive images
|
||||
<Image
|
||||
src="/note-thumbnail.webp"
|
||||
width={400}
|
||||
height={300}
|
||||
loading="lazy" // Lazy load below fold
|
||||
alt="Note thumbnail"
|
||||
/>
|
||||
|
||||
// Background images with fallback
|
||||
<div
|
||||
style={{
|
||||
backgroundImage: 'url(/image.webp), url(/image.jpg)'
|
||||
}}
|
||||
/>
|
||||
```
|
||||
|
||||
**Accessibility Development:**
|
||||
|
||||
**1. Semantic HTML:**
|
||||
```tsx
|
||||
// ✅ GOOD - Semantic
|
||||
<header>
|
||||
<nav aria-label="Cahiers navigation">
|
||||
<ul>
|
||||
<li><a href="/inbox" aria-current="page">Inbox</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
<article>
|
||||
<h1>Note Title</h1>
|
||||
<p>Note content...</p>
|
||||
</article>
|
||||
</main>
|
||||
|
||||
// ❌ BAD - Non-semantic
|
||||
<div class="header">
|
||||
<div class="nav">
|
||||
<div class="nav-item" onclick="navigate('/inbox')">Inbox</div>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
**2. ARIA Labels and Roles:**
|
||||
```tsx
|
||||
// AIToast component
|
||||
<div
|
||||
role="alert"
|
||||
aria-live="polite"
|
||||
aria-label="AI notification: Note connection discovered"
|
||||
>
|
||||
<div className="flex items-center gap-3">
|
||||
<span aria-hidden="true">💡</span>
|
||||
<h3>I noticed something...</h3>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
// TitleSuggestionsDropdown
|
||||
<ul role="listbox" aria-label="AI-generated title suggestions">
|
||||
<li role="option">✨ Title 1</li>
|
||||
<li role="option">✨ Title 2</li>
|
||||
<li role="option">✨ Title 3</li>
|
||||
</ul>
|
||||
```
|
||||
|
||||
**3. Keyboard Navigation:**
|
||||
```tsx
|
||||
// Focus trap in modal
|
||||
const Modal = () => {
|
||||
useEffect(() => {
|
||||
// Trap focus within modal
|
||||
const focusableElements = modalRef.current.querySelectorAll(
|
||||
'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
|
||||
);
|
||||
const firstElement = focusableElements[0];
|
||||
const lastElement = focusableElements[focusableElements.length - 1];
|
||||
|
||||
const handleTab = (e) => {
|
||||
if (e.key === 'Tab') {
|
||||
if (e.shiftKey) {
|
||||
if (document.activeElement === firstElement) {
|
||||
e.preventDefault();
|
||||
lastElement.focus();
|
||||
}
|
||||
} else {
|
||||
if (document.activeElement === lastElement) {
|
||||
e.preventDefault();
|
||||
firstElement.focus();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
document.addEventListener('keydown', handleTab);
|
||||
return () => document.removeEventListener('keydown', handleTab);
|
||||
}, []);
|
||||
|
||||
// Modal JSX...
|
||||
};
|
||||
```
|
||||
|
||||
**4. Focus Management:**
|
||||
```tsx
|
||||
// Skip link (top of page)
|
||||
<a
|
||||
href="#main-content"
|
||||
className="sr-only focus:not-sr-only focus:absolute focus:top-4 focus:left-4 bg-purple-600 text-white px-4 py-2 rounded-lg"
|
||||
>
|
||||
Skip to main content
|
||||
</a>
|
||||
|
||||
<main id="main-content" tabIndex={-1}>
|
||||
{/* Main content */}
|
||||
</main>
|
||||
```
|
||||
|
||||
**5. High Contrast Mode Support:**
|
||||
```css
|
||||
/* Respect high contrast mode preference */
|
||||
@media (prefers-contrast: high) {
|
||||
.ai-button {
|
||||
border: 2px solid currentColor;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.note-card {
|
||||
border: 2px solid currentColor;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Component Library Resources
|
||||
|
||||
**Alternative UI Component Libraries (Built on Radix UI + Tailwind):**
|
||||
|
||||
These libraries are compatible with Memento's design system choice (Radix UI + Tailwind CSS):
|
||||
|
||||
1. **Aceternity UI** - https://ui.aceternity.com/components
|
||||
- Modern components built with Radix UI + Tailwind
|
||||
- Animated components, dark mode support
|
||||
- Useful for: Advanced animations, bento grids, particles
|
||||
|
||||
2. **Origin UI** - https://www.originui-ng.com/
|
||||
- Next.js components with Framer Motion animations
|
||||
- shadcn/ui-based with enhanced styling
|
||||
- Useful for: Animated cards, transitions, hero sections
|
||||
|
||||
3. **Magic UI** - https://magicui.design/docs/components
|
||||
- Creative components with unique animations
|
||||
- Built with Radix UI + Tailwind + Framer Motion
|
||||
- Useful for: Special effects, interactive components
|
||||
|
||||
**Recommendation:**
|
||||
- **Base:** Stick with Radix UI primitives (current choice)
|
||||
- **Enhancement:** These libraries can provide inspiration or pre-built components for specific features
|
||||
- **Customization:** All components can be customized to match Memento's design tokens (purple/blue AI colors)
|
||||
|
||||
**Integration Strategy:**
|
||||
1. Start with Radix UI primitives (as planned)
|
||||
2. Reference these libraries for component patterns and animation ideas
|
||||
3. Customize any imported components to use Memento's design tokens
|
||||
4. Maintain consistency with established UX patterns from Step 12
|
||||
|
||||
---
|
||||
|
||||
Reference in New Issue
Block a user