From 110fa39da5a750b3193440877c6ec77a58444e94 Mon Sep 17 00:00:00 2001 From: Echo Date: Mon, 2 Feb 2026 10:45:03 +0000 Subject: [PATCH] Update dashboard, root (+1 ~2) --- TOOLS.md | 2 +- dashboard/index.html | 256 ++++++++++++++++++++++++++++++++++++++++++- dashboard/todos.json | 15 +++ 3 files changed, 271 insertions(+), 2 deletions(-) create mode 100644 dashboard/todos.json diff --git a/TOOLS.md b/TOOLS.md index e3e2913..2b107cc 100644 --- a/TOOLS.md +++ b/TOOLS.md @@ -114,7 +114,7 @@ memory_get path="memory/file.md" from=1 lines=50 | 15:00 3/feb | 17:00 | grup-sprijin-pregatire | #echo-sprijin | Pregătire fișă grup joi | | 15:00 5/feb | 17:00 | grup-sprijin-5feb | #echo-sprijin | Reminder grup sprijin | | 18:00 | 20:00 | evening-report | 📧 EMAIL | Raport seară HTML + TOATE propunerile cu context | -| 19:00 | 21:00 | evening-coaching | #echo-self | Reflecție seară → memory/kb/coaching/ | +| 19:00 | 21:00 | evening-coaching | #echo-self + 📧 | Reflecție seară → memory/kb/coaching/ | | 20:00 | 22:00 | seara-merit-reminder | #echo-self | Reminder lista "10 lucruri pentru care merit respect" | | 19:00 dum | 21:00 | weekly-planning | #echo-work | Planning săptămânal | | 21:00 | 23:00 | night-execute | #echo-work | Execută task-uri aprobate (run 1) | diff --git a/dashboard/index.html b/dashboard/index.html index 778d91c..f0c15ef 100644 --- a/dashboard/index.html +++ b/dashboard/index.html @@ -706,6 +706,71 @@ .issue-owner.marius { color: #22c55e; } .issue-owner.robert { color: #f59e0b; } + + /* Todo's Panel */ + .todos-panel { border-left: 3px solid #8b5cf6; } + .todo-section { margin-bottom: 16px; } + .todo-section-title { + font-size: 12px; + font-weight: 600; + color: #9ca3af; + margin-bottom: 8px; + display: flex; + align-items: center; + gap: 6px; + } + .todo-section-title.overdue { color: #ef4444; } + .todo-item { + display: flex; + align-items: flex-start; + gap: 12px; + padding: 10px 12px; + background: #1f2937; + border-radius: 6px; + margin-bottom: 6px; + transition: all 0.2s; + } + .todo-item:hover { background: #374151; } + .todo-item.done { opacity: 0.6; } + .todo-item.done .todo-text { text-decoration: line-through; } + .todo-checkbox { + width: 20px; + height: 20px; + border: 2px solid #6b7280; + border-radius: 4px; + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + flex-shrink: 0; + transition: all 0.2s; + } + .todo-checkbox:hover { border-color: #8b5cf6; } + .todo-checkbox.checked { + background: #8b5cf6; + border-color: #8b5cf6; + } + .todo-checkbox svg { display: none; width: 14px; height: 14px; color: white; } + .todo-checkbox.checked svg { display: block; } + .todo-content { flex: 1; min-width: 0; } + .todo-text { font-size: 14px; color: #f3f4f6; margin-bottom: 4px; } + .todo-meta { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; } + .todo-domain { + font-size: 11px; + padding: 2px 8px; + border-radius: 4px; + font-weight: 500; + } + .todo-domain.work { background: #1e40af; color: #93c5fd; } + .todo-domain.self { background: #6b21a8; color: #d8b4fe; } + .todo-domain.sprijin { background: #166534; color: #86efac; } + .todo-domain.scout { background: #c2410c; color: #fdba74; } + .todo-due { + font-size: 11px; + color: #9ca3af; + } + .todo-due.overdue { color: #ef4444; font-weight: 500; } + .todo-source { font-size: 11px; color: #6b7280; } .issue-owner.clawdbot { color: #8b5cf6; } .issue-date { @@ -978,6 +1043,32 @@ + +
+
+
+ +
+ + Todo's +
+ 0 +
+
+ +
+
+
+
+ +

Se încarcă...

