vokabeltraining/src/app/deck-list.component.html

145 lines
9.2 KiB
HTML

<div class="flex flex-col">
<!-- Two-column layout -->
<div *ngIf="!trainingsDeck" class="flex flex-col md:flex-row gap-4 mx-auto max-w-5xl">
<!-- Left column: List of decks -->
<div class="w-auto">
<div class="bg-white shadow rounded-lg p-4">
<div class="flex">
<h2 class="text-xl font-semibold mb-4">Decks</h2>
<button (click)="openCreateDeckModal()" class="text-gray-500 hover:text-gray-700 focus:outline-none flex items-start ml-2.5 translate-y-0.5">
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="#2563eb">
<circle cx="12" cy="12" r="9" stroke-width="2" />
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v8M8 12h8" />
</svg>
</button>
</div>
<div class="space-y-2">
<div *ngFor="let deck of decks" class="flex justify-between items-center p-2 rounded hover:bg-gray-300 cursor-pointer" [class.bg-blue-200]="isDeckActive(deck)" (click)="toggleDeckExpansion(deck)">
<div class="flex flex-col space-y-1">
<div class="flex items-center space-x-2 whitespace-nowrap">
<h3 class="font-medium">{{ deck.name }}</h3>
<span class="text-gray-600">({{ deck.images.length }} Pics)</span>
</div>
<div class="text-sm text-gray-600">
<div [ngClass]="{ 'text-blue-500 font-bold': isToday(getNextTrainingDate(deck)), 'text-rose-500 font-bold': isBeforeToday(getNextTrainingDate(deck)) }">
Next training: {{ getNextTrainingString(deck) }}
</div>
<div>Words to review: {{ getWordsToReview(deck) }}</div>
</div>
</div>
<button class="text-gray-500 hover:text-gray-700 focus:outline-none">
<svg *ngIf="!isDeckActive(deck)" 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">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
</svg>
<svg *ngIf="isDeckActive(deck)" 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">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7" />
</svg>
</button>
</div>
</div>
</div>
</div>
<!-- Right column: Active deck details -->
<div class="w-auto min-w-96" *ngIf="activeDeck">
<div class="bg-white shadow rounded-lg p-6 border-dashed border-2 border-gray-300">
<!-- Deck header -->
<div class="flex justify-between items-center mb-4">
<div class="flex items-center space-x-2">
<h2 class="text-xl font-semibold">{{ activeDeck.name }}</h2>
<span class="text-gray-600">({{ activeDeck.images.length }} images)</span>
</div>
<div class="flex space-x-2">
<button (click)="openDeletePopover(activeDeck.name)" class="text-red-500 hover:text-red-700" title="Delete Deck">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" 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>
</button>
<button (click)="openRenamePopover(activeDeck)" class="text-yellow-500 hover:text-yellow-700" title="Rename Deck">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15.232 5.232l3.536 3.536m-2.036-5.036a2.5 2.5 0 113.536 3.536L6.5 21.036H3v-3.572L16.732 3.732z" />
</svg>
</button>
</div>
</div>
<!-- Image list -->
<ul class="mb-4">
<li *ngFor="let image of activeDeck.images" class="flex justify-between items-center py-2 border-b last:border-b-0">
<div class="flex items-center space-x-2">
<div class="relative group">
<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="/images/{{ image.bildid }}/thumbnail.webp" alt="{{ image.name }}" class="w-full h-auto object-cover" />
</div>
<span class="font-medium cursor-pointer">{{ image.name }}</span>
</div>
<span class="text-gray-600">({{ image.boxes.length }} boxes)</span>
</div>
<div class="flex space-x-2">
<button (click)="editImage(activeDeck, image)" class="text-blue-500 hover:text-blue-700" title="Edit Image">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 4H4v7m0 0l9-9 9 9M20 13v7h-7m0 0l-9-9-9 9" />
</svg>
</button>
<button (click)="deleteImage(activeDeck, image)" class="text-red-500 hover:text-red-700" title="Delete Image">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" 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>
</button>
<button (click)="openMoveImageModal(activeDeck, image)" class="text-yellow-500 hover:text-yellow-700" title="Move Image">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7" />
</svg>
</button>
<button (click)="openRenameImagePopover(image)" class="text-yellow-500 hover:text-yellow-700" title="Rename Image">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15.232 5.232l3.536 3.536m-2.036-5.036a2.5 2.5 0 113.536 3.536L6.5 21.036H3v-3.572L16.732 3.732z" />
</svg>
</button>
</div>
</li>
</ul>
<div class="flex flex-row space-x-2 items-stretch">
<button (click)="openTraining(activeDeck)" class="flex-1 bg-blue-500 text-white py-2 px-4 rounded hover:bg-blue-600 flex items-center justify-center whitespace-nowrap">Start Training</button>
<div class="flex-1">
<div class="relative h-full">
<label for="imageFile" class="flex justify-center items-center bg-green-500 text-white py-2 px-4 rounded hover:bg-green-600 cursor-pointer h-full">
<div class="flex flex-col items-center">
<div class="whitespace-nowrap">Add Image</div>
<div class="text-xs whitespace-nowrap">(from file)</div>
</div>
</label>
<input #imageFile type="file" id="imageFile" (change)="onFileChange($event)" accept="image/jpeg,image/png,image/gif,image/webp" required class="hidden" />
</div>
</div>
<!-- Neuer Button Paste Image -->
<div class="flex-1">
<button (click)="pasteImage()" class="w-full bg-purple-500 text-white py-2 px-4 rounded hover:bg-purple-600 flex items-center justify-center h-full">
<div class="flex flex-col items-center">
<div class="whitespace-nowrap">Paste Image</div>
<div class="text-xs whitespace-nowrap">(from clipboard)</div>
</div>
</button>
</div>
</div>
</div>
</div>
</div>
<!-- Loading overlay -->
<div *ngIf="loading" class="absolute inset-0 bg-gray-800 bg-opacity-50 flex items-center justify-center z-10">
<div class="bg-white p-4 rounded shadow">
<p class="text-sm text-gray-700">Processing in progress...</p>
</div>
</div>
<!-- CreateDeckModalComponent -->
<app-create-deck-modal (deckCreated)="loadDecks()"></app-create-deck-modal>
<!-- UploadImageModalComponent -->
<!-- <app-upload-image-modal (imageUploaded)="onImageUploaded($event)"></app-upload-image-modal> -->
<app-edit-image-modal *ngIf="imageData" [deckName]="activeDeck.name" [imageData]="imageData" (imageSaved)="onImageSaved()" (closed)="onClosed()"></app-edit-image-modal>
<!-- TrainingComponent -->
<app-training *ngIf="trainingsDeck" [deck]="trainingsDeck" (close)="closeTraining()"></app-training>
<!-- MoveImageModalComponent -->
<app-move-image-modal *ngIf="imageToMove" [image]="imageToMove.image" [sourceDeck]="imageToMove.sourceDeck" [decks]="decks" (moveCompleted)="onImageMoved()" (closed)="imageToMove = null"> </app-move-image-modal>
</div>