macos: add a popover to the readonly badge with info

pull/9130/head
Mitchell Hashimoto 2025-12-12 14:01:35 -08:00
parent 173d8efd90
commit 22b8809858
No known key found for this signature in database
GPG Key ID: 523D5DC389D273BC
1 changed files with 52 additions and 2 deletions

View File

@ -106,7 +106,9 @@ extension Ghostty {
// Readonly indicator badge
if surfaceView.readonly {
ReadonlyBadge()
ReadonlyBadge {
surfaceView.toggleReadonly(nil)
}
}
// Progress report
@ -767,6 +769,10 @@ extension Ghostty {
/// A badge overlay that indicates a surface is in readonly mode.
/// Positioned in the top-right corner and styled to be noticeable but unobtrusive.
struct ReadonlyBadge: View {
let onDisable: () -> Void
@State private var showingPopover = false
private let badgeColor = Color(hue: 0.08, saturation: 0.5, brightness: 0.8)
var body: some View {
@ -784,12 +790,18 @@ extension Ghostty {
.padding(.vertical, 4)
.background(badgeBackground)
.foregroundStyle(badgeColor)
.onTapGesture {
showingPopover = true
}
.backport.pointerStyle(.link)
.popover(isPresented: $showingPopover, arrowEdge: .bottom) {
ReadonlyPopoverView(onDisable: onDisable, isPresented: $showingPopover)
}
}
.padding(8)
Spacer()
}
.allowsHitTesting(false)
.accessibilityElement(children: .ignore)
.accessibilityLabel("Read-only terminal")
}
@ -803,6 +815,44 @@ extension Ghostty {
)
}
}
struct ReadonlyPopoverView: View {
let onDisable: () -> Void
@Binding var isPresented: Bool
var body: some View {
VStack(alignment: .leading, spacing: 16) {
VStack(alignment: .leading, spacing: 8) {
HStack(spacing: 8) {
Image(systemName: "eye.fill")
.foregroundColor(.orange)
.font(.system(size: 13))
Text("Read-Only Mode")
.font(.system(size: 13, weight: .semibold))
}
Text("This terminal is in read-only mode. You can still view, select, and scroll through the content, but no input events will be sent to the running application.")
.font(.system(size: 11))
.foregroundColor(.secondary)
.fixedSize(horizontal: false, vertical: true)
}
HStack {
Spacer()
Button("Disable") {
onDisable()
isPresented = false
}
.keyboardShortcut(.defaultAction)
.buttonStyle(.borderedProminent)
.controlSize(.small)
}
}
.padding(16)
.frame(width: 280)
}
}
#if canImport(AppKit)
/// When changing the split state, or going full screen (native or non), the terminal view