Updated version of #4550. Closes#337, closes#872 (#337 can't be fully
addressed — tracking nick changes isn't really possible atm).
<img width="253" height="149" alt="image"
src="https://github.com/user-attachments/assets/8a961868-0aa9-406b-92e2-f9d4858e2d0d"
/>
Away support:
<img width="214" alt="image"
src="https://user-images.githubusercontent.com/8675906/165882385-6f928c8e-5a0b-4502-8bd3-3cd0bd70e0e0.png">
## Summary
Query windows show whether the person behind them is online, and whether
they are away, using
[MONITOR](https://ircv3.net/specs/extensions/monitor) rather than
polling. `Network` keeps the monitor list: queries are registered in
batched `MONITOR +` commands once RPL_ISUPPORT tells us the server
supports it, and one at a time as new query windows open. The limit
advertised in `MONITOR=<n>` is respected, with anything over it waiting
for a slot; `MONITOR=0` means no monitoring at all, a bare `MONITOR`
means no limit. A nick change on a monitored query swaps the target in
place so the query keeps its slot.
[extended-monitor](https://ircv3.net/specs/extensions/extended-monitor)
is requested too, so away, nick, account and chghost updates arrive for
monitored nicks we share no channel with. Away state for people we do
share a channel with comes from a WHO on join.
The indicator is a dot on the query in the sidebar and next to the nick
in the message bubble, with a tooltip and an `img` role so it isn't
colour-only, and it can be turned off under Appearance.
Known limitation: a server that enforces a monitor limit it doesn't
advertise will reject part of a batch with `ERR_MONLISTFULL`; the user
gets a message in the lobby, but the client's own list isn't reconciled
until reconnect.
## Test Plan
- Unit tests for the monitor list: add, case-insensitive dedupe,
queueing at the limit, removal draining the queue, batching, and the
rename path.
- Ran the server against a local IRCd and watched the wire: opening
queries sends `MONITOR + <nick>` each, a reconnect with four open
queries sends a single `MONITOR + bob,carol,dave,mallory`, 730/731 drive
the online/offline state, a rename sends `MONITOR - bob` then `MONITOR +
bob2`, `MONITOR=0` sends nothing at all, and a bare `MONITOR` behaves as
unlimited.
| | |
|--------|--------|
| <img width="2016" height="1476" alt="image"
src="https://github.com/user-attachments/assets/381036c4-f9e2-4412-b3c7-2ac3c1a1163f"
/> | <img width="1890" height="1458" alt="image"
src="https://github.com/user-attachments/assets/f7d55d77-52f8-4493-9ad5-37ca00cb051f"
/> |
| <img width="1760" height="940" alt="image"
src="https://github.com/user-attachments/assets/dacb9a5e-cf96-4f9c-bd4a-0633b2b55120"
/> | <img width="1966" height="1424" alt="image"
src="https://github.com/user-attachments/assets/110d409e-2bba-4fec-90e9-48ef2cdd5c98"
/> |
## Summary
Each settings page becomes a stack of cards with a consistent title,
intro line and toggle rows, instead of loose headings and bare
checkboxes. The shared pieces are `SettingCard.vue` and
`SettingToggle.vue`, and the styling moves out of `style.css` into
`client/css/settings.css`.
Appearance is now the landing page for `/settings` (General moves to
`/settings/general`, with a redirect so old `/settings/appearance` links
keep working). Below the width where the fixed sidebar would collide
with the centered container, the tabs collapse into a dropdown instead
of stacking above the content.
Setting names and bindings are unchanged, so nothing about how
preferences are stored or synced moves.
## Test Plan
- Ran the client and stepped through Appearance and Notifications:
toggling a switch still writes through to the settings store,
`/settings/appearance` redirects to Appearance, and the mobile dropdown
opens aligned to the card.
- Not verified in a browser: Account and General, which need a
non-public instance.
Relies on https://github.com/kiwiirc/irc-framework/pull/411https://ircv3.net/specs/client-tags/reply.html
Design feedback very welcome
<img width="1718" height="278" alt="Screenshot 2026-04-11 at 21-00-22
#thelounge — The Lounge"
src="https://github.com/user-attachments/assets/ba6e7c69-2477-4a7b-b196-901d19ca9cba"
/>
1. we lack a 'thread' view (irccloud, slack, etc). can be a followup if
we do want it
2. need to test scrolling to messages outside of the current buffer
3. due to lack of client support, i opted to auto prefill the input with
\`<targetNick>: \` so people can follow along even without reply support
4. CSS can definitely be improved (once a design is settled on)
---------
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com>
The only thing that cares about user colors is the user component.
Putting a class value on the chat component seems to be the wrong
place.
This also allows us to remove various css selectors so that we
don't need to be that specific.
After all whatever has that class needs to be colored, we don't
care where it is.
Firefox does not seem to select leading (or trailing) characters that are
too small; so this commit sets a very small width, that is still large
enough to be selected.
This commit also adds `display: inline-block`, so the width is not
ignored; but this causes Chrome to ignore the space after `>`, so I made
it a non-breakable space.
An alternative is to make only the leading `only-copy` an
`inline-block`, but I think the non-breakable space is a good idea
regardless.
When a user long touches on iOS, they will select the nearest
selectable text. This causes a distracting visual bug when reordering
the network list (which also uses a long press).