97 lines
4.1 KiB
JavaScript
97 lines
4.1 KiB
JavaScript
let items = [];
|
|
let doneIds = new Set();
|
|
document.addEventListener('DOMContentLoaded', async () => {
|
|
const container = document.getElementById('container');
|
|
const progress = document.getElementById('progress');
|
|
try {
|
|
const res = await chrome.runtime.sendMessage({ type: 'getReviewTasks' });
|
|
if (res.error) {
|
|
container.innerHTML = `<div class="error">${escapeHtml(res.error)}</div>`;
|
|
return;
|
|
}
|
|
items = res.review || [];
|
|
render();
|
|
}
|
|
catch (e) {
|
|
container.innerHTML = `<div class="error">${escapeHtml(e.message)}</div>`;
|
|
}
|
|
function render() {
|
|
const remaining = items.filter(i => !doneIds.has(i.task.id));
|
|
progress.textContent = `${items.length - remaining.length} / ${items.length} reviewed`;
|
|
if (remaining.length === 0) {
|
|
container.innerHTML = `
|
|
<div class="empty-state">
|
|
<h2>All caught up!</h2>
|
|
<p>No more decayed tasks to review. Come back next week.</p>
|
|
</div>
|
|
`;
|
|
chrome.runtime.sendMessage({ type: 'setLastReviewDate', date: new Date().toISOString() }).catch(() => { });
|
|
return;
|
|
}
|
|
container.innerHTML = '';
|
|
for (const item of remaining) {
|
|
container.appendChild(renderCard(item));
|
|
}
|
|
}
|
|
function renderCard(item) {
|
|
const card = document.createElement('div');
|
|
card.className = 'card';
|
|
card.id = `card-${item.task.id}`;
|
|
const pillClass = item.score.score >= 70 ? 'score-hot' : item.score.score >= 40 ? 'score-warm' : 'score-cold';
|
|
card.innerHTML = `
|
|
<div class="card-header">
|
|
<div class="title">${escapeHtml(item.task.title)}</div>
|
|
<div class="score-pill ${pillClass}">${item.score.score} decay</div>
|
|
</div>
|
|
<div class="meta">
|
|
<span>${escapeHtml(item.task.source)}</span>
|
|
${item.task.projectName ? `<span>Project: ${escapeHtml(item.task.projectName)}</span>` : ''}
|
|
${item.task.labels.length > 0 ? `<span>Labels: ${escapeHtml(item.task.labels.join(', '))}</span>` : ''}
|
|
<span>Age: ${Math.round(item.score.ageDays)} days</span>
|
|
</div>
|
|
<div class="meta">${escapeHtml(item.score.explanation)}</div>
|
|
<div class="actions">
|
|
<button class="btn btn-done" data-action="complete" data-id="${item.task.id}">Mark Done</button>
|
|
<button class="btn btn-archive" data-action="delete" data-id="${item.task.id}">Delete</button>
|
|
<button class="btn btn-dismiss" data-action="dismiss" data-id="${item.task.id}">Dismiss</button>
|
|
<a href="${escapeHtml(item.task.url)}" target="_blank" class="btn btn-open">Open</a>
|
|
</div>
|
|
`;
|
|
card.querySelectorAll('button[data-action]').forEach(btn => {
|
|
btn.addEventListener('click', async (e) => {
|
|
const target = e.currentTarget;
|
|
const action = target.getAttribute('data-action');
|
|
const id = target.getAttribute('data-id');
|
|
target.textContent = '...';
|
|
try {
|
|
if (action === 'complete') {
|
|
await chrome.runtime.sendMessage({ type: 'complete', taskId: id });
|
|
}
|
|
else if (action === 'delete') {
|
|
await chrome.runtime.sendMessage({ type: 'delete', taskId: id });
|
|
}
|
|
else if (action === 'dismiss') {
|
|
await chrome.runtime.sendMessage({ type: 'dismiss', taskId: id });
|
|
}
|
|
doneIds.add(id);
|
|
const c = document.getElementById(`card-${id}`);
|
|
if (c) {
|
|
c.classList.add('done');
|
|
}
|
|
setTimeout(render, 300);
|
|
}
|
|
catch (err) {
|
|
target.textContent = 'Error';
|
|
}
|
|
});
|
|
});
|
|
return card;
|
|
}
|
|
function escapeHtml(text) {
|
|
const div = document.createElement('div');
|
|
div.textContent = text;
|
|
return div.innerHTML;
|
|
}
|
|
});
|
|
export {};
|