feat: beautify command palette

This commit is contained in:
Aaron Ruan 2025-04-24 12:34:02 +08:00
parent 4e91d11a60
commit 3827ce9e4c
No known key found for this signature in database
3 changed files with 67 additions and 45 deletions

View File

@ -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 {
@ -18,7 +18,6 @@ struct CommandOption: Identifiable, Hashable {
struct CommandPaletteView: View {
@Binding var isPresented: Bool
var backgroundColor: Color = Color(nsColor: .windowBackgroundColor)
var options: [CommandOption]
@State private var query = ""
@State private var selectedIndex: UInt?
@ -89,7 +88,6 @@ struct CommandPaletteView: View {
}
Divider()
.padding(.bottom, 4)
CommandTable(
options: filteredOptions,
@ -100,15 +98,13 @@ 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)
)
.background(BackgroundVisualEffectView())
.clipShape(RoundedRectangle(cornerRadius: 10))
.overlay(
RoundedRectangle(cornerRadius: 10)
.stroke(Color(nsColor: .tertiaryLabelColor).opacity(0.75))
)
.shadow(radius: 32, x: 0, y: 12)
.padding()
}
}
@ -147,8 +143,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 +175,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 +195,7 @@ fileprivate struct CommandTable: View {
}
}
}
.padding(10)
}
.frame(maxHeight: 200)
.onChange(of: selectedIndex) { _ in
@ -223,20 +221,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 +234,43 @@ 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 view that creates a semi-transparent blurry background.
fileprivate struct BackgroundVisualEffectView: NSViewRepresentable {
func makeNSView(context: Context) -> NSVisualEffectView {
let view = NSVisualEffectView()
view.blendingMode = .withinWindow
view.state = .active
view.material = .sidebar
return view
}
func updateNSView(_ nsView: NSVisualEffectView, context: Context) {
//
}
}
/// 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)
}
}
}
}

View File

@ -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)
}
@ -59,7 +59,6 @@ struct TerminalCommandPaletteView: View {
CommandPaletteView(
isPresented: $isPresented,
backgroundColor: ghosttyConfig.backgroundColor,
options: commandOptions
)
.transition(

View File

@ -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.