@knowcode/doc-builder 1.3.14 → 1.4.0

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,31 @@ 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.0] - 2025-07-20
9
+
10
+ ### Added
11
+ - **Tooltip functionality restored** - Added summary extraction from markdown files
12
+ - Tooltips now appear on hover for navigation items showing content preview
13
+ - `extractSummary()` function looks for Overview/Summary sections or first paragraph
14
+ - Summaries are collected in first pass and added as `data-tooltip` attributes
15
+
16
+ ### Fixed
17
+ - **CSS layout restored to match original** - Reverted all layout changes to original values
18
+ - Header height restored to 64px (was 56px)
19
+ - Main wrapper uses margin-top approach (not absolute positioning)
20
+ - Content uses original padding values (var(--space-6) var(--space-8))
21
+ - Content-inner uses centered layout (margin: 0 auto)
22
+ - Navigation padding restored to all sides
23
+
24
+ ### Removed
25
+ - Removed unused style.css file - only notion-style.css is used
26
+ - Eliminated dual CSS file confusion
27
+
28
+ ### Technical Details
29
+ - Summary extraction matches original build.js implementation
30
+ - Navigation generation passes summaries through recursive renderSection calls
31
+ - Tooltips use same CSS implementation as original with fixed positioning
32
+
8
33
  ## [1.3.14] - 2025-07-20
9
34
 
10
35
  ### Fixed
@@ -125,7 +125,7 @@
125
125
  /* Layout */
126
126
  --container-padding-mobile: 20px;
127
127
  --container-padding-desktop: 40px;
128
- --header-height: 56px;
128
+ --header-height: 64px;
129
129
  --breadcrumb-height: 40px;
130
130
  --sidebar-width: 280px;
131
131
  }
