# Epic 12: Mobile Experience Overhaul Status: ready-for-dev ## Epic Overview **Epic Goal:** Transform Keep's interface into a truly mobile-first experience while keeping the desktop interface unchanged. **User Pain Points:** - Interface overflows device screen (Galaxy S22 Ultra) - Note cards too complex and large for mobile - Masonry grid layout not suitable for small screens - Too much visual information on mobile - No mobile-specific UX patterns **Success Criteria:** - ✅ No horizontal/vertical overflow on any mobile device - ✅ Simplified note cards optimized for mobile viewing - ✅ Mobile-first layouts that adapt to screen size - ✅ Smooth 60fps animations on mobile - ✅ Touch-friendly interactions (44x44px min targets) - ✅ Desktop interface completely unchanged - ✅ Tested on Galaxy S22 Ultra and various mobile devices --- ## Story 12.1: Mobile Note Cards Simplification **Status:** ready-for-dev ## Story As a **mobile user**, I want **simple, compact note cards**, so that **I can see more notes and scan the interface quickly**. ## Acceptance Criteria 1. **Given** a user is viewing notes on a mobile device (< 768px), 2. **When** notes are displayed, 3. **Then** the system should: - Display notes in a vertical list (NOT masonry grid) - Show simple card with title + 2-3 lines of preview only - Minimize badges and indicators (pin, labels, notebook) - Hide image thumbnails on mobile - Ensure touch targets are minimum 44x44px - Implement swipe-to-delete or quick actions ## Tasks / Subtasks - [ ] Create mobile variant of NoteCard component - [ ] Create `MobileNoteCard.tsx` component - [ ] Vertical card layout (not masonry) - [ ] Simplified content: title + 2-3 lines preview - [ ] Reduced badges (pin icon, label count only) - [ ] No image thumbnails on mobile - [ ] Implement mobile list layout - [ ] Replace masonry grid with simple list on mobile - [ ] 100% width cards on mobile - [ ] Adequate spacing between cards - [ ] Add mobile touch interactions - [ ] Tap to open note (full screen) - [ ] Long-press for actions menu - [ ] Swipe gestures (left/right actions) - [ ] Ensure responsive design - [ ] Mobile cards: < 768px - [ ] Desktop cards: >= 768px (UNCHANGED) - [ ] Smooth transition between breakpoints - [ ] Test on mobile devices - [ ] Galaxy S22 Ultra (main target) - [ ] iPhone SE (small screen) - [ ] Android various sizes - [ ] Portrait and landscape ## Dev Notes ### Mobile Card Design Requirements **Layout:** ``` ┌─────────────────────────────┐ │ [PIN] Title │ <- Title row with pin icon │ Preview text... │ <- 2-3 lines max │ [📎] [🏷️] • 2d ago │ <- Footer: indicators + time └─────────────────────────────┘ ``` **Typography (Mobile):** - Title: 16-18px, semibold, 1 line clamp - Preview: 14px, regular, 2-3 lines clamp - Footer text: 12px, lighter color **Spacing (Mobile):** - Card padding: 12-16px - Gap between cards: 8-12px - Touch targets: 44x44px minimum **Color & Contrast:** - Light background on cards - Good contrast for readability - Subtle hover state ### Swipe Gestures Implementation **Swipe Left → Archive** ```typescript // Use react-swipeable or similar handleArchive(note)} onSwipeRight={() => handlePin(note)} threshold={50} > ``` **Swipe Right → Pin** **Long Press → Action Menu** ### Responsive Logic ```typescript // In page.tsx const isMobile = useMediaQuery('(max-width: 768px)') {isMobile ? (
{notes.map(note => )}
) : ( // Existing desktop behavior )} ``` ### Files to Create - `keep-notes/components/mobile-note-card.tsx` - New mobile-specific component - `keep-notes/components/swipeable-wrapper.tsx` - Swipe gesture wrapper ### Files to Modify - `keep-notes/app/(main)/page.tsx` - Conditional rendering for mobile/desktop - `keep-notes/components/note-card.tsx` - No changes (keep desktop version intact) --- ## Story 12.2: Mobile-First Layout **Status:** ready-for-dev ## Story As a **mobile user**, I want **an interface optimized for my small screen**, so that **everything is accessible without zooming or horizontal scrolling**. ## Acceptance Criteria 1. **Given** a user is using the app on a mobile device, 2. **When** viewing any page, 3. **Then** the system should: - Use 100% width containers on mobile - Reduce margins/padding on mobile - Use compact header on mobile (60-80px vs 80px) - Simplified note input on mobile - Eliminate ALL horizontal overflow - Prevent double scroll (menu + page) - Maintain existing desktop layout unchanged ## Tasks / Subtasks - [ ] Create responsive container layout - [ ] Use `w-full` on mobile containers - [ ] Reduce padding on mobile (px-4 vs px-6) - [ ] Remove max-width constraints on mobile - [ ] Optimize header for mobile - [ ] Reduce header height on mobile (60px vs 80px) - [ ] Compact search bar on mobile - [ ] Hide non-essential controls on mobile - [ ] Simplify note input on mobile - [ ] Use minimal input on mobile - [ ] Placeholder text: "Add a note..." - [ ] Full FAB button for creating notes - [ ] Fix horizontal overflow issues - [ ] Use `overflow-x-hidden` on body - [ ] Ensure no fixed widths on mobile - [ ] Test on Galaxy S22 Ultra (main target) - [ ] Test on various screen sizes - [ ] Small phones: 320-375px - [ ] Medium phones: 375-428px - [ ] Large phones: 428px+ (Galaxy S22 Ultra) - [ ] Tablets: 768-1024px ## Dev Notes ### Breakpoint Strategy ```css /* Mobile First Approach */ /* Mobile: 0-767px */ .container { width: 100%; padding: 0.5rem 1rem; } /* Tablet: 768px+ */ @media (min-width: 768px) { .container { max-width: 1280px; padding: 2rem 3rem; } } ``` ### Header Optimization **Desktop (current):** - Height: 80px - Padding: px-6 lg:px-12 - Search: max-w-2xl **Mobile (new):** - Height: 60px - Padding: px-4 - Search: flex-1, shorter ### Note Input Simplification **Desktop:** Full card with title, content, options **Mobile:** ```typescript
``` ### Files to Create - `keep-notes/components/fab-button.tsx` - Floating Action Button - `keep-notes/hooks/use-media-query.ts` - Hook for responsive queries ### Files to Modify - `keep-notes/components/header.tsx` - Responsive header - `keep-notes/components/note-input.tsx` - Mobile variant - `keep-notes/app/(main)/page.tsx` - Container adjustments - `keep-notes/app/globals.css` - Responsive utilities --- ## Story 12.3: Mobile Bottom Navigation **Status:** ready-for-dev ## Story As a **mobile user**, I want **easy-to-access navigation tabs**, so that **I can quickly switch between views**. ## Acceptance Criteria 1. **Given** a user is on a mobile device, 2. **When** navigating the app, 3. **Then** the system should: - Display horizontal tabs at bottom of screen (Bottom Navigation) - Show 3-4 tabs max (Notes, Favorites, Settings) - Clearly indicate active tab - Animate transitions between tabs - NOT affect desktop interface (unchanged) ## Tasks / Subtasks - [ ] Create Bottom Navigation component - [ ] Create `MobileBottomNav.tsx` component - [ ] 3 tabs: Notes, Favorites, Settings - [ ] Icons for each tab - [ ] Active state indicator - [ ] Implement tab navigation logic - [ ] Switch between views (Notes, Favorites, Settings) - [ ] Maintain state on tab switch - [ ] Animate transitions - [ ] Style for mobile UX - [ ] Fixed position at bottom - [ ] Height: 56-64px (standard mobile nav) - [ ] Safe area padding for iPhone notch - [ ] Material Design / iOS Human Guidelines compliant - [ ] Test on mobile devices - [ ] Android (including Galaxy S22 Ultra) - [ ] iOS (iPhone SE, 14 Pro) - [ ] Different screen orientations - [ ] Ensure desktop unchanged - [ ] Only show on mobile (< 768px) - [ ] No CSS conflicts with desktop layout ## Dev Notes ### Bottom Navigation Design **Layout:** ``` ┌─────────────────────────────────┐ │ [📝 Notes] [⭐ Favs] [⚙️] │ └─────────────────────────────────┘ ^ Active (with underline/indicator) ``` **Material Design Spec:** - Height: 56px minimum - Icons: 24x24px - Labels: 12-14px (can be hidden on very small screens) - Active indicator: 4px height bar below icon **Implementation:** ```typescript // keep-notes/components/MobileBottomNav.tsx 'use client' import { Home, Star, Settings } from 'lucide-react' import Link from 'next/link' import { usePathname } from 'next/navigation' export function MobileBottomNav() { const pathname = usePathname() const tabs = [ { icon: Home, label: 'Notes', href: '/' }, { icon: Star, label: 'Favorites', href: '/favorites' }, { icon: Settings, label: 'Settings', href: '/settings' }, ] return ( ) } ``` ### Safe Area Padding For iPhone notch (notch devices): ```css padding-bottom: env(safe-area-inset-bottom, 0); ``` ### Files to Create - `keep-notes/components/mobile-bottom-nav.tsx` - Bottom navigation component ### Files to Modify - `keep-notes/app/layout.tsx` - Add bottom nav to layout - `keep-notes/app/(main)/page.tsx` - Adjust layout spacing --- ## Story 12.4: Full-Screen Mobile Note Editor **Status:** ready-for-dev ## Story As a **mobile user**, I want **to create notes in full-screen mode**, so that **I can focus on content without distractions**. ## Acceptance Criteria 1. **Given** a user is on a mobile device, 2. **When** they want to create a note, 3. **Then** the system should: - Show a Floating Action Button (FAB) to create note - Open full-screen note editor when tapped - Display title and content fields optimized for mobile - Place action buttons at bottom of screen - Animate smoothly back to list view - NOT affect desktop experience ## Tasks / Subtasks - [ ] Create Floating Action Button (FAB) - [ ] Create `fab-button.tsx` component - [ ] Fixed position: bottom-right of screen - [ ] Circle button: 56x56px - [ ] Plus icon (+) - [ ] Shadow and elevation - [ ] Ripple effect on tap - [ ] Create full-screen note editor - [ ] Create `MobileNoteEditor.tsx` component - [ ] Full viewport: `h-screen w-screen` - [ ] Title field at top - [ ] Content field takes remaining space - [ - Action buttons at bottom (Save, Cancel) - [ ] Optimize mobile keyboard handling - [ ] Auto-focus on title when opened - [ ] Keyboard-avoiding behavior - [ ] Smooth keyboard transitions - [ ] Implement save & close flow - [ ] Save note on close - [ ] Animated transition back to list - [ ] Auto-scroll to new note in list - [ ] Test on mobile devices - [ ] Galaxy S22 Ultra - [ ] iPhone - [ ] Android various sizes - [ ] Portrait and landscape ## Dev Notes ### FAB Design (Material Design) ```typescript // keep-notes/components/fab-button.tsx 'use client' import { Plus } from 'lucide-react' interface FabButtonProps { onClick: () => void } export function FabButton({ onClick }: FabButtonProps) { return ( ) } ``` **Specs:** - Size: 56x56px (standard FAB) - Elevation: 6px (shadow-lg) - Animation: 300ms - Ripple effect on tap ### Full-Screen Editor Layout ``` ┌─────────────────────────────┐ │ [X] │ <- Top bar: Close button │ Title │ <- Title input ├─────────────────────────────┤ │ │ │ Content area │ <- Takes remaining space │ (auto-expands) │ │ │ ├─────────────────────────────┤ │ [Cancel] [Save] │ <- Bottom bar: Actions └─────────────────────────────┘ ``` ### Keyboard Avoidance ```typescript import { KeyboardAvoidingView } from 'react-native' // or web equivalent // On web, use CSS: .keyboard-avoiding { padding-bottom: 200px; // Estimated keyboard height transition: padding-bottom 0.3s; } .keyboard-visible { padding-bottom: 0; } ``` ### Files to Create - `keep-notes/components/fab-button.tsx` - Floating Action Button - `keep-notes/components/mobile-note-editor.tsx` - Full-screen editor ### Files to Modify - `keep-notes/app/(main)/page.tsx` - Add FAB to mobile layout --- ## Story 12.5: Mobile Quick Actions (Swipe Gestures) **Status:** ready-for-dev ## Story As a **mobile user**, I want **quick swipe actions on notes**, so that **I can manage notes efficiently**. ## Acceptance Criteria 1. **Given** a user is viewing notes on a mobile device, 2. **When** they swipe on a note card, 3. **Then** the system should: - Swipe left: Archive the note - Swipe right: Pin the note - Long press: Show action menu - Provide haptic feedback on swipe - Show undo toast after action - NOT affect desktop (no swipe on desktop) ## Tasks / Subtasks - [ ] Implement swipe gesture library - [ ] Integrate `react-swipeable` or `use-swipeable` - [ ] Configure thresholds and velocities - [ ] Handle touch events properly - [ ] Add swipe actions - [ ] Swipe left → Archive - [ ] Swipe right → Pin/Unpin - [ ] Long press → Action menu - [ ] Add visual feedback - [ ] Swipe indicator (icon appears) - [ - Color change during swipe - [ - Smooth animation - [ - Snap back if not swiped enough - [ ] Implement haptic feedback - [ ] Vibrate on swipe (50-100ms) - [ ] Vibrate on action complete - [ ] Respect device haptic settings - [ ] Add undo functionality - [ ] Show toast after action - [ ] Undo button in toast - [ - Revert action on undo tap - [ ] Test on mobile devices - [ ] Android (various sensitivity) - [ ] iOS (smooth swipes) - [ - Different screen sizes ## Dev Notes ### Swipe Implementation ```typescript // Using use-swipeable import { useSwipeable } from 'react-swipeable' export function SwipeableNoteCard({ note }: { note: Note }) { const handlers = useSwipeable({ onSwipedLeft: () => handleArchive(note), onSwipedRight: () => handlePin(note), preventDefaultTouchmoveEvent: true, trackMouse: false, // Touch only on mobile }) return (
) } ``` ### Visual Feedback During Swipe ```css /* Swipe left (archive) */ .swipe-left { background: linear-gradient(90deg, #f59e0b 0%, transparent 100%); } /* Swipe right (pin) */ .swipe-right { background: linear-gradient(-90deg, #fbbf24 0%, transparent 100%); } ``` ### Haptic Feedback ```typescript // Web Vibration API if ('vibrate' in navigator) { navigator.vibrate(50) // 50ms vibration } ``` ### Undo Toast ```typescript import { toast } from 'sonner' const handleArchive = async (note: Note) => { await toggleArchive(note.id) toast.success('Note archived', { action: { label: 'Undo', onClick: () => toggleArchive(note.id) } }) } ``` ### Files to Create - `keep-notes/components/swipeable-note-card.tsx` - Swipe wrapper - `keep-notes/hooks/use-swipe-actions.ts` - Swipe logic hook ### Files to Modify - `keep-notes/components/mobile-note-card.tsx` - Wrap in swipeable --- ## Story 12.6: Mobile Typography & Spacing **Status:** ready-for-dev ## Story As a **mobile user**, I want **readable text and comfortable spacing**, so that **the interface is pleasant to use**. ## Acceptance Criteria 1. **Given** a user is viewing the app on a mobile device, 2. **When** reading any text, 3. **Then** the system should: - Use mobile-optimized font sizes (min 16px) - Use generous line heights (1.5-1.6) - Have comfortable padding for touch - Maintain good contrast ratios - NOT affect desktop typography ## Tasks / Subtasks - [ ] Define mobile typography system - [ ] Base font size: 16px (prevents iOS zoom) - [ ] Headings: 18-24px - [ ] Body text: 16px - [ ] Small text: 14px - [ ] Line heights: 1.5-1.6 - [ ] Optimize spacing for mobile - [ ] Card padding: 12-16px - [ ] Gap between elements: 8-12px - [ - Touch targets: 44x44px minimum - [ ] Ensure contrast compliance - [ ] WCAG AA: 4.5:1 ratio - [ ] Dark mode contrast - [ - Test on mobile screens - [ ] Create utility classes - [ ] `text-mobile-base`: 16px - [ - `text-mobile-sm`: 14px - [ - `text-mobile-lg`: 18px - [ ] Test on mobile devices - [ ] Various screen sizes - [ ] Different orientations - [ - Accessibility check ## Dev Notes ### Typography Scale (Mobile) ```css /* Mobile Typography */ :root { --mobile-font-base: 16px; --mobile-font-sm: 14px; --mobile-font-lg: 18px; --mobile-font-xl: 24px; --line-height-relaxed: 1.6; --line-height-normal: 1.5; } .text-mobile-base { font-size: var(--mobile-font-base); } .text-mobile-sm { font-size: var(--mobile-font-sm); } .text-mobile-lg { font-size: var(--mobile-font-lg); } .text-mobile-xl { font-size: var(--mobile-font-xl); } .leading-mobile { line-height: var(--line-height-relaxed); } ``` ### Why 16px Minimum? iOS Safari automatically zooms if font-size < 16px on input fields. Setting base font to 16px prevents this. ### Contrast Ratios (WCAG AA) - Normal text: 4.5:1 - Large text (18pt+): 3:1 - UI components: 3:1 ### Spacing System (Mobile) ```css :root { --spacing-mobile-xs: 4px; --spacing-mobile-sm: 8px; --spacing-mobile-md: 12px; --spacing-mobile-lg: 16px; --spacing-mobile-xl: 20px; } ``` ### Files to Modify - `keep-notes/app/globals.css` - Typography and spacing utilities - `keep-notes/components/mobile-note-card.tsx` - Apply mobile typography - `keep-notes/components/mobile-bottom-nav.tsx` - Apply mobile spacing --- ## Story 12.7: Mobile Performance Optimization **Status:** ready-for-dev ## Story As a **mobile user**, I want **fluid animations and fast performance**, so that **the app is responsive and smooth**. ## Acceptance Criteria 1. **Given** a user is using the app on a mobile device, 2. **When** performing any action, 3. **Then** the system should: - Animate at 60fps consistently - Have no layout shifts - Show loading skeletons on mobile - Lazy load images - Use optimized debounce for mobile - Test and verify on Galaxy S22 Ultra ## Tasks / Subtasks - [ ] Optimize animations for mobile - [ ] Use CSS transforms (GPU-accelerated) - [ ] Limit animation duration to 300ms max - [ ] Respect `prefers-reduced-motion` - [ ] Eliminate layout shifts - [ ] Use skeleton loaders instead of empty states - [ - Reserve space for content - [ ] Use loading states - [ ] Implement lazy loading - [ ] Lazy load images - [ ] Intersection Observer for off-screen content - [ - Code splitting for mobile components - [ ] Optimize event handlers - [ ] Debounce search on mobile (150-200ms) - [ - Passive event listeners where possible - [ - Throttle scroll events - [ ] Test on real devices - [ ] Galaxy S22 Ultra (main target) - [ ] iPhone SE, 14 Pro - [ ] Android various models - [ ] Measure FPS and performance - [ ] Performance monitoring - [ ] Add performance marks - [ - Monitor Core Web Vitals - [ - Log slow interactions ## Dev Notes ### GPU-Accelerated Animations ```css /* Good: GPU-accelerated */ .element { transform: translateX(0); opacity: 1; } /* Bad: Triggers reflow */ .element { left: 0; width: 100%; } ``` ### Skeleton Loading ```typescript // keep-notes/components/note-skeleton.tsx export function NoteSkeleton() { return (
) } ``` ### Lazy Loading Images ```typescript // Using Intersection Observer const [isVisible, setIsVisible] = useState(false) const ref = useRef(null) useEffect(() => { const observer = new IntersectionObserver(([entry]) => { if (entry.isIntersecting) { setIsVisible(true) } }) if (ref.current) { observer.observe(ref.current) } return () => observer.disconnect() }, [])
{isVisible && }
``` ### Debounce Optimization ```typescript // Keep shorter debounce on mobile for responsiveness const debounceTime = isMobile ? 150 : 300 const debouncedSearch = useDebounce(searchQuery, debounceTime) ``` ### Performance Measurement ```typescript // Performance API performance.mark('render-start') // ... component renders performance.mark('render-end') performance.measure('render', 'render-start', 'render-end') // Log slow renders (> 16ms = < 60fps) const measure = performance.getEntriesByName('render')[0] if (measure.duration > 16) { console.warn('Slow render:', measure.duration, 'ms') } ``` ### Files to Create - `keep-notes/components/note-skeleton.tsx` - Skeleton loader - `keep-notes/hooks/use-visibility.ts` - Intersection Observer hook ### Files to Modify - `keep-notes/components/masonry-grid.tsx` - Performance optimizations - `keep-notes/components/mobile-note-card.tsx` - GPU-accelerated animations - `keep-notes/app/(main)/page.tsx` - Skeleton loading states --- ## Epic Summary **Stories in Epic 12:** 1. 12-1: Mobile Note Cards Simplification 2. 12-2: Mobile-First Layout 3. 12-3: Mobile Bottom Navigation 4. 12-4: Full-Screen Mobile Note Editor 5. 12-5: Mobile Quick Actions (Swipe Gestures) 6. 12-6: Mobile Typography & Spacing 7. 12-7: Mobile Performance Optimization **Total Stories:** 7 **Estimated Complexity:** High (comprehensive mobile overhaul) **Priority:** High (critical UX issue on mobile) **Dependencies:** - Story 12-1 should be done first (foundational) - Story 12-2 depends on 12-1 - Story 12-3, 12-4, 12-5 depend on 12-1 - Story 12-6 depends on 12-1 - Story 12-7 can be done in parallel **Testing Requirements:** - ✅ Test on Galaxy S22 Ultra (main target from user feedback) - ✅ Test on iPhone SE (small screen) - ✅ Test on iPhone 14 Pro (large screen) - ✅ Test on Android various sizes - ✅ Test in portrait and landscape - ✅ Verify desktop unchanged (0 regression) **Success Metrics:** - Zero horizontal/vertical overflow on mobile - 60fps animations on mobile devices - Touch targets meet minimum 44x44px - Desktop functionality 100% unchanged - User satisfaction on mobile UX --- ## Dev Agent Record ### Agent Model Used claude-sonnet-4-5-20250929 ### Completion Notes List - [x] Created Epic 12 with 7 comprehensive user stories - [x] Documented mobile UX requirements - [x] Detailed each story with tasks and dev notes - [x] Created file list for implementation - [ ] Epic pending implementation ### File List **Epic Files:** - `_bmad-output/implementation-artifacts/12-mobile-experience-overhaul.md` (this file) **Files to Create (across all stories):** - `keep-notes/components/mobile-note-card.tsx` - `keep-notes/components/swipeable-note-card.tsx` - `keep-notes/components/fab-button.tsx` - `keep-notes/components/mobile-bottom-nav.tsx` - `keep-notes/components/mobile-note-editor.tsx` - `keep-notes/components/note-skeleton.tsx` - `keep-notes/hooks/use-media-query.ts` - `keep-notes/hooks/use-swipe-actions.ts` - `keep-notes/hooks/use-visibility.ts` **Files to Modify:** - `keep-notes/app/(main)/page.tsx` - `keep-notes/app/layout.tsx` - `keep-notes/components/header.tsx` - `keep-notes/components/note-input.tsx` - `keep-notes/components/masonry-grid.tsx` - `keep-notes/app/globals.css` --- *Created: 2026-01-17* *Based on user feedback from Galaxy S22 Ultra testing* *Desktop Interface: NO CHANGES - Mobile Only*