- Read states store: smarter hasUnread compares against latest message
- ConversationList: orange dot + bold name for unread DMs
- DMChat: auto-mark-read when viewing conversation
- WS handler: mark DM read on new message while active+focused
FormatToolbar component: B I S ` || buttons that wrap selected text
with markdown syntax. Added to both channel and DM input areas.
Keyboard shortcuts: Ctrl+B bold, Ctrl+I italic already work via
browser defaults on the rendered markdown.
- Added GiphyPicker to DM input area (toggle with [GIF] button)
- Added EmojiPicker/kaomoji to DMs (toggle with [☺] or Ctrl+E)
- GiphyPicker shows above input when toggled
- Kaomoji appends to input text
- Mobile (<md): single-panel view, sidebar/chat/members as overlays
- Hamburger button toggles sidebar overlay (ServerBar + ChannelList)
- Members button toggles MemberList overlay
- ← back button in ChatArea and DMChat headers returns to sidebar
- Auto-switch to chat view when channel or DM is selected
- Tap empty area to dismiss overlays
- Desktop layout unchanged (all panels side by side)
- Status/settings buttons hidden on small screens to save space
Wired existing typing store (backend WS broadcast + frontend
_handleTypingEvent with 3s auto-expiry) into ChatArea and DMChat.
Typing events throttled to once per 3s. Shows 'X is typing...' or
'X and N others are typing...' below the messages, above the input.
Both ChatArea and DMChat now detect when you scroll near the top
and fetch the next 50 older messages. Scroll position is preserved
so you don't lose your place. Works for both server channels and
DM conversations.