From 5d525d42468dcb90108631c50ea6c261b2cabc6f Mon Sep 17 00:00:00 2001 From: Jared Vititoe Date: Fri, 5 Jun 2026 00:33:51 -0400 Subject: [PATCH] docs: update TODO and README for ring fix, E2EE edit history fix, reaction count MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - P5-17: 5 → 3 emoji count - P5-18: box-shadow/borderRadius → outline/cloneElement implementation note - P0-6 edit history: document getClearContent() E2EE fix Co-Authored-By: Claude Sonnet 4.6 --- LOTUS_TODO.md | 6 +++--- README.md | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/LOTUS_TODO.md b/LOTUS_TODO.md index 9df7c16d2..18b342612 100644 --- a/LOTUS_TODO.md +++ b/LOTUS_TODO.md @@ -258,7 +258,7 @@ Parse the `contacts` array and `support_page` URL. Display in Settings → Help **What:** Click the "edited" label → popover/modal lists every prior version with timestamps. Fetch via `GET /_matrix/client/v1/rooms/{roomId}/relations/{eventId}/m.replace`. Show each version's body + timestamp. Use folds `Overlay`+`Modal` pattern. **Where:** `src/app/features/room/message/Message.tsx` — find where "edited" label renders (line ~1231) and add onClick handler that opens the history modal. **Complexity:** Low — one API call, display list. -**COMPLETED June 2026.** `EditHistoryModal.tsx` — fetches via raw fetch to `/_matrix/client/v1/rooms/.../relations/.../m.replace` (v1, not v3 — Synapse only supports relations at v1). `isRawEditEvent` type guard, `next_batch` truncation indicator (50-edit limit). Formatted HTML rendered via `sanitizeCustomHtml` + `html-react-parser` with Linkify fallback. `role="dialog"` + `aria-modal` accessibility. **Critical fix:** "Original" entry uses `mEvent.event.content` (raw server data) not `mEvent.getContent()` (SDK returns post-edit content after applying replacements) — prevents original and edit-1 showing identical text. +**COMPLETED June 2026.** `EditHistoryModal.tsx` — fetches via raw fetch to `/_matrix/client/v1/rooms/.../relations/.../m.replace` (v1, not v3 — Synapse only supports relations at v1). `isRawEditEvent` type guard, `next_batch` truncation indicator (50-edit limit). Formatted HTML rendered via `sanitizeCustomHtml` + `html-react-parser` with Linkify fallback. `role="dialog"` + `aria-modal` accessibility. **E2EE fix (June 2026):** "Original" entry now uses `evt.getClearContent()` (SDK public method returning decrypted content, bypassing `_replacingEvent`) with fallback to `evt.event.content` for unencrypted events. Previously used only `evt.event.content` which is still the raw ciphertext for E2EE messages — no `body` field → "(no text)" shown for almost all encrypted originals. --- @@ -1108,7 +1108,7 @@ Themes: **[AUDIT REQUIRED]** Find the message hover toolbar in `Message.tsx` and confirm how to inject an additional row without breaking layout. Confirm recent emoji tracking mechanism in EmojiBoard. **Complexity:** Medium. -**COMPLETED June 2026.** `MessageQuickReactions` component (already existed) moved from the 3-dots PopOut menu into the main hover toolbar in `Message.tsx`. Now renders directly on hover between the "Add Reaction" emoji-board button and the "Reply" button, guarded by `canSendReaction`. Limit increased from 4 to 5 recent emojis (`useRecentEmoji(mx, 5)`). The `` separator (appropriate in menu context only) removed from the component. `setEmojiBoardAnchor(undefined)` added to the toolbar callback so clicking a quick reaction also closes any open emoji picker. Removed from 3-dots menu entirely (was redundant). Emoji source: Matrix account data `ElementRecentEmoji`, sorted by usage count. +**COMPLETED June 2026.** `MessageQuickReactions` component (already existed) moved from the 3-dots PopOut menu into the main hover toolbar in `Message.tsx`. Now renders directly on hover between the "Add Reaction" emoji-board button and the "Reply" button, guarded by `canSendReaction`. Limit set to 3 recent emojis (`useRecentEmoji(mx, 3)`) — 5 was tried but made the toolbar too wide. The `` separator (appropriate in menu context only) removed from the component. `setEmojiBoardAnchor(undefined)` added to the toolbar callback so clicking a quick reaction also closes any open emoji picker. Removed from 3-dots menu entirely (was redundant). Emoji source: Matrix account data `ElementRecentEmoji`, sorted by usage count. --- @@ -1118,7 +1118,7 @@ Themes: **[AUDIT REQUIRED]** Check existing `PresenceBadge` component — this extends that concept to the avatar border. Verify folds Avatar allows border/shadow styling. **Complexity:** Low-Medium. -**COMPLETED June 2026.** New `PresenceRingAvatar` wrapper component (`src/app/components/presence/PresenceRingAvatar.tsx`) — calls `useUserPresence(userId)` internally, applies `boxShadow: 0 0 0 2px ` + `borderRadius: 50%` on a transparent `inline-flex` wrapper div. Ring colors: `color.Success.Main` (online), `color.Warning.Main` (unavailable/idle), `color.Critical.Main` (DND — detected via `presence.status === 'dnd'`), no ring (offline). Applied to: message timeline sender avatars (`Message.tsx`), members drawer member + knock-request avatars (`MembersDrawer.tsx`), @mention autocomplete suggestions (`UserMentionAutocomplete.tsx`), and inbox notification sender avatars (`Notifications.tsx`). Exported via `src/app/components/presence/index.ts`. +**COMPLETED June 2026.** New `PresenceRingAvatar` wrapper component (`src/app/components/presence/PresenceRingAvatar.tsx`) — calls `useUserPresence(userId)` internally. Uses `React.cloneElement` to inject `outline: 2px solid ` + `outlineOffset: 2px` directly onto the child `Avatar` element so the ring follows the avatar's actual `border-radius` rather than being forced circular. Ring colors: `color.Success.Main` (online), `color.Warning.Main` (unavailable/idle), `color.Critical.Main` (DND — detected via `presence.status === 'dnd'`), no ring (offline). Applied to: message timeline sender avatars (`Message.tsx`), members drawer member + knock-request avatars (`MembersDrawer.tsx`), @mention autocomplete suggestions (`UserMentionAutocomplete.tsx`), and inbox notification sender avatars (`Notifications.tsx`). Exported via `src/app/components/presence/index.ts`. --- diff --git a/README.md b/README.md index 7ad5e71b4..d3f52e64f 100644 --- a/README.md +++ b/README.md @@ -75,7 +75,7 @@ A full custom theme engine layered on top of Cinny's vanilla-extract theming: ### Messaging Enhancements - **Rich room topics**: Room topics that contain formatted text (bold, links, italic) are now rendered with full HTML formatting. Falls back to plain text if no `formatted_body` is present. Activates when any room admin sets a formatted topic. -- **Edit history viewer**: Clicking the "edited" label on any edited message opens a modal showing every prior version with timestamps. Fetches all `m.replace` relations for the event and displays them oldest-to-newest. Previously the "edited" label was visible but unclickable. +- **Edit history viewer**: Clicking the "edited" label on any edited message opens a modal showing every prior version with timestamps. Fetches all `m.replace` relations for the event and displays them oldest-to-newest. Previously the "edited" label was visible but unclickable. E2EE fix: the "Original" entry now uses `getClearContent()` (bypasses the replacing-event chain, returns the decrypted pre-edit body) instead of `event.content` which is still raw ciphertext for encrypted messages — fixes "(no text)" shown for almost all E2EE message originals. - **Inline GIF preview**: Giphy and Tenor share links sent as plain text auto-embed as animated GIFs inline in the timeline. URL patterns are detected client-side; the image is fetched via the homeserver's `/_matrix/media/v3/preview_url` proxy (no direct contact with Giphy/Tenor from the client). Rendered as `` — respects the existing URL preview enabled/disabled setting. - **GIF picker**: Giphy-powered GIF search and send. Button appears in the message composer only when `gifApiKey` is set in `config.json`. Sends GIF as `m.image` — fetches blob, uploads via `mx.uploadContent`, sends with `mx.sendMessage`. `FocusTrap` handles click-outside / Escape to close. When TDS is active: dark navy background (`#060c14`), orange dim border, `// GIF_SEARCH` header, CSS overrides for Giphy SDK search bar (dark bg, orange border/focus ring, JetBrains Mono), custom orange scrollbar. All TDS styles live in `lotus-terminal.css.ts` — no runtime `