Native Liquid Glass Tab Bar Request

Nucleic-Session: 11F2B35E-E813-4A5E-AD28-9173ECC0B789
Co-authored-by: Nucleic <[email protected]>
This commit is contained in:
2026-07-05 23:41:20 -07:00
co-authored by Nucleic
parent 9ba6627539
commit 2633850865
@@ -175,6 +175,10 @@ struct NucleicTabBar: View {
@Binding var selection: Int
/// Sessions blocking on a human — the red badge on the Sessions item (was the tab item badge).
var needsYou: Int
@Environment(\.accessibilityReduceMotion) private var reduceMotion
/// Ties every item's selected-capsule to one shared geometry, so the "bubble" interpolates its
/// frame from the old tab to the new one instead of cross-fading — the native bar's slide.
@Namespace private var bubble
private struct Item { let index: Int; let title: String; let icon: String }
private let items = [
@@ -193,6 +197,10 @@ struct NucleicTabBar: View {
.padding(.horizontal, 6)
.padding(.vertical, 8)
.glassBar()
// Drive the bubble's slide (and the label/tint crossfade) off the selection itself, so any
// change — tap here or a programmatic jump from a notification — springs across.
.animation(reduceMotion ? nil : .spring(response: 0.32, dampingFraction: 0.78),
value: selection)
}
private func itemButton(_ item: Item) -> some View {
@@ -220,11 +228,14 @@ struct NucleicTabBar: View {
.foregroundStyle(selected ? Palette.accent : Color.secondary)
.frame(maxWidth: .infinity)
.padding(.vertical, 4)
// The selected item rides a soft accent-tinted capsule, echoing the system floating
// bar's highlighted tab.
// The selected item rides a soft accent-tinted capsule that slides between tabs — only
// the selected item mounts it, and the shared `bubble` geometry makes the single capsule
// travel to the new tab, echoing the system floating bar's highlighted-tab indicator.
.background {
if selected {
Capsule().fill(Palette.accent.opacity(0.15))
Capsule()
.fill(Palette.accent.opacity(0.15))
.matchedGeometryEffect(id: "selectionBubble", in: bubble)
}
}
.contentShape(Rectangle())