PromtGarageMac / Sources /PromptGarageApp /Views /PromptDetailView.swift
smlflg's picture
Initial public upload from Projekte/PromtGarageMac
4977db2 verified
Raw History Blame Contribute Delete
6.1 kB
import PromptGarageCore
import SwiftUI
struct PromptDetailView: View {
@Bindable 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 {
@Bindable 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)
}
}