# Notifications Mode for `post.html`

## Overview

Add a `notifications=true` URL parameter to [`post.html`](../www/post.html) that transforms the page into a notifications view. Notification events are rendered as full post cards using the existing [`renderPostItem()`](../www/js/post-interactions.mjs:549) from `post-interactions.mjs`, preserving all interaction capabilities — liking, replying, quoting, zapping, and commenting — on every notification item.

## URL Parameter

```
post.html?notifications=true
```

Added to the existing parameter set documented in the [`post.html` header comment](../www/post.html:3):

| Parameter | Values | Default | Description |
|-----------|--------|---------|-------------|
| `notifications` | `true`/`false` | `false` | Show notifications directed at the current user |

When `notifications=true`:
- `post` box is hidden (implies `post=false`)
- `follows` and `viewed` are ignored
- `npub` is ignored (notifications are always for the logged-in user)
- Header text changes to **NOTIFICATIONS**
- Footer shows notification count instead of post count

## Data Flow

```mermaid
flowchart TD
    A[Page Load] --> B[Parse URL: notifications=true]
    B --> C[initNDKPage + getPubkey]
    C --> D[Subscribe: kinds 1,6,7,9735 with #p = currentPubkey]
    C --> E[fetchEventsFromAllRelays for initial batch]
    D --> F[ndkEvent listener]
    E --> F
    F --> G{Is notification for me?}
    G -->|No: own event or not tagged| H[Discard]
    G -->|Yes| I[Fetch referenced post if needed]
    I --> J[Store in notifications array]
    J --> K[Render as full post card via renderPostItem]
    K --> L[Append interaction bar: like, reply, quote, zap, comment]
```

## Rendering Approach — Full Post Cards

The key design decision: **notifications render the referenced post as a full interactive card**, not a compact notification summary. Each notification shows:

1. **A notification header** — small banner above the post card showing who did what
   - Avatar + name of the actor
   - Action type badge: `L` liked, `R` reposted, `C` replied, `Z` zapped, `@` mentioned
   - Relative timestamp
2. **The referenced post** — rendered via [`renderPostItem()`](../www/js/post-interactions.mjs:549) with full interaction bar
   - For reactions/reposts/zaps: shows YOUR original post that was interacted with
   - For replies: shows the REPLY itself as the main card, with your original post as a compact reference below
   - For mentions: shows the mentioning post as the main card

This means every notification card supports:
- Liking (via [`publishLike()`](../www/js/post-interactions.mjs:1724))
- Replying (via inline composer + [`handleComposerCommentIntent()`](../www/post.html:1794))
- Quoting (via inline composer + [`handleComposerQuoteIntent()`](../www/post.html:1809))
- Zapping (via interaction bar)
- Viewing/toggling comments (via [`renderCommentThread()`](../www/js/post-interactions.mjs:1336))

### Card Layout

```
┌─────────────────────────────────────────────────┐
│ 🔔 Alice liked your post                   2m  │  ← notification header
├─────────────────────────────────────────────────┤
│ [Your Avatar] You                               │  ← standard post card
│                                                 │
│ Your original post content here...              │
│                                                 │
│ [Like] [Reply] [Quote] [Zap] [Time]            │  ← full interaction bar
└─────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────┐
│ 🔔 Bob replied to your post                5m  │  ← notification header
├─────────────────────────────────────────────────┤
│ [Bob Avatar] Bob                                │  ← reply post card
│                                                 │
│ Bob reply content here...                       │
│                                                 │
│ [Like] [Reply] [Quote] [Zap] [Time]            │  ← full interaction bar
│ ┌─────────────────────────────────────────────┐ │
│ │ In reply to:                                │ │  ← compact reference
│ │ Your original post snippet...               │ │
│ └─────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────┘
```

## Implementation Details

### 1. URL Parameter Parsing

Add to the existing parameter parsing block at [line 648](../www/post.html:648):

```javascript
const notificationsParam = urlParams.get('notifications');
const showNotifications = notificationsParam === 'true';
```

Mode precedence: `notifications` overrides `viewed`, `follows`, `profile`, and `post`:

