// Task Item Component class TaskItem extends HTMLElement { constructor() { super(); this.attachShadow({ mode: 'open' }); } connectedCallback() { this.taskId = this.getAttribute('task-id'); this.completed = this.getAttribute('completed') === 'true'; this.loadTaskData(); this.render(); this.setupEventListeners(); } static get observedAttributes() { return ['task-id', 'completed']; } attributeChangedCallback(name, oldValue, newValue) { if (name === 'task-id' && oldValue !== newValue) { this.taskId = newValue; this.loadTaskData(); } else if (name === 'completed') { this.completed = newValue === 'true'; } this.render(); } loadTaskData() { if (!window.state || !window.state.tasks) return; this.task = window.state.tasks.find(t => t.id === this.taskId); this.tags = window.state.tags || []; } render() { if (!this.task) { this.shadowRoot.innerHTML = `
Lädt...
`; return; } const { title, estimatedTime, spentTime, tags } = this.task; const progress = estimatedTime > 0 ? (spentTime / estimatedTime) * 100 : 0; const tagElements = (tags || []).map(tagId => { const tag = this.tags?.find(t => t.id === tagId); return tag ? `${tag.name}` : ''; }).join(''); this.shadowRoot.innerHTML = `
${title}
${formatTime(spentTime)} / ${formatTime(estimatedTime)}
${tagElements}
`; if (this.completed) { this.classList.add('completed'); } else { this.classList.remove('completed'); } // Replace feather icons this.shadowRoot.querySelectorAll('i[data-feather]').forEach(icon => { const iconName = icon.getAttribute('data-feather'); icon.outerHTML = feather.icons[iconName].toSvg({ width: 16, height: 16 }); }); } setupEventListeners() { this.shadowRoot.addEventListener('click', (e) => { const action = e.target.closest('button')?.getAttribute('@click'); if (action) { e.stopPropagation(); this[action.replace('${this.', '').replace('}', '')](e); } }); this.shadowRoot.addEventListener('change', (e) => { if (e.target.classList.contains('task-checkbox')) { e.stopPropagation(); this.handleToggleComplete(e); } }); } handleToggleComplete(e) { const completed = e.target.checked; this.dispatchEvent(new CustomEvent('toggle-complete', { detail: { taskId: this.getAttribute('task-id'), completed }, bubbles: true })); if (completed) { this.classList.add('completed'); } else { this.classList.remove('completed'); } } handleFocus(e) { const taskId = this.getAttribute('task-id'); const task = state.tasks.find(t => t.id === taskId); if (task) { startFocusMode(task); } } handleEdit(e) { const editForm = this.shadowRoot.querySelector('.edit-form'); editForm.classList.add('active'); } handleDelete(e) { if (confirm('Aufgabe wirklich löschen?')) { this.dispatchEvent(new CustomEvent('delete-task', { detail: { taskId: this.getAttribute('task-id') }, bubbles: true })); } } handleSave(e) { const taskId = this.getAttribute('task-id'); const title = this.shadowRoot.getElementById(`edit-title-${taskId}`).value; const hours = parseInt(this.shadowRoot.getElementById(`edit-hours-${taskId}`).value) || 0; const minutes = parseInt(this.shadowRoot.getElementById(`edit-minutes-${taskId}`).value) || 0; const estimatedTime = hours * 60 + minutes; this.dispatchEvent(new CustomEvent('update-task', { detail: { taskId, updates: { title, estimatedTime } }, bubbles: true })); } handleCancel(e) { const editForm = this.shadowRoot.querySelector('.edit-form'); editForm.classList.remove('active'); } handleAddTime(e) { const minutes = prompt('Wie viele Minuten willst du hinzufügen?', '15'); if (minutes && !isNaN(minutes)) { this.dispatchEvent(new CustomEvent('add-time', { detail: { taskId: this.getAttribute('task-id'), minutes: parseInt(minutes) }, bubbles: true })); } } } customElements.define('task-item', TaskItem);