@knowcode/doc-builder 1.8.7 → 1.9.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.
Files changed (45) hide show
  1. package/.claude/settings.local.json +2 -1
  2. package/CHANGELOG.md +27 -0
  3. package/assets/css/notion-style.css +141 -0
  4. package/assets/js/main.js +76 -0
  5. package/html/README.html +10 -3
  6. package/html/css/notion-style.css +141 -0
  7. package/html/documentation-index.html +10 -3
  8. package/html/guides/authentication-default-change.html +10 -3
  9. package/html/guides/authentication-guide.html +10 -3
  10. package/html/guides/claude-workflow-guide.html +10 -3
  11. package/html/guides/documentation-standards.html +10 -3
  12. package/html/guides/phosphor-icons-guide.html +10 -3
  13. package/html/guides/private-directory-authentication.html +10 -3
  14. package/html/guides/public-site-deployment.html +10 -3
  15. package/html/guides/search-engine-verification-guide.html +10 -3
  16. package/html/guides/seo-guide.html +10 -3
  17. package/html/guides/seo-optimization-guide.html +10 -3
  18. package/html/guides/troubleshooting-guide.html +10 -3
  19. package/html/guides/windows-setup-guide.html +10 -3
  20. package/html/image-modal-test.html +305 -0
  21. package/html/index.html +10 -3
  22. package/html/js/main.js +76 -0
  23. package/html/private/cache-control-anti-pattern.html +10 -3
  24. package/html/private/launch/README.html +10 -3
  25. package/html/private/launch/auth-cleanup-summary.html +10 -3
  26. package/html/private/launch/bubble-plugin-specification.html +10 -3
  27. package/html/private/launch/go-to-market-strategy.html +10 -3
  28. package/html/private/launch/launch-announcements.html +10 -3
  29. package/html/private/launch/vercel-deployment-auth-setup.html +10 -3
  30. package/html/private/next-steps-walkthrough.html +11 -4
  31. package/html/private/supabase-auth-implementation-completed.html +10 -3
  32. package/html/private/supabase-auth-implementation-plan.html +10 -3
  33. package/html/private/supabase-auth-integration-plan.html +10 -3
  34. package/html/private/supabase-auth-setup-guide.html +10 -3
  35. package/html/private/test-private-doc.html +10 -3
  36. package/html/private/user-management-tooling.html +10 -3
  37. package/html/prompts/markdown-document-standards.html +409 -0
  38. package/html/sitemap.xml +56 -44
  39. package/html/vercel-cli-setup-guide.html +10 -3
  40. package/html/vercel-first-time-setup-guide.html +10 -3
  41. package/lib/core-builder.js +1 -0
  42. package/lib/emoji-mapper.js +13 -0
  43. package/package/assets/css/notion-style.css +432 -135
  44. package/package/assets/js/main.js +259 -25
  45. package/package.json +1 -1
