redesign bottom bar

This commit is contained in:
2026-05-03 21:06:20 -07:00
parent 53a3b722ec
commit ee8a93a8c4
3 changed files with 79 additions and 28 deletions

View File

@@ -6,6 +6,7 @@ struct SybilChatTranscriptView: View {
var isLoading: Bool
var isSending: Bool
var topContentInset: CGFloat = 0
var bottomContentInset: CGFloat = 0
@State private var hasHandledInitialTranscriptScroll = false
private var hasPendingAssistant: Bool {
@@ -50,7 +51,7 @@ struct SybilChatTranscriptView: View {
.frame(maxWidth: .infinity, alignment: .leading)
.padding(.horizontal, 14)
.padding(.top, 18 + topContentInset)
.padding(.bottom, 18)
.padding(.bottom, 18 + bottomContentInset)
}
.frame(maxWidth: .infinity, alignment: .leading)
.scrollDismissesKeyboard(.interactively)

View File

@@ -7,6 +7,7 @@ struct SybilSearchResultsView: View {
var isRunning: Bool
var isStartingChat: Bool = false
var topContentInset: CGFloat = 0
var bottomContentInset: CGFloat = 0
var onStartChat: (() -> Void)? = nil
var body: some View {
@@ -100,7 +101,7 @@ struct SybilSearchResultsView: View {
.frame(maxWidth: .infinity, alignment: .leading)
.padding(.horizontal, 14)
.padding(.top, 20 + topContentInset)
.padding(.bottom, 20)
.padding(.bottom, 20 + bottomContentInset)
}
.scrollDismissesKeyboard(.interactively)
.frame(maxWidth: .infinity, alignment: .leading)

View File

@@ -35,6 +35,7 @@ struct SybilWorkspaceView: View {
@State private var newChatSwipeFeedbackGenerator: UIImpactFeedbackGenerator?
private let customWorkspaceNavigationContentInset: CGFloat = 96
private let composerOverlayContentInset: CGFloat = 112
private var isSettingsSelected: Bool {
if case .settings = viewModel.selectedItem {
@@ -149,7 +150,7 @@ struct SybilWorkspaceView: View {
.overlay(SybilTheme.border)
}
Group {
ZStack(alignment: .bottom) {
if isSettingsSelected {
SybilSettingsView(viewModel: viewModel)
} else if viewModel.isSearchMode {
@@ -158,7 +159,8 @@ struct SybilWorkspaceView: View {
isLoading: viewModel.isLoadingSelection,
isRunning: viewModel.isSending,
isStartingChat: viewModel.isCreatingSearchChat,
topContentInset: showsCustomWorkspaceNavigation ? customWorkspaceNavigationContentInset : 0
topContentInset: showsCustomWorkspaceNavigation ? customWorkspaceNavigationContentInset : 0,
bottomContentInset: viewModel.showsComposer ? composerOverlayContentInset : 0
) {
Task {
await viewModel.startChatFromSelectedSearch()
@@ -169,10 +171,15 @@ struct SybilWorkspaceView: View {
messages: viewModel.displayedMessages,
isLoading: viewModel.isLoadingSelection,
isSending: viewModel.isSending,
topContentInset: showsCustomWorkspaceNavigation ? customWorkspaceNavigationContentInset : 0
topContentInset: showsCustomWorkspaceNavigation ? customWorkspaceNavigationContentInset : 0,
bottomContentInset: viewModel.showsComposer ? composerOverlayContentInset : 0
)
.id(transcriptScrollContextID)
}
if viewModel.showsComposer {
composerBar
}
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background {
@@ -193,12 +200,6 @@ struct SybilWorkspaceView: View {
}
)
}
if viewModel.showsComposer {
Divider()
.overlay(SybilTheme.border)
composerBar
}
}
}
@@ -501,7 +502,7 @@ struct SybilWorkspaceView: View {
}
TextField(
viewModel.isSearchMode ? "Search the web" : "Message Sybil",
viewModel.isSearchMode ? "Search the web" : "Enter Prompt",
text: $viewModel.composer,
axis: .vertical
)
@@ -518,10 +519,7 @@ struct SybilWorkspaceView: View {
.background(
RoundedRectangle(cornerRadius: 12)
.fill(SybilTheme.composerGradient)
.overlay(
RoundedRectangle(cornerRadius: 12)
.stroke(SybilTheme.primary.opacity(0.34), lineWidth: 1)
)
.opacity(0.98)
)
.foregroundStyle(SybilTheme.text)
@@ -546,23 +544,19 @@ struct SybilWorkspaceView: View {
}
}
.padding(.horizontal, 14)
.padding(.vertical, 12)
.background(
LinearGradient(
colors: [
SybilTheme.background.opacity(0.18),
SybilTheme.background.opacity(0.96)
],
startPoint: .top,
endPoint: .bottom
)
)
.padding(.top, 34)
.padding(.bottom, 12)
.background(alignment: .bottom) {
SybilComposerFadeBackground()
.allowsHitTesting(false)
}
.overlay {
if isComposerDropTargeted && !viewModel.isSearchMode {
RoundedRectangle(cornerRadius: 18)
.stroke(SybilTheme.accent.opacity(0.78), style: StrokeStyle(lineWidth: 1.5, dash: [7, 5]))
.padding(.horizontal, 14)
.padding(.vertical, 10)
.padding(.top, 32)
.padding(.bottom, 10)
}
}
.onDrop(of: [UTType.fileURL.identifier, UTType.image.identifier], isTargeted: $isComposerDropTargeted) { providers in
@@ -982,6 +976,60 @@ private extension UIView {
}
}
private struct SybilComposerFadeBackground: View {
var body: some View {
ZStack(alignment: .bottomLeading) {
LinearGradient(
colors: [
Color.clear,
SybilTheme.background.opacity(0.30),
SybilTheme.background.opacity(0.86),
SybilTheme.background.opacity(0.86),
SybilTheme.background.opacity(0.98)
],
startPoint: .top,
endPoint: .bottom
)
LinearGradient(
colors: [
SybilTheme.primary.opacity(0.18),
SybilTheme.surface.opacity(0.16),
SybilTheme.accent.opacity(0.08)
],
startPoint: .topLeading,
endPoint: .bottomTrailing
)
.mask(
LinearGradient(
colors: [
Color.clear,
Color.black.opacity(0.42),
Color.black
],
startPoint: .top,
endPoint: .bottom
)
)
.blendMode(.screen)
RadialGradient(
colors: [
SybilTheme.primary.opacity(0.28),
SybilTheme.primary.opacity(0.08),
Color.clear
],
center: .bottomLeading,
startRadius: 8,
endRadius: 180
)
.blendMode(.screen)
.offset(x: -42, y: 42)
}
.ignoresSafeArea(edges: .bottom)
}
}
private struct SybilNavigationIcon: View {
var systemImage: String
@@ -1024,6 +1072,7 @@ private struct SybilNavigationFadeBackground: View {
.blendMode(.screen)
.offset(x: -44, y: -46)
}
.frame(height: 200.0)
.ignoresSafeArea(edges: .top)
}
}