@mgks/docmd 0.2.0 → 0.2.1
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 +10 -5
- package/docs/configuration.md +11 -5
- 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 +5 -1167
- 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 +89 -29
- package/src/commands/build.js +62 -120
- package/src/commands/dev.js +2 -1
- package/src/commands/init.js +4 -0
- package/src/core/config-loader.js +2 -0
- package/src/core/file-processor.js +130 -97
- 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/no-style.ejs +23 -6
- package/src/templates/partials/theme-init.js +26 -0
package/assets/css/welcome.css
CHANGED
|
@@ -1,66 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
[data-theme=
|
|
7
|
-
*{margin:0;padding:0;box-sizing:border-box}
|
|
8
|
-
body{font-family:'Inter',-apple-system,BlinkMacSystemFont,sans-serif;line-height:1.5;color:var(--text-color);background-color:var(--bg-color);height:100vh;display:flex;overflow:hidden}
|
|
9
|
-
.landing-container{display:flex;width:100%;height:100%;padding:0 var(--container-padding);max-width:1600px;margin:0 auto}
|
|
10
|
-
.content-side{flex:1;padding:3rem 2rem 3rem 0;display:flex;flex-direction:column;justify-content:center}
|
|
11
|
-
.preview-side{flex:1;display:flex;align-items:center;justify-content:flex-start;position:relative;overflow:visible}
|
|
12
|
-
.header-top{position:absolute;top:2rem;right:3rem;z-index:100}
|
|
13
|
-
.theme-toggle{background:var(--bg-secondary);border:1px solid var(--border-color);color:var(--text-color);width:40px;height:40px;border-radius:50%;display:flex;align-items:center;justify-content:center;cursor:pointer;transition:all .2s ease}
|
|
14
|
-
.theme-toggle:hover{background:var(--border-color)}
|
|
15
|
-
.logo{margin-bottom:1.5rem;display:flex;align-items:center}
|
|
16
|
-
.logo svg{height:48px;width:auto}
|
|
17
|
-
.logo-text{font-family:'PT Mono',monospace;font-weight:700;font-size:2em;margin-left:.25em}
|
|
18
|
-
h1{font-size:3rem;font-weight:700;margin-bottom:1rem;letter-spacing:-.02em}
|
|
19
|
-
.tagline{font-size:1.25rem;color:var(--text-light);margin-bottom:2rem;font-weight:400}
|
|
20
|
-
.features{display:grid;grid-template-columns:repeat(2,1fr);gap:1.5rem;margin-bottom:2rem}
|
|
21
|
-
.feature{display:flex;align-items:flex-start;gap:.75rem}
|
|
22
|
-
.feature-icon{background-color:var(--primary-color);color:#fff;width:32px;height:32px;border-radius:6px;display:flex;align-items:center;justify-content:center;flex-shrink:0}
|
|
23
|
-
.feature-text{font-size:.9rem}
|
|
24
|
-
.feature-text strong{display:block;margin-bottom:.25rem}
|
|
25
|
-
.buttons{display:flex;gap:1rem;margin-bottom:2rem}
|
|
26
|
-
.btn{display:inline-flex;align-items:center;gap:.5rem;padding:.75rem 1.5rem;border-radius:8px;font-weight:600;font-size:1rem;text-decoration:none;transition:all .2s ease}
|
|
27
|
-
.btn-primary{background-color:var(--primary-color);color:#fff;border:none}
|
|
28
|
-
.btn-primary:hover{background-color:var(--primary-hover)}
|
|
29
|
-
.btn-secondary{background-color:var(--bg-secondary);color:var(--text-color);border:1px solid var(--border-color)}
|
|
30
|
-
.btn-secondary:hover{background-color:var(--border-color)}
|
|
31
|
-
.social-links{display:flex;gap:1rem;padding:0 .25em}
|
|
32
|
-
.social-link{color:var(--text-light);transition:color .2s ease}
|
|
33
|
-
.social-link:hover{color:var(--primary-color)}
|
|
34
|
-
.preview-stack{position:relative;width:100%;height:400px;transform:translateX(15%);perspective:1000px}
|
|
35
|
-
.preview-image{position:absolute;width:100%;max-width:700px;height:400px;border-radius:20px;box-shadow:0 25px 50px -12px var(--shadow-color);transition:all .3s ease;overflow:hidden}
|
|
36
|
-
.preview-image img{width:100%;height:100%;object-fit:cover;object-position:left top;border-radius:8px;pointer-events:none}
|
|
37
|
-
.preview-image.top{z-index:3;transform:rotate(3deg) translateY(-10%) translateX(7%)}
|
|
38
|
-
.preview-image.middle{z-index:2;transform:rotate(-3deg) translateY(1%) translateX(-2%)}
|
|
39
|
-
.preview-image.bottom{z-index:1;transform:rotate(-8deg) translateY(10%) translateX(-10%)}
|
|
40
|
-
body[data-theme="light"] .preview-image .light-img{display:block}
|
|
41
|
-
body[data-theme="light"] .preview-image .dark-img{display:none}
|
|
42
|
-
body[data-theme="dark"] .preview-image .light-img{display:none}
|
|
43
|
-
body[data-theme="dark"] .preview-image .dark-img{display:block}
|
|
44
|
-
@media (max-width: 1400px) {
|
|
45
|
-
:root{--container-padding:3rem}
|
|
46
|
-
.preview-stack{transform:translateX(15%)}
|
|
47
|
-
}
|
|
48
|
-
@media (max-width: 1200px) {
|
|
49
|
-
:root{--container-padding:2rem}
|
|
50
|
-
.preview-side{display:none}
|
|
51
|
-
.content-side{max-width:100%;padding:3rem 0}
|
|
52
|
-
.header-top{right:2rem}
|
|
53
|
-
}
|
|
54
|
-
@media (max-width: 768px) {
|
|
55
|
-
:root{--container-padding:1.5rem}
|
|
56
|
-
body{overflow:auto}
|
|
57
|
-
.content-side{padding:2rem 0}
|
|
58
|
-
h1{font-size:2.5rem}
|
|
59
|
-
.features{grid-template-columns:1fr}
|
|
60
|
-
.buttons{flex-direction:column}
|
|
61
|
-
.header-top{padding:1rem 0;text-align:center;right:1rem}
|
|
62
|
-
h1{font-size:2.5rem}
|
|
63
|
-
.tagline{font-size:1em;font-weight:500}
|
|
64
|
-
.landing-container{padding:1rem;flex-direction:column}
|
|
65
|
-
}
|
|
66
|
-
.social-links .lucide-heart-handshake{color:#cd2727}
|
|
1
|
+
/*
|
|
2
|
+
* Source file from the docmd project — https://github.com/mgks/docmd
|
|
3
|
+
* Configuration for the docmd project's own documentation
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
:root,html[data-theme=light]{--primary-color:#047bf1;--primary-hover:#026ed9;--text-color:#333;--text-light:#666;--bg-color:#fff;--bg-secondary:#f8f9fa;--border-color:#eaeaea}.theme-toggle,body{color:var(--text-color);display:flex}.logo-text,h1{font-weight:700}.install-code pre,.logo-text{font-family:'PT Mono',monospace}:root{--shadow-color:#00000014;--container-padding:5rem}@media (prefers-color-scheme:dark){:root{--primary-color:#047bf1;--primary-hover:#026ed9;--text-color:#e0e0e0;--text-light:#aaa;--bg-color:#121212;--bg-secondary:#1e1e1e;--border-color:#333;--shadow-color:#0000004d}}[data-theme=light]{--shadow-color:#00000059}[data-theme=dark]{--primary-color:#1955b6;--primary-hover:#084dbd;--text-color:#e0e0e0;--text-light:#aaa;--bg-color:#121212;--bg-secondary:#1e1e1e;--border-color:#333;--shadow-color:#000000de}*{margin:0;padding:0;box-sizing:border-box}body{font-family:Inter,-apple-system,BlinkMacSystemFont,sans-serif;line-height:1.5;background-color:var(--bg-color);height:100vh;overflow:hidden}.landing-container{display:flex;width:100%;height:100%;padding:0 var(--container-padding);max-width:1600px;margin:0 auto}.content-side{flex:1;padding:3rem 2rem 3rem 0;display:flex;flex-direction:column;justify-content:center}.preview-side{flex:1;display:flex;align-items:center;justify-content:flex-start;position:relative;overflow:visible}.header-top{position:absolute;top:2rem;right:3rem;z-index:100}.theme-toggle{background:var(--bg-secondary);border:1px solid var(--border-color);width:40px;height:40px;border-radius:50%;align-items:center;justify-content:center;cursor:pointer;transition:.2s}.theme-toggle:hover{background:var(--border-color)}.logo{margin-bottom:1.5rem;display:flex;align-items:center}.buttons,.features,.install-section,.tagline{margin-bottom:2rem}.logo svg{height:48px;width:auto}.logo-text{font-size:2em;margin-left:.25em}h1{font-size:3rem;margin-bottom:1rem;letter-spacing:-.02em}.tagline{font-size:1.25rem;color:var(--text-light);font-weight:400}.btn-primary,.feature-icon{background-color:var(--primary-color);color:#fff}.features{display:grid;grid-template-columns:repeat(2,1fr);gap:1.5rem}.feature{display:flex;align-items:flex-start;gap:.75rem}.feature-icon{width:32px;height:32px;border-radius:6px;display:flex;align-items:center;justify-content:center;flex-shrink:0}.feature-text{font-size:.9rem}.feature-text strong{display:block;margin-bottom:.25rem}.buttons{display:flex;gap:1rem}.btn{display:inline-flex;align-items:center;gap:.5rem;padding:.75rem 1.5rem;border-radius:8px;font-weight:600;font-size:1rem;text-decoration:none;transition:.2s}.btn-primary{border:none}.btn-secondary,.install-code pre{background-color:var(--bg-secondary);border:1px solid var(--border-color)}.btn-primary:hover{background-color:var(--primary-hover)}.btn-secondary{color:var(--text-color)}.btn-secondary:hover{background-color:var(--border-color)}.social-links{display:flex;gap:1rem;padding:0 .25em}.social-link{color:var(--text-light);transition:color .2s}.social-link:hover{color:var(--primary-color)}.preview-stack{position:relative;width:100%;height:400px;transform:translateX(15%);perspective:1000px}.preview-image{position:absolute;width:100%;max-width:700px;height:400px;border-radius:20px;box-shadow:0 25px 50px -12px var(--shadow-color);transition:.3s;overflow:hidden}.preview-image img{width:100%;height:100%;object-fit:cover;object-position:left top;border-radius:8px;pointer-events:none}.preview-image.top{z-index:3;transform:rotate(3deg) translateY(-10%) translateX(7%)}.preview-image.middle{z-index:2;transform:rotate(-3deg) translateY(1%) translateX(-2%)}.preview-image.bottom{z-index:1;transform:rotate(-8deg) translateY(10%) translateX(-10%)}[data-theme=dark] .preview-image .dark-img,[data-theme=light] .preview-image .light-img{display:block}[data-theme=dark] .preview-image .light-img,[data-theme=light] .preview-image .dark-img{display:none}@media (max-width:1400px){:root{--container-padding:3rem}.preview-stack{transform:translateX(15%)}}@media (max-width:1200px){:root{--container-padding:2rem}.preview-side{display:none}.content-side{max-width:100%;padding:3rem 0}.header-top{right:2rem}}@media (max-width:768px){:root{--container-padding:1.5rem}body{overflow:auto}.content-side{padding:2rem 0}.features{grid-template-columns:1fr}.buttons{flex-direction:column}.header-top{padding:1rem 0;text-align:center;right:1rem}h1{font-size:2.5rem}.tagline{font-size:1em;font-weight:500}.landing-container{padding:1rem;flex-direction:column}}.social-links .lucide-heart-handshake{color:#cd2727}.install-code{position:relative;display:inline-block}.install-code pre{border-radius:8px;padding:1rem 3.5rem 1rem 1rem;margin:0;font-size:.9rem;color:var(--text-color)}.install-code code{background:0 0;padding:0;color:inherit}.copy-button{position:absolute;top:.5rem;right:.5rem;background:var(--bg-color);border:1px solid var(--border-color);border-radius:4px;padding:.5rem;cursor:pointer;transition:.2s;color:var(--text-light)}.copy-button:hover{background:var(--border-color);color:var(--text-color)}
|
package/config.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
//
|
|
1
|
+
// Source file from the docmd project — https://github.com/mgks/docmd
|
|
2
|
+
|
|
3
|
+
// Configuration for the docmd project's own documentation
|
|
2
4
|
module.exports = {
|
|
3
5
|
// Core Site Metadata
|
|
4
6
|
siteTitle: 'docmd',
|
|
@@ -26,10 +28,11 @@ module.exports = {
|
|
|
26
28
|
|
|
27
29
|
// Theme Configuration
|
|
28
30
|
theme: {
|
|
29
|
-
name: 'sky', // Themes: 'default', 'sky'
|
|
31
|
+
name: 'sky', // Themes: 'default', 'sky', 'retro', 'ruby'
|
|
30
32
|
defaultMode: 'light', // Initial color mode: 'light' or 'dark'
|
|
31
33
|
enableModeToggle: true, // Show UI button to toggle light/dark modes
|
|
32
|
-
positionMode: 'top',
|
|
34
|
+
positionMode: 'top', // 'top' or 'bottom' for the theme toggle
|
|
35
|
+
codeHighlight: true, // Enable/disable codeblock highlighting and import of highlight.js
|
|
33
36
|
customCss: [ // Array of paths to custom CSS files
|
|
34
37
|
// '/assets/css/custom.css', // Custom TOC styles
|
|
35
38
|
],
|
|
@@ -42,13 +45,15 @@ module.exports = {
|
|
|
42
45
|
|
|
43
46
|
// Content Processing
|
|
44
47
|
autoTitleFromH1: true, // Set to true to automatically use the first H1 as page title
|
|
48
|
+
copyCode: true, // Enable/disable the copy code button on code blocks
|
|
45
49
|
|
|
46
50
|
// Plugins Configuration (Object format)
|
|
47
51
|
// Plugins are configured here. docmd will look for these keys.
|
|
48
52
|
plugins: {
|
|
49
53
|
// SEO Plugin Configuration
|
|
50
|
-
//
|
|
51
|
-
//
|
|
54
|
+
// These are site-wide fallbacks. For detailed per-page SEO controls,
|
|
55
|
+
// including structured data (LD+JSON), use the `seo` key in your page's frontmatter.
|
|
56
|
+
// See the SEO plugin documentation for all available frontmatter options.
|
|
52
57
|
seo: {
|
|
53
58
|
// Default meta description if a page doesn't have one in its frontmatter
|
|
54
59
|
defaultDescription: 'docmd is a Node.js command-line tool for generating beautiful, lightweight static documentation sites from Markdown files.',
|
package/docs/configuration.md
CHANGED
|
@@ -44,6 +44,7 @@ module.exports = {
|
|
|
44
44
|
],
|
|
45
45
|
|
|
46
46
|
autoTitleFromH1: true,
|
|
47
|
+
copyCode: true,
|
|
47
48
|
|
|
48
49
|
sponsor: {
|
|
49
50
|
enabled: true,
|
|
@@ -141,6 +142,11 @@ module.exports = {
|
|
|
141
142
|
// ---
|
|
142
143
|
```
|
|
143
144
|
|
|
145
|
+
### `copyCode`
|
|
146
|
+
* **Type:** `Boolean`
|
|
147
|
+
* **Default:** `true`
|
|
148
|
+
* **Description:** If `true`, a "Copy" button will be added to the top-right corner of all code blocks, allowing users to easily copy the code to their clipboard with a single click. **Note:** This setting only applies to regular pages. For noStyle pages, copy code functionality must be explicitly enabled via the `components.mainScripts: true` setting.
|
|
149
|
+
|
|
144
150
|
## `sidebar` (Object)
|
|
145
151
|
|
|
146
152
|
Configures the behavior of the sidebar.
|
|
@@ -186,7 +192,7 @@ Configures the visual theme of your site.
|
|
|
186
192
|
### `theme.customCss`
|
|
187
193
|
* **Type:** `Array` of `String`
|
|
188
194
|
* **Default:** `[]` (empty array)
|
|
189
|
-
* **Description:** An array of paths to your custom CSS files. These files will be linked in the `<head>` of every page *after* the main theme CSS, allowing you to override or extend styles.
|
|
195
|
+
* **Description:** An array of paths to your custom CSS files. These files will be linked in the `<head>` of every regular page *after* the main theme CSS, allowing you to override or extend styles. **Note:** For noStyle pages, custom CSS must be explicitly enabled via `components.customCss: true`.
|
|
190
196
|
* **Paths:** Should be relative to the `outputDir` root (e.g., `'/css/my-styles.css'`). You are responsible for ensuring these files exist at the specified location in your final `site/` output (e.g., by placing them in an assets folder that `docmd` copies, or in your project's static assets if your `srcDir` is part of a larger project).
|
|
191
197
|
* **Example:** `customCss: ['/assets/css/custom-branding.css']`
|
|
192
198
|
|
|
@@ -197,7 +203,7 @@ Configures the visual theme of your site.
|
|
|
197
203
|
## `customJs` (Array of String)
|
|
198
204
|
* **Type:** `Array` of `String`
|
|
199
205
|
* **Default:** `[]`
|
|
200
|
-
* **Description:** An array of paths to your custom JavaScript files. These files will be included as `<script>` tags just before the closing `</body>` tag on every page.
|
|
206
|
+
* **Description:** An array of paths to your custom JavaScript files. These files will be included as `<script>` tags just before the closing `</body>` tag on every regular page. **Note:** For noStyle pages, custom JavaScript must be explicitly enabled via `components.customJs: true`.
|
|
201
207
|
* **Paths:** Should be relative to the `outputDir` root (e.g., `'/js/my-analytics-alternative.js'`).
|
|
202
208
|
* **Example:** `customJs: ['/assets/js/interactive-component.js']`
|
|
203
209
|
|
|
@@ -222,11 +228,11 @@ Configures the visual theme of your site.
|
|
|
222
228
|
* `external` (Boolean, Optional): If set to `true`, the `path` is treated as an absolute external URL and the link will open in a new tab (`target="_blank"`). Defaults to `false`.
|
|
223
229
|
|
|
224
230
|
## `footer` (String, Optional)
|
|
225
|
-
* **Description:** Custom footer text (Markdown supported).
|
|
231
|
+
* **Description:** Custom footer text (Markdown supported). **Note:** For noStyle pages, the footer must be explicitly enabled via `components.footer: true`.
|
|
226
232
|
|
|
227
233
|
## `sponsor` (Object, Optional)
|
|
228
234
|
* **Type:** `Object`
|
|
229
|
-
* **Description:** Configures a sponsor ribbon that appears in the bottom-right corner of every page.
|
|
235
|
+
* **Description:** Configures a sponsor ribbon that appears in the bottom-right corner of every regular page. **Note:** For noStyle pages, the sponsor ribbon must be explicitly enabled via `components.branding: true`.
|
|
230
236
|
* **Properties:**
|
|
231
237
|
* `enabled` (Boolean, Optional): Whether to show the sponsor ribbon. Defaults to `true` if the sponsor object is provided.
|
|
232
238
|
* `title` (String, Optional): Text to display on the ribbon. Defaults to `'Sponsor the Project'`.
|
|
@@ -242,6 +248,6 @@ Configures the visual theme of your site.
|
|
|
242
248
|
* **Note:** The ribbon is positioned fixed in the bottom-right corner and includes a heart icon with a subtle animation.
|
|
243
249
|
|
|
244
250
|
## `favicon` (String, Optional)
|
|
245
|
-
* **Description:** Path to your favicon file, relative to `outputDir` root.
|
|
251
|
+
* **Description:** Path to your favicon file, relative to `outputDir` root. **Note:** For noStyle pages, the favicon must be explicitly enabled via `components.favicon: true`.
|
|
246
252
|
|
|
247
253
|
This file needs significant detail for each new option, explaining its purpose, type, default value, and how to use it with examples.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Custom Containers"
|
|
3
|
+
description: "Enhance your documentation with special components like callouts, cards, and steps using docmd's custom container syntax."
|
|
4
|
+
noStyle: true
|
|
5
|
+
components:
|
|
6
|
+
meta: false
|
|
7
|
+
favicon: true
|
|
8
|
+
css: false
|
|
9
|
+
theme: false
|
|
10
|
+
scripts: false
|
|
11
|
+
customHead: |
|
|
12
|
+
<script>
|
|
13
|
+
window.location.href = "https://docmd.mgks.dev/content/containers/";
|
|
14
|
+
document.addEventListener("DOMContentLoaded", function () {
|
|
15
|
+
window.location.href = "https://docmd.mgks.dev/content/containers/";
|
|
16
|
+
});
|
|
17
|
+
</script>
|
|
18
|
+
bodyClass: "no-style-example"
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
<div class="container">
|
|
22
|
+
Redirecting...<br/>
|
|
23
|
+
/custom-containers have moved to /containers now <a href="https://docmd.mgks.dev/content/containers/">Visit New Custom Containers Page</a>
|
|
24
|
+
</div>
|
|
@@ -17,7 +17,9 @@ docmd offers a "no-style" page format that gives you maximum flexibility to crea
|
|
|
17
17
|
|
|
18
18
|
To create a no-style page, add `noStyle: true` to your page's frontmatter. This tells docmd to use a special template that only includes the components you explicitly request.
|
|
19
19
|
|
|
20
|
-
By default, a no-style page will render just your content with minimal HTML structure.
|
|
20
|
+
By default, a no-style page will render just your content with minimal HTML structure. **All components are disabled by default** and must be explicitly enabled via the `components` object in frontmatter.
|
|
21
|
+
|
|
22
|
+
> **Note:** This behavior changed in v0.2.0. Previously, some components were enabled by default and had to be disabled. Now all components are opt-in only.
|
|
21
23
|
|
|
22
24
|
## HTML Support
|
|
23
25
|
|
|
@@ -36,7 +38,7 @@ description: "Welcome to my project"
|
|
|
36
38
|
noStyle: true
|
|
37
39
|
components:
|
|
38
40
|
meta: true # Include meta tags, title, description
|
|
39
|
-
css: false #
|
|
41
|
+
# css: false # Not needed - CSS is disabled by default
|
|
40
42
|
---
|
|
41
43
|
|
|
42
44
|
<div style="text-align: center; padding: 50px;">
|
|
@@ -48,32 +50,35 @@ components:
|
|
|
48
50
|
|
|
49
51
|
## Available Components
|
|
50
52
|
|
|
51
|
-
You can control exactly which components are included in your page by setting them to `true`
|
|
52
|
-
|
|
53
|
-
| Component | Description |
|
|
54
|
-
|
|
55
|
-
| `meta` | Meta tags, title, description | `true` |
|
|
56
|
-
| `siteTitle` | Include site title after page title | `true` |
|
|
57
|
-
| `favicon` | Include favicon | `true` |
|
|
58
|
-
| `css` | Include main CSS | `
|
|
59
|
-
| `highlight` | Include syntax highlighting CSS | `
|
|
60
|
-
| `theme` | Include theme-specific CSS | `
|
|
61
|
-
| `
|
|
62
|
-
| `
|
|
63
|
-
| `
|
|
64
|
-
| `
|
|
65
|
-
| `
|
|
66
|
-
| `
|
|
67
|
-
| `
|
|
68
|
-
| `
|
|
69
|
-
| `
|
|
70
|
-
| `
|
|
71
|
-
| `
|
|
72
|
-
| `
|
|
73
|
-
| `
|
|
74
|
-
| `
|
|
75
|
-
| `
|
|
76
|
-
| `
|
|
53
|
+
You can control exactly which components are included in your page by setting them to `true` in the `components` object. **All components are disabled by default** and must be explicitly enabled:
|
|
54
|
+
|
|
55
|
+
| Component | Description | Required Setting |
|
|
56
|
+
|-----------|-------------|------------------|
|
|
57
|
+
| `meta` | Meta tags, title, description | `meta: true` |
|
|
58
|
+
| `siteTitle` | Include site title after page title | `siteTitle: true` |
|
|
59
|
+
| `favicon` | Include favicon | `favicon: true` |
|
|
60
|
+
| `css` | Include main CSS | `css: true` |
|
|
61
|
+
| `highlight` | Include syntax highlighting CSS | `highlight: true` |
|
|
62
|
+
| `theme` | Include theme-specific CSS | `theme: true` |
|
|
63
|
+
| `themeMode` | Include theme mode toggle functionality | `themeMode: true` |
|
|
64
|
+
| `customCss` | Include custom CSS files from config | `customCss: true` |
|
|
65
|
+
| `pluginStyles` | Include plugin-specific CSS | `pluginStyles: true` |
|
|
66
|
+
| `pluginHeadScripts` | Include plugin scripts in head | `pluginHeadScripts: true` |
|
|
67
|
+
| `layout` | Use main content layout (`true`, `'full'`, or `false`) | `layout: true` or `layout: 'full'` |
|
|
68
|
+
| `sidebar` | Include sidebar | `sidebar: true` |
|
|
69
|
+
| `header` | Include page header | `header: true` |
|
|
70
|
+
| `pageTitle` | Include page title in header | `pageTitle: true` |
|
|
71
|
+
| `footer` | Include page footer | `footer: true` |
|
|
72
|
+
| `branding` | Include docmd branding in footer | `branding: true` |
|
|
73
|
+
| `logo` | Include logo in sidebar | `logo: true` |
|
|
74
|
+
| `navigation` | Include navigation in sidebar | `navigation: true` |
|
|
75
|
+
| `themeToggle` | Include theme toggle button | `themeToggle: true` |
|
|
76
|
+
| `toc` | Include table of contents | `toc: true` |
|
|
77
|
+
| `scripts` | Enable script loading (required for other script components) | `scripts: true` |
|
|
78
|
+
| `mainScripts` | Include main JavaScript (copy code, theme toggle, etc.) | `mainScripts: true` |
|
|
79
|
+
| `lightbox` | Include image lightbox functionality | `lightbox: true` |
|
|
80
|
+
| `customJs` | Include custom JS files from config | `customJs: true` |
|
|
81
|
+
| `pluginBodyScripts` | Include plugin scripts at end of body | `pluginBodyScripts: true` |
|
|
77
82
|
|
|
78
83
|
## Layout Options
|
|
79
84
|
|
|
@@ -83,6 +88,22 @@ The `components.layout` property has three possible values:
|
|
|
83
88
|
- `true`: Use the main content layout with optional header and footer
|
|
84
89
|
- `'full'`: Same as `true`, a full layout with content area
|
|
85
90
|
|
|
91
|
+
## Script Components
|
|
92
|
+
|
|
93
|
+
Script components work in a hierarchical manner:
|
|
94
|
+
|
|
95
|
+
1. **`scripts: true`** - Enables script loading (required for all other script components)
|
|
96
|
+
2. **`mainScripts: true`** - Includes main JavaScript functionality (copy code, theme toggle, etc.)
|
|
97
|
+
3. **`lightbox: true`** - Includes image lightbox functionality (requires `mainScripts: true`)
|
|
98
|
+
|
|
99
|
+
**Example:**
|
|
100
|
+
```yaml
|
|
101
|
+
components:
|
|
102
|
+
scripts: true # Enable script loading
|
|
103
|
+
mainScripts: true # Include main JavaScript
|
|
104
|
+
lightbox: true # Include lightbox (requires mainScripts)
|
|
105
|
+
```
|
|
106
|
+
|
|
86
107
|
## Sidebar Option
|
|
87
108
|
|
|
88
109
|
If you set `components.sidebar: true`, the sidebar will be included with optional logo, navigation, and theme toggle button.
|
|
@@ -124,12 +145,15 @@ components:
|
|
|
124
145
|
favicon: true
|
|
125
146
|
css: true
|
|
126
147
|
theme: true
|
|
148
|
+
themeMode: true
|
|
127
149
|
layout: true
|
|
128
150
|
header: true
|
|
129
151
|
pageTitle: true
|
|
130
152
|
footer: true
|
|
131
153
|
branding: true
|
|
132
154
|
scripts: true
|
|
155
|
+
mainScripts: true
|
|
156
|
+
lightbox: true
|
|
133
157
|
customHead: |
|
|
134
158
|
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;600&display=swap" rel="stylesheet">
|
|
135
159
|
<style>
|
package/docs/index.md
CHANGED
|
@@ -7,32 +7,51 @@ components:
|
|
|
7
7
|
favicon: true
|
|
8
8
|
css: false
|
|
9
9
|
theme: false
|
|
10
|
+
themeMode: true
|
|
10
11
|
scripts: false
|
|
12
|
+
mainScripts: false
|
|
13
|
+
lightbox: false
|
|
14
|
+
seo:
|
|
15
|
+
ldJson:
|
|
16
|
+
"@context": "https://schema.org"
|
|
17
|
+
"@type": "SoftwareApplication"
|
|
18
|
+
name: "docmd"
|
|
19
|
+
operatingSystem: "Any"
|
|
20
|
+
applicationCategory: "DeveloperApplication"
|
|
21
|
+
url: "https://docmd.mgks.dev"
|
|
22
|
+
description: "docmd is a Node.js-powered static site generator for Markdown documentation. It features custom containers, multiple themes, and zero client-side bloat."
|
|
23
|
+
creator:
|
|
24
|
+
"@type": "Person"
|
|
25
|
+
name: "Ghazi"
|
|
26
|
+
sameAs:
|
|
27
|
+
- "https://github.com/mgks"
|
|
28
|
+
- "https://mgks.dev"
|
|
29
|
+
codeRepository: "https://github.com/mgks/docmd"
|
|
30
|
+
releaseNotes: "See GitHub Releases for changelog"
|
|
31
|
+
programmingLanguage: "Node.js"
|
|
32
|
+
installUrl: "https://www.npmjs.com/package/@mgks/docmd"
|
|
11
33
|
customHead: |
|
|
12
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
13
34
|
<link rel="stylesheet" href="/assets/css/welcome.css">
|
|
14
35
|
<script>
|
|
15
|
-
// Initialize theme from localStorage or system preference
|
|
16
|
-
function initTheme() {
|
|
17
|
-
const storedTheme = localStorage.getItem('docmd-theme');
|
|
18
|
-
if (storedTheme) {
|
|
19
|
-
document.body.setAttribute('data-theme', storedTheme);
|
|
20
|
-
} else {
|
|
21
|
-
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
|
|
22
|
-
document.body.setAttribute('data-theme', prefersDark ? 'dark' : 'light');
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
// Toggle theme between light and dark
|
|
27
36
|
function toggleTheme() {
|
|
28
|
-
const currentTheme = document.
|
|
37
|
+
const currentTheme = document.documentElement.getAttribute('data-theme');
|
|
29
38
|
const newTheme = currentTheme === 'light' ? 'dark' : 'light';
|
|
30
|
-
document.
|
|
39
|
+
document.documentElement.setAttribute('data-theme', newTheme);
|
|
31
40
|
localStorage.setItem('docmd-theme', newTheme);
|
|
32
41
|
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
42
|
+
|
|
43
|
+
function copyToClipboard(text) {
|
|
44
|
+
navigator.clipboard.writeText(text).then(() => {
|
|
45
|
+
const button = event.target.closest('.copy-button');
|
|
46
|
+
const originalHTML = button.innerHTML;
|
|
47
|
+
button.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="20,6 9,17 4,12"></polyline></svg>';
|
|
48
|
+
button.style.color = '#10b981';
|
|
49
|
+
setTimeout(() => {
|
|
50
|
+
button.innerHTML = originalHTML;
|
|
51
|
+
button.style.color = '';
|
|
52
|
+
}, 2000);
|
|
53
|
+
});
|
|
54
|
+
}
|
|
36
55
|
</script>
|
|
37
56
|
---
|
|
38
57
|
|
|
@@ -97,6 +116,18 @@ customHead: |
|
|
|
97
116
|
</div>
|
|
98
117
|
</div>
|
|
99
118
|
|
|
119
|
+
<div class="install-section">
|
|
120
|
+
<div class="install-code">
|
|
121
|
+
<pre><code>npm install @mgks/docmd</code></pre>
|
|
122
|
+
<button class="copy-button" onclick="copyToClipboard('npm install @mgks/docmd')" aria-label="Copy npm install command">
|
|
123
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
124
|
+
<rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect>
|
|
125
|
+
<path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path>
|
|
126
|
+
</svg>
|
|
127
|
+
</button>
|
|
128
|
+
</div>
|
|
129
|
+
</div>
|
|
130
|
+
|
|
100
131
|
<div class="buttons">
|
|
101
132
|
<a href="/getting-started/" class="btn btn-primary">
|
|
102
133
|
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-rocket-icon lucide-rocket"><path d="M4.5 16.5c-1.5 1.26-2 5-2 5s3.74-.5 5-2c.71-.84.7-2.13-.09-2.91a2.18 2.18 0 0 0-2.91-.09z"/><path d="m12 15-3-3a22 22 0 0 1 2-3.95A12.88 12.88 0 0 1 22 2c0 2.72-.78 7.5-6 11a22.35 22.35 0 0 1-4 2z"/><path d="M9 12H4s.55-3.03 2-4c1.62-1.08 5 0 5 0"/><path d="M12 15v5s3.03-.55 4-2c1.08-1.62 0-5 0-5"/></svg>
|
package/docs/plugins/seo.md
CHANGED
|
@@ -36,46 +36,93 @@ module.exports = {
|
|
|
36
36
|
|
|
37
37
|
## Configuration Options
|
|
38
38
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
* `defaultDescription` (String):
|
|
42
|
-
* A fallback meta description used for pages that do not have a `description` specified in their YAML frontmatter.
|
|
43
|
-
* `openGraph` (Object): Configures [Open Graph](https://ogp.me/) meta tags, primarily used by Facebook, LinkedIn, Pinterest, etc.
|
|
44
|
-
* `siteName` (String): The name of your website (e.g., "My Project Documentation"). If not provided, `config.siteTitle` is used.
|
|
45
|
-
* `defaultImage` (String): Absolute path (from site root) to a default image for `og:image` when a page is shared, if the page itself doesn't specify an image in its frontmatter (e.g., via `image: /path/to/page-image.png` or `ogImage: ...`).
|
|
46
|
-
* Other tags like `og:title`, `og:description`, `og:url`, and `og:type` are automatically generated based on page frontmatter and URL.
|
|
47
|
-
* `twitter` (Object): Configures [Twitter Card](https://developer.twitter.com/en/docs/twitter-for-websites/cards/overview/abouts-cards) meta tags.
|
|
48
|
-
* `cardType` (String): The type of Twitter card. Common values: `'summary'`, `'summary_large_image'`. Defaults to `'summary'`.
|
|
49
|
-
* `siteUsername` (String): The Twitter @username of the site/publisher (e.g., `@MyProjectAccount`).
|
|
50
|
-
* `creatorUsername` (String): The default Twitter @username of the content creator. Can be overridden per page via frontmatter (e.g., `twitterCreator: @PageAuthorHandle`).
|
|
51
|
-
* Twitter tags like `twitter:title`, `twitter:description`, and `twitter:image` are also derived from page frontmatter, similar to Open Graph tags.
|
|
39
|
+
The options in `config.js` serve as site-wide defaults. For the best results, you should provide specific metadata for each page using frontmatter.
|
|
52
40
|
|
|
53
41
|
## Frontmatter for SEO
|
|
54
42
|
|
|
55
|
-
|
|
43
|
+
To control SEO on a per-page basis, add a nested `seo` object to your page's frontmatter. This keeps all SEO-related settings organized and prevents conflicts with other frontmatter keys.
|
|
56
44
|
|
|
57
45
|
```yaml
|
|
58
46
|
---
|
|
59
47
|
title: "Advanced Widget Configuration"
|
|
60
|
-
description: "A detailed guide on configuring advanced settings for the Super Widget
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
48
|
+
description: "A detailed guide on configuring advanced settings for the Super Widget."
|
|
49
|
+
seo:
|
|
50
|
+
description: "A more specific SEO description for search engines, overriding the main description if needed."
|
|
51
|
+
image: "/assets/images/widgets/super-widget-social.jpg"
|
|
52
|
+
ogType: "article"
|
|
53
|
+
twitterCard: "summary_large_image"
|
|
54
|
+
twitterCreator: "@widgetMaster"
|
|
55
|
+
keywords: ["widget", "configuration", "advanced", "performance"]
|
|
56
|
+
permalink: "https://example.com/docs/widgets/advanced-configuration"
|
|
57
|
+
noindex: false
|
|
66
58
|
---
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
::: callout info Backward Compatibility
|
|
62
|
+
For backward compatibility, the plugin will still recognize top-level SEO fields like `image`, `ogType`, etc. However, the nested `seo:` structure is the recommended approach.
|
|
63
|
+
:::
|
|
64
|
+
|
|
65
|
+
### Supported Frontmatter Fields
|
|
66
|
+
|
|
67
|
+
All fields should be placed inside the `seo:` object.
|
|
68
|
+
|
|
69
|
+
* `description` (String): Overrides the main page description for SEO meta tags.
|
|
70
|
+
* `image` or `ogImage` (String): Path to an image for `og:image` and `twitter:image`.
|
|
71
|
+
* `ogType` (String): Overrides the default Open Graph type (e.g., `article`, `website`).
|
|
72
|
+
* `twitterCard` (String): Overrides the default Twitter card type for this page.
|
|
73
|
+
* `twitterCreator` (String): The Twitter @username of the page's author.
|
|
74
|
+
* `keywords` (Array of Strings or String): Keywords for the `<meta name="keywords">` tag.
|
|
75
|
+
* `permalink` or `canonicalUrl` (String): The canonical URL for the page.
|
|
76
|
+
* `noindex` (Boolean): If `true`, adds `<meta name="robots" content="noindex">` to discourage search engines from indexing this page.
|
|
77
|
+
|
|
78
|
+
## Structured Data (LD+JSON)
|
|
67
79
|
|
|
68
|
-
|
|
69
|
-
|
|
80
|
+
The SEO plugin can generate [Structured Data](https://developers.google.com/search/docs/appearance/structured-data/intro-structured-data) (LD+JSON), which can enable rich search results. This feature is enabled per-page in your frontmatter.
|
|
81
|
+
|
|
82
|
+
### Enabling Structured Data
|
|
83
|
+
|
|
84
|
+
To generate a default LD+JSON block, add `ldJson: true` inside your `seo` frontmatter object.
|
|
85
|
+
|
|
86
|
+
```yaml
|
|
87
|
+
---
|
|
88
|
+
title: "My Article"
|
|
89
|
+
description: "An article about something important."
|
|
90
|
+
seo:
|
|
91
|
+
ldJson: true
|
|
92
|
+
---
|
|
70
93
|
```
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
94
|
+
|
|
95
|
+
This generates a basic `Article` schema using your page's metadata.
|
|
96
|
+
|
|
97
|
+
### Customizing Structured Data
|
|
98
|
+
|
|
99
|
+
For more control, provide an object to `ldJson`. This object will be merged with the default data, allowing you to add or override any properties.
|
|
100
|
+
|
|
101
|
+
**Example: Customizing schema type and adding an author**
|
|
102
|
+
|
|
103
|
+
```yaml
|
|
104
|
+
---
|
|
105
|
+
title: "Advanced Widget Configuration"
|
|
106
|
+
description: "A detailed guide on configuring advanced settings for the Super Widget."
|
|
107
|
+
seo:
|
|
108
|
+
image: "/assets/images/widgets/super-widget-social.jpg"
|
|
109
|
+
ldJson:
|
|
110
|
+
"@type": "TechArticle"
|
|
111
|
+
author:
|
|
112
|
+
"@type": "Person"
|
|
113
|
+
name: "Jane Doe"
|
|
114
|
+
url: "https://example.com/authors/jane-doe"
|
|
115
|
+
datePublished: "2024-01-15"
|
|
116
|
+
review:
|
|
117
|
+
"@type": "Review"
|
|
118
|
+
reviewRating:
|
|
119
|
+
"@type": "Rating"
|
|
120
|
+
ratingValue: "5"
|
|
121
|
+
bestRating: "5"
|
|
122
|
+
author:
|
|
123
|
+
"@type": "Person"
|
|
124
|
+
name: "John Smith"
|
|
125
|
+
---
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
In this example, the schema type is changed to `TechArticle`, and detailed `author`, `datePublished`, and `review` information is added, giving search engines a much richer understanding of your content.
|
package/package.json
CHANGED
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mgks/docmd",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "Generate beautiful, lightweight static documentation sites directly from your Markdown files. Zero clutter, just content.",
|
|
5
5
|
"main": "src/index.js",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": {
|
|
8
|
+
"import": "./src/index.js",
|
|
9
|
+
"require": "./src/index.js"
|
|
10
|
+
}
|
|
11
|
+
},
|
|
6
12
|
"bin": {
|
|
7
13
|
"docmd": "bin/docmd.js"
|
|
8
14
|
},
|
|
@@ -35,14 +41,14 @@
|
|
|
35
41
|
},
|
|
36
42
|
"homepage": "https://github.com/mgks/docmd#readme",
|
|
37
43
|
"dependencies": {
|
|
38
|
-
"chokidar": "^
|
|
39
|
-
"commander": "^
|
|
44
|
+
"chokidar": "^4.0.3",
|
|
45
|
+
"commander": "^14.0.0",
|
|
40
46
|
"ejs": "^3.1.9",
|
|
41
|
-
"express": "^
|
|
47
|
+
"express": "^5.1.0",
|
|
42
48
|
"fs-extra": "^11.2.0",
|
|
43
49
|
"gray-matter": "^4.0.3",
|
|
44
50
|
"highlight.js": "^11.11.1",
|
|
45
|
-
"lucide-static": "^0.
|
|
51
|
+
"lucide-static": "^0.535.0",
|
|
46
52
|
"markdown-it-abbr": "^2.0.0",
|
|
47
53
|
"markdown-it-attrs": "^4.3.1",
|
|
48
54
|
"markdown-it-container": "^4.0.0",
|
|
@@ -52,8 +58,8 @@
|
|
|
52
58
|
"ws": "^8.17.0"
|
|
53
59
|
},
|
|
54
60
|
"devDependencies": {
|
|
55
|
-
"eslint": "^
|
|
56
|
-
"eslint-config-prettier": "^
|
|
61
|
+
"eslint": "^9.32.0",
|
|
62
|
+
"eslint-config-prettier": "^10.1.8",
|
|
57
63
|
"eslint-plugin-node": "^11.1.0",
|
|
58
64
|
"prettier": "^3.2.5"
|
|
59
65
|
},
|