# Post Page Social Interactions Plan (Revised)

## Overview

Add likes, reposts, comments, zaps display, inline comment threads, and real-time "time ago" updates to [`www/post.html`](www/post.html). Build as a **reusable module** so [`www/feed.html`](www/feed.html) (future) can share the same interaction bar and comment rendering.

The interaction icons will use **HamburgerMorphing** instances with new custom shapes (heart, repost-arrows, speech-bubble, lightning-bolt), giving the satisfying animated morph effect when users click to like/repost/zap/comment.

## Architecture Overview

```mermaid
flowchart TD
    subgraph Reusable Module
        A[post-interactions.mjs] --> B[renderInteractionBar]
        A --> C[subscribeToInteractions]
        A --> D[handleInteractionEvent]
        A --> E[renderCommentThread]
        A --> F[publishReaction]
        A --> G[publishRepost]
        A --> H[publishComment]
    end

    subgraph Pages
        P1[post.html] --> A
        P2[feed.html - future] --> A
    end

    subgraph HamburgerMorphing
        HM[hamburger.mjs] --> S1[heart shape - new]
        HM --> S2[repost shape - new]
        HM --> S3[comment shape - new]
        HM --> S4[bolt shape - new]
    end

    A --> HM
    A --> NDK[init-ndk.mjs subscribe + publishEvent]
```

## Making HamburgerMorphing Work for Repeated Icons

### The Problem
Each `HamburgerMorphing` instance creates an SVG.js drawing with 3 animated lines. With 20 posts × 4 icons = 80 instances, this could be heavy.

### The Solution: Lazy Instantiation + Viewport Optimization

1. **Render static SVG initially** — On first render, each interaction icon is a lightweight static SVG string (no SVG.js, no animation). This is just an `innerHTML` set.

2. **Instantiate HamburgerMorphing on first interaction** — When a user clicks an icon (like, repost, etc.), we create the HamburgerMorphing instance *for that specific icon only*, animate the morph (e.g., from empty heart to filled heart), then optionally destroy it after the animation completes and replace with the new static SVG state.

3. **Result**: At most 1-2 HamburgerMorphing instances alive at any time, not 80.

This gives us the satisfying morph animation on click without the overhead of 80 persistent instances.

### Implementation Pattern

```javascript
function onInteractionClick(iconContainer, fromShape, toShape) {
    // Create temporary HamburgerMorphing instance
    const hm = new HamburgerMorphing(iconContainer, {
        size: 20,
        foreground: 'var(--muted-color)',
        background: 'var(--secondary-color)',
        hover: 'var(--accent-color)'
    });
    
    // Start at the from shape, then animate to the to shape
    hm.animateTo(fromShape);
    requestAnimationFrame(() => {
        hm.animateTo(toShape);
    });
    
    // After animation completes, destroy instance and set static SVG
    setTimeout(() => {
        const staticSvg = hm.getSvgCode();
        hm.destroy();
        iconContainer.innerHTML = staticSvg;
    }, 600); // slightly longer than ANIMATION_DURATION of 500ms
}
```

## New HamburgerMorphing Shapes

Add 4 new shapes to [`www/hamburger_morphing/hamburger.mjs`](www/hamburger_morphing/hamburger.mjs) in the `animateTo()` switch statement:

| Shape Name | Visual | 3-Line Approximation |
|-----------|--------|---------------------|
| `heart` | ❤️ | Line1: left-top diagonal down-right; Line2: right-top diagonal down-left; Line3: bottom V-shape |
| `heart_filled` | Filled ❤️ | Same as heart but with thick stroke to appear solid |
| `repost_arrows` | 🔄 | Line1: top horizontal arrow-right; Line2: connecting diagonal; Line3: bottom horizontal arrow-left |
| `comment_bubble` | 💬 | Line1: top arc; Line2: bottom with tail; Line3: side |
| `bolt` | ⚡ | Line1: top-right to center-left; Line2: center horizontal; Line3: center-right to bottom-left |

## Nostr Event Kinds

| Interaction | Kind | NIP | Filter Pattern |
|-------------|------|-----|---------------|
| Reaction/Like | 7 | NIP-25 | `{ kinds: [7], #e: [postIds] }` |
| Repost | 6 | NIP-18 | `{ kinds: [6], #e: [postIds] }` |
| Reply/Comment | 1 | NIP-10 | `{ kinds: [1], #e: [postIds] }` |
| Zap Receipt | 9735 | NIP-57 | `{ kinds: [9735], #e: [postIds] }` |

## Reusable Module: `www/js/post-interactions.mjs`

### Exports

```javascript
// Initialize interaction tracking for a set of posts
export function initInteractions(posts, currentPubkey, options)

// Render the interaction bar HTML for a single post
export function renderInteractionBar(postId, counts)

// Render comment thread under a post
export function renderCommentThread(postId, comments)

// Subscribe to all interaction events for given post IDs
export function subscribeToInteractions(postIds, onUpdate)

// Publish a like reaction
export function publishLike(postId, postPubkey)

// Publish a repost
export function publishRepost(postId, postPubkey, originalEvent)

// Publish a comment/reply
export function publishComment(postId, postPubkey, content)

// Update all time-ago displays on the page
export function updateTimeAgos()

// Get static SVG string for an interaction icon
export function getIconSvg(type, active)
```

### Data Structure

