feat(mission): Ajout du composant MissionCard utilisé pour la vue globale à venir
This commit is contained in:
parent
31cb949403
commit
e16c0bbf41
1 changed files with 143 additions and 0 deletions
143
urbancanvas/Components/MissionCard.swift
Normal file
143
urbancanvas/Components/MissionCard.swift
Normal file
|
|
@ -0,0 +1,143 @@
|
|||
//
|
||||
// MissionCard.swift
|
||||
// urbancanvas
|
||||
//
|
||||
// Created by Apprenant154 on 25/06/2026.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct MissionCard: View {
|
||||
let numero: Int
|
||||
let oeuvre: Oeuvre
|
||||
var onMarquerDecouverte: () -> Void
|
||||
|
||||
private var auteurNom: String {
|
||||
MockData.auteur(for: oeuvre)?.nom ?? "Auteur inconnu"
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
VStack(alignment: .leading, spacing: 12) {
|
||||
|
||||
Color.clear
|
||||
.frame(maxWidth: .infinity)
|
||||
.frame(height: 185)
|
||||
.background {
|
||||
Image(oeuvre.imageName)
|
||||
.resizable()
|
||||
.scaledToFill()
|
||||
.allowsHitTesting(false)
|
||||
}
|
||||
|
||||
.clipped()
|
||||
.clipShape(.rect(cornerRadius: 20))
|
||||
.overlay(alignment: .topLeading) {
|
||||
Text("\(numero)")
|
||||
.font(.headline)
|
||||
.fontWeight(.bold)
|
||||
.foregroundStyle(.white)
|
||||
.frame(width: 34, height: 34)
|
||||
.background(Color.accentColor.gradient)
|
||||
.clipShape(.circle)
|
||||
.padding(10)
|
||||
}
|
||||
|
||||
Text(oeuvre.nom)
|
||||
.font(.title3)
|
||||
.fontWeight(.bold)
|
||||
|
||||
VStack(alignment: .leading, spacing: 2) {
|
||||
|
||||
InfoText(titre: "Type", valeur: oeuvre.type.rawValue)
|
||||
.font(.subheadline)
|
||||
|
||||
InfoText(titre: "Auteur", valeur: auteurNom)
|
||||
.font(.subheadline)
|
||||
|
||||
InfoText(titre: "Localisation", valeur: oeuvre.localisation.adresseComplete)
|
||||
.font(.subheadline)
|
||||
.lineLimit(2)
|
||||
.minimumScaleFactor(0.85)
|
||||
}
|
||||
|
||||
|
||||
HStack(spacing: 8) {
|
||||
Button {
|
||||
onMarquerDecouverte()
|
||||
} label: {
|
||||
Text(oeuvre.estDecouverte ? "Découverte ✓" : "Marquer comme découverte")
|
||||
.fontWeight(.semibold)
|
||||
.lineLimit(1)
|
||||
.minimumScaleFactor(0.75)
|
||||
}
|
||||
.tint(.orangeSecondary)
|
||||
.buttonStyle(.borderedProminent)
|
||||
.disabled(oeuvre.estDecouverte)
|
||||
|
||||
Spacer()
|
||||
|
||||
NavigationLink(value: oeuvre) {
|
||||
Label("Voir", systemImage: "arrow.forward")
|
||||
.fontWeight(.semibold)
|
||||
}
|
||||
.tint(.accent)
|
||||
.buttonStyle(.bordered)
|
||||
}
|
||||
}
|
||||
.padding(12)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.background(.background)
|
||||
.clipShape(RoundedRectangle(cornerRadius: 28))
|
||||
}
|
||||
}
|
||||
|
||||
#Preview("2") {
|
||||
let store = MissionStore()
|
||||
let oeuvre = MockData.oeuvres.first { $0.id == "tigre-et-cigale" }!
|
||||
|
||||
NavigationStack {
|
||||
ScrollView {
|
||||
MissionCard(
|
||||
numero: 1,
|
||||
oeuvre: oeuvre,
|
||||
onMarquerDecouverte: { store.marquerCommeDecouverte(oeuvre) }
|
||||
)
|
||||
.padding()
|
||||
}
|
||||
.background(.bgGray)
|
||||
.navigationDestination(for: Oeuvre.self) { OeuvreDetaille_View(oeuvre: $0) }
|
||||
}
|
||||
}
|
||||
|
||||
#Preview {
|
||||
@Previewable @State var oeuvre = MockData.oeuvres[14]
|
||||
let store = MissionStore()
|
||||
|
||||
NavigationStack {
|
||||
ScrollView {
|
||||
MissionCard(
|
||||
numero: 1,
|
||||
oeuvre: oeuvre,
|
||||
onMarquerDecouverte: { store.marquerCommeDecouverte(oeuvre) }
|
||||
)
|
||||
.padding()
|
||||
}
|
||||
.background(.bgGray)
|
||||
.navigationDestination(for: Oeuvre.self) { oeuvre in
|
||||
OeuvreDetaille_View(oeuvre: oeuvre)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#Preview("Sans ScrollView") {
|
||||
@Previewable @State var oeuvre = MockData.oeuvres[2]
|
||||
let store = MissionStore()
|
||||
|
||||
|
||||
MissionCard(
|
||||
numero: 1,
|
||||
oeuvre: oeuvre,
|
||||
onMarquerDecouverte: { store.marquerCommeDecouverte(oeuvre) }
|
||||
)
|
||||
|
||||
}
|
||||
Loading…
Reference in a new issue