// 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 = `
${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);