1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
// Collapsible chapters functionality with localStorage persistence
(function() {
'use strict';
var STORAGE_KEY = 'guidebook-expanded-chapters';
var sidebar = document.querySelector('.book-summary');
if (!sidebar) return;
// Get stored expanded state
function getExpandedState() {
try {
var stored = localStorage.getItem(STORAGE_KEY);
return stored ? JSON.parse(stored) : {};
} catch (e) {
return {};
}
}
// Save expanded state
function saveExpandedState(state) {
try {
localStorage.setItem(STORAGE_KEY, JSON.stringify(state));
} catch (e) {}
}
// Get unique identifier for a chapter (based on its link href or title)
function getChapterId(chapter) {
var link = chapter.querySelector(':scope > a');
if (link) {
return link.getAttribute('href');
}
var title = chapter.querySelector(':scope > .chapter-title');
if (title) {
return 'title:' + title.textContent.trim();
}
return null;
}
// Restore expanded state from localStorage
function restoreExpandedState() {
var state = getExpandedState();
var chapters = sidebar.querySelectorAll('.chapter.expandable');
chapters.forEach(function(chapter) {
var id = getChapterId(chapter);
if (id && state[id] !== undefined) {
if (state[id]) {
chapter.classList.add('expanded');
} else {
// Only close if not in the active path
if (!chapter.classList.contains('active') &&
!chapter.querySelector('.chapter.active')) {
chapter.classList.remove('expanded');
}
}
}
});
}
// Save current expanded state to localStorage
function saveCurrentState() {
var state = {};
var chapters = sidebar.querySelectorAll('.chapter.expandable');
chapters.forEach(function(chapter) {
var id = getChapterId(chapter);
if (id) {
state[id] = chapter.classList.contains('expanded');
}
});
saveExpandedState(state);
}
// Restore state on page load
restoreExpandedState();
// Use event delegation so it works after SPA navigation
sidebar.addEventListener('click', function(e) {
var link = e.target.closest('a');
var titleSpan = e.target.closest('.chapter-title');
// Get the direct parent chapter of the clicked element
var directChapter = (link || titleSpan)?.closest('.chapter');
if (!directChapter) return;
// Only handle if the direct chapter is expandable
if (!directChapter.classList.contains('expandable')) return;
var articles = directChapter.querySelector(':scope > .articles');
if (!articles) return;
// If clicked on chapter-title (no link), toggle expand
if (titleSpan && !link) {
e.preventDefault();
e.stopImmediatePropagation();
directChapter.classList.toggle('expanded');
saveCurrentState();
return;
}
// If clicked on link with children - check click position
// Left side (arrow icon area) = toggle, Right side (text) = navigate
if (link) {
var linkRect = link.getBoundingClientRect();
var clickX = e.clientX - linkRect.left;
// Get actual padding-left of the link (where arrow icon is)
var paddingLeft = parseInt(window.getComputedStyle(link).paddingLeft, 10) || 50;
// Add small margin for easier clicking
var toggleWidth = paddingLeft + 10;
// If clicked on the left arrow area, toggle expand/collapse
if (clickX < toggleWidth) {
e.preventDefault();
e.stopImmediatePropagation();
directChapter.classList.toggle('expanded');
saveCurrentState();
return;
}
// Otherwise, allow normal link navigation (do nothing, let browser handle)
return;
}
});
})();