@mgks/docmd 0.1.2 → 0.1.3
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 +3 -1
- package/assets/css/welcome.css +362 -0
- package/assets/images/preview-dark-1.png +0 -0
- package/assets/images/preview-dark-2.png +0 -0
- package/assets/images/preview-dark-3.png +0 -0
- package/assets/images/preview-light-1.png +0 -0
- package/assets/images/preview-light-2.png +0 -0
- package/assets/images/preview-light-3.png +0 -0
- package/config.js +5 -2
- package/docs/content/no-style-example.md +110 -0
- package/docs/content/no-style-pages.md +202 -0
- package/docs/index.md +140 -53
- package/docs/overview.md +56 -0
- package/package.json +1 -1
- package/src/commands/build.js +239 -203
- package/src/commands/dev.js +70 -28
- package/src/core/file-processor.js +67 -5
- package/src/core/html-generator.js +16 -3
- package/src/plugins/sitemap.js +15 -1
- package/src/templates/no-style.ejs +159 -0
package/src/commands/dev.js
CHANGED
|
@@ -8,6 +8,25 @@ const fs = require('fs-extra');
|
|
|
8
8
|
const { buildSite } = require('./build'); // Re-use the build logic
|
|
9
9
|
const { loadConfig } = require('../core/config-loader');
|
|
10
10
|
|
|
11
|
+
/**
|
|
12
|
+
* Format paths for display to make them relative to CWD
|
|
13
|
+
* @param {string} absolutePath - The absolute path to format
|
|
14
|
+
* @param {string} cwd - Current working directory
|
|
15
|
+
* @returns {string} - Formatted relative path
|
|
16
|
+
*/
|
|
17
|
+
function formatPathForDisplay(absolutePath, cwd) {
|
|
18
|
+
// Get the relative path from CWD
|
|
19
|
+
const relativePath = path.relative(cwd, absolutePath);
|
|
20
|
+
|
|
21
|
+
// If it's not a subdirectory, prefix with ./ for clarity
|
|
22
|
+
if (!relativePath.startsWith('..') && !path.isAbsolute(relativePath)) {
|
|
23
|
+
return `./${relativePath}`;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Return the relative path
|
|
27
|
+
return relativePath;
|
|
28
|
+
}
|
|
29
|
+
|
|
11
30
|
async function startDevServer(configPathOption, options = { preserve: false }) {
|
|
12
31
|
let config = await loadConfig(configPathOption); // Load initial config
|
|
13
32
|
const CWD = process.cwd(); // Current Working Directory where user runs `docmd dev`
|
|
@@ -48,22 +67,24 @@ async function startDevServer(configPathOption, options = { preserve: false }) {
|
|
|
48
67
|
console.error('WebSocket Server error:', error);
|
|
49
68
|
});
|
|
50
69
|
|
|
51
|
-
|
|
52
70
|
function broadcastReload() {
|
|
53
|
-
// console.log('Broadcasting reload to', wsClients.size, 'clients');
|
|
54
71
|
wsClients.forEach(client => {
|
|
55
72
|
if (client.readyState === WebSocket.OPEN) {
|
|
56
|
-
|
|
73
|
+
try {
|
|
74
|
+
client.send('reload');
|
|
75
|
+
} catch (error) {
|
|
76
|
+
console.error('Error sending reload command to client:', error);
|
|
77
|
+
}
|
|
57
78
|
}
|
|
58
79
|
});
|
|
59
80
|
}
|
|
60
81
|
|
|
61
|
-
// Inject live reload script into HTML
|
|
82
|
+
// Inject live reload script into HTML responses
|
|
62
83
|
app.use((req, res, next) => {
|
|
63
|
-
if (req.path.endsWith('.html')) {
|
|
84
|
+
if (req.path.endsWith('.html') || !req.path.includes('.')) {
|
|
64
85
|
const originalSend = res.send;
|
|
65
|
-
res.send = function
|
|
66
|
-
if (typeof body === 'string') {
|
|
86
|
+
res.send = function(body) {
|
|
87
|
+
if (typeof body === 'string' && body.includes('</body>')) {
|
|
67
88
|
const liveReloadScript = `
|
|
68
89
|
<script>
|
|
69
90
|
(function() {
|
|
@@ -156,7 +177,7 @@ async function startDevServer(configPathOption, options = { preserve: false }) {
|
|
|
156
177
|
// Initial build
|
|
157
178
|
console.log('🚀 Performing initial build for dev server...');
|
|
158
179
|
try {
|
|
159
|
-
await buildSite(configPathOption, { isDev: true, preserve: options.preserve }); // Use the original config path option
|
|
180
|
+
await buildSite(configPathOption, { isDev: true, preserve: options.preserve, noDoubleProcessing: true }); // Use the original config path option
|
|
160
181
|
console.log('✅ Initial build complete.');
|
|
161
182
|
} catch (error) {
|
|
162
183
|
console.error('❌ Initial build failed:', error.message, error.stack);
|
|
@@ -186,14 +207,14 @@ async function startDevServer(configPathOption, options = { preserve: false }) {
|
|
|
186
207
|
}
|
|
187
208
|
|
|
188
209
|
console.log(`👀 Watching for changes in:`);
|
|
189
|
-
console.log(` - Source: ${paths.srcDirToWatch}`);
|
|
190
|
-
console.log(` - Config: ${paths.configFileToWatch}`);
|
|
210
|
+
console.log(` - Source: ${formatPathForDisplay(paths.srcDirToWatch, CWD)}`);
|
|
211
|
+
console.log(` - Config: ${formatPathForDisplay(paths.configFileToWatch, CWD)}`);
|
|
191
212
|
if (userAssetsDirExists) {
|
|
192
|
-
console.log(` - Assets: ${paths.userAssetsDir}`);
|
|
213
|
+
console.log(` - Assets: ${formatPathForDisplay(paths.userAssetsDir, CWD)}`);
|
|
193
214
|
}
|
|
194
215
|
if (process.env.DOCMD_DEV === 'true') {
|
|
195
|
-
console.log(` - docmd Templates: ${DOCMD_TEMPLATES_DIR} (internal)`);
|
|
196
|
-
console.log(` - docmd Assets: ${DOCMD_ASSETS_DIR} (internal)`);
|
|
216
|
+
console.log(` - docmd Templates: ${formatPathForDisplay(DOCMD_TEMPLATES_DIR, CWD)} (internal)`);
|
|
217
|
+
console.log(` - docmd Assets: ${formatPathForDisplay(DOCMD_ASSETS_DIR, CWD)} (internal)`);
|
|
197
218
|
}
|
|
198
219
|
|
|
199
220
|
const watcher = chokidar.watch(watchedPaths, {
|
|
@@ -219,7 +240,7 @@ async function startDevServer(configPathOption, options = { preserve: false }) {
|
|
|
219
240
|
// For simplicity, we might need to restart the watcher or inform user to restart dev server if srcDir/outputDir change.
|
|
220
241
|
// For now, we'll at least update the static server path.
|
|
221
242
|
if (newPaths.outputDir !== paths.outputDir) {
|
|
222
|
-
console.log(`Output directory changed from ${paths.outputDir} to ${newPaths.outputDir}. Updating static server.`);
|
|
243
|
+
console.log(`Output directory changed from ${formatPathForDisplay(paths.outputDir, CWD)} to ${formatPathForDisplay(newPaths.outputDir, CWD)}. Updating static server.`);
|
|
223
244
|
staticMiddleware = express.static(newPaths.outputDir);
|
|
224
245
|
}
|
|
225
246
|
// If srcDirToWatch changes, chokidar won't automatically pick it up.
|
|
@@ -228,9 +249,9 @@ async function startDevServer(configPathOption, options = { preserve: false }) {
|
|
|
228
249
|
paths = newPaths; // Update paths for next build reference
|
|
229
250
|
}
|
|
230
251
|
|
|
231
|
-
await buildSite(configPathOption, { isDev: true, preserve: options.preserve }); // Re-build using the potentially updated config path
|
|
252
|
+
await buildSite(configPathOption, { isDev: true, preserve: options.preserve, noDoubleProcessing: true }); // Re-build using the potentially updated config path
|
|
232
253
|
broadcastReload();
|
|
233
|
-
console.log('✅ Rebuild complete.
|
|
254
|
+
console.log('✅ Rebuild complete.');
|
|
234
255
|
} catch (error) {
|
|
235
256
|
console.error('❌ Rebuild failed:', error.message, error.stack);
|
|
236
257
|
}
|
|
@@ -238,19 +259,40 @@ async function startDevServer(configPathOption, options = { preserve: false }) {
|
|
|
238
259
|
|
|
239
260
|
watcher.on('error', error => console.error(`Watcher error: ${error}`));
|
|
240
261
|
|
|
262
|
+
// Try different ports if the default port is in use
|
|
241
263
|
const PORT = process.env.PORT || 3000;
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
264
|
+
const MAX_PORT_ATTEMPTS = 10;
|
|
265
|
+
let currentPort = PORT;
|
|
266
|
+
|
|
267
|
+
// Function to try starting the server on different ports
|
|
268
|
+
function tryStartServer(port, attempt = 1) {
|
|
269
|
+
server.listen(port)
|
|
270
|
+
.on('listening', async () => {
|
|
271
|
+
// Check if index.html exists after initial build
|
|
272
|
+
const indexHtmlPath = path.join(paths.outputDir, 'index.html');
|
|
273
|
+
if (!await fs.pathExists(indexHtmlPath)) {
|
|
274
|
+
console.warn(`⚠️ Warning: ${formatPathForDisplay(indexHtmlPath, CWD)} not found after initial build.
|
|
275
|
+
The dev server is running, but you might see a 404 for the root page.
|
|
276
|
+
Ensure your '${config.srcDir}' directory contains an 'index.md' or your navigation points to existing files.`);
|
|
277
|
+
}
|
|
278
|
+
console.log(`🎉 Dev server started at http://localhost:${port}`);
|
|
279
|
+
console.log(`Serving content from: ${formatPathForDisplay(paths.outputDir, CWD)}`);
|
|
280
|
+
console.log(`Live reload is active. Browser will refresh automatically when files change.`);
|
|
281
|
+
})
|
|
282
|
+
.on('error', (err) => {
|
|
283
|
+
if (err.code === 'EADDRINUSE' && attempt < MAX_PORT_ATTEMPTS) {
|
|
284
|
+
console.log(`Port ${port} is in use, trying port ${port + 1}...`);
|
|
285
|
+
server.close();
|
|
286
|
+
tryStartServer(port + 1, attempt + 1);
|
|
287
|
+
} else {
|
|
288
|
+
console.error(`Failed to start server: ${err.message}`);
|
|
289
|
+
process.exit(1);
|
|
290
|
+
}
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// Start the server with port fallback
|
|
295
|
+
tryStartServer(currentPort);
|
|
254
296
|
|
|
255
297
|
// Graceful shutdown
|
|
256
298
|
process.on('SIGINT', () => {
|
|
@@ -5,6 +5,21 @@ const matter = require('gray-matter');
|
|
|
5
5
|
const hljs = require('highlight.js');
|
|
6
6
|
const container = require('markdown-it-container');
|
|
7
7
|
const attrs = require('markdown-it-attrs');
|
|
8
|
+
const path = require('path'); // Add path module for findMarkdownFiles
|
|
9
|
+
|
|
10
|
+
// Function to format paths for display (relative to CWD)
|
|
11
|
+
function formatPathForDisplay(absolutePath) {
|
|
12
|
+
const CWD = process.cwd();
|
|
13
|
+
const relativePath = path.relative(CWD, absolutePath);
|
|
14
|
+
|
|
15
|
+
// If it's not a subdirectory, prefix with ./ for clarity
|
|
16
|
+
if (!relativePath.startsWith('..') && !path.isAbsolute(relativePath)) {
|
|
17
|
+
return `./${relativePath}`;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Return the relative path
|
|
21
|
+
return relativePath;
|
|
22
|
+
}
|
|
8
23
|
|
|
9
24
|
const md = new MarkdownIt({
|
|
10
25
|
html: true,
|
|
@@ -335,7 +350,7 @@ function extractHeadingsFromHtml(htmlContent) {
|
|
|
335
350
|
return headings;
|
|
336
351
|
}
|
|
337
352
|
|
|
338
|
-
async function processMarkdownFile(filePath) {
|
|
353
|
+
async function processMarkdownFile(filePath, options = { isDev: false }) {
|
|
339
354
|
const rawContent = await fs.readFile(filePath, 'utf8');
|
|
340
355
|
let frontmatter, markdownContent;
|
|
341
356
|
|
|
@@ -346,21 +361,43 @@ async function processMarkdownFile(filePath) {
|
|
|
346
361
|
} catch (e) {
|
|
347
362
|
if (e.name === 'YAMLException') {
|
|
348
363
|
// Provide more specific error for YAML parsing issues
|
|
349
|
-
const errorMessage = `Error parsing YAML frontmatter in ${filePath}: ${e.reason || e.message}${e.mark ? ` at line ${e.mark.line + 1}, column ${e.mark.column + 1}` : ''}. Please check the syntax.`;
|
|
364
|
+
const errorMessage = `Error parsing YAML frontmatter in ${formatPathForDisplay(filePath)}: ${e.reason || e.message}${e.mark ? ` at line ${e.mark.line + 1}, column ${e.mark.column + 1}` : ''}. Please check the syntax.`;
|
|
350
365
|
console.error(`❌ ${errorMessage}`);
|
|
351
366
|
throw new Error(errorMessage); // Propagate error to stop build/dev
|
|
352
367
|
}
|
|
353
368
|
// For other errors from gray-matter or unknown errors
|
|
354
|
-
console.error(`❌ Error processing frontmatter in ${filePath}: ${e.message}`);
|
|
369
|
+
console.error(`❌ Error processing frontmatter in ${formatPathForDisplay(filePath)}: ${e.message}`);
|
|
355
370
|
throw e;
|
|
356
371
|
}
|
|
357
372
|
|
|
358
373
|
if (!frontmatter.title) {
|
|
359
|
-
console.warn(`⚠️ Warning: Markdown file ${filePath} is missing a 'title' in its frontmatter. Using filename as fallback.`);
|
|
374
|
+
console.warn(`⚠️ Warning: Markdown file ${formatPathForDisplay(filePath)} is missing a 'title' in its frontmatter. Using filename as fallback.`);
|
|
360
375
|
// Fallback title, or you could make it an error
|
|
361
376
|
// frontmatter.title = path.basename(filePath, path.extname(filePath));
|
|
362
377
|
}
|
|
363
378
|
|
|
379
|
+
// Special handling for no-style pages with HTML content
|
|
380
|
+
if (frontmatter.noStyle === true) {
|
|
381
|
+
// Only log when not in dev mode to reduce console output during dev
|
|
382
|
+
if (!options.isDev) {
|
|
383
|
+
console.log(`📄 Processing no-style page: ${formatPathForDisplay(filePath)} - Using raw HTML content`);
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
// For no-style pages, we'll use the raw content directly
|
|
387
|
+
// No markdown processing, no HTML escaping
|
|
388
|
+
const htmlContent = markdownContent;
|
|
389
|
+
|
|
390
|
+
// Extract headings for table of contents (if needed)
|
|
391
|
+
const headings = extractHeadingsFromHtml(htmlContent);
|
|
392
|
+
|
|
393
|
+
return {
|
|
394
|
+
frontmatter,
|
|
395
|
+
htmlContent,
|
|
396
|
+
headings,
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
// Regular processing for standard pages
|
|
364
401
|
// Check if this is a documentation example showing how to use containers
|
|
365
402
|
const isContainerDocumentation = markdownContent.includes('containerName [optionalTitleOrType]') ||
|
|
366
403
|
markdownContent.includes('## Callouts') ||
|
|
@@ -413,4 +450,29 @@ async function processMarkdownFile(filePath) {
|
|
|
413
450
|
};
|
|
414
451
|
}
|
|
415
452
|
|
|
416
|
-
|
|
453
|
+
// Add findMarkdownFiles function
|
|
454
|
+
/**
|
|
455
|
+
* Recursively finds all Markdown files in a directory and its subdirectories
|
|
456
|
+
* @param {string} dir - Directory to search in
|
|
457
|
+
* @returns {Promise<string[]>} - Array of file paths
|
|
458
|
+
*/
|
|
459
|
+
async function findMarkdownFiles(dir) {
|
|
460
|
+
let files = [];
|
|
461
|
+
const items = await fs.readdir(dir, { withFileTypes: true });
|
|
462
|
+
for (const item of items) {
|
|
463
|
+
const fullPath = path.join(dir, item.name);
|
|
464
|
+
if (item.isDirectory()) {
|
|
465
|
+
files = files.concat(await findMarkdownFiles(fullPath));
|
|
466
|
+
} else if (item.isFile() && (item.name.endsWith('.md') || item.name.endsWith('.markdown'))) {
|
|
467
|
+
files.push(fullPath);
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
return files;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
module.exports = {
|
|
474
|
+
processMarkdownFile,
|
|
475
|
+
mdInstance: md,
|
|
476
|
+
extractHeadingsFromHtml,
|
|
477
|
+
findMarkdownFiles // Export the findMarkdownFiles function
|
|
478
|
+
};
|
|
@@ -18,7 +18,7 @@ async function processPluginHooks(config, pageData, relativePathToRoot) {
|
|
|
18
18
|
// 1. Favicon (built-in handling)
|
|
19
19
|
if (config.favicon) {
|
|
20
20
|
const faviconPath = config.favicon.startsWith('/') ? config.favicon.substring(1) : config.favicon;
|
|
21
|
-
faviconLinkHtml =
|
|
21
|
+
faviconLinkHtml = `<link rel="shortcut icon" href="${relativePathToRoot}${faviconPath}" type="image/x-icon">\n`;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
// 2. Theme CSS (built-in handling for theme.name)
|
|
@@ -75,9 +75,21 @@ async function generateHtmlPage(templateData) {
|
|
|
75
75
|
footerHtml = mdInstance.renderInline(config.footer);
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
-
|
|
78
|
+
// Determine which template to use based on frontmatter
|
|
79
|
+
let templateName = 'layout.ejs';
|
|
80
|
+
if (frontmatter.noStyle === true) {
|
|
81
|
+
templateName = 'no-style.ejs';
|
|
82
|
+
|
|
83
|
+
// For no-style pages, ensure we're passing the raw HTML content
|
|
84
|
+
// without any additional processing or escaping
|
|
85
|
+
if (content.includes('<') || content.includes('>')) {
|
|
86
|
+
console.warn(`⚠️ Warning: HTML content in no-style page appears to be escaped. This may cause rendering issues.`);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const layoutTemplatePath = path.join(__dirname, '..', 'templates', templateName);
|
|
79
91
|
if (!await fs.pathExists(layoutTemplatePath)) {
|
|
80
|
-
throw new Error(`
|
|
92
|
+
throw new Error(`Template not found: ${layoutTemplatePath}`);
|
|
81
93
|
}
|
|
82
94
|
const layoutTemplate = await fs.readFile(layoutTemplatePath, 'utf8');
|
|
83
95
|
|
|
@@ -105,6 +117,7 @@ async function generateHtmlPage(templateData) {
|
|
|
105
117
|
currentPagePath, // Pass the current page path for active state detection
|
|
106
118
|
headings: headings || [], // Pass headings for TOC, default to empty array if not provided
|
|
107
119
|
isActivePage, // Flag to determine if TOC should be shown
|
|
120
|
+
frontmatter, // Pass the entire frontmatter for no-style template
|
|
108
121
|
...pluginOutputs, // Spread all plugin generated HTML strings
|
|
109
122
|
};
|
|
110
123
|
|
package/src/plugins/sitemap.js
CHANGED
|
@@ -1,6 +1,20 @@
|
|
|
1
1
|
const fs = require('fs-extra');
|
|
2
2
|
const path = require('path');
|
|
3
3
|
|
|
4
|
+
// Function to format paths for display (relative to CWD)
|
|
5
|
+
function formatPathForDisplay(absolutePath) {
|
|
6
|
+
const CWD = process.cwd();
|
|
7
|
+
const relativePath = path.relative(CWD, absolutePath);
|
|
8
|
+
|
|
9
|
+
// If it's not a subdirectory, prefix with ./ for clarity
|
|
10
|
+
if (!relativePath.startsWith('..') && !path.isAbsolute(relativePath)) {
|
|
11
|
+
return `./${relativePath}`;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// Return the relative path
|
|
15
|
+
return relativePath;
|
|
16
|
+
}
|
|
17
|
+
|
|
4
18
|
/**
|
|
5
19
|
* Generate sitemap.xml in the output directory root
|
|
6
20
|
* @param {Object} config - The full configuration object
|
|
@@ -100,7 +114,7 @@ async function generateSitemap(config, pages, outputDir, options = { isDev: fals
|
|
|
100
114
|
|
|
101
115
|
// Only show sitemap generation message in production mode or if DOCMD_DEV is true
|
|
102
116
|
if (!options.isDev || process.env.DOCMD_DEV === 'true') {
|
|
103
|
-
console.log(`✅ Generated sitemap at ${sitemapPath}`);
|
|
117
|
+
console.log(`✅ Generated sitemap at ${formatPathForDisplay(sitemapPath)}`);
|
|
104
118
|
}
|
|
105
119
|
}
|
|
106
120
|
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
|
|
7
|
+
<% if (frontmatter.components?.meta !== false) { %>
|
|
8
|
+
<%- metaTagsHtml || '' %>
|
|
9
|
+
<title><%= pageTitle %><% if (frontmatter.components?.siteTitle !== false) { %> | <%= siteTitle %><% } %></title>
|
|
10
|
+
<% if (description && !(metaTagsHtml && metaTagsHtml.includes('name="description"'))) { %>
|
|
11
|
+
<meta name="description" content="<%= description %>">
|
|
12
|
+
<% } %>
|
|
13
|
+
<% } %>
|
|
14
|
+
|
|
15
|
+
<% if (frontmatter.components?.favicon !== false) { %>
|
|
16
|
+
<%- faviconLinkHtml || '' %>
|
|
17
|
+
<% } %>
|
|
18
|
+
|
|
19
|
+
<% if (frontmatter.components?.css !== false) { %>
|
|
20
|
+
<link rel="stylesheet" href="<%= relativePathToRoot %>assets/css/docmd-main.css">
|
|
21
|
+
<% if (frontmatter.components?.highlight !== false) { %>
|
|
22
|
+
<link rel="stylesheet" href="<%= relativePathToRoot %>assets/css/docmd-highlight-<%= defaultMode === 'dark' ? 'dark' : 'light' %>.css" id="highlight-theme">
|
|
23
|
+
<% } %>
|
|
24
|
+
<% } %>
|
|
25
|
+
|
|
26
|
+
<% if (frontmatter.components?.theme !== false) { %>
|
|
27
|
+
<%- themeCssLinkHtml || '' %>
|
|
28
|
+
<% } %>
|
|
29
|
+
|
|
30
|
+
<% if (frontmatter.components?.customCss !== false && customCssFiles && customCssFiles.length > 0) { %>
|
|
31
|
+
<% customCssFiles.forEach(cssFile => { %>
|
|
32
|
+
<link rel="stylesheet" href="<%= relativePathToRoot %><%- cssFile.startsWith('/') ? cssFile.substring(1) : cssFile %>">
|
|
33
|
+
<% }); %>
|
|
34
|
+
<% } %>
|
|
35
|
+
|
|
36
|
+
<% if (frontmatter.components?.pluginStyles !== false) { %>
|
|
37
|
+
<%- pluginStylesHtml || '' %>
|
|
38
|
+
<% } %>
|
|
39
|
+
|
|
40
|
+
<% if (frontmatter.components?.pluginHeadScripts !== false) { %>
|
|
41
|
+
<%- pluginHeadScriptsHtml || '' %>
|
|
42
|
+
<% } %>
|
|
43
|
+
|
|
44
|
+
<% if (frontmatter.customHead) { %>
|
|
45
|
+
<%- frontmatter.customHead %>
|
|
46
|
+
<% } %>
|
|
47
|
+
</head>
|
|
48
|
+
<body<% if (frontmatter.components?.theme !== false) { %> data-theme="<%= defaultMode %>"<% } %><% if (frontmatter.bodyClass) { %> class="<%= frontmatter.bodyClass %>"<% } %>>
|
|
49
|
+
<% if (frontmatter.components?.layout === true || frontmatter.components?.layout === 'full') { %>
|
|
50
|
+
<div class="main-content-wrapper">
|
|
51
|
+
<% if (frontmatter.components?.header !== false) { %>
|
|
52
|
+
<header class="page-header">
|
|
53
|
+
<% if (frontmatter.components?.pageTitle !== false) { %>
|
|
54
|
+
<h1><%= pageTitle %></h1>
|
|
55
|
+
<% } %>
|
|
56
|
+
</header>
|
|
57
|
+
<% } %>
|
|
58
|
+
<main class="content-area">
|
|
59
|
+
<div class="content-layout">
|
|
60
|
+
<div class="main-content">
|
|
61
|
+
<%- content %>
|
|
62
|
+
</div>
|
|
63
|
+
</div>
|
|
64
|
+
</main>
|
|
65
|
+
<% if (frontmatter.components?.footer !== false) { %>
|
|
66
|
+
<footer class="page-footer">
|
|
67
|
+
<div class="footer-content">
|
|
68
|
+
<div class="user-footer">
|
|
69
|
+
<%- footerHtml || '' %>
|
|
70
|
+
</div>
|
|
71
|
+
<% if (frontmatter.components?.branding !== false) { %>
|
|
72
|
+
<div class="branding-footer">
|
|
73
|
+
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>
|
|
74
|
+
</div>
|
|
75
|
+
<% } %>
|
|
76
|
+
</div>
|
|
77
|
+
</footer>
|
|
78
|
+
<% } %>
|
|
79
|
+
</div>
|
|
80
|
+
<% } else if (frontmatter.components?.sidebar === true) { %>
|
|
81
|
+
<aside class="sidebar">
|
|
82
|
+
<% if (frontmatter.components?.logo !== false && logo && logo.light && logo.dark) { %>
|
|
83
|
+
<div class="sidebar-header">
|
|
84
|
+
<a href="<%= logo.href || (relativePathToRoot + 'index.html') %>" class="logo-link">
|
|
85
|
+
<img src="<%= relativePathToRoot %><%- logo.light.startsWith('/') ? logo.light.substring(1) : logo.light %>" alt="<%= logo.alt || siteTitle %>" class="logo-light" <% if (logo.height) { %>style="height: <%= logo.height %>;"<% } %>>
|
|
86
|
+
<img src="<%= relativePathToRoot %><%- logo.dark.startsWith('/') ? logo.dark.substring(1) : logo.dark %>" alt="<%= logo.alt || siteTitle %>" class="logo-dark" <% if (logo.height) { %>style="height: <%= logo.height %>;"<% } %>>
|
|
87
|
+
</a>
|
|
88
|
+
</div>
|
|
89
|
+
<% } %>
|
|
90
|
+
<% if (frontmatter.components?.navigation !== false) { %>
|
|
91
|
+
<%- navigationHtml %>
|
|
92
|
+
<% } %>
|
|
93
|
+
<% if (frontmatter.components?.themeToggle !== false && theme && theme.enableModeToggle) { %>
|
|
94
|
+
<button id="theme-toggle-button" aria-label="Toggle theme" class="theme-toggle-button">
|
|
95
|
+
<%- renderIcon('sun', { class: 'icon-sun' }) %>
|
|
96
|
+
<%- renderIcon('moon', { class: 'icon-moon' }) %>
|
|
97
|
+
</button>
|
|
98
|
+
<% } %>
|
|
99
|
+
</aside>
|
|
100
|
+
<div class="main-content-wrapper">
|
|
101
|
+
<% if (frontmatter.components?.header !== false) { %>
|
|
102
|
+
<header class="page-header">
|
|
103
|
+
<% if (frontmatter.components?.pageTitle !== false) { %>
|
|
104
|
+
<h1><%= pageTitle %></h1>
|
|
105
|
+
<% } %>
|
|
106
|
+
</header>
|
|
107
|
+
<% } %>
|
|
108
|
+
<main class="content-area">
|
|
109
|
+
<div class="content-layout">
|
|
110
|
+
<div class="main-content">
|
|
111
|
+
<%- content %>
|
|
112
|
+
</div>
|
|
113
|
+
<% if (frontmatter.components?.toc !== false && headings && headings.length > 0) { %>
|
|
114
|
+
<div class="toc-sidebar">
|
|
115
|
+
<%- include('toc', { content, headings, navigationHtml, isActivePage }) %>
|
|
116
|
+
</div>
|
|
117
|
+
<% } %>
|
|
118
|
+
</div>
|
|
119
|
+
</main>
|
|
120
|
+
<% if (frontmatter.components?.footer !== false) { %>
|
|
121
|
+
<footer class="page-footer">
|
|
122
|
+
<div class="footer-content">
|
|
123
|
+
<div class="user-footer">
|
|
124
|
+
<%- footerHtml || '' %>
|
|
125
|
+
</div>
|
|
126
|
+
<% if (frontmatter.components?.branding !== false) { %>
|
|
127
|
+
<div class="branding-footer">
|
|
128
|
+
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>
|
|
129
|
+
</div>
|
|
130
|
+
<% } %>
|
|
131
|
+
</div>
|
|
132
|
+
</footer>
|
|
133
|
+
<% } %>
|
|
134
|
+
</div>
|
|
135
|
+
<% } else { %>
|
|
136
|
+
<%- content %>
|
|
137
|
+
<% } %>
|
|
138
|
+
|
|
139
|
+
<% if (frontmatter.components?.scripts !== false) { %>
|
|
140
|
+
<% if (frontmatter.components?.themeToggle !== false) { %>
|
|
141
|
+
<script src="<%= relativePathToRoot %>assets/js/docmd-theme-toggle.js"></script>
|
|
142
|
+
<% } %>
|
|
143
|
+
|
|
144
|
+
<% if (frontmatter.components?.customJs !== false && customJsFiles && customJsFiles.length > 0) { %>
|
|
145
|
+
<% customJsFiles.forEach(jsFile => { %>
|
|
146
|
+
<script src="<%= relativePathToRoot %><%- jsFile.startsWith('/') ? jsFile.substring(1) : jsFile %>"></script>
|
|
147
|
+
<% }); %>
|
|
148
|
+
<% } %>
|
|
149
|
+
|
|
150
|
+
<% if (frontmatter.components?.pluginBodyScripts !== false) { %>
|
|
151
|
+
<%- pluginBodyScriptsHtml || '' %>
|
|
152
|
+
<% } %>
|
|
153
|
+
<% } %>
|
|
154
|
+
|
|
155
|
+
<% if (frontmatter.customScripts) { %>
|
|
156
|
+
<%- frontmatter.customScripts %>
|
|
157
|
+
<% } %>
|
|
158
|
+
</body>
|
|
159
|
+
</html>
|