Skip to content

Rustty v1.38.0

Choose a tag to compare

@github-actions github-actions released this 29 Jun 08:53

Rustty 1.38.0 — Accessibility & keyboard navigation

Rustty is a cross-platform, local-first SSH/SFTP/FTP/RDP client and connection
manager. The backend is pure Rust (russh, russh-sftp, FTPS over rustls); the UI
runs in a Tauri 2 system WebView. No telemetry, Apache-2.0.

This release makes the whole UI usable for people who rely on high contrast,
reduced motion, or keyboard-only navigation. Everything below lives in
Preferences → Appearance → Accessibility unless noted.

Interface contrast (Normal / High / Max)

Why: Rustty ships 200+ themes, so I can't hand-tune contrast per theme, and
low-vision users need a contrast boost that's orthogonal to which theme they
picked.

How: pick a level in the Accessibility block; it reinforces text, borders,
focus and selection across the whole app without changing the active theme.

What I learned: my first instinct was CSS relative color syntax
(oklch(from var(--text) …)) to lift the dim colors programmatically, but
Tauri uses the OS WebView and our build targets (Safari 16 / Chromium 105)
don't all support it. So instead I re-read the active theme's palette at runtime
with getComputedStyle and promote the dimmer text/overlay CSS custom
properties one or two steps toward the main text color, preserving a compressed
hierarchy. Good reminder that "it's a desktop app" still means "mind the WebView
baseline".

Terminal minimum contrast + high-visibility cursor

Why: some terminal themes have ANSI colors that are barely legible on their
own background.

How: "Terminal minimum contrast" (Off / AA 4.5:1 / AAA 7:1) and a
"More visible cursor" toggle.

What I learned: xterm.js has a built-in minimumContrastRatio that adjusts
each glyph's foreground per cell against its background — I didn't have to touch
the palette at all. For the cursor I compute the WCAG relative luminance of the
theme background to choose black or white ink, so it stands out in block, bar
and underline styles (cursorWidth only thickens the bar caret).

Reduced motion + non-flashing visual bell

Why: honor prefers-reduced-motion, plus an explicit in-app toggle for
people whose OS doesn't expose it.

What I learned (the fun bug): the global
@media (prefers-reduced-motion: reduce) rule collapses every animation to
~0 ms — which silently made the terminal's visual bell flash invisibly, i.e.
reducing motion quietly removed a feedback cue. Fixed by swapping the keyframe
flash for a steady highlight that a timeout removes. "Reduce motion" must not
mean "remove feedback".

Colorblind mode, beyond status dots

Why: toasts differed only by background hue (green success / red error — the
classic confusion), and SFTP transfer bars only by color.

How: toggle "Colorblind mode". Toasts now carry a per-severity SVG glyph and
SFTP transfer bars get a hatch pattern per final state, in addition to color.

What I learned: I render the toast icons with CSS mask +
background-color: currentColor, so the glyph inherits each toast's text color
automatically across all 200+ themes — no per-theme icon assets.

Keyboard navigation

Why: sidebar connections were plain <div>s, so keyboard users couldn't
reach them or their context menus at all.

How: connections and tabs are now focusable (Enter/Space activates;
Shift+F10 opens the context menu). Floating menus focus their first item on
open, move with arrows / Home / End, and close with Tab/Escape, returning focus
to where you started.

What I learned: a neat property of the :focus-visible heuristic —
programmatically focusing the first menu item on open shows the focus ring only
when the menu was opened via keyboard (the engine tracks input modality), so
mouse users never see a stray ring. I also put scroll-margin on
:focus-visible so a focused row doesn't hide under sticky edges while tabbing.


Full changelog: https://github.com/Aleixenandros/Rustty/blob/main/CHANGELOG.md

Disclosure: these release notes were drafted with the assistance of an LLM and
reviewed/edited by me, the author.