feat: Update about menu design to match macOS.

This commit is contained in:
Josh
2024-10-19 00:31:43 -07:00
parent 0084103ff1
commit 42bf37af32
3 changed files with 125 additions and 17 deletions

View File

@ -14,7 +14,7 @@
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/> <customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application" customClass="NSObject"/> <customObject id="-3" userLabel="Application" customClass="NSObject"/>
<window allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" animationBehavior="default" titlebarAppearsTransparent="YES" id="QvC-M9-y7g"> <window allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" animationBehavior="default" titlebarAppearsTransparent="YES" id="QvC-M9-y7g">
<windowStyleMask key="styleMask" titled="YES" closable="YES"/> <windowStyleMask key="styleMask" titled="YES" closable="YES" fullSizeContentView="YES"/>
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/> <windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
<rect key="contentRect" x="196" y="240" width="300" height="172"/> <rect key="contentRect" x="196" y="240" width="300" height="172"/>
<rect key="screenRect" x="0.0" y="0.0" width="3008" height="1667"/> <rect key="screenRect" x="0.0" y="0.0" width="3008" height="1667"/>

View File

@ -10,6 +10,7 @@ class AboutController: NSWindowController, NSWindowDelegate {
override func windowDidLoad() { override func windowDidLoad() {
guard let window = window else { return } guard let window = window else { return }
window.center() window.center()
window.isMovableByWindowBackground = true
window.contentView = NSHostingView(rootView: AboutView()) window.contentView = NSHostingView(rootView: AboutView())
} }

View File

@ -1,35 +1,142 @@
import SwiftUI import SwiftUI
struct AboutView: View { struct AboutView: View {
@Environment(\.openURL) var openURL
/// Eventually this should be a redirect like https://go.ghostty.dev/discord or https://go.ghostty.dev/github
@State var discordLink: String = "https://discord.gg/ghostty"
@State var githubLink: String = "https://github.com/ghostty-org/ghostty"
/// Read the commit from the bundle. /// Read the commit from the bundle.
var build: String? { Bundle.main.infoDictionary?["CFBundleVersion"] as? String } var build: String? { Bundle.main.infoDictionary?["CFBundleVersion"] as? String }
var commit: String? { Bundle.main.infoDictionary?["GhosttyCommit"] as? String } var commit: String? { Bundle.main.infoDictionary?["GhosttyCommit"] as? String }
var version: String? { Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String } var version: String? { Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String }
var copyright: String? { Bundle.main.infoDictionary?["NSHumanReadableCopyright"] as? String }
struct ValuePair<Value: Equatable>: Identifiable {
var id = UUID()
public let key: LocalizedStringResource
public let value: Value
}
var computedStrings: [ValuePair<String>] {
let list: [ValuePair<String?>] = [
ValuePair(key: "Version", value: self.version),
ValuePair(key: "Build", value: self.build),
ValuePair(key: "Commit", value: self.commit == "" ? nil : self.commit)
]
let strings: [ValuePair<String>] = list.compactMap {
guard let value = $0.value else { return nil }
return ValuePair(key: $0.key, value: value)
}
return strings
}
#if os(macOS)
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 { var body: some View {
VStack(alignment: .center) { VStack(alignment: .center) {
Image("AppIconImage") Image("AppIconImage")
.resizable() .resizable()
.aspectRatio(contentMode: .fit) .aspectRatio(contentMode: .fit)
.frame(maxHeight: 96) .frame(height: 128)
VStack(alignment: .center, spacing: 32) {
VStack(alignment: .center, spacing: 8) {
Text("Ghostty") Text("Ghostty")
.font(.title3) .bold()
.textSelection(.enabled) .font(.title)
Text("Fast, native, feature-rich terminal emulator pushing modern features.")
.multilineTextAlignment(.center)
.fixedSize(horizontal: false, vertical: true)
.font(.caption)
.tint(.secondary)
.opacity(0.8)
}
VStack(spacing: 2) {
ForEach(computedStrings) { item in
if let version = self.version { HStack(spacing: 4) {
Text("Version: \(version)") Text(item.key)
.font(.body) .frame(width: 126, alignment: .trailing)
.textSelection(.enabled) .padding(.trailing, 2)
Text(item.value)
.frame(width: 125, alignment: .leading)
.padding(.leading, 2)
.tint(.secondary)
.opacity(0.8)
}
.font(.callout)
.frame(maxWidth: .infinity)
}
}
.frame(maxWidth: .infinity)
HStack(spacing: 8) {
Button("Discord") {
guard let url = URL(string: discordLink) else { return
}
openURL(url)
}
Button("Github") {
guard let url = URL(string: githubLink) else { return
}
openURL(url)
}
} }
if let build = self.build { if let copy = self.copyright {
Text("Build: \(build)") Text(copy)
.font(.body) .font(.caption)
.textSelection(.enabled) .tint(.secondary)
.opacity(0.8)
.multilineTextAlignment(.center)
.frame(maxWidth: .infinity)
} }
} }
.frame(minWidth: 300) .frame(maxWidth: .infinity)
.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()
} }
} }