Keep/_bmad-output/implementation-artifacts/10-2-fix-mobile-menu-bug.md

8.5 KiB

Story 10.2: Fix Mobile Menu Issues

Status: ready-for-dev

Story

As a mobile user, I want a working menu that is easy to access and use on mobile devices, so that I can navigate the app and access all features.

Acceptance Criteria

  1. Given a user is using the app on a mobile device,
  2. When the user needs to access the menu or navigation,
  3. Then the system should:
    • Display a functional mobile menu (hamburger menu or similar)
    • Allow easy opening/closing of the menu
    • Show all navigation options clearly
    • Work with touch interactions smoothly
    • Not interfere with content scrolling

Tasks / Subtasks

  • Investigate current mobile menu implementation
    • Check if mobile menu exists
    • Identify menu component
    • Document current issues
    • Test on real mobile devices
  • Implement or fix mobile menu
    • Create responsive navigation component
    • Add hamburger menu for mobile (< 768px)
    • Implement menu open/close states
    • Add backdrop/overlay when menu open
    • Ensure close on backdrop click
  • Optimize menu for touch
    • Large touch targets (min 44x44px)
    • Clear visual feedback on touch
    • Smooth animations
    • Accessible with screen readers
  • Test menu on various mobile devices
    • iOS Safari (iPhone)
    • Chrome (Android)
    • Different screen sizes
    • Portrait and landscape orientations

Dev Notes

Bug Description

Problem: The menu has issues on mobile - may not open, close properly, or be accessible.

User Report: "Il paraît également qu'il y a un problème avec le menu en mode mobile" (There also seems to be a problem with the menu in mobile mode)

Expected Behavior:

  • Hamburger menu visible on mobile
  • Tapping menu icon opens full-screen or slide-out menu
  • Menu items are large and easy to tap
  • Tapping outside menu or X button closes menu
  • Smooth animations and transitions

Current Behavior:

  • Menu may not work on mobile
  • Menu items may be too small to tap
  • Menu may not close properly
  • Poor UX overall

Technical Requirements

Responsive Breakpoints:

/* Tailwind defaults or custom */
sm: 640px
md: 768px
lg: 1024px
xl: 1280px
2xl: 1536px

Mobile Menu Pattern Options:

Option 1: Slide-out Menu (Recommended)

// keep-notes/components/MobileMenu.tsx
'use client'

import { useState } from 'react'
import { X } from 'lucide-react'

export function MobileMenu() {
  const [isOpen, setIsOpen] = useState(false)

  return (
    <>
      {/* Hamburger button */}
      <button
        onClick={() => setIsOpen(true)}
        className="lg:hidden p-4"
        aria-label="Open menu"
      >
        <svg width="24" height="24" viewBox="0 0 24 24">
          <path d="M3 12h18M3 6h18M3 18h18" stroke="currentColor" strokeWidth="2"/>
        </svg>
      </button>

      {/* Backdrop */}
      {isOpen && (
        <div
          className="fixed inset-0 bg-black/50 z-40 lg:hidden"
          onClick={() => setIsOpen(false)}
        />
      )}

      {/* Slide-out menu */}
      <div className={`
        fixed top-0 right-0 h-full w-80 bg-white z-50
        transform transition-transform duration-300 ease-in-out
        ${isOpen ? 'translate-x-0' : 'translate-x-full'}
        lg:hidden
      `}>
        {/* Header */}
        <div className="flex justify-between items-center p-4 border-b">
          <h2 className="text-lg font-semibold">Menu</h2>
          <button
            onClick={() => setIsOpen(false)}
            className="p-2"
            aria-label="Close menu"
          >
            <X size={24} />
          </button>
        </div>

        {/* Menu items */}
        <nav className="p-4 space-y-2">
          <MenuButton to="/">All Notes</MenuButton>
          <MenuButton to="/notebooks">Notebooks</MenuButton>
          <MenuButton to="/labels">Labels</MenuButton>
          <MenuButton to="/settings">Settings</MenuButton>
        </nav>
      </div>
    </>
  )
}

function MenuButton({ to, children }: { to: string; children: React.ReactNode }) {
  return (
    <a
      href={to}
      className="block px-4 py-3 rounded-lg hover:bg-gray-100 active:bg-gray-200"
      style={{ minHeight: '44px' }} // Touch target size
    >
      {children}
    </a>
  )
}

