Settings: rows read like macOS System Settings rows - #201
Open
T0mSIlver wants to merge 1 commit into
Open
Conversation
Presentation only — the same controls, bound to the same state, in the row
idiom the rest of the system uses: label leading, control trailing,
explanation on its own full-width line underneath.
The old row put the label in a fixed 128pt column and everything else to
its right. Long labels ("Use Claude Code project files as polish context")
wrapped inside that column while short ones left a gutter, and each help
sentence started at the column's edge, so every card had a second, ragged
left margin. Now the label takes the leftover width and the explanation is
a row of its own, aligned to the label.
Help text becomes a `help:` parameter instead of a view inside the control
closure. This is the one call-site change, and it is forced: most call
sites nest the text inside their own VStack, and a row cannot pull a view
out of its control column — which is precisely where this text must not
be. Hoisting it with a PreferenceKey instead would put every row's layout
a frame behind its content and fight Swift 6's @sendable
onPreferenceChange, to keep a diff that is mechanical either way.
Composite rows (plugin button bar, enrolled SSH hosts, config file list)
opt into `layout: .stacked` — beside a 400pt-wide control the label would
be squeezed into a wrapped stub. Sliders get an explicit width because a
Slider reports no intrinsic one and would collapse in a trailing column.
Groups: radius 18 -> 8, .quinary fill with a .quaternary border, .headline
header, and a divider between rows. The last divider is removed
geometrically (container 1pt short, clipped) rather than by teaching the
card to enumerate heterogeneous children.
1 task
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Stacked on #199 — this PR targets
settings-sidebar-chrome, notmain.Do not delete #199's branch before this one is retargeted; GitHub auto-closes
children when a base branch disappears. Review #199 first.
Presentation-only rewrite of the shared row/group primitives in
SettingsView.swift. Same controls, same bindings, same behavior — rendered inthe row idiom the rest of macOS uses: label leading, control trailing,
explanation on its own full-width line underneath.
The old row put the label in a fixed 128pt column with everything else to its
right. Long labels ("Use Claude Code project files as polish context") wrapped
inside that column while short ones ("Enable") left a gutter, and every help
sentence started at the column's edge — so each card had a second, ragged left
margin. Now the label takes the leftover width (
layoutPriority(0), so controlskeep their intrinsic size) and the explanation is a row of its own, aligned to
the label.
Also:
.toggleStyle(.switch), so 12 call sites stop repeating it.SettingsGroup: corner radius 18 → 8,.quinaryfill with a.quaternaryborder,
.headlineheader (down from 17pt semibold), and aDivider()betweenrows.
1pt short and clipped, so the final divider falls outside the clip. The
alternative was teaching the card to enumerate its children, which are
heterogeneous and arrive wrapped in
Group/ifbranches.Deviations from the brief (with reasons)
help:parameter — the one call-site change. The briefasked for no call-site changes, but most call sites nest the help text inside
their own
VStack, and a row cannot pull a nested view out of its controlcolumn — which is exactly where this text must not be. The zero-call-site
alternative is hoisting the string with a
PreferenceKey, which puts everyrow's layout one frame behind its content and fights Swift 6's
@SendableonPreferenceChange(the closure would capture a non-SendablegenericView). The migration is mechanical, and it shrinks the call sites — thewrapper
VStacks disappear..controlSize(.mini). Applied at page level it shrinks everybutton, picker, and text field on the page, not just switches — and macOS
System Settings uses regular-size switches. Says so here rather than shipping
a pane of miniature buttons; happy to reverse if the owner wants the smaller
switch specifically.
layout: .stackedfor composite rows (see below). Not in the brief,but it is the fix for the exact rows the brief asked me to hand-check.
.toprather than centering: several rowshave tall controls, and a centered short label beside those reads as
misaligned.
The composite rows the brief flagged — what I found and did
Hand-check here = careful code reading plus a clean build; none of it has been
seen on screen (see below).
ShortcutRecorderField+ Reset/Clear button (:578-632)SettingsInlineMessage("Not set. Record one to enable.") now sits under the control, trailing-aligned, instead of under the label.:558,:651)Sliderreports no intrinsic width, so in a trailing column it collapses to nothing.SettingsLayout.sliderWidth(190pt) track.ManagedBackendStatusRow(:386)ClaudePluginSettingsRowlayout: .stacked.ClaudeRemoteHostsSettingsRowlayout: .stacked.SettingsFileNotes("Included files")layout: .stacked.PermissionRowsViewSettingsGroupRowat the call site rather than modified — onboarding is untouched.SettingsAvailabilityCardSettingsGroupRow; radius 16 → 8.Every consent-critical help string (the polish-context toggles, the non-local
endpoint toggle) is byte-identical, and the rationale comments that explain each
one moved with them.
Proof
./scripts/remote-build.shNo new warnings (
.build/last-remote.loghas only the pre-existingClaudePluginInstallService.swift:226andClaudeHookPublisherTestsones).CI
build-teston this branch: pass (4m38s). #199 picked up review hardeningafter this branch was cut (
da5d653, drill scripts only — no app code), so thisbranch is one commit behind its base; nothing in it touches the same files.
"Start dictation with", …) and field labels ("Endpoint", "API key"), all
unchanged by this PR, and Settings: hand-rolled sidebar chrome in place of the TabView #199's scoped selectors are unaffected. The drill
could not run tonight — see Settings: hand-rolled sidebar chrome in place of the TabView #199's Proof for the two runs and why (an existing
app instance on the runner's GUI session would not quit; the guard was not
weakened).
Nothing here changes prompts, model pins, sampling, or anything that reaches
the model;
scripts/ci/llm-lane-filter.shmatches nothing in the diff.UI change — what was verified, and what was not
Verified: clean build under Swift 6.2 strict concurrency, full unit suite, and
the row-by-row reading in the table above.
Not verified — needs the owner's eyes (
./scripts/try-pr.sh <this PR>), inpriority order:
composite rows: do the toggles line up on the right, and does the explanation
under each one read as belonging to it?
spots where I changed geometry on a guess.
above the bottom edge (the 1pt clip trick).
.quinaryon.windowBackgroundColoris still visible as a card in bothlight and dark appearance.