Compare commits
2 Commits
ddac7102fe
...
303ba7c4b2
| Author | SHA1 | Date |
|---|---|---|
|
|
303ba7c4b2 | |
|
|
0ea427b265 |
|
|
@ -1,7 +1,6 @@
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
import { Component } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
import { RouterOutlet } from '@angular/router';
|
import { RouterOutlet } from '@angular/router';
|
||||||
import { initFlowbite } from 'flowbite';
|
|
||||||
import { DeckListComponent } from './deck-list.component';
|
import { DeckListComponent } from './deck-list.component';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
|
|
@ -18,6 +17,5 @@ import { DeckListComponent } from './deck-list.component';
|
||||||
export class AppComponent {
|
export class AppComponent {
|
||||||
title = 'vocabulary-training';
|
title = 'vocabulary-training';
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
initFlowbite();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,16 +1,9 @@
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
<!-- Button to create a new deck -->
|
|
||||||
<!-- <div class="flex justify-end mb-4">
|
|
||||||
<button (click)="openCreateDeckModal()" class="bg-green-500 text-white py-2 px-4 rounded hover:bg-green-600">
|
|
||||||
Create New Deck
|
|
||||||
</button>
|
|
||||||
</div> -->
|
|
||||||
|
|
||||||
<!-- Two-column layout -->
|
<!-- Two-column layout -->
|
||||||
<div class="flex flex-col md:flex-row gap-4 mx-auto max-w-5xl">
|
<div *ngIf="!trainingsDeck" class="flex flex-col md:flex-row gap-4 mx-auto max-w-5xl">
|
||||||
|
|
||||||
<!-- Left column: List of decks -->
|
<!-- Left column: List of decks -->
|
||||||
<div class="w-full md:w-1/3">
|
<div class="w-auto">
|
||||||
<div class="bg-white shadow rounded-lg p-4">
|
<div class="bg-white shadow rounded-lg p-4">
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<h2 class="text-xl font-semibold mb-4">Decks</h2>
|
<h2 class="text-xl font-semibold mb-4">Decks</h2>
|
||||||
|
|
@ -23,13 +16,14 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="space-y-2">
|
<div class="space-y-2">
|
||||||
<div *ngFor="let deck of decks"
|
<div *ngFor="let deck of decks"
|
||||||
class="flex justify-between items-center p-2 rounded hover:bg-gray-100 cursor-pointer"
|
class="flex justify-between items-center p-2 rounded hover:bg-gray-300 cursor-pointer"
|
||||||
[class.bg-blue-100]="isDeckActive(deck)">
|
[class.bg-blue-200]="isDeckActive(deck)"
|
||||||
|
(click)="toggleDeckExpansion(deck)">
|
||||||
<div class="flex items-center space-x-2 whitespace-nowrap">
|
<div class="flex items-center space-x-2 whitespace-nowrap">
|
||||||
<h3 class="font-medium">{{ deck.name }}</h3>
|
<h3 class="font-medium">{{ deck.name }}</h3>
|
||||||
<span class="text-gray-600">({{ deck.images.length }})</span>
|
<span class="text-gray-600">({{ deck.images.length }})</span>
|
||||||
</div>
|
</div>
|
||||||
<button (click)="toggleDeckExpansion(deck)" class="text-gray-500 hover:text-gray-700 focus:outline-none">
|
<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">
|
<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" />
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
|
||||||
</svg>
|
</svg>
|
||||||
|
|
@ -43,8 +37,8 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Right column: Active deck details -->
|
<!-- Right column: Active deck details -->
|
||||||
<div class="w-full md:w-2/3" *ngIf="activeDeck">
|
<div class="w-auto min-w-96" *ngIf="activeDeck">
|
||||||
<div class="bg-white shadow rounded-lg p-6 border-dashed border-2 border-indigo-600">
|
<div class="bg-white shadow rounded-lg p-6 border-dashed border-2 border-gray-300">
|
||||||
<!-- Deck header -->
|
<!-- Deck header -->
|
||||||
<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">
|
<div class="flex items-center space-x-2">
|
||||||
|
|
@ -116,7 +110,7 @@
|
||||||
<app-upload-image-modal (imageUploaded)="onImageUploaded($event)"></app-upload-image-modal>
|
<app-upload-image-modal (imageUploaded)="onImageUploaded($event)"></app-upload-image-modal>
|
||||||
<app-edit-image-modal *ngIf="imageData" [deckName]="currentUploadDeckName" [imageData]="imageData" (imageSaved)="onImageSaved()" (closed)="onClosed()"></app-edit-image-modal>
|
<app-edit-image-modal *ngIf="imageData" [deckName]="currentUploadDeckName" [imageData]="imageData" (imageSaved)="onImageSaved()" (closed)="onClosed()"></app-edit-image-modal>
|
||||||
<!-- TrainingComponent -->
|
<!-- TrainingComponent -->
|
||||||
<app-training *ngIf="selectedDeck" [deck]="selectedDeck" (close)="closeTraining()"></app-training>
|
<app-training *ngIf="trainingsDeck" [deck]="trainingsDeck" (close)="closeTraining()"></app-training>
|
||||||
<!-- MoveImageModalComponent -->
|
<!-- MoveImageModalComponent -->
|
||||||
<app-move-image-modal
|
<app-move-image-modal
|
||||||
*ngIf="imageToMove"
|
*ngIf="imageToMove"
|
||||||
|
|
@ -139,7 +133,7 @@
|
||||||
<!-- Popover für die Eingabe des neuen Decknamens -->
|
<!-- Popover für die Eingabe des neuen Decknamens -->
|
||||||
<div id="renamePopover" popover="manual" class="popover">
|
<div id="renamePopover" popover="manual" class="popover">
|
||||||
<p>Enter the new name for the deck:</p>
|
<p>Enter the new name for the deck:</p>
|
||||||
<input type="text" id="newDeckNameInput" class="w-full p-2 border rounded mb-2" />
|
<input type="text" id="newDeckNameInput" class="w-full p-2 border rounded mb-2" [value]="deckToRename?.name" />
|
||||||
<div class="flex justify-end space-x-2">
|
<div class="flex justify-end space-x-2">
|
||||||
<button (click)="confirmRename()" class="bg-blue-500 text-white px-4 py-2 rounded">Rename</button>
|
<button (click)="confirmRename()" class="bg-blue-500 text-white px-4 py-2 rounded">Rename</button>
|
||||||
<button (click)="cancelRename()" class="bg-gray-500 text-white px-4 py-2 rounded">Cancel</button>
|
<button (click)="cancelRename()" class="bg-gray-500 text-white px-4 py-2 rounded">Cancel</button>
|
||||||
|
|
|
||||||
|
|
@ -34,10 +34,10 @@ import { MoveImageModalComponent } from './move-image-modal/move-image-modal.com
|
||||||
})
|
})
|
||||||
export class DeckListComponent implements OnInit {
|
export class DeckListComponent implements OnInit {
|
||||||
decks: Deck[] = [];
|
decks: Deck[] = [];
|
||||||
selectedDeck: Deck | null = null;
|
trainingsDeck: Deck | null = null;
|
||||||
activeDeck: Deck | null = null;
|
activeDeck: Deck | null = null;
|
||||||
private deckToDelete: string | null = null;
|
private deckToDelete: string | null = null;
|
||||||
private deckToRename: Deck | null = null;
|
deckToRename: Deck | null = null;
|
||||||
|
|
||||||
@ViewChild(CreateDeckModalComponent) createDeckModal!: CreateDeckModalComponent;
|
@ViewChild(CreateDeckModalComponent) createDeckModal!: CreateDeckModalComponent;
|
||||||
@ViewChild(UploadImageModalComponent) uploadImageModal!: UploadImageModalComponent;
|
@ViewChild(UploadImageModalComponent) uploadImageModal!: UploadImageModalComponent;
|
||||||
|
|
@ -79,8 +79,7 @@ export class DeckListComponent implements OnInit {
|
||||||
this.activeDeck = deck;
|
this.activeDeck = deck;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Method to open the delete confirmation popover
|
||||||
// Methode zum Öffnen des Lösch-Popovers
|
|
||||||
openDeletePopover(deckName: string): void {
|
openDeletePopover(deckName: string): void {
|
||||||
this.deckToDelete = deckName;
|
this.deckToDelete = deckName;
|
||||||
const deletePopover = document.getElementById('deletePopover');
|
const deletePopover = document.getElementById('deletePopover');
|
||||||
|
|
@ -88,29 +87,32 @@ export class DeckListComponent implements OnInit {
|
||||||
deletePopover.showPopover();
|
deletePopover.showPopover();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Method to check if a deck is active
|
// Method to check if a deck is active
|
||||||
isDeckActive(deck: Deck): boolean {
|
isDeckActive(deck: Deck): boolean {
|
||||||
return this.activeDeck?.name === deck.name;
|
return this.activeDeck?.name === deck.name;
|
||||||
}
|
}
|
||||||
// Methode zum Bestätigen des Löschens
|
|
||||||
|
// Method to confirm the deletion of a deck
|
||||||
confirmDelete(): void {
|
confirmDelete(): void {
|
||||||
if (this.deckToDelete) {
|
if (this.deckToDelete) {
|
||||||
this.deckService.deleteDeck(this.deckToDelete).subscribe({
|
this.deckService.deleteDeck(this.deckToDelete).subscribe({
|
||||||
next: () => {
|
next: () => {
|
||||||
this.loadDecks();
|
this.loadDecks();
|
||||||
this.closeDeletePopover();
|
this.closeDeletePopover();
|
||||||
|
this.activeDeck = this.decks[0];
|
||||||
},
|
},
|
||||||
error: (err) => console.error('Error deleting deck', err),
|
error: (err) => console.error('Error deleting deck', err),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Methode zum Abbrechen des Löschens
|
// Method to cancel the deletion of a deck
|
||||||
cancelDelete(): void {
|
cancelDelete(): void {
|
||||||
this.closeDeletePopover();
|
this.closeDeletePopover();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Methode zum Schließen des Lösch-Popovers
|
// Method to close the delete confirmation popover
|
||||||
closeDeletePopover(): void {
|
closeDeletePopover(): void {
|
||||||
const deletePopover = document.getElementById('deletePopover');
|
const deletePopover = document.getElementById('deletePopover');
|
||||||
if (deletePopover) {
|
if (deletePopover) {
|
||||||
|
|
@ -119,16 +121,24 @@ export class DeckListComponent implements OnInit {
|
||||||
this.deckToDelete = null;
|
this.deckToDelete = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Methode zum Öffnen des Umbenennungs-Popovers
|
// Method to open the rename popover
|
||||||
openRenamePopover(deck: Deck): void {
|
openRenamePopover(deck: Deck): void {
|
||||||
this.deckToRename = deck;
|
this.deckToRename = deck;
|
||||||
const renamePopover = document.getElementById('renamePopover');
|
const renamePopover = document.getElementById('renamePopover');
|
||||||
if (renamePopover) {
|
if (renamePopover) {
|
||||||
renamePopover.showPopover();
|
renamePopover.showPopover();
|
||||||
|
// Set the input value to the current deck name and select it
|
||||||
|
setTimeout(() => {
|
||||||
|
const newDeckNameInput = document.getElementById('newDeckNameInput') as HTMLInputElement;
|
||||||
|
if (newDeckNameInput) {
|
||||||
|
newDeckNameInput.value = deck.name;
|
||||||
|
newDeckNameInput.select();
|
||||||
|
}
|
||||||
|
}, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Methode zum Bestätigen des Umbenennens
|
// Method to confirm the renaming of a deck
|
||||||
confirmRename(): void {
|
confirmRename(): void {
|
||||||
const newDeckNameInput = document.getElementById('newDeckNameInput') as HTMLInputElement;
|
const newDeckNameInput = document.getElementById('newDeckNameInput') as HTMLInputElement;
|
||||||
if (newDeckNameInput && this.deckToRename) {
|
if (newDeckNameInput && this.deckToRename) {
|
||||||
|
|
@ -136,7 +146,11 @@ export class DeckListComponent implements OnInit {
|
||||||
if (newDeckName && newDeckName !== this.deckToRename.name) {
|
if (newDeckName && newDeckName !== this.deckToRename.name) {
|
||||||
this.deckService.renameDeck(this.deckToRename.name, newDeckName).subscribe({
|
this.deckService.renameDeck(this.deckToRename.name, newDeckName).subscribe({
|
||||||
next: () => {
|
next: () => {
|
||||||
this.loadDecks();
|
// Aktualisiere den Namen im activeDeck, falls dieser der umbenannte Deck ist
|
||||||
|
if (this.activeDeck && this.activeDeck.name === this.deckToRename?.name) {
|
||||||
|
this.activeDeck.name = newDeckName;
|
||||||
|
}
|
||||||
|
this.loadDecks(); // Lade die Decks neu, um die Liste zu aktualisieren
|
||||||
this.closeRenamePopover();
|
this.closeRenamePopover();
|
||||||
},
|
},
|
||||||
error: (err) => console.error('Error renaming deck', err),
|
error: (err) => console.error('Error renaming deck', err),
|
||||||
|
|
@ -145,12 +159,12 @@ export class DeckListComponent implements OnInit {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Methode zum Abbrechen des Umbenennens
|
// Method to cancel the renaming of a deck
|
||||||
cancelRename(): void {
|
cancelRename(): void {
|
||||||
this.closeRenamePopover();
|
this.closeRenamePopover();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Methode zum Schließen des Umbenennungs-Popovers
|
// Method to close the rename popover
|
||||||
closeRenamePopover(): void {
|
closeRenamePopover(): void {
|
||||||
const renamePopover = document.getElementById('renamePopover');
|
const renamePopover = document.getElementById('renamePopover');
|
||||||
if (renamePopover) {
|
if (renamePopover) {
|
||||||
|
|
@ -158,6 +172,8 @@ export class DeckListComponent implements OnInit {
|
||||||
}
|
}
|
||||||
this.deckToRename = null;
|
this.deckToRename = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Method to delete a deck
|
||||||
deleteDeck(deckName: string): void {
|
deleteDeck(deckName: string): void {
|
||||||
if (!confirm(`Are you sure you want to delete the deck "${deckName}"?`)) {
|
if (!confirm(`Are you sure you want to delete the deck "${deckName}"?`)) {
|
||||||
return;
|
return;
|
||||||
|
|
@ -168,6 +184,7 @@ export class DeckListComponent implements OnInit {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Method to rename a deck
|
||||||
renameDeck(deck: Deck): void {
|
renameDeck(deck: Deck): void {
|
||||||
const newDeckName = prompt('Enter the new name for the deck:', deck.name);
|
const newDeckName = prompt('Enter the new name for the deck:', deck.name);
|
||||||
if (newDeckName && newDeckName !== deck.name) {
|
if (newDeckName && newDeckName !== deck.name) {
|
||||||
|
|
@ -178,6 +195,7 @@ export class DeckListComponent implements OnInit {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Method to delete an image from a deck
|
||||||
deleteImage(deck: Deck, image: DeckImage): void {
|
deleteImage(deck: Deck, image: DeckImage): void {
|
||||||
if (!confirm(`Are you sure you want to delete the image "${image.name}"?`)) {
|
if (!confirm(`Are you sure you want to delete the image "${image.name}"?`)) {
|
||||||
return;
|
return;
|
||||||
|
|
@ -191,6 +209,7 @@ export class DeckListComponent implements OnInit {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Method to edit an image in a deck
|
||||||
editImage(deck: Deck, image: DeckImage): void {
|
editImage(deck: Deck, image: DeckImage): void {
|
||||||
let imageSrc = null;
|
let imageSrc = null;
|
||||||
this.currentUploadDeckName = deck.name;
|
this.currentUploadDeckName = deck.name;
|
||||||
|
|
@ -214,19 +233,23 @@ export class DeckListComponent implements OnInit {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Method to open the training component
|
||||||
openTraining(deck: Deck): void {
|
openTraining(deck: Deck): void {
|
||||||
this.selectedDeck = deck;
|
this.trainingsDeck = deck;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Method to close the training component
|
||||||
closeTraining(): void {
|
closeTraining(): void {
|
||||||
this.selectedDeck = null;
|
this.trainingsDeck = null;
|
||||||
this.loadDecks();
|
this.loadDecks();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Method to open the create deck modal
|
||||||
openCreateDeckModal(): void {
|
openCreateDeckModal(): void {
|
||||||
this.createDeckModal.open();
|
this.createDeckModal.open();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Method to open the upload image modal
|
||||||
openUploadImageModal(deckName: string): void {
|
openUploadImageModal(deckName: string): void {
|
||||||
this.currentUploadDeckName = deckName;
|
this.currentUploadDeckName = deckName;
|
||||||
this.uploadImageModal.deckName = deckName;
|
this.uploadImageModal.deckName = deckName;
|
||||||
|
|
@ -238,7 +261,7 @@ export class DeckListComponent implements OnInit {
|
||||||
return this.expandedDecks.has(deckName);
|
return this.expandedDecks.has(deckName);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load expanded decks from sessionStorage
|
// Method to load expanded decks from sessionStorage
|
||||||
loadExpandedDecks(): void {
|
loadExpandedDecks(): void {
|
||||||
const stored = sessionStorage.getItem('expandedDecks');
|
const stored = sessionStorage.getItem('expandedDecks');
|
||||||
if (stored) {
|
if (stored) {
|
||||||
|
|
@ -254,13 +277,13 @@ export class DeckListComponent implements OnInit {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save expanded decks to sessionStorage
|
// Method to save expanded decks to sessionStorage
|
||||||
saveExpandedDecks(): void {
|
saveExpandedDecks(): void {
|
||||||
const expandedArray = Array.from(this.expandedDecks);
|
const expandedArray = Array.from(this.expandedDecks);
|
||||||
sessionStorage.setItem('expandedDecks', JSON.stringify(expandedArray));
|
sessionStorage.setItem('expandedDecks', JSON.stringify(expandedArray));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Function to open the upload modal (can be triggered by a button)
|
// Method to open the upload modal
|
||||||
openUploadModal(): void {
|
openUploadModal(): void {
|
||||||
this.uploadImageModal.open();
|
this.uploadImageModal.open();
|
||||||
}
|
}
|
||||||
|
|
@ -277,7 +300,17 @@ export class DeckListComponent implements OnInit {
|
||||||
async onImageSaved() {
|
async onImageSaved() {
|
||||||
// Handle saving the image data, e.g., update the list of images
|
// Handle saving the image data, e.g., update the list of images
|
||||||
this.imageData = null;
|
this.imageData = null;
|
||||||
|
|
||||||
|
// Lade die Decks neu
|
||||||
this.decks = await firstValueFrom(this.deckService.getDecks());
|
this.decks = await firstValueFrom(this.deckService.getDecks());
|
||||||
|
|
||||||
|
// Aktualisiere den activeDeck, falls dieser der aktuelle Deck ist
|
||||||
|
if (this.activeDeck) {
|
||||||
|
const updatedDeck = this.decks.find(deck => deck.name === this.activeDeck?.name);
|
||||||
|
if (updatedDeck) {
|
||||||
|
this.activeDeck = updatedDeck;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Method to open the MoveImageModal
|
// Method to open the MoveImageModal
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue