@mgks/docmd 0.1.0 → 0.1.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/.github/workflows/publish.yml +1 -1
- package/README.md +2 -2
- package/bin/docmd.js +8 -2
- package/config.js +31 -31
- package/docs/cli-commands.md +13 -0
- package/docs/content/images.md +205 -0
- package/docs/content/index.md +17 -0
- package/docs/theming/assets-management.md +126 -0
- package/docs/theming/custom-css-js.md +3 -6
- package/package.json +2 -1
- package/src/assets/css/{main.css → docmd-main.css} +255 -10
- package/src/assets/css/{theme-sky.css → docmd-theme-sky.css} +153 -1
- package/src/assets/js/docmd-image-lightbox.js +72 -0
- package/src/assets/js/{theme-toggle.js → docmd-theme-toggle.js} +4 -4
- package/src/commands/build.js +151 -9
- package/src/commands/dev.js +103 -17
- package/src/commands/init.js +198 -17
- package/src/core/file-processor.js +40 -0
- package/src/core/html-generator.js +7 -3
- package/src/plugins/sitemap.js +10 -3
- package/src/templates/layout.ejs +5 -63
- package/src/templates/toc.ejs +53 -20
- package/docs/writing-content/index.md +0 -17
- package/src/assets/css/toc.css +0 -76
- /package/docs/{writing-content → content}/custom-containers.md +0 -0
- /package/docs/{writing-content → content}/frontmatter.md +0 -0
- /package/docs/{writing-content → content}/markdown-syntax.md +0 -0
- /package/src/assets/css/{highlight-dark.css → docmd-highlight-dark.css} +0 -0
- /package/src/assets/css/{highlight-light.css → docmd-highlight-light.css} +0 -0
- /package/src/assets/images/{logo-dark.png → docmd-logo-dark.png} +0 -0
- /package/src/assets/images/{logo-light.png → docmd-logo-light.png} +0 -0
|
@@ -23,8 +23,8 @@ async function processPluginHooks(config, pageData, relativePathToRoot) {
|
|
|
23
23
|
|
|
24
24
|
// 2. Theme CSS (built-in handling for theme.name)
|
|
25
25
|
if (config.theme && config.theme.name && config.theme.name !== 'default') {
|
|
26
|
-
// Assumes theme CSS files are like 'theme-yourthemename.css' in assets/css
|
|
27
|
-
const themeCssPath = `assets/css/theme-${config.theme.name}.css`;
|
|
26
|
+
// Assumes theme CSS files are like 'docmd-theme-yourthemename.css' in assets/css
|
|
27
|
+
const themeCssPath = `assets/css/docmd-theme-${config.theme.name}.css`;
|
|
28
28
|
// Check if theme file exists before linking (optional, good practice)
|
|
29
29
|
// For now, assume it will exist if specified.
|
|
30
30
|
themeCssLinkHtml = ` <link rel="stylesheet" href="${relativePathToRoot}${themeCssPath}">\n`;
|
|
@@ -109,7 +109,9 @@ async function generateHtmlPage(templateData) {
|
|
|
109
109
|
};
|
|
110
110
|
|
|
111
111
|
try {
|
|
112
|
-
return ejs.render(layoutTemplate, ejsData
|
|
112
|
+
return ejs.render(layoutTemplate, ejsData, {
|
|
113
|
+
filename: layoutTemplatePath // Add filename for proper include resolution
|
|
114
|
+
});
|
|
113
115
|
} catch (e) {
|
|
114
116
|
console.error(`❌ Error rendering EJS template for ${outputPath}: ${e.message}`);
|
|
115
117
|
console.error("EJS Data:", JSON.stringify(ejsData, null, 2).substring(0, 1000) + "..."); // Log partial data
|
|
@@ -133,6 +135,8 @@ async function generateNavigationHtml(navItems, currentPagePath, relativePathToR
|
|
|
133
135
|
relativePathToRoot,
|
|
134
136
|
config, // Pass full config if needed by nav (e.g. for base path)
|
|
135
137
|
...ejsHelpers
|
|
138
|
+
}, {
|
|
139
|
+
filename: navTemplatePath // Add filename for proper include resolution
|
|
136
140
|
});
|
|
137
141
|
}
|
|
138
142
|
|
package/src/plugins/sitemap.js
CHANGED
|
@@ -6,11 +6,15 @@ const path = require('path');
|
|
|
6
6
|
* @param {Object} config - The full configuration object
|
|
7
7
|
* @param {Array} pages - Array of page objects with data about each processed page
|
|
8
8
|
* @param {string} outputDir - Path to the output directory
|
|
9
|
+
* @param {Object} options - Additional options
|
|
10
|
+
* @param {boolean} options.isDev - Whether running in development mode
|
|
9
11
|
*/
|
|
10
|
-
async function generateSitemap(config, pages, outputDir) {
|
|
12
|
+
async function generateSitemap(config, pages, outputDir, options = { isDev: false }) {
|
|
11
13
|
// Skip if no siteUrl is defined (sitemap needs absolute URLs)
|
|
12
14
|
if (!config.siteUrl) {
|
|
13
|
-
|
|
15
|
+
if (!options.isDev) {
|
|
16
|
+
console.warn('⚠️ No siteUrl defined in config. Skipping sitemap generation.');
|
|
17
|
+
}
|
|
14
18
|
return;
|
|
15
19
|
}
|
|
16
20
|
|
|
@@ -94,7 +98,10 @@ async function generateSitemap(config, pages, outputDir) {
|
|
|
94
98
|
const sitemapPath = path.join(outputDir, 'sitemap.xml');
|
|
95
99
|
await fs.writeFile(sitemapPath, sitemapXml);
|
|
96
100
|
|
|
97
|
-
|
|
101
|
+
// Only show sitemap generation message in production mode or if DOCMD_DEV is true
|
|
102
|
+
if (!options.isDev || process.env.DOCMD_DEV === 'true') {
|
|
103
|
+
console.log(`✅ Generated sitemap at ${sitemapPath}`);
|
|
104
|
+
}
|
|
98
105
|
}
|
|
99
106
|
|
|
100
107
|
module.exports = { generateSitemap };
|
package/src/templates/layout.ejs
CHANGED
|
@@ -13,9 +13,9 @@
|
|
|
13
13
|
|
|
14
14
|
<%- faviconLinkHtml || '' %> <%# Favicon %>
|
|
15
15
|
|
|
16
|
-
<link rel="stylesheet" href="<%= relativePathToRoot %>assets/css/main.css">
|
|
16
|
+
<link rel="stylesheet" href="<%= relativePathToRoot %>assets/css/docmd-main.css">
|
|
17
17
|
|
|
18
|
-
<link rel="stylesheet" href="<%= relativePathToRoot %>assets/css/highlight-<%= defaultMode === 'dark' ? 'dark' : 'light' %>.css" id="highlight-theme">
|
|
18
|
+
<link rel="stylesheet" href="<%= relativePathToRoot %>assets/css/docmd-highlight-<%= defaultMode === 'dark' ? 'dark' : 'light' %>.css" id="highlight-theme">
|
|
19
19
|
|
|
20
20
|
<%- themeCssLinkHtml || '' %> <%# For theme.name specific CSS %>
|
|
21
21
|
|
|
@@ -90,65 +90,7 @@
|
|
|
90
90
|
|
|
91
91
|
<!-- TOC sidebar -->
|
|
92
92
|
<div class="toc-sidebar">
|
|
93
|
-
|
|
94
|
-
// Helper function to decode HTML entities
|
|
95
|
-
function decodeHtmlEntities(html) {
|
|
96
|
-
return html
|
|
97
|
-
.replace(/&/g, '&')
|
|
98
|
-
.replace(/</g, '<')
|
|
99
|
-
.replace(/>/g, '>')
|
|
100
|
-
.replace(/"/g, '"')
|
|
101
|
-
.replace(/'/g, "'")
|
|
102
|
-
.replace(/ /g, ' ');
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
// Only show TOC on active pages
|
|
106
|
-
const isActive = navigationHtml && navigationHtml.includes('class="active"');
|
|
107
|
-
|
|
108
|
-
if (isActive) {
|
|
109
|
-
// Extract headings directly from content - match with or without id attribute
|
|
110
|
-
const headingRegex = /<h([2-4])[^>]*?(?:id="([^"]*)")?[^>]*?>([\s\S]*?)<\/h\1>/g;
|
|
111
|
-
const tocHeadings = [];
|
|
112
|
-
let match;
|
|
113
|
-
let contentStr = content.toString();
|
|
114
|
-
|
|
115
|
-
while ((match = headingRegex.exec(contentStr)) !== null) {
|
|
116
|
-
const level = parseInt(match[1], 10);
|
|
117
|
-
// Use ID if available, or generate one from the text
|
|
118
|
-
let id = match[2];
|
|
119
|
-
// Remove any HTML tags inside the heading text and decode HTML entities
|
|
120
|
-
const textWithTags = match[3].replace(/<\/?[^>]+(>|$)/g, '');
|
|
121
|
-
// Decode HTML entities
|
|
122
|
-
const text = decodeHtmlEntities(textWithTags);
|
|
123
|
-
|
|
124
|
-
if (!id) {
|
|
125
|
-
// Generate an ID from the heading text if none exists
|
|
126
|
-
id = text
|
|
127
|
-
.toLowerCase()
|
|
128
|
-
.replace(/\s+/g, '-')
|
|
129
|
-
.replace(/[^\w-]/g, '')
|
|
130
|
-
.replace(/--+/g, '-')
|
|
131
|
-
.replace(/^-+|-+$/g, '');
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
tocHeadings.push({ id, level, text });
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
// Only show TOC if there are enough headings
|
|
138
|
-
if (tocHeadings.length > 1) {
|
|
139
|
-
%>
|
|
140
|
-
<div class="toc-container">
|
|
141
|
-
<h2 class="toc-title">On This Page</h2>
|
|
142
|
-
<ul class="toc-list">
|
|
143
|
-
<% tocHeadings.forEach(heading => { %>
|
|
144
|
-
<li class="toc-item toc-level-<%= heading.level %>">
|
|
145
|
-
<a href="#<%= heading.id %>" class="toc-link"><%- heading.text %></a>
|
|
146
|
-
</li>
|
|
147
|
-
<% }); %>
|
|
148
|
-
</ul>
|
|
149
|
-
</div>
|
|
150
|
-
<% }
|
|
151
|
-
} %>
|
|
93
|
+
<%- include('toc', { content, headings, navigationHtml, isActivePage }) %>
|
|
152
94
|
</div>
|
|
153
95
|
</div>
|
|
154
96
|
</main>
|
|
@@ -158,13 +100,13 @@
|
|
|
158
100
|
<%- footerHtml || '' %>
|
|
159
101
|
</div>
|
|
160
102
|
<div class="branding-footer">
|
|
161
|
-
Build with
|
|
103
|
+
Build with <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M19 14c1.49-1.46 3-3.21 3-5.5A5.5 5.5 0 0 0 16.5 3c-1.76 0-3 .5-4.5 2-1.5-1.5-2.74-2-4.5-2A5.5 5.5 0 0 0 2 8.5c0 2.3 1.5 4.05 3 5.5l7 7Z"></path><path d="M12 5 9.04 7.96a2.17 2.17 0 0 0 0 3.08c.82.82 2.13.85 3 .07l2.07-1.9a2.82 2.82 0 0 1 3.79 0l2.96 2.66"></path><path d="m18 15-2-2"></path><path d="m15 18-2-2"></path></svg> <a href="https://docmd.mgks.dev" target="_blank" rel="noopener">docmd.</a>
|
|
162
104
|
</div>
|
|
163
105
|
</div>
|
|
164
106
|
</footer>
|
|
165
107
|
</div>
|
|
166
108
|
|
|
167
|
-
<script src="<%= relativePathToRoot %>assets/js/theme-toggle.js"></script>
|
|
109
|
+
<script src="<%= relativePathToRoot %>assets/js/docmd-theme-toggle.js"></script>
|
|
168
110
|
<% (customJsFiles || []).forEach(jsFile => { %>
|
|
169
111
|
<script src="<%= relativePathToRoot %><%- jsFile.startsWith('/') ? jsFile.substring(1) : jsFile %>"></script>
|
|
170
112
|
<% }); %>
|
package/src/templates/toc.ejs
CHANGED
|
@@ -1,34 +1,67 @@
|
|
|
1
1
|
<%# src/templates/toc.ejs %>
|
|
2
2
|
<%
|
|
3
|
-
//
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
while ((match = headingRegex.exec(content)) !== null) {
|
|
13
|
-
const level = parseInt(match[1], 10);
|
|
14
|
-
const id = match[2];
|
|
15
|
-
// Remove any HTML tags inside the heading text
|
|
16
|
-
const text = match[3].replace(/<\/?[^>]+(>|$)/g, '');
|
|
17
|
-
tocHeadings.push({ id, level, text });
|
|
18
|
-
}
|
|
3
|
+
// Helper function to decode HTML entities
|
|
4
|
+
function decodeHtmlEntities(html) {
|
|
5
|
+
return html
|
|
6
|
+
.replace(/&/g, '&')
|
|
7
|
+
.replace(/</g, '<')
|
|
8
|
+
.replace(/>/g, '>')
|
|
9
|
+
.replace(/"/g, '"')
|
|
10
|
+
.replace(/'/g, "'")
|
|
11
|
+
.replace(/ /g, ' ');
|
|
19
12
|
}
|
|
20
13
|
|
|
21
|
-
//
|
|
22
|
-
|
|
14
|
+
// Use the isActivePage flag if provided, otherwise fall back to checking navigationHtml
|
|
15
|
+
const shouldShowToc = typeof isActivePage !== 'undefined' ? isActivePage :
|
|
16
|
+
(typeof navigationHtml !== 'undefined' && navigationHtml && navigationHtml.includes('class="active"'));
|
|
17
|
+
|
|
18
|
+
if (shouldShowToc) {
|
|
19
|
+
// If direct headings aren't available, we'll try to extract them from the content
|
|
20
|
+
let tocHeadings = [];
|
|
21
|
+
if (headings && headings.length > 0) {
|
|
22
|
+
// Use provided headings if available
|
|
23
|
+
tocHeadings = headings.filter(h => h.level >= 2 && h.level <= 4);
|
|
24
|
+
} else if (content) {
|
|
25
|
+
// Basic regex to extract headings from HTML content
|
|
26
|
+
const headingRegex = /<h([2-4])[^>]*?(?:id="([^"]*)")?[^>]*?>([\s\S]*?)<\/h\1>/g;
|
|
27
|
+
let match;
|
|
28
|
+
let contentStr = content.toString();
|
|
29
|
+
|
|
30
|
+
while ((match = headingRegex.exec(contentStr)) !== null) {
|
|
31
|
+
const level = parseInt(match[1], 10);
|
|
32
|
+
// Use ID if available, or generate one from the text
|
|
33
|
+
let id = match[2];
|
|
34
|
+
// Remove any HTML tags inside the heading text
|
|
35
|
+
const textWithTags = match[3].replace(/<\/?[^>]+(>|$)/g, '');
|
|
36
|
+
// Decode HTML entities
|
|
37
|
+
const text = decodeHtmlEntities(textWithTags);
|
|
38
|
+
|
|
39
|
+
if (!id) {
|
|
40
|
+
// Generate an ID from the heading text if none exists
|
|
41
|
+
id = text
|
|
42
|
+
.toLowerCase()
|
|
43
|
+
.replace(/\s+/g, '-')
|
|
44
|
+
.replace(/[^\w-]/g, '')
|
|
45
|
+
.replace(/--+/g, '-')
|
|
46
|
+
.replace(/^-+|-+$/g, '');
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
tocHeadings.push({ id, level, text });
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Only show TOC if there are enough headings
|
|
54
|
+
if (tocHeadings.length > 1) {
|
|
23
55
|
%>
|
|
24
56
|
<div class="toc-container">
|
|
25
57
|
<h2 class="toc-title">On This Page</h2>
|
|
26
58
|
<ul class="toc-list">
|
|
27
59
|
<% tocHeadings.forEach(heading => { %>
|
|
28
60
|
<li class="toc-item toc-level-<%= heading.level %>">
|
|
29
|
-
<a href="#<%= heading.id %>" class="toc-link"
|
|
61
|
+
<a href="#<%= heading.id %>" class="toc-link"><%- heading.text %></a>
|
|
30
62
|
</li>
|
|
31
63
|
<% }); %>
|
|
32
64
|
</ul>
|
|
33
65
|
</div>
|
|
34
|
-
<% }
|
|
66
|
+
<% }
|
|
67
|
+
} %>
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: "Writing Content with docmd"
|
|
3
|
-
description: "Learn how to write effective documentation using Markdown, frontmatter, and custom components in docmd."
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Writing Content
|
|
7
|
-
|
|
8
|
-
`docmd` is designed to let you focus on your content, written in standard Markdown. This section covers the essentials of creating pages, structuring your content, and leveraging `docmd`'s features to enhance your documentation.
|
|
9
|
-
|
|
10
|
-
## Key Aspects:
|
|
11
|
-
|
|
12
|
-
* **[Frontmatter](/writing-content/frontmatter/):** Define page-specific metadata like titles and descriptions using simple YAML at the top of your Markdown files.
|
|
13
|
-
* **[Markdown Syntax](/writing-content/markdown-syntax/):** Utilize standard CommonMark and GitHub Flavored Markdown for formatting your text, code blocks, lists, tables, and more.
|
|
14
|
-
* **[Custom Containers](/writing-content/custom-containers/):** Enhance your pages with special components like callouts, cards, and steps using a simple `::: name :::` syntax.
|
|
15
|
-
* **[Steps Container](/writing-content/steps-test/):** Create sequential guides with the specialized steps container.
|
|
16
|
-
|
|
17
|
-
By understanding these elements, you can create rich, well-structured, and engaging documentation.
|
package/src/assets/css/toc.css
DELETED
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
/* TOC Styles - Simplified Hyperlink Style */
|
|
2
|
-
.toc-container {
|
|
3
|
-
margin: 0;
|
|
4
|
-
padding: 0;
|
|
5
|
-
border: none;
|
|
6
|
-
background-color: transparent;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
.toc-title {
|
|
10
|
-
margin-top: 0;
|
|
11
|
-
margin-bottom: 0.5rem;
|
|
12
|
-
font-size: 1rem;
|
|
13
|
-
font-weight: bold;
|
|
14
|
-
color: var(--text-muted);
|
|
15
|
-
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
.toc-list {
|
|
19
|
-
list-style: none;
|
|
20
|
-
padding-left: 0;
|
|
21
|
-
margin: 0;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
.toc-item {
|
|
25
|
-
margin-bottom: 0.25rem;
|
|
26
|
-
line-height: 1.4;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
.toc-link {
|
|
30
|
-
text-decoration: none;
|
|
31
|
-
color: var(--link-color);
|
|
32
|
-
display: inline-block;
|
|
33
|
-
padding: 0.1rem 0;
|
|
34
|
-
font-size: 0.9rem;
|
|
35
|
-
font-weight: 500;
|
|
36
|
-
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
.toc-link:hover {
|
|
40
|
-
text-decoration: underline;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/* Indentation for different heading levels */
|
|
44
|
-
.toc-level-2 {
|
|
45
|
-
margin-left: 0;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
.toc-level-3 {
|
|
49
|
-
margin-left: 0.75rem;
|
|
50
|
-
font-size: 0.85rem;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
.toc-level-4 {
|
|
54
|
-
margin-left: 1.5rem;
|
|
55
|
-
font-size: 0.8rem;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/* TOC sidebar should only display on active pages */
|
|
59
|
-
.toc-sidebar {
|
|
60
|
-
width: 180px;
|
|
61
|
-
position: sticky;
|
|
62
|
-
top: 2rem;
|
|
63
|
-
max-height: calc(100vh - 4rem);
|
|
64
|
-
overflow-y: auto;
|
|
65
|
-
align-self: flex-start;
|
|
66
|
-
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
/* Hide TOC on mobile */
|
|
70
|
-
@media (max-width: 1024px) {
|
|
71
|
-
.toc-sidebar {
|
|
72
|
-
width: 100%;
|
|
73
|
-
position: static;
|
|
74
|
-
margin-bottom: 1rem;
|
|
75
|
-
}
|
|
76
|
-
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|