Native Liquid Glass Tab Bar Request
Nucleic-Session: 11F2B35E-E813-4A5E-AD28-9173ECC0B789 Co-authored-by: Nucleic <[email protected]>
This commit is contained in:
@@ -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())
|
||||
|
||||
Reference in New Issue
Block a user