# Story 12.1: Fix Masonry Grid Drag & Drop and Responsive Layout

Status: planning

## Story

As a **user**,
I want **a responsive masonry grid where notes can be easily dragged and dropped while maintaining their sizes**,
so that **I can organize my notes efficiently on any screen size, similar to Google Keep**.

## Acceptance Criteria

1. **Given** a user is viewing notes in the masonry grid,
2. **When** the user drags a note to reorder it,
3. **Then** the system should:
   - Allow smooth drag and drop of notes without losing their positions
   - Maintain the exact size (small, medium, large) of each note during drag and after drop
   - Provide visual feedback during drag (opacity change, placeholder)
   - Save the new order to the database
   - Work seamlessly on both desktop and mobile devices

4. **Given** the user is viewing notes on different screen sizes,
5. **When** the browser window is resized,
6. **Then** the system should:
   - Automatically adjust the number of columns to fit the available width
   - Display more columns on larger screens (e.g., 2-4 columns on desktop)
   - Display fewer columns on smaller screens (e.g., 1-2 columns on mobile)
   - Maintain the masonry layout where items fill available vertical space
   - Not break the layout or cause overlapping items

7. **Given** notes have different sizes (small, medium, large),
8. **When** the grid is rendered,
9. **Then** the system should:
   - Respect the size property of each note (small, medium, large)
   - Display small notes as compact cards
   - Display medium notes as standard cards
   - Display large notes as expanded cards
   - Arrange items in a true masonry pattern (no gaps, items stack vertically)

## Tasks / Subtasks

- [x] Analyze current implementation
  - [x] Review Muuri configuration in masonry-grid.tsx
  - [x] Check note size handling (small, medium, large)
  - [x] Identify drag & drop issues
  - [x] Identify responsive layout issues
- [x] Research best practices
  - [x] Study Google Keep's masonry layout behavior
  - [x] Research Muuri layout options and responsive configuration
  - [x] Document optimal settings for responsive masonry grids
- [x] Create detailed fix plan
  - [x] Document all issues found
  - [x] Create step-by-step correction plan
  - [x] Define responsive breakpoints
  - [x] Define note size dimensions
- [ ] Implement fixes
  - [ ] Fix responsive layout configuration
  - [ ] Fix drag & drop behavior
  - [ ] Ensure note sizes are properly applied
  - [ ] Test on multiple screen sizes
- [ ] Testing and validation
  - [ ] Test drag & drop on desktop
  - [ ] Test drag & drop on mobile
  - [ ] Test responsive behavior
  - [ ] Verify note sizes are maintained
  - [ ] Verify layout matches Google Keep behavior

## Dev Notes

### Problem Analysis

**Current Implementation:**
- Using Muuri library for masonry grid layout
- Notes have size property: 'small' | 'medium' | 'large'
- Layout options include drag settings but not optimized for responsiveness
- Grid uses absolute positioning with width: 100% but no column count management

**Issues Identified:**

1. **Responsive Layout Issues:**
   - No defined column counts for different screen sizes
   - Grid doesn't adjust number of columns when window resizes
   - Items may overlap or leave gaps
   - Layout breaks on mobile devices

2. **Drag & Drop Issues:**
   - Items may not maintain their positions during drag
   - Visual feedback is minimal
   - Drag handle only visible on mobile, but desktop dragging may interfere with content interaction
   - Auto-scroll settings may not be optimal

3. **Note Size Issues:**
   - Note sizes (small, medium, large) are defined but may not be applied correctly to CSS
   - No visual distinction between sizes
   - Size changes during drag may cause layout shifts

### Google Keep Reference Behavior

**Google Keep Layout Characteristics:**
- Fixed card width (e.g., 240px on desktop, variable on mobile)
- Height varies based on content + size setting
- Responsive columns:
  - Mobile (320px-480px): 1 column
  - Tablet (481px-768px): 2 columns
  - Desktop (769px-1200px): 3-4 columns
  - Large Desktop (1201px+): 4-5 columns
