Spaces:
Running
Running
Promote version 4e9dea2 to main
Browse filesPromoted commit 4e9dea2414107edb6f5eff48279f88ea9f8aaf7e to main branch
- components/task-item.js +25 -20
- index.html +10 -11
- script.js +16 -30
components/task-item.js
CHANGED
|
@@ -218,12 +218,12 @@ class TaskItem extends HTMLElement {
|
|
| 218 |
</style>
|
| 219 |
<div class="task-header">
|
| 220 |
<input type="checkbox" class="task-checkbox" ${this.completed ? 'checked' : ''}>
|
| 221 |
-
|
| 222 |
<div class="task-actions">
|
| 223 |
<button class="focus-btn" title="Pomodoro starten">
|
| 224 |
<i data-feather="clock"></i>
|
| 225 |
</button>
|
| 226 |
-
|
| 227 |
<i data-feather="edit-2"></i>
|
| 228 |
</button>
|
| 229 |
<button class="task-action" title="Löschen">
|
|
@@ -231,7 +231,8 @@ class TaskItem extends HTMLElement {
|
|
| 231 |
</button>
|
| 232 |
</div>
|
| 233 |
</div>
|
| 234 |
-
|
|
|
|
| 235 |
<span class="time-info">${formatTime(spentTime)} / ${formatTime(estimatedTime)}</span>
|
| 236 |
<div class="tags">${tagElements}</div>
|
| 237 |
</div>
|
|
@@ -269,26 +270,30 @@ class TaskItem extends HTMLElement {
|
|
| 269 |
icon.outerHTML = feather.icons[iconName].toSvg({ width: 16, height: 16 });
|
| 270 |
});
|
| 271 |
}
|
|
|
|
| 272 |
setupEventListeners() {
|
| 273 |
-
|
| 274 |
-
|
| 275 |
-
|
| 276 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 277 |
|
| 278 |
-
|
| 279 |
-
|
| 280 |
-
|
| 281 |
-
|
| 282 |
-
|
| 283 |
-
}
|
| 284 |
-
if (deleteBtn) {
|
| 285 |
-
deleteBtn.addEventListener('click', (e) => this.handleDelete(e));
|
| 286 |
-
}
|
| 287 |
-
if (checkbox) {
|
| 288 |
-
checkbox.addEventListener('change', (e) => this.handleToggleComplete(e));
|
| 289 |
-
}
|
| 290 |
}
|
| 291 |
-
|
|
|
|
| 292 |
const completed = e.target.checked;
|
| 293 |
this.dispatchEvent(new CustomEvent('toggle-complete', {
|
| 294 |
detail: { taskId: this.getAttribute('task-id'), completed },
|
|
|
|
| 218 |
</style>
|
| 219 |
<div class="task-header">
|
| 220 |
<input type="checkbox" class="task-checkbox" ${this.completed ? 'checked' : ''}>
|
| 221 |
+
<span class="task-title">${title}</span>
|
| 222 |
<div class="task-actions">
|
| 223 |
<button class="focus-btn" title="Pomodoro starten">
|
| 224 |
<i data-feather="clock"></i>
|
| 225 |
</button>
|
| 226 |
+
<button class="task-action" title="Bearbeiten">
|
| 227 |
<i data-feather="edit-2"></i>
|
| 228 |
</button>
|
| 229 |
<button class="task-action" title="Löschen">
|
|
|
|
| 231 |
</button>
|
| 232 |
</div>
|
| 233 |
</div>
|
| 234 |
+
|
| 235 |
+
<div class="task-info">
|
| 236 |
<span class="time-info">${formatTime(spentTime)} / ${formatTime(estimatedTime)}</span>
|
| 237 |
<div class="tags">${tagElements}</div>
|
| 238 |
</div>
|
|
|
|
| 270 |
icon.outerHTML = feather.icons[iconName].toSvg({ width: 16, height: 16 });
|
| 271 |
});
|
| 272 |
}
|
| 273 |
+
|
| 274 |
setupEventListeners() {
|
| 275 |
+
this.shadowRoot.addEventListener('click', (e) => {
|
| 276 |
+
const target = e.target.closest('button');
|
| 277 |
+
if (target) {
|
| 278 |
+
const action = target.getAttribute('title');
|
| 279 |
+
if (action === 'Bearbeiten') {
|
| 280 |
+
this.handleEdit(e);
|
| 281 |
+
} else if (action === 'Löschen') {
|
| 282 |
+
this.handleDelete(e);
|
| 283 |
+
} else if (action === 'Pomodoro starten') {
|
| 284 |
+
this.handleFocus(e);
|
| 285 |
+
}
|
| 286 |
+
}
|
| 287 |
+
});
|
| 288 |
|
| 289 |
+
this.shadowRoot.addEventListener('change', (e) => {
|
| 290 |
+
if (e.target.classList.contains('task-checkbox')) {
|
| 291 |
+
this.handleToggleComplete(e);
|
| 292 |
+
}
|
| 293 |
+
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 294 |
}
|
| 295 |
+
|
| 296 |
+
handleToggleComplete(e) {
|
| 297 |
const completed = e.target.checked;
|
| 298 |
this.dispatchEvent(new CustomEvent('toggle-complete', {
|
| 299 |
detail: { taskId: this.getAttribute('task-id'), completed },
|
index.html
CHANGED
|
@@ -6,6 +6,7 @@
|
|
| 6 |
<title>TaskForge Pro</title>
|
| 7 |
<link rel="stylesheet" href="style.css">
|
| 8 |
<script src="https://cdn.tailwindcss.com"></script>
|
|
|
|
| 9 |
<script src="https://unpkg.com/feather-icons"></script>
|
| 10 |
</head>
|
| 11 |
<body class="bg-gray-900 text-gray-100 min-h-screen">
|
|
@@ -15,14 +16,14 @@
|
|
| 15 |
<div class="flex items-center justify-between">
|
| 16 |
<h1 class="text-2xl font-bold text-orange-500">TaskForge Pro</h1>
|
| 17 |
<nav class="flex items-center space-x-4">
|
| 18 |
-
<
|
| 19 |
<i data-feather="home"></i> Übersicht
|
| 20 |
-
</
|
| 21 |
-
<
|
| 22 |
<i data-feather="settings"></i> Einstellungen
|
| 23 |
-
</
|
| 24 |
</nav>
|
| 25 |
-
</div>
|
| 26 |
</div>
|
| 27 |
</header>
|
| 28 |
<!-- Main Content -->
|
|
@@ -192,20 +193,18 @@
|
|
| 192 |
<!-- FAB Buttons -->
|
| 193 |
<div class="fixed bottom-6 right-6 flex flex-col space-y-3">
|
| 194 |
<button id="focus-fab" class="p-4 bg-orange-500 hover:bg-orange-600 rounded-full shadow-lg transition transform hover:scale-110">
|
| 195 |
-
<i data-feather="
|
| 196 |
</button>
|
| 197 |
<button id="add-task-fab" class="p-4 bg-emerald-500 hover:bg-emerald-600 rounded-full shadow-lg transition transform hover:scale-110">
|
| 198 |
<i data-feather="plus"></i>
|
| 199 |
</button>
|
| 200 |
</div>
|
|
|
|
| 201 |
<script src="components/task-item.js"></script>
|
| 202 |
<script src="components/tag-item.js"></script>
|
|
|
|
| 203 |
<script src="script.js"></script>
|
| 204 |
-
<script>
|
| 205 |
-
document.addEventListener('DOMContentLoaded', function() {
|
| 206 |
-
feather.replace();
|
| 207 |
-
});
|
| 208 |
-
</script>
|
| 209 |
<script src="https://huggingface.co/deepsite/deepsite-badge.js"></script>
|
| 210 |
</body>
|
| 211 |
</html>
|
|
|
|
| 6 |
<title>TaskForge Pro</title>
|
| 7 |
<link rel="stylesheet" href="style.css">
|
| 8 |
<script src="https://cdn.tailwindcss.com"></script>
|
| 9 |
+
<script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>
|
| 10 |
<script src="https://unpkg.com/feather-icons"></script>
|
| 11 |
</head>
|
| 12 |
<body class="bg-gray-900 text-gray-100 min-h-screen">
|
|
|
|
| 16 |
<div class="flex items-center justify-between">
|
| 17 |
<h1 class="text-2xl font-bold text-orange-500">TaskForge Pro</h1>
|
| 18 |
<nav class="flex items-center space-x-4">
|
| 19 |
+
<button id="view-home" class="nav-btn active" data-view="home">
|
| 20 |
<i data-feather="home"></i> Übersicht
|
| 21 |
+
</button>
|
| 22 |
+
<button id="view-settings" class="nav-btn" data-view="settings">
|
| 23 |
<i data-feather="settings"></i> Einstellungen
|
| 24 |
+
</button>
|
| 25 |
</nav>
|
| 26 |
+
</div>
|
| 27 |
</div>
|
| 28 |
</header>
|
| 29 |
<!-- Main Content -->
|
|
|
|
| 193 |
<!-- FAB Buttons -->
|
| 194 |
<div class="fixed bottom-6 right-6 flex flex-col space-y-3">
|
| 195 |
<button id="focus-fab" class="p-4 bg-orange-500 hover:bg-orange-600 rounded-full shadow-lg transition transform hover:scale-110">
|
| 196 |
+
<i data-feather="focus"></i>
|
| 197 |
</button>
|
| 198 |
<button id="add-task-fab" class="p-4 bg-emerald-500 hover:bg-emerald-600 rounded-full shadow-lg transition transform hover:scale-110">
|
| 199 |
<i data-feather="plus"></i>
|
| 200 |
</button>
|
| 201 |
</div>
|
| 202 |
+
<timeline-sidebar id="timeline-sidebar"></timeline-sidebar>
|
| 203 |
<script src="components/task-item.js"></script>
|
| 204 |
<script src="components/tag-item.js"></script>
|
| 205 |
+
<script src="components/timeline-tasks.js"></script>
|
| 206 |
<script src="script.js"></script>
|
| 207 |
+
<script>feather.replace();</script>
|
|
|
|
|
|
|
|
|
|
|
|
|
| 208 |
<script src="https://huggingface.co/deepsite/deepsite-badge.js"></script>
|
| 209 |
</body>
|
| 210 |
</html>
|
script.js
CHANGED
|
@@ -21,7 +21,6 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
| 21 |
initializeUI();
|
| 22 |
setupEventListeners();
|
| 23 |
render();
|
| 24 |
-
feather.replace();
|
| 25 |
});
|
| 26 |
// Local Storage
|
| 27 |
function loadFromLocalStorage() {
|
|
@@ -83,20 +82,22 @@ function updateCurrentTime() {
|
|
| 83 |
document.getElementById('current-time').textContent = timeString;
|
| 84 |
}
|
| 85 |
function setupEventListeners() {
|
| 86 |
-
// Navigation
|
| 87 |
document.querySelectorAll('.nav-btn').forEach(btn => {
|
| 88 |
btn.addEventListener('click', (e) => {
|
| 89 |
-
e.preventDefault();
|
| 90 |
const view = e.currentTarget.dataset.view;
|
| 91 |
switchView(view);
|
| 92 |
});
|
| 93 |
});
|
| 94 |
-
|
|
|
|
| 95 |
document.getElementById('add-task-fab').addEventListener('click', openAddTaskModal);
|
| 96 |
document.getElementById('focus-fab').addEventListener('click', enterFocusMode);
|
|
|
|
| 97 |
// Add task modal
|
| 98 |
document.getElementById('add-task-form').addEventListener('submit', handleAddTask);
|
| 99 |
document.getElementById('cancel-task').addEventListener('click', closeAddTaskModal);
|
|
|
|
| 100 |
// Settings
|
| 101 |
document.getElementById('import-btn').addEventListener('click', handleImport);
|
| 102 |
document.getElementById('export-btn').addEventListener('click', handleExport);
|
|
@@ -104,11 +105,13 @@ function setupEventListeners() {
|
|
| 104 |
|
| 105 |
document.getElementById('pomodoro-work').addEventListener('change', savePomodoroSettings);
|
| 106 |
document.getElementById('pomodoro-break').addEventListener('change', savePomodoroSettings);
|
|
|
|
| 107 |
// Focus mode
|
| 108 |
document.getElementById('focus-pause').addEventListener('click', pausePomodoro);
|
| 109 |
document.getElementById('focus-play').addEventListener('click', resumePomodoro);
|
| 110 |
document.getElementById('focus-stop').addEventListener('click', stopPomodoro);
|
| 111 |
-
|
|
|
|
| 112 |
document.addEventListener('delete-task', (e) => {
|
| 113 |
deleteTask(e.detail.taskId);
|
| 114 |
});
|
|
@@ -124,7 +127,8 @@ function setupEventListeners() {
|
|
| 124 |
document.addEventListener('add-time', (e) => {
|
| 125 |
addTimeToTask(e.detail.taskId, e.detail.minutes);
|
| 126 |
});
|
| 127 |
-
|
|
|
|
| 128 |
const timelineSidebar = document.getElementById('timeline-sidebar');
|
| 129 |
if (timelineSidebar) {
|
| 130 |
timelineSidebar.addEventListener('task-dropped', (e) => {
|
|
@@ -208,6 +212,7 @@ function closeAddTaskModal() {
|
|
| 208 |
modal.classList.add('hidden');
|
| 209 |
document.getElementById('add-task-form').reset();
|
| 210 |
}
|
|
|
|
| 211 |
function handleAddTask(e) {
|
| 212 |
e.preventDefault();
|
| 213 |
|
|
@@ -226,6 +231,7 @@ function handleAddTask(e) {
|
|
| 226 |
|
| 227 |
closeAddTaskModal();
|
| 228 |
}
|
|
|
|
| 229 |
function renderModalTags() {
|
| 230 |
const container = document.getElementById('modal-tags-list');
|
| 231 |
container.innerHTML = state.tags.map(tag => `
|
|
@@ -394,9 +400,6 @@ function renderTasks() {
|
|
| 394 |
|
| 395 |
// Replace feather icons
|
| 396 |
feather.replace();
|
| 397 |
-
|
| 398 |
-
// Re-attach event listeners to task items after render
|
| 399 |
-
reattachTaskEventListeners();
|
| 400 |
}
|
| 401 |
function renderProgressBars() {
|
| 402 |
// Overall progress
|
|
@@ -649,8 +652,8 @@ function savePomodoroSettings() {
|
|
| 649 |
function initializeTimeline() {
|
| 650 |
// Setup drag start for task items
|
| 651 |
document.addEventListener('dragstart', (e) => {
|
| 652 |
-
|
| 653 |
-
|
| 654 |
e.dataTransfer.setData('text/plain', taskId);
|
| 655 |
}
|
| 656 |
});
|
|
@@ -711,10 +714,12 @@ function formatTime(minutes) {
|
|
| 711 |
const m = minutes % 60;
|
| 712 |
return `${h}h${m > 0 ? ` ${m}m` : ''}`;
|
| 713 |
}
|
|
|
|
| 714 |
// Request notification permission
|
| 715 |
if ('Notification' in window && Notification.permission === 'default') {
|
| 716 |
Notification.requestPermission();
|
| 717 |
}
|
|
|
|
| 718 |
// New functions for task management
|
| 719 |
function addTimeToTask(taskId, minutes) {
|
| 720 |
const task = state.tasks.find(t => t.id === taskId);
|
|
@@ -725,9 +730,6 @@ function addTimeToTask(taskId, minutes) {
|
|
| 725 |
}
|
| 726 |
}
|
| 727 |
|
| 728 |
-
// Fix missing global functions
|
| 729 |
-
window.startFocusModeWithId = startFocusModeWithId;
|
| 730 |
-
window.formatTime = formatTime;
|
| 731 |
function setupTaskDragAndDrop() {
|
| 732 |
const openContainer = document.getElementById('open-tasks');
|
| 733 |
const completedContainer = document.getElementById('completed-tasks');
|
|
@@ -750,22 +752,6 @@ function setupTaskDragAndDrop() {
|
|
| 750 |
});
|
| 751 |
}
|
| 752 |
|
| 753 |
-
function reattachTaskEventListeners() {
|
| 754 |
-
document.querySelectorAll('task-item').forEach(taskEl => {
|
| 755 |
-
// Remove existing listeners and re-add
|
| 756 |
-
const taskId = taskEl.getAttribute('task-id');
|
| 757 |
-
|
| 758 |
-
// Add event listeners for checkbox toggle
|
| 759 |
-
const checkbox = taskEl.shadowRoot?.querySelector('.task-checkbox');
|
| 760 |
-
if (checkbox) {
|
| 761 |
-
checkbox.addEventListener('change', (e) => {
|
| 762 |
-
const completed = e.target.checked;
|
| 763 |
-
toggleTaskComplete(taskId, completed);
|
| 764 |
-
});
|
| 765 |
-
|
| 766 |
-
}
|
| 767 |
-
});
|
| 768 |
-
}
|
| 769 |
function getDragAfterElement(container, y) {
|
| 770 |
const draggableElements = [...container.querySelectorAll('task-item:not(.dragging)'));
|
| 771 |
|
|
|
|
| 21 |
initializeUI();
|
| 22 |
setupEventListeners();
|
| 23 |
render();
|
|
|
|
| 24 |
});
|
| 25 |
// Local Storage
|
| 26 |
function loadFromLocalStorage() {
|
|
|
|
| 82 |
document.getElementById('current-time').textContent = timeString;
|
| 83 |
}
|
| 84 |
function setupEventListeners() {
|
| 85 |
+
// Navigation
|
| 86 |
document.querySelectorAll('.nav-btn').forEach(btn => {
|
| 87 |
btn.addEventListener('click', (e) => {
|
|
|
|
| 88 |
const view = e.currentTarget.dataset.view;
|
| 89 |
switchView(view);
|
| 90 |
});
|
| 91 |
});
|
| 92 |
+
|
| 93 |
+
// FAB buttons
|
| 94 |
document.getElementById('add-task-fab').addEventListener('click', openAddTaskModal);
|
| 95 |
document.getElementById('focus-fab').addEventListener('click', enterFocusMode);
|
| 96 |
+
|
| 97 |
// Add task modal
|
| 98 |
document.getElementById('add-task-form').addEventListener('submit', handleAddTask);
|
| 99 |
document.getElementById('cancel-task').addEventListener('click', closeAddTaskModal);
|
| 100 |
+
|
| 101 |
// Settings
|
| 102 |
document.getElementById('import-btn').addEventListener('click', handleImport);
|
| 103 |
document.getElementById('export-btn').addEventListener('click', handleExport);
|
|
|
|
| 105 |
|
| 106 |
document.getElementById('pomodoro-work').addEventListener('change', savePomodoroSettings);
|
| 107 |
document.getElementById('pomodoro-break').addEventListener('change', savePomodoroSettings);
|
| 108 |
+
|
| 109 |
// Focus mode
|
| 110 |
document.getElementById('focus-pause').addEventListener('click', pausePomodoro);
|
| 111 |
document.getElementById('focus-play').addEventListener('click', resumePomodoro);
|
| 112 |
document.getElementById('focus-stop').addEventListener('click', stopPomodoro);
|
| 113 |
+
|
| 114 |
+
// Event delegation for task item events
|
| 115 |
document.addEventListener('delete-task', (e) => {
|
| 116 |
deleteTask(e.detail.taskId);
|
| 117 |
});
|
|
|
|
| 127 |
document.addEventListener('add-time', (e) => {
|
| 128 |
addTimeToTask(e.detail.taskId, e.detail.minutes);
|
| 129 |
});
|
| 130 |
+
|
| 131 |
+
// Timeline sidebar events
|
| 132 |
const timelineSidebar = document.getElementById('timeline-sidebar');
|
| 133 |
if (timelineSidebar) {
|
| 134 |
timelineSidebar.addEventListener('task-dropped', (e) => {
|
|
|
|
| 212 |
modal.classList.add('hidden');
|
| 213 |
document.getElementById('add-task-form').reset();
|
| 214 |
}
|
| 215 |
+
|
| 216 |
function handleAddTask(e) {
|
| 217 |
e.preventDefault();
|
| 218 |
|
|
|
|
| 231 |
|
| 232 |
closeAddTaskModal();
|
| 233 |
}
|
| 234 |
+
|
| 235 |
function renderModalTags() {
|
| 236 |
const container = document.getElementById('modal-tags-list');
|
| 237 |
container.innerHTML = state.tags.map(tag => `
|
|
|
|
| 400 |
|
| 401 |
// Replace feather icons
|
| 402 |
feather.replace();
|
|
|
|
|
|
|
|
|
|
| 403 |
}
|
| 404 |
function renderProgressBars() {
|
| 405 |
// Overall progress
|
|
|
|
| 652 |
function initializeTimeline() {
|
| 653 |
// Setup drag start for task items
|
| 654 |
document.addEventListener('dragstart', (e) => {
|
| 655 |
+
if (e.target.tagName === 'TASK-ITEM') {
|
| 656 |
+
const taskId = e.target.getAttribute('task-id');
|
| 657 |
e.dataTransfer.setData('text/plain', taskId);
|
| 658 |
}
|
| 659 |
});
|
|
|
|
| 714 |
const m = minutes % 60;
|
| 715 |
return `${h}h${m > 0 ? ` ${m}m` : ''}`;
|
| 716 |
}
|
| 717 |
+
|
| 718 |
// Request notification permission
|
| 719 |
if ('Notification' in window && Notification.permission === 'default') {
|
| 720 |
Notification.requestPermission();
|
| 721 |
}
|
| 722 |
+
|
| 723 |
// New functions for task management
|
| 724 |
function addTimeToTask(taskId, minutes) {
|
| 725 |
const task = state.tasks.find(t => t.id === taskId);
|
|
|
|
| 730 |
}
|
| 731 |
}
|
| 732 |
|
|
|
|
|
|
|
|
|
|
| 733 |
function setupTaskDragAndDrop() {
|
| 734 |
const openContainer = document.getElementById('open-tasks');
|
| 735 |
const completedContainer = document.getElementById('completed-tasks');
|
|
|
|
| 752 |
});
|
| 753 |
}
|
| 754 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 755 |
function getDragAfterElement(container, y) {
|
| 756 |
const draggableElements = [...container.querySelectorAll('task-item:not(.dragging)'));
|
| 757 |
|