@knowcode/doc-builder 1.4.1 → 1.4.3

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.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,26 @@ All notable changes to @knowcode/doc-builder will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [1.4.3] - 2025-07-20
9
+
10
+ ### Fixed
11
+ - Restored tooltip functionality by adding back the extractSummary function
12
+ - Added data-tooltip attributes to navigation items showing document summaries
13
+ - Removed unwanted Home link from sidebar breadcrumbs section
14
+ - Navigation items now display helpful summaries on hover
15
+
16
+ ### Technical Details
17
+ - extractSummary function extracts first 150 characters of meaningful content
18
+ - Tooltips are properly escaped for HTML safety
19
+ - Sidebar header simplified by removing redundant breadcrumb navigation
20
+
21
+ ## [1.4.2] - 2025-01-20
22
+
23
+ ### Fixed
24
+ - Fixed excessive left padding on content area by removing JavaScript margin-left assignments
25
+ - Content layout now properly uses flexbox spacing without manual margin adjustments
26
+ - The JavaScript was adding inline `style="margin-left: 200px;"` which was causing the issue
27
+
8
28
  ## [1.4.1] - 2025-07-20
9
29
 
10
30
  ### Fixed
@@ -125,8 +125,8 @@
125
125
  /* Layout */
126
126
  --container-padding-mobile: 20px;
127
127
  --container-padding-desktop: 40px;
128
- --header-height: 64px;
129
- --breadcrumb-height: 40px;
128
+ --header-height: 40px;
129
+ --breadcrumb-height: 0px;
130
130
  --sidebar-width: 280px;
131
131
  }
132
132
 