```javascript
const showNotifications = notificationsParam === 'true';
const showViewed = showNotifications ? false : (viewedParam === 'true');
const showProfile = showNotifications ? false : (profileParam === 'true');
const showPostBox = showNotifications ? false : (showViewed ? false : (postParam !== 'false'));
const showFollows = showNotifications ? false : (showViewed ? true : (followsParam === 'true'));
```

### 2. Notification State Variables

```javascript
// Notifications mode state
const NOTIF_KINDS = [1, 6, 7, 9735];
const MAX_NOTIFICATIONS = 300;
let notifications = [];
let notificationIds = new Set();
let referencedPosts = new Map();  // eventId -> event (your original posts)
let notifRenderCount = 20;
```

### 3. Notification Subscription

In the `main()` function, when `showNotifications` is true:

```javascript
if (showNotifications) {
    document.title = 'NOTIFICATIONS';
    headerText.textContent = 'NOTIFICATIONS';
    
    // Subscribe to events tagging the current user
    subscribe(
        { kinds: NOTIF_KINDS, '#p': [currentPubkey], limit: 50 },
        { closeOnEose: false, cacheUsage: 'CACHE_FIRST' }
    );
    
    // Also do a direct fetch for initial population
    fetchEventsFromAllRelays({
        kinds: NOTIF_KINDS, '#p': [currentPubkey], limit: 50
    });
}
```

### 4. Event Processing in ndkEvent Handler

Add a new branch in the [`ndkEvent` listener](../www/post.html:2098) for notifications mode:

```javascript
if (showNotifications && NOTIF_KINDS.includes(evt.kind)) {
    // Filter: skip own events, skip duplicates
    if (evt.pubkey === currentPubkey) return;
    if (notificationIds.has(evt.id)) return;
    
    // For kind 1: only keep if current user is in p-tags
    if (evt.kind === 1) {
        const pTags = evt.tags?.filter(t => t[0] === 'p').map(t => t[1]) || [];
        if (!pTags.includes(currentPubkey)) return;
    }
    
    // Fetch referenced post for context
    await ensureReferencedPost(evt);
    
    // For reactions/reposts/zaps: only keep if referenced post is ours
    if ([6, 7, 9735].includes(evt.kind)) {
        const refId = getRootEventId(evt);
        const refEvent = referencedPosts.get(refId);
        if (!refEvent || refEvent.pubkey !== currentPubkey) return;
    }
    
    notificationIds.add(evt.id);
    notifications.push(evt);
    pruneNotifications();
    renderNotificationsFeed();
}
```

### 5. Rendering Notifications

```javascript
function createNotificationElement(notifEvent) {
    const wrapper = document.createElement('div');
    wrapper.className = 'divNotifWrapper';
    
    // 1. Notification header (who did what)
    const header = createNotifHeader(notifEvent);
    wrapper.appendChild(header);
    
    // 2. The main post card — determine which event to render
    let mainEvent;
    if (notifEvent.kind === 1) {
        // Reply/mention: show the reply itself
        mainEvent = notifEvent;
    } else {
        // Like/repost/zap: show the referenced (your) post
        const refId = getRootEventId(notifEvent);
        mainEvent = referencedPosts.get(refId) || notifEvent;
    }
    
    // Render as full interactive post card
    const postEl = interactions.renderPostItem(mainEvent, {
        currentPubkey,
        showHeader: true,
        isCompact: false
    });
    wrapper.appendChild(postEl);
    
    // 3. For replies: add compact reference to original post
    if (notifEvent.kind === 1) {
        const refId = getRootEventId(notifEvent);
        const refEvent = referencedPosts.get(refId);
        if (refEvent) {
            const refSnippet = createCompactReference(refEvent);
            wrapper.appendChild(refSnippet);
        }
    }
    
    return wrapper;
}
```

### 6. Notification Header CSS

```css
.divNotifWrapper {
    margin-bottom: 15px;
}

.divNotifHeader {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 6px 12px;
    font-size: 80%;
    color: var(--muted-color);
    border: 1px solid var(--muted-color);
    border-bottom: none;
    border-radius: 10px 10px 0 0;
    background: var(--secondary-color);
}

.divNotifHeader .notif-avatar {
    width: 20px;
    height: 20px;
    border-radius: 3px;
    object-fit: cover;
}

.divNotifHeader .notif-type-badge {
    border: 1px solid var(--muted-color);
    color: var(--accent-color);
    border-radius: 999px;
    min-width: 18px;
    height: 18px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 75%;
    font-weight: bold;
    padding: 0 4px;
}

.divNotifWrapper .divPostItem {
    border-radius: 0 0 10px 10px;
    margin-bottom: 0;
}
```