@@ -470,14 +470,14 @@ pre code {
470
470
  /* Main Wrapper */
471
471
  .main-wrapper {
472
472
  display: flex;
473
- height: 100vh;
474
- padding-top: calc(var(--header-height) + var(--breadcrumb-height));
473
+ height: calc(100vh - var(--header-height) - var(--breadcrumb-height));
474
+ margin-top: calc(var(--header-height) + var(--breadcrumb-height));
475
475
  overflow: hidden;
476
476
  }
477
477
 
478
478
  .main-wrapper.banner-visible {
479
- height: 100vh;
480
- padding-top: calc(var(--header-height) + var(--breadcrumb-height) + 3.5rem);
479
+ height: calc(100vh - var(--header-height) - var(--breadcrumb-height) - 3.5rem);
480
+ margin-top: calc(var(--header-height) + var(--breadcrumb-height) + 3.5rem);
481
481
  }
482
482
 
483
483
  /* Sidebar */
@@ -528,7 +528,7 @@ pre code {
528
528
  /* Navigation */
529
529
  .navigation {
530
530
  flex: 1;
531
- padding: 0 var(--space-2) var(--space-2) var(--space-2); /* No top padding */
531
+ padding: var(--space-2);
532
532
  overflow-y: auto;
533
533
  overflow-x: visible;
534
534
 
@@ -688,7 +688,7 @@ pre code {
688
688
  .content {
689
689
  flex: 1;
690
690
  margin-left: var(--sidebar-width);
691
- padding: var(--space-2) var(--space-8) var(--space-4); /* Reduced top padding */
691
+ padding: var(--space-6) var(--space-8);
692
692
  overflow-y: auto;
693
693
  background: var(--color-bg-default);
694
694
  transition: margin-left var(--duration-normal);
@@ -696,7 +696,7 @@ pre code {
696
696
 
697
697
  .content-inner {
698
698
  max-width: 65rem;
699
- margin: 0; /* Left aligned instead of centered */
699
+ margin: 0 auto;
700
700
  }
701
701
 
702
702
  /* Tables */
@@ -1030,7 +1030,7 @@ tr:hover {
1030
1030
 
1031
1031
  .content {
1032
1032
  margin-left: 0 !important;
1033
- padding: var(--space-2) var(--space-4) var(--space-4); /* Reduced top padding */
1033
+ padding: var(--space-6) var(--space-4);
1034
1034
  max-width: 100%;
1035
1035
  }
1036
1036
 
@@ -1672,7 +1672,7 @@ tr:hover {
1672
1672
 
1673
1673
  .content {
1674
1674
  margin-left: 0 !important;
1675
- padding: var(--space-2) var(--space-4) var(--space-4); /* Reduced top padding */
1675
+ padding: var(--space-6) var(--space-4);
1676
1676
  max-width: 100%;
1677
1677
  }
1678
1678
 
Binary file
@@ -24,6 +24,44 @@ 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
+ }
37
+
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
+ }
59
+ }
60
+
61
+ summary = summary.trim();
62
+ return summary.length > 200 ? summary.substring(0, 200) + '...' : summary;
63
+ }
64
+
27
65
  // Process markdown content
28
66
  function processMarkdownContent(content) {
29
67
  // Convert mermaid code blocks to mermaid divs with titles
@@ -194,7 +232,7 @@ const folderDescriptions = {
194
232
  };
195
233
 
196
234
  // Build navigation structure with rich functionality
197
- function buildNavigationStructure(files, currentFile) {
235
+ function buildNavigationStructure(files, currentFile, summaries = {}) {
198
236
  const tree = { files: [], folders: {} };
199
237
 
200
238
  files.forEach(file => {
@@ -241,7 +279,7 @@ function buildNavigationStructure(files, currentFile) {
241
279
  };
242
280
 
243
281
  // Helper function to render a section
244
- const renderSection = (folderName, folderData, level = 0, parentPath = '') => {
282
+ const renderSection = (folderName, folderData, level = 0, parentPath = '', summaries = {}) => {
245
283
  const icons = {
246
284
  'root': 'fas fa-home',
247
285
  'product-roadmap': 'fas fa-road',
@@ -318,8 +356,12 @@ function buildNavigationStructure(files, currentFile) {
318
356
 
319
357
  const linkPath = '/' + file.urlPath;
320
358
 
359
+ // Get summary for tooltip
360
+ const summary = summaries[file.urlPath] || '';
361
+ const tooltipAttr = summary ? `data-tooltip="${escapeHtml(summary)}"` : '';
362
+
321
363
  html += `
322
- <a href="${linkPath}" class="nav-item${isActive}"><i class="fas fa-file-alt"></i> ${title}</a>`;
364
+ <a href="${linkPath}" class="nav-item${isActive}" ${tooltipAttr}><i class="fas fa-file-alt"></i> ${title}</a>`;
323
365
  });
324
366
 
325
367
  html += `</div></div>`;
@@ -330,7 +372,7 @@ function buildNavigationStructure(files, currentFile) {
330
372
  .forEach(subFolder => {
331
373
  // Build the path for the subfolder including current folder
332
374
  const currentPath = parentPath ? `${parentPath}-${folderName}` : folderName;
333
- html += renderSection(subFolder, folderData.folders[subFolder], level + 1, currentPath);
375
+ html += renderSection(subFolder, folderData.folders[subFolder], level + 1, currentPath, summaries);
334
376
  });
335
377
 
336
378
  return html;
@@ -341,14 +383,14 @@ function buildNavigationStructure(files, currentFile) {
341
383
 
342
384
  if (!hasFolders) {
343
385
  // Generate simple flat navigation for all files in root
344
- return renderSection('root', { files: tree.files, folders: {} }, 0);
386
+ return renderSection('root', { files: tree.files, folders: {} }, 0, '', summaries);
345
387
  } else {
346
388
  // Generate hierarchical navigation
347
389
  let nav = '';
348
390
 
349
391
  // Render root files first
350
392
  if (tree.files.length > 0) {
351
- nav += renderSection('root', { files: tree.files, folders: {} }, 0);
393
+ nav += renderSection('root', { files: tree.files, folders: {} }, 0, '', summaries);
352
394
  }
353
395
 
354
396
  // Add other top-level folders in logical order
@@ -371,7 +413,7 @@ function buildNavigationStructure(files, currentFile) {
371
413
 
372
414
  folderOrder.forEach(folderName => {
373
415
  if (tree.folders[folderName]) {
374
- nav += renderSection(folderName, tree.folders[folderName], 1);
416
+ nav += renderSection(folderName, tree.folders[folderName], 1, '', summaries);
375
417
  delete tree.folders[folderName]; // Remove so we don't render it again
376
418
  }
377
419
  });
@@ -380,7 +422,7 @@ function buildNavigationStructure(files, currentFile) {
380
422
  Object.keys(tree.folders)
381
423
  .sort()
382
424
  .forEach(folderName => {
383
- nav += renderSection(folderName, tree.folders[folderName], 1);
425
+ nav += renderSection(folderName, tree.folders[folderName], 1, '', summaries);
384
426
  });
385
427
 
386
428
  return nav;
@@ -388,7 +430,7 @@ function buildNavigationStructure(files, currentFile) {
388
430
  }
389
431
 
390
432
  // Process single markdown file
391
- async function processMarkdownFile(filePath, outputPath, allFiles, config) {
433
+ async function processMarkdownFile(filePath, outputPath, allFiles, config, summaries = {}) {
392
434
  const content = await fs.readFile(filePath, 'utf-8');
393
435
  const fileName = path.basename(filePath, '.md');
394
436
  const relativePath = path.relative(config.docsDir, filePath);
@@ -402,7 +444,7 @@ async function processMarkdownFile(filePath, outputPath, allFiles, config) {
402
444
  const htmlContent = processMarkdownContent(content);
403
445
 
404
446
  // Build navigation
405
- const navigation = buildNavigationStructure(allFiles, urlPath);
447
+ const navigation = buildNavigationStructure(allFiles, urlPath, summaries);
406
448
 
407
449
  // Generate full HTML
408
450
  const html = generateHTML(title, htmlContent, navigation, urlPath, config);
@@ -470,10 +512,21 @@ async function buildDocumentation(config) {
470
512
  });
471
513
  }
472
514
 
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
+
473
526
  console.log(chalk.blue('📝 Processing files...'));
474
527
  for (const file of files) {
475
528
  const outputPath = path.join(outputDir, file.urlPath);
476
- await processMarkdownFile(file.path, outputPath, files, config);
529
+ await processMarkdownFile(file.path, outputPath, files, config, summaries);
477
530
  console.log(chalk.green(`✅ Generated: ${outputPath}`));
478
531
  }
479
532
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@knowcode/doc-builder",
3
- "version": "1.3.14",
3
+ "version": "1.4.0",
4
4
  "description": "Reusable documentation builder for markdown-based sites with Vercel deployment support",
5
5
  "main": "index.js",
6
6
  "bin": {