ForwardMessageDialog:
- Room list now shows small avatars (48px crop) + DM label beneath room name
- Forward is now async: spinner overlay while in-flight, '✓ Forwarded' only
shown after sendEvent resolves; error clears sending state so user can retry
- Search bar hidden in success state for cleaner confirmation view
DeliveryStatus:
- QUEUED state used ⏳ emoji breaking the ASCII/terminal aesthetic; changed
to ⟳ matching the SENDING/ENCRYPTING icon
PollContent:
- Added data-poll-content + data-poll-answer + data-selected attributes so
TDS CSS can override inline styles without JS branching
- Added data-poll-content-label on the ◉ Poll header
- TDS dark: answers get cyan dim bg/border, selected gets orange highlight
with subtle box-shadow; hover brightens border; label uses cyan glow
- TDS light: equivalent blue/orange variants
Caption input:
- Marked with data-caption-input; focus-visible ring added in index.css
(blue for default, dark-theme dark blue) and lotus-terminal.css.ts
(orange glow for TDS dark, orange for TDS light)
Boot sequence:
- Added '[ ESC ] skip' hint at bottom-right of overlay so users know
they can dismiss it without waiting
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- CallControls: screenshare confirm now closes on Escape or click-outside
(transparent fixed backdrop + window keydown listener); cleaned indentation
- GifPicker: TDS header rendered a JSX comment ({/* GIF_SEARCH */}) so the
// GIF_SEARCH label was invisible; changed to {'// GIF_SEARCH'}
- CallEmbedProvider: PiP resize clamping now works at initial bottom/right
position by normalising to top/left before parsing el.style.left
- CallEmbedProvider: incoming call subtitle now reads 'Incoming Video Call'
or 'Incoming Voice Call' based on m.call.intent
- PollContent: progress bar background now uses --bg-surface-active /
--bg-surface-low instead of hardcoded white (invisible in light mode)
- index.css + lotus-terminal.css.ts: define --bg-surface, --bg-surface-low,
--bg-surface-active, --bg-surface-border, --text-primary as global CSS vars
with vanilla fallbacks and TDS dark/light overrides; these were used by
poll, location map, upload card and GIF picker but never defined
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Prettier: auto-formatted 103 files to fix baseline. Prettier check in CI
is now a hard gate (removed continue-on-error).
Brotli: installed libnginx-mod-http-brotli-filter/static. Enabled in nginx
with brotli_static on for pre-compressed assets and comp_level 6.
Sentry releases: deploy script now exports VITE_APP_VERSION=<git-short-sha>
before building so each Sentry release maps to an exact commit.
CI also passes github.sha as VITE_APP_VERSION.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
BUG-18: clearTimeout cleanup in focusItem useLayoutEffect prevents leaked timers
BUG-24: Room timeline listener catches first poll vote before Relations object exists
BUG-25: Use timelineRef.current in handleOpenEvent to prevent stale index on rapid navigation
Perf-6: React.lazy + Suspense for GifPicker and EmojiBoard (initial bundle -114 kB)
Perf-7: React.memo on RoomNavItem to prevent re-renders on unrelated state
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
PollContent now:
- Reads existing m.poll.response / org.matrix.msc3381.poll.response events
from the room timeline on mount to restore vote state across refreshes
- Counts votes per answer (per-sender latest-wins deduplication)
- Shows percentage bars and vote totals in real time
- Subscribes to RelationsEvent.Add/Remove/Redaction so counts update live
when other users vote without requiring a page reload
- Optimistic local update keeps the UI snappy while the send request flies
- ForwardMessageDialog: use sendEvent instead of sendMessage to preserve
the original event type (stickers, polls, etc.)
- PollContent: use m.selections for stable m.poll.response (per spec),
was incorrectly using m.responses
- Poll voting: PollContent sends m.poll.response on answer click
- Location: MLocation shows OSM map embed + share-location button in toolbar
- Image captions: caption field on media uploads sets message body
- Message forwarding: ForwardMessageDialog with searchable room picker
- Also includes ring timeout fix and earlier session patches
Bug fixes:
- IncomingCallNotification: track ring setTimeout ID and clear it on
cleanup/dismiss — prevents orphaned callbacks after unmount
- RoomTimeline: allow redacted m.room.message, m.room.encrypted and
m.sticker events past the early-return filter so they hit the
existing RedactedContent renderer showing the trash-icon placeholder
New features:
- PollContent component: read-only display of m.poll.start and
org.matrix.msc3381.poll.start events (both stable Matrix 1.7 and
MSC3381 unstable content keys); renders poll question + answer
options inside the standard Message bubble; registered both as
top-level event renderers and inside EncryptedContent callback
so encrypted polls also render after decryption
- Deleted message placeholder: m.room.message and m.room.encrypted
redacted events now show the existing MessageDeletedContent
component (trash icon + italic notice) instead of disappearing
entirely — matches Element, FluffyChat, Commet, Nheko behaviour