Download Sources/PromptGarageApp/AppUI.swift from smlflg/PromtGarageMac: direct link, hf CLI and curl.
- Browser
- Download file 5.55 kB
-
https://huggingface.co/smlflg/PromtGarageMac/resolve/main/Sources/PromptGarageApp/AppUI.swift
- Command line
-
hf download hf://smlflg/PromtGarageMac/Sources/PromptGarageApp/AppUI.swift
-
curl -L -o AppUI.swift https://huggingface.co/smlflg/PromtGarageMac/resolve/main/Sources/PromptGarageApp/AppUI.swift
5.55 kB
| import SwiftUI | |
| enum AppUI { | |
| static let accent = Color(red: 0.91, green: 0.48, blue: 0.12) | |
| static let cardCornerRadius: CGFloat = 14 | |
| static let compactCornerRadius: CGFloat = 8 | |
| } | |
| struct LocalStatusLabel: View { | |
| let databaseName: String? | |
| var body: some View { | |
| HStack(spacing: 7) { | |
| Circle() | |
| .fill(.green) | |
| .frame(width: 7, height: 7) | |
| Text("Lokal · nicht synchronisiert") | |
| .font(.caption) | |
| .foregroundStyle(.secondary) | |
| if let databaseName { | |
| Text("·") | |
| .foregroundStyle(.tertiary) | |
| Text(databaseName) | |
| .font(.caption.monospaced()) | |
| .foregroundStyle(.tertiary) | |
| .lineLimit(1) | |
| } | |
| } | |
| .accessibilityElement(children: .combine) | |
| .accessibilityLabel("Lokale Datenbank, keine Synchronisierung") | |
| } | |
| } | |
| struct StatusChip: View { | |
| let title: String | |
| var systemImage: String? = nil | |
| var tint: Color = .secondary | |
| var body: some View { | |
| HStack(spacing: 5) { | |
| if let systemImage { | |
| Image(systemName: systemImage) | |
| } | |
| Text(title) | |
| .lineLimit(1) | |
| } | |
| .font(.caption.weight(.medium)) | |
| .foregroundStyle(tint) | |
| .padding(.horizontal, 8) | |
| .padding(.vertical, 4) | |
| .background(tint.opacity(0.11), in: Capsule()) | |
| } | |
| } | |
| struct ErrorBanner: View { | |
| let error: AppErrorPresentation | |
| let dismiss: () -> Void | |
| let copyDiagnostic: () -> Void | |
| var body: some View { | |
| HStack(alignment: .top, spacing: 12) { | |
| Image(systemName: "exclamationmark.triangle.fill") | |
| .foregroundStyle(.red) | |
| .padding(.top, 2) | |
| VStack(alignment: .leading, spacing: 3) { | |
| Text(error.title) | |
| .font(.subheadline.weight(.semibold)) | |
| Text(error.message) | |
| .font(.caption) | |
| .foregroundStyle(.secondary) | |
| .textSelection(.enabled) | |
| } | |
| Spacer(minLength: 16) | |
| Button("Diagnose kopieren", action: copyDiagnostic) | |
| .buttonStyle(.borderless) | |
| .font(.caption) | |
| Button(action: dismiss) { | |
| Image(systemName: "xmark") | |
| } | |
| .buttonStyle(.borderless) | |
| .accessibilityLabel("Fehler ausblenden") | |
| } | |
| .padding(12) | |
| .background(.red.opacity(0.08)) | |
| .overlay(alignment: .bottom) { | |
| Divider().overlay(.red.opacity(0.2)) | |
| } | |
| } | |
| } | |
| struct SuccessToast: View { | |
| let message: String | |
| var body: some View { | |
| Label(message, systemImage: "checkmark.circle.fill") | |
| .font(.callout.weight(.medium)) | |
| .padding(.horizontal, 14) | |
| .padding(.vertical, 10) | |
| .background(.regularMaterial, in: Capsule()) | |
| .shadow(color: .black.opacity(0.13), radius: 16, y: 7) | |
| .accessibilityAddTraits(.isStaticText) | |
| } | |
| } | |
| struct MetricCard: View { | |
| let title: String | |
| let value: Int | |
| let systemImage: String | |
| var tint: Color = AppUI.accent | |
| var body: some View { | |
| HStack(spacing: 13) { | |
| Image(systemName: systemImage) | |
| .font(.title2) | |
| .foregroundStyle(tint) | |
| .frame(width: 36, height: 36) | |
| .background(tint.opacity(0.12), in: RoundedRectangle(cornerRadius: 9)) | |
| VStack(alignment: .leading, spacing: 2) { | |
| Text(value.formatted()) | |
| .font(.title2.weight(.semibold).monospacedDigit()) | |
| Text(title) | |
| .font(.caption) | |
| .foregroundStyle(.secondary) | |
| } | |
| Spacer(minLength: 0) | |
| } | |
| .padding(14) | |
| .background( | |
| Color(nsColor: .controlBackgroundColor), | |
| in: RoundedRectangle(cornerRadius: AppUI.cardCornerRadius) | |
| ) | |
| .overlay { | |
| RoundedRectangle(cornerRadius: AppUI.cardCornerRadius) | |
| .stroke(Color(nsColor: .separatorColor).opacity(0.55), lineWidth: 1) | |
| } | |
| } | |
| } | |
| struct RatingControl: View { | |
| let rating: Int? | |
| var size: Font = .body | |
| var onChange: ((Int?) -> Void)? | |
| var body: some View { | |
| HStack(spacing: 2) { | |
| ForEach(1...5, id: \.self) { value in | |
| Button { | |
| onChange?(rating == value ? nil : value) | |
| } label: { | |
| Image(systemName: value <= (rating ?? 0) ? "star.fill" : "star") | |
| .font(size) | |
| .foregroundStyle(value <= (rating ?? 0) ? AppUI.accent : .secondary) | |
| } | |
| .buttonStyle(.plain) | |
| .disabled(onChange == nil) | |
| .accessibilityLabel("\(value) von 5 Sternen") | |
| .accessibilityAddTraits(rating == value ? .isSelected : []) | |
| } | |
| } | |
| } | |
| } | |
| struct LoadingOverlay: View { | |
| let label: String | |
| var body: some View { | |
| VStack(spacing: 12) { | |
| ProgressView() | |
| .controlSize(.large) | |
| Text(label) | |
| .font(.callout) | |
| .foregroundStyle(.secondary) | |
| } | |
| .padding(24) | |
| .background(.regularMaterial, in: RoundedRectangle(cornerRadius: AppUI.cardCornerRadius)) | |
| .shadow(color: .black.opacity(0.12), radius: 20, y: 8) | |
| } | |
| } | |