dsh-nerd-mode 0.5.0 → 0.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/README.md +1 -1
  2. package/README.zh.md +1 -1
  3. package/assets/calibration.svg +69 -69
  4. package/assets/nerd.svg +22 -22
  5. package/assets/section.md +15 -15
  6. package/client.js +2170 -2225
  7. package/cordis.patch.yml +24 -24
  8. package/lib/index.js +838 -286
  9. package/lib/study-sessions.js +283 -283
  10. package/package.json +70 -70
  11. package/skills/convert-documents-to-markdown/SKILL.md +26 -26
  12. package/skills/diagram/SKILL.md +43 -19
  13. package/skills/diagram/scripts/check-svg.mjs +184 -0
  14. package/skills/humanizer/.claude-plugin/marketplace.json +18 -18
  15. package/skills/humanizer/.claude-plugin/plugin.json +15 -15
  16. package/skills/humanizer/.cursor-plugin/plugin.json +12 -12
  17. package/skills/humanizer/.github/ISSUE_TEMPLATE/config.yml +8 -8
  18. package/skills/humanizer/.github/ISSUE_TEMPLATE/new-pattern.yml +24 -24
  19. package/skills/humanizer/.github/ISSUE_TEMPLATE/rewrite-problem.yml +44 -44
  20. package/skills/humanizer/.github/workflows/validate.yml +29 -29
  21. package/skills/humanizer/AGENTS.md +54 -54
  22. package/skills/humanizer/CHANGELOG.md +116 -116
  23. package/skills/humanizer/LICENSE +21 -21
  24. package/skills/humanizer/README.md +206 -206
  25. package/skills/humanizer/SKILL.md +397 -397
  26. package/skills/humanizer/agents/openai.yaml +4 -4
  27. package/skills/humanizer/scripts/validate-package.py +146 -146
  28. package/skills/study/SKILL.md +81 -78
  29. package/skills/study-plus/SKILL.md +246 -246
  30. package/skills/study-plus/scripts/book-client.js +284 -284
  31. package/skills/study-plus/scripts/book-data.mjs +289 -289
  32. package/skills/study-plus/scripts/build-book.mjs +155 -155
  33. package/skills/writing-beats/SKILL.md +66 -66
  34. package/skills/writing-beats/agents/openai.yaml +5 -5
