Download Sources/PromptGarageApp/Views/PromptDetailView.swift from smlflg/PromtGarageMac: direct link, hf CLI and curl.
- Browser
- Download file 6.1 kB
-
https://huggingface.co/smlflg/PromtGarageMac/resolve/main/Sources/PromptGarageApp/Views/PromptDetailView.swift
- Command line
-
hf download hf://smlflg/PromtGarageMac/Sources/PromptGarageApp/Views/PromptDetailView.swift
-
curl -L -o PromptDetailView.swift https://huggingface.co/smlflg/PromtGarageMac/resolve/main/Sources/PromptGarageApp/Views/PromptDetailView.swift
6.1 kB
| import PromptGarageCore | |
| import SwiftUI | |
| struct PromptDetailView: View { | |
| var model: AppModel | |
| var body: some View { | |
| Group { | |
| if let prompt = model.selectedPrompt { | |
| PromptDetailContent(model: model, prompt: prompt) | |
| } else { | |
| ContentUnavailableView { | |
| Label("Prompt auswählen", systemImage: "text.quote") | |
| } description: { | |
| Text("Wähle links einen Prompt aus, um Inhalt und Metadaten zu sehen.") | |
| } | |
| } | |
| } | |
| .navigationTitle(model.selectedPrompt?.title ?? "Details") | |
| } | |
| } | |
| private struct PromptDetailContent: View { | |
| var model: AppModel | |
| let prompt: PromptRecord | |
| var body: some View { | |
| VStack(spacing: 0) { | |
| ScrollView { | |
| VStack(alignment: .leading, spacing: 22) { | |
| header | |
| metadata | |
| Divider() | |
| Text(prompt.content) | |
| .font(.body) | |
| .textSelection(.enabled) | |
| .frame(maxWidth: .infinity, alignment: .leading) | |
| .padding(.bottom, 16) | |
| } | |
| .padding(24) | |
| .frame(maxWidth: 820, alignment: .leading) | |
| .frame(maxWidth: .infinity) | |
| } | |
| Divider() | |
| actionBar | |
| } | |
| .background(Color(nsColor: .textBackgroundColor).opacity(0.38)) | |
| .toolbar { | |
| ToolbarItemGroup { | |
| Button { | |
| Task { await model.toggleStar(prompt) } | |
| } label: { | |
| Label( | |
| prompt.isStarred ? "Favorit entfernen" : "Favorit", | |
| systemImage: prompt.isStarred ? "star.fill" : "star" | |
| ) | |
| } | |
| .disabled(!model.canMutatePrompts) | |
| Menu { | |
| Button("Nur kopieren") { | |
| Task { await model.copy(prompt, countAsUse: false) } | |
| } | |
| Button("Bearbeiten …") { | |
| model.presentEditPrompt(prompt) | |
| } | |
| .disabled(!model.canMutatePrompts) | |
| Divider() | |
| Button("Löschen …", role: .destructive) { | |
| model.requestDelete(prompt) | |
| } | |
| .disabled(!model.canMutatePrompts) | |
| } label: { | |
| Label("Weitere Aktionen", systemImage: "ellipsis.circle") | |
| } | |
| } | |
| } | |
| } | |
| private var header: some View { | |
| VStack(alignment: .leading, spacing: 12) { | |
| Text(prompt.title) | |
| .font(.largeTitle.weight(.semibold)) | |
| .textSelection(.enabled) | |
| HStack(spacing: 12) { | |
| RatingControl(rating: prompt.rating) { rating in | |
| Task { await model.setRating(rating, for: prompt) } | |
| } | |
| .disabled(!model.canMutatePrompts) | |
| if prompt.isStarred { | |
| StatusChip(title: "Favorit", systemImage: "star.fill", tint: AppUI.accent) | |
| } | |
| StatusChip( | |
| title: "\(prompt.useCount)× verwendet", | |
| systemImage: "arrow.up.forward.circle" | |
| ) | |
| } | |
| } | |
| } | |
| private var metadata: some View { | |
| VStack(alignment: .leading, spacing: 10) { | |
| if !prompt.tagList.isEmpty { | |
| HStack(spacing: 6) { | |
| ForEach(prompt.tagList, id: \.self) { tag in | |
| StatusChip(title: tag, systemImage: "tag", tint: .primary) | |
| } | |
| } | |
| } | |
| Grid(alignment: .leading, horizontalSpacing: 18, verticalSpacing: 6) { | |
| GridRow { | |
| Text("Quelle").foregroundStyle(.secondary) | |
| Text(prompt.source ?? "Unbekannt").textSelection(.enabled) | |
| } | |
| if let modelName = prompt.model, !modelName.isEmpty { | |
| GridRow { | |
| Text("Modell").foregroundStyle(.secondary) | |
| Text(modelName).textSelection(.enabled) | |
| } | |
| } | |
| GridRow { | |
| Text("Aktualisiert").foregroundStyle(.secondary) | |
| Text(prompt.updatedAt).textSelection(.enabled) | |
| } | |
| if let promptedAt = prompt.promptedAt, !promptedAt.isEmpty { | |
| GridRow { | |
| Text("Prompt-Datum").foregroundStyle(.secondary) | |
| Text(promptedAt).textSelection(.enabled) | |
| } | |
| } else { | |
| GridRow { | |
| Text("Prompt-Datum").foregroundStyle(.secondary) | |
| Label( | |
| "Legacy · Originaldatum unbekannt", | |
| systemImage: "clock.badge.questionmark" | |
| ) | |
| .foregroundStyle(.secondary) | |
| } | |
| } | |
| } | |
| .font(.caption) | |
| } | |
| } | |
| private var actionBar: some View { | |
| HStack(spacing: 10) { | |
| Button("Bearbeiten") { | |
| model.presentEditPrompt(prompt) | |
| } | |
| .disabled(!model.canMutatePrompts) | |
| Spacer() | |
| Button { | |
| Task { await model.copy(prompt, countAsUse: model.canMutatePrompts) } | |
| } label: { | |
| Label( | |
| model.canMutatePrompts | |
| ? "Kopieren & als verwendet zählen" | |
| : "Prompt kopieren", | |
| systemImage: "doc.on.doc.fill" | |
| ) | |
| } | |
| .buttonStyle(.borderedProminent) | |
| .keyboardShortcut(.return, modifiers: [.command]) | |
| } | |
| .padding(14) | |
| .background(.bar) | |
| } | |
| } | |