From 6d3fac76ef48b12d8c239c9a1bddc6027946d1f7 Mon Sep 17 00:00:00 2001 From: Beingpax Date: Fri, 31 Oct 2025 15:12:12 +0545 Subject: [PATCH] Redesign predefinedprompttemplates view --- VoiceInk/Models/PromptTemplates.swift | 6 +- VoiceInk/Views/PredefinedPromptsView.swift | 90 ++++++++++++++ VoiceInk/Views/PromptEditorView.swift | 136 ++++----------------- 3 files changed, 117 insertions(+), 115 deletions(-) create mode 100644 VoiceInk/Views/PredefinedPromptsView.swift diff --git a/VoiceInk/Models/PromptTemplates.swift b/VoiceInk/Models/PromptTemplates.swift index 47eb348..7b6b086 100644 --- a/VoiceInk/Models/PromptTemplates.swift +++ b/VoiceInk/Models/PromptTemplates.swift @@ -43,7 +43,7 @@ enum PromptTemplates { - Don't add any information not available in the text ever. """, icon: "checkmark.seal.fill", - description: "Default system prompt for improving clarity and accuracy of transcriptions" + description: "Default system prompt" ), TemplatePrompt( id: UUID(), @@ -77,7 +77,7 @@ enum PromptTemplates { - Don't add any information not available in the text ever. """, icon: "envelope.fill", - description: "Template for converting casual messages into professional email format" + description: "Professional email formatting" ), TemplatePrompt( id: UUID(), @@ -96,7 +96,7 @@ enum PromptTemplates { - Don't add any information not available in the text ever. """, icon: "pencil.circle.fill", - description: "Rewrites transcriptions with enhanced clarity, improved sentence structure, and rhythmic flow while preserving original meaning." + description: "Rewrites with better clarity." ) ] } diff --git a/VoiceInk/Views/PredefinedPromptsView.swift b/VoiceInk/Views/PredefinedPromptsView.swift new file mode 100644 index 0000000..bfe85fe --- /dev/null +++ b/VoiceInk/Views/PredefinedPromptsView.swift @@ -0,0 +1,90 @@ +import SwiftUI + +struct PredefinedPromptsView: View { + let onSelect: (TemplatePrompt) -> Void + + private let columns: [GridItem] = Array(repeating: GridItem(.flexible(), spacing: 18), count: 2) + + var body: some View { + ScrollView { + LazyVGrid(columns: columns, spacing: 16) { + ForEach(PromptTemplates.all) { template in + PredefinedTemplateButton(prompt: template) { + onSelect(template) + } + } + } + .padding(.horizontal, 24) + .padding(.vertical, 20) + } + .frame(minWidth: 410, idealWidth: 520, maxWidth: 570, maxHeight: 440) + } +} + +struct PredefinedTemplateButton: View { + let prompt: TemplatePrompt + let action: () -> Void + + var body: some View { + Button(action: action) { + VStack(alignment: .leading, spacing: 12) { + HStack(alignment: .center, spacing: 12) { + RoundedRectangle(cornerRadius: 10, style: .continuous) + .fill(Color(NSColor.unemphasizedSelectedTextBackgroundColor)) + .frame(width: 42, height: 42) + .overlay( + Image(systemName: prompt.icon) + .font(.system(size: 19, weight: .medium)) + .foregroundColor(Color(NSColor.labelColor)) + ) + + Text(prompt.title) + .font(.system(size: 15, weight: .semibold)) + .foregroundColor(.primary) + .lineLimit(1) + + Spacer(minLength: 0) + } + + Text(prompt.description) + .font(.system(size: 12)) + .foregroundColor(Color(NSColor.secondaryLabelColor)) + .lineLimit(1) + .truncationMode(.tail) + .frame(maxWidth: .infinity, alignment: .leading) + } + .frame(maxWidth: .infinity, alignment: .topLeading) + .padding(.horizontal, 18) + .padding(.vertical, 12) + .background(cardBackground) + .overlay(cardStroke) + .contentShape(RoundedRectangle(cornerRadius: 16, style: .continuous)) + .shadow(color: cardShadowColor, radius: 6, x: 0, y: 4) + } + .buttonStyle(.plain) + } + + private var cardBackground: some View { + RoundedRectangle(cornerRadius: 16, style: .continuous) + .fill(Color(NSColor.controlBackgroundColor)) + } + + private var cardStroke: some View { + RoundedRectangle(cornerRadius: 16, style: .continuous) + .stroke( + LinearGradient( + colors: [ + Color(NSColor.separatorColor).opacity(0.35), + Color(NSColor.separatorColor).opacity(0.15) + ], + startPoint: .topLeading, + endPoint: .bottomTrailing + ), + lineWidth: 1 + ) + } + + private var cardShadowColor: Color { + Color(NSColor.shadowColor).opacity(0.25) + } +} diff --git a/VoiceInk/Views/PromptEditorView.swift b/VoiceInk/Views/PromptEditorView.swift index 46c497e..0a005d6 100644 --- a/VoiceInk/Views/PromptEditorView.swift +++ b/VoiceInk/Views/PromptEditorView.swift @@ -215,36 +215,32 @@ struct PromptEditorView: View { .padding(.horizontal) if case .add = mode { - // Templates Section with modern styling - VStack(alignment: .leading, spacing: 16) { - Text("Start with a Predefined Template") - .font(.title2) - .fontWeight(.semibold) - .foregroundColor(.primary) - - let columns = [ - GridItem(.flexible(), spacing: 16), - GridItem(.flexible(), spacing: 16) - ] - - LazyVGrid(columns: columns, spacing: 16) { - ForEach(PromptTemplates.all) { template in - CleanTemplateButton(prompt: template) { - title = template.title - promptText = template.promptText - selectedIcon = template.icon - description = template.description - } - } + // Popover keeps templates accessible without taking space in the layout + Button("Start with a Predefined Template") { + showingPredefinedPrompts.toggle() + } + .font(.headline) + .padding(.horizontal, 24) + .padding(.vertical, 12) + .background( + Capsule() + .fill(Color(.windowBackgroundColor).opacity(0.9)) + ) + .overlay( + Capsule() + .stroke(Color.secondary.opacity(0.2), lineWidth: 1) + ) + .buttonStyle(.plain) + .padding(.horizontal) + .popover(isPresented: $showingPredefinedPrompts, arrowEdge: .bottom) { + PredefinedPromptsView { template in + title = template.title + promptText = template.promptText + selectedIcon = template.icon + description = template.description + showingPredefinedPrompts = false } } - .padding(.horizontal) - .padding(.vertical, 16) - .background( - RoundedRectangle(cornerRadius: 16) - .fill(Color(.windowBackgroundColor).opacity(0.6)) - ) - .padding(.horizontal) } } } @@ -282,90 +278,6 @@ struct PromptEditorView: View { } } -// Clean template button with minimal styling -struct CleanTemplateButton: View { - let prompt: TemplatePrompt - let action: () -> Void - - var body: some View { - Button(action: action) { - HStack(alignment: .top, spacing: 12) { - // Clean icon design - ZStack { - RoundedRectangle(cornerRadius: 12) - .fill(Color.accentColor.opacity(0.15)) - .frame(width: 44, height: 44) - - Image(systemName: prompt.icon) - .font(.system(size: 20, weight: .semibold)) - .foregroundColor(.accentColor) - } - - VStack(alignment: .leading, spacing: 4) { - Text(prompt.title) - .font(.system(size: 16, weight: .semibold)) - .foregroundColor(.primary) - .lineLimit(1) - - Text(prompt.description) - .font(.system(size: 13)) - .foregroundColor(.secondary) - .lineLimit(2) - .multilineTextAlignment(.leading) - } - - Spacer(minLength: 0) - } - .padding(16) - .frame(maxWidth: .infinity, alignment: .leading) - .background( - RoundedRectangle(cornerRadius: 12) - .fill(Color(.controlBackgroundColor)) - ) - .overlay( - RoundedRectangle(cornerRadius: 12) - .stroke(Color.secondary.opacity(0.2), lineWidth: 1) - ) - } - .buttonStyle(.plain) - } -} - -// Keep the old TemplateButton for backward compatibility if needed elsewhere -struct TemplateButton: View { - let prompt: TemplatePrompt - let action: () -> Void - - var body: some View { - Button(action: action) { - HStack(alignment: .center, spacing: 12) { - Image(systemName: prompt.icon) - .font(.system(size: 20, weight: .medium)) - .foregroundColor(.accentColor) - .frame(width: 28, height: 28) - .background(Color.accentColor.opacity(0.12)) - .clipShape(RoundedRectangle(cornerRadius: 6)) - VStack(alignment: .leading, spacing: 4) { - Text(prompt.title) - .font(.system(size: 15, weight: .semibold)) - .foregroundColor(.primary) - .lineLimit(1) - } - Spacer(minLength: 0) - } - .padding(12) - .frame(height: 60) - .background(Color(NSColor.controlBackgroundColor)) - .cornerRadius(10) - .overlay( - RoundedRectangle(cornerRadius: 10) - .stroke(Color.secondary.opacity(0.18), lineWidth: 1) - ) - } - .buttonStyle(.plain) - } -} - // Reusable Trigger Words Editor Component struct TriggerWordsEditor: View { @Binding var triggerWords: [String]