diff --git a/components/navbar.html b/components/navbar.html
index b1dcf5d..f8b4891 100644
--- a/components/navbar.html
+++ b/components/navbar.html
@@ -15,6 +15,7 @@
Notenrechner
Textanalyse
Notenrechner (DOM)
+ Kanban Board
PDF ↓
diff --git a/css/kanban.css b/css/kanban.css
new file mode 100644
index 0000000..4bde3ea
--- /dev/null
+++ b/css/kanban.css
@@ -0,0 +1,417 @@
+/* ====================== KANBAN BOARD STYLES ====================== */
+
+.kanban-main {
+ min-height: 100vh;
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+ padding: 2rem 0;
+}
+
+.kanban-header {
+ max-width: 1400px;
+ margin: 0 auto 2rem;
+ padding: 0 2rem;
+ text-align: center;
+}
+
+.kanban-header h1 {
+ font-size: 3rem;
+ color: white;
+ margin: 0 0 0.5rem 0;
+ text-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
+}
+
+.kanban-header p {
+ color: rgba(255, 255, 255, 0.9);
+ font-size: 1.1rem;
+ margin-bottom: 2rem;
+}
+
+.header-actions {
+ display: flex;
+ gap: 1rem;
+ justify-content: center;
+ flex-wrap: wrap;
+}
+
+.btn {
+ padding: 0.8rem 1.5rem;
+ border: none;
+ border-radius: 8px;
+ font-size: 1rem;
+ font-weight: 600;
+ cursor: pointer;
+ transition: all 0.3s ease;
+ text-transform: capitalize;
+}
+
+.btn-primary {
+ background: white;
+ color: #667eea;
+ box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
+}
+
+.btn-primary:hover {
+ transform: translateY(-2px);
+ box-shadow: 0 6px 20px rgba(0, 0, 0, 0.3);
+}
+
+.btn-secondary {
+ background: rgba(255, 255, 255, 0.2);
+ color: white;
+ border: 2px solid rgba(255, 255, 255, 0.5);
+}
+
+.btn-secondary:hover {
+ background: rgba(255, 255, 255, 0.3);
+ border-color: white;
+}
+
+.btn-danger {
+ background: rgba(239, 68, 68, 0.2);
+ color: #fecaca;
+ border: 2px solid rgba(239, 68, 68, 0.5);
+}
+
+.btn-danger:hover {
+ background: rgba(239, 68, 68, 0.3);
+ border-color: #fecaca;
+}
+
+/* ====================== KANBAN CONTAINER ====================== */
+
+.kanban-container {
+ max-width: 1400px;
+ margin: 0 auto;
+ padding: 0 2rem;
+ display: flex;
+ gap: 2rem;
+ overflow-x: auto;
+ padding-bottom: 2rem;
+}
+
+.kanban-container::-webkit-scrollbar {
+ height: 8px;
+}
+
+.kanban-container::-webkit-scrollbar-track {
+ background: rgba(255, 255, 255, 0.1);
+}
+
+.kanban-container::-webkit-scrollbar-thumb {
+ background: rgba(255, 255, 255, 0.3);
+ border-radius: 4px;
+}
+
+.kanban-container::-webkit-scrollbar-thumb:hover {
+ background: rgba(255, 255, 255, 0.5);
+}
+
+/* ====================== SPALTEN ====================== */
+
+.kanban-column {
+ flex: 0 0 320px;
+ background: white;
+ border-radius: 12px;
+ box-shadow: 0 8px 25px rgba(0, 0, 0, 0.15);
+ display: flex;
+ flex-direction: column;
+ max-height: 80vh;
+ overflow: hidden;
+ transition: all 0.3s ease;
+}
+
+.kanban-column.drag-over {
+ background: #f0f4ff;
+ box-shadow: 0 12px 35px rgba(102, 126, 234, 0.3);
+ transform: scale(1.02);
+}
+
+.kanban-column-header {
+ padding: 1.5rem;
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+ color: white;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ border-radius: 12px 12px 0 0;
+}
+
+.kanban-column-title {
+ font-size: 1.2rem;
+ font-weight: 700;
+ margin: 0;
+}
+
+.column-delete-btn {
+ background: rgba(255, 255, 255, 0.2);
+ border: none;
+ color: white;
+ width: 32px;
+ height: 32px;
+ border-radius: 6px;
+ cursor: pointer;
+ font-size: 1.2rem;
+ transition: all 0.2s ease;
+}
+
+.column-delete-btn:hover {
+ background: rgba(255, 255, 255, 0.4);
+}
+
+.kanban-cards {
+ flex: 1;
+ padding: 1rem;
+ display: flex;
+ flex-direction: column;
+ gap: 1rem;
+ overflow-y: auto;
+}
+
+.kanban-cards::-webkit-scrollbar {
+ width: 6px;
+}
+
+.kanban-cards::-webkit-scrollbar-track {
+ background: transparent;
+}
+
+.kanban-cards::-webkit-scrollbar-thumb {
+ background: #e2e8f0;
+ border-radius: 3px;
+}
+
+.kanban-cards::-webkit-scrollbar-thumb:hover {
+ background: #cbd5e1;
+}
+
+/* ====================== KARTEN ====================== */
+
+.kanban-card {
+ background: white;
+ border: 2px solid #e2e8f0;
+ border-radius: 8px;
+ padding: 1rem;
+ cursor: move;
+ transition: all 0.2s ease;
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
+ position: relative;
+ min-height: 60px;
+ display: flex;
+ justify-content: space-between;
+ align-items: flex-start;
+ gap: 0.5rem;
+}
+
+.kanban-card:hover {
+ box-shadow: 0 8px 20px rgba(0, 0, 0, 0.15);
+ border-color: #667eea;
+ transform: translateY(-2px);
+}
+
+.kanban-card.dragging {
+ opacity: 0.5;
+ transform: rotate(5deg);
+}
+
+.kanban-card.drag-over-card {
+ border-top: 3px solid #667eea;
+ margin-top: 8px;
+}
+
+.card-content {
+ flex: 1;
+ word-break: break-word;
+}
+
+.card-text {
+ margin: 0;
+ color: #1e293b;
+ font-size: 0.95rem;
+ line-height: 1.5;
+ outline: none;
+ min-height: 1.5em;
+}
+
+.card-text:focus {
+ background: #f0f4ff;
+ padding: 0.25rem;
+ border-radius: 4px;
+}
+
+.card-label {
+ display: inline-block;
+ padding: 0.3rem 0.6rem;
+ border-radius: 4px;
+ font-size: 0.75rem;
+ font-weight: 600;
+ color: white;
+ margin-top: 0.5rem;
+ cursor: pointer;
+ transition: all 0.2s ease;
+}
+
+.card-label:hover {
+ transform: scale(1.1);
+}
+
+.label-red {
+ background: #ef4444;
+}
+
+.label-blue {
+ background: #3b82f6;
+}
+
+.label-yellow {
+ background: #eab308;
+}
+
+.label-green {
+ background: #22c55e;
+}
+
+.label-purple {
+ background: #a855f7;
+}
+
+.card-actions {
+ display: flex;
+ gap: 0.3rem;
+ flex-direction: column;
+}
+
+.card-delete-btn {
+ background: #ef4444;
+ border: none;
+ color: white;
+ width: 28px;
+ height: 28px;
+ border-radius: 4px;
+ cursor: pointer;
+ font-size: 1rem;
+ transition: all 0.2s ease;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.card-delete-btn:hover {
+ background: #dc2626;
+ transform: scale(1.15);
+}
+
+/* ====================== ADD BUTTON ====================== */
+
+.add-card-btn {
+ width: 100%;
+ padding: 0.8rem;
+ background: #f1f5f9;
+ border: 2px dashed #cbd5e1;
+ border-radius: 8px;
+ color: #64748b;
+ font-size: 0.95rem;
+ font-weight: 600;
+ cursor: pointer;
+ transition: all 0.2s ease;
+ margin-top: auto;
+}
+
+.add-card-btn:hover {
+ background: #e2e8f0;
+ border-color: #667eea;
+ color: #667eea;
+}
+
+/* ====================== COLOR PICKER ====================== */
+
+.color-picker {
+ position: fixed;
+ background: white;
+ border-radius: 8px;
+ box-shadow: 0 8px 25px rgba(0, 0, 0, 0.2);
+ z-index: 1000;
+ overflow: hidden;
+}
+
+.color-picker-title {
+ padding: 0.8rem 1rem;
+ background: #f1f5f9;
+ font-size: 0.9rem;
+ font-weight: 600;
+ color: #475569;
+ border-bottom: 1px solid #e2e8f0;
+}
+
+.color-options {
+ display: grid;
+ grid-template-columns: repeat(3, 1fr);
+ gap: 0.5rem;
+ padding: 0.8rem;
+}
+
+.color-option {
+ width: 40px;
+ height: 40px;
+ border-radius: 6px;
+ cursor: pointer;
+ border: 3px solid transparent;
+ transition: all 0.2s ease;
+}
+
+.color-option:hover {
+ transform: scale(1.1);
+}
+
+.color-option.active {
+ border-color: #1e293b;
+ box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
+}
+
+/* ====================== RESPONSIVE ====================== */
+
+@media (max-width: 768px) {
+ .kanban-header h1 {
+ font-size: 2rem;
+ }
+
+ .kanban-container {
+ padding: 0 1rem;
+ gap: 1rem;
+ }
+
+ .kanban-column {
+ flex: 0 0 280px;
+ }
+
+ .header-actions {
+ gap: 0.5rem;
+ }
+
+ .btn {
+ padding: 0.6rem 1rem;
+ font-size: 0.9rem;
+ }
+}
+
+@media (max-width: 480px) {
+ .kanban-header h1 {
+ font-size: 1.5rem;
+ }
+
+ .kanban-container {
+ padding: 0 0.5rem;
+ gap: 0.5rem;
+ }
+
+ .kanban-column {
+ flex: 0 0 250px;
+ }
+
+ .header-actions {
+ flex-direction: column;
+ }
+
+ .btn {
+ width: 100%;
+ }
+}
diff --git a/js/kanban.js b/js/kanban.js
new file mode 100644
index 0000000..1d68dba
--- /dev/null
+++ b/js/kanban.js
@@ -0,0 +1,475 @@
+// ====================== KANBAN BOARD APP ======================
+// Single-Page Kanban Board mit Drag & Drop und localStorage Persistenz
+
+class KanbanBoard {
+ constructor() {
+ this.container = document.getElementById('kanbanContainer');
+ this.board = this.loadFromLocalStorage() || this.getDefaultBoard();
+ this.draggedCard = null;
+ this.draggedFromColumn = null;
+ this.colorPickerCard = null;
+
+ this.initializeEventListeners();
+ this.render();
+ }
+
+ /**
+ * Standard-Board mit 3 Spalten
+ */
+ getDefaultBoard() {
+ return {
+ columns: [
+ {
+ id: this.generateId(),
+ title: 'To Do',
+ cards: [
+ { id: this.generateId(), text: 'Beispiel Aufgabe 1', color: null },
+ { id: this.generateId(), text: 'Beispiel Aufgabe 2', color: null }
+ ]
+ },
+ {
+ id: this.generateId(),
+ title: 'In Arbeit',
+ cards: [
+ { id: this.generateId(), text: 'Aktuelle Aufgabe', color: null }
+ ]
+ },
+ {
+ id: this.generateId(),
+ title: 'Erledigt',
+ cards: [
+ { id: this.generateId(), text: 'Abgeschlossene Aufgabe', color: null }
+ ]
+ }
+ ]
+ };
+ }
+
+ /**
+ * Event Listener initialisieren
+ */
+ initializeEventListeners() {
+ document.getElementById('addColumnBtn').addEventListener('click', () => this.addColumn());
+ document.getElementById('exportBtn').addEventListener('click', () => this.exportAsJSON());
+ document.getElementById('importBtn').addEventListener('click', () => this.triggerImport());
+ document.getElementById('resetBtn').addEventListener('click', () => this.resetBoard());
+ document.getElementById('importFileInput').addEventListener('change', (e) => this.importFromJSON(e));
+
+ // Close color picker wenn außerhalb geklickt wird
+ document.addEventListener('click', (e) => {
+ if (!e.target.closest('.color-picker') && !e.target.closest('.kanban-card')) {
+ this.hideColorPicker();
+ }
+ });
+ }
+
+ /**
+ * Spalten und Karten rendern
+ */
+ render() {
+ this.container.innerHTML = '';
+
+ this.board.columns.forEach(column => {
+ const columnEl = document.createElement('div');
+ columnEl.className = 'kanban-column';
+ columnEl.id = `column-${column.id}`;
+ columnEl.draggable = false;
+
+ // Column Header
+ const headerEl = document.createElement('div');
+ headerEl.className = 'kanban-column-header';
+
+ const titleEl = document.createElement('h2');
+ titleEl.className = 'kanban-column-title';
+ titleEl.textContent = `${column.title} (${column.cards.length})`;
+
+ const deleteBtn = document.createElement('button');
+ deleteBtn.className = 'column-delete-btn';
+ deleteBtn.textContent = '✕';
+ deleteBtn.addEventListener('click', () => this.deleteColumn(column.id));
+
+ headerEl.appendChild(titleEl);
+ headerEl.appendChild(deleteBtn);
+
+ // Cards Container
+ const cardsEl = document.createElement('div');
+ cardsEl.className = 'kanban-cards';
+ cardsEl.id = `cards-${column.id}`;
+
+ // Drag & Drop Events für Spalte
+ cardsEl.addEventListener('dragover', (e) => this.handleDragOver(e, column.id));
+ cardsEl.addEventListener('dragleave', (e) => this.handleDragLeave(e, column.id));
+ cardsEl.addEventListener('drop', (e) => this.handleDrop(e, column.id));
+ cardsEl.addEventListener('dragenter', (e) => this.handleDragEnter(e, column.id));
+
+ // Karten rendern
+ column.cards.forEach(card => {
+ const cardEl = this.createCardElement(card, column.id);
+ cardsEl.appendChild(cardEl);
+ });
+
+ // Add Card Button
+ const addCardBtn = document.createElement('button');
+ addCardBtn.className = 'add-card-btn';
+ addCardBtn.textContent = '+ Neue Karte';
+ addCardBtn.addEventListener('click', () => this.addCard(column.id));
+
+ cardsEl.appendChild(addCardBtn);
+ columnEl.appendChild(headerEl);
+ columnEl.appendChild(cardsEl);
+ this.container.appendChild(columnEl);
+ });
+
+ this.save();
+ }
+
+ /**
+ * Karten-Element erstellen
+ */
+ createCardElement(card, columnId) {
+ const cardEl = document.createElement('div');
+ cardEl.className = 'kanban-card';
+ cardEl.id = `card-${card.id}`;
+ cardEl.draggable = true;
+
+ // Drag Events
+ cardEl.addEventListener('dragstart', (e) => this.handleDragStart(e, card, columnId));
+ cardEl.addEventListener('dragend', (e) => this.handleDragEnd(e));
+
+ // Card Content
+ const contentEl = document.createElement('div');
+ contentEl.className = 'card-content';
+
+ const textEl = document.createElement('p');
+ textEl.className = 'card-text';
+ textEl.textContent = card.text;
+ textEl.contentEditable = 'true';
+ textEl.addEventListener('blur', () => {
+ card.text = textEl.textContent;
+ this.save();
+ });
+
+ contentEl.appendChild(textEl);
+
+ // Label anzeigen, falls vorhanden
+ if (card.color) {
+ const labelEl = document.createElement('div');
+ labelEl.className = `card-label label-${card.color}`;
+ labelEl.textContent = this.getColorName(card.color);
+ contentEl.appendChild(labelEl);
+ }
+
+ // Rechtsklick für Farben (Bonus)
+ cardEl.addEventListener('contextmenu', (e) => {
+ e.preventDefault();
+ this.showColorPicker(e, card, columnId);
+ });
+
+ // Card Actions
+ const actionsEl = document.createElement('div');
+ actionsEl.className = 'card-actions';
+
+ const deleteBtn = document.createElement('button');
+ deleteBtn.className = 'card-delete-btn';
+ deleteBtn.textContent = '✕';
+ deleteBtn.addEventListener('click', () => this.deleteCard(columnId, card.id));
+
+ actionsEl.appendChild(deleteBtn);
+
+ cardEl.appendChild(contentEl);
+ cardEl.appendChild(actionsEl);
+
+ return cardEl;
+ }
+
+ /**
+ * Spalte hinzufügen
+ */
+ addColumn() {
+ const title = prompt('Spaltenname eingeben:');
+ if (!title || title.trim() === '') return;
+
+ const newColumn = {
+ id: this.generateId(),
+ title: title.trim(),
+ cards: []
+ };
+
+ this.board.columns.push(newColumn);
+ this.render();
+ }
+
+ /**
+ * Spalte löschen
+ */
+ deleteColumn(columnId) {
+ if (confirm('Spalte und alle Karten löschen?')) {
+ this.board.columns = this.board.columns.filter(col => col.id !== columnId);
+ this.render();
+ }
+ }
+
+ /**
+ * Karte hinzufügen
+ */
+ addCard(columnId) {
+ const column = this.board.columns.find(col => col.id === columnId);
+ if (!column) return;
+
+ const newCard = {
+ id: this.generateId(),
+ text: 'Neue Aufgabe...',
+ color: null
+ };
+
+ column.cards.push(newCard);
+ this.render();
+ }
+
+ /**
+ * Karte löschen
+ */
+ deleteCard(columnId, cardId) {
+ const column = this.board.columns.find(col => col.id === columnId);
+ if (!column) return;
+
+ column.cards = column.cards.filter(card => card.id !== cardId);
+ this.render();
+ }
+
+ /**
+ * ====================== DRAG & DROP ======================
+ */
+
+ handleDragStart(e, card, columnId) {
+ this.draggedCard = card;
+ this.draggedFromColumn = columnId;
+ const cardEl = document.getElementById(`card-${card.id}`);
+ cardEl.classList.add('dragging');
+ }
+
+ handleDragEnd(e) {
+ document.querySelectorAll('.kanban-card').forEach(card => {
+ card.classList.remove('dragging');
+ card.classList.remove('drag-over-card');
+ });
+ document.querySelectorAll('.kanban-column').forEach(col => {
+ col.classList.remove('drag-over');
+ });
+ }
+
+ handleDragOver(e, columnId) {
+ e.preventDefault();
+ e.dataTransfer.dropEffect = 'move';
+
+ const cardsContainer = document.getElementById(`cards-${columnId}`);
+ const afterElement = this.getDragAfterElement(cardsContainer, e.clientY);
+
+ if (afterElement == null) {
+ // Vor den Add Button einfügen
+ cardsContainer.insertBefore(this.draggedCard, cardsContainer.lastElementChild);
+ } else {
+ cardsContainer.insertBefore(this.draggedCard, afterElement);
+ }
+ }
+
+ handleDragEnter(e, columnId) {
+ const columnEl = document.getElementById(`column-${columnId}`);
+ columnEl.classList.add('drag-over');
+ }
+
+ handleDragLeave(e, columnId) {
+ const columnEl = document.getElementById(`column-${columnId}`);
+ const cardsEl = document.getElementById(`cards-${columnId}`);
+
+ // Nur entfernen wenn wirklich die Spalte verlassen wird
+ if (e.target === cardsEl || e.target.classList.contains('kanban-cards')) {
+ columnEl.classList.remove('drag-over');
+ }
+ }
+
+ handleDrop(e, columnId) {
+ e.preventDefault();
+
+ const columnEl = document.getElementById(`column-${columnId}`);
+ columnEl.classList.remove('drag-over');
+
+ if (!this.draggedCard) return;
+
+ // Alte Spalte aktualisieren
+ const oldColumn = this.board.columns.find(col => col.id === this.draggedFromColumn);
+ if (oldColumn) {
+ oldColumn.cards = oldColumn.cards.filter(card => card.id !== this.draggedCard.id);
+ }
+
+ // Neue Spalte aktualisieren
+ const newColumn = this.board.columns.find(col => col.id === columnId);
+ if (newColumn) {
+ // Prüfen ob die Karte bereits in der neuen Spalte ist (aus derselben Spalte kommend)
+ if (!newColumn.cards.find(card => card.id === this.draggedCard.id)) {
+ newColumn.cards.push(this.draggedCard);
+ }
+ }
+
+ this.draggedCard = null;
+ this.draggedFromColumn = null;
+ this.render();
+ }
+
+ /**
+ * Hilfsfunktion um Position des draggable Elements zu bestimmen
+ */
+ getDragAfterElement(container, y) {
+ const draggableElements = [...container.querySelectorAll('.kanban-card:not(.dragging)')];
+
+ return draggableElements.reduce((closest, child) => {
+ const box = child.getBoundingClientRect();
+ const offset = y - box.top - box.height / 2;
+
+ if (offset < 0 && offset > closest.offset) {
+ return { offset: offset, element: child };
+ } else {
+ return closest;
+ }
+ }, { offset: Number.NEGATIVE_INFINITY }).element;
+ }
+
+ /**
+ * ====================== FARBEN (BONUS) ======================
+ */
+
+ showColorPicker(e, card, columnId) {
+ this.hideColorPicker();
+
+ const picker = document.createElement('div');
+ picker.className = 'color-picker';
+ picker.style.left = e.clientX + 'px';
+ picker.style.top = e.clientY + 'px';
+ picker.id = 'colorPickerMenu';
+
+ const title = document.createElement('div');
+ title.className = 'color-picker-title';
+ title.textContent = 'Farbe wählen:';
+
+ const options = document.createElement('div');
+ options.className = 'color-options';
+
+ const colors = ['red', 'blue', 'yellow', 'green', 'purple'];
+ colors.forEach(color => {
+ const option = document.createElement('div');
+ option.className = `color-option label-${color}`;
+ if (card.color === color) option.classList.add('active');
+
+ option.addEventListener('click', () => {
+ card.color = card.color === color ? null : color;
+ const column = this.board.columns.find(col => col.id === columnId);
+ const cardToUpdate = column.cards.find(c => c.id === card.id);
+ if (cardToUpdate) cardToUpdate.color = card.color;
+ this.save();
+ this.render();
+ this.hideColorPicker();
+ });
+
+ options.appendChild(option);
+ });
+
+ picker.appendChild(title);
+ picker.appendChild(options);
+ document.body.appendChild(picker);
+ }
+
+ hideColorPicker() {
+ const picker = document.getElementById('colorPickerMenu');
+ if (picker) picker.remove();
+ }
+
+ getColorName(color) {
+ const names = {
+ 'red': '🔴',
+ 'blue': '🔵',
+ 'yellow': '🟡',
+ 'green': '🟢',
+ 'purple': '🟣'
+ };
+ return names[color] || '';
+ }
+
+ /**
+ * ====================== PERSISTENZ ======================
+ */
+
+ save() {
+ localStorage.setItem('kanbanBoard', JSON.stringify(this.board));
+ }
+
+ loadFromLocalStorage() {
+ const stored = localStorage.getItem('kanbanBoard');
+ return stored ? JSON.parse(stored) : null;
+ }
+
+ /**
+ * ====================== EXPORT/IMPORT ======================
+ */
+
+ exportAsJSON() {
+ const dataStr = JSON.stringify(this.board, null, 2);
+ const blob = new Blob([dataStr], { type: 'application/json' });
+ const url = URL.createObjectURL(blob);
+
+ const link = document.createElement('a');
+ link.href = url;
+ link.download = `kanban-board-${new Date().toISOString().split('T')[0]}.json`;
+ document.body.appendChild(link);
+ link.click();
+ document.body.removeChild(link);
+ URL.revokeObjectURL(url);
+ }
+
+ triggerImport() {
+ document.getElementById('importFileInput').click();
+ }
+
+ importFromJSON(e) {
+ const file = e.target.files[0];
+ if (!file) return;
+
+ const reader = new FileReader();
+ reader.onload = (event) => {
+ try {
+ const imported = JSON.parse(event.target.result);
+ if (imported.columns && Array.isArray(imported.columns)) {
+ this.board = imported;
+ this.save();
+ this.render();
+ alert('Board erfolgreich importiert!');
+ } else {
+ alert('Ungültiges JSON-Format!');
+ }
+ } catch (error) {
+ alert('Fehler beim Import: ' + error.message);
+ }
+ };
+ reader.readAsText(file);
+ }
+
+ resetBoard() {
+ if (confirm('Möchtest du das Board wirklich zurücksetzen?')) {
+ this.board = this.getDefaultBoard();
+ this.save();
+ this.render();
+ }
+ }
+
+ /**
+ * Utility: Eindeutige ID generieren
+ */
+ generateId() {
+ return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
+ }
+}
+
+// ====================== APP STARTEN ======================
+
+document.addEventListener('DOMContentLoaded', () => {
+ new KanbanBoard();
+});
diff --git a/kanban.html b/kanban.html
new file mode 100644
index 0000000..04f02f2
--- /dev/null
+++ b/kanban.html
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+ Kanban Board - EIS Projekt
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+