parent
d2e6f8d567
commit
a83133a6f0
@ -0,0 +1,73 @@
|
|||||||
|
<!-- Spinner pendant le chargement -->
|
||||||
|
<div *ngIf="loading" class="flex justify-center items-center h-64">
|
||||||
|
<div
|
||||||
|
class="animate-spin rounded-full h-12 w-12 border-4 border-blue-500 border-t-transparent"
|
||||||
|
></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Timeline -->
|
||||||
|
<div
|
||||||
|
*ngIf="!loading && pins.length > 0"
|
||||||
|
class="relative mx-auto max-w-3xl py-10 px-4"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="absolute h-full left-1/2 transform -translate-x-1/2 border-l-2 border-blue-500"
|
||||||
|
></div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
*ngFor="let pin of pins; let i = index"
|
||||||
|
class="mb-12 flex justify-between items-center w-full"
|
||||||
|
>
|
||||||
|
<!-- Si pair, carte à droite, point à gauche -->
|
||||||
|
<div
|
||||||
|
class="w-5/12"
|
||||||
|
[ngClass]="{ 'order-1': i % 2 === 0, 'order-2': i % 2 !== 0 }"
|
||||||
|
></div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="z-20 flex items-center bg-blue-600 shadow-lg w-10 h-10 rounded-full"
|
||||||
|
[ngClass]="{ 'order-2': i % 2 === 0, 'order-1': i % 2 !== 0 }"
|
||||||
|
>
|
||||||
|
<span class="text-white font-semibold mx-auto">{{ i + 1 }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Content card -->
|
||||||
|
<div
|
||||||
|
class="bg-white dark:bg-gray-800 rounded-xl shadow-xl px-6 py-5 w-5/12 transition-all duration-300 hover:scale-[1.02]"
|
||||||
|
[ngClass]="{
|
||||||
|
'order-3': i % 2 === 0,
|
||||||
|
'order-0': i % 2 !== 0,
|
||||||
|
'text-right': i % 2 !== 0
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<div class="text-sm text-gray-400 mb-1">
|
||||||
|
{{ pin.date ? (pin.date | date : "dd/MM/yyyy") : "Date inconnue" }}
|
||||||
|
</div>
|
||||||
|
<div class="text-lg font-bold text-gray-900 dark:text-white mb-1">
|
||||||
|
{{ pin.title || "Titre inconnu" }}
|
||||||
|
</div>
|
||||||
|
<div class="text-gray-700 dark:text-gray-300 mb-3">
|
||||||
|
{{ pin.description || "Aucune description" }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ng-container *ngIf="imageUrls[i] && imageUrls[i].length > 0">
|
||||||
|
<img
|
||||||
|
[src]="imageUrls[i][0]"
|
||||||
|
alt="image"
|
||||||
|
class="rounded-lg mx-auto max-h-40 object-cover shadow"
|
||||||
|
/>
|
||||||
|
</ng-container>
|
||||||
|
<ng-container *ngIf="!imageUrls[i] || imageUrls[i].length === 0">
|
||||||
|
<div class="text-gray-400 italic text-center">Aucune image</div>
|
||||||
|
</ng-container>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Message si vide -->
|
||||||
|
<div
|
||||||
|
*ngIf="!loading && pins.length === 0"
|
||||||
|
class="text-center text-gray-500 py-12 text-lg"
|
||||||
|
>
|
||||||
|
Aucun souvenir à afficher pour le moment.
|
||||||
|
</div>
|
@ -0,0 +1,47 @@
|
|||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { DomSanitizer, SafeUrl } from '@angular/platform-browser';
|
||||||
|
import { Pin } from '../../model/Pin';
|
||||||
|
import { ImageService } from '../../services/image/image.service';
|
||||||
|
import { PinService } from '../../services/pin/pin.service';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-timeline',
|
||||||
|
standalone: true,
|
||||||
|
imports: [CommonModule],
|
||||||
|
templateUrl: './timeline.component.html',
|
||||||
|
})
|
||||||
|
export class TimelineComponent implements OnInit {
|
||||||
|
pins: Pin[] = [];
|
||||||
|
imageUrls: SafeUrl[][] = [];
|
||||||
|
loading = true;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private pinService: PinService,
|
||||||
|
private imageService: ImageService,
|
||||||
|
private sanitizer: DomSanitizer
|
||||||
|
) {}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.pinService.getPins().subscribe((pins: Pin[]) => {
|
||||||
|
this.pins = pins
|
||||||
|
.filter((pin) => !!pin.date)
|
||||||
|
.sort((a, b) => (a.date! > b.date! ? 1 : -1));
|
||||||
|
this.imageUrls = this.pins.map(() => []); // initialise le tableau d'images
|
||||||
|
|
||||||
|
this.pins.forEach((pin, index) => {
|
||||||
|
if (pin.files && pin.files.length > 0) {
|
||||||
|
pin.files.forEach((imageId) => {
|
||||||
|
this.imageService.getImage(imageId).subscribe((blob) => {
|
||||||
|
const objectUrl = URL.createObjectURL(blob);
|
||||||
|
const safeUrl = this.sanitizer.bypassSecurityTrustUrl(objectUrl);
|
||||||
|
this.imageUrls[index].push(safeUrl);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.loading = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in new issue