- Cards have rounded corners, shadow on hover
- Smooth animations for drag and resize

**Google Keep Drag & Drop:**
- Entire card is draggable on desktop
- Long press to drag on mobile
- Visual feedback: opacity reduction, shadow increase
- Placeholder shows drop position
- Auto-scroll when dragging near edges
- Items reorder smoothly with animation

### Solution Architecture

**Responsive Layout Strategy:**

Option 1: CSS Grid + Muuri for Drag/Drop
```css
.masonry-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: 16px;
}
```
- Pros: Native CSS responsive behavior
- Cons: Muuri may conflict with CSS Grid positioning

Option 2: Muuri with Responsive Configuration (RECOMMENDED)
```javascript
const getColumns = (width) => {
  if (width < 640) return 1;
  if (width < 1024) return 2;
  if (width < 1280) return 3;
  return 4;
};
```
- Pros: Muuri handles all positioning and drag/drop
- Cons: Requires JavaScript to update on resize

**Drag & Drop Improvements:**
- Improve visual feedback during drag
- Optimize auto-scroll speed
- Add transition animations
- Ensure mobile touch support

**Note Size Implementation:**
```css
.note-card[data-size="small"] {
  min-height: 150px;
}
.note-card[data-size="medium"] {
  min-height: 200px;
}
.note-card[data-size="large"] {
  min-height: 300px;
}
```

### Implementation Plan

#### Step 1: Define Responsive Breakpoints and Dimensions

Create a configuration file for layout settings:

```typescript
// keep-notes/config/masonry-layout.ts
export interface MasonryLayoutConfig {
  breakpoints: {
    mobile: number;    // < 640px
    tablet: number;     // 640px - 1024px
    desktop: number;    // 1024px - 1280px
    largeDesktop: number; // > 1280px
  };
  columns: {
    mobile: number;
    tablet: number;
    desktop: number;
    largeDesktop: number;
  };
  noteSizes: {
    small: { minHeight: number; width: number };
    medium: { minHeight: number; width: number };
    large: { minHeight: number; width: number };
  };
  gap: number;
  gutter: number;
}

export const DEFAULT_LAYOUT: MasonryLayoutConfig = {
  breakpoints: {
    mobile: 640,
    tablet: 1024,
    desktop: 1280,
    largeDesktop: 1920,
  },
  columns: {
    mobile: 1,
    tablet: 2,
    desktop: 3,
    largeDesktop: 4,
  },
  noteSizes: {
    small: { minHeight: 150, width: 240 },
    medium: { minHeight: 200, width: 240 },
    large: { minHeight: 300, width: 240 },
  },
  gap: 16,
  gutter: 16,
};
```

#### Step 2: Update Muuri Configuration

Modify `masonry-grid.tsx` to use responsive configuration:

```typescript
// Dynamic column calculation based on window width
const getLayoutOptions = (containerWidth: number) => {
  const columns = calculateColumns(containerWidth);
  const itemWidth = (containerWidth - (columns - 1) * DEFAULT_LAYOUT.gap) / columns;
  
  return {
    dragEnabled: true,
    dragHandle: isMobile ? '.muuri-drag-handle' : undefined,
    dragContainer: document.body,
    dragStartPredicate: {
      distance: 10,
      delay: 0,
    },
    dragPlaceholder: {
      enabled: true,
      createElement: (item: any) => {
        const el = item.getElement().cloneNode(true);
        el.style.opacity = '0.4';
        el.style.transform = 'scale(1.05)';
        return el;
      },
    },
    dragAutoScroll: {
      targets: [window],
      speed: (item: any, target: any, intersection: any) => {
        return intersection * 30; // Faster auto-scroll
      },
      threshold: 50, // Start auto-scroll earlier
      smoothStop: true,
    },
    layoutDuration: 300,
    layoutEasing: 'cubic-bezier(0.25, 1, 0.5, 1)',
    fillGaps: true,
    horizontal: false,
    alignRight: false,
    alignBottom: false,
    rounding: false,
  };
};

// Calculate columns based on container width
const calculateColumns = (width: number) => {
  if (width < DEFAULT_LAYOUT.breakpoints.mobile) return DEFAULT_LAYOUT.columns.mobile;
  if (width < DEFAULT_LAYOUT.breakpoints.tablet) return DEFAULT_LAYOUT.columns.tablet;
  if (width < DEFAULT_LAYOUT.breakpoints.desktop) return DEFAULT_LAYOUT.columns.desktop;
  return DEFAULT_LAYOUT.columns.largeDesktop;
};
```

