@tenonhq/dovetail-dashboard 0.0.14 → 0.0.15

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tenonhq/dovetail-dashboard",
3
- "version": "0.0.14",
3
+ "version": "0.0.15",
4
4
  "description": "Update Set Dashboard for Dovetail",
5
5
  "main": "server.js",
6
6
  "scripts": {
@@ -105,7 +105,7 @@
105
105
  .cp-detail-header { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-bottom: 16px; }
106
106
  .cp-detail-header h2 { font-size: 20px; margin: 0; }
107
107
  .cp-stamp { font-size: 11px; color: var(--text-muted); margin-left: auto; }
108
- .cp-tabs { display: flex; gap: 0; border-bottom: 1px solid var(--border); margin-bottom: 16px; }
108
+ .cp-tabs { display: flex; gap: 0; align-items: center; border-bottom: 1px solid var(--border); margin-bottom: 16px; }
109
109
  .cp-tab {
110
110
  background: transparent;
111
111
  border: none;
@@ -148,8 +148,8 @@
148
148
  }
149
149
  .cp-artifact-head {
150
150
  display: flex;
151
- justify-content: space-between;
152
151
  align-items: center;
152
+ gap: 8px;
153
153
  margin-bottom: 12px;
154
154
  }
155
155
  .cp-artifact-title { font-weight: 600; font-size: 14px; }
@@ -99,6 +99,84 @@
99
99
  }
100
100
  }
101
101
 
102
+ /* ─── Copy helpers ─────────────────────────────────────────────────────────── */
103
+
104
+ function fallbackCopy(text) {
105
+ var ta = document.createElement("textarea");
106
+ ta.value = text;
107
+ ta.style.cssText = "position:fixed;left:-9999px;top:-9999px;opacity:0";
108
+ document.body.appendChild(ta);
109
+ ta.select();
110
+ try { document.execCommand("copy"); } catch (_) {}
111
+ ta.remove();
112
+ }
113
+
114
+ function makeCopyBtn(label, getText) {
115
+ var btn = document.createElement("button");
116
+ btn.className = "cp-copy-btn";
117
+ btn.textContent = label;
118
+ btn.addEventListener("click", function (e) {
119
+ e.stopPropagation();
120
+ var text = getText();
121
+ var flash = function () {
122
+ btn.textContent = "Copied!";
123
+ btn.classList.add("cp-copy-btn--copied");
124
+ setTimeout(function () {
125
+ btn.textContent = label;
126
+ btn.classList.remove("cp-copy-btn--copied");
127
+ }, 1500);
128
+ };
129
+ if (navigator.clipboard && navigator.clipboard.writeText) {
130
+ navigator.clipboard.writeText(text).then(flash).catch(function () {
131
+ fallbackCopy(text);
132
+ flash();
133
+ });
134
+ } else {
135
+ fallbackCopy(text);
136
+ flash();
137
+ }
138
+ });
139
+ return btn;
140
+ }
141
+
142
+ function addTabsCopyAll(plan, artifacts) {
143
+ var existing = document.getElementById("cp-tabs-copy-all");
144
+ if (existing) existing.remove();
145
+
146
+ var btn = makeCopyBtn("Copy All", function () {
147
+ if (state.activeTab === "artifacts") {
148
+ return artifacts.map(function (a) {
149
+ return "# " + a.title + "\n\n" + a.content;
150
+ }).join("\n\n---\n\n");
151
+ }
152
+ return plan.content_md && plan.content_md.trim()
153
+ ? plan.content_md
154
+ : els.planPanel.innerText.trim();
155
+ });
156
+ btn.id = "cp-tabs-copy-all";
157
+ btn.style.marginLeft = "auto";
158
+ var tabsEl = document.querySelector(".cp-tabs");
159
+ if (tabsEl) tabsEl.appendChild(btn);
160
+ }
161
+
162
+ function addPlanSectionCopyBtns() {
163
+ var structured = els.planPanel.querySelector(".cp-structured");
164
+ if (!structured) return;
165
+ var children = Array.from(structured.children);
166
+ children.forEach(function (child) {
167
+ child.classList.add("cp-c-copy-wrap");
168
+ var group = document.createElement("div");
169
+ group.className = "cp-copy-btn-group";
170
+ var btn = makeCopyBtn("Copy", (function (el) {
171
+ return function () { return el.innerText.trim(); };
172
+ })(child));
173
+ group.appendChild(btn);
174
+ child.appendChild(group);
175
+ });
176
+ }
177
+
178
+ /* ─────────────────────────────────────────────────────────────────────────── */
179
+
102
180
  function renderRail() {
103
181
  var plans = sortedPlans();
104
182
  els.count.textContent = String(plans.length);
@@ -165,6 +243,8 @@
165
243
  if (!state.selectedSlug || !state.plans.has(state.selectedSlug)) {
166
244
  els.detailEmpty.style.display = "block";
167
245
  els.detailBody.hidden = true;
246
+ var orphan = document.getElementById("cp-tabs-copy-all");
247
+ if (orphan) orphan.remove();
168
248
  return;
169
249
  }
170
250
  var plan = state.plans.get(state.selectedSlug);
@@ -201,6 +281,9 @@
201
281
  renderMarkdown(plan.content_md, els.planPanel);
202
282
  }
203
283
 
284
+ addPlanSectionCopyBtns();
285
+ addTabsCopyAll(plan, artifacts);
286
+
204
287
  els.artifactsPanel.innerHTML = "";
205
288
  if (artifacts.length === 0) {
206
289
  var empty = document.createElement("div");
@@ -222,6 +305,14 @@
222
305
  kind.textContent = artifact.kind;
223
306
  head.appendChild(title);
224
307
  head.appendChild(kind);
308
+
309
+ var copyGroup = document.createElement("div");
310
+ copyGroup.className = "cp-copy-btn-group cp-copy-btn-group--artifact";
311
+ copyGroup.appendChild(makeCopyBtn("Copy", (function (content) {
312
+ return function () { return content; };
313
+ })(artifact.content)));
314
+ head.appendChild(copyGroup);
315
+
225
316
  card.appendChild(head);
226
317
 
227
318
  var body = document.createElement("div");