@mgks/docmd 0.1.1 → 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.
@@ -2,7 +2,7 @@ name: Publish Package to NPM and GitHub Packages
2
2
 
3
3
  on:
4
4
  release:
5
- types: [created, published] # Triggers when a new GitHub Release is created or published
5
+ types: [created] # [created, published] Triggers when a new GitHub Release is created or published
6
6
  workflow_dispatch: # Allows manual triggering for testing
7
7
 
8
8
  jobs:
package/bin/docmd.js CHANGED
@@ -30,7 +30,8 @@ program
30
30
  .command('build')
31
31
  .description('Build the static site from Markdown files and config.js')
32
32
  .option('-c, --config <path>', 'Path to config.js file', 'config.js')
33
- .option('-p, --preserve', 'Preserve existing asset files instead of updating them', false)
33
+ .option('-p, --preserve', 'Preserve existing asset files instead of updating them')
34
+ .option('--no-preserve', 'Force update all asset files, overwriting existing ones')
34
35
  .action(async (options) => {
35
36
  try {
36
37
  console.log('🚀 Starting build process...');
@@ -49,7 +50,8 @@ program
49
50
  .command('dev')
50
51
  .description('Start a live preview development server')
51
52
  .option('-c, --config <path>', 'Path to config.js file', 'config.js')
52
- .option('-p, --preserve', 'Preserve existing asset files instead of updating them', false)
53
+ .option('-p, --preserve', 'Preserve existing asset files instead of updating them')
54
+ .option('--no-preserve', 'Force update all asset files, overwriting existing ones')
53
55
  .action(async (options) => {
54
56
  try {
55
57
  await startDevServer(options.config, { preserve: options.preserve });
@@ -0,0 +1,126 @@
1
+ ---
2
+ title: "Assets Management"
3
+ description: "Learn how to manage and customize your assets (CSS, JavaScript, images) in your docmd site."
4
+ ---
5
+
6
+ # Assets Management
7
+
8
+ Managing your custom assets (CSS, JavaScript, images) is an important part of customizing your documentation site. `docmd` provides flexible ways to include and manage these assets.
9
+
10
+ ## Project Structure
11
+
12
+ When you initialize a new project with `docmd init`, it creates the following structure:
13
+
14
+ ```
15
+ your-project/
16
+ ├── assets/ # User assets directory
17
+ │ ├── css/ # Custom CSS files
18
+ │ ├── js/ # Custom JavaScript files
19
+ │ └── images/ # Custom images
20
+ ├── docs/ # Markdown content
21
+ ├── config.js
22
+ └── ...
23
+ ```
24
+
25
+ This structure makes it easy to organize and manage your custom assets.
26
+
27
+ ## How Assets Are Handled
28
+
29
+ There are two main ways to manage assets in your docmd site:
30
+
31
+ ### 1. Root-Level Assets Directory (Recommended)
32
+
33
+ The simplest and recommended approach is to use the `assets/` directory in your project root:
34
+
35
+ **How it works:**
36
+ - During the build process, docmd automatically copies everything from your root `assets/` directory to the output `site/assets/` directory
37
+ - Your custom assets take precedence over docmd's built-in assets with the same name
38
+ - This approach is ideal for GitHub Pages deployments and other hosting scenarios
39
+
40
+ **Example workflow:**
41
+ 1. Create or modify files in your project's `assets/` directory:
42
+ ```
43
+ assets/css/custom-styles.css
44
+ assets/js/interactive-features.js
45
+ assets/images/logo.png
46
+ ```
47
+
48
+ 2. Reference these files in your `config.js`:
49
+ ```javascript
50
+ module.exports = {
51
+ // ...
52
+ theme: {
53
+ // ...
54
+ customCss: [
55
+ '/assets/css/custom-styles.css',
56
+ ],
57
+ },
58
+ customJs: [
59
+ '/assets/js/interactive-features.js',
60
+ ],
61
+ // ...
62
+ };
63
+ ```
64
+
65
+ 3. Use images in your Markdown content:
66
+ ```markdown
67
+ ![Logo](/assets/images/logo.png)
68
+ ```
69
+
70
+ 4. Build your site:
71
+ ```bash
72
+ docmd build
73
+ ```
74
+
75
+ ### 2. Customizing Default Assets
76
+
77
+ If you want to modify docmd's default assets:
78
+
79
+ 1. First, build your site normally to generate all assets:
80
+ ```bash
81
+ docmd build
82
+ ```
83
+
84
+ 2. Modify the generated files in the `site/assets` directory as needed.
85
+
86
+ 3. When rebuilding, use the `--preserve` flag to keep your customized files:
87
+ ```bash
88
+ docmd build --preserve
89
+ ```
90
+
91
+ 4. If you want to update to the latest docmd assets (for example, after updating the package), run without the preserve flag:
92
+ ```bash
93
+ docmd build
94
+ ```
95
+
96
+ This approach allows you to:
97
+ - Get the latest assets by default when you update the package
98
+ - Preserve your customizations when needed with `--preserve`
99
+ - See which files are being preserved during the build process
100
+
101
+ The preservation behavior works with both `build` and `dev` commands:
102
+ ```bash
103
+ # Preserve custom assets during development
104
+ docmd dev --preserve
105
+ ```
106
+
107
+ ## Asset Precedence
108
+
109
+ When multiple assets with the same name exist, docmd follows this precedence order:
110
+
111
+ 1. **User assets** from the root `assets/` directory (highest priority)
112
+ 2. **Preserved assets** from previous builds (if `--preserve` is enabled, which is the default)
113
+ 3. **Built-in assets** from the docmd package (lowest priority)
114
+
115
+ This ensures your custom assets always take precedence over default ones.
116
+
117
+ ## GitHub Pages Deployment
118
+
119
+ When deploying to GitHub Pages, your assets structure is preserved. If you're using a custom domain or GitHub Pages URL, make sure your asset paths are correctly configured.
120
+
121
+ For more information on deployment, see the [Deployment](/deployment/) documentation.
122
+
123
+ ## Related Topics
124
+
125
+ - [Custom CSS & JS](/theming/custom-css-js/) - Learn how to configure custom CSS and JavaScript
126
+ - [Theming](/theming/) - Explore other theming options for your documentation site
@@ -1,5 +1,5 @@
1
1
  ---
2
- title: "Custom CSS & JS"
2
+ title: "Custom Styles & Scripts"
3
3
  description: "Learn how to add your own custom CSS and JavaScript to your docmd site for advanced customization."
4
4
  ---
5
5
 
@@ -30,41 +30,8 @@ module.exports = {
30
30
  **How it works:**
31
31
  * Each string in the `customCss` array should be an absolute path from the root of your generated `site/` directory (e.g., if your file is `site/assets/css/my-branding.css`, the path is `/assets/css/my-branding.css`).
32
32
  * These `<link rel="stylesheet">` tags will be added to the `<head>` of every page *after* the main theme CSS and `highlight.js` CSS. This allows your custom styles to override the default theme styles.
33
- * You are responsible for ensuring these CSS files exist at the specified locations in your final `site/` output. Typically, you would:
34
- 1. Create your custom CSS files (e.g., `my-branding.css`).
35
- 2. Place them in a folder within your project (e.g., `my-project/static-assets/css/`).
36
- 3. Ensure that this folder (or its contents) is copied to the correct location in your `site/` directory during `docmd`'s asset copying process. If `docmd` copies a top-level `assets/` folder from your source, place them there.
37
33
 
38
- ## Managing Custom Assets
39
-
40
- By default, `docmd` will always update assets to the latest version when you run `build` or `dev` commands. This ensures your site benefits from the latest improvements and fixes.
41
-
42
- ### Customizing Default Assets
43
-
44
- If you want to customize default assets (like theme CSS files or scripts):
45
-
46
- 1. First, build your site normally to generate all assets:
47
- ```bash
48
- docmd build
49
- ```
50
-
51
- 2. Modify the generated files in the `site/assets` directory as needed.
52
-
53
- 3. When rebuilding, use the `--preserve` flag to keep your customized files:
54
- ```bash
55
- docmd build --preserve
56
- ```
57
-
58
- This approach allows you to:
59
- - Always get the latest assets when you want them (default behavior)
60
- - Preserve your customizations when needed (with `--preserve`)
61
- - Easily see which files are being preserved during the build process
62
-
63
- The `--preserve` flag works with both `build` and `dev` commands:
64
- ```bash
65
- # Preserve custom assets during development
66
- docmd dev --preserve
67
- ```
34
+ > **Note:** For information on how to manage your custom asset files (CSS, JS, images), see the [Assets Management](/theming/assets-management/) documentation.
68
35
 
69
36
  **Use Cases for Custom CSS:**
70
37
  * **Overriding CSS Variables:** The `default` theme uses CSS variables extensively. You can redefine these in your custom CSS.
@@ -104,7 +71,6 @@ module.exports = {
104
71
  **How it works:**
105
72
  * Each string in the `customJs` array should be an absolute path from the root of your generated `site/` directory.
106
73
  * These `<script src="..."></script>` tags will be added just before the closing `</body>` tag on every page. This ensures the DOM is loaded before your scripts run and is generally better for page performance.
107
- * Similar to custom CSS, you are responsible for ensuring these JavaScript files exist at the specified locations in your final `site/` output.
108
74
 
109
75
  **Use Cases for Custom JS:**
110
76
  * Adding interactive elements (e.g., custom modals, tabs not provided by `docmd`).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mgks/docmd",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
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
  "bin": {
@@ -35,7 +35,6 @@
35
35
  },
36
36
  "homepage": "https://github.com/mgks/docmd#readme",
37
37
  "dependencies": {
38
- "@mgks/docmd": "^0.1.0",
39
38
  "chokidar": "^3.6.0",
40
39
  "commander": "^12.0.0",
41
40
  "ejs": "^3.1.9",
@@ -506,8 +506,10 @@
506
506
  text-align: right;
507
507
  opacity: 0.9;
508
508
  font-weight: 500;
509
-
510
509
  }
510
+ .branding-footer svg {
511
+ color: rgb(251, 58, 58);
512
+ }
511
513
 
512
514
  .page-footer a {
513
515
  color: var(--link-color);
@@ -35,6 +35,7 @@ async function buildSite(configPath, options = { isDev: false, preserve: false }
35
35
  const CWD = process.cwd();
36
36
  const SRC_DIR = path.resolve(CWD, config.srcDir);
37
37
  const OUTPUT_DIR = path.resolve(CWD, config.outputDir);
38
+ const USER_ASSETS_DIR = path.resolve(CWD, 'assets'); // User's custom assets directory
38
39
 
39
40
  if (!await fs.pathExists(SRC_DIR)) {
40
41
  throw new Error(`Source directory not found: ${SRC_DIR}`);
@@ -57,6 +58,33 @@ async function buildSite(configPath, options = { isDev: false, preserve: false }
57
58
 
58
59
  // Track preserved files for summary report
59
60
  const preservedFiles = [];
61
+ const userAssetsCopied = [];
62
+
63
+ // Copy user assets from root assets/ directory if it exists
64
+ if (await fs.pathExists(USER_ASSETS_DIR)) {
65
+ const assetsDestDir = path.join(OUTPUT_DIR, 'assets');
66
+ await fs.ensureDir(assetsDestDir);
67
+
68
+ if (!options.isDev) {
69
+ console.log(`📂 Copying user assets from ${USER_ASSETS_DIR} to ${assetsDestDir}...`);
70
+ }
71
+
72
+ const userAssetFiles = await getAllFiles(USER_ASSETS_DIR);
73
+
74
+ for (const srcFile of userAssetFiles) {
75
+ const relativePath = path.relative(USER_ASSETS_DIR, srcFile);
76
+ const destFile = path.join(assetsDestDir, relativePath);
77
+
78
+ // Ensure directory exists
79
+ await fs.ensureDir(path.dirname(destFile));
80
+ await fs.copyFile(srcFile, destFile);
81
+ userAssetsCopied.push(relativePath);
82
+ }
83
+
84
+ if (!options.isDev && userAssetsCopied.length > 0) {
85
+ console.log(`📦 Copied ${userAssetsCopied.length} user assets`);
86
+ }
87
+ }
60
88
 
61
89
  // Copy assets
62
90
  const assetsSrcDir = path.join(__dirname, '..', 'assets');
@@ -64,7 +92,7 @@ async function buildSite(configPath, options = { isDev: false, preserve: false }
64
92
 
65
93
  if (await fs.pathExists(assetsSrcDir)) {
66
94
  if (!options.isDev) {
67
- console.log(`📂 Copying assets to ${assetsDestDir}...`);
95
+ console.log(`📂 Copying docmd assets to ${assetsDestDir}...`);
68
96
  }
69
97
 
70
98
  // Create destination directory if it doesn't exist
@@ -81,10 +109,13 @@ async function buildSite(configPath, options = { isDev: false, preserve: false }
81
109
  // Check if destination file already exists
82
110
  const fileExists = await fs.pathExists(destFile);
83
111
 
84
- if (fileExists && options.preserve) {
112
+ // Skip if the file exists and either:
113
+ // 1. The preserve flag is set, OR
114
+ // 2. The file was copied from user assets (user assets take precedence)
115
+ if (fileExists && (options.preserve || userAssetsCopied.includes(relativePath))) {
85
116
  // Skip file and add to preserved list
86
117
  preservedFiles.push(relativePath);
87
- if (!options.isDev) {
118
+ if (!options.isDev && options.preserve) {
88
119
  console.log(` Preserving existing file: ${relativePath}`);
89
120
  }
90
121
  } else {
@@ -327,7 +358,7 @@ async function buildSite(configPath, options = { isDev: false, preserve: false }
327
358
  // Generate sitemap if enabled in config
328
359
  if (config.plugins?.sitemap !== false) {
329
360
  try {
330
- await generateSitemap(config, processedPages, OUTPUT_DIR);
361
+ await generateSitemap(config, processedPages, OUTPUT_DIR, { isDev: options.isDev });
331
362
  } catch (error) {
332
363
  console.error(`❌ Error generating sitemap: ${error.message}`);
333
364
  }
@@ -339,6 +370,16 @@ async function buildSite(configPath, options = { isDev: false, preserve: false }
339
370
  preservedFiles.forEach(file => console.log(` - assets/${file}`));
340
371
  console.log(`\nTo update these files in future builds, run without the --preserve flag.`);
341
372
  }
373
+
374
+ if (userAssetsCopied.length > 0 && !options.isDev) {
375
+ console.log(`\n📋 User Assets: ${userAssetsCopied.length} files were copied from your assets/ directory:`);
376
+ if (userAssetsCopied.length <= 10) {
377
+ userAssetsCopied.forEach(file => console.log(` - assets/${file}`));
378
+ } else {
379
+ userAssetsCopied.slice(0, 5).forEach(file => console.log(` - assets/${file}`));
380
+ console.log(` - ... and ${userAssetsCopied.length - 5} more files`);
381
+ }
382
+ }
342
383
  }
343
384
 
344
385
  // Helper function to find HTML files and sitemap.xml to clean up
@@ -18,6 +18,7 @@ async function startDevServer(configPathOption, options = { preserve: false }) {
18
18
  outputDir: path.resolve(CWD, currentConfig.outputDir),
19
19
  srcDirToWatch: path.resolve(CWD, currentConfig.srcDir),
20
20
  configFileToWatch: path.resolve(CWD, configPathOption), // Path to the config file itself
21
+ userAssetsDir: path.resolve(CWD, 'assets'), // User's assets directory
21
22
  };
22
23
  };
23
24
 
@@ -65,11 +66,72 @@ async function startDevServer(configPathOption, options = { preserve: false }) {
65
66
  if (typeof body === 'string') {
66
67
  const liveReloadScript = `
67
68
  <script>
68
- const socket = new WebSocket(\`ws://\${window.location.host}\`);
69
- socket.onmessage = function(event) { if (event.data === 'reload') window.location.reload(); };
70
- socket.onerror = function(error) { console.error('WebSocket Client Error:', error); };
71
- // socket.onopen = function() { console.log('WebSocket Client Connected'); };
72
- // socket.onclose = function() { console.log('WebSocket Client Disconnected'); };
69
+ (function() {
70
+ // More robust WebSocket connection with automatic reconnection
71
+ let socket;
72
+ let reconnectAttempts = 0;
73
+ const maxReconnectAttempts = 5;
74
+ const reconnectDelay = 1000; // Start with 1 second delay
75
+
76
+ function connect() {
77
+ socket = new WebSocket(\`ws://\${window.location.host}\`);
78
+
79
+ socket.onmessage = function(event) {
80
+ if (event.data === 'reload') {
81
+ console.log('Received reload signal. Refreshing page...');
82
+ window.location.reload();
83
+ }
84
+ };
85
+
86
+ socket.onopen = function() {
87
+ console.log('Live reload connected.');
88
+ reconnectAttempts = 0; // Reset reconnect counter on successful connection
89
+ };
90
+
91
+ socket.onclose = function() {
92
+ if (reconnectAttempts < maxReconnectAttempts) {
93
+ reconnectAttempts++;
94
+ const delay = reconnectDelay * Math.pow(1.5, reconnectAttempts - 1); // Exponential backoff
95
+ console.log(\`Live reload disconnected. Reconnecting in \${delay/1000} seconds...\`);
96
+ setTimeout(connect, delay);
97
+ } else {
98
+ console.log('Live reload disconnected. Max reconnect attempts reached.');
99
+ }
100
+ };
101
+
102
+ socket.onerror = function(error) {
103
+ console.error('WebSocket error:', error);
104
+ };
105
+ }
106
+
107
+ // Initial connection
108
+ connect();
109
+
110
+ // Backup reload mechanism using polling for browsers with WebSocket issues
111
+ let lastModified = new Date().getTime();
112
+ const pollInterval = 2000; // Poll every 2 seconds
113
+
114
+ function checkForChanges() {
115
+ fetch(window.location.href, { method: 'HEAD', cache: 'no-store' })
116
+ .then(response => {
117
+ const serverLastModified = new Date(response.headers.get('Last-Modified')).getTime();
118
+ if (serverLastModified > lastModified) {
119
+ console.log('Change detected via polling. Refreshing page...');
120
+ window.location.reload();
121
+ }
122
+ lastModified = serverLastModified;
123
+ })
124
+ .catch(error => console.error('Error checking for changes:', error));
125
+ }
126
+
127
+ // Only use polling as a fallback if WebSocket fails
128
+ setTimeout(() => {
129
+ if (socket.readyState !== WebSocket.OPEN) {
130
+ console.log('WebSocket not connected. Falling back to polling.');
131
+ setInterval(checkForChanges, pollInterval);
132
+ }
133
+ }, 5000);
134
+ })();
73
135
  </script>
74
136
  `;
75
137
  body = body.replace('</body>', `${liveReloadScript}</body>`);
@@ -80,6 +142,12 @@ async function startDevServer(configPathOption, options = { preserve: false }) {
80
142
  next();
81
143
  });
82
144
 
145
+ // Add Last-Modified header to all responses for polling fallback
146
+ app.use((req, res, next) => {
147
+ res.setHeader('Last-Modified', new Date().toUTCString());
148
+ next();
149
+ });
150
+
83
151
  // Serve static files from the output directory
84
152
  // This middleware needs to be dynamic if outputDir changes
85
153
  let staticMiddleware = express.static(paths.outputDir);
@@ -95,21 +163,38 @@ async function startDevServer(configPathOption, options = { preserve: false }) {
95
163
  // Optionally, don't start server if initial build fails, or serve a specific error page.
96
164
  }
97
165
 
166
+ // Check if user assets directory exists
167
+ const userAssetsDirExists = await fs.pathExists(paths.userAssetsDir);
98
168
 
99
169
  // Watch for changes
100
170
  const watchedPaths = [
101
171
  paths.srcDirToWatch,
102
172
  paths.configFileToWatch,
103
- DOCMD_TEMPLATES_DIR,
104
- DOCMD_ASSETS_DIR
105
173
  ];
106
174
 
107
- console.log(`👀 Watching for changes in:
108
- - Source: ${paths.srcDirToWatch}
109
- - Config: ${paths.configFileToWatch}
110
- - docmd Templates: ${DOCMD_TEMPLATES_DIR} (internal)
111
- - docmd Assets: ${DOCMD_ASSETS_DIR} (internal)
112
- `);
175
+ // Add user assets directory to watched paths if it exists
176
+ if (userAssetsDirExists) {
177
+ watchedPaths.push(paths.userAssetsDir);
178
+ }
179
+
180
+ // Add internal paths for docmd development (not shown to end users)
181
+ const internalPaths = [DOCMD_TEMPLATES_DIR, DOCMD_ASSETS_DIR];
182
+
183
+ // Only in development environments, we might want to watch internal files too
184
+ if (process.env.DOCMD_DEV === 'true') {
185
+ watchedPaths.push(...internalPaths);
186
+ }
187
+
188
+ console.log(`👀 Watching for changes in:`);
189
+ console.log(` - Source: ${paths.srcDirToWatch}`);
190
+ console.log(` - Config: ${paths.configFileToWatch}`);
191
+ if (userAssetsDirExists) {
192
+ console.log(` - Assets: ${paths.userAssetsDir}`);
193
+ }
194
+ if (process.env.DOCMD_DEV === 'true') {
195
+ console.log(` - docmd Templates: ${DOCMD_TEMPLATES_DIR} (internal)`);
196
+ console.log(` - docmd Assets: ${DOCMD_ASSETS_DIR} (internal)`);
197
+ }
113
198
 
114
199
  const watcher = chokidar.watch(watchedPaths, {
115
200
  ignored: /(^|[\/\\])\../, // ignore dotfiles
@@ -145,7 +230,7 @@ async function startDevServer(configPathOption, options = { preserve: false }) {
145
230
 
146
231
  await buildSite(configPathOption, { isDev: true, preserve: options.preserve }); // Re-build using the potentially updated config path
147
232
  broadcastReload();
148
- console.log('✅ Rebuild complete. Browser should refresh.');
233
+ console.log('✅ Rebuild complete. Browser will refresh automatically.');
149
234
  } catch (error) {
150
235
  console.error('❌ Rebuild failed:', error.message, error.stack);
151
236
  }
@@ -164,6 +249,7 @@ async function startDevServer(configPathOption, options = { preserve: false }) {
164
249
  }
165
250
  console.log(`🎉 Dev server started at http://localhost:${PORT}`);
166
251
  console.log(`Serving content from: ${paths.outputDir}`);
252
+ console.log(`Live reload is active. Browser will refresh automatically when files change.`);
167
253
  });
168
254
 
169
255
  // Graceful shutdown
@@ -1,5 +1,6 @@
1
1
  const fs = require('fs-extra');
2
2
  const path = require('path');
3
+ const readline = require('readline');
3
4
 
4
5
  const defaultConfigContent = `// config.js: basic config for docmd
5
6
  module.exports = {
@@ -76,9 +77,18 @@ module.exports = {
76
77
  // Icons are kebab-case names from Lucide Icons (https://lucide.dev/)
77
78
  navigation: [
78
79
  { title: 'Welcome', path: '/', icon: 'home' }, // Corresponds to docs/index.md
80
+ {
81
+ title: 'Getting Started',
82
+ icon: 'rocket',
83
+ path: '#',
84
+ children: [
85
+ { title: 'Documentation', path: 'https://docmd.mgks.dev', icon: 'scroll', external: true },
86
+ { title: 'Installation', path: 'https://docmd.mgks.dev/getting-started/installation', icon: 'download', external: true },
87
+ { title: 'Basic Usage', path: 'https://docmd.mgks.dev/getting-started/basic-usage', icon: 'play', external: true },
88
+ ],
89
+ },
79
90
  // External links:
80
91
  { title: 'GitHub', path: 'https://github.com/mgks/docmd', icon: 'github', external: true },
81
- { title: 'Documentation', path: 'https://github.com/mgks/docmd', icon: 'scroll', external: true }
82
92
  ],
83
93
 
84
94
  // Footer Configuration
@@ -106,16 +116,117 @@ async function initProject() {
106
116
  const docsDir = path.join(baseDir, 'docs');
107
117
  const configFile = path.join(baseDir, 'config.js');
108
118
  const indexMdFile = path.join(docsDir, 'index.md');
119
+ const assetsDir = path.join(baseDir, 'assets');
120
+ const assetsCssDir = path.join(assetsDir, 'css');
121
+ const assetsJsDir = path.join(assetsDir, 'js');
122
+ const assetsImagesDir = path.join(assetsDir, 'images');
123
+
124
+ const existingFiles = [];
125
+ const dirExists = {
126
+ docs: false,
127
+ assets: false
128
+ };
129
+
130
+ // Check each file individually
131
+ if (await fs.pathExists(configFile)) {
132
+ existingFiles.push('config.js');
133
+ }
134
+
135
+ if (await fs.pathExists(docsDir)) {
136
+ dirExists.docs = true;
137
+
138
+ if (await fs.pathExists(indexMdFile)) {
139
+ existingFiles.push('docs/index.md');
140
+ }
141
+ }
109
142
 
110
- if (await fs.pathExists(configFile) || await fs.pathExists(docsDir)) {
111
- console.warn('⚠️ `docs/` directory or `config.js` already exists. Skipping creation to avoid overwriting.');
112
- } else {
143
+ // Check if assets directory exists
144
+ if (await fs.pathExists(assetsDir)) {
145
+ dirExists.assets = true;
146
+ }
147
+
148
+ // Determine if we should override existing files
149
+ let shouldOverride = false;
150
+ if (existingFiles.length > 0) {
151
+ console.warn('⚠️ The following files already exist:');
152
+ existingFiles.forEach(file => console.warn(` - ${file}`));
153
+
154
+ const rl = readline.createInterface({
155
+ input: process.stdin,
156
+ output: process.stdout
157
+ });
158
+
159
+ const answer = await new Promise(resolve => {
160
+ rl.question('Do you want to override these files? (y/N): ', resolve);
161
+ });
162
+
163
+ rl.close();
164
+
165
+ shouldOverride = answer.toLowerCase() === 'y';
166
+
167
+ if (!shouldOverride) {
168
+ console.log('⏭️ Skipping existing files. Will only create new files.');
169
+ }
170
+ }
171
+
172
+ // Create docs directory if it doesn't exist
173
+ if (!dirExists.docs) {
113
174
  await fs.ensureDir(docsDir);
175
+ console.log('📁 Created `docs/` directory');
176
+ } else {
177
+ console.log('📁 Using existing `docs/` directory');
178
+ }
179
+
180
+ // Create assets directory structure if it doesn't exist
181
+ if (!dirExists.assets) {
182
+ await fs.ensureDir(assetsDir);
183
+ await fs.ensureDir(assetsCssDir);
184
+ await fs.ensureDir(assetsJsDir);
185
+ await fs.ensureDir(assetsImagesDir);
186
+ console.log('📁 Created `assets/` directory with css, js, and images subdirectories');
187
+ } else {
188
+ console.log('📁 Using existing `assets/` directory');
189
+
190
+ // Create subdirectories if they don't exist
191
+ if (!await fs.pathExists(assetsCssDir)) {
192
+ await fs.ensureDir(assetsCssDir);
193
+ console.log('📁 Created `assets/css/` directory');
194
+ }
195
+
196
+ if (!await fs.pathExists(assetsJsDir)) {
197
+ await fs.ensureDir(assetsJsDir);
198
+ console.log('📁 Created `assets/js/` directory');
199
+ }
200
+
201
+ if (!await fs.pathExists(assetsImagesDir)) {
202
+ await fs.ensureDir(assetsImagesDir);
203
+ console.log('📁 Created `assets/images/` directory');
204
+ }
205
+ }
206
+
207
+ // Write config file if it doesn't exist or user confirmed override
208
+ if (!await fs.pathExists(configFile)) {
114
209
  await fs.writeFile(configFile, defaultConfigContent, 'utf8');
115
- await fs.writeFile(indexMdFile, defaultIndexMdContent, 'utf8');
116
210
  console.log('📄 Created `config.js`');
117
- console.log('📁 Created `docs/` directory with a sample `index.md`');
211
+ } else if (shouldOverride) {
212
+ await fs.writeFile(configFile, defaultConfigContent, 'utf8');
213
+ console.log('📄 Updated `config.js`');
214
+ } else {
215
+ console.log('⏭️ Skipped existing `config.js`');
216
+ }
217
+
218
+ // Write index.md file if it doesn't exist or user confirmed override
219
+ if (!await fs.pathExists(indexMdFile)) {
220
+ await fs.writeFile(indexMdFile, defaultIndexMdContent, 'utf8');
221
+ console.log('📄 Created `docs/index.md`');
222
+ } else if (shouldOverride) {
223
+ await fs.writeFile(indexMdFile, defaultIndexMdContent, 'utf8');
224
+ console.log('📄 Updated `docs/index.md`');
225
+ } else {
226
+ console.log('⏭️ Skipped existing `docs/index.md`');
118
227
  }
228
+
229
+ console.log('✅ Project initialization complete!');
119
230
  }
120
231
 
121
232
  module.exports = { initProject };
@@ -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 };
@@ -100,7 +100,7 @@
100
100
  <%- footerHtml || '' %>
101
101
  </div>
102
102
  <div class="branding-footer">
103
- 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>
104
104
  </div>
105
105
  </div>
106
106
  </footer>