From e16c0bbf41b19266fc814bc59c5a283f8cc025df Mon Sep 17 00:00:00 2001 From: CreepsoOff <51055703+CreepsoOff@users.noreply.github.com> Date: Fri, 26 Jun 2026 11:04:09 +0200 Subject: [PATCH] =?UTF-8?q?feat(mission):=20Ajout=20du=20composant=20Missi?= =?UTF-8?q?onCard=20utilis=C3=A9=20pour=20la=20vue=20globale=20=C3=A0=20ve?= =?UTF-8?q?nir?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- urbancanvas/Components/MissionCard.swift | 143 +++++++++++++++++++++++ 1 file changed, 143 insertions(+) create mode 100644 urbancanvas/Components/MissionCard.swift diff --git a/urbancanvas/Components/MissionCard.swift b/urbancanvas/Components/MissionCard.swift new file mode 100644 index 0000000..d8f9dfb --- /dev/null +++ b/urbancanvas/Components/MissionCard.swift @@ -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) } + ) + +}