Add active path highlighting in html exports (#929)

* fix(coding-agent): HTML export sidebar click scrolls instead of truncating branch

Previously, clicking a message in the sidebar tree would set that message
as the new leaf, causing getPath() to only return messages up to that point
and hiding all messages below it.

Now handleTreeNodeClick() checks if the clicked entry is on the current path:
- If yes: just scrolls to it without re-rendering
- If no: finds the actual leaf of that branch and navigates to it, then
  scrolls to the clicked message

Added childrenMap for parent->children lookup and findBranchLeaf() to
traverse down to a branch's leaf.

* fix(coding-agent): HTML export sidebar click scrolls instead of truncating branch

Previously, clicking a message in the sidebar tree would set that message
as the new leaf, causing getPath() to only return messages up to that point
and hiding all messages below it.

Now handleTreeNodeClick() checks if the clicked entry is on the current path:
- If yes: scrolls to it and updates the active marker
- If no: finds the branch's leaf, navigates to it, then scrolls to clicked message

Adds currentTargetId to track the selected entry separately from currentLeafId
(which branch to display), so the active marker follows user selection.

* most recent path wins

* reuse method

* revert

* feat(coding-agent): highlight active path in HTML export sidebar

- Add subtle accent background tint to in-path nodes
- Dim off-path nodes to 50% opacity (restore on hover)
- Makes current branch visually distinct in tree navigation

* docs(coding-agent): move changelog entry to Unreleased and add attribution

* chore(coding-agent): remove dead code and fix changelog attribution

- Remove unused childrenMap, findBranchLeaf, handleTreeNodeClick, scrollToEntry
- Split changelog entry: navigation (#853 by @mitsuhiko), highlighting (#929 by @hewliyang)
This commit is contained in:
Li Yang 2026-01-26 02:25:44 +08:00 committed by GitHub
parent b1211261be
commit 1675824ed3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 19 additions and 9 deletions

View file

@ -144,6 +144,15 @@
}
.tree-node.in-path {
background: color-mix(in srgb, var(--accent) 10%, transparent);
}
.tree-node:not(.in-path) {
opacity: 0.5;
}
.tree-node:not(.in-path):hover {
opacity: 1;
}
.tree-prefix {

View file

@ -665,6 +665,7 @@
// ============================================================
let currentLeafId = leafId;
let currentTargetId = urlTargetId || leafId;
let treeRendered = false;
function renderTree() {
@ -681,12 +682,12 @@
for (const flatNode of filtered) {
const entry = flatNode.node.entry;
const isOnPath = activePathIds.has(entry.id);
const isLeaf = entry.id === currentLeafId;
const isTarget = entry.id === currentTargetId;
const div = document.createElement('div');
div.className = 'tree-node';
if (isOnPath) div.classList.add('in-path');
if (isLeaf) div.classList.add('active');
if (isTarget) div.classList.add('active');
div.dataset.id = entry.id;
const prefix = buildTreePrefix(flatNode);
@ -721,10 +722,10 @@
for (const node of nodes) {
const id = node.dataset.id;
const isOnPath = activePathIds.has(id);
const isLeaf = id === currentLeafId;
const isTarget = id === currentTargetId;
node.classList.toggle('in-path', isOnPath);
node.classList.toggle('active', isLeaf);
node.classList.toggle('active', isTarget);
const marker = node.querySelector('.tree-marker');
if (marker) {
@ -1351,6 +1352,7 @@
function navigateTo(targetId, scrollMode = 'target', scrollToEntryId = null) {
currentLeafId = targetId;
currentTargetId = scrollToEntryId || targetId;
const path = getPath(targetId);
renderTree();