#### Step 3: Apply Note Sizes with CSS

Add CSS classes for different note sizes:

```css
/* keep-notes/components/masonry-grid.css */
.masonry-item-content .note-card[data-size="small"] {
  min-height: 150px;
}

.masonry-item-content .note-card[data-size="medium"] {
  min-height: 200px;
}

.masonry-item-content .note-card[data-size="large"] {
  min-height: 300px;
}

/* Responsive adjustments */
@media (max-width: 640px) {
  .masonry-item-content .note-card {
    width: 100%;
  }
  
  .masonry-item-content .note-card[data-size="small"] {
    min-height: 120px;
  }
  
  .masonry-item-content .note-card[data-size="medium"] {
    min-height: 160px;
  }
  
  .masonry-item-content .note-card[data-size="large"] {
    min-height: 240px;
  }
}

/* Drag state improvements */
.masonry-item.muuri-item-dragging .note-card {
  transform: scale(1.02);
  box-shadow: 0 20px 40px rgba(0, 0, 0, 0.3);
}

.masonry-item.muuri-item-releasing .note-card {
  transition: transform 0.2s ease-out, box-shadow 0.2s ease-out;
}
```

#### Step 4: Add Resize Handler for Responsive Updates

Add resize listener to update layout when window size changes:

```typescript
useEffect(() => {
  const handleResize = () => {
    if (!pinnedMuuri.current || !othersMuuri.current) return;
    
    const containerWidth = window.innerWidth - 32; // Subtract padding
    const columns = calculateColumns(containerWidth);
    
    // Update Muuri settings
    [pinnedMuuri.current, othersMuuri.current].forEach(grid => {
      if (grid) {
        grid.refreshItems().layout();
      }
    });
  };
  
  const debouncedResize = debounce(handleResize, 150);
  window.addEventListener('resize', debouncedResize);
  
  return () => {
    window.removeEventListener('resize', debouncedResize);
  };
}, []);
```

#### Step 5: Update NoteCard to Display Size Attribute

Ensure NoteCard component renders with data-size attribute:

```typescript
// In NoteCard component
<Card
  data-testid="note-card"
  data-note-id={note.id}
  data-size={note.size} // Add this
  // ... other props
>
```

#### Step 6: Test on Multiple Devices

**Test Matrix:**

1. **Mobile (< 640px)**
   - 1 column layout
   - Drag handle visible
   - Notes stack vertically
   - Touch interaction works

2. **Tablet (640px - 1024px)**
   - 2 column layout
   - Desktop drag behavior
   - Notes align in columns

3. **Desktop (1024px - 1280px)**
   - 3 column layout
   - Smooth drag and drop
   - Responsive to window resize

4. **Large Desktop (> 1280px)**
   - 4 column layout
   - Optimal use of space
   - No layout issues

### Files to Create

- `keep-notes/config/masonry-layout.ts` - Layout configuration
- `keep-notes/components/masonry-grid.css` - Masonry-specific styles

### Files to Modify

