@knowcode/doc-builder 1.3.15 → 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 +25 -0
- package/assets/css/notion-style.css +11 -14
- package/knowcode-doc-builder-1.3.15.tgz +0 -0
- package/lib/core-builder.js +64 -11
- package/package.json +1 -1
- package/assets/css/style.css +0 -2121
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:
|
|
128
|
+
--header-height: 64px;
|
|
129
129
|
--breadcrumb-height: 40px;
|
|
130
130
|
--sidebar-width: 280px;
|
|
131
131
|
}
|
|
@@ -469,17 +469,15 @@ pre code {
|
|
|
469
469
|
|
|
470
470
|
/* Main Wrapper */
|
|
471
471
|
.main-wrapper {
|
|
472
|
-
position: absolute;
|
|
473
|
-
top: calc(var(--header-height) + var(--breadcrumb-height));
|
|
474
|
-
left: 0;
|
|
475
|
-
right: 0;
|
|
476
|
-
bottom: 0;
|
|
477
472
|
display: flex;
|
|
473
|
+
height: calc(100vh - var(--header-height) - var(--breadcrumb-height));
|
|
474
|
+
margin-top: calc(var(--header-height) + var(--breadcrumb-height));
|
|
478
475
|
overflow: hidden;
|
|
479
476
|
}
|
|
480
477
|
|
|
481
478
|
.main-wrapper.banner-visible {
|
|
482
|
-
|
|
479
|
+
height: calc(100vh - var(--header-height) - var(--breadcrumb-height) - 3.5rem);
|
|
480
|
+
margin-top: calc(var(--header-height) + var(--breadcrumb-height) + 3.5rem);
|
|
483
481
|
}
|
|
484
482
|
|
|
485
483
|
/* Sidebar */
|
|
@@ -530,7 +528,7 @@ pre code {
|
|
|
530
528
|
/* Navigation */
|
|
531
529
|
.navigation {
|
|
532
530
|
flex: 1;
|
|
533
|
-
padding:
|
|
531
|
+
padding: var(--space-2);
|
|
534
532
|
overflow-y: auto;
|
|
535
533
|
overflow-x: visible;
|
|
536
534
|
|
|
@@ -690,7 +688,7 @@ pre code {
|
|
|
690
688
|
.content {
|
|
691
689
|
flex: 1;
|
|
692
690
|
margin-left: var(--sidebar-width);
|
|
693
|
-
padding: var(--space-
|
|
691
|
+
padding: var(--space-6) var(--space-8);
|
|
694
692
|
overflow-y: auto;
|
|
695
693
|
background: var(--color-bg-default);
|
|
696
694
|
transition: margin-left var(--duration-normal);
|
|
@@ -698,7 +696,7 @@ pre code {
|
|
|
698
696
|
|
|
699
697
|
.content-inner {
|
|
700
698
|
max-width: 65rem;
|
|
701
|
-
margin: 0;
|
|
699
|
+
margin: 0 auto;
|
|
702
700
|
}
|
|
703
701
|
|
|
704
702
|
/* Tables */
|
|
@@ -1032,7 +1030,7 @@ tr:hover {
|
|
|
1032
1030
|
|
|
1033
1031
|
.content {
|
|
1034
1032
|
margin-left: 0 !important;
|
|
1035
|
-
padding: var(--space-
|
|
1033
|
+
padding: var(--space-6) var(--space-4);
|
|
1036
1034
|
max-width: 100%;
|
|
1037
1035
|
}
|
|
1038
1036
|
|
|
@@ -1660,9 +1658,8 @@ tr:hover {
|
|
|
1660
1658
|
}
|
|
1661
1659
|
|
|
1662
1660
|
.main-wrapper {
|
|
1663
|
-
position: relative; /* Change back to relative for mobile */
|
|
1664
|
-
top: 0;
|
|
1665
1661
|
flex-direction: column;
|
|
1662
|
+
height: auto;
|
|
1666
1663
|
min-height: calc(100vh - var(--header-height) - var(--breadcrumb-height));
|
|
1667
1664
|
}
|
|
1668
1665
|
|
|
@@ -1675,7 +1672,7 @@ tr:hover {
|
|
|
1675
1672
|
|
|
1676
1673
|
.content {
|
|
1677
1674
|
margin-left: 0 !important;
|
|
1678
|
-
padding: var(--space-
|
|
1675
|
+
padding: var(--space-6) var(--space-4);
|
|
1679
1676
|
max-width: 100%;
|
|
1680
1677
|
}
|
|
1681
1678
|
|
|
Binary file
|
package/lib/core-builder.js
CHANGED
|
@@ -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
|
|