You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
front/src/app/components/timeline/timeline.component.html

241 lines
8.6 KiB

<!-- Spinner pendant le chargement -->
<div *ngIf="loading" class="flex justify-center items-center h-64">
<div
class="animate-spin rounded-full h-16 w-16 border-4 border-blue-500 border-t-transparent"
></div>
</div>
<!-- Timeline principale -->
<div
*ngIf="!loading && pins.length > 0"
class="relative mx-auto max-w-7xl py-20 px-6 z-0"
>
<!-- Barre centrale -->
<div
class="absolute left-1/2 transform -translate-x-1/2 h-full bg-blue-500 w-6 rounded-full z-0"
></div>
<!-- Groupement par années -->
<ng-container *ngFor="let year of sortedYears">
<!-- Marqueur d'année -->
<div class="relative mb-24 flex justify-center items-center">
<div
class="absolute left-1/2 transform -translate-x-1/2 h-16 w-8 bg-blue-500 z-0"
></div>
<div
class="bg-blue-600 text-white text-2xl font-bold px-10 py-5 rounded-full shadow-2xl z-10 border-4 border-white"
>
{{ year }}
</div>
</div>
<!-- Pins de l'année -->
<ng-container *ngFor="let pin of groupedPins[year]; let i = index">
<div
class="mb-32 flex flex-col sm:flex-row justify-between items-center w-full relative z-10"
>
<!-- Espace vide -->
<div
class="w-full sm:w-5/12"
[ngClass]="{ 'sm:order-1': i % 2 === 0, 'sm:order-2': i % 2 !== 0 }"
></div>
<!-- Bulle centrale avec la date -->
<div
class="z-20 flex items-center justify-center bg-white border-[6px] sm:border-blue-600 border-gray-800 sm:text-blue-700 text-gray-800 font-bold text-base sm:text-lg shadow-2xl sm:rounded-full rounded-t-3xl sm:w-32 sm:h-32 text-center leading-tight px-4 py-2 sm:px-10 sm:py-5 date-bubble"
[ngClass]="{
'sm:order-2': i % 2 === 0,
'sm:order-1': i % 2 !== 0
}"
>
<span>{{ pin.date | date : "d MMMM yyyy" }}</span>
</div>
<!-- Ligne de liaison (desktop uniquement) -->
<div
class="hidden -z-10 sm:block absolute top-1/2 transform -translate-y-1/2 h-2 w-[calc(50%-8rem)] bg-blue-500"
[ngClass]="{
'left-1/2': i % 2 === 0,
'right-1/2': i % 2 !== 0
}"
></div>
<!-- Carte de contenu -->
<div
class="bg-white dark:bg-gray-800 rounded-3xl shadow-2xl px-10 py-8 w-full sm:w-5/12 transition-all duration-300 hover:scale-[1.02] cursor-pointer"
[ngClass]="{
'sm:order-3 sm:text-left text-center': i % 2 === 0,
'sm:order-0 sm:text-right text-left': i % 2 !== 0
}"
(click)="navigateToPinOnMap(pin.id)"
>
<!-- Titre centré -->
<h3
class="text-2xl font-extrabold text-gray-900 dark:text-white mb-4 text-center"
>
{{ pin.title || "Titre inconnu" }}
</h3>
<!-- Description justifiée tronquée -->
<div
class="text-md text-gray-700 dark:text-gray-300 mb-4 text-justify transition-all duration-300"
[ngClass]="{
'line-clamp-5 overflow-hidden':
!expandedDescriptions[pins.indexOf(pin)]
}"
>
{{ pin.description || "Aucune description" }}
</div>
<!-- Bouton "voir plus / moins" -->
<div *ngIf="pin.description.length > 200" class="text-right mb-6">
<button
class="text-blue-600 font-semibold hover:underline"
(click)="toggleDescription(pins.indexOf(pin))"
>
{{
expandedDescriptions[pins.indexOf(pin)]
? "Voir moins"
: "Voir plus"
}}
</button>
</div>
<!-- Carrousel d'images -->
<ng-container *ngIf="imageUrls[pins.indexOf(pin)].length > 0">
<div
class="relative h-64 mt-2 overflow-hidden rounded-lg flex items-center justify-center"
>
<div
*ngFor="
let imageId of imageUrls[pins.indexOf(pin)];
let index = index
"
[class]="
'absolute inset-0 transition-opacity duration-700 ease-in-out' +
(index === carouselIndexes[pins.indexOf(pin)]
? ' opacity-100'
: ' opacity-0')
"
>
<img
[src]="imageId"
class="object-contain max-h-full max-w-full h-full w-auto mx-auto"
alt="image"
/>
</div>
<!-- Slider controls -->
<div *ngIf="imageUrls[pins.indexOf(pin)].length > 1">
<button
type="button"
class="absolute top-0 left-0 z-30 flex items-center justify-center h-full cursor-pointer group focus:outline-none"
(click)="
prevImage(pins.indexOf(pin)); $event.stopPropagation()
"
>
<span
class="inline-flex items-center justify-center w-8 h-8 rounded-full bg-black/30 group-hover:bg-black/50"
>
<svg
class="w-4 h-4 text-white"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 6 10"
>
<path
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M5 1 1 5l4 4"
/>
</svg>
<span class="sr-only">Précédent</span>
</span>
</button>
<button
type="button"
class="absolute top-0 right-0 z-30 flex items-center justify-center h-full cursor-pointer group focus:outline-none"
(click)="
nextImage(pins.indexOf(pin)); $event.stopPropagation()
"
>
<span
class="inline-flex items-center justify-center w-8 h-8 rounded-full bg-black/30 group-hover:bg-black/50"
>
<svg
class="w-4 h-4 text-white"
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 6 10"
>
<path
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M1 9l4-4-4-4"
/>
</svg>
<span class="sr-only">Suivant</span>
</span>
</button>
</div>
</div>
<!-- Indicateur de position -->
<div
*ngIf="imageUrls[pins.indexOf(pin)].length > 1"
class="flex justify-center mt-2 space-x-2"
>
<div
*ngFor="let img of imageUrls[pins.indexOf(pin)]; let j = index"
class="w-3 h-3 rounded-full"
[ngClass]="{
'bg-blue-600': j === carouselIndexes[pins.indexOf(pin)],
'bg-blue-200': j !== carouselIndexes[pins.indexOf(pin)]
}"
></div>
</div>
</ng-container>
<!-- Fallback s'il n'y a pas d'image -->
<ng-container
*ngIf="
!imageUrls[pins.indexOf(pin)] ||
imageUrls[pins.indexOf(pin)].length === 0
"
>
<div class="text-gray-400 italic text-center">Aucune image</div>
</ng-container>
</div>
<!-- Message si vide -->
<div
*ngIf="!loading && pins.length === 0"
class="text-center text-gray-500 py-12 text-xl"
>
Aucun souvenir à afficher pour le moment.
</div>
</div></ng-container
></ng-container
>
</div>
<div
*ngIf="!loading && pins.length === 0"
class="flex flex-col items-center justify-center h-64 space-y-6"
>
<p class="text-xl text-gray-800 text-center">
Commencez à créer votre histoire en ajoutant des souvenirs sur la carte !
</p>
<button
(click)="openPinModal()"
class="px-6 py-3 bg-gray-800 text-white rounded-lg hover:bg-gray-700 transition-colors duration-200 shadow-lg"
>
Ajouter un souvenir
</button>
</div>