Rework timeline fork display to vertical arrows with badge

Replace horizontal arrow layout with vertical stack: up/down arrows
above and below the marker, with a small blue badge showing the fork
count on the marker node.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-26 12:07:14 +01:00
parent d142df5332
commit d0057db397

View File

@@ -2061,31 +2061,26 @@ const CSS = `
line-height: 32px; line-height: 32px;
} }
.snap-timeline-fork-group { .snap-timeline-fork-group {
display: flex;
align-items: center;
gap: 1px;
flex-shrink: 0;
}
.snap-timeline-fork-center {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
gap: 1px; flex-shrink: 0;
gap: 0;
} }
.snap-timeline-branch-btn { .snap-timeline-branch-btn {
background: none; background: none;
border: none; border: none;
color: #3b82f6; color: #3b82f6;
font-size: 10px; font-size: 8px;
cursor: pointer; cursor: pointer;
padding: 0 1px; padding: 0;
line-height: 1; line-height: 1;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
width: 14px; width: 18px;
height: 18px; height: 10px;
border-radius: 3px; border-radius: 2px;
flex-shrink: 0; flex-shrink: 0;
opacity: 0.7; opacity: 0.7;
transition: opacity 0.1s, background 0.1s; transition: opacity 0.1s, background 0.1s;
@@ -2094,12 +2089,28 @@ const CSS = `
opacity: 1; opacity: 1;
background: rgba(59, 130, 246, 0.2); background: rgba(59, 130, 246, 0.2);
} }
.snap-timeline-branch-label { .snap-timeline-fork-marker-wrap {
font-size: 8px; position: relative;
color: #3b82f6; display: flex;
font-weight: 600; align-items: center;
white-space: nowrap; justify-content: center;
}
.snap-timeline-fork-badge {
position: absolute;
top: -4px;
right: -6px;
font-size: 7px;
font-weight: 700;
color: #fff;
background: #3b82f6;
border-radius: 6px;
min-width: 12px;
height: 12px;
display: flex;
align-items: center;
justify-content: center;
line-height: 1; line-height: 1;
pointer-events: none;
} }
.snap-diff-overlay { .snap-diff-overlay {
position: fixed; position: fixed;
@@ -3493,7 +3504,7 @@ function buildTimeline() {
swapSnapshot(rec); swapSnapshot(rec);
}); });
// Fork point: wrap marker with branch arrows // Fork point: vertical stack — up arrow, marker with badge, down arrow
if (forkPointSet.has(rec.id)) { if (forkPointSet.has(rec.id)) {
const children = tree.childrenOf.get(rec.id); const children = tree.childrenOf.get(rec.id);
const selectedIndex = Math.min(activeBranchSelections.get(rec.id) ?? 0, children.length - 1); const selectedIndex = Math.min(activeBranchSelections.get(rec.id) ?? 0, children.length - 1);
@@ -3501,44 +3512,44 @@ function buildTimeline() {
const group = document.createElement("div"); const group = document.createElement("div");
group.className = "snap-timeline-fork-group"; group.className = "snap-timeline-fork-group";
// Left arrow // Up arrow (previous branch)
const leftBtn = document.createElement("button"); const upBtn = document.createElement("button");
leftBtn.className = "snap-timeline-branch-btn"; upBtn.className = "snap-timeline-branch-btn";
leftBtn.textContent = "\u25C0"; upBtn.textContent = "\u25B2";
leftBtn.title = "Previous branch"; upBtn.title = `Branch ${selectedIndex}/${children.length}`;
if (selectedIndex <= 0) leftBtn.style.visibility = "hidden"; if (selectedIndex <= 0) upBtn.style.visibility = "hidden";
leftBtn.addEventListener("click", (e) => { upBtn.addEventListener("click", (e) => {
e.stopPropagation(); e.stopPropagation();
activeBranchSelections.set(rec.id, Math.max(0, selectedIndex - 1)); activeBranchSelections.set(rec.id, Math.max(0, selectedIndex - 1));
refresh(); refresh();
if (sidebarRefresh) sidebarRefresh().catch(() => {}); if (sidebarRefresh) sidebarRefresh().catch(() => {});
}); });
// Right arrow // Down arrow (next branch)
const rightBtn = document.createElement("button"); const downBtn = document.createElement("button");
rightBtn.className = "snap-timeline-branch-btn"; downBtn.className = "snap-timeline-branch-btn";
rightBtn.textContent = "\u25B6"; downBtn.textContent = "\u25BC";
rightBtn.title = "Next branch"; downBtn.title = `Branch ${selectedIndex + 2}/${children.length}`;
if (selectedIndex >= children.length - 1) rightBtn.style.visibility = "hidden"; if (selectedIndex >= children.length - 1) downBtn.style.visibility = "hidden";
rightBtn.addEventListener("click", (e) => { downBtn.addEventListener("click", (e) => {
e.stopPropagation(); e.stopPropagation();
activeBranchSelections.set(rec.id, Math.min(children.length - 1, selectedIndex + 1)); activeBranchSelections.set(rec.id, Math.min(children.length - 1, selectedIndex + 1));
refresh(); refresh();
if (sidebarRefresh) sidebarRefresh().catch(() => {}); if (sidebarRefresh) sidebarRefresh().catch(() => {});
}); });
// Center column: marker + branch label stacked vertically // Marker with fork count badge
const center = document.createElement("div"); const markerWrap = document.createElement("div");
center.className = "snap-timeline-fork-center"; markerWrap.className = "snap-timeline-fork-marker-wrap";
const branchLabel = document.createElement("span"); const badge = document.createElement("span");
branchLabel.className = "snap-timeline-branch-label"; badge.className = "snap-timeline-fork-badge";
branchLabel.textContent = `${selectedIndex + 1}/${children.length}`; badge.textContent = `${children.length}`;
center.appendChild(marker); markerWrap.appendChild(marker);
center.appendChild(branchLabel); markerWrap.appendChild(badge);
group.appendChild(leftBtn); group.appendChild(upBtn);
group.appendChild(center); group.appendChild(markerWrap);
group.appendChild(rightBtn); group.appendChild(downBtn);
track.appendChild(group); track.appendChild(group);
} else { } else {
track.appendChild(marker); track.appendChild(marker);