Skip to content

Add an accessibility text size for the app chrome - #774

Merged
sbertix merged 6 commits into
supabitapp:mainfrom
sageframe-no-kaji:feat/662-accessibility-chrome-text-size
Aug 10, 2026
Merged

Add an accessibility text size for the app chrome#774
sbertix merged 6 commits into
supabitapp:mainfrom
sageframe-no-kaji:feat/662-accessibility-chrome-text-size

Conversation

@sageframe-no-kaji

@sageframe-no-kaji sageframe-no-kaji commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Closes #662

Summary

Adds a chrome text size setting so the sidebar, tab bar, toolbars, and Settings can be enlarged without changing the OS-wide display scale, which resizes the terminal along with everything else.

macOS SwiftUI does not resize text in response to dynamicTypeSize, so the size is applied by resolving each semantic font explicitly: a uiTextScale environment value is published at every window root, and chrome text opts in through appFont(_:weight:monospaced:) in place of .font(.body). The Ghostty terminal surface is NSView-backed with its own font system and is unaffected.

Three points that may be worth a closer look during review:

  • The toolbar title publishes the size a second time inside its TerminalSchemeHost closure. That host re-hosts its content in a fresh NSHostingView, which starts a new environment rather than inheriting the window's. Views behind the other imperatively-constructed hosting roots (command palette panel, terminal split tree) are deliberately left alone rather than plumbed, to keep this change out of the terminal internals.
  • Section headers need appFontInheriting. List styles its own headers and SwiftUI does not expose the font it resolved, so there is nothing to scale in place. The modifier leaves them alone at Default and only supplies a point size above that, so the repository name and the Active and Pinned titles grow with the rows beneath them.
  • chromeTextSize is mirrored into SettingsFeature.State like the other global fields, so the picker binds through the store and persists on the existing .binding path. Scaled point sizes are rounded to whole points, and the system text-style metrics are read once rather than on every body evaluation.

A missing or unrecognized chromeTextSize falls back to the default rather than throwing, which would reset the rest of the settings file — matching the existing appVisibility decode. The new pane is reachable at supacode://settings/accessibility and supacode settings accessibility, like every other pane.

Type of change

  • Bug fix (the linked issue is a bug report)
  • Feature (the linked issue is a feature request marked ready)
  • Documentation
  • Other (please describe)

How was this tested?

make check and make test both pass locally. New tests cover the case order and raw-value stability, the decode migration from a settings file predating the key, the fallback for an unrecognized value, and that an unrelated settings change no longer resets the size.

Also verified by running a Debug build against an isolated data directory at Extra Large: the toolbar title, the sidebar rows, and the Active/Pinned section headers all scale, and the terminal surface is unaffected.

  • make check passes (format + lint)
  • make test passes
  • I built and ran the app to confirm the change works

Checklist

  • This pull request is linked to an issue with Closes # above.
  • For a feature, the linked issue is labeled ready.
  • I am the author of this work and accountable for it; no commit is authored or co-authored by an AI agent.
  • I have read the Contributing guide and the Code of Conduct.

There is no in-app way to enlarge the sidebar, tab bar, toolbars, or
Settings without changing the OS-wide display scale, which resizes the
terminal along with everything else.

macOS SwiftUI does not resize text in response to dynamicTypeSize, so the
size is applied by resolving each semantic font explicitly: a uiTextScale
environment value is published at every window root, and chrome text opts
in through appFont(_:weight:monospaced:) in place of .font(.body). The
Ghostty terminal surface is NSView-backed with its own font system and is
unaffected. The toolbar title publishes the size a second time inside its
TerminalSchemeHost closure, because that host re-hosts its content in a
fresh NSHostingView rather than inheriting the window's environment.

Section headers take appFontInheriting instead. List styles its own
headers and SwiftUI does not expose the font it resolved, so there is
nothing to scale in place; the modifier leaves them alone at Default and
only supplies a point size above that, so the repository name and the
Active and Pinned titles grow with the rows beneath them.

