@tenonhq/dovetail-dashboard 0.0.43 → 0.0.45

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/public/app.js CHANGED
@@ -79,11 +79,16 @@ function renderScopes() {
79
79
 
80
80
  scopesData.forEach(function (scope) {
81
81
  var card = document.createElement("div");
82
- card.className = "scope-card" + (scope.selected_update_set ? " has-selection" : "");
82
+ card.className =
83
+ "scope-card" + (scope.selected_update_set ? " has-selection" : "");
83
84
  card.id = "card-" + scope.scope;
84
85
 
85
- var selectedName = scope.selected_update_set ? scope.selected_update_set.name : "None";
86
- var selectedId = scope.selected_update_set ? scope.selected_update_set.sys_id : "";
86
+ var selectedName = scope.selected_update_set
87
+ ? scope.selected_update_set.name
88
+ : "None";
89
+ var selectedId = scope.selected_update_set
90
+ ? scope.selected_update_set.sys_id
91
+ : "";
87
92
 
88
93
  // Build activate button HTML if there's an active task
89
94
  var activateHtml = "";
@@ -95,8 +100,12 @@ function renderScopes() {
95
100
  } else {
96
101
  activateHtml =
97
102
  '<button class="btn-activate" onclick="activateScope(\'' +
98
- scope.scope + "', '" + scope.sys_id +
99
- "')\">Activate CU-" + activeTask.taskId + "</button>";
103
+ scope.scope +
104
+ "', '" +
105
+ scope.sys_id +
106
+ "')\">Activate " +
107
+ (activeTask.customId || activeTask.taskId) +
108
+ "</button>";
100
109
  }
101
110
  }
102
111
 
@@ -104,30 +113,72 @@ function renderScopes() {
104
113
  var taskBadgeHtml = "";
105
114
  if (activeTask && activeTask.scopes && activeTask.scopes[scope.scope]) {
106
115
  taskBadgeHtml =
107
- '<div class="scope-task-badge">CU-' + activeTask.taskId + "</div>";
116
+ '<div class="scope-task-badge">' +
117
+ (activeTask.customId || activeTask.taskId) +
118
+ "</div>";
108
119
  }
109
120
 
110
121
  card.innerHTML =
111
122
  '<div class="scope-header">' +
112
- '<span class="scope-name">' + scope.scope + "</span>" +
113
- '<span class="scope-id">' + (scope.sys_id ? scope.sys_id.substring(0, 8) + "..." : "not found") + "</span>" +
123
+ '<span class="scope-name">' +
124
+ scope.scope +
125
+ "</span>" +
126
+ '<span class="scope-id">' +
127
+ (scope.sys_id ? scope.sys_id.substring(0, 8) + "..." : "not found") +
128
+ "</span>" +
129
+ "</div>" +
130
+ '<div class="display-name">' +
131
+ scope.display_name +
114
132
  "</div>" +
115
- '<div class="display-name">' + scope.display_name + "</div>" +
116
- '<select class="update-set-select" id="select-' + scope.scope + '" onchange="onSelectChange(\'' + scope.scope + '\')">' +
117
- '<option value="">-- No Update Set --</option>' +
118
- '<option value="__loading" disabled>Loading...</option>' +
133
+ '<select class="update-set-select" id="select-' +
134
+ scope.scope +
135
+ '" onchange="onSelectChange(\'' +
136
+ scope.scope +
137
+ "')\">" +
138
+ '<option value="">-- No Update Set --</option>' +
139
+ '<option value="__loading" disabled>Loading...</option>' +
119
140
  "</select>" +
120
141
  '<div class="card-actions">' +
121
- '<button class="btn btn-primary" onclick="openCreateModal(\'' + scope.scope + "', '" + scope.sys_id + "')\" " + (!scope.sys_id ? "disabled" : "") + ">New</button>" +
122
- '<button class="btn btn-danger" id="close-btn-' + scope.scope + '" onclick="closeUpdateSet(\'' + scope.scope + '\')" disabled>Close</button>' +
123
- '<button class="btn btn-clear" id="clear-btn-' + scope.scope + '" onclick="clearSelection(\'' + scope.scope + '\')" ' + (!scope.selected_update_set ? "disabled" : "") + ">Clear</button>" +
124
- activateHtml +
142
+ '<button class="btn btn-primary" onclick="openCreateModal(\'' +
143
+ scope.scope +
144
+ "', '" +
145
+ scope.sys_id +
146
+ "')\" " +
147
+ (!scope.sys_id ? "disabled" : "") +
148
+ ">New</button>" +
149
+ '<button class="btn btn-danger" id="close-btn-' +
150
+ scope.scope +
151
+ '" onclick="closeUpdateSet(\'' +
152
+ scope.scope +
153
+ "')\" disabled>Close</button>" +
154
+ '<button class="btn btn-clear" id="clear-btn-' +
155
+ scope.scope +
156
+ '" onclick="clearSelection(\'' +
157
+ scope.scope +
158
+ "')\" " +
159
+ (!scope.selected_update_set ? "disabled" : "") +
160
+ ">Clear</button>" +
161
+ activateHtml +
125
162
  "</div>" +
126
163
  '<div class="quick-create">' +
127
- '<input type="text" id="quick-name-' + scope.scope + '" placeholder="Update set name..." class="quick-create-input" onkeydown="if(event.key===\'Enter\')quickCreateUpdateSet(\'' + scope.scope + "', '" + scope.sys_id + "')\" />" +
128
- '<button class="btn btn-primary btn-small" onclick="quickCreateUpdateSet(\'' + scope.scope + "', '" + scope.sys_id + "')\" " + (!scope.sys_id ? "disabled" : "") + ">Create</button>" +
164
+ '<input type="text" id="quick-name-' +
165
+ scope.scope +
166
+ '" placeholder="Update set name..." class="quick-create-input" onkeydown="if(event.key===\'Enter\')quickCreateUpdateSet(\'' +
167
+ scope.scope +
168
+ "', '" +
169
+ scope.sys_id +
170
+ "')\" />" +
171
+ '<button class="btn btn-primary btn-small" onclick="quickCreateUpdateSet(\'' +
172
+ scope.scope +
173
+ "', '" +
174
+ scope.sys_id +
175
+ "')\" " +
176
+ (!scope.sys_id ? "disabled" : "") +
177
+ ">Create</button>" +
129
178
  "</div>" +
130
- (scope.selected_update_set ? '<div class="selected-badge">Active for push</div>' : "") +
179
+ (scope.selected_update_set
180
+ ? '<div class="selected-badge">Active for push</div>'
181
+ : "") +
131
182
  taskBadgeHtml;
132
183
 
133
184
  grid.appendChild(card);
@@ -166,7 +217,9 @@ async function loadUpdateSets(scope, selectedId) {
166
217
  async function onSelectChange(scope) {
167
218
  var select = document.getElementById("select-" + scope);
168
219
  var sysId = select.value;
169
- var name = select.options[select.selectedIndex] ? select.options[select.selectedIndex].textContent : "";
220
+ var name = select.options[select.selectedIndex]
221
+ ? select.options[select.selectedIndex].textContent
222
+ : "";
170
223
 
171
224
  try {
172
225
  await api("POST", "/api/select-update-set", {
@@ -175,9 +228,13 @@ async function onSelectChange(scope) {
175
228
  update_set_name: sysId ? name : null,
176
229
  });
177
230
 
178
- var scopeData = scopesData.find(function (s) { return s.scope === scope; });
231
+ var scopeData = scopesData.find(function (s) {
232
+ return s.scope === scope;
233
+ });
179
234
  if (scopeData) {
180
- scopeData.selected_update_set = sysId ? { sys_id: sysId, name: name } : null;
235
+ scopeData.selected_update_set = sysId
236
+ ? { sys_id: sysId, name: name }
237
+ : null;
181
238
  }
182
239
 
183
240
  var card = document.getElementById("card-" + scope);
@@ -221,8 +278,10 @@ async function closeUpdateSet(scope) {
221
278
  var sysId = select ? select.value : "";
222
279
  if (!sysId) return;
223
280
 
224
- var name = select.options[select.selectedIndex] ? select.options[select.selectedIndex].textContent : "";
225
- if (!confirm("Close update set \"" + name + "\"?")) return;
281
+ var name = select.options[select.selectedIndex]
282
+ ? select.options[select.selectedIndex].textContent
283
+ : "";
284
+ if (!confirm('Close update set "' + name + '"?')) return;
226
285
 
227
286
  try {
228
287
  await api("PATCH", "/api/update-set/" + sysId + "/close");
@@ -233,7 +292,9 @@ async function closeUpdateSet(scope) {
233
292
  update_set_name: null,
234
293
  });
235
294
 
236
- var scopeData = scopesData.find(function (s) { return s.scope === scope; });
295
+ var scopeData = scopesData.find(function (s) {
296
+ return s.scope === scope;
297
+ });
237
298
  if (scopeData) scopeData.selected_update_set = null;
238
299
 
239
300
  toast("Closed: " + name);
@@ -260,8 +321,12 @@ function openCreateModal(scope, scopeSysId) {
260
321
  modalScopeKey = scope;
261
322
  modalScopeSysId = scopeSysId;
262
323
  document.getElementById("modal-scope").value = scope;
263
- document.getElementById("modal-name").value = activeTask ? activeTask.updateSetName : "";
264
- document.getElementById("modal-description").value = activeTask ? activeTask.description : "";
324
+ document.getElementById("modal-name").value = activeTask
325
+ ? activeTask.updateSetName
326
+ : "";
327
+ document.getElementById("modal-description").value = activeTask
328
+ ? activeTask.description
329
+ : "";
265
330
  document.getElementById("create-modal").classList.add("active");
266
331
  document.getElementById("modal-name").focus();
267
332
  }
@@ -299,7 +364,9 @@ async function createUpdateSet() {
299
364
  update_set_name: name,
300
365
  });
301
366
 
302
- var scopeData = scopesData.find(function (s) { return s.scope === modalScopeKey; });
367
+ var scopeData = scopesData.find(function (s) {
368
+ return s.scope === modalScopeKey;
369
+ });
303
370
  if (scopeData) {
304
371
  scopeData.selected_update_set = { sys_id: newSysId, name: name };
305
372
  }
@@ -366,7 +433,9 @@ async function quickCreateUpdateSet(scope, scopeSysId) {
366
433
  update_set_name: name,
367
434
  });
368
435
 
369
- var scopeData = scopesData.find(function (s) { return s.scope === scope; });
436
+ var scopeData = scopesData.find(function (s) {
437
+ return s.scope === scope;
438
+ });
370
439
  if (scopeData) {
371
440
  scopeData.selected_update_set = { sys_id: newSysId, name: name };
372
441
  }
@@ -468,7 +537,10 @@ async function loadClickUpTasks() {
468
537
 
469
538
  try {
470
539
  var statusParam = activeStatuses.join(",");
471
- var data = await api("GET", "/api/clickup/tasks?statuses=" + encodeURIComponent(statusParam));
540
+ var data = await api(
541
+ "GET",
542
+ "/api/clickup/tasks?statuses=" + encodeURIComponent(statusParam)
543
+ );
472
544
  clickupTasks = data.byStatus || {};
473
545
 
474
546
  // Merge discovered statuses with what we know
@@ -505,7 +577,8 @@ function renderStatusFilters() {
505
577
  container.innerHTML = "";
506
578
  availableStatuses.forEach(function (status) {
507
579
  var chip = document.createElement("button");
508
- chip.className = "filter-chip" + (activeStatuses.indexOf(status) !== -1 ? " active" : "");
580
+ chip.className =
581
+ "filter-chip" + (activeStatuses.indexOf(status) !== -1 ? " active" : "");
509
582
  chip.textContent = status;
510
583
  chip.onclick = function () {
511
584
  var idx = activeStatuses.indexOf(status);
@@ -535,9 +608,12 @@ function filterTasks(tasks) {
535
608
  }
536
609
  if (myTasksOnly && clickupUserId) {
537
610
  filtered = filtered.filter(function (task) {
538
- return task.assignees && task.assignees.some(function (a) {
539
- return String(a.id) === String(clickupUserId);
540
- });
611
+ return (
612
+ task.assignees &&
613
+ task.assignees.some(function (a) {
614
+ return String(a.id) === String(clickupUserId);
615
+ })
616
+ );
541
617
  });
542
618
  }
543
619
  return filtered;
@@ -571,7 +647,9 @@ function renderTaskList() {
571
647
 
572
648
  tasks.forEach(function (task) {
573
649
  var card = document.createElement("div");
574
- card.className = "task-card" + (activeTask && activeTask.taskId === task.id ? " selected" : "");
650
+ card.className =
651
+ "task-card" +
652
+ (activeTask && activeTask.taskId === task.id ? " selected" : "");
575
653
  card.onclick = function () {
576
654
  selectTask(task);
577
655
  };
@@ -579,25 +657,44 @@ function renderTaskList() {
579
657
  var priorityHtml = "";
580
658
  if (task.priority) {
581
659
  // Tenon tertiary + status palette (see tokens.css)
582
- var colors = { urgent: "#d92b2b", high: "#f16b19", normal: "#f4dc00", low: "#76d6ff" };
660
+ var colors = {
661
+ urgent: "#d92b2b",
662
+ high: "#f16b19",
663
+ normal: "#f4dc00",
664
+ low: "#76d6ff",
665
+ };
583
666
  var color = colors[task.priority] || "#9caaa1";
584
- priorityHtml = '<span class="task-priority-dot" style="background:' + color + '"></span>';
667
+ priorityHtml =
668
+ '<span class="task-priority-dot" style="background:' +
669
+ color +
670
+ '"></span>';
585
671
  }
586
672
 
587
673
  var assigneeHtml = "";
588
674
  if (task.assignees && task.assignees.length > 0) {
589
- var initials = task.assignees.map(function (a) {
590
- return a.initials || (a.username || "?").substring(0, 2).toUpperCase();
591
- }).join(", ");
592
- assigneeHtml = '<span class="task-card-assignee">' + escapeHtml(initials) + "</span>";
675
+ var initials = task.assignees
676
+ .map(function (a) {
677
+ return (
678
+ a.initials || (a.username || "?").substring(0, 2).toUpperCase()
679
+ );
680
+ })
681
+ .join(", ");
682
+ assigneeHtml =
683
+ '<span class="task-card-assignee">' +
684
+ escapeHtml(initials) +
685
+ "</span>";
593
686
  }
594
687
 
595
688
  card.innerHTML =
596
- '<div class="task-card-name">' + escapeHtml(task.name) + "</div>" +
689
+ '<div class="task-card-name">' +
690
+ escapeHtml(task.name) +
691
+ "</div>" +
597
692
  '<div class="task-card-meta">' +
598
- '<span class="task-card-id">' + (task.customId || task.id) + "</span>" +
599
- priorityHtml +
600
- assigneeHtml +
693
+ '<span class="task-card-id">' +
694
+ (task.customId || task.id) +
695
+ "</span>" +
696
+ priorityHtml +
697
+ assigneeHtml +
601
698
  "</div>";
602
699
 
603
700
  group.appendChild(card);
@@ -607,7 +704,8 @@ function renderTaskList() {
607
704
  });
608
705
 
609
706
  if (totalVisible === 0) {
610
- container.innerHTML = '<div class="sidebar-loading">No matching tasks</div>';
707
+ container.innerHTML =
708
+ '<div class="sidebar-loading">No matching tasks</div>';
611
709
  }
612
710
  }
613
711
 
@@ -623,6 +721,7 @@ async function selectTask(task) {
623
721
  try {
624
722
  var data = await api("POST", "/api/clickup/select-task", {
625
723
  taskId: task.id,
724
+ customId: task.customId || "",
626
725
  taskName: task.name,
627
726
  taskDescription: task.description || "",
628
727
  taskUrl: task.url || "",
@@ -676,14 +775,22 @@ function renderActiveTaskBanner() {
676
775
  banner.style.display = "";
677
776
 
678
777
  var scopeKeys = activeTask.scopes ? Object.keys(activeTask.scopes) : [];
679
- var scopeText = scopeKeys.length > 0
680
- ? "<span>" + scopeKeys.join(", ") + "</span>"
681
- : "None activated yet";
778
+ var scopeText =
779
+ scopeKeys.length > 0
780
+ ? "<span>" + scopeKeys.join(", ") + "</span>"
781
+ : "None activated yet";
682
782
 
683
783
  banner.innerHTML =
684
- '<div class="active-task-name">' + escapeHtml(activeTask.taskName) + "</div>" +
685
- '<div class="active-task-us-name">' + escapeHtml(activeTask.updateSetName) + "</div>" +
686
- '<div class="active-task-scopes">Scopes: ' + scopeText + "</div>" +
784
+ '<div class="active-task-name">' +
785
+ escapeHtml(activeTask.taskName) +
786
+ "</div>" +
787
+ '<div class="active-task-us-name">' +
788
+ escapeHtml(activeTask.updateSetName) +
789
+ "</div>" +
790
+ '<div class="active-task-scopes">Scopes: ' +
791
+ scopeText +
792
+ "</div>" +
793
+ '<button class="btn-start-task" onclick="startTask()">Start Task</button>' +
687
794
  '<button class="btn-deselect" onclick="deselectTask()">Deselect</button>';
688
795
  }
689
796
 
@@ -698,7 +805,7 @@ function renderActiveTaskChip() {
698
805
  }
699
806
 
700
807
  chip.style.display = "";
701
- chip.textContent = "CU-" + activeTask.taskId;
808
+ chip.textContent = activeTask.customId || activeTask.taskId;
702
809
  chip.title = activeTask.updateSetName;
703
810
  chip.onclick = function () {
704
811
  if (!sidebarOpen) toggleSidebar();
@@ -736,7 +843,9 @@ async function activateScope(scope, scopeSysId) {
736
843
  activeTask.scopes[scope] = { sys_id: us.sys_id, name: us.name };
737
844
 
738
845
  // Update scopesData so the dropdown reflects the new selection
739
- var scopeData = scopesData.find(function (s) { return s.scope === scope; });
846
+ var scopeData = scopesData.find(function (s) {
847
+ return s.scope === scope;
848
+ });
740
849
  if (scopeData) {
741
850
  scopeData.selected_update_set = { sys_id: us.sys_id, name: us.name };
742
851
  }
@@ -748,7 +857,80 @@ async function activateScope(scope, scopeSysId) {
748
857
  toast("Failed to activate scope: " + e.message, "error");
749
858
  if (activateBtn) {
750
859
  activateBtn.disabled = false;
751
- activateBtn.textContent = "Activate CU-" + activeTask.taskId;
860
+ activateBtn.textContent =
861
+ "Activate " + (activeTask.customId || activeTask.taskId);
862
+ }
863
+ }
864
+ }
865
+
866
+ // --- Start task: ClickUp status -> in progress, per-scope update sets, branch ---
867
+
868
+ async function startTask() {
869
+ if (!activeTask) return;
870
+
871
+ var btn = document.querySelector(".btn-start-task");
872
+ if (btn) {
873
+ btn.disabled = true;
874
+ btn.textContent = "Starting...";
875
+ }
876
+
877
+ try {
878
+ var data = await api("POST", "/api/clickup/start-task");
879
+ var scopeResults = data.scopes || [];
880
+
881
+ if (data.activeTask) {
882
+ activeTask = data.activeTask;
883
+ }
884
+
885
+ var created = 0;
886
+ var found = 0;
887
+ var errors = 0;
888
+ scopeResults.forEach(function (r) {
889
+ if (r.error) {
890
+ errors++;
891
+ } else if (r.created) {
892
+ created++;
893
+ } else {
894
+ found++;
895
+ }
896
+ var scopeData = scopesData.find(function (s) {
897
+ return s.scope === r.scope;
898
+ });
899
+ if (scopeData && r.update_set) {
900
+ scopeData.selected_update_set = {
901
+ sys_id: r.update_set.sys_id,
902
+ name: r.update_set.name,
903
+ };
904
+ }
905
+ });
906
+
907
+ var parts = ["status: in progress"];
908
+ var setParts = [];
909
+ if (created > 0) setParts.push(created + " created");
910
+ if (found > 0) setParts.push(found + " found");
911
+ if (errors > 0) setParts.push(errors + " failed");
912
+ if (setParts.length) parts.push("update sets: " + setParts.join(", "));
913
+
914
+ if (data.branch && data.branch.branch) {
915
+ parts.push(
916
+ (data.branch.created ? "branch created: " : "switched to branch: ") +
917
+ data.branch.branch
918
+ );
919
+ } else if (data.branch && data.branch.error) {
920
+ parts.push("branch failed: " + data.branch.error);
921
+ }
922
+
923
+ toast(parts.join(" — "));
924
+
925
+ renderActiveTaskBanner();
926
+ renderScopes();
927
+ } catch (e) {
928
+ toast("Failed to start task: " + e.message, "error");
929
+ } finally {
930
+ var refreshedBtn = document.querySelector(".btn-start-task");
931
+ if (refreshedBtn) {
932
+ refreshedBtn.disabled = false;
933
+ refreshedBtn.textContent = "Start Task";
752
934
  }
753
935
  }
754
936
  }
@@ -793,9 +975,14 @@ async function autoActivateAllScopes() {
793
975
  }
794
976
 
795
977
  // Update scopesData
796
- var scopeData = scopesData.find(function (s) { return s.scope === r.scope; });
978
+ var scopeData = scopesData.find(function (s) {
979
+ return s.scope === r.scope;
980
+ });
797
981
  if (scopeData) {
798
- scopeData.selected_update_set = { sys_id: r.update_set.sys_id, name: r.update_set.name };
982
+ scopeData.selected_update_set = {
983
+ sys_id: r.update_set.sys_id,
984
+ name: r.update_set.name,
985
+ };
799
986
  }
800
987
  });
801
988
 
@@ -879,7 +1066,10 @@ async function loadRecentEdits() {
879
1066
  );
880
1067
  });
881
1068
  if (recentSave) {
882
- toast(edit.name + " was already saved less than 30 minutes ago.", "warn");
1069
+ toast(
1070
+ edit.name + " was already saved less than 30 minutes ago.",
1071
+ "warn"
1072
+ );
883
1073
  }
884
1074
  }
885
1075
  });
@@ -893,7 +1083,10 @@ async function loadRecentEdits() {
893
1083
 
894
1084
  async function dismissRecentEdit(sys_id, tableName) {
895
1085
  try {
896
- await api("POST", "/api/recent-edits/dismiss", { sys_id: sys_id, tableName: tableName });
1086
+ await api("POST", "/api/recent-edits/dismiss", {
1087
+ sys_id: sys_id,
1088
+ tableName: tableName,
1089
+ });
897
1090
  recentEdits = recentEdits.filter(function (e) {
898
1091
  return !(e.sys_id === sys_id && e.tableName === tableName);
899
1092
  });
@@ -951,8 +1144,10 @@ function renderRecentEdits() {
951
1144
  var updateSetEl = document.createElement("span");
952
1145
  var isDefault = edit.updateSet.toLowerCase().indexOf("default") !== -1;
953
1146
  var expected = expectedUpdateSets[edit.scope];
954
- var isMismatch = expected && edit.updateSet !== expected && edit.updateSet !== "unknown";
955
- updateSetEl.className = "recent-edit-update-set" + (isDefault || isMismatch ? " warning" : "");
1147
+ var isMismatch =
1148
+ expected && edit.updateSet !== expected && edit.updateSet !== "unknown";
1149
+ updateSetEl.className =
1150
+ "recent-edit-update-set" + (isDefault || isMismatch ? " warning" : "");
956
1151
  updateSetEl.textContent = edit.updateSet;
957
1152
  if (isMismatch && expected) {
958
1153
  updateSetEl.title = "Expected: " + expected;
@@ -1031,9 +1226,15 @@ loadClickUpStatus();
1031
1226
  recentEditsInterval = setInterval(loadRecentEdits, 60000);
1032
1227
 
1033
1228
  // Wire up sidebar toggle and close buttons
1034
- document.getElementById("sidebar-toggle").addEventListener("click", toggleSidebar);
1035
- document.getElementById("sidebar-close").addEventListener("click", toggleSidebar);
1036
- document.getElementById("refresh-btn").addEventListener("click", refreshDashboard);
1229
+ document
1230
+ .getElementById("sidebar-toggle")
1231
+ .addEventListener("click", toggleSidebar);
1232
+ document
1233
+ .getElementById("sidebar-close")
1234
+ .addEventListener("click", toggleSidebar);
1235
+ document
1236
+ .getElementById("refresh-btn")
1237
+ .addEventListener("click", refreshDashboard);
1037
1238
 
1038
1239
  // Render initial status filter chips
1039
1240
  renderStatusFilters();
@@ -1050,7 +1251,9 @@ renderTaskToggles();
1050
1251
  // --- Theme toggle ---
1051
1252
 
1052
1253
  function currentTheme() {
1053
- return document.documentElement.getAttribute("data-theme") === "dark" ? "dark" : "light";
1254
+ return document.documentElement.getAttribute("data-theme") === "dark"
1255
+ ? "dark"
1256
+ : "light";
1054
1257
  }
1055
1258
 
1056
1259
  function applyTheme(theme) {
@@ -1061,7 +1264,8 @@ function applyTheme(theme) {
1061
1264
  var btn = document.getElementById("cp-theme-toggle");
1062
1265
  if (btn) {
1063
1266
  btn.textContent = theme === "dark" ? "☀︎" : "☾";
1064
- btn.title = theme === "dark" ? "Switch to light mode" : "Switch to dark mode";
1267
+ btn.title =
1268
+ theme === "dark" ? "Switch to light mode" : "Switch to dark mode";
1065
1269
  }
1066
1270
  }
1067
1271
 
package/public/styles.css CHANGED
@@ -312,6 +312,28 @@ header h1 span {
312
312
  font-weight: var(--weight-semibold);
313
313
  }
314
314
 
315
+ .btn-start-task {
316
+ font-family: inherit;
317
+ font-size: 11px;
318
+ font-weight: var(--weight-semibold);
319
+ padding: 4px 10px;
320
+ margin-right: 6px;
321
+ background: var(--success);
322
+ color: var(--fg-on-dark);
323
+ border: 1px solid var(--success);
324
+ border-radius: var(--radius-sm);
325
+ cursor: pointer;
326
+ }
327
+
328
+ .btn-start-task:hover {
329
+ filter: brightness(1.1);
330
+ }
331
+
332
+ .btn-start-task:disabled {
333
+ opacity: 0.6;
334
+ cursor: default;
335
+ }
336
+
315
337
  .btn-deselect {
316
338
  font-family: inherit;
317
339
  font-size: 11px;