fix: ESLint errors and Prettier formatting
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:
+78
-57
@@ -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, 2–10 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, 2–10 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 |
|
||||
|
||||
Reference in New Issue
Block a user