A missing or unrecognized chromeTextSize falls back to the default rather
than throwing, which would reset the rest of the settings file. macOS has
no Dynamic Type step table to inherit, so the two steps are chosen to land
near where iOS's .xLarge and .xxLarge sit, and scaled point sizes round to
whole points.

The Accessibility pane holding the picker is reachable at
supacode://settings/accessibility and `supacode settings accessibility`,
like every other pane.

Tests cover the case order and raw-value stability, the decode migration
from a file predating the setting, the fallback for an unrecognized value,
and that an unrelated settings change no longer resets the size.
Resolve conflicts from the terminal-layer rework and the background-refresh
setting:

- Keep both chromeTextSize and automaticRepositoryRefreshEnabled across
  GlobalSettings, SettingsFeature state, and the persistence tests.
- Adopt main's refactors (Form-based WorktreeStatusInspector, the hint-based
  EmptyTerminalPaneView, the File explorer beta card, the DeveloperSettings
  path-safe message) and re-apply appFont scaling on top of them.
- Drop the onboarding cards and the old TerminalTab views deleted on main; the
  tab bar's scaling is re-applied to the reworked pane strip separately.
Re-apply the chrome text size to the pane strip, pane window header, and the
Form-based pull request inspector that the terminal-layer rework replaced, so
tab titles, the rename field, the shortcut hint, and the inspector follow the
setting again. Fixed-size control and indicator glyphs stay unscaled.

The pane tree and windowed panes mount in fresh NSHostingViews that do not
inherit the scene environment, so republish the size at each hosted root
(LayoutPaneTreeView, WindowedPaneRootView) the same way the toolbar host does;
without it the tab bar never scales.

Reach the remaining chrome the same way:
- Command palette: republish the size inside its hosted overlay and scale the
  query field and row text.
- Settings and reference windows: raise the base font (appChromeBaseFont) so the
  implicit Form/Picker/Toggle labels scale without a per-label opt-in; left at
  the system size for Default.

Also:
- Scale the loading placeholder toolbar title, which re-hosts in a fresh
  NSHostingView and so needs the size published inside its closure.
- Scale the Accessibility pane's own picker label so it previews the size.
- Extract the font-resolution core into AppFontMetrics and carry ChromeTextSize
  through the environment instead of a raw Double, and cover the math with
  unit tests. Use the canonical no-design system font for regular text.
- Add decode coverage for a mistyped chromeTextSize value and a settingsLoaded
  read-path test.
- Trim the doc comments and drop the em dashes.
@sbertix

sbertix commented Aug 10, 2026

Copy link
Copy Markdown
Collaborator

Thank you 🙇‍♂️ let me fold in some changes with the new tab bars, add some missing cases, and report back 💪

Move the chrome text size out of a standalone Accessibility pane into an
Accessibility section in General, before Analytics, and drop the now-unused
pane, its settings section, deeplink, and CLI subcommand. Label the system
size Regular with the shared Default tag, and mark the setting Beta.

Scale the file explorer's AppKit outline view, which never sees the SwiftUI
chrome environment: thread the size into the cell and breadcrumb fonts and
rebuild rows when it changes. A non-custom rowSizeStyle makes the table override
the cell font, so switch to custom above the system size; the exact preferred
font is kept at Default. A parity test pins the NSFont scale to AppFontMetrics.

Scale the two remaining chrome surfaces that opt out of the environment: raise
the base font on the pull request inspector Form, and size the settings
sidebar rows explicitly since the sidebar list style pins its own font.

@sbertix sbertix left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks 🙇‍♂️

@sbertix
sbertix enabled auto-merge (squash) August 10, 2026 22:06
@sbertix
sbertix merged commit b924ebe into supabitapp:main Aug 10, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Accessibility: large-text options for the app chrome

2 participants