Settings sections now sit in the same order as the nav on both the user and admin panels, so clicking down the nav scrolls in one direction instead of jumping around. Admin settings get the same scroll spy the user settings had, a Terms of Service nav entry, and icons and names that match their sections. Fixes#5576.
Layout settings gain a Channel Scrolling choice: separate scrollbars for channels and DMs, or one for the whole sidebar. Short windows fall back to the combined layout so the channel controls stay reachable. The Layout section is split into Density and Channel Scrolling subsections, and the picker setup code is shared. Thanks to @birdcrazy.
Braid shipped one spacing. Settings → Braid spacing (and Menu → Braid
spacing, which cycles without closing the menu) now offers Compact, Cozy
and Spacious. Cozy is exactly what shipped, so the two new levels go in
both directions: the same eight messages measure 417 / 513 / 617 px.
The scale is tokens on html[data-braid-density], read by both the form
and layout sheets, so message runs and channel rows tighten together
along with the sidebar width. Corner radii are deliberately left out of
the scale — this is a density control, not a shape one, and the cards
measure an identical 14px (12px for channel rows) at all three levels.
--braid-gutter is now derived as inset + avatar + row gap rather than
hardcoded. A continuation indents by exactly its leader's gutter, so a
level that shrinks the avatar can no longer drift a run out of line with
its own first message. Measured 0px drift at all three levels.
The Android App badge kept a hardcoded white label. It cannot follow
--accent-text because it paints itself a fixed Android-green gradient in
every theme, so white sat at 1.78:1 at the light end of that gradient.
It and its dismiss button now use an ink that measures 9.65:1 there and
6.46:1 at the dark end.
Co-authored-by: ancsemi <ancsemi@gmail.com>
* fix(braid): keep main channels out of sub-channel cards
_markRuns marked a channel card run from "is my neighbour also a
.channel-item", with no notion of parentage, so any unbroken run of rows
became one card. The first main channel after another channel's
sub-channels continued their card, and read as belonging to a tag it has
no relation to. Reported on both the web client and the Android app.
A card is now a family: siblings under one parent, or a parent followed
by its own subs. famOf() keys a sub row by dataset.parentId and a main
row by "main". joinsRun() continues a run only inside one key, or from a
parent into its own subs, so sub -> main always breaks the card. The
sub-tag-label row carries the same parentId, so a tag stays with the
subs it labels.
Version 1.7 -> 1.8.
* fix(braid): a main channel always starts its own card
Follow-up to review: the first rule still let two adjacent main channels
share a card. A main channel now always begins a new group, so it can
never sit inside a run that reads as a sub-channel family. A card is a
main channel plus its own subs, or a run of sibling subs, or the DM list.
joinsRun() continues a run only into a sub row: from that sub's parent,
or from a sibling sub with the same parentId. Anything into a main row
breaks. DM rows keep grouping among themselves.
* fix(braid): a tag header takes over the grouping, so its channels read flat
Matches the Android app. When sub-channels are re-grouped under their own
tag header, the header already carries the grouping, so indenting the rows
under it as well claims the sub arrow for channels that only look nested
because of where they sit.
Rows the core marks with data-sub-tag (exactly those under a tag label)
get data-braid-flat, and the arrow is painted over with # in Braid form.
Private subs keep their lock, since only a literal arrow is replaced, and
a sub shown directly beneath its parent with no header still keeps it.
Purely cosmetic and scoped to data-braid-form, so toggling the form off
restores the original glyph with no DOM left behind.
Reported by birdycrazy: the layout "seems to completely remove the ability
to join or create channels", and the Encryption menu entry does nothing.
Both are real. Join and Create were not merely collapsed — they could not
be reopened at all.
_collapseJoinCreate() added its own `braid-collapsed` class to the section
alongside the stock `.collapsed` class on the body, and the stylesheet hid
`.braid-collapsed .collapsible-section-body` with !important. Nothing ever
removed that class, so the stock toggle went on flipping `.collapsed`
underneath while the body stayed hidden. Traced live: clicking the header
moves the stock class exactly as it should, computed display stays `none`,
and dropping `braid-collapsed` by hand returns it to `block`. That left an
admin unable to create a channel and everyone unable to join one for as
long as the layout was on.
Visibility now comes only from the stock class, which the collapse helper
still sets, so the sections keep opening collapsed and the header reopens
them.
The Encryption entry proxied a click to #e2e-menu-btn, whose handler only
toggles #e2e-dropdown. That dropdown lives inside #e2e-menu-wrapper, which
the app sets to display:none outside a DM — so in a normal channel the
entry appeared and did nothing whatsoever. Inside a DM it fared no better:
this layout hides the header chrome the dropdown anchors to, and the click
that opened it kept bubbling to the document handler that closes it again.
Proxy the three actions instead — Verify encryption, Recover keys, Reset
keys — each of which opens its own modal and does not depend on the
dropdown. The menu is built once, so they are marked and resolved when it
opens: shown where encryption applies, hidden everywhere else.
Theme respect (reported: 'braid layout is not properly respecting the
other themes'):
- --braid-bub (message-card / channel-card surface) was derived from
--bg-hover. On themes where hover is a full-contrast selection color
(win95's navy), every card painted as a permanent highlight and text
went illegible. Now mixed from text-primary over bg-secondary (5%),
which reads as a subtle card on every palette; hover states follow the
same recipe instead of --bg-active.
- All cosmetic shape rules (radii, decorative borders/shadows on
messages, buttons, modals, menus, toasts, reactions, code, inputs)
moved to :where() with no !important: they still override the base
stylesheet, but any [data-theme=...] rule now wins — win95 keeps its
square corners, themes keep their identity.
- Server strip: glyphs sitting on an accent tile (home, hover) use
--bg-primary so they stay visible on themes where accent equals
text-primary (matrix/fallout/crt terminal-glow palettes).
Server logo (reported: 'the server logo is becoming the background of
the server select tiles'):
- The admin-set icon is injected into #home-server as a bare classless
<img> with no CSS anywhere, so it rendered at natural size and
sprawled behind the neighboring tiles. style.css now constrains any
direct img child of .server-icon (100%/cover/inherit radius) — fixes
the stock vertical rail too — and the Braid strip carries the same
rule.
Verified live under the Braid layout across matrix (canary for
accent==text themes), win95, daylight, ffx: cards readable, square
corners preserved on win95, home glyph visible on matrix; a 512x512
injected logo renders contained at tile size with strip height
unchanged.
* Braid Layout v1.5: multi-server strip fix, voice dock with streaming options, one-click layout toggle
- Server strip: #server-list flexed inline so multiple servers keep one row;
vertical separator, compact utility buttons, hidden scrollbar
- Voice dock: relocate #voice-panel + #voice-settings-panel (screen share
resolution/fps pickers included) bottom-left with both mute/deafen pairs
and a People toggle; LIFO restore on suspend/disengage
- Layout toggle: engage/disengage split with persisted preference; Braid
hexagon switch lives IN the classic bottom bar next to themes; themes +
classic buttons beside the Menu under Braid; Ctrl+Shift+B (and Ctrl+Alt+B)
- Mod Mode: floating 'Done editing layout' exit, drag-handle leak fixed,
return switch hidden while editing
- Feedback round: join/create back on top, roomier message cards, contrast
tokens for buttons in light AND dark palettes, icon menu with short labels,
sidebar resize unlocked (stock inline width wins again)
* Braid Layout v1.5: calmer message-input focus ring
* Fail loudly when the server port cannot be bound, and stop refusing Node 24
A failed bind (EADDRINUSE/EACCES/EADDRNOTAVAIL) surfaces as an async
'error' event on the HTTP server. With no listener there, it fell
through to the global uncaughtException keep-alive, which logged it to
crash.log and kept a process alive that never got its socket: no
banner, no exit code, and Start Haven.bat's netstat readiness probe
was satisfied by the stale port-holder — so launches died silently.
Reproduced on 3.39.0 by double-launching; %APPDATA%\Haven\crash.log
shows the same swallowed EADDRINUSE in the wild.
- server.js: bind failures on the main listener are now fatal and
explain themselves (which port, why, what to do) before exit 1.
Other server errors keep the existing keep-alive behaviour.
- server.js: the HTTP->HTTPS redirect listener (port+1) warns and
continues instead of feeding the same silent uncaught path.
- Start Haven.bat: the hard Node >=24 refusal is gone — Node 24 is
current LTS and better-sqlite3 12.10.0 ships prebuilds for it
(verified working). The honest gate is a functional
require('better-sqlite3') check after npm install; >=25 warns.
- package.json/lock: engines widened to >=18 <25 (lock version also
synced from stale 3.31.2).
* Add Braid themes (dark/light) and the Braid Layout plugin
Ports the Braid look from the Amni-Haven mobile app to the web and
desktop clients, as pure opt-ins riding the existing rails — no core
file changes:
- themes/braid.theme.css / braid-light.theme.css: the mobile BRAID /
BRAID_LIGHT palettes (mint on slate / deep green on white) with the
1.6x-rounder shape language. Unpublished by default; admins opt in
via Settings -> Custom Themes, exactly like any file theme.
- plugins/BraidLayout.plugin.js: the 'vastly simplified' two-edge
layout — folds the server rail (including manage/sync) into a strip
atop the sidebar, tucks header extras into a kebab menu, and uses
the full width for messages. Every stock feature stays reachable:
the kebab proxies search/pins/gallery/channel code/encryption/
settings and adds People, Soundboard, Status bar, and app-download
entries for the chrome it hides. A separate variable-driven shape
layer applies the Braid format (radii, blur, focus rings) on top of
ANY active theme, so all built-in themes reskin the Braid layout
with their own palette. start()/stop() fully applies and fully
restores (DOM, styles, listeners, localStorage); the
MutationObserver is childList-only and only mutates
styles/attributes, so it cannot observe its own writes.
All sizes are rem so the interface Zoom slider scales Braid chrome
together with the rest of the UI. prefers-reduced-motion disables the
motion layer outright.
* Braid Layout: mobile-parity chat cards and condensed chrome
Feedback round: the flat message list didn't carry the mobile Braid
shape language, and leftover strips still read as four-edge chrome.
- Merged run cards (desktop twin of Haven-Mobile's braidForm): a run of
same-author posts becomes one bordered card on .message-body, dashed
seams between posts, avatar and hover-timestamp in the gutter, own
messages tinted with the accent. Run position comes from O(n)
data-braid-run marking in the existing observer batch — NOT
:has(+ .message-compact), which makes Chromium re-run invalidation
per sibling insert and sent a 600-message channel load quadratic.
Channel list runs are carded the same way.
- Condensed chrome: the topic bar folds into the header band as a
quiet subtitle (no second border strip), header drops to 3rem,
sidebar footer and composer tighten, media buttons shrink to 2rem.
- All gutter math is rem (.625 pad + 2.25 avatar + .75 gap = 3.625rem)
so cards and compacts stay aligned under interface zoom.
* Braid Layout v1.2: Mod Mode interop, themed icons, modern settings, subtler seams
- Mod Mode (the layout editor) is now fully functional with Braid on:
the layer suspends itself while body.mod-mode-on is set — gates come
off and the server rail unfolds so every draggable section and panel
handle is real — and re-applies when editing ends. A saved custom
section order wins over Braid's default join/create-at-bottom
ordering (the order rules load only when no haven-layout is stored).
'Edit layout' joins the kebab menu.
- The bottom-left emoji buttons (theme/activities/members/settings/
donate/mute/deafen) become currentColor line icons so they follow the
palette like the rest of the chrome; originals restore on disable.
- Modern settings: nav rail becomes grouped pills with an accent-tinted
active state, each settings section becomes a rounded card (the
inline border-top hairlines between sections retire), header gets the
blur band + pill tabs treatment.
- The seam between same-author posts shrinks to a centered dotted
hairline (min(7rem,45%)) instead of a full-width dashed rule.
* Braid Layout v1.3: true author-run merging, hamburger menu, text sliders, hex loader, logo glow
- Message merging now chains on AUTHOR: consecutive posts by the same
user merge into one card even when the app rendered them as separate
full .message elements (persona changes, break_chain, and system
notices still split). Continuing messages hide their avatar/header
and surface their own timestamp in the gutter on hover
(data-time-short). The visible full-width divider is gone — bodies
inside a run no longer draw internal horizontal borders, so the only
separator is the small centered dotted seam.
- One animated hamburger (morphs to an X) replaces both the header
kebab and the bottom-left icon bar: grouped Channel / View / App menu
with staggered item animation. The menu mounts on <body> — the
blurred header is a containing block with overflow:hidden that clips
even position:fixed descendants. Every absorbed feature keeps its
door (themes, activities, members, settings, donate, apps, Mod Mode).
- Braid text size: two continuous sliders in Settings (chat text
80-160%, interface text 85-140%) layered over rem zoom, live-applied
via CSS vars and persisted per user.
- The brand hexagon gets an accent glow that breathes (and a slow spin
on hover); a hexagonal loading indicator appears on channel switches
and reskins the setup wizard's circular spinner. All animations
respect prefers-reduced-motion.
- Braid / Braid Light themes: type & color enforcement pass — the font
stack and palette land over style.css's per-element declarations
(fonts on all controls, selection/placeholder/link/timestamp colors),
and the own-message tint calms from 12% to 8% accent.
* Braid Layout v1.4: hamburger moves home to the bottom-left, settings nav gets real pills and themed icons
- The hamburger relocates to the bottom-left corner where the icon bar
it absorbed used to live — the popups it opens (themes, activities)
anchor down there, so the menu and its children now share a corner
instead of spawning across the screen from the button. It is styled
as a Haven tile (bordered, bg-tertiary, accent hover) with a Menu
label, and the grouped menu rises from the bottom-left with the same
morph-to-X and stagger.
- Settings nav highlights now encompass their rows: stock uses a
hanging-indent hack (padding-left 1.625rem + text-indent -16px) so
wrapped labels clear the leading emoji, which pulled the first line
left out of the highlight pill. Items are now full-width flex pills
with text-indent reset — and every leading emoji (nav rows and the
User/Admin tabs) becomes a currentColor line glyph keyed by
data-target, same treatment as the old bottom-left buttons, with a
Haven hexagon fallback for unmapped rows. Originals restore on
disable.