marp-dev-preview 0.0.3 → 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
@@ -65,6 +65,22 @@ While viewing the presentation in your browser, in addition to the usual browser
65
65
  * <kbd>:&lt;number&gt;</kbd>: Go to the specified slide number.
66
66
  * <kbd>?</kbd>: Toggle the help box displaying key bindings.
67
67
 
68
+ ## Integration with other tools
69
+
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.:
71
+
72
+ ```bash
73
+ curl -X POST -H "Content-Type: application/json" -d '{"command": "find", "string": "my awesome text"}' http://localhost:8080/api/command
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
+
83
+
68
84
  ## License
69
85
 
70
86
  This project is licensed under the MIT License - see the `LICENSE` file for details.
@@ -137,21 +137,55 @@ async function renderMarp() {
137
137
  </style>
138
138
  <script>
139
139
  const ws = new WebSocket('ws://localhost:${port + 1}');
140
- ws.onmessage = (event) => {
141
- if (event.data === 'reload') {
142
- window.location.reload();
143
- }
144
- };
145
-
146
- let lastKey = '';
147
- let command = '';
148
- let commandMode = false;
149
140
 
150
141
  document.addEventListener('DOMContentLoaded', () => {
151
142
  const slides = Array.from(document.querySelectorAll('section[id]'));
152
143
  const commandPrompt = document.getElementById('command-prompt');
153
144
  const helpBox = document.getElementById('help-box');
154
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
+
155
189
  function updatePrompt(text, isError = false) {
156
190
  if (commandMode) {
157
191
  commandPrompt.style.display = 'block';
@@ -167,11 +201,10 @@ async function renderMarp() {
167
201
  if (commandMode) {
168
202
  if (e.key === 'Enter') {
169
203
  const slideNumber = parseInt(command, 10);
170
- if (!isNaN(slideNumber) && slideNumber > 0 && slideNumber <= slides.length) {
171
- slides[slideNumber - 1].scrollIntoView({ behavior: 'smooth' });
204
+ if (goToSlide(slideNumber)) {
172
205
  commandMode = false;
173
206
  command = '';
174
- updatePrompt(':' + command); // Reset to normal prompt
207
+ updatePrompt(':' + command);
175
208
  } else {
176
209
  updatePrompt(\`Error: Slide not found.\`, true); // Pass message and error flag
177
210
  setTimeout(() => {
@@ -250,6 +283,24 @@ const server = http.createServer(async (req, res) => {
250
283
  const html = await renderMarp();
251
284
  res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
252
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
+ });
253
304
  } else {
254
305
  const assetPath = path.join(markdownDir, req.url);
255
306
  const ext = path.extname(assetPath);
package/package.json CHANGED
@@ -1,24 +1,27 @@
1
1
  {
2
2
  "name": "marp-dev-preview",
3
- "version": "0.0.3",
3
+ "version": "0.0.4",
4
4
  "description": "A CLI tool to preview Marp markdown files.",
5
5
  "main": "marp-dev-preview.mjs",
6
6
  "type": "module",
7
7
  "bin": {
8
- "mdp":"./marp-dev-preview.mjs"
8
+ "mdp": "marp-dev-preview.mjs"
9
9
  },
10
10
  "scripts": {
11
- "start": "node marp-dev-preview.mjs"
11
+ "start": "node marp-dev-preview.mjs"
12
12
  },
13
13
  "keywords": [
14
- "marp",
15
- "markdown",
16
- "preview",
17
- "cli"
18
- ],
14
+ "marp",
15
+ "markdown",
16
+ "preview",
17
+ "cli"
18
+ ],
19
19
  "author": "Roberto Esposito",
20
20
  "license": "MIT",
21
- "repository": "git@github.com:boborbt/marp-dev-preview.git",
21
+ "repository": {
22
+ "type": "git",
23
+ "url": "git+ssh://git@github.com/boborbt/marp-dev-preview.git"
24
+ },
22
25
  "bugs": "https://github.com/boborbt/marp-dev-preview/issues",
23
26
  "dependencies": {
24
27
  "@marp-team/marp-core": "^4.1.0",