Match taskboard to Nexus dark board

This commit is contained in:
Iris
2026-06-26 15:37:16 +00:00
parent 2d906b9e1e
commit 1de4169303
4 changed files with 275 additions and 180 deletions
+33 -19
View File
@@ -130,10 +130,13 @@ function boardView() {
</div>
<div class="actions">
<span class="status-pill"><span class="dot ${connected ? "ok" : ""}"></span>OpenClaw ${connected ? "verbunden" : "pruefen"}</span>
<button class="primary" id="new-task">+ Aufgabe</button>
</div>
</header>
<section class="board">
<form class="quick-create" id="quick-create">
<input name="title" autocomplete="off" maxlength="180" placeholder="New task title">
<button type="submit">Create task</button>
</form>
<section class="kanban">
${states.map((name) => column(name)).join("")}
</section>
`;
@@ -142,8 +145,8 @@ function boardView() {
function column(name) {
const tasks = state.tasks.filter((task) => task.state === name);
return `
<section class="column" data-state="${name}" aria-label="${name}">
<h2><span>${name}</span><span class="count">${tasks.length}</span></h2>
<section class="kanban-column" data-state="${name}" aria-label="${name}">
<header><span>${name}</span><b>${tasks.length}</b></header>
<div class="dropzone" data-state="${name}">
${tasks.map(taskCard).join("") || `<p class="empty-state">Keine Aufgaben</p>`}
</div>
@@ -152,24 +155,22 @@ function column(name) {
}
function taskCard(task) {
const index = states.indexOf(task.state);
return `
<article class="task priority-${escapeHtml(task.priority).toLowerCase()}" draggable="true" data-task-id="${task.id}" tabindex="0" role="button" aria-label="Aufgabe ${escapeHtml(task.title)} oeffnen">
<article class="task-card priority-${escapeHtml(task.priority).toLowerCase()}" draggable="true" data-task-id="${task.id}" tabindex="0" role="button" aria-label="Aufgabe ${escapeHtml(task.title)} oeffnen">
<div class="task-card-head">
<span class="badge">${escapeHtml(task.priority)}</span>
<span class="meta">${escapeHtml(task.assignee || "luna")}</span>
<span class="priority ${escapeHtml(task.priority).toLowerCase()}">${escapeHtml(task.priority)}</span>
<button class="task-edit-btn" data-edit="${task.id}" title="Bearbeiten" aria-label="Aufgabe bearbeiten">✎</button>
</div>
<div>
<h3>${escapeHtml(task.title)}</h3>
${task.detail ? `<p>${escapeHtml(task.detail)}</p>` : ""}
</div>
<select class="task-status-select" data-status-task="${task.id}" aria-label="Status fuer ${escapeHtml(task.title)}">
${states.map((x) => `<option value="${x}" ${x === task.state ? "selected" : ""}>${x}</option>`).join("")}
</select>
<div class="task-footer">
<time class="meta" datetime="${escapeHtml(task.updatedAt)}">${formatDate(task.updatedAt)}</time>
<div class="task-controls">
<button class="icon-button" data-move="${task.id}" data-state="${states[Math.max(0, index - 1)]}" title="Zurueck"></button>
<button class="icon-button" data-edit="${task.id}" title="Bearbeiten">✎</button>
<button class="icon-button" data-move="${task.id}" data-state="${states[Math.min(states.length - 1, index + 1)]}" title="Weiter"></button>
</div>
<span class="meta">${escapeHtml(task.assignee || "luna")}</span>
</div>
</article>
`;
@@ -232,18 +233,31 @@ function bindBoard() {
dialogMeta.textContent = `Status ${task.state} · Aktualisiert ${formatDate(task.updatedAt)} · Erstellt ${formatDate(task.createdAt)}`;
dialog.showModal();
};
document.querySelector("#new-task").addEventListener("click", () => {
resetDialog();
dialog.showModal();
document.querySelector("#quick-create").addEventListener("submit", async (event) => {
event.preventDefault();
const formData = new FormData(event.currentTarget);
const title = String(formData.get("title") || "").trim();
if (!title) return;
await api("/api/tasks", {
method: "POST",
body: JSON.stringify({
title,
state: "Backlog",
priority: "Normal",
assignee: state.settings?.defaultAssignee || "luna"
})
});
await loadTasks();
renderApp();
});
document.querySelector("#cancel-task").addEventListener("click", () => dialog.close());
dialog.addEventListener("click", (event) => {
if (event.target === dialog) dialog.close();
});
document.querySelectorAll("[data-move]").forEach((button) => {
button.addEventListener("click", async (event) => {
document.querySelectorAll("[data-status-task]").forEach((select) => {
select.addEventListener("change", async (event) => {
event.stopPropagation();
await api(`/api/tasks/${button.dataset.move}`, { method: "PATCH", body: JSON.stringify({ state: button.dataset.state }) });
await api(`/api/tasks/${select.dataset.statusTask}`, { method: "PATCH", body: JSON.stringify({ state: select.value }) });
await loadTasks();
renderApp();
});