@mgks/docmd 0.2.5 → 0.2.6

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/README.md CHANGED
@@ -5,8 +5,8 @@
5
5
  </p>
6
6
 
7
7
  <p align="center">
8
- <b>Generate beautiful, lightweight static documentation sites from Markdown files.</b><br>
9
- Zero clutter, just content.
8
+ <b>Generate beautiful, lightweight static documentation sites from Markdown files.</b>
9
+ <br>Zero clutter, just content.
10
10
  </p>
11
11
 
12
12
  <p align="center">
@@ -15,71 +15,94 @@
15
15
  <a href="https://github.com/mgks/docmd/blob/main/LICENSE"><img src="https://img.shields.io/github/license/mgks/docmd.svg" alt="license"></a>
16
16
  </p>
17
17
 
18
- Docmd (`docmd`) is a Node.js command-line tool dedicated to generating beautiful, lightweight static documentation sites from standard Markdown files. It champions the philosophy of "zero clutter, just content," prioritizing ease of use for documentation authors and a clean, performant experience for readers.
18
+ Docmd is a Node.js command-line tool for generating fast, beautiful, and lightweight static documentation sites from standard Markdown files. It champions the philosophy of "zero clutter, just content," prioritizing a simple authoring experience and a clean, performant result for readers.
19
19
 
