Add Keyboardshortcutlview
This commit is contained in:
parent
fb69db2fe9
commit
35a08dce7b
467
VoiceInk/Views/KeyboardShortcutsListView.swift
Normal file
467
VoiceInk/Views/KeyboardShortcutsListView.swift
Normal file
@ -0,0 +1,467 @@
|
||||
import SwiftUI
|
||||
import SwiftData
|
||||
import KeyboardShortcuts
|
||||
|
||||
struct KeyboardShortcutsListView: View {
|
||||
@EnvironmentObject private var hotkeyManager: HotkeyManager
|
||||
@ObservedObject private var shortcutSettings = EnhancementShortcutSettings.shared
|
||||
@State private var customCancelShortcut: KeyboardShortcuts.Shortcut?
|
||||
@State private var pasteOriginalShortcut: KeyboardShortcuts.Shortcut?
|
||||
@State private var pasteEnhancedShortcut: KeyboardShortcuts.Shortcut?
|
||||
@State private var retryShortcut: KeyboardShortcuts.Shortcut?
|
||||
@State private var toggleHotkey1: KeyboardShortcuts.Shortcut?
|
||||
@State private var toggleHotkey2: KeyboardShortcuts.Shortcut?
|
||||
|
||||
var body: some View {
|
||||
VStack(spacing: 0) {
|
||||
// Header
|
||||
VStack(alignment: .leading, spacing: 6) {
|
||||
Text("Keyboard Shortcuts")
|
||||
.font(.system(size: 24, weight: .bold))
|
||||
.foregroundColor(.primary)
|
||||
Text("Quick reference for all VoiceInk shortcuts")
|
||||
.font(.system(size: 13, weight: .medium))
|
||||
.foregroundColor(.secondary)
|
||||
}
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.padding(.horizontal, 28)
|
||||
.padding(.vertical, 24)
|
||||
.background(
|
||||
Rectangle()
|
||||
.fill(Color(NSColor.controlBackgroundColor).opacity(0.5))
|
||||
)
|
||||
|
||||
Divider()
|
||||
.overlay(Color(NSColor.separatorColor).opacity(0.5))
|
||||
|
||||
// Content
|
||||
ScrollView {
|
||||
LazyVGrid(columns: [
|
||||
GridItem(.flexible(), spacing: 14),
|
||||
GridItem(.flexible(), spacing: 14)
|
||||
], spacing: 14) {
|
||||
// Recording Hotkeys
|
||||
if hotkeyManager.selectedHotkey1 != .none {
|
||||
ShortcutCard(
|
||||
icon: "mic.fill",
|
||||
iconColor: .blue,
|
||||
title: "Toggle Recording",
|
||||
subtitle: "Hotkey 1"
|
||||
) {
|
||||
if hotkeyManager.selectedHotkey1 == .custom, let shortcut = toggleHotkey1 {
|
||||
KeyboardShortcutBadge(shortcut: shortcut)
|
||||
} else {
|
||||
HotkeyBadge(text: hotkeyManager.selectedHotkey1.displayName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if hotkeyManager.selectedHotkey2 != .none {
|
||||
ShortcutCard(
|
||||
icon: "mic.fill",
|
||||
iconColor: .purple,
|
||||
title: "Toggle Recording",
|
||||
subtitle: "Hotkey 2"
|
||||
) {
|
||||
if hotkeyManager.selectedHotkey2 == .custom, let shortcut = toggleHotkey2 {
|
||||
KeyboardShortcutBadge(shortcut: shortcut)
|
||||
} else {
|
||||
HotkeyBadge(text: hotkeyManager.selectedHotkey2.displayName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if hotkeyManager.isMiddleClickToggleEnabled {
|
||||
ShortcutCard(
|
||||
icon: "cursorarrow.click.2",
|
||||
iconColor: .green,
|
||||
title: "Middle-Click",
|
||||
subtitle: "Hold to record"
|
||||
) {
|
||||
MouseBadge()
|
||||
}
|
||||
}
|
||||
|
||||
// Transcription Actions
|
||||
ShortcutCard(
|
||||
icon: "doc.text.fill",
|
||||
iconColor: .orange,
|
||||
title: "Paste Last Transcription (Orig.)",
|
||||
subtitle: "Paste most recent original transcription"
|
||||
) {
|
||||
if let shortcut = pasteOriginalShortcut {
|
||||
KeyboardShortcutBadge(shortcut: shortcut)
|
||||
} else {
|
||||
NotSetBadge()
|
||||
}
|
||||
}
|
||||
|
||||
ShortcutCard(
|
||||
icon: "wand.and.stars",
|
||||
iconColor: .pink,
|
||||
title: "Paste Last Transcription (Enh.)",
|
||||
subtitle: "Paste enhanced or original if unavailable"
|
||||
) {
|
||||
if let shortcut = pasteEnhancedShortcut {
|
||||
KeyboardShortcutBadge(shortcut: shortcut)
|
||||
} else {
|
||||
NotSetBadge()
|
||||
}
|
||||
}
|
||||
|
||||
ShortcutCard(
|
||||
icon: "arrow.clockwise",
|
||||
iconColor: .blue,
|
||||
title: "Retry Last Transcription",
|
||||
subtitle: "Redo the last transcription"
|
||||
) {
|
||||
if let shortcut = retryShortcut {
|
||||
KeyboardShortcutBadge(shortcut: shortcut)
|
||||
} else {
|
||||
NotSetBadge()
|
||||
}
|
||||
}
|
||||
|
||||
// Recording Session Shortcuts
|
||||
ShortcutCard(
|
||||
icon: "escape",
|
||||
iconColor: .red,
|
||||
title: "Dismiss Recorder",
|
||||
subtitle: customCancelShortcut != nil ? "Custom shortcut or default: Double ESC" : "Default: Double ESC"
|
||||
) {
|
||||
if let cancelShortcut = customCancelShortcut {
|
||||
KeyboardShortcutBadge(shortcut: cancelShortcut)
|
||||
} else {
|
||||
StaticKeysBadge(keys: ["⎋", "⎋"])
|
||||
}
|
||||
}
|
||||
|
||||
ShortcutCard(
|
||||
icon: "wand.and.stars",
|
||||
iconColor: .purple,
|
||||
title: "Toggle Enhancement",
|
||||
subtitle: shortcutSettings.isToggleEnhancementShortcutEnabled ? "Enable/disable AI enhancement" : "Disabled in settings"
|
||||
) {
|
||||
StaticKeysBadge(keys: ["⌘", "E"], isEnabled: shortcutSettings.isToggleEnhancementShortcutEnabled)
|
||||
}
|
||||
|
||||
ShortcutCard(
|
||||
icon: "wand.and.stars",
|
||||
iconColor: .orange,
|
||||
title: "Switch Enhancement Prompt",
|
||||
subtitle: "Use ⌘1–⌘0 (Command)"
|
||||
) {
|
||||
StaticKeysBadge(keys: ["⌘", "1–0"])
|
||||
}
|
||||
|
||||
ShortcutCard(
|
||||
icon: "sparkles.square.fill.on.square",
|
||||
iconColor: Color(red: 1.0, green: 0.8, blue: 0.0),
|
||||
title: "Switch Power Mode",
|
||||
subtitle: "Use ⌥1–⌥0 (Option)"
|
||||
) {
|
||||
StaticKeysBadge(keys: ["⌥", "1–0"])
|
||||
}
|
||||
}
|
||||
.padding(.horizontal, 26)
|
||||
.padding(.vertical, 26)
|
||||
}
|
||||
.background(
|
||||
LinearGradient(
|
||||
gradient: Gradient(colors: [
|
||||
Color(NSColor.windowBackgroundColor),
|
||||
Color(NSColor.controlBackgroundColor).opacity(0.3)
|
||||
]),
|
||||
startPoint: .top,
|
||||
endPoint: .bottom
|
||||
)
|
||||
)
|
||||
}
|
||||
.frame(width: 820, height: 600)
|
||||
.clipShape(RoundedRectangle(cornerRadius: 12, style: .continuous))
|
||||
.onAppear {
|
||||
loadShortcuts()
|
||||
}
|
||||
.onReceive(Timer.publish(every: 0.5, on: .main, in: .common).autoconnect()) { _ in
|
||||
// Poll for shortcut changes every 0.5 seconds
|
||||
loadShortcuts()
|
||||
}
|
||||
}
|
||||
|
||||
private func loadShortcuts() {
|
||||
customCancelShortcut = KeyboardShortcuts.getShortcut(for: .cancelRecorder)
|
||||
pasteOriginalShortcut = KeyboardShortcuts.getShortcut(for: .pasteLastTranscription)
|
||||
pasteEnhancedShortcut = KeyboardShortcuts.getShortcut(for: .pasteLastEnhancement)
|
||||
retryShortcut = KeyboardShortcuts.getShortcut(for: .retryLastTranscription)
|
||||
toggleHotkey1 = KeyboardShortcuts.getShortcut(for: .toggleMiniRecorder)
|
||||
toggleHotkey2 = KeyboardShortcuts.getShortcut(for: .toggleMiniRecorder2)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Shortcut Card
|
||||
private struct ShortcutCard<Content: View>: View {
|
||||
let title: String
|
||||
let subtitle: String
|
||||
let shortcutView: Content
|
||||
|
||||
init(icon: String = "", iconColor: Color = .clear, title: String, subtitle: String, @ViewBuilder shortcutView: () -> Content) {
|
||||
self.title = title
|
||||
self.subtitle = subtitle
|
||||
self.shortcutView = shortcutView()
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
HStack(alignment: .center, spacing: 16) {
|
||||
VStack(alignment: .leading, spacing: 4) {
|
||||
Text(title)
|
||||
.font(.system(size: 14, weight: .semibold))
|
||||
.foregroundColor(.primary)
|
||||
.lineLimit(1)
|
||||
|
||||
Text(subtitle)
|
||||
.font(.system(size: 12, weight: .regular))
|
||||
.foregroundColor(.secondary.opacity(0.8))
|
||||
.lineLimit(1)
|
||||
}
|
||||
|
||||
Spacer(minLength: 12)
|
||||
|
||||
shortcutView
|
||||
}
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.padding(.horizontal, 18)
|
||||
.padding(.vertical, 16)
|
||||
.background(
|
||||
RoundedRectangle(cornerRadius: 10, style: .continuous)
|
||||
.fill(
|
||||
LinearGradient(
|
||||
gradient: Gradient(colors: [
|
||||
Color(NSColor.controlBackgroundColor).opacity(0.7),
|
||||
Color(NSColor.controlBackgroundColor).opacity(0.5)
|
||||
]),
|
||||
startPoint: .topLeading,
|
||||
endPoint: .bottomTrailing
|
||||
)
|
||||
)
|
||||
)
|
||||
.overlay(
|
||||
RoundedRectangle(cornerRadius: 10, style: .continuous)
|
||||
.strokeBorder(
|
||||
LinearGradient(
|
||||
gradient: Gradient(colors: [
|
||||
Color(NSColor.separatorColor).opacity(0.5),
|
||||
Color(NSColor.separatorColor).opacity(0.3)
|
||||
]),
|
||||
startPoint: .top,
|
||||
endPoint: .bottom
|
||||
),
|
||||
lineWidth: 1.5
|
||||
)
|
||||
)
|
||||
.shadow(color: Color(NSColor.shadowColor).opacity(0.2), radius: 4, x: 0, y: 2)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Badge Components
|
||||
private struct KeyboardShortcutBadge: View {
|
||||
let shortcut: KeyboardShortcuts.Shortcut
|
||||
|
||||
var body: some View {
|
||||
HStack(spacing: 4) {
|
||||
ForEach(shortcutComponents, id: \.self) { component in
|
||||
KeyBadge(text: component)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private var shortcutComponents: [String] {
|
||||
var components: [String] = []
|
||||
if shortcut.modifiers.contains(.command) { components.append("⌘") }
|
||||
if shortcut.modifiers.contains(.option) { components.append("⌥") }
|
||||
if shortcut.modifiers.contains(.shift) { components.append("⇧") }
|
||||
if shortcut.modifiers.contains(.control) { components.append("⌃") }
|
||||
if let key = shortcut.key {
|
||||
components.append(keyToString(key))
|
||||
}
|
||||
return components
|
||||
}
|
||||
|
||||
private func keyToString(_ key: KeyboardShortcuts.Key) -> String {
|
||||
switch key {
|
||||
case .space: return "Space"
|
||||
case .return: return "↩"
|
||||
case .escape: return "⎋"
|
||||
case .a: return "A"
|
||||
case .b: return "B"
|
||||
case .c: return "C"
|
||||
case .d: return "D"
|
||||
case .e: return "E"
|
||||
case .f: return "F"
|
||||
case .g: return "G"
|
||||
case .h: return "H"
|
||||
case .i: return "I"
|
||||
case .j: return "J"
|
||||
case .k: return "K"
|
||||
case .l: return "L"
|
||||
case .m: return "M"
|
||||
case .n: return "N"
|
||||
case .o: return "O"
|
||||
case .p: return "P"
|
||||
case .q: return "Q"
|
||||
case .r: return "R"
|
||||
case .s: return "S"
|
||||
case .t: return "T"
|
||||
case .u: return "U"
|
||||
case .v: return "V"
|
||||
case .w: return "W"
|
||||
case .x: return "X"
|
||||
case .y: return "Y"
|
||||
case .z: return "Z"
|
||||
case .zero: return "0"
|
||||
case .one: return "1"
|
||||
case .two: return "2"
|
||||
case .three: return "3"
|
||||
case .four: return "4"
|
||||
case .five: return "5"
|
||||
case .six: return "6"
|
||||
case .seven: return "7"
|
||||
case .eight: return "8"
|
||||
case .nine: return "9"
|
||||
default: return String(key.rawValue).uppercased()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private struct StaticKeysBadge: View {
|
||||
let keys: [String]
|
||||
var isEnabled: Bool = true
|
||||
|
||||
var body: some View {
|
||||
HStack(spacing: 4) {
|
||||
ForEach(keys, id: \.self) { key in
|
||||
KeyBadge(text: key, isEnabled: isEnabled)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private struct KeyBadge: View {
|
||||
let text: String
|
||||
var isEnabled: Bool = true
|
||||
|
||||
var body: some View {
|
||||
Text(text)
|
||||
.font(.system(size: 13, weight: .semibold, design: .rounded))
|
||||
.foregroundColor(isEnabled ? .primary : .secondary)
|
||||
.padding(.horizontal, 10)
|
||||
.padding(.vertical, 6)
|
||||
.background(
|
||||
RoundedRectangle(cornerRadius: 6, style: .continuous)
|
||||
.fill(
|
||||
LinearGradient(
|
||||
gradient: Gradient(colors: [
|
||||
Color(NSColor.controlBackgroundColor).opacity(isEnabled ? 0.9 : 0.6),
|
||||
Color(NSColor.controlBackgroundColor).opacity(isEnabled ? 0.7 : 0.5)
|
||||
]),
|
||||
startPoint: .top,
|
||||
endPoint: .bottom
|
||||
)
|
||||
)
|
||||
)
|
||||
.overlay(
|
||||
RoundedRectangle(cornerRadius: 6, style: .continuous)
|
||||
.strokeBorder(
|
||||
Color(NSColor.separatorColor).opacity(isEnabled ? 0.4 : 0.2),
|
||||
lineWidth: 1
|
||||
)
|
||||
)
|
||||
.shadow(color: Color(NSColor.shadowColor).opacity(isEnabled ? 0.15 : 0.05), radius: 2, x: 0, y: 1)
|
||||
.opacity(isEnabled ? 1.0 : 0.6)
|
||||
}
|
||||
}
|
||||
|
||||
private struct HotkeyBadge: View {
|
||||
let text: String
|
||||
|
||||
var body: some View {
|
||||
Text(text)
|
||||
.font(.system(size: 12, weight: .semibold))
|
||||
.foregroundColor(.primary)
|
||||
.padding(.horizontal, 12)
|
||||
.padding(.vertical, 6)
|
||||
.background(
|
||||
RoundedRectangle(cornerRadius: 6, style: .continuous)
|
||||
.fill(
|
||||
LinearGradient(
|
||||
gradient: Gradient(colors: [
|
||||
Color(NSColor.controlBackgroundColor).opacity(0.9),
|
||||
Color(NSColor.controlBackgroundColor).opacity(0.7)
|
||||
]),
|
||||
startPoint: .top,
|
||||
endPoint: .bottom
|
||||
)
|
||||
)
|
||||
)
|
||||
.overlay(
|
||||
RoundedRectangle(cornerRadius: 6, style: .continuous)
|
||||
.strokeBorder(Color(NSColor.separatorColor).opacity(0.4), lineWidth: 1)
|
||||
)
|
||||
.shadow(color: Color(NSColor.shadowColor).opacity(0.15), radius: 2, x: 0, y: 1)
|
||||
}
|
||||
}
|
||||
|
||||
private struct MouseBadge: View {
|
||||
var body: some View {
|
||||
HStack(spacing: 6) {
|
||||
Image(systemName: "button.vertical.right.press.fill")
|
||||
.font(.system(size: 11))
|
||||
.foregroundColor(.primary)
|
||||
Text("Middle Button")
|
||||
.font(.system(size: 12, weight: .semibold))
|
||||
.foregroundColor(.primary)
|
||||
}
|
||||
.padding(.horizontal, 12)
|
||||
.padding(.vertical, 6)
|
||||
.background(
|
||||
RoundedRectangle(cornerRadius: 6, style: .continuous)
|
||||
.fill(
|
||||
LinearGradient(
|
||||
gradient: Gradient(colors: [
|
||||
Color(NSColor.controlBackgroundColor).opacity(0.9),
|
||||
Color(NSColor.controlBackgroundColor).opacity(0.7)
|
||||
]),
|
||||
startPoint: .top,
|
||||
endPoint: .bottom
|
||||
)
|
||||
)
|
||||
)
|
||||
.overlay(
|
||||
RoundedRectangle(cornerRadius: 6, style: .continuous)
|
||||
.strokeBorder(Color(NSColor.separatorColor).opacity(0.4), lineWidth: 1)
|
||||
)
|
||||
.shadow(color: Color(NSColor.shadowColor).opacity(0.15), radius: 2, x: 0, y: 1)
|
||||
}
|
||||
}
|
||||
|
||||
private struct NotSetBadge: View {
|
||||
var body: some View {
|
||||
Text("Not Set")
|
||||
.font(.system(size: 12, weight: .medium))
|
||||
.foregroundColor(.secondary)
|
||||
.padding(.horizontal, 12)
|
||||
.padding(.vertical, 6)
|
||||
.background(
|
||||
RoundedRectangle(cornerRadius: 6, style: .continuous)
|
||||
.fill(Color(NSColor.controlBackgroundColor).opacity(0.3))
|
||||
)
|
||||
.overlay(
|
||||
RoundedRectangle(cornerRadius: 6, style: .continuous)
|
||||
.strokeBorder(Color(NSColor.separatorColor).opacity(0.25), lineWidth: 1)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#Preview {
|
||||
KeyboardShortcutsListView()
|
||||
.environmentObject(HotkeyManager(whisperState: WhisperState(modelContext: try! ModelContext(ModelContainer(for: Transcription.self)))))
|
||||
}
|
||||
@ -3,7 +3,8 @@ import SwiftUI
|
||||
struct MetricsContent: View {
|
||||
let transcriptions: [Transcription]
|
||||
let licenseState: LicenseViewModel.LicenseState
|
||||
|
||||
@State private var showKeyboardShortcuts = false
|
||||
|
||||
var body: some View {
|
||||
Group {
|
||||
if transcriptions.isEmpty {
|
||||
@ -138,6 +139,7 @@ struct MetricsContent: View {
|
||||
|
||||
private var footerActionsView: some View {
|
||||
HStack(spacing: 12) {
|
||||
KeyboardShortcutsButton(showKeyboardShortcuts: $showKeyboardShortcuts)
|
||||
CopySystemInfoButton()
|
||||
FeedbackButton()
|
||||
}
|
||||
@ -280,6 +282,31 @@ private struct FeedbackButton: View {
|
||||
}
|
||||
}
|
||||
|
||||
private struct KeyboardShortcutsButton: View {
|
||||
@Binding var showKeyboardShortcuts: Bool
|
||||
|
||||
var body: some View {
|
||||
Button(action: {
|
||||
showKeyboardShortcuts = true
|
||||
}) {
|
||||
HStack(spacing: 8) {
|
||||
Image(systemName: "command")
|
||||
.font(.system(size: 13, weight: .medium))
|
||||
|
||||
Text("Keyboard Shortcuts")
|
||||
}
|
||||
.font(.system(size: 13, weight: .medium))
|
||||
.padding(.horizontal, 12)
|
||||
.padding(.vertical, 8)
|
||||
.background(Capsule().fill(.thinMaterial))
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
.popover(isPresented: $showKeyboardShortcuts, arrowEdge: .bottom) {
|
||||
KeyboardShortcutsListView()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private struct CopySystemInfoButton: View {
|
||||
@State private var isCopied: Bool = false
|
||||
|
||||
|
||||
@ -105,12 +105,18 @@ private struct ShortcutRow: View {
|
||||
HStack(spacing: 8) {
|
||||
Text(title)
|
||||
.font(.system(size: 14, weight: .semibold))
|
||||
.foregroundColor(.primary)
|
||||
InfoTip(title: title, message: description, learnMoreURL: "https://tryvoiceink.com/docs/switching-enhancement-prompts")
|
||||
}
|
||||
|
||||
Text(description)
|
||||
.font(.caption)
|
||||
.foregroundColor(.secondary)
|
||||
.lineLimit(2)
|
||||
}
|
||||
|
||||
Spacer(minLength: 0)
|
||||
|
||||
|
||||
Spacer(minLength: 12)
|
||||
|
||||
if let isOn = isOn {
|
||||
keyDisplayView(isActive: isOn.wrappedValue)
|
||||
.onTapGesture {
|
||||
@ -123,9 +129,11 @@ private struct ShortcutRow: View {
|
||||
keyDisplayView()
|
||||
}
|
||||
}
|
||||
.padding(.horizontal, 8)
|
||||
.padding(.horizontal, 16)
|
||||
.padding(.vertical, 14)
|
||||
.background(CardBackground(isSelected: false))
|
||||
}
|
||||
|
||||
|
||||
@ViewBuilder
|
||||
private func keyDisplayView(isActive: Bool? = nil) -> some View {
|
||||
HStack(spacing: 8) {
|
||||
@ -142,21 +150,33 @@ private struct KeyChip: View {
|
||||
|
||||
var body: some View {
|
||||
let active = isActive ?? true
|
||||
|
||||
|
||||
Text(label)
|
||||
.font(.system(size: 13, weight: .semibold, design: .monospaced))
|
||||
.padding(.horizontal, 12)
|
||||
.font(.system(size: 13, weight: .semibold, design: .rounded))
|
||||
.foregroundColor(active ? .primary : .secondary)
|
||||
.padding(.horizontal, 10)
|
||||
.padding(.vertical, 6)
|
||||
.background(
|
||||
RoundedRectangle(cornerRadius: 10, style: .continuous)
|
||||
.fill(Color(NSColor.controlBackgroundColor))
|
||||
.overlay(
|
||||
RoundedRectangle(cornerRadius: 10, style: .continuous)
|
||||
.stroke(Color(NSColor.separatorColor).opacity(active ? 0.7 : 0.3), lineWidth: 1)
|
||||
RoundedRectangle(cornerRadius: 6, style: .continuous)
|
||||
.fill(
|
||||
LinearGradient(
|
||||
gradient: Gradient(colors: [
|
||||
Color(NSColor.controlBackgroundColor).opacity(active ? 0.9 : 0.6),
|
||||
Color(NSColor.controlBackgroundColor).opacity(active ? 0.7 : 0.5)
|
||||
]),
|
||||
startPoint: .top,
|
||||
endPoint: .bottom
|
||||
)
|
||||
)
|
||||
)
|
||||
.foregroundColor(active ? .primary : .secondary)
|
||||
.shadow(color: Color(NSColor.shadowColor).opacity(active ? 0.1 : 0), radius: 4, x: 0, y: 2)
|
||||
.overlay(
|
||||
RoundedRectangle(cornerRadius: 6, style: .continuous)
|
||||
.strokeBorder(
|
||||
Color(NSColor.separatorColor).opacity(active ? 0.4 : 0.2),
|
||||
lineWidth: 1
|
||||
)
|
||||
)
|
||||
.shadow(color: Color(NSColor.shadowColor).opacity(active ? 0.15 : 0.05), radius: 2, x: 0, y: 1)
|
||||
.opacity(active ? 1.0 : 0.6)
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user