Skip to content

fix(ui): slide the detail tab indicator instead of morphing glass - #386

Merged
AprilNEA merged 2 commits into
masterfrom
fix/detail-tab-glass-animation
Aug 12, 2026
Merged

fix(ui): slide the detail tab indicator instead of morphing glass#386
AprilNEA merged 2 commits into
masterfrom
fix/detail-tab-glass-animation

Conversation

@KafuChino123

@KafuChino123 KafuChino123 commented Aug 11, 2026

Copy link
Copy Markdown
Member

Problem

The detail tab bar in the toolbar played an exaggerated stretch on every tab switch — most visible on the four-tab Containers view — and the first switch after a cold launch was worse still. The Runners detail bar was unaffected because it uses a native segmented Picker, where AppKit owns the indicator.

Affected views: Containers, Volumes, Images (Docker), Sandboxes, Machines — everything going through DetailTabPicker.

Root cause

Two independent departures from the documented Liquid Glass contract, compounding:

1. GlassEffectContainer(spacing:) was being used as a layout gap. It is a blend thresholdApple: "As shapes near one another, their paths start to blend into one another. The higher the spacing, the sooner blending begins." It was set to tabCount * AppMetrics.detailTabSegment:

View Tabs spacing HStack spacing
Containers 4 320pt 2pt
Images 3 240pt 2pt
Sandboxes 6 480pt 2pt

Applying Liquid Glass to custom views: "A spacing value on the container that's larger than the spacing of an interior HStack … causes Liquid Glass effects to blend together at rest." Apple's own example pairs GlassEffectContainer(spacing: 40) with HStack(spacing: 40). The blend field here covered the entire bar, so the indicator blended against segments it was nowhere near.

2. One shared glassEffectID over a per-segment .regular.identity toggle. GlassEffectTransition.matchedGeometry: "this transition applies additional scale and offset effects to content when the identity of the shape does not change but its content does." "selected-detail-tab" stayed constant while the segment beneath it changed — precisely that trigger.

Fix

Render one persistent glass capsule and position it with matchedGeometryEffect against the selected segment: each segment is a geometry source, and a single Color.clear.glassEffect(.regular.interactive()) background follows id: selection.

The pill now moves instead of appearing and disappearing, so there is no morph to overshoot and no appearance transition to misfire on first mount. GlassEffectContainer is dropped — it exists to blend multiple effects, and there is now one.

Animation also tightened from 0.3s to 0.2s, closer to the native indicator's pace. reduceMotion handling and the accessibilityRepresentation segmented Picker are unchanged.

Verification

  • make build, make lint (0 violations), make test (91 tests / 10 suites) all pass on this branch.
  • Manually verified in ArcBox Dev across several cold launches — cold-start first open, Containers (4 tabs), and repeated switching. Confirmed by the reporter.
  • No test added: this is animation geometry with no branching logic to assert against. The behaviour is only observable in a running window.

Note for reviewers

The pill reads as a cleaner slide than before — the liquid squish is gone. That is intentional, and tunable independently of the bug. If a glassier feel is wanted back, the lever is the animation curve, not the container spacing.


Also included: curate the 1.35.0 highlights

This PR carries a second, unrelated commit because CI on master is currently red for every PR and this one cannot be verified without it.

Release PR #382 (chore(master): release 1.35.0, 4e034ec) merged with its own check already red, leaving ## [1.35.0] in CHANGELOG.md without a ### Highlights section while .release-please-manifest.json names 1.35.0. pr.yml:90 therefore fails with release 1.35.0 has no non-empty ### Highlights section, and that step runs before Lint, Build (Debug) and Run Tests — so no PR reaches the compiler. The release DMG extracts the same section to feed Sparkle's update dialog and refuses to build without it, so 1.35.0 cannot be packaged either.