20
- #### 🟢 [Live Preview](https://docmd.mgks.dev): Documentation site powered entirely by *Docmd*, serving as both the official docs and a live demo.
20
+ **:rocket: [Live Preview](https://docmd.mgks.dev): Official documentation site powered by `docmd`.**
21
21
 
22
- ## Features
22
+ ## Key Features
23
23
 
24
- - 📝 **Markdown First** - Standard Markdown with YAML frontmatter
25
- - 🎨 **Beautiful Themes** - Multiple themes and light/dark modes with syntax highlighting
26
- - 🚀 **Fast & Lightweight** - Static site generation with minimal JS
27
- - 🧩 **Custom Components** - Callouts, cards, steps, and more
28
- - 🔌 **Built-in Plugins** - SEO, Analytics, and Sitemap support
29
- - 🎭 **No-Style Pages** - Create custom standalone pages with complete HTML control
30
- - 🖌️ **Custom Styling** - Add custom CSS/JS and HTML directly in frontmatter
31
- - 💻 **Simple CLI** - Easy `init`, `dev`, and `build` commands
32
- - 🌐 **Deploy Anywhere** - Deploy the generated sites anywhere (GitHub Pages, Netlify, Vercel, etc.)
24
+ - **Markdown First:** Write your content in standard Markdown with simple YAML frontmatter.
25
+ - **Beautiful Themes:** Comes with multiple built-in themes (`sky`, `ruby`, `retro`) and automatic light/dark mode support.
26
+ - **Fast & Lightweight:** Blazing fast static site generation with a minimal client-side footprint.
27
+ - **Rich Content:** Go beyond basic Markdown with custom components like callouts, cards, steps, tabs, and Mermaid diagrams.
28
+ - **Built-in Plugins:** SEO meta tags, sitemap, and analytics are all included out-of-the-box.
29
+ - **No-Style Pages:** Create completely custom pages (like landing pages) with full control over the HTML.
30
+ - **Customizable:** Easily extend or override styles with your own CSS and JavaScript.
31
+ - **Simple CLI:** A straightforward workflow with three main commands: `init`, `dev`, and `build`.
32
+ - **Deploy Anywhere:** The generated `site/` folder can be hosted on any static web host (GitHub Pages, Netlify, Vercel, etc.).
33
33
 
34
34
  ## Installation
35
+ **Prerequisites:** [Node.js](https://nodejs.org/) (version 22.x or higher)
35
36
 
36
- ### From npm
37
+ ### Quick Start: Your First Site in 60 Seconds
38
+
39
+ No global installation is required. You can create and run your site in a new folder with one command.
37
40
 
38
41
  ```bash
39
- # Global installation (recommended)
40
- npm install -g @mgks/docmd
42
+ # Create a new project in 'my-docs' and navigate into it
43
+ npx @mgks/docmd init my-docs && cd my-docs
41
44
 
42
- # Local project installation
43
- npm install --save-dev @mgks/docmd
45
+ # Start the development server
46
+ npm start
44
47
  ```
45
48
 
46
- ### Quick Start
49
+ Your new documentation site is now running at `http://localhost:3000` *(or, at your selected or available port)*.
47
50
 
48
- ```bash
49
- # Initialize a new documentation project
50
- docmd init
51
+ ### Global Installation
51
52
 
52
- # Start the development server
53
- docmd dev
53
+ For frequent use, or if you prefer to have the command available system-wide, you can install `docmd` globally using npm.
54
54
 
55
- # Build for production
56
- docmd build
55
+ ```bash
56
+ npm install -g @mgks/docmd
57
57
  ```
58
+ After installation, you can run the `docmd` commands from any directory.
58
59
 
59
- ### Documentation
60
+ ### Basic Workflow
60
61
 
61
- For complete documentation, visit **[docmd.mgks.dev](https://docmd.mgks.dev)**
62
+ 1. **Initialize a Project:**
63
+ ```bash
64
+ docmd init
65
+ ```
66
+ This creates a `docs/` directory, a `docmd.config.js` file, and a sample `index.md` to get you started.
62
67
 
63
- ## Contributing
68
+ 2. **Start the Dev Server:**
69
+ ```bash
70
+ docmd dev
71
+ ```
72
+ This starts a live-reloading server to preview your site as you write.
64
73
 
65
- Contributions are welcome! Please check our [contributing guidelines](https://docmd.mgks.dev/contributing/) to get started.
74
+ 3. **Build for Production:**
75
+ ```bash
76
+ docmd build
77
+ ```
78
+ This generates the complete, optimized static site into the `site/` directory, ready for deployment.
66
79
 
67
- 1. Fork the repository
68
- 2. Clone your fork: `git clone https://github.com/YOUR_USERNAME/docmd.git`
69
- 3. Install dependencies: `npm install`
70
- 4. Make your changes and test them
71
- 5. Submit a pull request
80
+ ## Documentation
72
81
 
73
- ## License
82
+ For a complete guide covering all features, including theming, custom containers, and plugin configuration, please visit the official documentation website: **[docmd.mgks.dev](https://docmd.mgks.dev)**.
83
+
84
+ ## Contributing
85
+
86
+ We welcome contributions of all kinds! Whether it's reporting a bug, suggesting a feature, or submitting a pull request, your help is appreciated.
74
87
 
75
- `docmd` is licensed under the [MIT License](https://github.com/mgks/docmd/blob/main/LICENSE).
88
+ 1. Fork the repository.
89
+ 2. Clone your fork: `git clone https://github.com/YOUR_USERNAME/docmd.git`
90
+ 3. Install dependencies: `npm install`
91
+ 4. Make your changes and test them thoroughly.
92
+ 5. Submit a pull request to the `main` branch.
93
+
94
+ Please check our [contributing guidelines](https://docmd.mgks.dev/contributing/) for more detailed information.
76
95
 
77
96
  ## Support the Project
78
97
 
79
98
  If you find `docmd` useful, please consider:
80
99
 
81
- - Starring the repository on GitHub
82
- - Sharing it with others who might benefit
83
- - Reporting issues or submitting pull requests
100
+ - Starring the repository on GitHub.
101
+ - Sharing it with others who might benefit.
102
+ - Reporting issues or submitting pull requests.
103
+
104
+ ❤️ **[GitHub Sponsors](https://github.com/sponsors/mgks): Become a sponsor to support the ongoing development of `docmd`.**
105
+
106
+ ## License
84
107
 
85
- **[GitHub Sponsors](https://github.com/sponsors/mgks): Become a monthly or one-time GitHub sponsor to support docmd & other projects developed by [@mgks](https://mgks.dev).**
108
+ Docmd is licensed under the [MIT License](https://github.com/mgks/docmd/blob/main/LICENSE).
package/bin/docmd.js CHANGED
@@ -7,6 +7,7 @@ const { version } = require('../package.json');
7
7
  const { initProject } = require('../src/commands/init');
8
8
  const { buildSite } = require('../src/commands/build');
9
9
  const { startDevServer } = require('../src/commands/dev');
10
+ const { printBanner } = require('../src/core/logger');
10
11
 
11
12
  // Helper function to find the config file
12
13
  const findConfigFile = () => {
@@ -52,6 +53,8 @@ program
52
53
  .option('--silent', 'Suppress log output')
53
54
  .action(async (options) => {
54
55
  try {
56
+ if (!options.silent) { printBanner(); }
57
+
55
58
  const originalLog = console.log;
56
59
  if (options.silent) { console.log = () => {}; }
57
60
 
@@ -68,7 +71,7 @@ program
68
71
 
69
72
  } catch (error) {
70
73
  console.error('❌ Build failed:', error.message);
71
- console.error(error.stack);
74
+ // console.error(error.stack);
72
75
  process.exit(1);
73
76
  }
74
77
  });
@@ -83,6 +86,8 @@ program
83
86
  .option('--silent', 'Suppress log output')
84
87
  .action(async (options) => {
85
88
  try {
89
+ if (!options.silent) { printBanner(); }
90
+
86
91
  if (options.silent) {
87
92
  const originalLog = console.log;
88
93
  console.log = (message) => {
@@ -96,7 +101,7 @@ program
96
101
 
97
102
  } catch (error) {
98
103
  console.error('❌ Dev server failed:', error.message);
99
- console.error(error.stack);
104
+ // console.error(error.stack);
100
105
  process.exit(1);
101
106
  }
102
107
  });
@@ -0,0 +1,14 @@
1
+ // bin/postinstall.js
2
+
3
+ const chalk = require('chalk');
4
+
5
+ // This script runs after 'npm install', runs only when the user installs it globally and not in a CI environment
6
+
7
+ if (process.env.npm_config_global && !process.env.CI) {
8
+ console.log(chalk.green('\n🎉 Thank you for installing docmd!'));
9
+ console.log('\nTo get started, run the following commands:');
10
+ console.log(`\n ${chalk.cyan('docmd init my-awesome-docs')}`);
11
+ console.log(` ${chalk.cyan('cd my-awesome-docs')}`);
12
+ console.log(` ${chalk.cyan('npm start')}`);
13
+ console.log('\nFor complete documentation, visit: https://docmd.mgks.dev');
14
+ }
package/config.js CHANGED
@@ -169,7 +169,7 @@ module.exports = {
169
169
  // Sponsor Ribbon Configuration
170
170
  sponsor: {
171
171
  enabled: true, // Enable/disable the sponsor ribbon
172
- title: 'Support docmd', // Text to display on the ribbon
172
+ title: 'Sponsor', // Text to display on the ribbon
173
173
  link: 'https://github.com/sponsors/mgks', // URL for the sponsor link
174
174
  },
175
175
 
package/docs/overview.md CHANGED
@@ -3,7 +3,13 @@ title: "Minimalist Markdown Docs Generator"
3
3
  description: "Generate beautiful, lightweight static documentation sites directly from your Markdown files with docmd. Zero clutter, just content."
4
4
  ---
5
5
 
6
- # docmd
6
+ ```
7
+ _ _
8
+ _| |___ ___ _____ _| |
9
+ | . | . | _| | . |
10
+ |___|___|___|_|_|_|___|
11
+
12
+ ```
7
13
 
8
14
  **Generate beautiful, lightweight static documentation sites directly from your Markdown files. Zero clutter, just content.**
9
15
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mgks/docmd",
3
- "version": "0.2.5",
3
+ "version": "0.2.6",
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
6
  "exports": {
@@ -15,6 +15,7 @@
15
15
  "scripts": {
16
16
  "start": "node ./bin/docmd.js dev",
17
17
  "build": "node ./bin/docmd.js build",
18
+ "postinstall": "node ./bin/postinstall.js",
18
19
  "lint": "eslint .",
19
20
  "format": "prettier --write .",
20
21
  "test": "echo \"Error: no test specified\" && exit 1"
@@ -41,6 +42,8 @@
41
42
  },
42
43
  "homepage": "https://github.com/mgks/docmd#readme",
43
44
  "dependencies": {
45
+ "@mgks/docmd": "^0.2.5",
46
+ "chalk": "^4.1.2",
44
47
  "chokidar": "^4.0.3",
45
48
  "commander": "^14.0.0",
46
49
  "ejs": "^3.1.9",
@@ -6,6 +6,7 @@ const { loadConfig } = require('../core/config-loader');
6
6
  const { createMarkdownItInstance, processMarkdownFile, findMarkdownFiles } = require('../core/file-processor');
7
7
  const { generateHtmlPage, generateNavigationHtml } = require('../core/html-generator');
8
8
  const { renderIcon, clearWarnedIcons } = require('../core/icon-renderer');
9
+ const { findPageNeighbors } = require('../core/navigation-helper');
9
10
  const { generateSitemap } = require('../plugins/sitemap');
10
11
  const { version } = require('../../package.json');
11
12
  const matter = require('gray-matter');
@@ -218,8 +219,12 @@ async function buildSite(configPath, options = { isDev: false, preserve: false,
218
219
 
219
220
  const finalOutputHtmlPath = path.join(OUTPUT_DIR, outputHtmlPath);
220
221
 
221
- const depth = outputHtmlPath.split(path.sep).length - 1;
222
- const relativePathToRoot = depth > 0 ? '../'.repeat(depth) : './';
222
+ let relativePathToRoot = path.relative(path.dirname(finalOutputHtmlPath), OUTPUT_DIR);
223
+ if (relativePathToRoot === '') {
224
+ relativePathToRoot = './';
225
+ } else {
226
+ relativePathToRoot = relativePathToRoot.replace(/\\/g, '/') + '/';
227
+ }
223
228
 
224
229
  let normalizedPath = path.relative(SRC_DIR, filePath).replace(/\\/g, '/');
225
230
  if (path.basename(normalizedPath) === 'index.md') {
@@ -247,74 +252,20 @@ async function buildSite(configPath, options = { isDev: false, preserve: false,
247
252
  config
248
253
  );
249
254
 
250
- let prevPage = null;
251
- let nextPage = null;
252
- let currentPageIndex = -1;
253
-
254
- const flatNavigation = [];
255
-
256
- function createNormalizedPath(item) {
257
- if (!item.path) return null;
258
- return item.path.startsWith('/') ? item.path : '/' + item.path;
259
- }
260
-
261
- function extractNavigationItems(items) {
262
- if (!items || !Array.isArray(items)) return;
263
-
264
- for (const item of items) {
265
- if (item.external) continue;
266
-
267
- if (item.path) {
268
- let normalizedItemPath = createNormalizedPath(item);
269
- if (item.children && !normalizedItemPath.endsWith('/')) {
270
- normalizedItemPath += '/';
271
- }
272
- flatNavigation.push({
273
- title: item.title,
274
- path: normalizedItemPath,
275
- });
276
- }
277
-
278
- if (item.children && Array.isArray(item.children)) {
279
- extractNavigationItems(item.children);
280
- }
281
- }
282
- }
283
-
284
- extractNavigationItems(config.navigation);
285
-
286
- currentPageIndex = flatNavigation.findIndex(item => {
287
- const itemPath = item.path;
288
- const currentPagePath = normalizedPath;
289
- if (itemPath === currentPagePath) {
290
- return true;
291
- }
292
- if (itemPath.endsWith('/') && itemPath.slice(0, -1) === currentPagePath) {
293
- return true;
294
- }
295
- if (currentPagePath.endsWith('/') && currentPagePath.slice(0, -1) === itemPath) {
296
- return true;
297
- }
298
- return false;
299
- });
300
-
301
- if (currentPageIndex >= 0) {
302
- if (currentPageIndex > 0) prevPage = flatNavigation[currentPageIndex - 1];
303
- if (currentPageIndex < flatNavigation.length - 1) nextPage = flatNavigation[currentPageIndex + 1];
304
- }
305
-
255
+ // Find previous and next pages for navigation
256
+ const { prevPage, nextPage } = findPageNeighbors(config.navigation, normalizedPath);
257
+
306
258
  if (prevPage) {
307
- const cleanPath = prevPage.path.startsWith('/') ? prevPage.path.substring(1) : prevPage.path;
308
- prevPage.url = relativePathToRoot + (cleanPath.endsWith('/') ? cleanPath : cleanPath + '/');
309
- if (prevPage.path === '/') prevPage.url = relativePathToRoot;
259
+ const cleanPath = prevPage.path.substring(1);
260
+ prevPage.url = relativePathToRoot + cleanPath;
310
261
  }
311
262
 
312
263
  if (nextPage) {
313
- const cleanPath = nextPage.path.startsWith('/') ? nextPage.path.substring(1) : nextPage.path;
314
- nextPage.url = relativePathToRoot + (cleanPath.endsWith('/') ? cleanPath : cleanPath + '/');
315
- if (nextPage.path === '/') nextPage.url = relativePathToRoot;
264
+ const cleanPath = nextPage.path.substring(1);
265
+ nextPage.url = relativePathToRoot + cleanPath;
316
266
  }
317
267
 
268
+ // Log navigation paths for debugging
318
269
  const pageDataForTemplate = {
319
270
  content: htmlContent,
320
271
  pageTitle: pageFrontmatter.title || 'Untitled',
@@ -1,4 +1,4 @@
1
- //
1
+ // Source file from the docmd project — https://github.com/mgks/docmd
2
2
 
3
3
  const ejs = require('ejs');
4
4
  const path = require('path');
@@ -0,0 +1,21 @@
1
+ // Source file from the docmd project — https://github.com/mgks/docmd
2
+
3
+ const chalk = require('chalk');
4
+
5
+ const { version } = require('../../package.json');
6
+
7
+ const printBanner = () => {
8
+ const logo = `
9
+
10
+ ${chalk.blue(' _ _ ')}
11
+ ${chalk.blue(' _| |___ ___ _____ _| |')}
12
+ ${chalk.blue(' | . | . | _| | . |')}
13
+ ${chalk.blue(' |___|___|___|_|_|_|___|')}
14
+ `;
15
+
16
+ console.log(logo);
17
+ console.log(` ${chalk.dim(`v${version}`)}`);
18
+ console.log(`\n`);
19
+ };
20
+
21
+ module.exports = { printBanner };
@@ -0,0 +1,62 @@
1
+ // Source file from the docmd project — https://github.com/mgks/docmd
2
+
3
+ /**
4
+ * Flattens the navigation tree and finds the previous and next pages relative to the current page.
5
+ * @param {Array} navItems - The navigation array from config.
6
+ * @param {string} currentPagePath - The normalized path of the current page.
7
+ * @returns {{prevPage: object|null, nextPage: object|null}}
8
+ */
9
+ function findPageNeighbors(navItems, currentPagePath) {
10
+ const flatNavigation = [];
11
+
12
+ // Recursive function to flatten the navigation tree
13
+ function extractNavigationItems(items) {
14
+ if (!items || !Array.isArray(items)) return;
15
+
16
+ for (const item of items) {
17
+ if (item.external || !item.path || item.path === '#') {
18
+ // If it's a category with no path but has children, recurse into them
19
+ if (item.children && Array.isArray(item.children)) {
20
+ extractNavigationItems(item.children);
21
+ }
22
+ continue; // Skip external links and parent items without a direct path
23
+ }
24
+
25
+ let normalizedItemPath = item.path;
26
+
27
+ // Ensure it starts with a slash
28
+ if (!normalizedItemPath.startsWith('/')) {
29
+ normalizedItemPath = '/' + normalizedItemPath;
30
+ }
31
+
32
+ // Ensure it ends with a slash (unless it's the root path)
33
+ if (normalizedItemPath.length > 1 && !normalizedItemPath.endsWith('/')) {
34
+ normalizedItemPath += '/';
35
+ }
36
+
37
+ flatNavigation.push({
38
+ title: item.title,
39
+ path: normalizedItemPath,
40
+ });
41
+
42
+ if (item.children && Array.isArray(item.children)) {
43
+ extractNavigationItems(item.children);
44
+ }
45
+ }
46
+ }
47
+
48
+ extractNavigationItems(navItems);
49
+
50
+ const currentPageIndex = flatNavigation.findIndex(item => item.path === currentPagePath);
51
+
52
+ if (currentPageIndex === -1) {
53
+ return { prevPage: null, nextPage: null };
54
+ }
55
+
56
+ const prevPage = currentPageIndex > 0 ? flatNavigation[currentPageIndex - 1] : null;
57
+ const nextPage = currentPageIndex < flatNavigation.length - 1 ? flatNavigation[currentPageIndex + 1] : null;
58
+
59
+ return { prevPage, nextPage };
60
+ }
61
+
62
+ module.exports = { findPageNeighbors };