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 +16 -0
- package/marp-dev-preview.mjs +63 -12
- package/package.json +12 -9
package/README.md
CHANGED
|
@@ -65,6 +65,22 @@ While viewing the presentation in your browser, in addition to the usual browser
|
|
|
65
65
|
* <kbd>:<number></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.
|
package/marp-dev-preview.mjs
CHANGED
|
@@ -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 (
|
|
171
|
-
slides[slideNumber - 1].scrollIntoView({ behavior: 'smooth' });
|
|
204
|
+
if (goToSlide(slideNumber)) {
|
|
172
205
|
commandMode = false;
|
|
173
206
|
command = '';
|
|
174
|
-
updatePrompt(':' + command);
|
|
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
|
+
"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
|
-
|
|
8
|
+
"mdp": "marp-dev-preview.mjs"
|
|
9
9
|
},
|
|
10
10
|
"scripts": {
|
|
11
|
-
|
|
11
|
+
"start": "node marp-dev-preview.mjs"
|
|
12
12
|
},
|
|
13
13
|
"keywords": [
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
14
|
+
"marp",
|
|
15
|
+
"markdown",
|
|
16
|
+
"preview",
|
|
17
|
+
"cli"
|
|
18
|
+
],
|
|
19
19
|
"author": "Roberto Esposito",
|
|
20
20
|
"license": "MIT",
|
|
21
|
-
"repository":
|
|
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",
|