Option 2: Full-Screen Menu

// Full-screen overlay menu
<div className={`
  fixed inset-0 bg-white z-50
  transform transition-transform duration-300
  ${isOpen ? 'translate-y-0' : '-translate-y-full'}
`}>
  {/* Menu content */}
</div>

Option 3: Bottom Sheet (Material Design style)

// Bottom sheet menu
<div className={`
  fixed bottom-0 left-0 right-0 bg-white rounded-t-3xl z-50
  transform transition-transform duration-300
  ${isOpen ? 'translate-y-0' : 'translate-y-full'}
`}>
  {/* Menu content */}
</div>

Implementation Checklist

Essential Features:

  • Hamburger icon visible on mobile (< 768px)
  • Menu opens with smooth animation
  • Backdrop overlay when menu open
  • Close on backdrop tap
  • Close button (X) in menu header
  • Menu items are full-width with min-height 44px
  • Active state on menu items (hover/active)
  • Keyboard accessible (Esc to close)
  • Screen reader announcements
  • Menu closes on navigation

Nice-to-Have Features:

  • Swipe to close gesture
  • Haptic feedback on open/close
  • User profile in menu
  • Search in menu
  • Recent items in menu

Files to Create

// keep-notes/components/MobileMenu.tsx
'use client'

import { useState, useEffect } from 'react'
import { X, Home, Notebook, Tags, Settings } from 'lucide-react'

export function MobileMenu() {
  const [isOpen, setIsOpen] = useState(false)

  // Close menu on route change
  useEffect(() => {
    setIsOpen(false)
  }, [pathname])

  // Prevent body scroll when menu open
  useEffect(() => {
    if (isOpen) {
      document.body.style.overflow = 'hidden'
    } else {
      document.body.style.overflow = ''
    }
    return () => {
      document.body.style.overflow = ''
    }
  }, [isOpen])

  return (
    <>
      <MenuButton onOpen={() => setIsOpen(true)} />
      <MenuOverlay isOpen={isOpen} onClose={() => setIsOpen(false)} />
      <MenuPanel isOpen={isOpen} onClose={() => setIsOpen(false)} />
    </>
  )
}

// ... rest of implementation

Files to Modify

Current Navigation/Header:

  • keep-notes/components/Header.tsx (likely exists)
  • keep-notes/components/Navigation.tsx (if exists)
  • keep-notes/app/layout.tsx - May need mobile menu wrapper

Testing Requirements

Test on Real Devices:

  1. iPhone SE (small screen)
  2. iPhone 14 Pro (large screen)
  3. Android phone (various sizes)
  4. iPad (tablet)
  5. Portrait and landscape

Test Scenarios:

  1. Tap hamburger → menu opens smoothly
  2. Tap backdrop → menu closes
  3. Tap X button → menu closes
  4. Tap menu item → navigates and closes menu
  5. Swipe gesture → menu closes (if implemented)
  6. Press Esc → menu closes
  7. Scroll content → menu stays open

Accessibility Testing:

  1. Screen reader announces menu state
  2. Keyboard navigation works
  3. Focus trap when menu open
  4. ARIA labels correct

Mobile UX Best Practices

Touch Targets:

  • Minimum 44x44px (iOS)
  • Minimum 48x48px (Android)
  • Full-width buttons for easy tapping

Visual Design:

  • Clear visual hierarchy
  • Good contrast ratios
  • Large, readable text (min 16px)
  • Spacious padding

Animations:

  • Smooth transitions (300ms or less)
  • No janky animations
  • Respect prefers-reduced-motion

Performance:

  • Menu renders quickly
  • No layout shifts
  • Smooth 60fps animations

References

Dev Agent Record

Agent Model Used

claude-sonnet-4-5-20250929

Completion Notes List

  • Created story file with comprehensive bug fix requirements
  • Identified mobile menu patterns
  • Recommended slide-out menu implementation
  • Added mobile UX best practices
  • Bug fix pending (see tasks above)

File List

Files to Create:

  • keep-notes/components/MobileMenu.tsx
  • keep-notes/components/MenuButton.tsx (optional)
  • keep-notes/components/MenuPanel.tsx (optional)

Files to Modify:

  • keep-notes/components/Header.tsx (or similar)
  • keep-notes/app/layout.tsx