diff --git a/macos/Sources/Features/About/About.xib b/macos/Sources/Features/About/About.xib index e884beff1..5803a32de 100644 --- a/macos/Sources/Features/About/About.xib +++ b/macos/Sources/Features/About/About.xib @@ -14,7 +14,7 @@ - + diff --git a/macos/Sources/Features/About/AboutController.swift b/macos/Sources/Features/About/AboutController.swift index d2ae68ea7..efd7a515a 100644 --- a/macos/Sources/Features/About/AboutController.swift +++ b/macos/Sources/Features/About/AboutController.swift @@ -10,6 +10,7 @@ class AboutController: NSWindowController, NSWindowDelegate { override func windowDidLoad() { guard let window = window else { return } window.center() + window.isMovableByWindowBackground = true window.contentView = NSHostingView(rootView: AboutView()) } diff --git a/macos/Sources/Features/About/AboutView.swift b/macos/Sources/Features/About/AboutView.swift index 02f899cc4..71fe9c252 100644 --- a/macos/Sources/Features/About/AboutView.swift +++ b/macos/Sources/Features/About/AboutView.swift @@ -1,35 +1,136 @@ import SwiftUI struct AboutView: View { + @Environment(\.openURL) var openURL + + private let githubLink = URL(string: "https://github.com/ghostty-org/ghostty") + /// Read the commit from the bundle. - var build: String? { Bundle.main.infoDictionary?["CFBundleVersion"] as? String } - var commit: String? { Bundle.main.infoDictionary?["GhosttyCommit"] as? String } - var version: String? { Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String } + private var build: String? { Bundle.main.infoDictionary?["CFBundleVersion"] as? String } + private var commit: String? { Bundle.main.infoDictionary?["GhosttyCommit"] as? String } + private var version: String? { Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String } + private var copyright: String? { Bundle.main.infoDictionary?["NSHumanReadableCopyright"] as? String } + + private var properties: [KeyValue] { + let list: [KeyValue] = [ + .init(key: "Version", value: version), + .init(key: "Build", value: build), + .init(key: "Commit", value: commit == "" ? nil : commit) + ] + + return list.compactMap { + guard let value = $0.value else { return nil } + return .init(key: $0.key, value: value) + } + } + + private struct KeyValue: Identifiable { + var id = UUID() + public let key: LocalizedStringResource + public let value: Value + } + + #if os(macOS) + // This creates a background style similar to the Apple "About My Mac" Window + private struct VisualEffectBackground: NSViewRepresentable { + let material: NSVisualEffectView.Material + let blendingMode: NSVisualEffectView.BlendingMode + let isEmphasized: Bool + + init(material: NSVisualEffectView.Material, + blendingMode: NSVisualEffectView.BlendingMode = .behindWindow, + isEmphasized: Bool = false) + { + self.material = material + self.blendingMode = blendingMode + self.isEmphasized = isEmphasized + } + + func updateNSView(_ nsView: NSVisualEffectView, context: Context) { + nsView.material = material + nsView.blendingMode = blendingMode + nsView.isEmphasized = isEmphasized + } + + func makeNSView(context: Context) -> NSVisualEffectView { + let visualEffect = NSVisualEffectView() + visualEffect.autoresizingMask = [.width, .height] + return visualEffect + } + } + #endif var body: some View { VStack(alignment: .center) { Image("AppIconImage") .resizable() .aspectRatio(contentMode: .fit) - .frame(maxHeight: 96) + .frame(height: 128) - Text("Ghostty") - .font(.title3) + VStack(alignment: .center, spacing: 32) { + VStack(alignment: .center, spacing: 8) { + Text("Ghostty") + .bold() + .font(.title) + Text("Fast, native, feature-rich terminal \nemulator pushing modern features.") + .multilineTextAlignment(.center) + .fixedSize(horizontal: false, vertical: true) + .font(.caption) + .tint(.secondary) + .opacity(0.8) + } .textSelection(.enabled) + VStack(spacing: 2) { + ForEach(properties) { item in + HStack(spacing: 4) { + Text(item.key) + .frame(width: 126, alignment: .trailing) + .padding(.trailing, 2) + Text(item.value) + .frame(width: 125, alignment: .leading) + .padding(.leading, 2) + .tint(.secondary) + .opacity(0.8) + } + .font(.callout) + .textSelection(.enabled) + .frame(maxWidth: .infinity) + } + } + .frame(maxWidth: .infinity) - if let version = self.version { - Text("Version: \(version)") - .font(.body) - .textSelection(.enabled) - } + HStack(spacing: 8) { + if let url = githubLink { + Button("GitHub") { + openURL(url) + } + } - if let build = self.build { - Text("Build: \(build)") - .font(.body) - .textSelection(.enabled) + } + + if let copy = self.copyright { + Text(copy) + .font(.caption) + .textSelection(.enabled) + .tint(.secondary) + .opacity(0.8) + .multilineTextAlignment(.center) + .frame(maxWidth: .infinity) + } } + .frame(maxWidth: .infinity) } - .frame(minWidth: 300) - .padding() + .padding(.top, 8) + .padding(32) + .frame(minWidth: 256) + #if os(macOS) + .background(VisualEffectBackground(material: .underWindowBackground).ignoresSafeArea()) + #endif + } +} + +struct AboutView_Previews: PreviewProvider { + static var previews: some View { + AboutView() } }