The added section is written from what 1.35.0 actually shipped — Fleet device auth and runner management (#320), authoritative sandbox port reconciliation (#374), and telemetry identification with the Privacy toggle ordering (#367). Build, docs and CI-only entries are left out; this text is what users see in the update dialog.

cargo xtask release notes --version "$(jq -r '."."' .release-please-manifest.json)" — the exact CI invocation — now succeeds. Verified green on its own branch before consolidation: Build & Test passed in 8m48s with Verify curated release highlights, Lint, Build (Debug) and Run Tests all ✓.

Reviewers: the changelog wording is the part worth reviewing, since it ships verbatim to users. One sentence is a deliberate judgment call — it states plainly that a signed-in account is identified by email and name while analytics is on. #367 made that change and also corrected the Privacy toggle's caption, which had claimed no personal data was collected. Reword or drop it if you'd rather it not appear there.

Happy to split this back out if you'd rather land the unblock on its own — it was originally #389.

The detail tab bar played an exaggerated stretch on every tab switch,
worst on the four-tab container view, and the first switch after a cold
launch was worse still.

GlassEffectContainer's spacing is a blend threshold, not a layout gap:
the higher it is, the sooner shapes start merging as they approach. It
was set to tabCount * detailTabSegment -- 320pt for containers, 480pt
for sandboxes -- against an HStack spacing of 2pt, so the blend field
spanned the whole bar. Apple documents that a container spacing larger
than the interior stack's spacing blends the effects together at rest.

The indicator also toggled glassEffect between .regular and .identity
per segment under one shared glassEffectID. That ID stays constant while
the segment beneath it changes, which is the documented trigger for
GlassEffectTransition.matchedGeometry to apply "additional scale and
offset effects to content" -- on top of the oversized blend.

Render one persistent glass capsule instead and position it with
matchedGeometryEffect against the selected segment. The pill now moves
rather than appearing and disappearing, so there is no morph to
overshoot and no appearance transition to misfire on first mount.
GlassEffectContainer is no longer needed for a single effect.
@greptile-apps

greptile-apps Bot commented Aug 11, 2026

Copy link
Copy Markdown

Greptile Summary

The PR replaces the per-segment Liquid Glass morph with one persistent capsule that follows the selected detail tab using matched geometry, while preserving reduced-motion and accessibility behavior.

  • Removes the oversized GlassEffectContainer blend field and per-segment glass toggling.
  • Shortens the selection animation and centralizes the segment gap.
  • Adds curated highlights for the 1.35.0 changelog.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains.

Important Files Changed

Filename Overview
ArcBox/Components/DetailTabPicker.swift Reworks the shared detail-tab indicator into a single matched-geometry glass capsule without an accepted blocking issue.
CHANGELOG.md Adds release highlights without affecting application behavior.

Reviews (2): Last reviewed commit: "chore(release): curate the 1.35.0 highli..." | Re-trigger Greptile

The 1.35.0 release PR merged with an empty `### Highlights` section, so
`cargo xtask release notes` now fails on every PR against master. That
step runs before Lint, Build and Test, so no PR gets as far as
compiling. The release DMG extracts the same section to feed Sparkle's
update dialog and refuses to build without it, so 1.35.0 cannot be
packaged either.

Write the section from what 1.35.0 actually shipped: the Fleet device
auth, enrollment and runner management in #320, the authoritative
sandbox port reconciliation in #374, and the telemetry identification
and Privacy toggle ordering in #367.
@AprilNEA
AprilNEA merged commit 1c34044 into master Aug 12, 2026
6 checks passed
@AprilNEA
AprilNEA deleted the fix/detail-tab-glass-animation branch August 12, 2026 08:24
AprilNEA added a commit that referenced this pull request Aug 13, 2026
…er (#393)

* ci: fail the highlights gate only where it protects a release

581a33c added this check to catch a missing `### Highlights` while it was
still an edit, because v1.34.2 through v1.34.4 each cut a tag and a GitHub
release with no DMG behind them. That part works and stays.

What it did not account for is that release-please never writes that
section, so every release PR fails this by construction — and the version
comes from the manifest, so once one merged red, every other PR failed the
same way, at a step ahead of Lint, Build and Test. Nothing reached the
compiler for 22 hours after 1.35.0, and #386 had to smuggle the changelog
fix into a UI PR to verify itself.

Keep it fatal on the release PR and on master, where it guards the tag and
says master is unshippable. Everywhere else report the same finding as a
warning: still visible, no longer everyone's outage. Both paths now spell
out what to add and why.

* feat(release): build notes from highlights and the change list together

Highlights were the *only* source of release notes, so a release without
them had nothing to ship and `release notes` refused to build — which is
why every release PR failed by construction and why v1.34.2 through
v1.34.4 each cut a tag with no DMG behind it.

The prose and the list answer different questions. Curated Highlights say
why to update; the Features and Bug Fixes entries say what changed. Emit
both, in that order, and let either be absent.

Only a release with neither now fails, which is a real signal rather than
a standing tax: a bare engine bump lands under Miscellaneous and produces
no user-facing entry, so a human still has to say what it means.

Section titles reuse ChangelogParser's user-facing set, so the About
window and the update dialog cannot disagree about what counts. The
`([#387](…)) ([abc1234](…))` trailers are dropped — right for a changelog,
noise in an update dialog.
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.

2 participants