```javascript
// Per-post interaction state
const interactionState = new Map();
// Key: postId
// Value: {
//   likes: Set of pubkeys,
//   reposts: Set of pubkeys,
//   comments: Array of { id, pubkey, content, created_at },
//   zaps: Array of { pubkey, amount, comment },
//   zapTotal: number (in sats),
//   userLiked: boolean,
//   userReposted: boolean
// }
```

## Comment Thread Display

When a post has comments, they appear below the interaction bar in a collapsible section:

```mermaid
flowchart TD
    subgraph Post Card
        Content[Post Content]
        Footer[Time Ago]
        Bar[Interaction Bar: heart 3 | comment 2 | repost 1 | bolt 500]
        Toggle[Click comment icon to expand]
        Thread[Comment Thread]
        Reply[Reply Input - contenteditable div]
    end
    
    Content --> Footer --> Bar --> Toggle --> Thread --> Reply
```

- Comments are sorted by `created_at` ascending
- Each comment shows: content + time ago + its own mini interaction bar (like only)
- Reply input appears at the bottom — press Enter to post reply (same UX as the main post box)
- Comments on comments (nested replies) are shown flat with indentation based on the reply chain depth (max 2 levels)

## Detailed Implementation Steps

### Step 1: Add new shapes to HamburgerMorphing

Add `heart`, `heart_filled`, `repost_arrows`, `comment_bubble`, and `bolt` cases to the [`animateTo()`](www/hamburger_morphing/hamburger.mjs:102) switch statement in [`www/hamburger_morphing/hamburger.mjs`](www/hamburger_morphing/hamburger.mjs).

### Step 2: Create `www/js/post-interactions.mjs`

The reusable module containing:
- Static SVG icon generation functions
- Interaction state management (Map of post ID to counts/sets)
- Subscription management (subscribe to kinds 7, 6, 1, 9735 with #e filter)
- Event handlers that update state and trigger re-renders
- Publish functions for like, repost, comment
- Comment thread rendering
- Time-ago update function

### Step 3: Create `www/css/post-interactions.css` (or add to client.css)

Styles for:
- `.divPostInteractions` — horizontal flex row, gap between items
- `.interaction-item` — inline-flex, align-items center, cursor pointer
- `.interaction-item.active` — accent color
- `.interaction-count` — small font, muted color
- `.divCommentThread` — indented, border-left
- `.divCommentItem` — individual comment styling
- `.divCommentReply` — reply input box styling

### Step 4: Modify `www/post.html` to use the module

- Import `post-interactions.mjs`
- After posts render, call `initInteractions(posts, currentPubkey)`
- Modify [`renderFeed()`](www/post.html:263) to include interaction bar HTML
- Add event delegation for interaction clicks
- Set up 30-second interval for `updateTimeAgos()`
- Handle new interaction events from the `ndkEvent` listener

### Step 5: Wire up comment thread

- Clicking the comment icon toggles the comment thread visibility
- Comment thread shows existing replies
- Reply input at bottom of thread
- Enter to submit reply (Shift+Enter for newline, same as main post)
- New replies appear in real-time via the subscription

### Step 6: Wire up all interactive actions

- **Like**: Click heart → morph animation → publish kind 7 → update count
- **Repost**: Click repost → morph animation → publish kind 6 → update count
- **Comment**: Click comment → expand thread → focus reply input
- **Zap**: Click bolt → morph animation → (future: integrate with wallet/NWC)

## Real-Time Time Ago

```javascript
// In post-interactions.mjs
export function updateTimeAgos() {
    document.querySelectorAll('[data-timestamp]').forEach(el => {
        const ts = parseInt(el.dataset.timestamp);
        if (!isNaN(ts)) {
            el.textContent = formatTimeAgo(ts);
        }
    });
}

// Called from page every 30 seconds
setInterval(updateTimeAgos, 30000);
```

The [`formatTimeAgo()`](www/post.html:250) function already exists in post.html — it should be moved into the module or into [`www/js/utilities.mjs`](www/js/utilities.mjs) for reuse.

## File Changes Summary

| File | Action | Description |
|------|--------|-------------|
| [`www/hamburger_morphing/hamburger.mjs`](www/hamburger_morphing/hamburger.mjs) | Modify | Add heart, heart_filled, repost_arrows, comment_bubble, bolt shapes |
| `www/js/post-interactions.mjs` | **Create** | Reusable interaction bar module |
| [`www/post.html`](www/post.html) | Modify | Import module, modify renderFeed, add interaction handlers, add time-ago interval |
| [`www/css/client.css`](www/css/client.css) | Modify | Add interaction bar and comment thread styles |
| [`www/js/utilities.mjs`](www/js/utilities.mjs) | Modify | Move formatTimeAgo here for reuse |

## Future: feed.html

The same `post-interactions.mjs` module will be imported by `feed.html` with identical usage:

```javascript
import { initInteractions, updateTimeAgos } from './js/post-interactions.mjs';

// After rendering feed posts...
initInteractions(posts, currentPubkey);
setInterval(updateTimeAgos, 30000);
```

## Design Principles

- **Minimal**: Small icons + numbers, no text labels
- **Animated**: HamburgerMorphing morph effect on click (lazy instantiation keeps it lightweight)
- **Reusable**: Module works for post.html, feed.html, and any future page with posts
- **Real-time**: Counts update as events arrive; timestamps update every 30s
- **Threaded**: Comments appear inline under posts with reply capability
- **Recursive**: Comments on comments supported (flat with indentation, max 2 levels)
