marp-dev-preview 0.0.2 → 0.0.4

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
@@ -10,10 +10,18 @@ The tool is mainly intended for slide deck authors who want to preview their sli
10
10
  * Automatic browser reload on file changes.
11
11
  * Custom theme support.
12
12
  * Keyboard navigation for slides.
13
- * Also installs and uses the following markdown-it plugins:
13
+ * Also installs and uses the following markdown-it plugins (it's easy to add more if needed):
14
14
  * `markdown-it-container`
15
15
  * `markdown-it-mark`
16
16
  * `markdown-it-footnote`
17
+
18
+ ## Usage via npx
19
+
20
+ The simplest way to start the previewer is via npx:
21
+
22
+ ```bash
23
+ npx marp-dev-preview --theme-dir <dir containing your themes> <your presentation>.md
24
+ ```
17
25
 
18
26
  ## Installation
19
27
 
@@ -31,16 +39,16 @@ npm install marp-dev-preview
31
39
 
32
40
  ## Usage
33
41
 
34
- To start the preview server, run the `mp` command followed by your markdown file path:
42
+ To start the preview server, run the `mdp` command followed by your markdown file path:
35
43
 
36
44
  ```bash
37
- mp <path-to-your-markdown-file.md> [options]
45
+ mdp <path-to-your-markdown-file> [options]
38
46
  ```
39
47
 
40
48
  **Example:**
41
49
 
42
50
  ```bash
43
- mp my-slides/presentation.md --port 3000 --theme-dir my-themes
51
+ mdp my-slides/presentation.md --port 3000 --theme-dir my-themes
44
52
  ```
45
53
 
46
54
  ### Options
@@ -57,13 +65,21 @@ While viewing the presentation in your browser, in addition to the usual browser
57
65
  * <kbd>:&lt;number&gt;</kbd>: Go to the specified slide number.
58
66
  * <kbd>?</kbd>: Toggle the help box displaying key bindings.
59
67
 
60
- ## Development
68
+ ## Integration with other tools
61
69
 
62
- If you are contributing to the development of this tool, you can run it locally using:
70
+ The tool can respond to http requests to change slides and to scroll to a slide containing a given text. Any http client can be used to send such requests, e.g.:
63
71
 
64
72
  ```bash
65
- npm run preview -- <path-to-your-markdown-file.md>
73
+ curl -X POST -H "Content-Type: application/json" -d '{"command": "find", "string": "my awesome text"}' http://localhost:8080/api/command
66
74
  ```
75
+ would scroll to the first slide containing "my awesome text".
76
+
77
+ ```bash
78
+ curl -X POST -H "Content-Type: application/json" -d '{"command": "goto", "slide": 3}' http://localhost:8080/api/command
79
+ ````
80
+
81
+ would go to slide 3.
82
+
67
83
 
68
84
  ## License
69
85
 
@@ -7,6 +7,9 @@ import chokidar from 'chokidar';
7
7
  import { WebSocketServer } from 'ws';
8
8
  import yargs from 'yargs';
9
9
  import { hideBin } from 'yargs/helpers';
10
+ import markdownItFootnote from 'markdown-it-footnote';
11
+ import markdownItMark from 'markdown-it-mark';
12
+ import markdownItContainer from 'markdown-it-container';
10
13
 
11
14
  const argv = yargs(hideBin(process.argv))
12
15
  .usage('Usage: $0 <markdown-file> [options]')
@@ -65,7 +68,11 @@ let marp;
65
68
 
66
69
  async function initializeMarp() {
67
70
  const options = { html: true, linkify: true, };
68
- marp = new Marp(options);
71
+ marp = new Marp(options)
72
+ .use(markdownItFootnote)
73
+ .use(markdownItMark)
74
+ .use(markdownItContainer, 'note');
75
+
69
76
  if (themeDir) {
70
77
  const themeFiles = await fs.readdir(themeDir);
71
78
  for (const file of themeFiles) {
@@ -130,21 +137,55 @@ async function renderMarp() {
130
137
  </style>
131
138
  <script>
132
139
  const ws = new WebSocket('ws://localhost:${port + 1}');
133
- ws.onmessage = (event) => {
134
- if (event.data === 'reload') {
135
- window.location.reload();
136
- }
137
- };
138
-
139
- let lastKey = '';
140
- let command = '';
141
- let commandMode = false;
142
140
 
143
141
  document.addEventListener('DOMContentLoaded', () => {
144
142
  const slides = Array.from(document.querySelectorAll('section[id]'));
145
143
  const commandPrompt = document.getElementById('command-prompt');
146
144
  const helpBox = document.getElementById('help-box');
147
145
 
146
+ let lastKey = '';
147
+ let command = '';
148
+ let commandMode = false;
149
+
150
+ function goToSlide(slideNumber) {
151
+ if (!isNaN(slideNumber) && slideNumber > 0 && slideNumber <= slides.length) {
152
+ slides[slideNumber - 1].scrollIntoView({ behavior: 'smooth' });
153
+ return true;
154
+ }
155
+ return false;
156
+ }
157
+
158
+ function findSlideByString(string) {
159
+ const lowerString = string.toLowerCase();
160
+ let found = false;
161
+ for (let i = 0; i < slides.length; i++) {
162
+ if (slides[i].textContent.toLowerCase().includes(lowerString)) {
163
+ slides[i].scrollIntoView({ behavior: 'smooth' });
164
+ found = true;
165
+ }
166
+ }
167
+ if (!found) {
168
+ console.error('No slide contains the string: ' + string);
169
+ }
170
+ }
171
+
172
+ ws.onmessage = (event) => {
173
+ if (event.data === 'reload') {
174
+ window.location.reload();
175
+ return;
176
+ }
177
+ try {
178
+ const data = JSON.parse(event.data);
179
+ if (data.command === 'goto' && data.slide) {
180
+ goToSlide(parseInt(data.slide, 10));
181
+ } else if (data.command === 'find' && data.string) {
182
+ findSlideByString(data.string);
183
+ }
184
+ } catch (e) {
185
+ console.error('Failed to parse WebSocket message:', e);
186
+ }
187
+ };
188
+
148
189
  function updatePrompt(text, isError = false) {
149
190
  if (commandMode) {
150
191
  commandPrompt.style.display = 'block';
@@ -160,11 +201,10 @@ async function renderMarp() {
160
201
  if (commandMode) {
161
202
  if (e.key === 'Enter') {
162
203
  const slideNumber = parseInt(command, 10);
163
- if (!isNaN(slideNumber) && slideNumber > 0 && slideNumber <= slides.length) {
164
- slides[slideNumber - 1].scrollIntoView({ behavior: 'smooth' });
204
+ if (goToSlide(slideNumber)) {
165
205
  commandMode = false;
166
206
  command = '';
167
- updatePrompt(':' + command); // Reset to normal prompt
207
+ updatePrompt(':' + command);
168
208
  } else {
169
209
  updatePrompt(\`Error: Slide not found.\`, true); // Pass message and error flag
170
210
  setTimeout(() => {
@@ -243,6 +283,24 @@ const server = http.createServer(async (req, res) => {
243
283
  const html = await renderMarp();
244
284
  res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
245
285
  res.end(html);
286
+ } else if (req.url === '/api/command' && req.method === 'POST') {
287
+ let body = '';
288
+ req.on('data', chunk => {
289
+ body += chunk.toString();
290
+ });
291
+ req.on('end', () => {
292
+ try {
293
+ const command = JSON.parse(body);
294
+ for (const ws of wss.clients) {
295
+ ws.send(JSON.stringify(command));
296
+ }
297
+ res.writeHead(200, { 'Content-Type': 'application/json' });
298
+ res.end(JSON.stringify({ status: 'ok', command }));
299
+ } catch (e) {
300
+ res.writeHead(400, { 'Content-Type': 'application/json' });
301
+ res.end(JSON.stringify({ status: 'error', message: 'Invalid JSON' }));
302
+ }
303
+ });
246
304
  } else {
247
305
  const assetPath = path.join(markdownDir, req.url);
248
306
  const ext = path.extname(assetPath);
package/package.json CHANGED
@@ -1,24 +1,28 @@
1
1
  {
2
2
  "name": "marp-dev-preview",
3
- "version": "0.0.2",
3
+ "version": "0.0.4",
4
4
  "description": "A CLI tool to preview Marp markdown files.",
5
- "main": "marp-preview.mjs",
5
+ "main": "marp-dev-preview.mjs",
6
6
  "type": "module",
7
7
  "bin": {
8
- "mp":"./marp-preview.mjs"
8
+ "mdp": "marp-dev-preview.mjs"
9
9
  },
10
10
  "scripts": {
11
- "start": "node marp-preview.mjs",
12
- "preview": "node marp-preview.mjs"
11
+ "start": "node marp-dev-preview.mjs"
13
12
  },
14
13
  "keywords": [
15
- "marp",
16
- "markdown",
17
- "preview",
18
- "cli"
19
- ],
14
+ "marp",
15
+ "markdown",
16
+ "preview",
17
+ "cli"
18
+ ],
20
19
  "author": "Roberto Esposito",
21
- "licence": "MIT",
20
+ "license": "MIT",
21
+ "repository": {
22
+ "type": "git",
23
+ "url": "git+ssh://git@github.com/boborbt/marp-dev-preview.git"
24
+ },
25
+ "bugs": "https://github.com/boborbt/marp-dev-preview/issues",
22
26
  "dependencies": {
23
27
  "@marp-team/marp-core": "^4.1.0",
24
28
  "chokidar": "^4.0.3",