Signed-off-by: Lewis lewis@tangled.org
+72
-52
Diff
round #0
+45
-33
appview/pages/templates/repo/fragments/diff.html
+45
-33
appview/pages/templates/repo/fragments/diff.html
···
8
8
#filesToggle:not(:checked) ~ div div#resize-files { display: none; }
9
9
</style>
10
10
11
-
{{ template "diffTopbar" . }}
12
-
{{ block "diffLayout" . }} {{ end }}
13
-
{{ template "fragments/resizable" }}
14
-
{{ template "activeFileHighlight" }}
15
-
{{ template "fragments/line-quote-button" }}
11
+
<div id="diff-area">
12
+
{{ template "diffTopbar" . }}
13
+
{{ block "diffLayout" . }} {{ end }}
14
+
{{ template "fragments/resizable" }}
15
+
{{ template "activeFileHighlight" }}
16
+
{{ template "fragments/line-quote-button" }}
17
+
</div>
16
18
{{ end }}
17
19
18
20
{{ define "diffTopbar" }}
···
86
88
{{ $id := index . 0 }}
87
89
{{ $target := index . 1 }}
88
90
{{ $direction := index . 2 }}
89
-
<div id="{{ $id }}"
91
+
<div id="{{ $id }}"
90
92
data-resizer="vertical"
91
93
data-target="{{ $target }}"
92
94
data-direction="{{ $direction }}"
···
217
219
</span>
218
220
</label>
219
221
<script>
220
-
document.addEventListener('DOMContentLoaded', function() {
222
+
(() => {
221
223
const checkbox = document.getElementById('collapseToggle');
222
-
const details = document.querySelectorAll('details[id^="file-"]');
224
+
const diffArea = document.getElementById('diff-area');
223
225
224
-
checkbox.addEventListener('change', function() {
225
-
details.forEach(detail => {
226
+
checkbox.addEventListener('change', () => {
227
+
document.querySelectorAll('details[id^="file-"]').forEach(detail => {
226
228
detail.open = checkbox.checked;
227
229
});
228
230
});
229
231
230
-
details.forEach(detail => {
231
-
detail.addEventListener('toggle', function() {
232
-
const allOpen = Array.from(details).every(d => d.open);
233
-
const allClosed = Array.from(details).every(d => !d.open);
232
+
if (window.__collapseToggleHandler) {
233
+
diffArea.removeEventListener('toggle', window.__collapseToggleHandler, true);
234
+
}
234
235
235
-
if (allOpen) {
236
-
checkbox.checked = true;
237
-
} else if (allClosed) {
238
-
checkbox.checked = false;
239
-
}
240
-
});
241
-
});
242
-
});
236
+
const handler = (e) => {
237
+
if (!e.target.matches('details[id^="file-"]')) return;
238
+
const details = document.querySelectorAll('details[id^="file-"]');
239
+
const allOpen = Array.from(details).every(d => d.open);
240
+
const allClosed = Array.from(details).every(d => !d.open);
241
+
242
+
if (allOpen) checkbox.checked = true;
243
+
else if (allClosed) checkbox.checked = false;
244
+
};
245
+
246
+
window.__collapseToggleHandler = handler;
247
+
diffArea.addEventListener('toggle', handler, true);
248
+
})();
243
249
</script>
244
250
{{ end }}
245
251
246
252
{{ define "activeFileHighlight" }}
247
253
<script>
248
-
document.addEventListener('DOMContentLoaded', function() {
249
-
const diffFiles = document.querySelectorAll('details[id^="file-"]');
254
+
(() => {
255
+
if (window.__activeFileScrollHandler) {
256
+
document.removeEventListener('scroll', window.__activeFileScrollHandler);
257
+
}
258
+
250
259
const filetreeLinks = document.querySelectorAll('.filetree-link');
251
-
if (diffFiles.length === 0 || filetreeLinks.length === 0) return;
260
+
if (filetreeLinks.length === 0) return;
252
261
253
262
const linkMap = new Map();
254
263
filetreeLinks.forEach(link => {
···
257
266
});
258
267
259
268
let currentActive = null;
260
-
function setActive(link) {
269
+
const setActive = (link) => {
261
270
if (link && link !== currentActive) {
262
271
if (currentActive) currentActive.classList.remove('font-bold');
263
272
link.classList.add('font-bold');
264
273
currentActive = link;
265
274
}
266
-
}
275
+
};
267
276
268
277
filetreeLinks.forEach(link => {
269
278
link.addEventListener('click', () => setActive(link));
···
272
281
const topbar = document.querySelector('.sticky.top-0.z-30');
273
282
const headerHeight = topbar ? topbar.offsetHeight : 0;
274
283
275
-
function updateActiveFile() {
276
-
for (const file of diffFiles) {
284
+
const updateActiveFile = () => {
285
+
const diffFiles = document.querySelectorAll('details[id^="file-"]');
286
+
Array.from(diffFiles).some(file => {
277
287
const rect = file.getBoundingClientRect();
278
288
if (rect.top <= headerHeight && rect.bottom > headerHeight) {
279
289
setActive(linkMap.get(file.id));
280
-
return;
290
+
return true;
281
291
}
282
-
}
283
-
}
292
+
return false;
293
+
});
294
+
};
284
295
296
+
window.__activeFileScrollHandler = updateActiveFile;
285
297
document.addEventListener('scroll', updateActiveFile);
286
298
updateActiveFile();
287
-
});
299
+
})();
288
300
</script>
289
301
{{ end }}
+27
-19
appview/pages/templates/repo/fragments/diffOpts.html
+27
-19
appview/pages/templates/repo/fragments/diffOpts.html
···
4
4
{{ $active = "split" }}
5
5
{{ end }}
6
6
7
-
{{ $unified :=
8
-
(dict
9
-
"Key" "unified"
10
-
"Value" "unified"
11
-
"Icon" "square-split-vertical"
12
-
"Meta" "") }}
13
-
{{ $split :=
14
-
(dict
15
-
"Key" "split"
16
-
"Value" "split"
17
-
"Icon" "square-split-horizontal"
18
-
"Meta" "") }}
19
-
{{ $values := list $unified $split }}
7
+
{{ $activeTab := "bg-white dark:bg-gray-700 shadow-sm" }}
8
+
{{ $inactiveTab := "bg-gray-100 dark:bg-gray-800 shadow-inner" }}
20
9
21
-
{{ template "fragments/tabSelector"
22
-
(dict
23
-
"Name" "diff"
24
-
"Values" $values
25
-
"Active" $active) }}
10
+
<div class="flex justify-between divide-x divide-gray-200 dark:divide-gray-700 rounded border border-gray-200 dark:border-gray-700 overflow-hidden"
11
+
hx-on::before-request="const t=event.target.closest('button'); if(!t||t.classList.contains('shadow-sm'))return event.preventDefault(); this.querySelectorAll('button').forEach(b => { const active=b===t; b.classList.toggle('bg-white',active); b.classList.toggle('dark:bg-gray-700',active); b.classList.toggle('shadow-sm',active); b.classList.toggle('bg-gray-100',!active); b.classList.toggle('dark:bg-gray-800',!active); b.classList.toggle('shadow-inner',!active); })">
12
+
<button
13
+
hx-get="?diff=unified"
14
+
hx-target="#diff-files"
15
+
hx-select="#diff-files"
16
+
hx-swap="outerHTML"
17
+
hx-push-url="true"
18
+
class="group p-2 whitespace-nowrap flex justify-center items-center gap-2 text-sm w-full hover:no-underline text-center {{ if eq $active "unified" }} {{ $activeTab }} {{ else }} {{ $inactiveTab }} {{ end }}">
19
+
{{ i "square-split-vertical" "size-4 inline group-[.htmx-request]:hidden" }}
20
+
{{ i "loader-circle" "size-4 animate-spin hidden group-[.htmx-request]:inline" }}
21
+
unified
22
+
</button>
23
+
<button
24
+
hx-get="?diff=split"
25
+
hx-target="#diff-files"
26
+
hx-select="#diff-files"
27
+
hx-swap="outerHTML"
28
+
hx-push-url="true"
29
+
class="group p-2 whitespace-nowrap flex justify-center items-center gap-2 text-sm w-full hover:no-underline text-center {{ if eq $active "split" }} {{ $activeTab }} {{ else }} {{ $inactiveTab }} {{ end }}">
30
+
{{ i "square-split-horizontal" "size-4 inline group-[.htmx-request]:hidden" }}
31
+
{{ i "loader-circle" "size-4 animate-spin hidden group-[.htmx-request]:inline" }}
32
+
split
33
+
</button>
34
+
</div>
26
35
{{ end }}
27
-
History
1 round
0 comments
oyster.cafe
submitted
#0
1 commit
expand
collapse
appview/pages: split diff without needing page refresh
Signed-off-by: Lewis <lewis@tangled.org>
3/3 success
expand
collapse
expand 0 comments
pull request successfully merged