Spaces:
Running
Running
| // Initial data structure with enhanced features | |
| const todos = [ | |
| { | |
| id: 1, | |
| text: 'Beispielaufgabe erstellen', | |
| completed: true, | |
| priority: 'medium', | |
| createdAt: new Date().toISOString(), | |
| updatedAt: new Date().toISOString() | |
| }, | |
| { | |
| id: 2, | |
| text: 'Todo-App mit neuen Features verbessern', | |
| completed: false, | |
| priority: 'high', | |
| dueDate: new Date(Date.now() + 86400000).toISOString().split('T')[0], // Morgen | |
| createdAt: new Date(Date.now() - 86400000).toISOString(), | |
| updatedAt: new Date(Date.now() - 86400000).toISOString() | |
| }, | |
| { | |
| id: 3, | |
| text: 'Dokumentation für das Team erstellen', | |
| completed: false, | |
| priority: 'low', | |
| createdAt: new Date(Date.now() - 172800000).toISOString(), // Vorgestern | |
| updatedAt: new Date(Date.now() - 172800000).toISOString() | |
| } | |
| ]; | |
| function todoApp() { | |
| return { | |
| todos: [], | |
| newTodo: '', | |
| newPriority: 'medium', | |
| newDueDate: '', | |
| filter: 'all', | |
| sortBy: 'priority', | |
| searchQuery: '', | |
| showToast: false, | |
| toastMessage: '', | |
| toastType: 'success', | |
| editingId: null, | |
| editingText: '', | |
| editingPriority: 'medium', | |
| editingDueDate: '', | |
| dragStartIndex: null, | |
| dragOverIndex: null, | |
| // Initialize from localStorage or default | |
| init() { | |
| const savedTodos = localStorage.getItem('todos'); | |
| this.todos = savedTodos ? JSON.parse(savedTodos) : todos; | |
| this.updateLocalStorage(); | |
| // Initialize Feather icons after content loads | |
| setTimeout(() => { | |
| if (typeof feather !== 'undefined') { | |
| feather.replace(); | |
| } | |
| }, 100); | |
| }, | |
| // Filtered and sorted todos based on current settings | |
| get filteredTodos() { | |
| let filtered = this.todos; | |
| // Apply search filter | |
| if (this.searchQuery.trim() !== '') { | |
| const query = this.searchQuery.toLowerCase(); | |
| filtered = filtered.filter(todo => | |
| todo.text.toLowerCase().includes(query) | |
| ); | |
| } | |
| // Apply status filter | |
| if (this.filter === 'active') { | |
| filtered = filtered.filter(todo => !todo.completed); | |
| } else if (this.filter === 'completed') { | |
| filtered = filtered.filter(todo => todo.completed); | |
| } | |
| // Apply sorting | |
| filtered = [...filtered]; // Create a copy | |
| if (this.sortBy === 'priority') { | |
| const priorityOrder = { high: 0, medium: 1, low: 2, undefined: 3 }; | |
| filtered.sort((a, b) => { | |
| const aPriority = priorityOrder[a.priority || 'undefined']; | |
| const bPriority = priorityOrder[b.priority || 'undefined']; | |
| return aPriority - bPriority; | |
| }); | |
| } else { | |
| filtered.sort((a, b) => { | |
| const aDate = new Date(a.createdAt); | |
| const bDate = new Date(b.createdAt); | |
| return bDate - aDate; // Newest first | |
| }); | |
| } | |
| return filtered; | |
| }, | |
| // Enhanced statistics | |
| get completedCount() { | |
| return this.todos.filter(todo => todo.completed).length; | |
| }, | |
| get activeCount() { | |
| return this.todos.filter(todo => !todo.completed).length; | |
| }, | |
| get totalCount() { | |
| return this.todos.length; | |
| }, | |
| get overdueCount() { | |
| const today = new Date().toISOString().split('T')[0]; | |
| return this.todos.filter(todo => | |
| !todo.completed && | |
| todo.dueDate && | |
| todo.dueDate < today | |
| ).length; | |
| }, | |
| // Check if a todo is overdue | |
| isOverdue(dueDate) { | |
| if (!dueDate) return false; | |
| const today = new Date().toISOString().split('T')[0]; | |
| return dueDate < today; | |
| }, | |
| // Add new todo with enhanced features | |
| addTodo() { | |
| if (this.newTodo.trim() === '') { | |
| this.showNotification('Bitte gib eine Aufgabe ein', 'error'); | |
| return; | |
| } | |
| const newTodo = { | |
| id: Date.now(), | |
| text: this.newTodo.trim(), | |
| completed: false, | |
| priority: this.newPriority, | |
| dueDate: this.newDueDate || null, | |
| overdue: this.isOverdue(this.newDueDate), | |
| createdAt: new Date().toISOString(), | |
| updatedAt: new Date().toISOString() | |
| }; | |
| this.todos.unshift(newTodo); | |
| this.newTodo = ''; | |
| this.newDueDate = ''; | |
| this.newPriority = 'medium'; | |
| this.updateLocalStorage(); | |
| this.showNotification('Aufgabe hinzugefügt', 'success'); | |
| }, | |
| // Toggle todo completion | |
| toggleTodo(id) { | |
| const todo = this.todos.find(t => t.id === id); | |
| if (todo) { | |
| todo.completed = !todo.completed; | |
| todo.updatedAt = new Date().toISOString(); | |
| this.updateLocalStorage(); | |
| const message = todo.completed ? 'Aufgabe erledigt!' : 'Aufgabe wieder geöffnet'; | |
| this.showNotification(message, 'success'); | |
| } | |
| }, | |
| // Delete todo | |
| deleteTodo(id) { | |
| this.todos = this.todos.filter(t => t.id !== id); | |
| this.updateLocalStorage(); | |
| this.showNotification('Aufgabe gelöscht', 'success'); | |
| }, | |
| // Clear completed todos | |
| clearCompleted() { | |
| const completedCount = this.completedCount; | |
| this.todos = this.todos.filter(t => !t.completed); | |
| this.updateLocalStorage(); | |
| this.showNotification(`${completedCount} erledigte Aufgabe(n) gelöscht`, 'success'); | |
| }, | |
| // Edit todo with enhanced features | |
| startEdit(id, text, priority = 'medium', dueDate = '') { | |
| this.editingId = id; | |
| this.editingText = text; | |
| this.editingPriority = priority || 'medium'; | |
| this.editingDueDate = dueDate || ''; | |
| }, | |
| saveEdit() { | |
| if (this.editingText.trim() === '') { | |
| this.showNotification('Aufgabe darf nicht leer sein', 'error'); | |
| return; | |
| } | |
| const todo = this.todos.find(t => t.id === this.editingId); | |
| if (todo) { | |
| todo.text = this.editingText.trim(); | |
| todo.priority = this.editingPriority; | |
| todo.dueDate = this.editingDueDate || null; | |
| todo.overdue = this.isOverdue(this.editingDueDate); | |
| todo.updatedAt = new Date().toISOString(); | |
| this.updateLocalStorage(); | |
| this.cancelEdit(); | |
| this.showNotification('Aufgabe aktualisiert', 'success'); | |
| } | |
| }, | |
| cancelEdit() { | |
| this.editingId = null; | |
| this.editingText = ''; | |
| this.editingPriority = 'medium'; | |
| this.editingDueDate = ''; | |
| }, | |
| // Drag and drop functionality | |
| dragStart(index) { | |
| this.dragStartIndex = index; | |
| this.dragOverIndex = null; | |
| }, | |
| dragOver(event) { | |
| event.preventDefault(); | |
| }, | |
| setDragOver(index) { | |
| if (index !== this.dragStartIndex) { | |
| this.dragOverIndex = index; | |
| } | |
| }, | |
| clearDragOver() { | |
| this.dragOverIndex = null; | |
| }, | |
| dropOn(targetIndex) { | |
| if (this.dragStartIndex === null || this.dragStartIndex === targetIndex) { | |
| this.clearDragOver(); | |
| return; | |
| } | |
| const draggedTodo = this.todos[this.dragStartIndex]; | |
| this.todos.splice(this.dragStartIndex, 1); | |
| this.todos.splice(targetIndex, 0, draggedTodo); | |
| this.dragStartIndex = null; | |
| this.dragOverIndex = null; | |
| this.updateLocalStorage(); | |
| this.showNotification('Aufgabe verschoben', 'success'); | |
| }, | |
| drop() { | |
| this.dragStartIndex = null; | |
| this.dragOverIndex = null; | |
| }, | |
| // Format date for display | |
| formatDate(dateString) { | |
| const date = new Date(dateString); | |
| return date.toLocaleDateString('de-DE', { | |
| day: '2-digit', | |
| month: '2-digit', | |
| year: 'numeric', | |
| hour: '2-digit', | |
| minute: '2-digit' | |
| }); | |
| }, | |
| // Format due date | |
| formatDueDate(dateString) { | |
| if (!dateString) return ''; | |
| const date = new Date(dateString); | |
| const today = new Date(); | |
| const tomorrow = new Date(today); | |
| tomorrow.setDate(tomorrow.getDate() + 1); | |
| if (date.toDateString() === today.toDateString()) { | |
| return 'Heute'; | |
| } else if (date.toDateString() === tomorrow.toDateString()) { | |
| return 'Morgen'; | |
| } else { | |
| return date.toLocaleDateString('de-DE', { | |
| day: '2-digit', | |
| month: '2-digit', | |
| year: 'numeric' | |
| }); | |
| } | |
| }, | |
| // Show notification toast | |
| showNotification(message, type = 'success') { | |
| this.toastMessage = message; | |
| this.toastType = type; | |
| this.showToast = true; | |
| setTimeout(() => { | |
| this.showToast = false; | |
| }, 3000); | |
| }, | |
| // Update localStorage | |
| updateLocalStorage() { | |
| localStorage.setItem('todos', JSON.stringify(this.todos)); | |
| }, | |
| // Update Feather icons when needed | |
| updateIcons() { | |
| if (typeof feather !== 'undefined') { | |
| feather.replace(); | |
| } | |
| } | |
| }; | |
| } |