mirror of
https://github.com/ghostty-org/ghostty.git
synced 2026-04-19 05:50:27 +00:00
macos: cycle through our icons in the About view (#10298)
Clicking on the icon immediately advances to the next one. Hovering on the icon pauses the automatic cycling, and the "help" tooltip displays the icon's configuration name (for `macos-icon`). --- https://github.com/user-attachments/assets/5cfbd225-bbdf-4077-96c1-7da315ce02cc
This commit is contained in:
@@ -72,6 +72,7 @@
|
||||
Features/About/About.xib,
|
||||
Features/About/AboutController.swift,
|
||||
Features/About/AboutView.swift,
|
||||
Features/About/CyclingIconView.swift,
|
||||
"Features/App Intents/CloseTerminalIntent.swift",
|
||||
"Features/App Intents/CommandPaletteIntent.swift",
|
||||
"Features/App Intents/Entities/CommandEntity.swift",
|
||||
|
||||
@@ -946,33 +946,8 @@ class AppDelegate: NSObject,
|
||||
var appIconName: String? = config.macosIcon.rawValue
|
||||
|
||||
switch (config.macosIcon) {
|
||||
case .official:
|
||||
// Discard saved icon name
|
||||
appIconName = nil
|
||||
break
|
||||
case .blueprint:
|
||||
appIcon = NSImage(named: "BlueprintImage")!
|
||||
|
||||
case .chalkboard:
|
||||
appIcon = NSImage(named: "ChalkboardImage")!
|
||||
|
||||
case .glass:
|
||||
appIcon = NSImage(named: "GlassImage")!
|
||||
|
||||
case .holographic:
|
||||
appIcon = NSImage(named: "HolographicImage")!
|
||||
|
||||
case .microchip:
|
||||
appIcon = NSImage(named: "MicrochipImage")!
|
||||
|
||||
case .paper:
|
||||
appIcon = NSImage(named: "PaperImage")!
|
||||
|
||||
case .retro:
|
||||
appIcon = NSImage(named: "RetroImage")!
|
||||
|
||||
case .xray:
|
||||
appIcon = NSImage(named: "XrayImage")!
|
||||
case let icon where icon.assetName != nil:
|
||||
appIcon = NSImage(named: icon.assetName!)!
|
||||
|
||||
case .custom:
|
||||
if let userIcon = NSImage(contentsOfFile: config.macosCustomIcon) {
|
||||
@@ -982,6 +957,7 @@ class AppDelegate: NSObject,
|
||||
appIcon = nil // Revert back to official icon if invalid location
|
||||
appIconName = nil // Discard saved icon name
|
||||
}
|
||||
|
||||
case .customStyle:
|
||||
// Discard saved icon name
|
||||
// if no valid colours were found
|
||||
@@ -997,6 +973,10 @@ class AppDelegate: NSObject,
|
||||
let colorStrings = ([ghostColor] + screenColors).compactMap(\.hexString)
|
||||
appIconName = (colorStrings + [config.macosIconFrame.rawValue])
|
||||
.joined(separator: "_")
|
||||
|
||||
default:
|
||||
// Discard saved icon name
|
||||
appIconName = nil
|
||||
}
|
||||
|
||||
// Only change the icon if it has actually changed from the current one,
|
||||
|
||||
@@ -44,10 +44,7 @@ struct AboutView: View {
|
||||
|
||||
var body: some View {
|
||||
VStack(alignment: .center) {
|
||||
ghosttyIconImage()
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.frame(height: 128)
|
||||
CyclingIconView()
|
||||
|
||||
VStack(alignment: .center, spacing: 32) {
|
||||
VStack(alignment: .center, spacing: 8) {
|
||||
|
||||
62
macos/Sources/Features/About/CyclingIconView.swift
Normal file
62
macos/Sources/Features/About/CyclingIconView.swift
Normal file
@@ -0,0 +1,62 @@
|
||||
import SwiftUI
|
||||
import GhosttyKit
|
||||
|
||||
/// A view that cycles through Ghostty's official icon variants.
|
||||
struct CyclingIconView: View {
|
||||
@State private var currentIcon: Ghostty.MacOSIcon = .official
|
||||
@State private var isHovering: Bool = false
|
||||
|
||||
private let icons: [Ghostty.MacOSIcon] = [
|
||||
.official,
|
||||
.blueprint,
|
||||
.chalkboard,
|
||||
.microchip,
|
||||
.glass,
|
||||
.holographic,
|
||||
.paper,
|
||||
.retro,
|
||||
.xray,
|
||||
]
|
||||
private let timerPublisher = Timer.publish(every: 3, on: .main, in: .common)
|
||||
|
||||
var body: some View {
|
||||
ZStack {
|
||||
iconView(for: currentIcon)
|
||||
.id(currentIcon)
|
||||
}
|
||||
.animation(.easeInOut(duration: 0.5), value: currentIcon)
|
||||
.frame(height: 128)
|
||||
.onReceive(timerPublisher.autoconnect()) { _ in
|
||||
if !isHovering {
|
||||
advanceToNextIcon()
|
||||
}
|
||||
}
|
||||
.onHover { hovering in
|
||||
isHovering = hovering
|
||||
}
|
||||
.onTapGesture {
|
||||
advanceToNextIcon()
|
||||
}
|
||||
.help("macos-icon = \(currentIcon.rawValue)")
|
||||
.accessibilityLabel("Ghostty Application Icon")
|
||||
.accessibilityHint("Click to cycle through icon variants")
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
private func iconView(for icon: Ghostty.MacOSIcon) -> some View {
|
||||
let iconImage: Image = switch icon.assetName {
|
||||
case let assetName?: Image(assetName)
|
||||
case nil: ghosttyIconImage()
|
||||
}
|
||||
|
||||
iconImage
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fit)
|
||||
}
|
||||
|
||||
private func advanceToNextIcon() {
|
||||
let currentIndex = icons.firstIndex(of: currentIcon) ?? 0
|
||||
let nextIndex = icons.indexWrapping(after: currentIndex)
|
||||
currentIcon = icons[nextIndex]
|
||||
}
|
||||
}
|
||||
@@ -330,6 +330,22 @@ extension Ghostty {
|
||||
case xray
|
||||
case custom
|
||||
case customStyle = "custom-style"
|
||||
|
||||
/// Bundled asset name for built-in icons
|
||||
var assetName: String? {
|
||||
switch self {
|
||||
case .official: return nil
|
||||
case .blueprint: return "BlueprintImage"
|
||||
case .chalkboard: return "ChalkboardImage"
|
||||
case .microchip: return "MicrochipImage"
|
||||
case .glass: return "GlassImage"
|
||||
case .holographic: return "HolographicImage"
|
||||
case .paper: return "PaperImage"
|
||||
case .retro: return "RetroImage"
|
||||
case .xray: return "XrayImage"
|
||||
case .custom, .customStyle: return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// macos-icon-frame
|
||||
|
||||
Reference in New Issue
Block a user