### 7. See More Button

Reuse the existing [`btnSeeMore`](../www/post.html:590) element. In notifications mode, wire it to:
1. First expand `notifRenderCount` if more notifications exist in memory
2. Then fetch older notifications with `until` parameter

### 8. Footer Update

In the [`UpdateFooter`](../www/post.html:1997) function, add notifications branch:

```javascript
if (showNotifications) {
    divFooterRight.innerHTML = `${notifications.length} notifications`;
}
```

### 9. Sidenav Link Update

Change the existing [notifications link in the sidenav](../www/post.html:609) from:
```html
<a href="./notifications.html">NOTIFICATIONS</a>
```
to:
```html
<a href="./post.html?notifications=true">NOTIFICATIONS</a>
```

### 10. Interaction Subscriptions for Notification Posts

After rendering notification cards, subscribe to interactions on the rendered posts so like/reply/quote/zap counts update in real-time — same pattern as the existing [`renderFeed()`](../www/post.html:1641) function that calls [`fetchExistingInteractions()`](../www/js/post-interactions.mjs:1813) and [`subscribeToInteractions()`](../www/js/post-interactions.mjs:1462).

### 11. Inline Reply Composer

The existing [`handleComposerCommentIntent()`](../www/post.html:1794) and [`handleComposerQuoteIntent()`](../www/post.html:1809) functions work by finding `.divPostItem[data-post-id="..."]` in the DOM. Since notification cards contain standard post items rendered by `renderPostItem()`, the inline composer will work automatically — no changes needed.

However, since `showPostBox` is false in notifications mode, the inline composers won't mount. We need to override this: in notifications mode, allow inline composers on notification post cards even though the top-level post box is hidden. This requires a small adjustment to [`getOrCreateInlineComposer()`](../www/post.html:1755) to check `showNotifications || showPostBox`.

## Index Page — LOVE Card

Add a new card to the [`arrApps`](../www/index.html:420) array in [`index.html`](../www/index.html) called **LOVE** that links to `post.html?notifications=true`.

The card follows the same pattern as `feed` and `view` which have special URL mappings at [line 594-598](../www/index.html:594). Add a new condition for `love`:

```javascript
{ id: `love`, svg: ``, name: `LOVE` },
```

And in the URL mapping logic:

```javascript
const url = Each.id === 'feed'
  ? './post.html?follows=true&post=false'
  : Each.id === 'view'
    ? './post.html?follows=true&post=false&viewed=true'
    : Each.id === 'love'
      ? './post.html?notifications=true'
      : `./${Each.id}.html`;
```

The SVG is left empty for now as requested.

## Files Modified

| File | Changes |
|------|---------|
| [`www/post.html`](../www/post.html) | Add `notifications` URL param, notification state, subscription, event handler branch, rendering functions, CSS, sidenav link update |
| [`www/index.html`](../www/index.html) | Add LOVE card to `arrApps` array, add URL mapping for `love` ID |

No new files needed. All logic stays inline following the existing patterns.

## Implementation Steps

1. Add `notifications=true` URL parameter parsing and mode flags in `post.html`
2. Add notification-specific CSS styles (notification header, wrapper)
3. Add notification state variables and helper functions
4. Add notification subscription in `main()` initialization
5. Add notification event processing branch in `ndkEvent` listener
6. Add notification rendering functions (createNotificationElement, renderNotificationsFeed, createNotifHeader, createCompactReference)
7. Wire See More button for notifications mode
8. Update footer to show notification count
9. Update sidenav link to use `post.html?notifications=true`
10. Allow inline composers in notifications mode (adjust showPostBox guard)
11. Wire interaction subscriptions for rendered notification post cards
12. Update the post.html header comment to document the new parameter
13. Add LOVE card to `arrApps` array in `index.html` with empty SVG
14. Add URL mapping for `love` → `post.html?notifications=true` in `index.html`
