@mgks/docmd 0.2.0 → 0.2.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.
- package/assets/css/welcome.css +6 -66
- package/config.js +14 -5
- package/docs/configuration.md +15 -6
- package/docs/content/containers/steps.md +2 -2
- package/docs/content/custom-containers.md +24 -0
- package/docs/content/no-style-example.md +2 -0
- package/docs/content/no-style-pages.md +52 -28
- package/docs/index.md +49 -18
- package/docs/plugins/seo.md +80 -33
- package/package.json +13 -7
- package/src/assets/css/docmd-main.css +6 -1168
- package/src/assets/css/docmd-theme-retro.css +3 -806
- package/src/assets/css/docmd-theme-ruby.css +7 -617
- package/src/assets/css/docmd-theme-sky.css +7 -650
- package/src/assets/js/docmd-image-lightbox.js +5 -1
- package/src/assets/js/docmd-main.js +164 -29
- package/src/commands/build.js +75 -134
- package/src/commands/dev.js +2 -1
- package/src/commands/init.js +6 -1
- package/src/core/config-loader.js +2 -0
- package/src/core/file-processor.js +147 -104
- package/src/core/html-generator.js +31 -12
- package/src/core/icon-renderer.js +3 -2
- package/src/plugins/analytics.js +5 -1
- package/src/plugins/seo.js +114 -66
- package/src/plugins/sitemap.js +6 -0
- package/src/templates/layout.ejs +8 -2
- package/src/templates/navigation.ejs +69 -98
- package/src/templates/no-style.ejs +23 -6
- package/src/templates/partials/theme-init.js +26 -0
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
//
|
|
1
|
+
// Source file from the docmd project — https://github.com/mgks/docmd
|
|
2
|
+
|
|
2
3
|
const fs = require('fs-extra');
|
|
3
4
|
const MarkdownIt = require('markdown-it');
|
|
4
5
|
const matter = require('gray-matter');
|
|
5
6
|
const hljs = require('highlight.js');
|
|
6
|
-
const container = require('markdown-it-container');
|
|
7
7
|
const attrs = require('markdown-it-attrs');
|
|
8
8
|
const path = require('path');
|
|
9
9
|
const markdown_it_footnote = require('markdown-it-footnote');
|
|
@@ -23,59 +23,80 @@ function formatPathForDisplay(absolutePath) {
|
|
|
23
23
|
return relativePath;
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
26
|
+
function createMarkdownItInstance(config) {
|
|
27
|
+
const mdOptions = {
|
|
28
|
+
html: true,
|
|
29
|
+
linkify: true,
|
|
30
|
+
typographer: true,
|
|
31
|
+
breaks: true,
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
// Conditionally enable highlighting
|
|
35
|
+
if (config.theme?.codeHighlight !== false) {
|
|
36
|
+
mdOptions.highlight = function (str, lang) {
|
|
37
|
+
if (lang && hljs.getLanguage(lang)) {
|
|
38
|
+
try {
|
|
39
|
+
return `<pre class="hljs"><code>${hljs.highlight(str, { language: lang, ignoreIllegals: true }).value}</code></pre>`;
|
|
40
|
+
} catch (e) { console.error(`Highlighting error for lang ${lang}:`, e); }
|
|
41
|
+
}
|
|
42
|
+
return `<pre class="hljs"><code>${new MarkdownIt().utils.escapeHtml(str)}</code></pre>`;
|
|
43
|
+
};
|
|
42
44
|
}
|
|
43
|
-
});
|
|
44
|
-
|
|
45
45
|
|
|
46
|
+
const md = new MarkdownIt(mdOptions);
|
|
47
|
+
|
|
48
|
+
// --- Attach all plugins and rules to this instance ---
|
|
49
|
+
md.use(attrs, { leftDelimiter: '{', rightDelimiter: '}' });
|
|
50
|
+
md.use(markdown_it_footnote);
|
|
51
|
+
md.use(markdown_it_task_lists);
|
|
52
|
+
md.use(markdown_it_abbr);
|
|
53
|
+
md.use(markdown_it_deflist);
|
|
54
|
+
md.use(headingIdPlugin);
|
|
55
|
+
|
|
56
|
+
// Register renderers for all containers
|
|
57
|
+
Object.keys(containers).forEach(containerName => {
|
|
58
|
+
const container = containers[containerName];
|
|
59
|
+
md.renderer.rules[`container_${containerName}_open`] = container.render;
|
|
60
|
+
md.renderer.rules[`container_${containerName}_close`] = container.render;
|
|
61
|
+
});
|
|
46
62
|
|
|
47
|
-
//
|
|
48
|
-
md.
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
md.
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
const token = tokens[idx];
|
|
58
|
-
|
|
59
|
-
// Escape HTML entities to prevent rendering
|
|
60
|
-
const escapedContent = token.content
|
|
61
|
-
.replace(/&/g, '&')
|
|
62
|
-
.replace(/</g, '<')
|
|
63
|
-
.replace(/>/g, '>')
|
|
64
|
-
.replace(/"/g, '"')
|
|
65
|
-
.replace(/'/g, ''');
|
|
66
|
-
|
|
67
|
-
// If no language is specified, preserve the original content without processing
|
|
68
|
-
if (!token.info || token.info.trim() === '') {
|
|
69
|
-
return '<pre class="hljs"><code>' + escapedContent + '</code></pre>';
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
// For all language blocks, preserve the original content to avoid processing HTML or other content
|
|
73
|
-
// This ensures code blocks are treated as literal text only
|
|
74
|
-
const language = token.info.trim();
|
|
75
|
-
return '<pre class="hljs"><code class="language-' + language + '">' + escapedContent + '</code></pre>';
|
|
76
|
-
};
|
|
63
|
+
// Register the enhanced rules
|
|
64
|
+
md.block.ruler.before('fence', 'steps_container', stepsContainerRule, {
|
|
65
|
+
alt: ['paragraph', 'reference', 'blockquote', 'list']
|
|
66
|
+
});
|
|
67
|
+
md.block.ruler.before('fence', 'enhanced_tabs', enhancedTabsRule, {
|
|
68
|
+
alt: ['paragraph', 'reference', 'blockquote', 'list']
|
|
69
|
+
});
|
|
70
|
+
md.block.ruler.before('paragraph', 'advanced_container', advancedContainerRule, {
|
|
71
|
+
alt: ['paragraph', 'reference', 'blockquote', 'list']
|
|
72
|
+
});
|
|
77
73
|
|
|
74
|
+
// Register all custom renderers
|
|
75
|
+
md.renderer.rules.ordered_list_open = customOrderedListOpenRenderer;
|
|
76
|
+
md.renderer.rules.list_item_open = customListItemOpenRenderer;
|
|
77
|
+
md.renderer.rules.image = customImageRenderer;
|
|
78
|
+
|
|
79
|
+
// Register tabs renderers
|
|
80
|
+
md.renderer.rules.tabs_open = tabsOpenRenderer;
|
|
81
|
+
md.renderer.rules.tabs_nav_open = tabsNavOpenRenderer;
|
|
82
|
+
md.renderer.rules.tabs_nav_close = tabsNavCloseRenderer;
|
|
83
|
+
md.renderer.rules.tabs_nav_item = tabsNavItemRenderer;
|
|
84
|
+
md.renderer.rules.tabs_content_open = tabsContentOpenRenderer;
|
|
85
|
+
md.renderer.rules.tabs_content_close = tabsContentCloseRenderer;
|
|
86
|
+
md.renderer.rules.tab_pane_open = tabPaneOpenRenderer;
|
|
87
|
+
md.renderer.rules.tab_pane_close = tabPaneCloseRenderer;
|
|
88
|
+
md.renderer.rules.tabs_close = tabsCloseRenderer;
|
|
89
|
+
|
|
90
|
+
// Register heading ID plugin
|
|
91
|
+
md.use(headingIdPlugin);
|
|
92
|
+
|
|
93
|
+
// Register standalone closing rule
|
|
94
|
+
md.block.ruler.before('paragraph', 'standalone_closing', standaloneClosingRule, {
|
|
95
|
+
alt: ['paragraph', 'reference', 'blockquote', 'list']
|
|
96
|
+
});
|
|
78
97
|
|
|
98
|
+
return md;
|
|
99
|
+
}
|
|
79
100
|
|
|
80
101
|
// ===================================================================
|
|
81
102
|
// --- ADVANCED NESTED CONTAINER SYSTEM ---
|
|
@@ -164,8 +185,6 @@ const containers = {
|
|
|
164
185
|
// }
|
|
165
186
|
};
|
|
166
187
|
|
|
167
|
-
|
|
168
|
-
|
|
169
188
|
// Advanced container rule with proper nesting support
|
|
170
189
|
function advancedContainerRule(state, startLine, endLine, silent) {
|
|
171
190
|
const start = state.bMarks[startLine] + state.tShift[startLine];
|
|
@@ -452,7 +471,7 @@ function enhancedTabsRule(state, startLine, endLine, silent) {
|
|
|
452
471
|
'</code></pre>';
|
|
453
472
|
} catch (e) { console.error(`Error highlighting language ${lang}:`, e); }
|
|
454
473
|
}
|
|
455
|
-
return '<pre class="hljs"><code>' + str + '</code></pre>';
|
|
474
|
+
return '<pre class="hljs"><code>' + MarkdownIt.utils.escapeHtml(str) + '</code></pre>';
|
|
456
475
|
}
|
|
457
476
|
});
|
|
458
477
|
|
|
@@ -481,6 +500,30 @@ function enhancedTabsRule(state, startLine, endLine, silent) {
|
|
|
481
500
|
alt: ['paragraph', 'reference', 'blockquote', 'list']
|
|
482
501
|
});
|
|
483
502
|
|
|
503
|
+
// Register custom renderers for the tab markdown instance
|
|
504
|
+
tabMd.renderer.rules.ordered_list_open = customOrderedListOpenRenderer;
|
|
505
|
+
tabMd.renderer.rules.list_item_open = customListItemOpenRenderer;
|
|
506
|
+
tabMd.renderer.rules.image = customImageRenderer;
|
|
507
|
+
|
|
508
|
+
// Register tabs renderers for the tab markdown instance
|
|
509
|
+
tabMd.renderer.rules.tabs_open = tabsOpenRenderer;
|
|
510
|
+
tabMd.renderer.rules.tabs_nav_open = tabsNavOpenRenderer;
|
|
511
|
+
tabMd.renderer.rules.tabs_nav_close = tabsNavCloseRenderer;
|
|
512
|
+
tabMd.renderer.rules.tabs_nav_item = tabsNavItemRenderer;
|
|
513
|
+
tabMd.renderer.rules.tabs_content_open = tabsContentOpenRenderer;
|
|
514
|
+
tabMd.renderer.rules.tabs_content_close = tabsContentCloseRenderer;
|
|
515
|
+
tabMd.renderer.rules.tab_pane_open = tabPaneOpenRenderer;
|
|
516
|
+
tabMd.renderer.rules.tab_pane_close = tabPaneCloseRenderer;
|
|
517
|
+
tabMd.renderer.rules.tabs_close = tabsCloseRenderer;
|
|
518
|
+
|
|
519
|
+
// Register heading ID plugin for the tab markdown instance
|
|
520
|
+
tabMd.use(headingIdPlugin);
|
|
521
|
+
|
|
522
|
+
// Register standalone closing rule for the tab markdown instance
|
|
523
|
+
tabMd.block.ruler.before('paragraph', 'standalone_closing', standaloneClosingRule, {
|
|
524
|
+
alt: ['paragraph', 'reference', 'blockquote', 'list']
|
|
525
|
+
});
|
|
526
|
+
|
|
484
527
|
// Render the tab content
|
|
485
528
|
const renderedContent = tabMd.render(tabContent);
|
|
486
529
|
const htmlToken = state.push('html_block', '', 0);
|
|
@@ -495,19 +538,8 @@ function enhancedTabsRule(state, startLine, endLine, silent) {
|
|
|
495
538
|
return true;
|
|
496
539
|
}
|
|
497
540
|
|
|
498
|
-
// Register the enhanced rules
|
|
499
|
-
md.block.ruler.before('fence', 'steps_container', stepsContainerRule, {
|
|
500
|
-
alt: ['paragraph', 'reference', 'blockquote', 'list']
|
|
501
|
-
});
|
|
502
|
-
md.block.ruler.before('fence', 'enhanced_tabs', enhancedTabsRule, {
|
|
503
|
-
alt: ['paragraph', 'reference', 'blockquote', 'list']
|
|
504
|
-
});
|
|
505
|
-
md.block.ruler.before('paragraph', 'advanced_container', advancedContainerRule, {
|
|
506
|
-
alt: ['paragraph', 'reference', 'blockquote', 'list']
|
|
507
|
-
});
|
|
508
|
-
|
|
509
541
|
// Add a rule to handle standalone closing tags
|
|
510
|
-
|
|
542
|
+
const standaloneClosingRule = (state, startLine, endLine, silent) => {
|
|
511
543
|
const start = state.bMarks[startLine] + state.tShift[startLine];
|
|
512
544
|
const max = state.eMarks[startLine];
|
|
513
545
|
const lineContent = state.src.slice(start, max).trim();
|
|
@@ -520,19 +552,10 @@ md.block.ruler.before('paragraph', 'standalone_closing', (state, startLine, endL
|
|
|
520
552
|
}
|
|
521
553
|
|
|
522
554
|
return false;
|
|
523
|
-
}
|
|
524
|
-
alt: ['paragraph', 'reference', 'blockquote', 'list']
|
|
525
|
-
});
|
|
526
|
-
|
|
527
|
-
// Register renderers for all containers
|
|
528
|
-
Object.keys(containers).forEach(containerName => {
|
|
529
|
-
const container = containers[containerName];
|
|
530
|
-
md.renderer.rules[`container_${containerName}_open`] = container.render;
|
|
531
|
-
md.renderer.rules[`container_${containerName}_close`] = container.render;
|
|
532
|
-
});
|
|
555
|
+
};
|
|
533
556
|
|
|
534
557
|
// Custom renderer for ordered lists in steps containers
|
|
535
|
-
|
|
558
|
+
const customOrderedListOpenRenderer = function(tokens, idx, options, env, self) {
|
|
536
559
|
const token = tokens[idx];
|
|
537
560
|
// Check if we're inside a steps container by looking at the context
|
|
538
561
|
let isInSteps = false;
|
|
@@ -561,7 +584,7 @@ md.renderer.rules.ordered_list_open = function(tokens, idx, options, env, self)
|
|
|
561
584
|
};
|
|
562
585
|
|
|
563
586
|
// Custom renderer for list items in steps containers
|
|
564
|
-
|
|
587
|
+
const customListItemOpenRenderer = function(tokens, idx, options, env, self) {
|
|
565
588
|
const token = tokens[idx];
|
|
566
589
|
// Check if we're inside a steps container and this is a direct child
|
|
567
590
|
let isInStepsList = false;
|
|
@@ -596,34 +619,34 @@ md.renderer.rules.list_item_open = function(tokens, idx, options, env, self) {
|
|
|
596
619
|
};
|
|
597
620
|
|
|
598
621
|
// Enhanced tabs renderers
|
|
599
|
-
|
|
622
|
+
const tabsOpenRenderer = (tokens, idx) => {
|
|
600
623
|
const token = tokens[idx];
|
|
601
624
|
return `<div class="${token.attrs.map(attr => attr[1]).join(' ')}">`;
|
|
602
625
|
};
|
|
603
626
|
|
|
604
|
-
|
|
605
|
-
|
|
627
|
+
const tabsNavOpenRenderer = () => '<div class="docmd-tabs-nav">';
|
|
628
|
+
const tabsNavCloseRenderer = () => '</div>';
|
|
606
629
|
|
|
607
|
-
|
|
630
|
+
const tabsNavItemRenderer = (tokens, idx) => {
|
|
608
631
|
const token = tokens[idx];
|
|
609
632
|
return `<div class="${token.attrs[0][1]}">${token.content}</div>`;
|
|
610
633
|
};
|
|
611
634
|
|
|
612
|
-
|
|
613
|
-
|
|
635
|
+
const tabsContentOpenRenderer = () => '<div class="docmd-tabs-content">';
|
|
636
|
+
const tabsContentCloseRenderer = () => '</div>';
|
|
614
637
|
|
|
615
|
-
|
|
638
|
+
const tabPaneOpenRenderer = (tokens, idx) => {
|
|
616
639
|
const token = tokens[idx];
|
|
617
640
|
return `<div class="${token.attrs[0][1]}">`;
|
|
618
641
|
};
|
|
619
642
|
|
|
620
|
-
|
|
643
|
+
const tabPaneCloseRenderer = () => '</div>';
|
|
621
644
|
|
|
622
|
-
|
|
645
|
+
const tabsCloseRenderer = () => '</div>';
|
|
623
646
|
|
|
624
647
|
// Override the default image renderer to properly handle attributes like {.class}.
|
|
625
|
-
const
|
|
626
|
-
|
|
648
|
+
const customImageRenderer = function(tokens, idx, options, env, self) {
|
|
649
|
+
const defaultImageRenderer = function(tokens, idx, options, env, self) { return self.renderToken(tokens, idx, options); };
|
|
627
650
|
const renderedImage = defaultImageRenderer(tokens, idx, options, env, self);
|
|
628
651
|
const nextToken = tokens[idx + 1];
|
|
629
652
|
if (nextToken && nextToken.type === 'attrs_block') {
|
|
@@ -635,22 +658,33 @@ md.renderer.rules.image = function(tokens, idx, options, env, self) {
|
|
|
635
658
|
};
|
|
636
659
|
|
|
637
660
|
// Add IDs to headings for anchor links, used by the Table of Contents.
|
|
638
|
-
|
|
639
|
-
const
|
|
661
|
+
const headingIdPlugin = (md) => {
|
|
662
|
+
const originalHeadingOpen = md.renderer.rules.heading_open || function(tokens, idx, options, env, self) {
|
|
640
663
|
return self.renderToken(tokens, idx, options);
|
|
641
664
|
};
|
|
665
|
+
|
|
642
666
|
md.renderer.rules.heading_open = function(tokens, idx, options, env, self) {
|
|
643
667
|
const token = tokens[idx];
|
|
644
668
|
const contentToken = tokens[idx + 1];
|
|
645
|
-
|
|
669
|
+
|
|
670
|
+
if (contentToken && contentToken.type === 'inline' && contentToken.content) {
|
|
646
671
|
const headingText = contentToken.content;
|
|
647
|
-
const id = headingText
|
|
648
|
-
|
|
672
|
+
const id = headingText
|
|
673
|
+
.toLowerCase()
|
|
674
|
+
.replace(/\s+/g, '-') // Replace spaces with -
|
|
675
|
+
.replace(/[^\w-]+/g, '') // Remove all non-word chars
|
|
676
|
+
.replace(/--+/g, '-') // Replace multiple - with single -
|
|
677
|
+
.replace(/^-+/, '') // Trim - from start of text
|
|
678
|
+
.replace(/-+$/, ''); // Trim - from end of text
|
|
679
|
+
|
|
680
|
+
if (id) {
|
|
681
|
+
token.attrSet('id', id);
|
|
682
|
+
}
|
|
649
683
|
}
|
|
650
|
-
|
|
684
|
+
|
|
685
|
+
return originalHeadingOpen(tokens, idx, options, env, self);
|
|
651
686
|
};
|
|
652
|
-
}
|
|
653
|
-
|
|
687
|
+
};
|
|
654
688
|
|
|
655
689
|
// ===================================================================
|
|
656
690
|
// --- SAFE CONTAINER WRAPPER (FOR SIMPLE CONTAINERS) ---
|
|
@@ -685,13 +719,21 @@ function extractHeadingsFromHtml(htmlContent) {
|
|
|
685
719
|
return headings;
|
|
686
720
|
}
|
|
687
721
|
|
|
688
|
-
async function processMarkdownFile(filePath,
|
|
722
|
+
async function processMarkdownFile(filePath, md, config) {
|
|
689
723
|
const rawContent = await fs.readFile(filePath, 'utf8');
|
|
690
|
-
let
|
|
724
|
+
let frontmatter, markdownContent;
|
|
725
|
+
|
|
726
|
+
try {
|
|
727
|
+
({ data: frontmatter, content: markdownContent } = matter(rawContent));
|
|
728
|
+
} catch (e) {
|
|
729
|
+
console.error(`❌ Error parsing frontmatter in ${formatPathForDisplay(filePath)}:`);
|
|
730
|
+
console.error(` ${e.message}`);
|
|
731
|
+
console.error(' This page will be skipped. Please fix the YAML syntax.');
|
|
732
|
+
return null;
|
|
733
|
+
}
|
|
691
734
|
|
|
692
|
-
// Handle autoTitleFromH1
|
|
693
735
|
if (!frontmatter.title) {
|
|
694
|
-
if (config.autoTitleFromH1 !== false) {
|
|
736
|
+
if (config.autoTitleFromH1 !== false) {
|
|
695
737
|
const h1Match = markdownContent.match(/^#\s+(.*)/m);
|
|
696
738
|
if (h1Match && h1Match[1]) {
|
|
697
739
|
frontmatter.title = h1Match[1].trim();
|
|
@@ -702,11 +744,12 @@ async function processMarkdownFile(filePath, options = { isDev: false }, config)
|
|
|
702
744
|
}
|
|
703
745
|
}
|
|
704
746
|
|
|
705
|
-
// For no-style pages, skip markdown processing and treat content as raw HTML
|
|
706
747
|
let htmlContent, headings;
|
|
707
748
|
if (frontmatter.noStyle === true) {
|
|
708
|
-
|
|
709
|
-
|
|
749
|
+
// For noStyle pages, NO markdown processing at all
|
|
750
|
+
// Pass the raw content directly as-is
|
|
751
|
+
htmlContent = markdownContent;
|
|
752
|
+
headings = [];
|
|
710
753
|
} else {
|
|
711
754
|
htmlContent = md.render(markdownContent);
|
|
712
755
|
headings = extractHeadingsFromHtml(htmlContent);
|
|
@@ -735,7 +778,7 @@ async function findMarkdownFiles(dir) {
|
|
|
735
778
|
|
|
736
779
|
module.exports = {
|
|
737
780
|
processMarkdownFile,
|
|
738
|
-
|
|
781
|
+
createMarkdownItInstance,
|
|
739
782
|
extractHeadingsFromHtml,
|
|
740
783
|
findMarkdownFiles
|
|
741
784
|
};
|
|
@@ -1,38 +1,51 @@
|
|
|
1
|
-
//
|
|
1
|
+
//
|
|
2
|
+
|
|
2
3
|
const ejs = require('ejs');
|
|
3
4
|
const path = require('path');
|
|
4
5
|
const fs = require('fs-extra');
|
|
5
|
-
const {
|
|
6
|
+
const { createMarkdownItInstance } = require('./file-processor');
|
|
6
7
|
const { generateSeoMetaTags } = require('../plugins/seo');
|
|
7
8
|
const { generateAnalyticsScripts } = require('../plugins/analytics');
|
|
8
|
-
const { renderIcon } = require('./icon-renderer');
|
|
9
|
+
const { renderIcon } = require('./icon-renderer');
|
|
10
|
+
|
|
11
|
+
// Create a markdown instance for inline rendering
|
|
12
|
+
let mdInstance = null;
|
|
13
|
+
|
|
14
|
+
let themeInitScript = '';
|
|
15
|
+
(async () => {
|
|
16
|
+
const themeInitPath = path.join(__dirname, '..', 'templates', 'partials', 'theme-init.js');
|
|
17
|
+
if (await fs.pathExists(themeInitPath)) {
|
|
18
|
+
const scriptContent = await fs.readFile(themeInitPath, 'utf8');
|
|
19
|
+
themeInitScript = `<script>${scriptContent}</script>`;
|
|
20
|
+
}
|
|
21
|
+
})();
|
|
9
22
|
|
|
10
23
|
async function processPluginHooks(config, pageData, relativePathToRoot) {
|
|
11
24
|
let metaTagsHtml = '';
|
|
12
25
|
let faviconLinkHtml = '';
|
|
13
|
-
let themeCssLinkHtml = '';
|
|
14
|
-
let pluginStylesHtml = '';
|
|
26
|
+
let themeCssLinkHtml = '';
|
|
27
|
+
let pluginStylesHtml = '';
|
|
15
28
|
let pluginHeadScriptsHtml = '';
|
|
16
29
|
let pluginBodyScriptsHtml = '';
|
|
17
30
|
|
|
18
|
-
//
|
|
31
|
+
// Favicon (built-in handling)
|
|
19
32
|
if (config.favicon) {
|
|
20
33
|
const faviconPath = config.favicon.startsWith('/') ? config.favicon.substring(1) : config.favicon;
|
|
21
34
|
faviconLinkHtml = `<link rel="shortcut icon" href="${relativePathToRoot}${faviconPath}" type="image/x-icon">\n`;
|
|
22
35
|
}
|
|
23
36
|
|
|
24
|
-
//
|
|
37
|
+
// Theme CSS (built-in handling for theme.name)
|
|
25
38
|
if (config.theme && config.theme.name && config.theme.name !== 'default') {
|
|
26
39
|
const themeCssPath = `assets/css/docmd-theme-${config.theme.name}.css`;
|
|
27
40
|
themeCssLinkHtml = ` <link rel="stylesheet" href="${relativePathToRoot}${themeCssPath}">\n`;
|
|
28
41
|
}
|
|
29
42
|
|
|
30
|
-
//
|
|
43
|
+
// SEO Plugin (if configured)
|
|
31
44
|
if (config.plugins?.seo) {
|
|
32
45
|
metaTagsHtml += generateSeoMetaTags(config, pageData, relativePathToRoot);
|
|
33
46
|
}
|
|
34
47
|
|
|
35
|
-
//
|
|
48
|
+
// Analytics Plugin (if configured)
|
|
36
49
|
if (config.plugins?.analytics) {
|
|
37
50
|
const analyticsScripts = generateAnalyticsScripts(config, pageData);
|
|
38
51
|
pluginHeadScriptsHtml += analyticsScripts.headScriptsHtml;
|
|
@@ -56,17 +69,21 @@ async function generateHtmlPage(templateData) {
|
|
|
56
69
|
prevPage, nextPage, currentPagePath, headings
|
|
57
70
|
} = templateData;
|
|
58
71
|
|
|
59
|
-
const pageTitle = frontmatter.title;
|
|
72
|
+
const pageTitle = frontmatter.title;
|
|
60
73
|
|
|
61
74
|
// Process plugins to get their HTML contributions
|
|
62
75
|
const pluginOutputs = await processPluginHooks(
|
|
63
76
|
config,
|
|
64
|
-
{ frontmatter, outputPath },
|
|
77
|
+
{ frontmatter, outputPath },
|
|
65
78
|
relativePathToRoot
|
|
66
79
|
);
|
|
67
80
|
|
|
68
81
|
let footerHtml = '';
|
|
69
82
|
if (config.footer) {
|
|
83
|
+
// Initialize mdInstance if not already done
|
|
84
|
+
if (!mdInstance) {
|
|
85
|
+
mdInstance = createMarkdownItInstance(config);
|
|
86
|
+
}
|
|
70
87
|
footerHtml = mdInstance.renderInline(config.footer);
|
|
71
88
|
}
|
|
72
89
|
|
|
@@ -85,7 +102,8 @@ async function generateHtmlPage(templateData) {
|
|
|
85
102
|
|
|
86
103
|
const ejsData = {
|
|
87
104
|
content,
|
|
88
|
-
pageTitle,
|
|
105
|
+
pageTitle,
|
|
106
|
+
themeInitScript,
|
|
89
107
|
description: frontmatter.description,
|
|
90
108
|
siteTitle,
|
|
91
109
|
navigationHtml,
|
|
@@ -109,6 +127,7 @@ async function generateHtmlPage(templateData) {
|
|
|
109
127
|
headings: headings || [],
|
|
110
128
|
isActivePage,
|
|
111
129
|
frontmatter,
|
|
130
|
+
config: config,
|
|
112
131
|
...pluginOutputs,
|
|
113
132
|
};
|
|
114
133
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
//
|
|
2
|
-
|
|
1
|
+
// Source file from the docmd project — https://github.com/mgks/docmd
|
|
2
|
+
|
|
3
|
+
const lucideStatic = require('lucide-static');
|
|
3
4
|
|
|
4
5
|
// On first load, log debug information about a specific icon to understand its structure
|
|
5
6
|
let debugRun = false;
|
package/src/plugins/analytics.js
CHANGED