Download Sources/PromptGarageApp/Views/PromptEditorSheet.swift from smlflg/PromtGarageMac: direct link, hf CLI and curl.
- Browser
- Download file 4.02 kB
-
https://huggingface.co/smlflg/PromtGarageMac/resolve/main/Sources/PromptGarageApp/Views/PromptEditorSheet.swift
- Command line
-
hf download hf://smlflg/PromtGarageMac/Sources/PromptGarageApp/Views/PromptEditorSheet.swift
-
curl -L -o PromptEditorSheet.swift https://huggingface.co/smlflg/PromtGarageMac/resolve/main/Sources/PromptGarageApp/Views/PromptEditorSheet.swift
4.02 kB
| import PromptGarageCore | |
| import SwiftUI | |
| struct PromptEditorSheet: View { | |
| var model: AppModel | |
| let presentation: PromptEditorPresentation | |
| private var draft: PromptDraft | |
| init(model: AppModel, presentation: PromptEditorPresentation) { | |
| self.model = model | |
| self.presentation = presentation | |
| _draft = State(initialValue: presentation.initialDraft) | |
| } | |
| var body: some View { | |
| VStack(spacing: 0) { | |
| HStack { | |
| VStack(alignment: .leading, spacing: 3) { | |
| Text(presentation.title) | |
| .font(.title2.weight(.semibold)) | |
| Text("Wird ausschließlich in deiner lokalen PromptGarage gespeichert.") | |
| .font(.caption) | |
| .foregroundStyle(.secondary) | |
| } | |
| Spacer() | |
| } | |
| .padding(22) | |
| .background(.bar) | |
| Divider() | |
| Form { | |
| Section("Prompt") { | |
| TextField("Titel", text: $draft.title) | |
| TextEditor(text: $draft.content) | |
| .font(.body) | |
| .frame(minHeight: 230) | |
| .scrollContentBackground(.hidden) | |
| .padding(8) | |
| .background( | |
| Color(nsColor: .textBackgroundColor), | |
| in: RoundedRectangle(cornerRadius: AppUI.compactCornerRadius) | |
| ) | |
| .overlay { | |
| RoundedRectangle(cornerRadius: AppUI.compactCornerRadius) | |
| .stroke(Color(nsColor: .separatorColor).opacity(0.7)) | |
| } | |
| } | |
| Section("Metadaten") { | |
| TextField("Tags, durch Kommas getrennt", text: optionalTextBinding(\PromptDraft.tags)) | |
| TextField("Quelle", text: $draft.source) | |
| TextField("Modell (optional)", text: optionalTextBinding(\PromptDraft.model)) | |
| Toggle("Favorit", isOn: $draft.isStarred) | |
| LabeledContent("Bewertung") { | |
| RatingControl(rating: draft.rating) { draft.rating = $0 } | |
| } | |
| } | |
| if let validationMessage = draft.validationMessage { | |
| Section { | |
| Label(validationMessage, systemImage: "exclamationmark.circle") | |
| .foregroundStyle(.red) | |
| } | |
| } | |
| } | |
| .formStyle(.grouped) | |
| Divider() | |
| HStack { | |
| Button("Abbrechen") { | |
| model.editor = nil | |
| } | |
| .keyboardShortcut(.cancelAction) | |
| .disabled(model.isSavingEditor) | |
| Spacer() | |
| Button { | |
| Task { _ = await model.saveEditor(draft, presentation: presentation) } | |
| } label: { | |
| if model.isSavingEditor { | |
| HStack(spacing: 8) { | |
| ProgressView().controlSize(.small) | |
| Text("Speichern …") | |
| } | |
| } else { | |
| Text("Speichern") | |
| } | |
| } | |
| .buttonStyle(.borderedProminent) | |
| .keyboardShortcut(.defaultAction) | |
| .disabled(draft.validationMessage != nil || model.isSavingEditor) | |
| } | |
| .padding(16) | |
| .background(.bar) | |
| } | |
| .frame(width: 680, height: 680) | |
| .interactiveDismissDisabled(model.isSavingEditor) | |
| } | |
| private func optionalTextBinding(_ keyPath: WritableKeyPath<PromptDraft, String?>) -> Binding<String> { | |
| Binding( | |
| get: { draft[keyPath: keyPath] ?? "" }, | |
| set: { draft[keyPath: keyPath] = $0.isEmpty ? nil : $0 } | |
| ) | |
| } | |
| } | |