- `keep-notes/components/masonry-grid.tsx` - Update Muuri configuration and add resize handler
- `keep-notes/components/note-card.tsx` - Add data-size attribute
- `keep-notes/app/globals.css` - Add note size styles if not in separate CSS file

### Testing Checklist

**Responsive Behavior:**
- [ ] Layout adjusts columns when resizing window
- [ ] No items overlap or create gaps
- [ ] Mobile shows 1 column
- [ ] Tablet shows 2 columns
- [ ] Desktop shows 3-4 columns
- [ ] Layout matches Google Keep behavior

**Drag & Drop Behavior:**
- [ ] Notes can be dragged smoothly
- [ ] Visual feedback during drag (opacity, shadow)
- [ ] Placeholder shows drop position
- [ ] Auto-scroll works when dragging near edges
- [ ] Order is saved after drop
- [ ] Notes maintain their positions
- [ ] Works on both desktop and mobile

**Note Sizes:**
- [ ] Small notes display compactly
- [ ] Medium notes display with standard height
- [ ] Large notes display with expanded height
- [ ] Sizes are maintained during drag
- [ ] Sizes persist after drop
- [ ] Size changes update layout correctly

**Cross-Browser:**
- [ ] Chrome: Works correctly
- [ ] Firefox: Works correctly
- [ ] Safari: Works correctly
- [ ] Edge: Works correctly

### Performance Considerations

- Debounce resize events to avoid excessive re-layouts
- Use requestAnimationFrame for smooth animations
- Avoid re-initializing Muuri on resize, use refreshItems() instead
- Optimize drag placeholder creation to avoid expensive DOM operations

### Accessibility Considerations

- Ensure drag handles are keyboard accessible
- Add ARIA attributes for drag state
- Provide visual feedback for screen readers
- Maintain focus management during drag

### References

- **Muuri Documentation:** https://github.com/haltu/muuri
- **Google Keep UI Reference:** https://keep.google.com
- **CSS Masonry Layout:** https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Grid_Layout/Masonry_Layout
- **Responsive Design Patterns:** https://www.smashingmagazine.com/2018/05/learning-layouts-with-css-grid/

## Dev Agent Record

### Initial Analysis (2026-01-18)

**Problems Identified:**
1. Muuri configuration lacks responsive column management
2. No resize handler to update layout on window resize
3. Note sizes (small, medium, large) are not visually applied via CSS
4. Drag & drop feedback could be improved
5. Mobile drag handle optimization needed

**Solution Approach:**
- Implement responsive column calculation based on window width
- Add resize listener with debounce to update layout
- Apply note sizes via CSS data attributes
- Improve drag & drop visual feedback
- Test thoroughly on multiple devices

### Implementation Progress

- [x] Analyze current implementation
- [x] Research best practices
- [x] Create detailed fix plan
- [ ] Implement fixes
- [ ] Test and validate

### Agent Model Used

claude-sonnet-4.5-20250929

### Completion Notes List

- [x] Analyzed Muuri configuration in masonry-grid.tsx
- [x] Reviewed note size handling (small, medium, large)
- [x] Identified drag & drop issues
- [x] Identified responsive layout issues
- [x] Studied Google Keep's masonry layout behavior
- [x] Researched Muuri layout options and responsive configuration
- [x] Documented optimal settings for responsive masonry grids
- [x] Created comprehensive fix plan with step-by-step instructions
- [x] Defined responsive breakpoints
- [x] Defined note size dimensions
- [ ] Fix responsive layout configuration
- [ ] Fix drag & drop behavior
- [ ] Ensure note sizes are properly applied
- [ ] Test on multiple screen sizes

### File List

**Files to Create:**
- `keep-notes/config/masonry-layout.ts`
- `keep-notes/components/masonry-grid.css`

**Files to Modify:**
- `keep-notes/components/masonry-grid.tsx`
- `keep-notes/components/note-card.tsx`
- `keep-notes/app/globals.css` (optional, depending on CSS organization)