+
+
+
+
@@ -1380,6 +1471,168 @@ }); // Load data + // ===== TODO'S ===== + let todosData = { items: [] }; + + async function loadTodos() { + try { + const response = await fetch('todos.json?' + Date.now()); + if (response.ok) { + todosData = await response.json(); + renderTodos(); + } + } catch (error) { + console.error('Error loading todos:', error); + } + } + + function renderTodos() { + const container = document.getElementById('todosBody'); + const today = new Date().toISOString().split('T')[0]; + const tomorrow = new Date(Date.now() + 86400000).toISOString().split('T')[0]; + + // Group by status + const todayItems = todosData.items.filter(t => !t.done && t.dueDate === today); + const tomorrowItems = todosData.items.filter(t => !t.done && t.dueDate === tomorrow); + const overdueItems = todosData.items.filter(t => !t.done && t.dueDate < today); + const futureItems = todosData.items.filter(t => !t.done && t.dueDate > tomorrow); + const doneToday = todosData.items.filter(t => t.done && t.doneAt && t.doneAt.startsWith(today)); + + // Update count + const activeCount = todosData.items.filter(t => !t.done).length; + document.getElementById('todosCount').textContent = activeCount; + + let html = ''; + + if (overdueItems.length > 0) { + html += '
⚠️ RESTANTE
'; + html += overdueItems.map(t => renderTodoItem(t)).join(''); + html += '
'; + } + + if (todayItems.length > 0) { + html += '
📅 AZI
'; + html += todayItems.map(t => renderTodoItem(t)).join(''); + html += '
'; + } + + if (tomorrowItems.length > 0) { + html += '
📅 MÂINE
'; + html += tomorrowItems.map(t => renderTodoItem(t)).join(''); + html += '
'; + } + + if (futureItems.length > 0) { + html += '
📆 VIITOR
'; + html += futureItems.map(t => renderTodoItem(t)).join(''); + html += '
'; + } + + if (doneToday.length > 0) { + html += '
✅ COMPLETATE AZI
'; + html += doneToday.map(t => renderTodoItem(t)).join(''); + html += '
'; + } + + if (html === '') { + html = '

Niciun todo activ

'; + } + + container.innerHTML = html; + lucide.createIcons(); + } + + function renderTodoItem(todo) { + const isOverdue = !todo.done && todo.dueDate < new Date().toISOString().split('T')[0]; + return ` +
+
+ +
+
+
${todo.text}
+
+ @${todo.domain} + ${todo.dueDate ? `${formatDate(todo.dueDate)}` : ''} + ${todo.source ? `${todo.source}` : ''} +
+
+
+ `; + } + + function formatDate(dateStr) { + const date = new Date(dateStr); + const today = new Date(); + const tomorrow = new Date(Date.now() + 86400000); + + if (dateStr === today.toISOString().split('T')[0]) return 'Azi'; + if (dateStr === tomorrow.toISOString().split('T')[0]) return 'Mâine'; + + return date.toLocaleDateString('ro-RO', { day: 'numeric', month: 'short' }); + } + + async function toggleTodo(id) { + const todo = todosData.items.find(t => t.id === id); + if (todo) { + todo.done = !todo.done; + todo.doneAt = todo.done ? new Date().toISOString() : null; + await saveTodos(); + renderTodos(); + } + } + + async function saveTodos() { + todosData.lastUpdated = new Date().toISOString(); + try { + const response = await fetch('/echo/api/files', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + path: 'dashboard/todos.json', + content: JSON.stringify(todosData, null, 2) + }) + }); + if (!response.ok) throw new Error('Save failed'); + } catch (error) { + showToast('Eroare la salvare', 'error'); + } + } + + function showAddTodoModal() { + const text = prompt('Todo (ex: @work Verifică client X)'); + if (text && text.trim()) { + addTodo(text.trim()); + } + } + + async function addTodo(text) { + // Parse domain from text (@work, @self, @sprijin, @scout) + let domain = 'work'; + const domainMatch = text.match(/@(work|self|sprijin|scout)/i); + if (domainMatch) { + domain = domainMatch[1].toLowerCase(); + text = text.replace(/@(work|self|sprijin|scout)/i, '').trim(); + } + + const todo = { + id: 'todo-' + Date.now(), + text: text, + domain: domain, + dueDate: new Date().toISOString().split('T')[0], + done: false, + doneAt: null, + source: 'manual', + createdAt: new Date().toISOString() + }; + + todosData.items.push(todo); + await saveTodos(); + renderTodos(); + showToast('Todo adăugat'); + } + + // ===== ISSUES ===== async function loadIssues() { try { const response = await fetch('issues.json?' + Date.now()); @@ -1717,7 +1970,7 @@ method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ - path: 'kanban/issues.json', + path: 'dashboard/issues.json', content: JSON.stringify(issuesData, null, 2) }) }); @@ -1743,6 +1996,7 @@ initStatusSections(); loadStatus(); loadIssues(); + loadTodos(); loadActivity(); diff --git a/dashboard/todos.json b/dashboard/todos.json new file mode 100644 index 0000000..4b400ec --- /dev/null +++ b/dashboard/todos.json @@ -0,0 +1,15 @@ +{ + "lastUpdated": "2026-02-02T10:45:00Z", + "items": [ + { + "id": "prov-2026-02-02", + "text": "Provocare: Observă când apare vocea critică și dă-i un nume ridicol", + "domain": "self", + "dueDate": "2026-02-02", + "done": false, + "doneAt": null, + "source": "morning-coaching", + "createdAt": "2026-02-02T09:00:00Z" + } + ] +}