mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-05-05 15:33:00 +00:00
feat: beautify macOS command palette (#7179)
Some checks failed
Nix / check-zig-cache-hash (push) Has been cancelled
Test / test (push) Has been cancelled
Test / zig-fmt (push) Has been cancelled
Test / prettier (push) Has been cancelled
Test / alejandra (push) Has been cancelled
Test / typos (push) Has been cancelled
Test / translations (push) Has been cancelled
Test / blueprint-compiler (push) Has been cancelled
Test / flatpak-check-zig-cache (push) Has been cancelled
Nix / Required Checks: Nix (push) Has been cancelled
Test / Required Checks: Test (push) Has been cancelled
Test / build-bench (push) Has been cancelled
Test / build-flatpak (push) Has been cancelled
Test / build-linux (namespace-profile-ghostty-md) (push) Has been cancelled
Test / build-linux (namespace-profile-ghostty-md-arm64) (push) Has been cancelled
Test / build-linux-libghostty (push) Has been cancelled
Test / build-nix (namespace-profile-ghostty-md) (push) Has been cancelled
Test / build-nix (namespace-profile-ghostty-md-arm64) (push) Has been cancelled
Test / build-dist (push) Has been cancelled
Test / build-macos (push) Has been cancelled
Test / build-macos-matrix (push) Has been cancelled
Test / build-snap (namespace-profile-ghostty-snap) (push) Has been cancelled
Test / build-snap (namespace-profile-ghostty-snap-arm64) (push) Has been cancelled
Test / build-windows (push) Has been cancelled
Test / build-windows-cross (namespace-profile-ghostty-md, x86-windows-gnu) (push) Has been cancelled
Test / build-windows-cross (namespace-profile-ghostty-md, x86_64-windows-gnu) (push) Has been cancelled
Test / GTK x11=false wayland=false (push) Has been cancelled
Test / GTK x11=true wayland=false (push) Has been cancelled
Test / GTK x11=false wayland=true (push) Has been cancelled
Test / GTK x11=true wayland=true (push) Has been cancelled
Test / Build -Dsentry=false (push) Has been cancelled
Test / Build -Dsentry=true (push) Has been cancelled
Test / test-macos (push) Has been cancelled
Test / Test pkg/wuffs (push) Has been cancelled
Test / Test build on Debian 12 (push) Has been cancelled
Test / Flatpak (map[arch:aarch64 runner:namespace-profile-ghostty-md-arm64]) (push) Has been cancelled
Test / Flatpak (map[arch:x86_64 runner:namespace-profile-ghostty-md]) (push) Has been cancelled
Update iTerm2 colorschemes / update-iterm2-schemes (push) Has been cancelled
Some checks failed
Nix / check-zig-cache-hash (push) Has been cancelled
Test / test (push) Has been cancelled
Test / zig-fmt (push) Has been cancelled
Test / prettier (push) Has been cancelled
Test / alejandra (push) Has been cancelled
Test / typos (push) Has been cancelled
Test / translations (push) Has been cancelled
Test / blueprint-compiler (push) Has been cancelled
Test / flatpak-check-zig-cache (push) Has been cancelled
Nix / Required Checks: Nix (push) Has been cancelled
Test / Required Checks: Test (push) Has been cancelled
Test / build-bench (push) Has been cancelled
Test / build-flatpak (push) Has been cancelled
Test / build-linux (namespace-profile-ghostty-md) (push) Has been cancelled
Test / build-linux (namespace-profile-ghostty-md-arm64) (push) Has been cancelled
Test / build-linux-libghostty (push) Has been cancelled
Test / build-nix (namespace-profile-ghostty-md) (push) Has been cancelled
Test / build-nix (namespace-profile-ghostty-md-arm64) (push) Has been cancelled
Test / build-dist (push) Has been cancelled
Test / build-macos (push) Has been cancelled
Test / build-macos-matrix (push) Has been cancelled
Test / build-snap (namespace-profile-ghostty-snap) (push) Has been cancelled
Test / build-snap (namespace-profile-ghostty-snap-arm64) (push) Has been cancelled
Test / build-windows (push) Has been cancelled
Test / build-windows-cross (namespace-profile-ghostty-md, x86-windows-gnu) (push) Has been cancelled
Test / build-windows-cross (namespace-profile-ghostty-md, x86_64-windows-gnu) (push) Has been cancelled
Test / GTK x11=false wayland=false (push) Has been cancelled
Test / GTK x11=true wayland=false (push) Has been cancelled
Test / GTK x11=false wayland=true (push) Has been cancelled
Test / GTK x11=true wayland=true (push) Has been cancelled
Test / Build -Dsentry=false (push) Has been cancelled
Test / Build -Dsentry=true (push) Has been cancelled
Test / test-macos (push) Has been cancelled
Test / Test pkg/wuffs (push) Has been cancelled
Test / Test build on Debian 12 (push) Has been cancelled
Test / Flatpak (map[arch:aarch64 runner:namespace-profile-ghostty-md-arm64]) (push) Has been cancelled
Test / Flatpak (map[arch:x86_64 runner:namespace-profile-ghostty-md]) (push) Has been cancelled
Update iTerm2 colorschemes / update-iterm2-schemes (push) Has been cancelled
Resolve 1. of #7173 <img width="1126" alt="image" src="https://github.com/user-attachments/assets/8904b09f-42f6-4f26-a722-c92dad8e2933" /> Changes made: 1. Change shortcut from `String` to `[String]` so its easier to iterate over it. 2. Overlay background color on top of an `ultraThinMaterial` for better aesthetic. 3. Reorganize and beautify the spacings and paddings. 4. Unhide the scrollbar. 5. Reorder the modifier keys to Control, Option, Shift and then Command. <https://leancrew.com/all-this/2017/11/modifier-key-order/> 6. Style shortcut keys to resemble macOS menu bar items, using corresponding symbols and fixed-width for alignment.
This commit is contained in:
commit
38445dca2a
@ -4,7 +4,7 @@ struct CommandOption: Identifiable, Hashable {
|
||||
let id = UUID()
|
||||
let title: String
|
||||
let description: String?
|
||||
let shortcut: String?
|
||||
let symbols: [String]?
|
||||
let action: () -> Void
|
||||
|
||||
static func == (lhs: CommandOption, rhs: CommandOption) -> Bool {
|
||||
@ -44,6 +44,12 @@ struct CommandPaletteView: View {
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
let scheme: ColorScheme = if OSColor(backgroundColor).isLightColor {
|
||||
.light
|
||||
} else {
|
||||
.dark
|
||||
}
|
||||
|
||||
VStack(alignment: .leading, spacing: 0) {
|
||||
CommandPaletteQuery(query: $query) { event in
|
||||
switch (event) {
|
||||
@ -89,7 +95,6 @@ struct CommandPaletteView: View {
|
||||
}
|
||||
|
||||
Divider()
|
||||
.padding(.bottom, 4)
|
||||
|
||||
CommandTable(
|
||||
options: filteredOptions,
|
||||
@ -101,15 +106,23 @@ struct CommandPaletteView: View {
|
||||
}
|
||||
.frame(maxWidth: 500)
|
||||
.background(
|
||||
RoundedRectangle(cornerRadius: 12)
|
||||
.fill(backgroundColor)
|
||||
.shadow(color: .black.opacity(0.4), radius: 10, x: 0, y: 10)
|
||||
.overlay(
|
||||
RoundedRectangle(cornerRadius: 12)
|
||||
.stroke(Color.black.opacity(0.1), lineWidth: 1)
|
||||
)
|
||||
ZStack {
|
||||
Rectangle()
|
||||
.fill(.ultraThinMaterial)
|
||||
Rectangle()
|
||||
.fill(backgroundColor)
|
||||
.blendMode(.color)
|
||||
}
|
||||
.compositingGroup()
|
||||
)
|
||||
.clipShape(RoundedRectangle(cornerRadius: 10))
|
||||
.overlay(
|
||||
RoundedRectangle(cornerRadius: 10)
|
||||
.stroke(Color(nsColor: .tertiaryLabelColor).opacity(0.75))
|
||||
)
|
||||
.shadow(radius: 32, x: 0, y: 12)
|
||||
.padding()
|
||||
.environment(\.colorScheme, scheme)
|
||||
}
|
||||
}
|
||||
|
||||
@ -147,8 +160,9 @@ fileprivate struct CommandPaletteQuery: View {
|
||||
|
||||
TextField("Execute a command…", text: $query)
|
||||
.padding()
|
||||
.font(.system(size: 14))
|
||||
.textFieldStyle(PlainTextFieldStyle())
|
||||
.font(.system(size: 20, weight: .light))
|
||||
.frame(height: 48)
|
||||
.textFieldStyle(.plain)
|
||||
.focused($isTextFieldFocused)
|
||||
.onAppear {
|
||||
isTextFieldFocused = true
|
||||
@ -178,7 +192,7 @@ fileprivate struct CommandTable: View {
|
||||
.padding()
|
||||
} else {
|
||||
ScrollViewReader { proxy in
|
||||
ScrollView(showsIndicators: false) {
|
||||
ScrollView {
|
||||
VStack(alignment: .leading, spacing: 0) {
|
||||
ForEach(Array(options.enumerated()), id: \.1.id) { index, option in
|
||||
CommandRow(
|
||||
@ -198,6 +212,7 @@ fileprivate struct CommandTable: View {
|
||||
}
|
||||
}
|
||||
}
|
||||
.padding(10)
|
||||
}
|
||||
.frame(maxHeight: 200)
|
||||
.onChange(of: selectedIndex) { _ in
|
||||
@ -223,20 +238,12 @@ fileprivate struct CommandRow: View {
|
||||
HStack {
|
||||
Text(option.title)
|
||||
Spacer()
|
||||
if let shortcut = option.shortcut {
|
||||
Text(shortcut)
|
||||
.font(.system(.body, design: .monospaced))
|
||||
.kerning(1.5)
|
||||
.padding(.horizontal, 6)
|
||||
.padding(.vertical, 2)
|
||||
.background(
|
||||
RoundedRectangle(cornerRadius: 6)
|
||||
.fill(Color.gray.opacity(0.2))
|
||||
)
|
||||
if let symbols = option.symbols {
|
||||
ShortcutSymbolsView(symbols: symbols)
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
}
|
||||
.padding(.horizontal, 6)
|
||||
.padding(.vertical, 8)
|
||||
.padding(8)
|
||||
.background(
|
||||
isSelected
|
||||
? Color.accentColor.opacity(0.2)
|
||||
@ -244,14 +251,26 @@ fileprivate struct CommandRow: View {
|
||||
? Color.secondary.opacity(0.2)
|
||||
: Color.clear)
|
||||
)
|
||||
.cornerRadius(6)
|
||||
.cornerRadius(5)
|
||||
}
|
||||
.help(option.description ?? "")
|
||||
.buttonStyle(PlainButtonStyle())
|
||||
.buttonStyle(.plain)
|
||||
.onHover { hovering in
|
||||
hoveredID = hovering ? option.id : nil
|
||||
}
|
||||
.padding(.horizontal, 4)
|
||||
.padding(.vertical, 1)
|
||||
}
|
||||
}
|
||||
|
||||
/// A row of Text representing a shortcut.
|
||||
fileprivate struct ShortcutSymbolsView: View {
|
||||
let symbols: [String]
|
||||
|
||||
var body: some View {
|
||||
HStack(spacing: 1) {
|
||||
ForEach(symbols, id: \.self) { symbol in
|
||||
Text(symbol)
|
||||
.frame(minWidth: 13)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -40,7 +40,7 @@ struct TerminalCommandPaletteView: View {
|
||||
return CommandOption(
|
||||
title: String(cString: c.title),
|
||||
description: String(cString: c.description),
|
||||
shortcut: ghosttyConfig.keyboardShortcut(for: action)?.description
|
||||
symbols: ghosttyConfig.keyboardShortcut(for: action)?.keyList
|
||||
) {
|
||||
onAction(action)
|
||||
}
|
||||
|
@ -1,12 +1,9 @@
|
||||
import SwiftUI
|
||||
|
||||
extension KeyboardShortcut: @retroactive CustomStringConvertible {
|
||||
public var description: String {
|
||||
var result = ""
|
||||
public var keyList: [String] {
|
||||
var result: [String] = []
|
||||
|
||||
if modifiers.contains(.command) {
|
||||
result.append("⌘")
|
||||
}
|
||||
if modifiers.contains(.control) {
|
||||
result.append("⌃")
|
||||
}
|
||||
@ -16,6 +13,9 @@ extension KeyboardShortcut: @retroactive CustomStringConvertible {
|
||||
if modifiers.contains(.shift) {
|
||||
result.append("⇧")
|
||||
}
|
||||
if modifiers.contains(.command) {
|
||||
result.append("⌘")
|
||||
}
|
||||
|
||||
let keyString: String
|
||||
switch key {
|
||||
@ -24,14 +24,14 @@ extension KeyboardShortcut: @retroactive CustomStringConvertible {
|
||||
case .delete: keyString = "⌫"
|
||||
case .space: keyString = "␣"
|
||||
case .tab: keyString = "⇥"
|
||||
case .upArrow: keyString = "↑"
|
||||
case .downArrow: keyString = "↓"
|
||||
case .leftArrow: keyString = "←"
|
||||
case .rightArrow: keyString = "→"
|
||||
case .pageUp: keyString = "PgUp"
|
||||
case .pageDown: keyString = "PgDown"
|
||||
case .end: keyString = "End"
|
||||
case .home: keyString = "Home"
|
||||
case .upArrow: keyString = "▲"
|
||||
case .downArrow: keyString = "▼"
|
||||
case .leftArrow: keyString = "◀"
|
||||
case .rightArrow: keyString = "▶"
|
||||
case .pageUp: keyString = "↑"
|
||||
case .pageDown: keyString = "↓"
|
||||
case .home: keyString = "⤒"
|
||||
case .end: keyString = "⤓"
|
||||
default:
|
||||
keyString = String(key.character.uppercased())
|
||||
}
|
||||
@ -39,6 +39,10 @@ extension KeyboardShortcut: @retroactive CustomStringConvertible {
|
||||
result.append(keyString)
|
||||
return result
|
||||
}
|
||||
|
||||
public var description: String {
|
||||
return self.keyList.joined()
|
||||
}
|
||||
}
|
||||
|
||||
// This is available in macOS 14 so this only applies to early macOS versions.
|
||||
|
Loading…
x
Reference in New Issue
Block a user