Lewis: May this revision serve well! lewis@tangled.org
+33
-36
appview/pages/templates/repo/fragments/diff.html
+33
-36
appview/pages/templates/repo/fragments/diff.html
···
179
179
{{ end }}
180
180
</div>
181
181
</div>
182
-
<button
183
-
type="button"
182
+
<label
184
183
data-review-btn="file-{{ .Id }}"
185
-
onclick="event.preventDefault(); event.stopPropagation(); window.__reviewToggle && window.__reviewToggle('file-{{ .Id }}')"
184
+
onclick="event.stopPropagation()"
186
185
class="review-btn hidden p-2 items-center gap-1 text-xs text-gray-400 dark:text-gray-500 hover:text-green-600 dark:hover:text-green-400 transition-colors cursor-pointer"
187
186
title="Mark as reviewed"
188
187
>
189
-
<span class="review-icon-unchecked">{{ i "circle" "size-4" }}</span>
190
-
<span class="review-icon-checked hidden">{{ i "circle-check" "size-4" }}</span>
188
+
<input
189
+
type="checkbox"
190
+
class="sr-only peer review-checkbox"
191
+
data-file-id="file-{{ .Id }}"
192
+
/>
193
+
<span class="peer-checked:hidden">{{ i "circle" "size-4" }}</span>
194
+
<span class="hidden peer-checked:inline text-green-600 dark:text-green-400">{{ i "circle-check" "size-4" }}</span>
191
195
<span class="hidden md:inline">reviewed</span>
192
-
</button>
196
+
</label>
193
197
</div>
194
198
</summary>
195
199
···
358
362
} catch { localStorage.removeItem(k); }
359
363
});
360
364
};
361
-
pruneStale();
365
+
if (Math.random() < 0.1) pruneStale();
362
366
363
367
const allFiles = () =>
364
368
document.querySelectorAll('details[id^="file-"]');
···
368
372
if (!detail) return;
369
373
370
374
const btn = detail.querySelector('[data-review-btn]');
375
+
const checkbox = btn?.querySelector('input[type="checkbox"]');
371
376
const path = CSS.escape(fileId.replace('file-', ''));
372
377
const treeLink = document.querySelector(`.filetree-link[data-path="${path}"]`);
373
378
374
-
if (isReviewed) {
375
-
detail.classList.add('opacity-60');
376
-
if (btn) {
377
-
btn.classList.replace('text-gray-400', 'text-green-600');
378
-
btn.classList.replace('dark:text-gray-500', 'dark:text-green-400');
379
-
btn.querySelector('.review-icon-unchecked')?.classList.add('hidden');
380
-
btn.querySelector('.review-icon-checked')?.classList.remove('hidden');
381
-
}
382
-
if (treeLink) {
383
-
let indicator = treeLink.parentElement.querySelector('.review-indicator');
384
-
if (!indicator) {
385
-
indicator = document.createElement('span');
386
-
indicator.className = 'review-indicator text-green-600 dark:text-green-400 flex-shrink-0';
387
-
indicator.innerHTML = '✓';
388
-
treeLink.parentElement.appendChild(indicator);
389
-
}
390
-
}
391
-
} else {
392
-
detail.classList.remove('opacity-60');
393
-
if (btn) {
394
-
btn.classList.replace('text-green-600', 'text-gray-400');
395
-
btn.classList.replace('dark:text-green-400', 'dark:text-gray-500');
396
-
btn.querySelector('.review-icon-unchecked')?.classList.remove('hidden');
397
-
btn.querySelector('.review-icon-checked')?.classList.add('hidden');
398
-
}
399
-
if (treeLink) {
400
-
const indicator = treeLink.parentElement.querySelector('.review-indicator');
401
-
if (indicator) indicator.remove();
379
+
detail.classList.toggle('opacity-60', isReviewed);
380
+
381
+
if (checkbox) checkbox.checked = isReviewed;
382
+
383
+
if (treeLink) {
384
+
const existing = treeLink.parentElement.querySelector('.review-indicator');
385
+
if (isReviewed && !existing) {
386
+
const indicator = document.createElement('span');
387
+
indicator.className = 'review-indicator text-green-600 dark:text-green-400 flex-shrink-0';
388
+
indicator.innerHTML = '✓';
389
+
treeLink.parentElement.appendChild(indicator);
390
+
} else if (!isReviewed && existing) {
391
+
existing.remove();
402
392
}
403
393
}
404
394
};
···
422
412
423
413
const reviewed = load();
424
414
425
-
window.__reviewToggle = (fileId) => {
415
+
const toggleReview = (fileId) => {
426
416
const detail = document.getElementById(fileId);
427
417
if (!detail) return;
428
418
const isNowReviewed = !reviewed.has(fileId);
···
437
427
updateProgress(reviewed);
438
428
};
439
429
430
+
document.getElementById('diff-area').addEventListener('change', (e) => {
431
+
const checkbox = e.target.closest('.review-checkbox');
432
+
if (!checkbox) return;
433
+
const fileId = checkbox.dataset.fileId;
434
+
if (fileId) toggleReview(fileId);
435
+
});
436
+
440
437
document.querySelectorAll('.review-btn').forEach(btn => {
441
438
btn.classList.remove('hidden');
442
439
btn.classList.add('flex');
appview/pages/templates/repo/pulls/pull.html
appview/pages/templates/repo/pulls/pull.html
This file has not been changed.
+1
-6
types/diff.go
+1
-6
types/diff.go
···
84
84
func (d NiceDiff) FileTree() *filetree.FileTreeNode {
85
85
fs := make([]string, len(d.Diff))
86
86
for i, s := range d.Diff {
87
-
n := s.Names()
88
-
if n.New == "" {
89
-
fs[i] = n.Old
90
-
} else {
91
-
fs[i] = n.New
92
-
}
87
+
fs[i] = s.Id()
93
88
}
94
89
return filetree.FileTree(fs)
95
90
}
History
2 rounds
3 comments
oyster.cafe
submitted
#1
1 commit
expand
collapse
appview/pages: PR mark-as-reviewed btn
Lewis: May this revision serve well! <lewis@tangled.org>
3/3 success
expand
collapse
oyster.cafe
submitted
#0
1 commit
expand
collapse
appview/pages: PR mark-as-reviewed btn
Lewis: May this revision serve well! <lewis@tangled.org>
3/3 success
expand
collapse
expand 1 comment
appview/pages/templates/repo/fragments/diff.html:182 this could probably be hacked into an actual literal checkbox input, but philosophically it's not part of a form it's just a button that does mark a thing as reviewed, and it just so happens to also toggle back in our case ๐คท
types/diff.go:87-87guarantees the filetree path matches the DOM id