Compare commits

..

2 Commits

Author SHA1 Message Date
Andreas Knuth 40abef241e deck list neu, selektor in rot 2024-12-02 21:50:20 +01:00
Andreas Knuth d02be08098 images als Tooltips, auf und zuklappbar 2024-12-02 21:19:48 +01:00
3 changed files with 79 additions and 23 deletions

View File

@ -8,33 +8,41 @@
</div> </div>
<!-- Decks anzeigen --> <!-- Decks anzeigen -->
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6"> <div class="flex flex-wrap gap-6">
<div *ngFor="let deck of decks" class="bg-white shadow rounded-lg p-6 flex flex-col"> <div *ngFor="let deck of decks" class="bg-white shadow rounded-lg p-6 w-full md:w-1/2 lg:w-1/3 flex flex-col">
<!-- Deck-Header mit Toggle-Button -->
<div class="flex justify-between items-center mb-4"> <div class="flex justify-between items-center mb-4">
<div class="flex items-center space-x-2">
<h2 class="text-xl font-semibold">{{ deck.name }}</h2> <h2 class="text-xl font-semibold">{{ deck.name }}</h2>
<span class="text-gray-600">({{ deck.images.length }} Bilder)</span>
<!-- Anzahl der Bilder anzeigen, wenn ein Training aktiv ist --> </div>
<span *ngIf="selectedDeck" class="text-gray-600"> <button (click)="toggleDeckExpansion(deck.id)" class="text-gray-500 hover:text-gray-700 focus:outline-none" title="Deck ein-/ausklappen">
{{ deck.images.length }} Bilder <svg *ngIf="!isDeckExpanded(deck.id)" xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 transform rotate-0 transition-transform duration-200" fill="none" viewBox="0 0 24 24" stroke="currentColor">
</span> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" />
</svg>
<!-- Löschen-Button anzeigen, wenn kein Training aktiv ist --> <svg *ngIf="isDeckExpanded(deck.id)" xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 transform rotate-180 transition-transform duration-200" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<button *ngIf="!selectedDeck" (click)="deleteDeck(deck.name)" class="text-red-500 hover:text-red-700" title="Deck löschen"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" />
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
</svg> </svg>
</button> </button>
</div> </div>
<!-- Bildliste und Action-Buttons nur anzeigen, wenn kein Training aktiv ist --> <!-- Bildliste und Action-Buttons nur anzeigen, wenn das Deck erweitert ist und kein Training aktiv ist -->
<ng-container *ngIf="!selectedDeck"> <ng-container *ngIf="isDeckExpanded(deck.id) && !selectedDeck">
<!-- Liste der Bilder mit Anzahl der Boxen und Icons --> <!-- Liste der Bilder mit Anzahl der Boxen und Icons -->
<ul class="mb-4"> <ul class="mb-4">
<li *ngFor="let image of deck.images" class="flex justify-between items-center py-2 border-b last:border-b-0"> <li *ngFor="let image of deck.images" class="flex justify-between items-center py-2 border-b last:border-b-0">
<div class="flex items-center"> <div class="flex items-center space-x-2">
<span class="font-medium">{{ image.name }}</span> <div class="relative group">
<!-- Tooltip Inhalt (Bild) -->
<div class="absolute left-0 bottom-full mb-2 w-48 bg-white border border-gray-300 rounded shadow-lg opacity-0 group-hover:opacity-100 transition-opacity duration-200 z-10 pointer-events-none">
<img src="/api/debug_image/{{image.id}}/thumbnail.jpg" alt="{{ image.name }}" class="w-full h-auto object-cover">
</div>
<!-- Bildname mit Tooltip -->
<span class="font-medium cursor-pointer">
{{ image.name }}
</span>
</div>
<span class="text-gray-600">({{ image.boxes.length }} Boxen)</span> <span class="text-gray-600">({{ image.boxes.length }} Boxen)</span>
<img src="/api/debug_image/{{image.id}}/thumbnail.jpg">
</div> </div>
<div class="flex space-x-2"> <div class="flex space-x-2">
<!-- Edit Icon --> <!-- Edit Icon -->

