mono/packages/ui/docs/feed.md
2026-02-08 15:09:32 +01:00

80 lines
4.4 KiB
Markdown

# Instagram-like Feed Implementation Plan
## Objective
Create a responsive, immersive feed experience that adapts to device size:
- **Desktop/Large Screens**: Retain the current `PhotoGrid` (grid view).
- **Mobile**: Implement a new `Feed` view (vertical list) similar to Instagram.
- **Carousel**: Support horizontal swiping (left/right) through multiple pictures within a single post.
- **Performance**: Implement "load ahead" strategy (buffer ~5 posts) to ensure smooth scrolling without loading the entire database.
## Architecture & Components
### 1. Data Layer Enhancements
Current `PhotoGrid` logic fetches posts and selects a single "cover" image.
We need to modify the data transformation to pass *all* visible pictures to the UI components.
- **Query**: Keep fetching `posts` with `pictures`.
- **Transformation**: Instead of flattening to a single `MediaItem`, we need a structure that preserves the list of pictures for each post.
```typescript
interface FeedPost {
id: string; // Post ID
user_id: string; // Author
pictures: MediaItemType[]; // Array of pictures in the post
// ... other post metadata (title, description, etc.)
}
```
### 2. New `Feed` Component (Mobile)
A new component `src/components/Feed.tsx` will be created for the mobile view.
- **Layout**: Vertical list of full-width cards.
- **Virtualization**: Use `react-window` or simpler intersection observer-based rendering to only render posts in (and slightly outside) the viewport.
- **Preloading**: Ensure the next 5 image/video assets are preloaded.
### 3. Updated `MediaCard` / New `FeedCard`
`MediaCard` currently handles a single media item. We have two options:
1. **Refactor `MediaCard`**: Add support for an array of media and internal carousel logic.
2. **Create `FeedCard`**: A specialized card for the Feed view that wraps `MediaCard` or implements its own carousel.
* *Decision*: Use `FeedCard` (or `PostCard`) to encapsulate the carousel logic (Embla Carousel or similar) and use `MediaCard` for individual slides if needed, or implement a lighter slide view.
* **Carousel**: Must support touch gestures for left/right swiping.
### 4. `PhotoGrid` Updates
- **Logic Separation**: Extract the data fetching hook (e.g., `useFeedMedia`) so both `PhotoGrid` and `Feed` can share the same data source and state (likes, etc.).
- **Responsive Switch**: In `Index.tsx`, conditionally render `PhotoGrid` (desktop) or `Feed` (mobile). Or render both and hide via CSS (better for SSR/hydration matching, but heavier on DOM). Better to use a valid hook for `isMobile`.
## Implementation Steps
### Phase 1: Data & Hooks
1. Create `useFeedQuery` hook to fetch posts + pictures.
2. Implement pagination (infinite scroll) logic (load 10, load next 10 when bottom reached).
3. Preloading utility: Function to preload images `n` indexes ahead of the current viewport item.
### Phase 2: Carousel Component
1. Implement a Swipe/Carousel component (using `embla-carousel-react` or purely custom CSS scroll-snap).
2. Ensure it handles image aspect ratios gracefully (Instagram usually restricts to 4:5 or square, but we might support flexible).
### Phase 3: `MobileFeed` Component
1. Create the vertical list layout.
2. Implement the "Load 5 ahead" logic (prefetching images for the next 5 cards).
3. Integrate the Carousel for multi-image posts.
### Phase 4: Integration
1. Update `Index.tsx` to switch between `PhotoGrid` and `MobileFeed`.
2. Ensure shared state (Likes, Comments) works in both views.
## Technical Details
### "Load 5 Ahead" Strategy
- **Intersection Observer**: Watch the last rendered element to trigger fetching the next page.
- **Image Preloading**: Watch the *currently visible* post index. Automatically create `Link rel="preload"` or `new Image()` for the `cover` images of the next 5 posts.
- **Carousel Preloading**: If a user stops on a post, prioritize loading the *next* slide of that specific post.
### Swiping Interaction
- **Carousel (Inner)**: Swiping horizontally moves between pictures of the *same* post.
- **Feed (Outer)**: Scrolling vertically moves between *different* posts.
## Proposed File Structure
- `src/components/feed/Feed.tsx`
- `src/components/feed/FeedCard.tsx` (Handles the carousel)
- `src/components/feed/FeedCarousel.tsx` (The actual swiper)
- `src/hooks/useFeed.ts` (Data fetching logic)