mdv-live 0.4.5 → 0.5.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/CHANGELOG.md CHANGED
@@ -5,6 +5,14 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.5.1] - 2026-03-20
9
+
10
+ ### Fixed
11
+
12
+ - Edit mode + PDF export bug: exporting PDF while in edit mode produced raw markdown text instead of rendered slides
13
+ - Now auto-exits edit mode before PDF generation
14
+ - Uses `tab.isMarp` fallback for Marp detection when DOM is not yet rendered
15
+
8
16
  ## [0.4.3] - 2026-02-15
9
17
 
10
18
  ### Fixed
package/bin/mdv.js CHANGED
@@ -453,7 +453,7 @@ async function main() {
453
453
  }
454
454
 
455
455
  if (values.version) {
456
- console.log('mdv v0.3.3');
456
+ console.log('mdv v0.5.0');
457
457
  process.exit(0);
458
458
  }
459
459
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mdv-live",
3
- "version": "0.4.5",
3
+ "version": "0.5.1",
4
4
  "description": "Markdown Viewer - File tree + Live preview + Marp support + Hot reload",
5
5
  "main": "src/server.js",
6
6
  "bin": {
package/src/api/file.js CHANGED
@@ -160,7 +160,8 @@ export function setupFileRoutes(app) {
160
160
  });
161
161
  }
162
162
 
163
- const rendered = await renderFile(fullPath);
163
+ const relativeDir = path.dirname(relativePath);
164
+ const rendered = await renderFile(fullPath, relativeDir === '.' ? '' : relativeDir);
164
165
  res.json({ name, ...rendered });
165
166
  } catch (err) {
166
167
  if (err.code === 'ENOENT') {
@@ -3,6 +3,7 @@
3
3
  */
4
4
 
5
5
  import fs from 'fs/promises';
6
+ import path from 'path';
6
7
  import { getFileType } from '../utils/fileTypes.js';
7
8
  import { renderMarkdown, isMarp } from './markdown.js';
8
9
  import { renderMarp } from './marp.js';
@@ -43,17 +44,36 @@ function renderText(content) {
43
44
  return `<pre class="plain-text">${escaped}</pre>`;
44
45
  }
45
46
 
47
+ /**
48
+ * Rewrite relative image/video/audio src paths to /raw/ URLs
49
+ * @param {string} html - Rendered HTML
50
+ * @param {string} relativeDir - Directory of the source file relative to rootDir
51
+ * @returns {string} HTML with rewritten paths
52
+ */
53
+ function rewriteMediaPaths(html, relativeDir) {
54
+ // Match src="..." that are not absolute URLs or data URIs
55
+ return html.replace(
56
+ /(<(?:img|video|audio|source)\s[^>]*?\bsrc=")([^"]+)(")/gi,
57
+ (match, before, src, after) => {
58
+ if (/^(https?:\/\/|data:|\/raw\/|\/)/.test(src)) return match;
59
+ const resolved = relativeDir ? `${relativeDir}/${src}` : src;
60
+ return `${before}/raw/${resolved}${after}`;
61
+ }
62
+ );
63
+ }
64
+
46
65
  /**
47
66
  * Render a file and return content for the frontend
48
67
  * @param {string} filePath - Full path to the file
68
+ * @param {string} [relativeDir] - Directory of the file relative to rootDir (for resolving relative paths)
49
69
  * @returns {Promise<Object>} Rendered content and metadata
50
70
  */
51
- export async function renderFile(filePath) {
71
+ export async function renderFile(filePath, relativeDir) {
52
72
  const content = await fs.readFile(filePath, 'utf-8');
53
73
  const fileType = getFileType(filePath);
54
74
 
55
75
  if (fileType.type === 'markdown') {
56
- return renderMarkdownFile(content);
76
+ return renderMarkdownFile(content, relativeDir);
57
77
  }
58
78
 
59
79
  if (fileType.type === 'code') {
@@ -74,13 +94,14 @@ export async function renderFile(filePath) {
74
94
  /**
75
95
  * Render markdown content, detecting Marp presentations
76
96
  * @param {string} content - Raw markdown content
97
+ * @param {string} [relativeDir] - Directory relative to rootDir for resolving image paths
77
98
  * @returns {Object} Rendered content and metadata
78
99
  */
79
- function renderMarkdownFile(content) {
100
+ function renderMarkdownFile(content, relativeDir) {
80
101
  if (isMarp(content)) {
81
102
  const { html, css } = renderMarp(content);
82
103
  return {
83
- content: html,
104
+ content: rewriteMediaPaths(html, relativeDir),
84
105
  css,
85
106
  raw: content,
86
107
  fileType: 'markdown',
@@ -89,7 +110,7 @@ function renderMarkdownFile(content) {
89
110
  }
90
111
 
91
112
  return {
92
- content: renderMarkdown(content),
113
+ content: rewriteMediaPaths(renderMarkdown(content), relativeDir),
93
114
  raw: content,
94
115
  fileType: 'markdown',
95
116
  isMarp: false
package/src/server.js CHANGED
@@ -17,7 +17,7 @@ import { setupWebSocket } from './websocket.js';
17
17
 
18
18
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
19
19
  const STATIC_DIR = path.join(__dirname, 'static');
20
- const VERSION = '0.3.3';
20
+ const VERSION = '0.5.0';
21
21
 
22
22
  /**
23
23
  * Setup API routes for the Express app
package/src/static/app.js CHANGED
@@ -1329,7 +1329,12 @@
1329
1329
 
1330
1330
  const tab = state.tabs[state.activeTabIndex];
1331
1331
 
1332
- if (this.isMarpPresentation()) {
1332
+ // editモード中は閉じてからPDF生成
1333
+ if (state.isEditMode) {
1334
+ await EditorManager.toggle();
1335
+ }
1336
+
1337
+ if (tab.isMarp || this.isMarpPresentation()) {
1333
1338
  await this.exportMarpPdf(tab.path);
1334
1339
  } else if (this.isHtmlPreview()) {
1335
1340
  this.printHtmlPreview(tab.name);