fix: ESLint errors and Prettier formatting
CI / Build & Quality Checks (push) Successful in 10m27s
Trigger Desktop Build / trigger (push) Successful in 5s

ESLint errors:
- usePresenceUpdater: remove redundant `const userId` inside handlePageHide
  that shadowed the outer declaration (no-shadow)
- RoomViewHeader: prefix unused encryptedRoom with _ (no-unused-vars)

Prettier: reformat 14 files to match project style

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-10 22:55:32 -04:00
parent b41bfd35c0
commit 46567555e1
14 changed files with 281 additions and 215 deletions
+78 -57
View File
@@ -47,6 +47,7 @@ Last updated: June 2026.
A CRT terminal aesthetic applied globally when the TDS theme is active.
**Visual effects:**
- Scanline overlay via repeating `linear-gradient` pseudo-element
- Vignette via radial-gradient overlay
- Phosphor glow on text and accents via `text-shadow` / `box-shadow`
@@ -61,14 +62,17 @@ A CRT terminal aesthetic applied globally when the TDS theme is active.
| `--lt-text` | `#c4d9ee` | Body text |
**Typography & chrome:**
- Monospace font stack applied to all UI elements
- Terminal-style scrollbars (thin, accent-colored track)
**Decorative patterns:**
- Custom hex-grid CSS background pattern
- Circuit-board CSS background pattern (switchable)
**Boot sequence:**
- Matrix-style boot messages on the welcome page; press Escape to skip
- Implemented in `src/lotus-boot.ts`
@@ -88,6 +92,7 @@ A full light-palette counterpart to the dark TDS theme.
| `--lt-text` | `#111827` | Body text |
**Differences from dark mode:**
- CRT effects (scanlines, vignette, phosphor glow) are disabled
- Scoped to `html[data-theme="light"] body.lotusTerminalBodyClass` to avoid bleed into non-TDS themes
- `ThemeManager.tsx` is responsible for setting the `data-theme` attribute on the `<html>` element when theme changes
@@ -155,6 +160,7 @@ A "Pause Background Animations" toggle is exposed in **Settings → Appearance**
An optional frosted-glass sidebar style toggled in **Settings → Appearance**.
**Implementation:**
- `SidebarGlass` vanilla-extract class applies `background: rgba(3, 5, 8, 0.55)` and `backdropFilter: blur(12px)` to the sidebar element
- `SidebarNav.tsx` uses a `useEffect` to mirror the active chat background onto `document.body` when the glassmorphism setting is enabled, so the blur filter has meaningful content to work through
- Degrades gracefully on browsers without `backdrop-filter` support (falls back to the semi-transparent background)
@@ -166,6 +172,7 @@ An optional frosted-glass sidebar style toggled in **Settings → Appearance**.
A warm orange overlay rendered over the entire UI to reduce blue light emission.
**Implementation:**
- `NightLightOverlay` component mounted directly in `App.tsx`
- CSS: `position: fixed; inset: 0; pointer-events: none; z-index: 9998`
- Orange tint color with configurable opacity
@@ -288,6 +295,7 @@ A pill of overlapping 24px user avatars displayed at the bottom-right of each me
### "Seen by" Modal — `EventReaders`
Clicking the avatar pill opens a modal (`src/app/components/event-readers/EventReaders.tsx`) listing:
- User avatar
- Display name
- Formatted timestamp of when the receipt was recorded
@@ -299,11 +307,11 @@ Clicking the avatar pill opens a modal (`src/app/components/event-readers/EventR
Visual feedback on message delivery state, shown on the sender's own messages:
| State | Indicator |
|---|---|
| Sending (local echo) | ⟳ rotating clock icon |
| Sent (server ACK received) | ✓ checkmark |
| Failed | ✕ in red; orange glow in TDS |
| State | Indicator |
| -------------------------- | ---------------------------- |
| Sending (local echo) | ⟳ rotating clock icon |
| Sent (server ACK received) | ✓ checkmark |
| Failed | ✕ in red; orange glow in TDS |
The indicator is hidden once the server confirms the event (when the internal status transitions to `null`), keeping the timeline clean for settled messages.
@@ -316,7 +324,7 @@ The indicator is hidden once the server confirms the event (when the internal st
- Topic `formatted_body` is rendered via `sanitizeCustomHtml` + `html-react-parser`, supporting bold, italic, links, and other inline HTML
- The room header shows a plain-text preview of the topic
- Clicking the topic preview opens a full modal with the formatted body
- The room settings topic editor includes a formatting toolbar with **B**, *I*, ~~S~~, and `code` buttons
- The room settings topic editor includes a formatting toolbar with **B**, _I_, ~~S~~, and `code` buttons
### Edit History Viewer
@@ -395,21 +403,21 @@ Redacted events display "This message has been deleted" along with the redaction
`UrlPreviewCard.tsx` implements 13 domain-specific card layouts:
| Domain | Layout |
|---|---|
| YouTube | Thumbnail, title, channel, duration |
| Vimeo | Thumbnail, title, author |
| GitHub | Repo name, description, stars/forks/language |
| Twitter / X | Avatar, display name, handle, tweet body |
| Reddit | Subreddit, post title, score, comment count |
| Spotify | Album art, track/album/playlist name, artist |
| Twitch | Stream thumbnail, streamer, game, viewer count |
| Steam | Header image, game name, price, rating |
| Wikipedia | Article title, extract excerpt |
| Discord | Server name, invite metadata |
| npm | Package name, version, description, weekly downloads |
| Stack Overflow | Question title, vote/answer count, tags |
| IMDb | Poster, title, year, rating |
| Domain | Layout |
| -------------- | ---------------------------------------------------- |
| YouTube | Thumbnail, title, channel, duration |
| Vimeo | Thumbnail, title, author |
| GitHub | Repo name, description, stars/forks/language |
| Twitter / X | Avatar, display name, handle, tweet body |
| Reddit | Subreddit, post title, score, comment count |
| Spotify | Album art, track/album/playlist name, artist |
| Twitch | Stream thumbnail, streamer, game, viewer count |
| Steam | Header image, game name, price, rating |
| Wikipedia | Article title, extract excerpt |
| Discord | Server name, invite metadata |
| npm | Package name, version, description, weekly downloads |
| Stack Overflow | Question title, vote/answer count, tags |
| IMDb | Poster, title, year, rating |
Generic (non-domain-specific) cards display a Google S2 favicon. Empty or unparseable preview responses are suppressed entirely rather than showing a blank card.
@@ -436,13 +444,13 @@ Generic (non-domain-specific) cards display a Google S2 favicon. Empty or unpars
A presence status selector in the user panel offering five modes:
| Mode | Matrix broadcast |
|---|---|
| Online | `online` |
| Idle | `unavailable` |
| Mode | Matrix broadcast |
| -------------- | ----------------------------------- |
| Online | `online` |
| Idle | `unavailable` |
| Do Not Disturb | `unavailable` + `status_msg: 'dnd'` |
| Invisible | `offline` |
| Auto | Standard Matrix presence lifecycle |
| Invisible | `offline` |
| Auto | Standard Matrix presence lifecycle |
- Selection persists via the `presenceStatus` setting
- `usePresenceUpdater` short-circuits its automatic presence updates when a manual mode (anything other than Auto) is selected
@@ -457,6 +465,7 @@ A presence status selector in the user panel offering five modes:
### Presence Badges
`PresenceBadge` component displays a colored dot indicating presence state. Used in:
- Members drawer
- User settings panel
@@ -465,6 +474,7 @@ A presence status selector in the user panel offering five modes:
`PresenceRingAvatar` wraps any avatar component using `React.cloneElement` to inject an `outline: 2px solid` ring whose color maps to the user's presence state. `outlineOffset: 2px` ensures the ring sits cleanly outside the avatar regardless of the avatar's `border-radius`.
Applied in:
- Message timeline
- Members drawer
- `@mention` autocomplete dropdown
@@ -473,6 +483,7 @@ Applied in:
### Document Title Unread Count
The browser tab title updates to reflect unread state:
- `(N) Lotus Chat` — N unread messages
- `· Lotus Chat` — unread activity without a specific count
- `Lotus Chat` — no unread items
@@ -480,6 +491,7 @@ The browser tab title updates to reflect unread state:
### Extended Profile Fields
Supports MSC4133 custom profile fields via `PUT /_matrix/client/unstable/uk.tcpip.msc4133/{userId}/{field}`:
- `m.pronouns` — displayed in profile panels
- `m.tz` — IANA timezone string (e.g., `America/New_York`)
@@ -488,6 +500,7 @@ Hook: `src/app/hooks/useExtendedProfile.ts`
### User Local Time
When a user has `m.tz` set in their profile:
- Their profile panel shows a clock icon, their current local time, and the timezone abbreviation
- The displayed time updates every 60 seconds
- Respects the global `hour24Clock` setting for 12h/24h formatting
@@ -509,6 +522,7 @@ A hover toolbar appears over messages, showing the 3 most recently used emojis (
### In-App Notification Toasts
`LotusToastContainer.tsx` displays rich in-app notification toasts with:
- 24px sender avatar
- Sender display name
- Message body preview
@@ -531,6 +545,7 @@ Messages exceeding a configurable line threshold are truncated with a "Show more
### Message Send Animation
A subtle animation plays on the sender's own messages as they appear in the timeline:
- `transform: scale(0.97) → scale(1)` combined with `opacity: 0.4 → 1`
- Duration: 0.15s, ease-out
- Only applied to the current user's outgoing messages
@@ -539,6 +554,7 @@ A subtle animation plays on the sender's own messages as they appear in the time
### Right-Click Room Context Menu
Right-clicking a room in the sidebar opens a context menu with:
- **Mute** with a duration submenu: 15 minutes, 1 hour, 8 hours, 24 hours, Indefinite
- **Copy Room Link** — copies the `matrix.to` URI to clipboard
- **Mark as Read** — marks all events in the room as read
@@ -558,6 +574,7 @@ A text input at the top of the room list filters rooms by display name in real t
### DM Last Message Preview
Direct message entries in the sidebar show:
- A 48-character truncated preview of the last message body
- A relative timestamp (e.g., "2m ago")
- Reactivity via `useRoomLatestRenderedEvent`
@@ -566,6 +583,7 @@ Direct message entries in the sidebar show:
### Room Sort Order
The room list sort order can be configured in **Settings → Appearance**:
- Recent Activity (default)
- A → Z (alphabetical)
- Unread First
@@ -582,6 +600,7 @@ Persists via the `homeRoomSort` setting.
### Invite Link + QR Code
`RoomShareInvite.tsx` provides a shareable invite UI:
- 160×160px QR code generated via `api.qrserver.com`
- "Copy Link" button to copy the `matrix.to` URI
- Also accessible via a toggle button (⊞) in the Invite modal
@@ -643,6 +662,7 @@ Users can individually show or hide each composer toolbar button in **Settings
- **HTML** — styled, self-contained page
Features:
- Optional date range filter
- Progress indicator during export
- Uses `mx.paginateEventTimeline()` to retrieve history in chunks
@@ -747,6 +767,7 @@ Three one-tap presets at the top of **Settings → Notifications** that apply a
### Server Notices
`m.server_notice` rooms receive special treatment:
- A `Chip variant="Warning"` badge reading "Server Notice" is shown in the room header
- The composer is read-only (no message input)
- Invite, Report Room, and Room Settings menu items are hidden
@@ -760,7 +781,7 @@ Three one-tap presets at the top of **Settings → Notifications** that apply a
`mxcUrlToHttp()` calls now use the correct argument order for MSC3916 authenticated media:
```ts
mxcUrlToHttp(mx, mxcUrl, useAuthentication, width, height, 'crop')
mxcUrlToHttp(mx, mxcUrl, useAuthentication, width, height, 'crop');
```
The `useAuthentication` parameter was previously mispositioned, causing unauthenticated requests to be sent for media in rooms that required authentication.
@@ -787,32 +808,32 @@ The `encUrlPreview` setting defaults to `true` rather than `false`. A security a
## Key Custom Files
| File | Purpose |
|---|---|
| `src/lotus-terminal.css.ts` | TDS CSS variable definitions, scanline/vignette effects, dark + light palette tokens |
| `src/lotus-boot.ts` | Matrix-style boot sequence animation on the welcome page |
| `src/app/hooks/useRoomReadPositions.ts` | Reactive hook returning `Map<eventId, userId[]>` for per-message read receipts |
| `src/app/features/room/ReadPositionsContext.ts` | React context providing read positions map to timeline components |
| `src/app/components/read-receipt-avatars/` | `ReadReceiptAvatars` component — overlapping avatar pill with overflow count |
| `src/app/components/event-readers/EventReaders.tsx` | "Seen by" modal listing readers with display name and timestamp |
| `src/app/components/GifPicker.tsx` | Giphy-powered GIF picker, TDS-styled, gated on `gifApiKey` in config |
| `src/app/features/call/CallControls.tsx` | Push to Deafen (M key), PTT visual indicator, TDS typing dots |
| `src/app/plugins/call/CallControl.ts` | `onControlMutation()` state tracking, screenshare audio mute logic, call button scoping |
| `src/app/components/CallEmbedProvider.tsx` | PiP window, draggable overlay, navigate-on-click, imperative geometry sync |
| `src/app/plugins/call/CallEmbed.ts` | `getBoundingClientRect()`-based embed positioning, ResizeObserver sync, dark mode injection |
| `src/app/plugins/millify.ts` | Named re-export of `millify` to fix Rolldown `__toESM` CJS interop bug |
| `src/app/features/room/MediaGallery.tsx` | Images/Videos/Files gallery drawer with pagination and E2EE awareness |
| `src/app/features/room/PollCreator.tsx` | Poll creation UI for stable `m.poll.start`, single/multiple choice, 210 options |
| `src/app/features/common-settings/general/RoomShareInvite.tsx` | QR code + copy link invite sharing modal |
| `src/app/utils/syntaxHighlight.ts` | TDS-aware syntax highlighter using `--lt-accent-*` inline styles |
| `src/app/features/room-settings/ExportRoomHistory.tsx` | Plain Text / JSON / HTML room history export with date range and E2EE support |
| `src/app/features/room-settings/RoomActivityLog.tsx` | Human-readable mod log for member and state change events |
| `src/app/features/room-settings/RoomServerACL.tsx` | `m.room.server_acl` editor with allow/deny lists and wildcard validation |
| `src/app/features/room-settings/RoomInsights.tsx` | Room stats: top members, top reactions, media breakdown, activity heatmap |
| `src/app/features/bookmarks/BookmarksPanel.tsx` | Bookmarks sidebar panel backed by `io.lotus.bookmarks` account data |
| `src/app/hooks/useBookmarks.ts` | Hook for reading and mutating the bookmarks account data entry |
| `src/app/features/room/ScheduleMessageModal.tsx` | MSC4140 delayed event scheduling UI with date/time picker |
| `src/app/utils/scheduledMessages.ts` | Helpers for creating, listing, and cancelling MSC4140 delayed events |
| `src/app/hooks/useExtendedProfile.ts` | MSC4133 extended profile fields (`m.pronouns`, `m.tz`) read/write |
| `src/app/hooks/useLocalTime.ts` | Derives current local time from `m.tz` profile field, updates every 60s |
| `src/app/components/url-preview/UrlPreviewCard.tsx` | 13 domain-specific URL preview layouts plus generic fallback with favicon |
| File | Purpose |
| -------------------------------------------------------------- | ------------------------------------------------------------------------------------------- |
| `src/lotus-terminal.css.ts` | TDS CSS variable definitions, scanline/vignette effects, dark + light palette tokens |
| `src/lotus-boot.ts` | Matrix-style boot sequence animation on the welcome page |
| `src/app/hooks/useRoomReadPositions.ts` | Reactive hook returning `Map<eventId, userId[]>` for per-message read receipts |
| `src/app/features/room/ReadPositionsContext.ts` | React context providing read positions map to timeline components |
| `src/app/components/read-receipt-avatars/` | `ReadReceiptAvatars` component — overlapping avatar pill with overflow count |
| `src/app/components/event-readers/EventReaders.tsx` | "Seen by" modal listing readers with display name and timestamp |
| `src/app/components/GifPicker.tsx` | Giphy-powered GIF picker, TDS-styled, gated on `gifApiKey` in config |
| `src/app/features/call/CallControls.tsx` | Push to Deafen (M key), PTT visual indicator, TDS typing dots |
| `src/app/plugins/call/CallControl.ts` | `onControlMutation()` state tracking, screenshare audio mute logic, call button scoping |
| `src/app/components/CallEmbedProvider.tsx` | PiP window, draggable overlay, navigate-on-click, imperative geometry sync |
| `src/app/plugins/call/CallEmbed.ts` | `getBoundingClientRect()`-based embed positioning, ResizeObserver sync, dark mode injection |
| `src/app/plugins/millify.ts` | Named re-export of `millify` to fix Rolldown `__toESM` CJS interop bug |
| `src/app/features/room/MediaGallery.tsx` | Images/Videos/Files gallery drawer with pagination and E2EE awareness |
| `src/app/features/room/PollCreator.tsx` | Poll creation UI for stable `m.poll.start`, single/multiple choice, 210 options |
| `src/app/features/common-settings/general/RoomShareInvite.tsx` | QR code + copy link invite sharing modal |
| `src/app/utils/syntaxHighlight.ts` | TDS-aware syntax highlighter using `--lt-accent-*` inline styles |
| `src/app/features/room-settings/ExportRoomHistory.tsx` | Plain Text / JSON / HTML room history export with date range and E2EE support |
| `src/app/features/room-settings/RoomActivityLog.tsx` | Human-readable mod log for member and state change events |
| `src/app/features/room-settings/RoomServerACL.tsx` | `m.room.server_acl` editor with allow/deny lists and wildcard validation |
| `src/app/features/room-settings/RoomInsights.tsx` | Room stats: top members, top reactions, media breakdown, activity heatmap |
| `src/app/features/bookmarks/BookmarksPanel.tsx` | Bookmarks sidebar panel backed by `io.lotus.bookmarks` account data |
| `src/app/hooks/useBookmarks.ts` | Hook for reading and mutating the bookmarks account data entry |
| `src/app/features/room/ScheduleMessageModal.tsx` | MSC4140 delayed event scheduling UI with date/time picker |
| `src/app/utils/scheduledMessages.ts` | Helpers for creating, listing, and cancelling MSC4140 delayed events |
| `src/app/hooks/useExtendedProfile.ts` | MSC4133 extended profile fields (`m.pronouns`, `m.tz`) read/write |
| `src/app/hooks/useLocalTime.ts` | Derives current local time from `m.tz` profile field, updates every 60s |
| `src/app/components/url-preview/UrlPreviewCard.tsx` | 13 domain-specific URL preview layouts plus generic fallback with favicon |