@@ -169,6 +169,7 @@ h2 {
169
169
  h3 {
170
170
  font-size: var(--text-xl);
171
171
  margin-top: var(--space-8);
172
+ margin-bottom: var(--space-4);
172
173
  }
173
174
 
174
175
  h4 {
@@ -332,7 +333,42 @@ pre code {
332
333
  top: calc(var(--header-height) + var(--breadcrumb-height) + 3.5rem);
333
334
  }
334
335
 
335
- /* Sidebar header styles moved to main sidebar section */
336
+ .sidebar-header {
337
+ padding: var(--space-4);
338
+ border-bottom: 1px solid var(--color-border-default);
339
+ margin-bottom: var(--space-4);
340
+ }
341
+
342
+ /* Sidebar Breadcrumbs */
343
+ .sidebar-breadcrumbs {
344
+ margin-bottom: var(--space-3);
345
+ }
346
+
347
+ .sidebar-home-link {
348
+ display: inline-flex;
349
+ align-items: center;
350
+ gap: var(--space-2);
351
+ padding: var(--space-2) var(--space-3);
352
+ color: var(--color-text-secondary);
353
+ text-decoration: none;
354
+ border-radius: var(--radius-base);
355
+ font-size: 0.875rem;
356
+ font-weight: 500;
357
+ transition: all 0.2s;
358
+ }
359
+
360
+ .sidebar-home-link:hover {
361
+ background: var(--color-bg-secondary);
362
+ color: var(--color-text-primary);
363
+ }
364
+
365
+ .sidebar-home-link i {
366
+ font-size: 1rem;
367
+ }
368
+
369
+ .filter-box {
370
+ position: relative;
371
+ }
336
372
 
337
373
  .filter-input {
338
374
  width: 100%;
@@ -493,6 +529,12 @@ pre code {
493
529
  .sidebar-header {
494
530
  padding: var(--space-3);
495
531
  border-bottom: 1px solid var(--color-border-default);
532
+ margin-bottom: var(--space-4);
533
+ }
534
+
535
+ /* Already defined above, but ensure consistency */
536
+ .sidebar-breadcrumbs {
537
+ margin-bottom: var(--space-3);
496
538
  }
497
539
 
498
540
  .filter-box {
@@ -683,11 +725,21 @@ pre code {
683
725
  }
684
726
 
685
727
  /* Main Content */
686
- /* Removed duplicate .main-wrapper - using the one defined earlier */
728
+ .main-wrapper {
729
+ display: flex;
730
+ padding-top: calc(var(--header-height) + var(--breadcrumb-height));
731
+ min-height: 100vh;
732
+ transition: padding-top var(--duration-normal);
733
+ }
734
+
735
+ /* Adjust layout when banner is visible */
736
+ .main-wrapper.banner-visible {
737
+ padding-top: calc(var(--header-height) + var(--breadcrumb-height) + 3.5rem);
738
+ }
687
739
 
688
740
  .content {
689
741
  flex: 1;
690
- padding: var(--space-6) var(--space-8);
742
+ padding: 40px var(--space-8);
691
743
  overflow-y: auto;
692
744
  background: var(--color-bg-default);
693
745
  }
@@ -788,6 +840,7 @@ tr:hover {
788
840
  border: 1px solid var(--color-border-default);
789
841
  border-radius: var(--radius-lg);
790
842
  padding: var(--space-6);
843
+ margin-bottom: var(--space-4);
791
844
  box-shadow: var(--shadow-sm);
792
845
  transition: all var(--duration-normal) var(--easing-out);
793
846
  }
@@ -970,43 +1023,6 @@ tr:hover {
970
1023
  cursor: pointer;
971
1024
  color: var(--color-text-primary);
972
1025
  padding: var(--space-2);
973
- margin-left: var(--space-2);
974
- transition: color var(--duration-fast);
975
- z-index: 1001;
976
- }
977
-
978
- .menu-toggle:hover {
979
- color: var(--color-accent-blue);
980
- }
981
-
982
- .menu-toggle.active i::before {
983
- content: "\f00d"; /* fa-times icon */
984
- }
985
-
986
- /* Mobile Sidebar Overlay */
987
- .sidebar-overlay {
988
- position: fixed;
989
- top: 0;
990
- left: 0;
991
- right: 0;
992
- bottom: 0;
993
- background: var(--color-bg-overlay);
994
- z-index: 998;
995
- opacity: 0;
996
- visibility: hidden;
997
- transition: opacity var(--duration-normal), visibility var(--duration-normal);
998
- display: none;
999
- }
1000
-
1001
- @media (max-width: 1024px) {
1002
- .sidebar-overlay {
1003
- display: block;
1004
- }
1005
- }
1006
-
1007
- .sidebar-overlay.active {
1008
- opacity: 1;
1009
- visibility: visible;
1010
1026
  }
1011
1027
 
1012
1028
  /* Responsive Design */
@@ -1014,8 +1030,6 @@ tr:hover {
1014
1030
  .sidebar {
1015
1031
  transform: translateX(-100%);
1016
1032
  transition: transform var(--duration-normal) var(--easing-out);
1017
- z-index: 999;
1018
- box-shadow: 2px 0 10px rgba(0, 0, 0, 0.1);
1019
1033
  }
1020
1034
 
1021
1035
  .sidebar.open {
@@ -1027,6 +1041,7 @@ tr:hover {
1027
1041
  }
1028
1042
 
1029
1043
  .content {
1044
+ margin-left: 0;
1030
1045
  padding: var(--space-6) var(--space-4);
1031
1046
  }
1032
1047
 
@@ -1434,6 +1449,7 @@ tr:hover {
1434
1449
  font-size: var(--text-lg);
1435
1450
  font-weight: var(--font-semibold);
1436
1451
  color: var(--color-text-primary);
1452
+ margin-bottom: var(--space-4);
1437
1453
  padding-bottom: var(--space-2);
1438
1454
  border-bottom: 2px solid var(--color-divider);
1439
1455
  }
@@ -1806,9 +1822,11 @@ tr:hover {
1806
1822
  .auth-box p {
1807
1823
  color: var(--color-text-secondary);
1808
1824
  text-align: center;
1825
+ margin-bottom: var(--space-4);
1809
1826
  }
1810
1827
 
1811
1828
  .form-group {
1829
+ margin-bottom: var(--space-4);
1812
1830
  }
1813
1831
 
1814
1832
  .form-group label {
package/assets/js/main.js CHANGED
@@ -511,30 +511,10 @@ function updateThemeIcon(theme) {
511
511
  // Mobile Menu Toggle
512
512
  const menuToggle = document.getElementById('menu-toggle');
513
513
  const sidebar = document.querySelector('.sidebar');
514
- const sidebarOverlay = document.querySelector('.sidebar-overlay');
515
514
 
516
515
  if (menuToggle) {
517
516
  menuToggle.addEventListener('click', () => {
518
517
  sidebar.classList.toggle('open');
519
- sidebarOverlay.classList.toggle('active');
520
- menuToggle.classList.toggle('active');
521
-
522
- // Prevent body scroll when menu is open
523
- if (sidebar.classList.contains('open')) {
524
- document.body.style.overflow = 'hidden';
525
- } else {
526
- document.body.style.overflow = '';
527
- }
528
- });
529
- }
530
-
531
- // Close sidebar when clicking overlay
532
- if (sidebarOverlay) {
533
- sidebarOverlay.addEventListener('click', () => {
534
- sidebar.classList.remove('open');
535
- sidebarOverlay.classList.remove('active');
536
- menuToggle.classList.remove('active');
537
- document.body.style.overflow = '';
538
518
  });
539
519
  }
540
520
 
@@ -542,17 +522,14 @@ if (sidebarOverlay) {
542
522
  // Only close when clicking outside the sidebar or the close button
543
523
  document.addEventListener('click', (e) => {
544
524
  // Check if we're on mobile
545
- if (window.innerWidth <= 1024) {
525
+ if (window.innerWidth <= 768) {
546
526
  const isClickInsideSidebar = sidebar && sidebar.contains(e.target);
547
527
  const isMenuToggle = e.target.closest('#menu-toggle');
548
- const isOverlay = e.target.closest('.sidebar-overlay');
528
+ const isNavItem = e.target.closest('.nav-item, .nav-title');
549
529
 
550
- // Close sidebar when clicking nav items on mobile
551
- if (e.target.closest('.nav-item') && sidebar?.classList.contains('open')) {
530
+ // Close sidebar only if clicking outside AND not on menu toggle AND not on nav items
531
+ if (!isClickInsideSidebar && !isMenuToggle && !isNavItem && sidebar?.classList.contains('open')) {
552
532
  sidebar.classList.remove('open');
553
- sidebarOverlay?.classList.remove('active');
554
- menuToggle?.classList.remove('active');
555
- document.body.style.overflow = '';
556
533
  }
557
534
  }
558
535
  });
@@ -689,9 +666,6 @@ document.addEventListener('keydown', (e) => {
689
666
  // Escape to close mobile menu
690
667
  if (e.key === 'Escape') {
691
668
  sidebar?.classList.remove('open');
692
- sidebarOverlay?.classList.remove('active');
693
- menuToggle?.classList.remove('active');
694
- document.body.style.overflow = '';
695
669
  }
696
670
  });
697
671
 
@@ -730,7 +704,7 @@ function initSidebarResize() {
730
704
  const savedWidth = localStorage.getItem('sidebarWidth');
731
705
  if (savedWidth && savedWidth >= 200 && savedWidth <= 500) {
732
706
  sidebar.style.width = `${savedWidth}px`;
733
- content.style.marginLeft = `${savedWidth}px`;
707
+ // Don't set margin-left - flexbox handles the layout
734
708
  }
735
709
 
736
710
  // Mouse down on resize handle
@@ -759,7 +733,7 @@ function initSidebarResize() {
759
733
  const constrainedWidth = Math.max(200, Math.min(500, width));
760
734
 
761
735
  sidebar.style.width = `${constrainedWidth}px`;
762
- content.style.marginLeft = `${constrainedWidth}px`;
736
+ // Don't set margin-left - flexbox handles the layout
763
737
 
764
738
  e.preventDefault();
765
739
  }
@@ -801,7 +775,7 @@ function initSidebarResize() {
801
775
  const constrainedWidth = Math.max(200, Math.min(500, width));
802
776
 
803
777
  sidebar.style.width = `${constrainedWidth}px`;
804
- content.style.marginLeft = `${constrainedWidth}px`;
778
+ // Don't set margin-left - flexbox handles the layout
805
779
 
806
780
  e.preventDefault();
807
781
  }
@@ -1085,7 +1059,6 @@ function exportToPDF() {
1085
1059
  const mainWrapper = document.querySelector('.main-wrapper');
1086
1060
 
1087
1061
  if (content) {
1088
- content.style.marginLeft = '0';
1089
1062
  content.style.padding = '20px';
1090
1063
  content.style.maxWidth = 'none';
1091
1064
  }
@@ -1200,7 +1173,6 @@ function exportToPDF() {
1200
1173
 
1201
1174
  // Restore content styles
1202
1175
  if (content) {
1203
- content.style.marginLeft = '';
1204
1176
  content.style.padding = '';
1205
1177
  content.style.maxWidth = '';
1206
1178
  }
@@ -1333,21 +1305,15 @@ function generateBreadcrumbs() {
1333
1305
  // Initialize tooltip positioning for navigation items
1334
1306
  function initTooltips() {
1335
1307
  const tooltipElements = document.querySelectorAll('[data-tooltip]');
1336
- console.log('[Tooltips] Found', tooltipElements.length, 'elements with tooltips');
1337
1308
 
1338
1309
  tooltipElements.forEach(element => {
1339
1310
  element.addEventListener('mouseenter', function(e) {
1340
1311
  const rect = element.getBoundingClientRect();
1312
+ const tooltip = window.getComputedStyle(element, '::after');
1341
1313
 
1342
1314
  // Position the tooltip using CSS variables
1343
1315
  element.style.setProperty('--tooltip-left', `${rect.right + 10}px`);
1344
1316
  element.style.setProperty('--tooltip-top', `${rect.top + rect.height / 2}px`);
1345
- console.log('[Tooltip] Positioned at:', rect.right + 10, rect.top + rect.height / 2);
1346
- });
1347
-
1348
- element.addEventListener('mouseleave', function(e) {
1349
- element.style.removeProperty('--tooltip-left');
1350
- element.style.removeProperty('--tooltip-top');
1351
1317
  });
1352
1318
  });
1353
1319
  }
@@ -24,42 +24,34 @@ function escapeHtml(text) {
24
24
  return text.replace(/[&<>"']/g, m => map[m]);
25
25
  }
26
26
 
27
- // Extract summary from markdown content
28
- function extractSummary(content) {
29
- // Look for ## Overview or ## Summary section
30
- const overviewMatch = content.match(/##\s+(?:Overview|Summary)\s*\n([\s\S]*?)(?=\n##|$)/i);
31
- if (overviewMatch) {
32
- // Get first paragraph or up to 200 characters
33
- const text = overviewMatch[1].trim();
34
- const firstPara = text.split('\n\n')[0];
35
- return firstPara.length > 200 ? firstPara.substring(0, 200) + '...' : firstPara;
36
- }
27
+ // Extract summary from markdown content for tooltips
28
+ function extractSummary(content, maxLength = 150) {
29
+ // Remove front matter
30
+ content = content.replace(/^---[\s\S]*?---\n/, '');
37
31
 
38
- // Fallback: get first paragraph after title
39
- const lines = content.split('\n');
40
- let foundContent = false;
41
- let summary = '';
42
-
43
- for (const line of lines) {
44
- // Skip title lines
45
- if (line.startsWith('#')) continue;
46
- // Skip metadata lines
47
- if (line.includes('**Generated**:') || line.includes('**Status**:') || line.includes('**Verified**:')) continue;
48
- // Skip empty lines until we find content
49
- if (!foundContent && line.trim() === '') continue;
50
-
51
- if (line.trim()) {
52
- foundContent = true;
53
- summary += line + ' ';
54
- if (summary.length > 200) break;
55
- } else if (foundContent) {
56
- // Found end of first paragraph
57
- break;
58
- }
32
+ // Remove headers
33
+ content = content.replace(/^#+\s+.+$/gm, '');
34
+
35
+ // Remove code blocks
36
+ content = content.replace(/```[\s\S]*?```/g, '');
37
+ content = content.replace(/`[^`]+`/g, '');
38
+
39
+ // Remove images and links
40
+ content = content.replace(/!\[[^\]]*\]\([^)]*\)/g, '');
41
+ content = content.replace(/\[[^\]]*\]\([^)]*\)/g, '');
42
+
43
+ // Remove HTML tags
44
+ content = content.replace(/<[^>]+>/g, '');
45
+
46
+ // Remove extra whitespace
47
+ content = content.trim().replace(/\s+/g, ' ');
48
+
49
+ // Truncate if needed
50
+ if (content.length > maxLength) {
51
+ content = content.substring(0, maxLength).trim() + '...';
59
52
  }
60
53
 
61
- summary = summary.trim();
62
- return summary.length > 200 ? summary.substring(0, 200) + '...' : summary;
54
+ return content || 'No description available';
63
55
  }
64
56
 
65
57
  // Process markdown content
@@ -121,6 +113,7 @@ function generateHTML(title, content, navigation, currentPath = '', config = {})
121
113
 
122
114
  <!-- Styles -->
123
115
  <link rel="stylesheet" href="/css/notion-style.css">
116
+ <link rel="stylesheet" href="/css/style.css">
124
117
 
125
118
  <!-- Favicon -->
126
119
  <link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>📚</text></svg>">
@@ -178,9 +171,6 @@ function generateHTML(title, content, navigation, currentPath = '', config = {})
178
171
 
179
172
  <!-- Main Content -->
180
173
  <div class="main-wrapper">
181
- <!-- Sidebar Overlay -->
182
- <div class="sidebar-overlay"></div>
183
-
184
174
  <!-- Sidebar -->
185
175
  <aside class="sidebar">
186
176
  <div class="sidebar-header">
@@ -232,7 +222,7 @@ const folderDescriptions = {
232
222
  };
233
223
 
234
224
  // Build navigation structure with rich functionality
235
- function buildNavigationStructure(files, currentFile, summaries = {}) {
225
+ function buildNavigationStructure(files, currentFile) {
236
226
  const tree = { files: [], folders: {} };
237
227
 
238
228
  files.forEach(file => {
@@ -279,7 +269,7 @@ function buildNavigationStructure(files, currentFile, summaries = {}) {
279
269
  };
280
270
 
281
271
  // Helper function to render a section
282
- const renderSection = (folderName, folderData, level = 0, parentPath = '', summaries = {}) => {
272
+ const renderSection = (folderName, folderData, level = 0, parentPath = '') => {
283
273
  const icons = {
284
274
  'root': 'fas fa-home',
285
275
  'product-roadmap': 'fas fa-road',
@@ -323,7 +313,7 @@ function buildNavigationStructure(files, currentFile, summaries = {}) {
323
313
 
324
314
  // Get folder description for tooltip
325
315
  const folderDescription = folderDescriptions[folderName] || '';
326
- const tooltipAttr = folderDescription ? `data-tooltip="${escapeHtml(folderDescription)}" title="${escapeHtml(folderDescription)}"` : '';
316
+ const tooltipAttr = folderDescription ? `data-tooltip="${escapeHtml(folderDescription)}"` : '';
327
317
 
328
318
  // Start all sections collapsed by default (JavaScript will expand sections containing active items)
329
319
  const hasActiveChild = checkActiveChild(folderData, currentFile);
@@ -355,13 +345,10 @@ function buildNavigationStructure(files, currentFile, summaries = {}) {
355
345
  }
356
346
 
357
347
  const linkPath = '/' + file.urlPath;
358
-
359
- // Get summary for tooltip
360
- const summary = summaries[file.urlPath] || '';
361
- const tooltipAttr = summary ? `data-tooltip="${escapeHtml(summary)}"` : '';
348
+ const tooltip = file.summary ? ` data-tooltip="${escapeHtml(file.summary)}"` : '';
362
349
 
363
350
  html += `
364
- <a href="${linkPath}" class="nav-item${isActive}" ${tooltipAttr}><i class="fas fa-file-alt"></i> ${title}</a>`;
351
+ <a href="${linkPath}" class="nav-item${isActive}"${tooltip}><i class="fas fa-file-alt"></i> ${title}</a>`;
365
352
  });
366
353
 
367
354
  html += `</div></div>`;
@@ -372,7 +359,7 @@ function buildNavigationStructure(files, currentFile, summaries = {}) {
372
359
  .forEach(subFolder => {
373
360
  // Build the path for the subfolder including current folder
374
361
  const currentPath = parentPath ? `${parentPath}-${folderName}` : folderName;
375
- html += renderSection(subFolder, folderData.folders[subFolder], level + 1, currentPath, summaries);
362
+ html += renderSection(subFolder, folderData.folders[subFolder], level + 1, currentPath);
376
363
  });
377
364
 
378
365
  return html;
@@ -383,14 +370,14 @@ function buildNavigationStructure(files, currentFile, summaries = {}) {
383
370
 
384
371
  if (!hasFolders) {
385
372
  // Generate simple flat navigation for all files in root
386
- return renderSection('root', { files: tree.files, folders: {} }, 0, '', summaries);
373
+ return renderSection('root', { files: tree.files, folders: {} }, 0);
387
374
  } else {
388
375
  // Generate hierarchical navigation
389
376
  let nav = '';
390
377
 
391
378
  // Render root files first
392
379
  if (tree.files.length > 0) {
393
- nav += renderSection('root', { files: tree.files, folders: {} }, 0, '', summaries);
380
+ nav += renderSection('root', { files: tree.files, folders: {} }, 0);
394
381
  }
395
382
 
396
383
  // Add other top-level folders in logical order
@@ -413,7 +400,7 @@ function buildNavigationStructure(files, currentFile, summaries = {}) {
413
400
 
414
401
  folderOrder.forEach(folderName => {
415
402
  if (tree.folders[folderName]) {
416
- nav += renderSection(folderName, tree.folders[folderName], 1, '', summaries);
403
+ nav += renderSection(folderName, tree.folders[folderName], 1);
417
404
  delete tree.folders[folderName]; // Remove so we don't render it again
418
405
  }
419
406
  });
@@ -422,7 +409,7 @@ function buildNavigationStructure(files, currentFile, summaries = {}) {
422
409
  Object.keys(tree.folders)
423
410
  .sort()
424
411
  .forEach(folderName => {
425
- nav += renderSection(folderName, tree.folders[folderName], 1, '', summaries);
412
+ nav += renderSection(folderName, tree.folders[folderName], 1);
426
413
  });
427
414
 
428
415
  return nav;
@@ -430,7 +417,7 @@ function buildNavigationStructure(files, currentFile, summaries = {}) {
430
417
  }
431
418
 
432
419
  // Process single markdown file
433
- async function processMarkdownFile(filePath, outputPath, allFiles, config, summaries = {}) {
420
+ async function processMarkdownFile(filePath, outputPath, allFiles, config) {
434
421
  const content = await fs.readFile(filePath, 'utf-8');
435
422
  const fileName = path.basename(filePath, '.md');
436
423
  const relativePath = path.relative(config.docsDir, filePath);
@@ -440,11 +427,14 @@ async function processMarkdownFile(filePath, outputPath, allFiles, config, summa
440
427
  const titleMatch = content.match(/^#\s+(.+)$/m);
441
428
  const title = titleMatch ? titleMatch[1] : fileName;
442
429
 
430
+ // Extract summary for tooltip
431
+ const summary = extractSummary(content);
432
+
443
433
  // Process content
444
434
  const htmlContent = processMarkdownContent(content);
445
435
 
446
436
  // Build navigation
447
- const navigation = buildNavigationStructure(allFiles, urlPath, summaries);
437
+ const navigation = buildNavigationStructure(allFiles, urlPath);
448
438
 
449
439
  // Generate full HTML
450
440
  const html = generateHTML(title, htmlContent, navigation, urlPath, config);
@@ -453,7 +443,7 @@ async function processMarkdownFile(filePath, outputPath, allFiles, config, summa
453
443
  await fs.ensureDir(path.dirname(outputPath));
454
444
  await fs.writeFile(outputPath, html);
455
445
 
456
- return { title, urlPath };
446
+ return { title, urlPath, summary };
457
447
  }
458
448
 
459
449
  // Get all markdown files
@@ -475,11 +465,16 @@ async function getAllMarkdownFiles(dir, baseDir = dir) {
475
465
  .replace(/[-_]/g, ' ')
476
466
  .replace(/\b\w/g, l => l.toUpperCase());
477
467
 
468
+ // Read file to extract summary
469
+ const content = await fs.readFile(fullPath, 'utf-8');
470
+ const summary = extractSummary(content);
471
+
478
472
  files.push({
479
473
  path: fullPath,
480
474
  relativePath,
481
475
  urlPath,
482
- displayName
476
+ displayName,
477
+ summary
483
478
  });
484
479
  }
485
480
  }
@@ -512,21 +507,10 @@ async function buildDocumentation(config) {
512
507
  });
513
508
  }
514
509
 
515
- // First pass: collect summaries
516
- console.log(chalk.blue('📊 Extracting summaries...'));
517
- const summaries = {};
518
- for (const file of files) {
519
- const content = await fs.readFile(file.path, 'utf-8');
520
- const summary = extractSummary(content);
521
- if (summary) {
522
- summaries[file.urlPath] = summary;
523
- }
524
- }
525
-
526
510
  console.log(chalk.blue('📝 Processing files...'));
527
511
  for (const file of files) {
528
512
  const outputPath = path.join(outputDir, file.urlPath);
529
- await processMarkdownFile(file.path, outputPath, files, config, summaries);
513
+ await processMarkdownFile(file.path, outputPath, files, config);
530
514
  console.log(chalk.green(`✅ Generated: ${outputPath}`));
531
515
  }
532
516
 
@@ -873,6 +857,7 @@ async function createDefaultIndexPage(outputDir, config, version) {
873
857
  <title>Welcome to ${siteName}</title>
874
858
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
875
859
  <link rel="stylesheet" href="/css/notion-style.css">
860
+ <link rel="stylesheet" href="/css/style.css">
876
861
  <style>
877
862
  .welcome-container {
878
863
  max-width: 800px;
@@ -0,0 +1,82 @@
1
+ # Cache Busting Guide for @knowcode/doc-builder
2
+
3
+ If you're not seeing updates after upgrading to a new version, it's likely due to caching. Follow these steps:
4
+
5
+ ## 1. Clean Everything Locally
6
+
7
+ ```bash
8
+ # Remove old build artifacts
9
+ rm -rf html/
10
+
11
+ # Clear npm cache
12
+ npm cache clean --force
13
+
14
+ # Remove node_modules and reinstall
15
+ rm -rf node_modules
16
+ npm install
17
+
18
+ # Make sure you have the latest version
19
+ npm install @knowcode/doc-builder@latest
20
+ ```
21
+
22
+ ## 2. Rebuild with Fresh Files
23
+
24
+ ```bash
25
+ # Build fresh documentation
26
+ npx @knowcode/doc-builder build
27
+ ```
28
+
29
+ ## 3. Deploy with Force Flag
30
+
31
+ ```bash
32
+ # Force Vercel to ignore cache
33
+ vercel --prod --force
34
+ ```
35
+
36
+ ## 4. Clear Browser Cache
37
+
38
+ - **Chrome/Edge**: Cmd+Shift+R (Mac) or Ctrl+Shift+R (Windows)
39
+ - **Firefox**: Cmd+Shift+R (Mac) or Ctrl+Shift+R (Windows)
40
+ - **Safari**: Cmd+Option+R
41
+ - Or use Incognito/Private browsing mode
42
+
43
+ ## 5. Clear Vercel/CDN Cache (if applicable)
44
+
45
+ If using Vercel:
46
+ 1. Go to your project dashboard
47
+ 2. Settings → Functions → Purge Cache
48
+ 3. Or redeploy with a different domain temporarily
49
+
50
+ ## 6. Add Cache Busting to Your Build
51
+
52
+ Edit your `doc-builder.config.js` to add version query strings:
53
+
54
+ ```javascript
55
+ module.exports = {
56
+ // ... other config
57
+ cacheBust: true, // This will add ?v=timestamp to CSS/JS files
58
+ };
59
+ ```
60
+
61
+ ## Common Issues
62
+
63
+ - **"I updated but nothing changed"** - It's cache. Follow all steps above.
64
+ - **"Tooltips still don't work"** - Clear browser cache and check console for errors
65
+ - **"Spacing is still wrong"** - The CSS is cached. Hard refresh the page.
66
+
67
+ ## Verify You Have The Right Version
68
+
69
+ Check the version in your package.json:
70
+ ```bash
71
+ npm list @knowcode/doc-builder
72
+ ```
73
+
74
+ Should show: `@knowcode/doc-builder@1.3.13` or higher.
75
+
76
+ ## Still Not Working?
77
+
78
+ 1. Open browser DevTools
79
+ 2. Go to Network tab
80
+ 3. Check "Disable cache" checkbox
81
+ 4. Refresh the page
82
+ 5. Look at the CSS/JS files being loaded - they should not show "(from cache)"