Tab Bar Load Animation

Nucleic-Session: EEC60FAE-8368-49CA-9202-7026C12E7F8C
Co-authored-by: Nucleic <[email protected]>
This commit is contained in:
2026-07-05 19:05:14 -07:00
co-authored by Nucleic
parent 2df5a97f4b
commit 5916919790
@@ -55,18 +55,20 @@ struct CompactRootView: View {
/// chat could actually be kicked off (mirrors `NewChatAffordance.canStart`). /// chat could actually be kicked off (mirrors `NewChatAffordance.canStart`).
private var canStartChat: Bool { store.canControl && !store.dashboard.projects.isEmpty } private var canStartChat: Bool { store.canControl && !store.dashboard.projects.isEmpty }
/// Height reserved under each tab's content for the floating bar — the measured bar height when
/// it's up, nothing when a session or the composer hides it (so those run full-bleed).
private var contentInset: CGFloat { showsTabBar ? barHeight : 0 }
var body: some View { var body: some View {
TabView(selection: $tab) { TabView(selection: $tab) {
HomeView().tag(0).toolbar(.hidden, for: .tabBar) // The inset is applied per tab (not to the `TabView`): a bottom `safeAreaInset` on the
SessionsView().tag(1).toolbar(.hidden, for: .tabBar) // container does NOT propagate into the tab pages' scroll content, so the list would run
ProjectsView().tag(2).toolbar(.hidden, for: .tabBar) // under the bar. On each tab's `NavigationStack` it reaches the scroll content and pushes
SettingsView().tag(3).toolbar(.hidden, for: .tabBar) // it up above the bar.
} HomeView().modifier(TabBarInset(height: contentInset)).tag(0)
// Reserve exactly the bar's height so top-level content (and each tab's own bottom chrome) SessionsView().modifier(TabBarInset(height: contentInset)).tag(1)
// lays out above the floating bar rather than under it; collapses to nothing when a session ProjectsView().modifier(TabBarInset(height: contentInset)).tag(2)
// hides the bar so the transcript runs full-bleed. SettingsView().modifier(TabBarInset(height: contentInset)).tag(3)
.safeAreaInset(edge: .bottom, spacing: 0) {
Color.clear.frame(height: showsTabBar ? barHeight : 0)
} }
// The bar itself lives in an always-mounted overlay and slides on `offset`, so it travels // The bar itself lives in an always-mounted overlay and slides on `offset`, so it travels
// continuously off the bottom of the screen (a fixed distance past the home-indicator curve) // continuously off the bottom of the screen (a fixed distance past the home-indicator curve)