Fifth release candidate: GIFs on every service with a picker, idle detection, YouTube and GIF cards on every service including over Tor, the tray's number counted by the window, mentions-only counts that survive a mute, and Discord mutes set on the account.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Fourth release candidate: a rebuilt tray, statuses by service, Do not disturb that silences notifications, and fixes to switching servers, Matrix rate limits and mutes, and Discord's connection.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Third release candidate: Discord forums, a redesigned interface and settings, the one-box composer, Discord's notices and read-only channels, and window recovery after a crash.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
lib/dialogs.ts watches for anything marked role=dialog aria-modal and gives it the keyboard: it takes focus when it opens, Tab and Shift+Tab stay inside the topmost one, and closing returns focus (to the message box when what had it is gone). That covers every dialog at once. Modal.tsx is the common frame - heading, X, Escape on the layer stack, growing in - and the reason prompt, the export dialog and the leave confirmation use it. The .modal-scrim stops under the title bar so the window stays draggable.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Rows, buttons and menu items fade between states on the shared durations. The fold arrow rotates instead of being swapped. A message said a moment ago arrives (fade and rise); history does not. A reaction that is new or has gone up pops. Popovers, pickers, dialogs and the switcher grow in, scrims fade, and the jump-to-present pill slides up. All of it stands still when the system asks for reduced motion.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Opened with a lot unread, the log starts at the New line rather than at the end. While that line is out of sight above, a strip along the top says how many new messages since when and offers Mark as read; clicking the words goes back to the line. The line goes where reading stopped (the time last marked read) when the conversation has not been loaded yet. The harness now sweeps up anything a run leaves behind.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
The entry animation scales the menu, so measuring it with getBoundingClientRect parked it a few pixels past the window's edge once it reached full size. The layout check caught it.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Arrow keys, Home and End move through the entries, Enter does the focused one, Tab or Escape closes it and gives focus back. role=menu and menuitem(checkbox). An entry can be checked (the status menu uses it instead of appending a tick to the label) or show its shortcut. It fades and scales in, closes when the window is left or something scrolls, and a menu button's menu opens beside the button.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Every popup, dialog and panel registers in the order it opened (lib/layers.ts) and Escape goes to the last one, not to all of them. Twenty-odd window-level Escape listeners moved onto it. Settings, Accounts, Downloads and Join close on Escape, under whatever opened over them. A field that handles Escape itself still wins.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Cancel is the quiet button next to a filled one, in every dialog; Decline on an invitation is quiet too. There is one filled red danger button, with the outline version in theme.css gone. Restart Tor and Restart daemon ask again in place.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
A 40px picture, the name with its time beside it, air above each new speaker, and the time of a follow-up line in the picture's column on hover. Classic keeps its time column and bubbles are unchanged. A mention row is amber instead of the selection blue. Quotes, code blocks and inline code have one look each. Join, part and topic lines get a mark in the picture's column so their text lines up. The New divider is a red rule with its marker at the right. The harness's rail selector uses aria-label now that tiles have no title.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Where the service reports presence each member gets their picture and a dot (idle amber, do-not-disturb red, offline a hollow ring). Clicking a member opens their profile; Shift+click, or the menu, mentions them. The Discord daemon now sends each member's avatar.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
A server tile with a mention shows how many are waiting in the corner its service mark sat in. A closed folder gets the pill and the summed count. Which folder is open is remembered. The browser's slow tooltip is replaced by an instant flyout in the app's style, the pill grows on hover, and a dashed + tile at the foot of the list opens Join. The close button goes red on hover and maximise/restore have their own glyphs.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
A pending row dims what was said, not the upload ring beside it, and a failed send has Delete beside Retry. Presence dots share one palette and one stylesheet (do-not-disturb red, offline and away a hollow ring, connecting pulsing and no longer labelled Offline), also used by the server header's connection dot. Relative times in the column are short (now, 8m, 3h, Yest, Mar 3) and age on one shared timer. Up arrow in an empty box edits your last message; the editor is multi-line, stays open when it loses focus, has a hint, and an empty save asks about deleting.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
The voice row's Disconnect is a sibling of the join button, not inside it. A folded category keeps its unread channels visible and counts what is waiting, not how many channels it has. A muted channel or server still shows a mention, and a quiet muted row dims. Toasts move to the top right so they cannot sit under or over the file panel or a verification. The typing strip always keeps its line and has animated dots. The pinned page marks each room with its service.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
It is always in the page and see-through until the row is pointed at or has focus in it, so it fades and its buttons can be tabbed to. Gone from join lines, notices and unsent messages. Your own messages get Edit; every message with text gets Copy text; the four reactions are the account's recent ones topped up with the usual. Room above the first line so it is no longer clipped.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
The row's own context menu replaced the window's, so right-clicking highlighted text offered no Copy. It now leads with Copy for the selection, then Copy text for the whole message. Discord gets Copy message link beside Open in Discord, from the daemon's existing link.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
A reply's whole preview line goes to the message it answers, bringing it into view first and saying so if it is gone. It shows the author's picture and name colour where the original is loaded. A name or avatar opens the profile card, as in Discord, Slack and Element. The highlight on a jumped-to row now fades out as well as in.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
The three rising strokes looked like phone signal but were the microphone level. It is now a bar along the panel that fills as you speak (polled ten times a second, on a square-root scale between a quiet room and loud speech), with the voice server's round trip beside the title in green, amber or red. Discord calls get a screen-share button.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Ctrl+K opens a switcher over every account's conversations: what is waiting first, then a ranked search by name and place. Alt+Up/Down move through the channel list as drawn, Alt+Shift+Up/Down to the next with something waiting, Ctrl+, opens Settings. A search button sits in the main window's title bar.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Channel rows and the header menu offer Mark as read while something is waiting. Every category heading has a menu now, with Mark as read first (custom headings keep Rename and Remove). A server tile's menu leads with it too. Escape reads the conversation you are in and goes to its end, Shift+Escape reads the server - from the message box too, but never when a menu, dialog or picker is open or another field has focus.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
A centred "Today", "Yesterday" or full date where the day changes, and on the first line drawn. Days are compared by the wall clock, and lines with no time are ignored.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Unread rows go bold with a bar at the edge. Mention badges (channel rows, rail corners, the mentions button) are red with white text instead of the selection blue. The five differently sized badges share one rule in two sizes.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Colours, shadows, layers, transition durations, radii, font sizes and weights now come from theme.css instead of literals. Timestamps and reply previews use the quieter text colour. The status dot in the join dialogs and the voice panel's mic bars no longer share class names with the avatar's presence dot and the voice recorder's level bar. Dead rules removed; icons are drawn at their own optical size. A test fails if the stylesheet uses an undefined custom property.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Seven undefined custom properties made borders fall back to the text colour (ExportDialog's dates, the emoji picker, the history gap, the voice play button); they now point at real tokens. theme.css gains visible hover/pressed/selected fills, red and amber, muted text, motion, shadow, z-index, radius, font-size and weight tokens, a keyboard focus ring and a global reduced-motion rule. Icon buttons hover neutral instead of blue.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
scripts/ui-shots.mjs photographs a fixed list of scenes from an isolated copy of the app (scratch home, its own daemon, a fake IRC server with several days of history) and records motion as mp4. Discord-shaped screens come from a test-only state hook that exists only when main is started with MOHO_UI_SHOTS=1. The launch and fake-server code is shared with the layout check in scripts/lib/harness.mjs.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
[url=X][img]X[/img][/url] pairs were collapsed to a bare URL with no separator, so two in a row became one address that loaded neither.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Second release candidate: YouTube cards for every kind of video, the formatting strip and right-click menu in the message box, typing anywhere, one # per channel row (#237, #265, #266, #267).
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Printable keys, paste and coming back to the window focus the box when nothing else is being typed into and no dialog is open, as other chat clients do.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
A strip appears over a selection offering what the service can carry: Discord Markdown (bold, italic, underline, strike, code, spoiler, quote), Matrix the subset its daemon converts, Sneedchat BBCode with colour, IRC control codes with colour, Kick nothing. The box shows the formatting; it becomes the service's markup only when sent. Ctrl+B/I/U go through the same path. IRC strikethrough and monospace now render in received messages too.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Chromium says what is misspelled and what could replace it; the window draws the menu in the app's own style: suggestions and Add to dictionary, then Undo, Redo, Cut, Copy, Paste, Delete, Select all. Every field gets it, main window and popouts alike.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Live broadcasts and unstarted premieres have no hqdefault picture; the 404 hid the whole embed. Try the live and smaller pictures, then show a dark frame. Also recognise watch links with v= after other parameters, music.youtube.com and youtube-nocookie.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>