Zoom moves into a new Accessibility section (the section keeps its
section-zoom id, which layout plugins anchor to) next to:
- Message text size, 80 to 200 %, separate from Zoom: messages, threads,
forum posts, code blocks and the message boxes.
- Line spacing (normal, relaxed, loose) and letter spacing (normal, wide).
- Font: the theme's, the system's, Atkinson Hyperlegible or OpenDyslexic,
self-hosted under SIL OFL 1.1 with their licenses in /fonts.
- High contrast: secondary text and borders pulled toward each theme's own
text color, and a thick focus ring.
- Reduce motion: follow system, on or off. One html.reduce-motion class now
covers every animation, the theme effects, the shimmering role colors,
smooth scrolling, and GIFs, animated emoji and profile pictures, which
wait for hover or tap. The old prefers-reduced-motion rules use it too.
- Underline links, and larger click targets.
Everything is per device and applied by theme-init.js before first paint,
which hands the same read/apply functions to the settings page.
Also: keyboard focus rings, keyboard-reachable settings nav rows,
aria-labels on the icon buttons in the channel header and message box, and
aria-pressed on the picker buttons.
Co-authored-by: ancsemi <ancsemi@gmail.com>
All opt-in; nothing changes until someone picks a setting.
- Keep official mode on (Settings > Chat, saved on the account as
users.official_mode, every device follows through set-official-mode /
official-mode-changed). The megaphone then rests armed, so staff don't
re-arm it for every message; pressing it sends just the next message
plain. The client still sends highlight: true per message, so the wire
format and the server's checks are unchanged.
- Official messages look (Settings > Chat, per device): Badge (the default,
as before), Colored text (the text and a lighter wash in the role's color,
a thinner bar, no badge; text mixed with the theme's own text color, more
of it on light themes), or Off.
- With Colored text, consecutive official messages from one person group
into one block. Badge keeps every official message's own header.
- session-info carries features: ['highlight_messages', 'official_mode'] and
officialMode, so apps can tell what a server supports.
Cover the Layout picker contract, the unread dots (DMs vs channels, muted
channels, Haven's server counts), hooking and unhooking Haven's methods,
restoring the Join and Create sections without undoing Haven's changes,
the tab kept in plugin data, guests, the Create Temp Channel row and the
translated labels.
A forum post whose text is just a YouTube link used the raw link as its
title and had no thumbnail, and the open topic showed only the link.
The topic card now takes the title and picture from the link's preview when
the post opens with a bare link and has no typed title, and the picture goes
through the media proxy like every other remote image (posted image
thumbnails did not before). The open topic gets the same video player or
link card the post gets in chat. A typed title still wins.
YouTube previews come from YouTube's oEmbed endpoint, since the watch page
is too large for the generic scrape to reach its title and image.
Default Theme in Appearance & Welcome and the theme in Defaults for New
Members were stored separately, so a new member saw one on the sign-in page
and the other once the shared defaults applied. Sharing a theme now also sets
the Default Theme (when it is a built-in or a published custom theme),
changing the Default Theme updates the shared theme, choosing None removes it
from the shared set, and unpublishing a custom default drops it from both.
The shared version is untouched, so nobody is re-sent defaults.
A new forum_blog switch on channels (off by default), turned on and off
through the same channel permission toggle as Forum mode and NSFW, so only
someone who can change the channel's settings can flip it. The channel list
carries it.
With it on, a topic belongs to its author. A reply in the topic's thread is
part of the post when the topic author's own account wrote it (and it is not
a bot or relayed message); everything else is a comment. Nothing is stored
per message, so turning it on or off needs no migration and changes nothing
on disk. The rule lives in src/forumBlog.js.
The server works the answer out and sends it: thread history marks each reply
post_part and says the topic is a blog post, a new reply carries post_part,
and topic cards and live thread updates carry a comments count alongside the
reply count. user_id comes from the signed-in socket, so nobody can make
their reply count as the author's, and bot replies are always comments.
A new Channel Functions row for forums, "Votes on posts", picks Off (the
default), Likes, or Likes and dislikes. Anyone who can change the channel's
settings can set it.
When votes are on, every topic shows a like button with its count, plus a
dislike button when dislikes are allowed, in the list, gallery and feed views
and in the bar above an open topic. Each member has one vote per topic:
clicking it again takes it back, and liking replaces a dislike (and the other
way round). Counts update live for everyone viewing the forum without saying
who voted. Only members who can see the forum can vote, muted members cannot,
and votes are refused while the setting is Off (stored votes are kept and come
back if it is turned on again). The forum's sort menu gains "Most liked" while
votes are on.
Votes live in a new forum_votes table set up by src/forumVotes.js; the socket
handlers are in src/socketHandlers/forumVotes.js and the client side in a new
app-forum-votes.js module. Reactions are unchanged.
A new Auto-Mod setting, "New accounts must wait before posting (minutes)",
sits next to the new-account link rule. 0 (the default) turns it off; the
maximum is 10080 minutes (one week).
While an account is younger than that, the server refuses channel messages,
forum topics, attachments, thread replies, polls, scheduled messages and DMs
to other people. A DM with yourself is allowed. Admins and members at or above
the Auto-Mod exempt role level are not held back. If the check itself fails,
the post is refused rather than let through.
The refusal says how long is left, and the app puts the message (or the
forum post being written) back so nothing is lost.
An admin can store a snapshot of cosmetic settings as the server setting
member_defaults, with an allowlist of keys and value checks. Each member
receives the theme and effects part once, only where they never saved
that setting themselves or still have what an earlier set put there.
Apply to everyone raises a version so members get the set once more.
Server templates carry the snapshot without the version.
Every group message made two extra round trips first. The member list
and keys are now kept until membership changes, a new key is published,
a key is re-shared, someone's keys are trusted, or the connection drops.
Only the last-member-leaves path cleaned up a group's key, epoch, invite
and rewrap rows. That cleanup now lives in the shared DM delete, so every
way a group is deleted removes them.
The server relays every group key, so it could forge a rewrap request and
collect the group key from everyone online, or plant an epoch key of its
own. Now a device wraps the group key only for the encryption key it has
pinned for that person (the same pins 1:1 DMs use), accepts a wrapped key
only from a sender whose pinned key opens it, and requires each epoch to
carry a statement signed by the member who published it, naming the key,
the group, the epoch and exactly who it was shared with. Signing keys are
pinned on first sight too. When someone's keys change, Haven asks before
trusting them, as 1:1 DMs do, and until then the group key is not shared
with the new keys and messages signed with them stay hidden. Groups whose
current key predates this are rotated to a signed one automatically.
Only the sender's current signing key was tried, so a key reset turned
everything they had sent before into "could not be verified". The server
now keeps every signing key a person has published, and a message shows
when it verifies under any of them. A message that verifies under none of
its author's recorded keys is still hidden.
Setup ran twice at once on every connect and each run accepted any
published reply, so a new account could save one key to its backup while
the server kept another, and everyone then saw that person's group
messages as unverifiable. Setup is now shared by every caller, replies
carry a request id, and the key and its backup are stored in one step.
Another device racing on a new account adopts the winner's key.