@@ -1,284 +1,284 @@
1
- // Runs inside book.html. It turns am's flat document into a three-column book:
2
- // chapter navigation, one section at a time, page contents, and search.
3
- //
4
- // This file is injected into <head>, not the end of <body>: am's own script
5
- // leaves scripts placed after it inert. init() waits for the DOM.
6
- (function () {
7
- function init() {
8
- var payload = document.getElementById('bk-book');
9
- if (!payload) return;
10
-
11
- var book = JSON.parse(payload.textContent);
12
- var panels = [].slice.call(document.querySelectorAll('.am-doc-body > .am-panel'));
13
- if (!panels.length) return;
14
-
15
- var L = book.lang === 'en'
16
- ? { search: 'Search the book', toc: 'Contents', none: 'No match', hits: ' hits', chapter: 'Chapter', sections: 'sections', menu: 'Chapters', draft: 'Draft' }
17
- : { search: '搜索全书', toc: '目录', none: '没有匹配', hits: ' 处', chapter: '第', sections: '节', menu: '章节', draft: '草稿' };
18
-
19
- var layout = document.querySelector('.am-doc-layout');
20
- var body = document.querySelector('.am-doc-body');
21
- var current = 0;
22
- var timer = 0;
23
-
24
- function esc(s) {
25
- return String(s).replace(/[&<>\"]/g, function (c) {
26
- return { '&': '&amp;', '<': '&lt;', '>': '&gt;', '\"': '&quot;' }[c];
27
- });
28
- }
29
-
30
- function chapterTitle(chapter) {
31
- return book.lang === 'en'
32
- ? L.chapter + ' ' + chapter.n + '. ' + chapter.name
33
- : L.chapter + chapter.n + '章 ' + chapter.name;
34
- }
35
-
36
- function sectionNumber(unit) {
37
- return unit.chapter + '.' + unit.section;
38
- }
39
-
40
- function chapterCount(chapter) {
41
- return book.lang === 'en'
42
- ? chapter.count + (chapter.count === 1 ? ' section included' : ' sections included')
43
- : '已收录 ' + chapter.count + ' ' + L.sections;
44
- }
45
-
46
- function sectionTitle(unit) {
47
- return sectionNumber(unit) + ' ' + unit.title;
48
- }
49
-
50
- var style = document.createElement('style');
51
- style.textContent = [
52
- ':root { --bk-bar: 52px; }',
53
- 'body { padding-top: var(--bk-bar); }',
54
- '.am-doc { max-width: 1440px; padding-top: 4px; }',
55
- '.am-doc > header { display: none !important; }',
56
- '.am-doc-layout, .am-doc-layout--notoc { grid-template-columns: 232px minmax(0, 1fr) 208px !important; max-width: none !important; gap: 28px !important; align-items: start; }',
57
- '.am-toc { display: none !important; }',
58
- '.am-toolbar { top: 10px !important; z-index: 30 !important; }',
59
- '.bk-top { position: fixed; top: 0; left: 0; right: 0; height: var(--bk-bar); z-index: 25; display: flex; align-items: center; gap: 16px; padding: 0 24px; background: var(--paper); border-bottom: 1px solid var(--line-2); }',
60
- '.am-toolbar .am-btn { display: none !important; }',
61
- '.am-panel-id, .am-comment-btn { display: none !important; }',
62
- '.am-doc-body .am-panel { border: 0 !important; background: transparent !important; border-radius: 0 !important; padding: 0 !important; }',
63
- '.am-doc-body .am-panel + .am-panel { margin-top: 0; }',
64
- '.am-doc-body .am-panel-head { padding-bottom: 12px; margin-bottom: 20px; }',
65
- '.am-doc-body .am-panel-head h2 { font-size: 24px; font-weight: 650; line-height: 1.3; }',
66
- '.am-doc-body .am-md h3 { font-size: 18px; font-weight: 650; margin-top: 28px; }',
67
- '.am-doc-body .am-md h3:first-child { margin-top: 0; }',
68
- '.am-doc-body .am-md h4 { font-size: 16px; font-weight: 600; margin-top: 20px; }',
69
- // am's overflow-x:auto makes overflow-y auto too; a 1px overshoot draws scrollbar arrows on Windows.
70
- '.am-math-block { overflow-y: hidden; }',
71
- '.bk-context { display: flex; align-items: baseline; justify-content: space-between; gap: 16px; margin: 0 0 8px; font-size: 13px; }',
72
- '.bk-context-chapter { color: var(--ink-2); font-weight: 600; }',
73
- '.bk-context-section { color: var(--ink-3); white-space: nowrap; }',
74
- '.bk-title { flex: 0 1 auto; min-width: 0; font-weight: 650; font-size: 15px; color: var(--ink); text-decoration: none; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }',
75
- '.bk-search { position: relative; margin-left: 18px; }',
76
- '.bk-search input { width: 210px; height: 30px; padding: 0 10px; border: 1px solid var(--line-2); border-radius: 6px; background: var(--bg); color: var(--ink); font: inherit; font-size: 13px; }',
77
- '.bk-results { position: absolute; top: 36px; right: 0; width: min(300px, calc(100vw - 24px)); margin: 0; padding: 4px; list-style: none; background: var(--paper); border: 1px solid var(--line-2); border-radius: 8px; box-shadow: 0 10px 28px rgba(0,0,0,.14); max-height: 60vh; overflow: auto; z-index: 40; }',
78
- '.bk-results li { padding: 6px 8px; border-radius: 6px; cursor: pointer; font-size: 13px; color: var(--ink); }',
79
- '.bk-results li:hover { background: var(--fill); }',
80
- '.bk-results .bk-n { color: var(--ink-3); font-size: 12px; margin-left: 6px; }',
81
- '.bk-nav { position: sticky; top: calc(var(--bk-bar) + 16px); max-height: calc(100vh - var(--bk-bar) - 40px); overflow: auto; font-size: 13px; padding-right: 6px; }',
82
- '.bk-ch { margin: 0 0 12px; }',
83
- '.bk-ch > summary { cursor: pointer; font-weight: 600; color: var(--ink); padding: 3px 0; }',
84
- '.bk-ch > summary::marker { color: var(--ink-3); }',
85
- '.bk-ch-count { color: var(--ink-3); font-size: 11px; font-weight: 400; margin-left: 6px; white-space: nowrap; }',
86
- '.bk-draft { color: var(--ink-3); border: 1px solid var(--line-2); border-radius: 4px; padding: 0 4px; margin-left: 6px; font-size: 11px; letter-spacing: .02em; vertical-align: middle; text-transform: uppercase; }',
87
- '.bk-u { display: block; padding: 4px 0 4px 12px; margin-left: 2px; color: var(--ink-2); text-decoration: none; border-left: 2px solid var(--line-2); }',
88
- '.bk-u:hover { color: var(--ink); }',
89
- '.bk-u.on { color: var(--accent); border-left-color: var(--accent); font-weight: 600; }',
90
- '.bk-toc { position: sticky; top: calc(var(--bk-bar) + 16px); max-height: calc(100vh - var(--bk-bar) - 40px); overflow: auto; font-size: 12.5px; }',
91
- '.bk-toc-t { color: var(--ink-3); margin-bottom: 6px; }',
92
- '.bk-h { display: block; padding: 3px 0; color: var(--ink-2); text-decoration: none; }',
93
- '.bk-h.lv2 { padding-left: 12px; font-size: 12px; }',
94
- '.bk-h:hover, .bk-h.on { color: var(--accent); }',
95
- '.bk-mobile { display: none; position: relative; }',
96
- '.bk-mobile > summary { list-style: none; cursor: pointer; color: var(--ink); font-size: 12px; padding: 6px 8px; border: 1px solid var(--line-2); border-radius: 6px; white-space: nowrap; }',
97
- '.bk-mobile > summary::-webkit-details-marker { display: none; }',
98
- '.bk-mobile-list { position: absolute; top: calc(100% + 8px); right: 0; width: min(300px, calc(100vw - 24px)); max-height: calc(100vh - var(--bk-bar) - 24px); overflow: auto; padding: 12px; background: var(--paper); border: 1px solid var(--line-2); border-radius: 8px; box-shadow: 0 10px 28px rgba(0,0,0,.14); z-index: 40; }',
99
- '.bk-nav-mobile { position: static; max-height: none; overflow: visible; padding-right: 0; }',
100
- '.am-panel[hidden] { display: none !important; }',
101
- '@media print { .bk-nav, .bk-toc, .bk-top, .am-toolbar { display: none !important; } body { padding-top: 0; } .am-panel[hidden] { display: block !important; } }',
102
- '@media (max-width: 1100px) { .bk-toc { display: none; } .am-doc-layout, .am-doc-layout--notoc { grid-template-columns: 200px minmax(0, 1fr) !important; } }',
103
- '@media (max-width: 800px) { .bk-top { gap: 8px; padding: 0 12px; } .bk-title { flex: 1 1 0; } .bk-search { margin-left: auto; } .bk-search input { width: clamp(88px, 34vw, 150px); } .bk-mobile { display: block; } .bk-nav { display: none; } .bk-nav-mobile { display: block; } .am-doc-layout, .am-doc-layout--notoc { grid-template-columns: minmax(0, 1fr) !important; } .bk-context { flex-wrap: wrap; } .bk-context-section { white-space: normal; } }'
104
- ].join('\n');
105
- document.head.appendChild(style);
106
-
107
- var top = document.createElement('header');
108
- top.className = 'bk-top';
109
- top.innerHTML =
110
- '<a class="bk-title" href="#' + esc(panels[0].id) + '">' + esc(book.title) + '</a>' +
111
- '<div class="bk-search"><input id="bk-q" type="search" placeholder="' + L.search + '" aria-label="' + L.search + '"><ul id="bk-results" class="bk-results" hidden></ul></div>' +
112
- '<details class="bk-mobile"><summary>' + L.menu + '</summary><div class="bk-mobile-list"><nav class="bk-nav bk-nav-mobile"></nav></div></details>';
113
- document.body.appendChild(top);
114
-
115
- var nav = document.createElement('nav');
116
- nav.className = 'bk-nav';
117
- var groups = (book.chapters || []).map(function (chapter) { return { chapter: chapter, units: [] }; });
118
- book.units.forEach(function (u) {
119
- for (var i = 0; i < groups.length; i++) {
120
- if (groups[i].chapter.n === u.chapter) {
121
- groups[i].units.push(u);
122
- break;
123
- }
124
- }
125
- });
126
-
127
- function draftTag(u) {
128
- return u.status === 'draft' ? '<span class="bk-draft">' + esc(L.draft) + '</span>' : '';
129
- }
130
-
131
- function link(u) {
132
- var index = Number(u.index);
133
- return '<a class="bk-u" href="#' + esc(panels[index].id) + '" data-i="' + esc(index) + '">' +
134
- esc(sectionTitle(u)) + draftTag(u) + '</a>';
135
- }
136
-
137
- var navHtml = '';
138
- groups.forEach(function (g) {
139
- if (!g.units.length) return;
140
- navHtml += '<details class="bk-ch" open><summary>' + esc(chapterTitle(g.chapter)) +
141
- '<span class="bk-ch-count">' + esc(chapterCount(g.chapter)) + '</span></summary>' +
142
- g.units.map(link).join('') + '</details>';
143
- g.units.forEach(function (u) {
144
- var panel = panels[Number(u.index)];
145
- var context = document.createElement('div');
146
- context.className = 'bk-context';
147
- var chapter = document.createElement('span');
148
- chapter.className = 'bk-context-chapter';
149
- chapter.textContent = chapterTitle(g.chapter);
150
- var section = document.createElement('span');
151
- section.className = 'bk-context-section';
152
- section.innerHTML = esc(sectionNumber(u)) + draftTag(u);
153
- context.appendChild(chapter);
154
- context.appendChild(section);
155
- var heading = panel.querySelector('.am-panel-head');
156
- panel.insertBefore(context, heading || panel.firstChild);
157
- });
158
- });
159
- nav.innerHTML = navHtml;
160
- layout.insertBefore(nav, body);
161
- var mobileNav = top.querySelector('.bk-nav-mobile');
162
- mobileNav.innerHTML = navHtml;
163
- var mobileMenu = top.querySelector('.bk-mobile');
164
-
165
- var toc = document.createElement('aside');
166
- toc.className = 'bk-toc';
167
- layout.appendChild(toc);
168
-
169
- function buildToc(i) {
170
- var heads = [].slice.call(panels[i].querySelectorAll('h3, h4'));
171
- if (!heads.length) { toc.innerHTML = ''; toc.hidden = true; return; }
172
- toc.hidden = false;
173
- toc.innerHTML = '<div class="bk-toc-t">' + L.toc + '</div>' + heads.map(function (h, k) {
174
- if (!h.id) h.id = panels[i].id + '-h' + k;
175
- return '<a class="bk-h' + (h.tagName === 'H4' ? ' lv2' : '') + '" href="#' + esc(h.id) + '" data-t="' + esc(h.id) + '">' + esc(h.textContent) + '</a>';
176
- }).join('');
177
- }
178
-
179
- function show(i, silent) {
180
- current = i;
181
- panels.forEach(function (p, j) { p.hidden = j !== i; });
182
- [nav, mobileNav].forEach(function (menu) {
183
- [].forEach.call(menu.querySelectorAll('.bk-u'), function (a) {
184
- a.classList.toggle('on', Number(a.dataset.i) === i);
185
- });
186
- });
187
- buildToc(i);
188
- if (!silent) history.replaceState(null, '', '#' + panels[i].id);
189
- window.scrollTo(0, 0);
190
- spy();
191
- }
192
-
193
- function bindNavigation(menu, isMobile) {
194
- menu.addEventListener('click', function (e) {
195
- var a = e.target.closest('.bk-u');
196
- if (!a) return;
197
- e.preventDefault();
198
- show(Number(a.dataset.i));
199
- if (isMobile) mobileMenu.open = false;
200
- });
201
- }
202
-
203
- bindNavigation(nav, false);
204
- bindNavigation(mobileNav, true);
205
-
206
- toc.addEventListener('click', function (e) {
207
- var a = e.target.closest('.bk-h');
208
- if (!a) return;
209
- e.preventDefault();
210
- var h = document.getElementById(a.dataset.t);
211
- if (h) h.scrollIntoView({ block: 'start', behavior: 'smooth' });
212
- });
213
-
214
- function spy() {
215
- var heads = [].slice.call(panels[current].querySelectorAll('h3, h4'));
216
- if (!heads.length) return;
217
- var line = window.scrollY + 120;
218
- var active = heads[0];
219
- heads.forEach(function (h) { if (h.getBoundingClientRect().top + window.scrollY <= line) active = h; });
220
- [].forEach.call(toc.querySelectorAll('.bk-h'), function (a) {
221
- a.classList.toggle('on', a.dataset.t === active.id);
222
- });
223
- }
224
-
225
- window.addEventListener('scroll', function () {
226
- clearTimeout(timer);
227
- timer = setTimeout(spy, 90);
228
- }, { passive: true });
229
-
230
- var q = document.getElementById('bk-q');
231
- var results = document.getElementById('bk-results');
232
-
233
- q.addEventListener('input', function () {
234
- var term = q.value.trim();
235
- if (term.length < 2) { results.hidden = true; results.innerHTML = ''; return; }
236
- var lower = term.toLowerCase();
237
- var hits = [];
238
- book.units.forEach(function (u) {
239
- var text = panels[u.index].textContent.toLowerCase();
240
- var n = text.split(lower).length - 1;
241
- if (n) hits.push({ u: u, n: n });
242
- });
243
- if (!hits.length) {
244
- results.innerHTML = '<li>' + L.none + '</li>';
245
- } else {
246
- results.innerHTML = hits.slice(0, 8).map(function (h) {
247
- return '<li data-i="' + esc(h.u.index) + '">' + esc(sectionTitle(h.u)) +
248
- '<span class="bk-n">' + h.n + L.hits + '</span></li>';
249
- }).join('');
250
- }
251
- results.hidden = false;
252
- });
253
-
254
- results.addEventListener('click', function (e) {
255
- var li = e.target.closest('li[data-i]');
256
- if (!li) return;
257
- var i = Number(li.dataset.i);
258
- var term = q.value.trim();
259
- show(i);
260
- results.hidden = true;
261
- // shortcut: window.find is Chromium-only and jumps to the first match;
262
- // the unit still opens when the host lacks it.
263
- setTimeout(function () {
264
- try { window.find(term, false, false, true); } catch (err) { /* no jump */ }
265
- }, 60);
266
- });
267
-
268
- document.addEventListener('click', function (e) {
269
- if (!e.target.closest('.bk-search')) results.hidden = true;
270
- });
271
-
272
- var start = 0;
273
- var hash = decodeURIComponent(location.hash.slice(1));
274
- for (var i = 0; i < panels.length; i++) if (panels[i].id === hash) start = i;
275
- show(start, !hash);
276
- }
277
-
278
- if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', boot);
279
- else boot();
280
-
281
- function boot() {
282
- try { init(); } catch (e) { console.error('[book]', e); }
283
- }
284
- })();
1
+ // Runs inside book.html. It turns am's flat document into a three-column book:
2
+ // chapter navigation, one section at a time, page contents, and search.
3
+ //
4
+ // This file is injected into <head>, not the end of <body>: am's own script
5
+ // leaves scripts placed after it inert. init() waits for the DOM.
6
+ (function () {
7
+ function init() {
8
+ var payload = document.getElementById('bk-book');
9
+ if (!payload) return;
10
+
11
+ var book = JSON.parse(payload.textContent);
12
+ var panels = [].slice.call(document.querySelectorAll('.am-doc-body > .am-panel'));
13
+ if (!panels.length) return;
14
+
15
+ var L = book.lang === 'en'
16
+ ? { search: 'Search the book', toc: 'Contents', none: 'No match', hits: ' hits', chapter: 'Chapter', sections: 'sections', menu: 'Chapters', draft: 'Draft' }
17
+ : { search: '搜索全书', toc: '目录', none: '没有匹配', hits: ' 处', chapter: '第', sections: '节', menu: '章节', draft: '草稿' };
18
+
19
+ var layout = document.querySelector('.am-doc-layout');
20
+ var body = document.querySelector('.am-doc-body');
21
+ var current = 0;
22
+ var timer = 0;
23
+
24
+ function esc(s) {
25
+ return String(s).replace(/[&<>\"]/g, function (c) {
26
+ return { '&': '&amp;', '<': '&lt;', '>': '&gt;', '\"': '&quot;' }[c];
27
+ });
28
+ }
29
+
30
+ function chapterTitle(chapter) {
31
+ return book.lang === 'en'
32
+ ? L.chapter + ' ' + chapter.n + '. ' + chapter.name
33
+ : L.chapter + chapter.n + '章 ' + chapter.name;
34
+ }
35
+
36
+ function sectionNumber(unit) {
37
+ return unit.chapter + '.' + unit.section;
38
+ }
39
+
40
+ function chapterCount(chapter) {
41
+ return book.lang === 'en'
42
+ ? chapter.count + (chapter.count === 1 ? ' section included' : ' sections included')
43
+ : '已收录 ' + chapter.count + ' ' + L.sections;
44
+ }
45
+
46
+ function sectionTitle(unit) {
47
+ return sectionNumber(unit) + ' ' + unit.title;
48
+ }
49
+
50
+ var style = document.createElement('style');
51
+ style.textContent = [
52
+ ':root { --bk-bar: 52px; }',
53
+ 'body { padding-top: var(--bk-bar); }',
54
+ '.am-doc { max-width: 1440px; padding-top: 4px; }',
55
+ '.am-doc > header { display: none !important; }',
56
+ '.am-doc-layout, .am-doc-layout--notoc { grid-template-columns: 232px minmax(0, 1fr) 208px !important; max-width: none !important; gap: 28px !important; align-items: start; }',
57
+ '.am-toc { display: none !important; }',
58
+ '.am-toolbar { top: 10px !important; z-index: 30 !important; }',
59
+ '.bk-top { position: fixed; top: 0; left: 0; right: 0; height: var(--bk-bar); z-index: 25; display: flex; align-items: center; gap: 16px; padding: 0 24px; background: var(--paper); border-bottom: 1px solid var(--line-2); }',
60
+ '.am-toolbar .am-btn { display: none !important; }',
61
+ '.am-panel-id, .am-comment-btn { display: none !important; }',
62
+ '.am-doc-body .am-panel { border: 0 !important; background: transparent !important; border-radius: 0 !important; padding: 0 !important; }',
63
+ '.am-doc-body .am-panel + .am-panel { margin-top: 0; }',
64
+ '.am-doc-body .am-panel-head { padding-bottom: 12px; margin-bottom: 20px; }',
65
+ '.am-doc-body .am-panel-head h2 { font-size: 24px; font-weight: 650; line-height: 1.3; }',
66
+ '.am-doc-body .am-md h3 { font-size: 18px; font-weight: 650; margin-top: 28px; }',
67
+ '.am-doc-body .am-md h3:first-child { margin-top: 0; }',
68
+ '.am-doc-body .am-md h4 { font-size: 16px; font-weight: 600; margin-top: 20px; }',
69
+ // am's overflow-x:auto makes overflow-y auto too; a 1px overshoot draws scrollbar arrows on Windows.
70
+ '.am-math-block { overflow-y: hidden; }',
71
+ '.bk-context { display: flex; align-items: baseline; justify-content: space-between; gap: 16px; margin: 0 0 8px; font-size: 13px; }',
72
+ '.bk-context-chapter { color: var(--ink-2); font-weight: 600; }',
73
+ '.bk-context-section { color: var(--ink-3); white-space: nowrap; }',
74
+ '.bk-title { flex: 0 1 auto; min-width: 0; font-weight: 650; font-size: 15px; color: var(--ink); text-decoration: none; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }',
75
+ '.bk-search { position: relative; margin-left: 18px; }',
76
+ '.bk-search input { width: 210px; height: 30px; padding: 0 10px; border: 1px solid var(--line-2); border-radius: 6px; background: var(--bg); color: var(--ink); font: inherit; font-size: 13px; }',
77
+ '.bk-results { position: absolute; top: 36px; right: 0; width: min(300px, calc(100vw - 24px)); margin: 0; padding: 4px; list-style: none; background: var(--paper); border: 1px solid var(--line-2); border-radius: 8px; box-shadow: 0 10px 28px rgba(0,0,0,.14); max-height: 60vh; overflow: auto; z-index: 40; }',
78
+ '.bk-results li { padding: 6px 8px; border-radius: 6px; cursor: pointer; font-size: 13px; color: var(--ink); }',
79
+ '.bk-results li:hover { background: var(--fill); }',
80
+ '.bk-results .bk-n { color: var(--ink-3); font-size: 12px; margin-left: 6px; }',
81
+ '.bk-nav { position: sticky; top: calc(var(--bk-bar) + 16px); max-height: calc(100vh - var(--bk-bar) - 40px); overflow: auto; font-size: 13px; padding-right: 6px; }',
82
+ '.bk-ch { margin: 0 0 12px; }',
83
+ '.bk-ch > summary { cursor: pointer; font-weight: 600; color: var(--ink); padding: 3px 0; }',
84
+ '.bk-ch > summary::marker { color: var(--ink-3); }',
85
+ '.bk-ch-count { color: var(--ink-3); font-size: 11px; font-weight: 400; margin-left: 6px; white-space: nowrap; }',
86
+ '.bk-draft { color: var(--ink-3); border: 1px solid var(--line-2); border-radius: 4px; padding: 0 4px; margin-left: 6px; font-size: 11px; letter-spacing: .02em; vertical-align: middle; text-transform: uppercase; }',
87
+ '.bk-u { display: block; padding: 4px 0 4px 12px; margin-left: 2px; color: var(--ink-2); text-decoration: none; border-left: 2px solid var(--line-2); }',
88
+ '.bk-u:hover { color: var(--ink); }',
89
+ '.bk-u.on { color: var(--accent); border-left-color: var(--accent); font-weight: 600; }',
90
+ '.bk-toc { position: sticky; top: calc(var(--bk-bar) + 16px); max-height: calc(100vh - var(--bk-bar) - 40px); overflow: auto; font-size: 12.5px; }',
91
+ '.bk-toc-t { color: var(--ink-3); margin-bottom: 6px; }',
92
+ '.bk-h { display: block; padding: 3px 0; color: var(--ink-2); text-decoration: none; }',
93
+ '.bk-h.lv2 { padding-left: 12px; font-size: 12px; }',
94
+ '.bk-h:hover, .bk-h.on { color: var(--accent); }',
95
+ '.bk-mobile { display: none; position: relative; }',
96
+ '.bk-mobile > summary { list-style: none; cursor: pointer; color: var(--ink); font-size: 12px; padding: 6px 8px; border: 1px solid var(--line-2); border-radius: 6px; white-space: nowrap; }',
97
+ '.bk-mobile > summary::-webkit-details-marker { display: none; }',
98
+ '.bk-mobile-list { position: absolute; top: calc(100% + 8px); right: 0; width: min(300px, calc(100vw - 24px)); max-height: calc(100vh - var(--bk-bar) - 24px); overflow: auto; padding: 12px; background: var(--paper); border: 1px solid var(--line-2); border-radius: 8px; box-shadow: 0 10px 28px rgba(0,0,0,.14); z-index: 40; }',
99
+ '.bk-nav-mobile { position: static; max-height: none; overflow: visible; padding-right: 0; }',
100
+ '.am-panel[hidden] { display: none !important; }',
101
+ '@media print { .bk-nav, .bk-toc, .bk-top, .am-toolbar { display: none !important; } body { padding-top: 0; } .am-panel[hidden] { display: block !important; } }',
102
+ '@media (max-width: 1100px) { .bk-toc { display: none; } .am-doc-layout, .am-doc-layout--notoc { grid-template-columns: 200px minmax(0, 1fr) !important; } }',
103
+ '@media (max-width: 800px) { .bk-top { gap: 8px; padding: 0 12px; } .bk-title { flex: 1 1 0; } .bk-search { margin-left: auto; } .bk-search input { width: clamp(88px, 34vw, 150px); } .bk-mobile { display: block; } .bk-nav { display: none; } .bk-nav-mobile { display: block; } .am-doc-layout, .am-doc-layout--notoc { grid-template-columns: minmax(0, 1fr) !important; } .bk-context { flex-wrap: wrap; } .bk-context-section { white-space: normal; } }'
104
+ ].join('\n');
105
+ document.head.appendChild(style);
106
+
107
+ var top = document.createElement('header');
108
+ top.className = 'bk-top';
109
+ top.innerHTML =
110
+ '<a class="bk-title" href="#' + esc(panels[0].id) + '">' + esc(book.title) + '</a>' +
111
+ '<div class="bk-search"><input id="bk-q" type="search" placeholder="' + L.search + '" aria-label="' + L.search + '"><ul id="bk-results" class="bk-results" hidden></ul></div>' +
112
+ '<details class="bk-mobile"><summary>' + L.menu + '</summary><div class="bk-mobile-list"><nav class="bk-nav bk-nav-mobile"></nav></div></details>';
113
+ document.body.appendChild(top);
114
+
115
+ var nav = document.createElement('nav');
116
+ nav.className = 'bk-nav';
117
+ var groups = (book.chapters || []).map(function (chapter) { return { chapter: chapter, units: [] }; });
118
+ book.units.forEach(function (u) {
119
+ for (var i = 0; i < groups.length; i++) {
120
+ if (groups[i].chapter.n === u.chapter) {
121
+ groups[i].units.push(u);
122
+ break;
123
+ }
124
+ }
125
+ });
126
+
127
+ function draftTag(u) {
128
+ return u.status === 'draft' ? '<span class="bk-draft">' + esc(L.draft) + '</span>' : '';
129
+ }
130
+
131
+ function link(u) {
132
+ var index = Number(u.index);
133
+ return '<a class="bk-u" href="#' + esc(panels[index].id) + '" data-i="' + esc(index) + '">' +
134
+ esc(sectionTitle(u)) + draftTag(u) + '</a>';
135
+ }
136
+
137
+ var navHtml = '';
138
+ groups.forEach(function (g) {
139
+ if (!g.units.length) return;
140
+ navHtml += '<details class="bk-ch" open><summary>' + esc(chapterTitle(g.chapter)) +
141
+ '<span class="bk-ch-count">' + esc(chapterCount(g.chapter)) + '</span></summary>' +
142
+ g.units.map(link).join('') + '</details>';
143
+ g.units.forEach(function (u) {
144
+ var panel = panels[Number(u.index)];
145
+ var context = document.createElement('div');
146
+ context.className = 'bk-context';
147
+ var chapter = document.createElement('span');
148
+ chapter.className = 'bk-context-chapter';
149
+ chapter.textContent = chapterTitle(g.chapter);
150
+ var section = document.createElement('span');
151
+ section.className = 'bk-context-section';
152
+ section.innerHTML = esc(sectionNumber(u)) + draftTag(u);
153
+ context.appendChild(chapter);
154
+ context.appendChild(section);
155
+ var heading = panel.querySelector('.am-panel-head');
156
+ panel.insertBefore(context, heading || panel.firstChild);
157
+ });
158
+ });
159
+ nav.innerHTML = navHtml;
160
+ layout.insertBefore(nav, body);
161
+ var mobileNav = top.querySelector('.bk-nav-mobile');
162
+ mobileNav.innerHTML = navHtml;
163
+ var mobileMenu = top.querySelector('.bk-mobile');
164
+
165
+ var toc = document.createElement('aside');
166
+ toc.className = 'bk-toc';
167
+ layout.appendChild(toc);
168
+
169
+ function buildToc(i) {
170
+ var heads = [].slice.call(panels[i].querySelectorAll('h3, h4'));
171
+ if (!heads.length) { toc.innerHTML = ''; toc.hidden = true; return; }
172
+ toc.hidden = false;
173
+ toc.innerHTML = '<div class="bk-toc-t">' + L.toc + '</div>' + heads.map(function (h, k) {
174
+ if (!h.id) h.id = panels[i].id + '-h' + k;
175
+ return '<a class="bk-h' + (h.tagName === 'H4' ? ' lv2' : '') + '" href="#' + esc(h.id) + '" data-t="' + esc(h.id) + '">' + esc(h.textContent) + '</a>';
176
+ }).join('');
177
+ }
178
+
179
+ function show(i, silent) {
180
+ current = i;
181
+ panels.forEach(function (p, j) { p.hidden = j !== i; });
182
+ [nav, mobileNav].forEach(function (menu) {
183
+ [].forEach.call(menu.querySelectorAll('.bk-u'), function (a) {
184
+ a.classList.toggle('on', Number(a.dataset.i) === i);
185
+ });
186
+ });
187
+ buildToc(i);
188
+ if (!silent) history.replaceState(null, '', '#' + panels[i].id);
189
+ window.scrollTo(0, 0);
190
+ spy();
191
+ }
192
+
193
+ function bindNavigation(menu, isMobile) {
194
+ menu.addEventListener('click', function (e) {
195
+ var a = e.target.closest('.bk-u');
196
+ if (!a) return;
197
+ e.preventDefault();
198
+ show(Number(a.dataset.i));
199
+ if (isMobile) mobileMenu.open = false;
200
+ });
201
+ }
202
+
203
+ bindNavigation(nav, false);
204
+ bindNavigation(mobileNav, true);
205
+
206
+ toc.addEventListener('click', function (e) {
207
+ var a = e.target.closest('.bk-h');
208
+ if (!a) return;
209
+ e.preventDefault();
210
+ var h = document.getElementById(a.dataset.t);
211
+ if (h) h.scrollIntoView({ block: 'start', behavior: 'smooth' });
212
+ });
213
+
214
+ function spy() {
215
+ var heads = [].slice.call(panels[current].querySelectorAll('h3, h4'));
216
+ if (!heads.length) return;
217
+ var line = window.scrollY + 120;
218
+ var active = heads[0];
219
+ heads.forEach(function (h) { if (h.getBoundingClientRect().top + window.scrollY <= line) active = h; });
220
+ [].forEach.call(toc.querySelectorAll('.bk-h'), function (a) {
221
+ a.classList.toggle('on', a.dataset.t === active.id);
222
+ });
223
+ }
224
+
225
+ window.addEventListener('scroll', function () {
226
+ clearTimeout(timer);
227
+ timer = setTimeout(spy, 90);
228
+ }, { passive: true });
229
+
230
+ var q = document.getElementById('bk-q');
231
+ var results = document.getElementById('bk-results');
232
+
233
+ q.addEventListener('input', function () {
234
+ var term = q.value.trim();
235
+ if (term.length < 2) { results.hidden = true; results.innerHTML = ''; return; }
236
+ var lower = term.toLowerCase();
237
+ var hits = [];
238
+ book.units.forEach(function (u) {
239
+ var text = panels[u.index].textContent.toLowerCase();
240
+ var n = text.split(lower).length - 1;
241
+ if (n) hits.push({ u: u, n: n });
242
+ });
243
+ if (!hits.length) {
244
+ results.innerHTML = '<li>' + L.none + '</li>';
245
+ } else {
246
+ results.innerHTML = hits.slice(0, 8).map(function (h) {
247
+ return '<li data-i="' + esc(h.u.index) + '">' + esc(sectionTitle(h.u)) +
248
+ '<span class="bk-n">' + h.n + L.hits + '</span></li>';
249
+ }).join('');
250
+ }
251
+ results.hidden = false;
252
+ });
253
+
254
+ results.addEventListener('click', function (e) {
255
+ var li = e.target.closest('li[data-i]');
256
+ if (!li) return;
257
+ var i = Number(li.dataset.i);
258
+ var term = q.value.trim();
259
+ show(i);
260
+ results.hidden = true;
261
+ // shortcut: window.find is Chromium-only and jumps to the first match;
262
+ // the unit still opens when the host lacks it.
263
+ setTimeout(function () {
264
+ try { window.find(term, false, false, true); } catch (err) { /* no jump */ }
265
+ }, 60);
266
+ });
267
+
268
+ document.addEventListener('click', function (e) {
269
+ if (!e.target.closest('.bk-search')) results.hidden = true;
270
+ });
271
+
272
+ var start = 0;
273
+ var hash = decodeURIComponent(location.hash.slice(1));
274
+ for (var i = 0; i < panels.length; i++) if (panels[i].id === hash) start = i;
275
+ show(start, !hash);
276
+ }
277
+
278
+ if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', boot);
279
+ else boot();
280
+
281
+ function boot() {
282
+ try { init(); } catch (e) { console.error('[book]', e); }
283
+ }
284
+ })();