@@ -79,9 +79,6 @@ function initializeMermaidFullScreen() {
79
79
  const toolbar = document.createElement('div');
80
80
  toolbar.className = 'mermaid-toolbar';
81
81
 
82
- const title = document.createElement('div');
83
- title.textContent = 'Mermaid Diagram';
84
-
85
82
  const actions = document.createElement('div');
86
83
  actions.className = 'mermaid-actions';
87
84
 
@@ -91,23 +88,8 @@ function initializeMermaidFullScreen() {
91
88
  fullScreenBtn.innerHTML = '<i class="fas fa-expand"></i> Full Screen';
92
89
  fullScreenBtn.addEventListener('click', () => openMermaidFullScreen(mermaidDiv, index));
93
90
 
94
- // Copy SVG button
95
- const copyBtn = document.createElement('button');
96
- copyBtn.className = 'mermaid-btn';
97
- copyBtn.innerHTML = '<i class="fas fa-copy"></i> Copy SVG';
98
- copyBtn.addEventListener('click', () => copyMermaidSVG(mermaidDiv));
99
-
100
- // Copy Mermaid source button
101
- const copyMermaidBtn = document.createElement('button');
102
- copyMermaidBtn.className = 'mermaid-btn';
103
- copyMermaidBtn.innerHTML = '<i class="fas fa-code"></i> Copy Mermaid';
104
- copyMermaidBtn.addEventListener('click', () => copyMermaidSource(mermaidDiv));
105
-
106
91
  actions.appendChild(fullScreenBtn);
107
- actions.appendChild(copyBtn);
108
- actions.appendChild(copyMermaidBtn);
109
92
 
110
- toolbar.appendChild(title);
111
93
  toolbar.appendChild(actions);
112
94
 
113
95
  // Create wrapper for the diagram
@@ -512,12 +494,147 @@ function updateThemeIcon(theme) {
512
494
  const menuToggle = document.getElementById('menu-toggle');
513
495
  const sidebar = document.querySelector('.sidebar');
514
496
 
497
+ // Set initial menu state based on configuration
498
+ const menuDefaultOpen = window.docBuilderConfig?.features?.menuDefaultOpen !== false;
499
+ if (sidebar && window.innerWidth > 768) {
500
+ if (!menuDefaultOpen) {
501
+ sidebar.classList.add('closed');
502
+ // Add class to body to show menu toggle on desktop when menu starts closed
503
+ document.body.classList.add('menu-starts-closed');
504
+ }
505
+ }
506
+
507
+ // Create overlay element for mobile
508
+ let overlay = document.querySelector('.sidebar-overlay');
509
+ if (!overlay && window.innerWidth <= 768) {
510
+ overlay = document.createElement('div');
511
+ overlay.className = 'sidebar-overlay';
512
+ document.body.appendChild(overlay);
513
+ }
514
+
515
515
  if (menuToggle) {
516
516
  menuToggle.addEventListener('click', () => {
517
+ if (window.innerWidth <= 768) {
518
+ // Mobile: toggle 'open' class
519
+ sidebar.classList.toggle('open');
520
+ } else {
521
+ // Desktop: toggle 'closed' class
522
+ sidebar.classList.toggle('closed');
523
+ // Update visibility of menu toggle based on sidebar state
524
+ updateMenuToggleVisibility();
525
+ }
526
+ if (overlay) {
527
+ overlay.classList.toggle('active');
528
+ }
529
+ });
530
+ }
531
+
532
+ // Function to update menu toggle visibility
533
+ function updateMenuToggleVisibility() {
534
+ if (window.innerWidth > 768) {
535
+ if (!menuDefaultOpen || sidebar.classList.contains('closed')) {
536
+ document.body.classList.add('show-menu-toggle');
537
+ } else {
538
+ document.body.classList.remove('show-menu-toggle');
539
+ }
540
+ }
541
+ }
542
+
543
+ // Initial check
544
+ updateMenuToggleVisibility();
545
+
546
+ // Update on window resize
547
+ window.addEventListener('resize', updateMenuToggleVisibility);
548
+
549
+ // Close menu when clicking overlay
550
+ if (overlay) {
551
+ overlay.addEventListener('click', () => {
552
+ sidebar.classList.remove('open');
553
+ overlay.classList.remove('active');
554
+ });
555
+ }
556
+
557
+ // Floating Menu Button for Mobile
558
+ function initFloatingMenuButton() {
559
+ // Only initialize on mobile
560
+ if (window.innerWidth > 768) return;
561
+
562
+ // Check if button already exists
563
+ if (document.getElementById('floating-menu-toggle')) return;
564
+
565
+ // Create floating button
566
+ const floatingButton = document.createElement('button');
567
+ floatingButton.id = 'floating-menu-toggle';
568
+ floatingButton.className = 'floating-menu-toggle';
569
+ floatingButton.setAttribute('aria-label', 'Toggle menu');
570
+ floatingButton.innerHTML = '<i class="fas fa-bars"></i>';
571
+ floatingButton.style.display = 'flex'; // Always visible on mobile
572
+ floatingButton.classList.add('visible'); // Start visible
573
+
574
+ // Add to body
575
+ document.body.appendChild(floatingButton);
576
+
577
+ // Toggle sidebar on click
578
+ floatingButton.addEventListener('click', () => {
517
579
  sidebar.classList.toggle('open');
580
+
581
+ // Handle overlay
582
+ let overlay = document.querySelector('.sidebar-overlay');
583
+ if (!overlay) {
584
+ overlay = document.createElement('div');
585
+ overlay.className = 'sidebar-overlay';
586
+ document.body.appendChild(overlay);
587
+
588
+ // Add overlay click handler
589
+ overlay.addEventListener('click', () => {
590
+ sidebar.classList.remove('open');
591
+ overlay.classList.remove('active');
592
+ floatingButton.querySelector('i').className = 'fas fa-bars';
593
+ });
594
+ }
595
+
596
+ if (overlay) {
597
+ overlay.classList.toggle('active');
598
+ }
599
+
600
+ // Update icon based on state
601
+ const icon = floatingButton.querySelector('i');
602
+ if (sidebar.classList.contains('open')) {
603
+ icon.className = 'fas fa-times';
604
+ } else {
605
+ icon.className = 'fas fa-bars';
606
+ }
607
+ });
608
+
609
+ // Remove scroll-based visibility - button is always visible on mobile
610
+
611
+ // Update icon when sidebar state changes from other sources
612
+ const observer = new MutationObserver(() => {
613
+ const icon = floatingButton.querySelector('i');
614
+ if (sidebar.classList.contains('open')) {
615
+ icon.className = 'fas fa-times';
616
+ } else {
617
+ icon.className = 'fas fa-bars';
618
+ }
619
+ });
620
+
621
+ observer.observe(sidebar, {
622
+ attributes: true,
623
+ attributeFilter: ['class']
518
624
  });
519
625
  }
520
626
 
627
+ // Initialize floating button on load and resize
628
+ document.addEventListener('DOMContentLoaded', initFloatingMenuButton);
629
+ window.addEventListener('resize', () => {
630
+ const existingButton = document.getElementById('floating-menu-toggle');
631
+ if (window.innerWidth > 768 && existingButton) {
632
+ existingButton.remove();
633
+ } else if (window.innerWidth <= 768 && !existingButton) {
634
+ initFloatingMenuButton();
635
+ }
636
+ });
637
+
521
638
  // Prevent sidebar from closing when clicking nav items
522
639
  // Only close when clicking outside the sidebar or the close button
523
640
  document.addEventListener('click', (e) => {
@@ -525,11 +642,21 @@ document.addEventListener('click', (e) => {
525
642
  if (window.innerWidth <= 768) {
526
643
  const isClickInsideSidebar = sidebar && sidebar.contains(e.target);
527
644
  const isMenuToggle = e.target.closest('#menu-toggle');
645
+ const isFloatingButton = e.target.closest('#floating-menu-toggle');
528
646
  const isNavItem = e.target.closest('.nav-item, .nav-title');
647
+ const overlay = document.querySelector('.sidebar-overlay');
529
648
 
530
649
  // 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')) {
650
+ if (!isClickInsideSidebar && !isMenuToggle && !isFloatingButton && !isNavItem && sidebar?.classList.contains('open')) {
532
651
  sidebar.classList.remove('open');
652
+ if (overlay) {
653
+ overlay.classList.remove('active');
654
+ }
655
+ // Update floating button icon if it exists
656
+ const floatingBtn = document.getElementById('floating-menu-toggle');
657
+ if (floatingBtn) {
658
+ floatingBtn.querySelector('i').className = 'fas fa-bars';
659
+ }
533
660
  }
534
661
  }
535
662
  });
@@ -538,12 +665,16 @@ document.addEventListener('click', (e) => {
538
665
  document.querySelectorAll('a[href^="#"]').forEach(anchor => {
539
666
  anchor.addEventListener('click', function (e) {
540
667
  e.preventDefault();
541
- const target = document.querySelector(this.getAttribute('href'));
542
- if (target) {
543
- target.scrollIntoView({
544
- behavior: 'smooth',
545
- block: 'start'
546
- });
668
+ const href = this.getAttribute('href');
669
+ // Skip if href is just '#' (prevents querySelector error)
670
+ if (href && href !== '#') {
671
+ const target = document.querySelector(href);
672
+ if (target) {
673
+ target.scrollIntoView({
674
+ behavior: 'smooth',
675
+ block: 'start'
676
+ });
677
+ }
547
678
  }
548
679
  });
549
680
  });
@@ -1186,6 +1317,10 @@ function exportToPDF() {
1186
1317
 
1187
1318
  // Add PDF export button functionality
1188
1319
  function addPDFExportButton() {
1320
+ // Check configuration - default to true if not set
1321
+ const showPdfDownload = window.docBuilderConfig?.features?.showPdfDownload !== false;
1322
+ if (!showPdfDownload) return;
1323
+
1189
1324
  const headerActions = document.querySelector('.header-actions');
1190
1325
  if (headerActions) {
1191
1326
  const pdfButton = document.createElement('button');
@@ -1318,8 +1453,106 @@ function initTooltips() {
1318
1453
  });
1319
1454
  }
1320
1455
 
1456
+ // Handle .md link redirects
1457
+ function initMarkdownLinkRedirects() {
1458
+ // Check if current URL ends with .md and redirect
1459
+ if (window.location.pathname.endsWith('.md')) {
1460
+ const htmlPath = window.location.pathname.replace(/\.md$/, '.html');
1461
+ console.log(`Redirecting from .md to .html: ${htmlPath}`);
1462
+ window.location.replace(htmlPath);
1463
+ return; // Stop execution as we're redirecting
1464
+ }
1465
+
1466
+ // Intercept clicks on .md links
1467
+ document.addEventListener('click', function(e) {
1468
+ const link = e.target.closest('a');
1469
+ if (link && link.href && link.href.endsWith('.md')) {
1470
+ e.preventDefault();
1471
+ const htmlUrl = link.href.replace(/\.md$/, '.html');
1472
+ console.log(`Converting .md link to .html: ${htmlUrl}`);
1473
+ window.location.href = htmlUrl;
1474
+ }
1475
+ });
1476
+ }
1477
+
1478
+ // Image Modal System
1479
+ function initImageModal() {
1480
+ // Create modal HTML structure
1481
+ const modalHTML = `
1482
+ <div class="image-modal" id="imageModal">
1483
+ <div class="image-modal-content">
1484
+ <div class="image-modal-close" id="imageModalClose">&times;</div>
1485
+ <img class="image-modal-img" id="imageModalImg" src="" alt="">
1486
+ <div class="image-modal-caption" id="imageModalCaption"></div>
1487
+ </div>
1488
+ </div>
1489
+ `;
1490
+
1491
+ // Add modal to document body
1492
+ document.body.insertAdjacentHTML('beforeend', modalHTML);
1493
+
1494
+ const modal = document.getElementById('imageModal');
1495
+ const modalImg = document.getElementById('imageModalImg');
1496
+ const modalCaption = document.getElementById('imageModalCaption');
1497
+ const closeBtn = document.getElementById('imageModalClose');
1498
+
1499
+ // Add click handlers to all content images
1500
+ const contentImages = document.querySelectorAll('.content img');
1501
+ contentImages.forEach(img => {
1502
+ img.addEventListener('click', function() {
1503
+ modal.classList.add('active');
1504
+ modalImg.src = this.src;
1505
+ modalImg.alt = this.alt;
1506
+ modalCaption.textContent = this.alt;
1507
+
1508
+ // Hide caption if no alt text
1509
+ if (!this.alt) {
1510
+ modalCaption.style.display = 'none';
1511
+ } else {
1512
+ modalCaption.style.display = 'block';
1513
+ }
1514
+
1515
+ // Prevent body scrolling
1516
+ document.body.style.overflow = 'hidden';
1517
+ });
1518
+ });
1519
+
1520
+ // Close modal functions
1521
+ function closeModal() {
1522
+ modal.classList.remove('active');
1523
+ document.body.style.overflow = '';
1524
+ }
1525
+
1526
+ // Close on X button click
1527
+ closeBtn.addEventListener('click', closeModal);
1528
+
1529
+ // Close on overlay click (but not on image click)
1530
+ modal.addEventListener('click', function(e) {
1531
+ if (e.target === modal) {
1532
+ closeModal();
1533
+ }
1534
+ });
1535
+
1536
+ // Close on Escape key
1537
+ document.addEventListener('keydown', function(e) {
1538
+ if (e.key === 'Escape' && modal.classList.contains('active')) {
1539
+ closeModal();
1540
+ }
1541
+ });
1542
+
1543
+ // Prevent modal content from closing modal when clicked
1544
+ modalImg.addEventListener('click', function(e) {
1545
+ e.stopPropagation();
1546
+ });
1547
+
1548
+ document.querySelector('.image-modal-content').addEventListener('click', function(e) {
1549
+ e.stopPropagation();
1550
+ });
1551
+ }
1552
+
1321
1553
  // Initialize on DOM Load
1322
1554
  document.addEventListener('DOMContentLoaded', () => {
1555
+ initMarkdownLinkRedirects();
1323
1556
  highlightNavigation();
1324
1557
  generateTableOfContents();
1325
1558
  initSidebarResize();
@@ -1327,5 +1560,6 @@ document.addEventListener('DOMContentLoaded', () => {
1327
1560
  initNavigationFilter();
1328
1561
  addPDFExportButton();
1329
1562
  generateBreadcrumbs();
1563
+ initImageModal();
1330
1564
  initTooltips();
1331
1565
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@knowcode/doc-builder",
3
- "version": "1.8.7",
3
+ "version": "1.9.0",
4
4
  "description": "Reusable documentation builder for markdown-based sites with Vercel deployment support",
5
5
  "main": "index.js",
6
6
  "bin": {