@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.
Files changed (31) hide show
  1. package/.github/workflows/publish.yml +1 -1
  2. package/README.md +2 -2
  3. package/bin/docmd.js +8 -2
  4. package/config.js +31 -31
  5. package/docs/cli-commands.md +13 -0
  6. package/docs/content/images.md +205 -0
  7. package/docs/content/index.md +17 -0
  8. package/docs/theming/assets-management.md +126 -0
  9. package/docs/theming/custom-css-js.md +3 -6
  10. package/package.json +2 -1
  11. package/src/assets/css/{main.css → docmd-main.css} +255 -10
  12. package/src/assets/css/{theme-sky.css → docmd-theme-sky.css} +153 -1
  13. package/src/assets/js/docmd-image-lightbox.js +72 -0
  14. package/src/assets/js/{theme-toggle.js → docmd-theme-toggle.js} +4 -4
  15. package/src/commands/build.js +151 -9
  16. package/src/commands/dev.js +103 -17
  17. package/src/commands/init.js +198 -17
  18. package/src/core/file-processor.js +40 -0
  19. package/src/core/html-generator.js +7 -3
  20. package/src/plugins/sitemap.js +10 -3
  21. package/src/templates/layout.ejs +5 -63
  22. package/src/templates/toc.ejs +53 -20
  23. package/docs/writing-content/index.md +0 -17
  24. package/src/assets/css/toc.css +0 -76
  25. /package/docs/{writing-content → content}/custom-containers.md +0 -0
  26. /package/docs/{writing-content → content}/frontmatter.md +0 -0
  27. /package/docs/{writing-content → content}/markdown-syntax.md +0 -0
  28. /package/src/assets/css/{highlight-dark.css → docmd-highlight-dark.css} +0 -0
  29. /package/src/assets/css/{highlight-light.css → docmd-highlight-light.css} +0 -0
  30. /package/src/assets/images/{logo-dark.png → docmd-logo-dark.png} +0 -0
  31. /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
 
@@ -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
- console.warn('⚠️ No siteUrl defined in config. Skipping sitemap generation.');
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
- console.log(`✅ Generated sitemap at ${sitemapPath}`);
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 };
@@ -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(/&amp;/g, '&')
98
- .replace(/&lt;/g, '<')
99
- .replace(/&gt;/g, '>')
100
- .replace(/&quot;/g, '"')
101
- .replace(/&#39;/g, "'")
102
- .replace(/&nbsp;/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 💜 <a href="https://docmd.mgks.dev" target="_blank" rel="noopener">docmd.</a>
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
  <% }); %>
@@ -1,34 +1,67 @@
1
1
  <%# src/templates/toc.ejs %>
2
2
  <%
3
- // If direct headings aren't available, we'll try to extract them from the content
4
- let tocHeadings = [];
5
- if (headings && headings.length > 0) {
6
- // Use provided headings if available
7
- tocHeadings = headings.filter(h => h.level >= 2 && h.level <= 4);
8
- } else if (content) {
9
- // Basic regex to extract headings from HTML content
10
- const headingRegex = /<h([2-4])[^>]*?id="([^"]*)"[^>]*?>([\s\S]*?)<\/h\1>/g;
11
- let match;
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(/&amp;/g, '&')
7
+ .replace(/&lt;/g, '<')
8
+ .replace(/&gt;/g, '>')
9
+ .replace(/&quot;/g, '"')
10
+ .replace(/&#39;/g, "'")
11
+ .replace(/&nbsp;/g, ' ');
19
12
  }
20
13
 
21
- // Only show TOC if there are enough headings
22
- if (tocHeadings.length > 1) {
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"><%= heading.text %></a>
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.
@@ -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
- }