Merge branch 'dev' into canary
This commit is contained in:
@@ -27,6 +27,10 @@ struct SessionDetailView: View {
|
|||||||
.safeAreaInset(edge: .bottom) { actionArea }
|
.safeAreaInset(edge: .bottom) { actionArea }
|
||||||
.navigationTitle(summary?.title ?? "Session")
|
.navigationTitle(summary?.title ?? "Session")
|
||||||
.navigationBarTitleDisplayMode(.inline)
|
.navigationBarTitleDisplayMode(.inline)
|
||||||
|
// With a session open the floating chat bar owns the bottom edge; the tab bar below it
|
||||||
|
// would be a redundant second bar (and clip the glass action area), so hide it while
|
||||||
|
// this detail is pushed. A no-op in the iPad split, which has no tab bar.
|
||||||
|
.toolbar(.hidden, for: .tabBar)
|
||||||
.toolbar {
|
.toolbar {
|
||||||
ToolbarItem(placement: .topBarTrailing) { sessionMenu }
|
ToolbarItem(placement: .topBarTrailing) { sessionMenu }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -108,28 +108,31 @@ struct SessionsView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.presentationDetents([.medium, .large])
|
// The composer needs only a fraction of the screen — a compact height by default,
|
||||||
|
// still expandable if the advanced options are opened.
|
||||||
|
.presentationDetents([.height(360), .large])
|
||||||
|
.presentationDragIndicator(.visible)
|
||||||
}
|
}
|
||||||
.safeAreaInset(edge: .bottom) { ConnectionChip().padding(.bottom, 8) }
|
.safeAreaInset(edge: .bottom) { ConnectionChip().padding(.bottom, 8) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The circular plus button, styled to match the transcript's jump-to-bottom FAB: an accent
|
/// The circular plus button, on Liquid Glass rather than a solid teal disc — an accent-tinted
|
||||||
/// disc with a soft shadow, floated clear of the connection chip.
|
/// glyph over a translucent glass circle so it reads as a floating control, not a stamped
|
||||||
|
/// button. Sits low over the list, clear of the connection chip.
|
||||||
private var newChatButton: some View {
|
private var newChatButton: some View {
|
||||||
Button {
|
Button {
|
||||||
showNewChat = true
|
showNewChat = true
|
||||||
} label: {
|
} label: {
|
||||||
Image(systemName: "plus")
|
Image(systemName: "plus")
|
||||||
.font(.system(size: 22, weight: .semibold))
|
.font(.system(size: 22, weight: .semibold))
|
||||||
.foregroundStyle(.white)
|
.foregroundStyle(Palette.accent)
|
||||||
.frame(width: 56, height: 56)
|
.frame(width: 56, height: 56)
|
||||||
.background(Palette.accent, in: .circle)
|
.glassCircle()
|
||||||
.shadow(color: .black.opacity(0.25), radius: 6, y: 2)
|
|
||||||
}
|
}
|
||||||
.buttonStyle(.plain)
|
.buttonStyle(.plain)
|
||||||
.padding(.trailing, 20)
|
.padding(.trailing, 20)
|
||||||
.padding(.bottom, 20)
|
.padding(.bottom, 6)
|
||||||
.accessibilityLabel("New chat")
|
.accessibilityLabel("New chat")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -354,6 +354,22 @@ struct GlassSurface: ViewModifier {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A circular Liquid Glass backing for a floating round control (the New-chat FAB). Real
|
||||||
|
/// interactive `glassEffect` on iOS 26; an ultra-thin material disc with a hairline edge and a
|
||||||
|
/// soft shadow on earlier systems so it still lifts off the list.
|
||||||
|
struct GlassCircle: ViewModifier {
|
||||||
|
func body(content: Content) -> some View {
|
||||||
|
if #available(iOS 26.0, *) {
|
||||||
|
content.glassEffect(.regular.interactive(), in: .circle)
|
||||||
|
} else {
|
||||||
|
content
|
||||||
|
.background(.ultraThinMaterial, in: .circle)
|
||||||
|
.overlay(Circle().strokeBorder(Color.primary.opacity(0.08), lineWidth: 1))
|
||||||
|
.shadow(color: .black.opacity(0.2), radius: 6, y: 2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A lifted card surface with a hairline border — the mobile echo of `AppTheme.surface`.
|
/// A lifted card surface with a hairline border — the mobile echo of `AppTheme.surface`.
|
||||||
struct CardBackground: ViewModifier {
|
struct CardBackground: ViewModifier {
|
||||||
var padding: CGFloat = 14
|
var padding: CGFloat = 14
|
||||||
@@ -373,6 +389,9 @@ extension View {
|
|||||||
func glassSurface(cornerRadius: CGFloat = 24) -> some View {
|
func glassSurface(cornerRadius: CGFloat = 24) -> some View {
|
||||||
modifier(GlassSurface(cornerRadius: cornerRadius))
|
modifier(GlassSurface(cornerRadius: cornerRadius))
|
||||||
}
|
}
|
||||||
|
/// Back a circular control (the floating New-chat FAB) with interactive Liquid Glass — the
|
||||||
|
/// round analogue of `glassSurface`, falling back to an ultra-thin material disc pre-iOS 26.
|
||||||
|
func glassCircle() -> some View { modifier(GlassCircle()) }
|
||||||
/// Apply the teal accent app-wide.
|
/// Apply the teal accent app-wide.
|
||||||
func nucleicTint() -> some View { tint(Palette.accent) }
|
func nucleicTint() -> some View { tint(Palette.accent) }
|
||||||
/// Give a text field a way to release the keyboard. Without this, iOS leaves a focused
|
/// Give a text field a way to release the keyboard. Without this, iOS leaves a focused
|
||||||
|
|||||||
Reference in New Issue
Block a user