View File

@ -26,9 +26,13 @@ export class DeckListComponent implements OnInit {
currentUploadDeckName: string = ''; currentUploadDeckName: string = '';
// Set zur Verfolgung erweiterter Decks
expandedDecks: Set<number> = new Set<number>();
constructor(private deckService: DeckService) { } constructor(private deckService: DeckService) { }
ngOnInit(): void { ngOnInit(): void {
this.loadExpandedDecks();
this.loadDecks(); this.loadDecks();
} }
@ -49,15 +53,12 @@ export class DeckListComponent implements OnInit {
}); });
} }
// Neue Methode zum Löschen eines Bildes
deleteImage(deck: Deck, image: DeckImage): void { deleteImage(deck: Deck, image: DeckImage): void {
if (!confirm(`Bist du sicher, dass du das Bild "${image.name}" löschen möchtest?`)) { if (!confirm(`Bist du sicher, dass du das Bild "${image.name}" löschen möchtest?`)) {
return; return;
} }
// Hier gehen wir davon aus, dass das Deck eine eindeutige ID hat. Falls nicht, passe den Code entsprechend an. const imageId = image.id;
const deckId = deck.id; // Stelle sicher, dass das Deck eine `id` hat
const imageId = image.id; // Stelle sicher, dass das Bild eine `id` hat
this.deckService.deleteImage(imageId).subscribe({ this.deckService.deleteImage(imageId).subscribe({
next: () => this.loadDecks(), next: () => this.loadDecks(),
@ -83,4 +84,51 @@ export class DeckListComponent implements OnInit {
this.uploadImageModal.deckName = deckName; this.uploadImageModal.deckName = deckName;
this.uploadImageModal.open(); this.uploadImageModal.open();
} }
// Methode zum Umschalten der Deck-Erweiterung
toggleDeckExpansion(deckId: number): void {
if (this.expandedDecks.has(deckId)) {
this.expandedDecks.delete(deckId);
} else {
this.expandedDecks.add(deckId);
}
this.saveExpandedDecks();
}
// Methode zur Überprüfung, ob ein Deck erweitert ist
isDeckExpanded(deckId: number): boolean {
return this.expandedDecks.has(deckId);
}
// Laden der erweiterten Decks aus dem sessionStorage
loadExpandedDecks(): void {
const stored = sessionStorage.getItem('expandedDecks');
if (stored) {
try {
const parsed: number[] = JSON.parse(stored);
this.expandedDecks = new Set<number>(parsed);
} catch (e) {
console.error('Fehler beim Parsen der erweiterten Decks aus sessionStorage', e);
}
} else {
// Wenn keine Daten gespeichert sind, alle Decks standardmäßig erweitern
this.expandedDecks = new Set<number>();
// Dieser Teil wird nach dem Laden der Decks initialisiert
// Wir erweitern alle Decks, sobald sie geladen sind
this.deckService.getDecks().subscribe({
next: (data) => {
data.forEach(deck => this.expandedDecks.add(deck.id));
this.saveExpandedDecks();
this.decks = data;
},
error: (err) => console.error('Fehler beim Laden der Decks', err)
});
}
}
// Speichern der erweiterten Decks in das sessionStorage
saveExpandedDecks(): void {
const expandedArray = Array.from(this.expandedDecks);
sessionStorage.setItem('expandedDecks', JSON.stringify(expandedArray));
}
} }

View File

@ -230,7 +230,7 @@ export class UploadImageModalComponent implements AfterViewInit, OnDestroy {
top: top, top: top,
width: width, width: width,
height: height, height: height,
fill: 'rgba(0, 0, 0, 0.3)', fill: 'rgba(255, 0, 0, 0.3)',
selectable: true, selectable: true,
hasControls: true, hasControls: true,
hasBorders: true, hasBorders: true,