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`).
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 {
TabView(selection: $tab) {
HomeView().tag(0).toolbar(.hidden, for: .tabBar)
SessionsView().tag(1).toolbar(.hidden, for: .tabBar)
ProjectsView().tag(2).toolbar(.hidden, for: .tabBar)
SettingsView().tag(3).toolbar(.hidden, for: .tabBar)
}
// Reserve exactly the bar's height so top-level content (and each tab's own bottom chrome)
// lays out above the floating bar rather than under it; collapses to nothing when a session
// hides the bar so the transcript runs full-bleed.
.safeAreaInset(edge: .bottom, spacing: 0) {
Color.clear.frame(height: showsTabBar ? barHeight : 0)
// The inset is applied per tab (not to the `TabView`): a bottom `safeAreaInset` on the
// container does NOT propagate into the tab pages' scroll content, so the list would run
// under the bar. On each tab's `NavigationStack` it reaches the scroll content and pushes
// it up above the bar.
HomeView().modifier(TabBarInset(height: contentInset)).tag(0)
SessionsView().modifier(TabBarInset(height: contentInset)).tag(1)
ProjectsView().modifier(TabBarInset(height: contentInset)).tag(2)
SettingsView().modifier(TabBarInset(height: contentInset)).tag(3)
}
// 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)