markdown-slides-cli 1.0.0
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 +440 -0
- package/index.js +504 -0
- package/package.json +35 -0
- package/slides/NOTES.md +76 -0
- package/slides/ai-agents.md +79 -0
- package/slides/icEngines.md +162 -0
- package/slides/numbers.md +333 -0
package/index.js
ADDED
|
@@ -0,0 +1,504 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* markdown-slides CLI
|
|
4
|
+
* Interactive markdown slide viewer with Monaco editor and thumbnail minimap
|
|
5
|
+
*/
|
|
6
|
+
const { program } = require('commander');
|
|
7
|
+
const fs = require('fs');
|
|
8
|
+
const path = require('path');
|
|
9
|
+
const http = require('http');
|
|
10
|
+
const { exec } = require('child_process');
|
|
11
|
+
|
|
12
|
+
program
|
|
13
|
+
.name('markdown-slides')
|
|
14
|
+
.description('Interactive markdown slide presentation with live editing')
|
|
15
|
+
.requiredOption('-f, --file <path>', 'markdown file with slides')
|
|
16
|
+
.option('-p, --port <number>', 'server port', '3457')
|
|
17
|
+
.option('-t, --title <title>', 'presentation title', 'Markdown Slides')
|
|
18
|
+
.option('--theme <theme>', 'slide theme: dark, light, blue', 'dark')
|
|
19
|
+
.parse();
|
|
20
|
+
|
|
21
|
+
const opts = program.opts();
|
|
22
|
+
|
|
23
|
+
// Validate markdown file
|
|
24
|
+
if (!fs.existsSync(opts.file)) {
|
|
25
|
+
console.error(`Error: File not found: ${opts.file}`);
|
|
26
|
+
process.exit(1);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const markdownContent = fs.readFileSync(opts.file, 'utf-8');
|
|
30
|
+
const fileName = path.basename(opts.file);
|
|
31
|
+
|
|
32
|
+
console.log(`\nπ Markdown Slides Viewer`);
|
|
33
|
+
console.log(`File: ${fileName}`);
|
|
34
|
+
console.log(`\nπ Starting server on http://localhost:${opts.port}`);
|
|
35
|
+
|
|
36
|
+
const html = `<!DOCTYPE html>
|
|
37
|
+
<html lang="en" class="dark">
|
|
38
|
+
<head>
|
|
39
|
+
<meta charset="UTF-8">
|
|
40
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
41
|
+
<title>${opts.title}</title>
|
|
42
|
+
<script src="https://cdn.tailwindcss.com"></script>
|
|
43
|
+
<link rel="icon" type="image/x-icon" href="https://mohan-chinnappan-n5.github.io/dfv/img/mc_favIcon.ico" />
|
|
44
|
+
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
|
|
45
|
+
<script src="https://cdn.jsdelivr.net/npm/monaco-editor@0.44.0/min/vs/loader.js"></script>
|
|
46
|
+
<script>
|
|
47
|
+
tailwind.config = { darkMode: 'class' }
|
|
48
|
+
</script>
|
|
49
|
+
<style>
|
|
50
|
+
.slide {
|
|
51
|
+
display: none;
|
|
52
|
+
height: 100%;
|
|
53
|
+
overflow: auto;
|
|
54
|
+
padding: 3rem;
|
|
55
|
+
}
|
|
56
|
+
.slide.active { display: block; }
|
|
57
|
+
|
|
58
|
+
.slide h1 { font-size: 2.5rem; font-weight: bold; margin-bottom: 1.5rem; }
|
|
59
|
+
.slide h2 { font-size: 2rem; font-weight: bold; margin: 1.5rem 0 1rem; }
|
|
60
|
+
.slide h3 { font-size: 1.5rem; font-weight: bold; margin: 1rem 0 0.5rem; }
|
|
61
|
+
.slide p { margin: 1rem 0; line-height: 1.8; }
|
|
62
|
+
.slide ul, .slide ol { margin: 1rem 0 1rem 2rem; line-height: 2; }
|
|
63
|
+
.slide li { margin: 0.5rem 0; }
|
|
64
|
+
.slide code {
|
|
65
|
+
background: rgba(0,0,0,0.3);
|
|
66
|
+
padding: 0.2rem 0.5rem;
|
|
67
|
+
border-radius: 0.25rem;
|
|
68
|
+
font-family: monospace;
|
|
69
|
+
}
|
|
70
|
+
.slide pre {
|
|
71
|
+
background: rgba(0,0,0,0.4);
|
|
72
|
+
padding: 1rem;
|
|
73
|
+
border-radius: 0.5rem;
|
|
74
|
+
overflow-x: auto;
|
|
75
|
+
margin: 1rem 0;
|
|
76
|
+
}
|
|
77
|
+
.slide pre code {
|
|
78
|
+
background: none;
|
|
79
|
+
padding: 0;
|
|
80
|
+
}
|
|
81
|
+
.slide blockquote {
|
|
82
|
+
border-left: 4px solid #3b82f6;
|
|
83
|
+
padding-left: 1rem;
|
|
84
|
+
margin: 1rem 0;
|
|
85
|
+
font-style: italic;
|
|
86
|
+
opacity: 0.9;
|
|
87
|
+
}
|
|
88
|
+
.slide img {
|
|
89
|
+
max-width: 100%;
|
|
90
|
+
height: auto;
|
|
91
|
+
border-radius: 0.5rem;
|
|
92
|
+
margin: 1rem 0;
|
|
93
|
+
}
|
|
94
|
+
.slide table {
|
|
95
|
+
width: 100%;
|
|
96
|
+
border-collapse: collapse;
|
|
97
|
+
margin: 1rem 0;
|
|
98
|
+
}
|
|
99
|
+
.slide th, .slide td {
|
|
100
|
+
border: 1px solid rgba(255,255,255,0.2);
|
|
101
|
+
padding: 0.75rem;
|
|
102
|
+
text-align: left;
|
|
103
|
+
}
|
|
104
|
+
.slide th {
|
|
105
|
+
background: rgba(59, 130, 246, 0.2);
|
|
106
|
+
font-weight: bold;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
.thumbnail {
|
|
110
|
+
cursor: pointer;
|
|
111
|
+
transition: all 0.2s;
|
|
112
|
+
border: 2px solid transparent;
|
|
113
|
+
}
|
|
114
|
+
.thumbnail:hover {
|
|
115
|
+
transform: scale(1.05);
|
|
116
|
+
border-color: rgba(59, 130, 246, 0.5);
|
|
117
|
+
}
|
|
118
|
+
.thumbnail.active {
|
|
119
|
+
border-color: #3b82f6;
|
|
120
|
+
box-shadow: 0 0 20px rgba(59, 130, 246, 0.5);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
.control-btn {
|
|
124
|
+
background: linear-gradient(135deg, rgba(59, 130, 246, 0.15) 0%, rgba(147, 51, 234, 0.15) 100%);
|
|
125
|
+
border: 1px solid rgba(255, 255, 255, 0.2);
|
|
126
|
+
padding: 0.75rem 1.5rem;
|
|
127
|
+
border-radius: 0.75rem;
|
|
128
|
+
font-weight: 600;
|
|
129
|
+
cursor: pointer;
|
|
130
|
+
transition: all 0.3s ease;
|
|
131
|
+
display: inline-flex;
|
|
132
|
+
align-items: center;
|
|
133
|
+
gap: 0.5rem;
|
|
134
|
+
backdrop-filter: blur(10px);
|
|
135
|
+
}
|
|
136
|
+
.control-btn:hover {
|
|
137
|
+
background: linear-gradient(135deg, rgba(59, 130, 246, 0.25) 0%, rgba(147, 51, 234, 0.25) 100%);
|
|
138
|
+
transform: translateY(-2px);
|
|
139
|
+
box-shadow: 0 4px 12px rgba(59, 130, 246, 0.4);
|
|
140
|
+
}
|
|
141
|
+
.control-btn svg { width: 20px; height: 20px; }
|
|
142
|
+
|
|
143
|
+
#editorContainer {
|
|
144
|
+
display: none;
|
|
145
|
+
position: fixed;
|
|
146
|
+
top: 0;
|
|
147
|
+
left: 0;
|
|
148
|
+
right: 0;
|
|
149
|
+
bottom: 0;
|
|
150
|
+
z-index: 100;
|
|
151
|
+
background: rgba(0, 0, 0, 0.95);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
#minimapPanel {
|
|
155
|
+
max-height: calc(100vh - 200px);
|
|
156
|
+
overflow-y: auto;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
::-webkit-scrollbar {
|
|
160
|
+
width: 8px;
|
|
161
|
+
height: 8px;
|
|
162
|
+
}
|
|
163
|
+
::-webkit-scrollbar-track {
|
|
164
|
+
background: rgba(255, 255, 255, 0.05);
|
|
165
|
+
}
|
|
166
|
+
::-webkit-scrollbar-thumb {
|
|
167
|
+
background: rgba(255, 255, 255, 0.2);
|
|
168
|
+
border-radius: 4px;
|
|
169
|
+
}
|
|
170
|
+
::-webkit-scrollbar-thumb:hover {
|
|
171
|
+
background: rgba(255, 255, 255, 0.3);
|
|
172
|
+
}
|
|
173
|
+
</style>
|
|
174
|
+
</head>
|
|
175
|
+
<body class="bg-gray-900 text-gray-100 min-h-screen">
|
|
176
|
+
|
|
177
|
+
<!-- Header -->
|
|
178
|
+
<header class="bg-gray-800 border-b border-gray-700 sticky top-0 z-50" id="mainHeader">
|
|
179
|
+
<div class="max-w-7xl mx-auto px-6 py-4">
|
|
180
|
+
<div class="flex justify-between items-center">
|
|
181
|
+
<div class="flex items-center gap-4">
|
|
182
|
+
<div class="text-3xl">π</div>
|
|
183
|
+
<div>
|
|
184
|
+
<h1 class="text-2xl font-bold">${opts.title}</h1>
|
|
185
|
+
<p class="text-sm text-gray-400" id="slideCounter">Slide 1 of 1</p>
|
|
186
|
+
</div>
|
|
187
|
+
</div>
|
|
188
|
+
|
|
189
|
+
<div class="flex items-center gap-3">
|
|
190
|
+
<button onclick="toggleMinimap()" class="control-btn">
|
|
191
|
+
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
192
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2V6zM14 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2V6zM4 16a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2v-2zM14 16a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2v-2z"/>
|
|
193
|
+
</svg>
|
|
194
|
+
Minimap
|
|
195
|
+
</button>
|
|
196
|
+
|
|
197
|
+
<button onclick="openEditor()" class="control-btn">
|
|
198
|
+
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
199
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"/>
|
|
200
|
+
</svg>
|
|
201
|
+
Edit
|
|
202
|
+
</button>
|
|
203
|
+
|
|
204
|
+
<button onclick="toggleFullscreen()" class="control-btn">
|
|
205
|
+
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
206
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 8V4m0 0h4M4 4l5 5m11-1V4m0 0h-4m4 0l-5 5M4 16v4m0 0h4m-4 0l5-5m11 5l-5-5m5 5v-4m0 4h-4"/>
|
|
207
|
+
</svg>
|
|
208
|
+
Fullscreen
|
|
209
|
+
</button>
|
|
210
|
+
</div>
|
|
211
|
+
</div>
|
|
212
|
+
</div>
|
|
213
|
+
</header>
|
|
214
|
+
|
|
215
|
+
<!-- Main Content -->
|
|
216
|
+
<main class="relative">
|
|
217
|
+
<div class="flex">
|
|
218
|
+
<!-- Slides Container -->
|
|
219
|
+
<div id="slidesContainer" class="flex-1" style="height: calc(100vh - 80px);">
|
|
220
|
+
<div id="slides" class="h-full"></div>
|
|
221
|
+
</div>
|
|
222
|
+
|
|
223
|
+
<!-- Minimap Panel -->
|
|
224
|
+
<aside id="minimapPanel" class="w-80 bg-gray-800 border-l border-gray-700 p-4 hidden">
|
|
225
|
+
<h3 class="text-lg font-bold mb-4">Slides Overview</h3>
|
|
226
|
+
<div id="minimapContent" class="space-y-3"></div>
|
|
227
|
+
</aside>
|
|
228
|
+
</div>
|
|
229
|
+
|
|
230
|
+
<!-- Navigation Controls -->
|
|
231
|
+
<div class="fixed bottom-6 left-1/2 transform -translate-x-1/2 flex gap-3 z-40" id="navControls">
|
|
232
|
+
<button onclick="prevSlide()" class="control-btn">
|
|
233
|
+
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
234
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7"/>
|
|
235
|
+
</svg>
|
|
236
|
+
Previous
|
|
237
|
+
</button>
|
|
238
|
+
|
|
239
|
+
<button onclick="nextSlide()" class="control-btn">
|
|
240
|
+
Next
|
|
241
|
+
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
242
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"/>
|
|
243
|
+
</svg>
|
|
244
|
+
</button>
|
|
245
|
+
</div>
|
|
246
|
+
</main>
|
|
247
|
+
|
|
248
|
+
<!-- Monaco Editor Container -->
|
|
249
|
+
<div id="editorContainer">
|
|
250
|
+
<div class="h-full flex flex-col">
|
|
251
|
+
<!-- Editor Header -->
|
|
252
|
+
<div class="bg-gray-800 border-b border-gray-700 p-4 flex justify-between items-center">
|
|
253
|
+
<h2 class="text-xl font-bold">Edit Slides</h2>
|
|
254
|
+
<div class="flex gap-3">
|
|
255
|
+
<button onclick="downloadMarkdown()" class="control-btn">
|
|
256
|
+
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
257
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4"/>
|
|
258
|
+
</svg>
|
|
259
|
+
Download
|
|
260
|
+
</button>
|
|
261
|
+
<button onclick="applyChanges()" class="control-btn bg-blue-600 hover:bg-blue-700">
|
|
262
|
+
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
263
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/>
|
|
264
|
+
</svg>
|
|
265
|
+
Apply
|
|
266
|
+
</button>
|
|
267
|
+
<button onclick="closeEditor()" class="control-btn">
|
|
268
|
+
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
269
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
|
|
270
|
+
</svg>
|
|
271
|
+
Close
|
|
272
|
+
</button>
|
|
273
|
+
</div>
|
|
274
|
+
</div>
|
|
275
|
+
|
|
276
|
+
<!-- Monaco Editor -->
|
|
277
|
+
<div id="editor" class="flex-1"></div>
|
|
278
|
+
</div>
|
|
279
|
+
</div>
|
|
280
|
+
|
|
281
|
+
<script>
|
|
282
|
+
let slides = [];
|
|
283
|
+
let currentSlide = 0;
|
|
284
|
+
let editor = null;
|
|
285
|
+
let markdownText = \`${markdownContent.replace(/`/g, '\\`').replace(/\$/g, '\\$')}\`;
|
|
286
|
+
|
|
287
|
+
// Parse markdown into slides (split by horizontal rule or headers)
|
|
288
|
+
function parseSlides(markdown) {
|
|
289
|
+
// Split by --- or *** or by # headers
|
|
290
|
+
let slideTexts = markdown.split(/\\n---\\n|\\n\\*\\*\\*\\n/).filter(s => s.trim());
|
|
291
|
+
|
|
292
|
+
// If no splits found, try splitting by top-level headers
|
|
293
|
+
if (slideTexts.length === 1) {
|
|
294
|
+
slideTexts = markdown.split(/(?=^# )/m).filter(s => s.trim());
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
return slideTexts.map(text => marked.parse(text));
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// Render all slides
|
|
301
|
+
function renderSlides() {
|
|
302
|
+
slides = parseSlides(markdownText);
|
|
303
|
+
const container = document.getElementById('slides');
|
|
304
|
+
container.innerHTML = slides.map((html, i) =>
|
|
305
|
+
\`<div class="slide \${i === 0 ? 'active' : ''}" data-index="\${i}">\${html}</div>\`
|
|
306
|
+
).join('');
|
|
307
|
+
|
|
308
|
+
updateSlideCounter();
|
|
309
|
+
renderMinimap();
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
// Render minimap thumbnails
|
|
313
|
+
function renderMinimap() {
|
|
314
|
+
const container = document.getElementById('minimapContent');
|
|
315
|
+
container.innerHTML = slides.map((html, i) => \`
|
|
316
|
+
<div class="thumbnail \${i === currentSlide ? 'active' : ''} bg-gray-900 rounded-lg p-4 border-2"
|
|
317
|
+
onclick="goToSlide(\${i})">
|
|
318
|
+
<div class="text-xs text-gray-400 mb-2">Slide \${i + 1}</div>
|
|
319
|
+
<div class="text-sm opacity-75 line-clamp-3">\${stripHtml(html)}</div>
|
|
320
|
+
</div>
|
|
321
|
+
\`).join('');
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
function stripHtml(html) {
|
|
325
|
+
const tmp = document.createElement('div');
|
|
326
|
+
tmp.innerHTML = html;
|
|
327
|
+
return tmp.textContent || tmp.innerText || '';
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
// Navigation
|
|
331
|
+
function goToSlide(index) {
|
|
332
|
+
if (index < 0 || index >= slides.length) return;
|
|
333
|
+
|
|
334
|
+
document.querySelectorAll('.slide').forEach(s => s.classList.remove('active'));
|
|
335
|
+
document.querySelectorAll('.thumbnail').forEach(t => t.classList.remove('active'));
|
|
336
|
+
|
|
337
|
+
document.querySelector(\`.slide[data-index="\${index}"]\`).classList.add('active');
|
|
338
|
+
const thumb = document.querySelectorAll('.thumbnail')[index];
|
|
339
|
+
if (thumb) thumb.classList.add('active');
|
|
340
|
+
|
|
341
|
+
currentSlide = index;
|
|
342
|
+
updateSlideCounter();
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
function nextSlide() {
|
|
346
|
+
goToSlide(currentSlide + 1);
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
function prevSlide() {
|
|
350
|
+
goToSlide(currentSlide - 1);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
function updateSlideCounter() {
|
|
354
|
+
document.getElementById('slideCounter').textContent =
|
|
355
|
+
\`Slide \${currentSlide + 1} of \${slides.length}\`;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
// Toggle minimap
|
|
359
|
+
function toggleMinimap() {
|
|
360
|
+
const panel = document.getElementById('minimapPanel');
|
|
361
|
+
panel.classList.toggle('hidden');
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
// Fullscreen
|
|
365
|
+
function toggleFullscreen() {
|
|
366
|
+
if (!document.fullscreenElement) {
|
|
367
|
+
document.documentElement.requestFullscreen();
|
|
368
|
+
document.getElementById('mainHeader').classList.add('hidden');
|
|
369
|
+
document.getElementById('navControls').style.opacity = '0.5';
|
|
370
|
+
} else {
|
|
371
|
+
document.exitFullscreen();
|
|
372
|
+
document.getElementById('mainHeader').classList.remove('hidden');
|
|
373
|
+
document.getElementById('navControls').style.opacity = '1';
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
// Editor functions
|
|
378
|
+
function openEditor() {
|
|
379
|
+
document.getElementById('editorContainer').style.display = 'block';
|
|
380
|
+
|
|
381
|
+
if (!editor) {
|
|
382
|
+
require.config({
|
|
383
|
+
paths: {
|
|
384
|
+
'vs': 'https://cdn.jsdelivr.net/npm/monaco-editor@0.44.0/min/vs'
|
|
385
|
+
}
|
|
386
|
+
});
|
|
387
|
+
|
|
388
|
+
require(['vs/editor/editor.main'], function() {
|
|
389
|
+
editor = monaco.editor.create(document.getElementById('editor'), {
|
|
390
|
+
value: markdownText,
|
|
391
|
+
language: 'markdown',
|
|
392
|
+
theme: 'vs-dark',
|
|
393
|
+
fontSize: 14,
|
|
394
|
+
minimap: { enabled: true },
|
|
395
|
+
wordWrap: 'on',
|
|
396
|
+
automaticLayout: true
|
|
397
|
+
});
|
|
398
|
+
});
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
function closeEditor() {
|
|
403
|
+
document.getElementById('editorContainer').style.display = 'none';
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
function applyChanges() {
|
|
407
|
+
if (editor) {
|
|
408
|
+
markdownText = editor.getValue();
|
|
409
|
+
renderSlides();
|
|
410
|
+
goToSlide(0);
|
|
411
|
+
closeEditor();
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
function downloadMarkdown() {
|
|
416
|
+
const content = editor ? editor.getValue() : markdownText;
|
|
417
|
+
const blob = new Blob([content], { type: 'text/markdown' });
|
|
418
|
+
const url = URL.createObjectURL(blob);
|
|
419
|
+
const a = document.createElement('a');
|
|
420
|
+
a.href = url;
|
|
421
|
+
a.download = '${fileName}';
|
|
422
|
+
a.click();
|
|
423
|
+
URL.revokeObjectURL(url);
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
// Keyboard navigation
|
|
427
|
+
document.addEventListener('keydown', (e) => {
|
|
428
|
+
if (document.getElementById('editorContainer').style.display === 'block') return;
|
|
429
|
+
|
|
430
|
+
if (e.key === 'ArrowRight' || e.key === ' ') {
|
|
431
|
+
e.preventDefault();
|
|
432
|
+
nextSlide();
|
|
433
|
+
} else if (e.key === 'ArrowLeft') {
|
|
434
|
+
e.preventDefault();
|
|
435
|
+
prevSlide();
|
|
436
|
+
} else if (e.key === 'Home') {
|
|
437
|
+
e.preventDefault();
|
|
438
|
+
goToSlide(0);
|
|
439
|
+
} else if (e.key === 'End') {
|
|
440
|
+
e.preventDefault();
|
|
441
|
+
goToSlide(slides.length - 1);
|
|
442
|
+
} else if (e.key === 'f' || e.key === 'F11') {
|
|
443
|
+
e.preventDefault();
|
|
444
|
+
toggleFullscreen();
|
|
445
|
+
} else if (e.key === 'e' || e.key === 'E') {
|
|
446
|
+
e.preventDefault();
|
|
447
|
+
openEditor();
|
|
448
|
+
} else if (e.key === 'm' || e.key === 'M') {
|
|
449
|
+
e.preventDefault();
|
|
450
|
+
toggleMinimap();
|
|
451
|
+
} else if (e.key === 'Escape') {
|
|
452
|
+
if (document.getElementById('editorContainer').style.display === 'block') {
|
|
453
|
+
closeEditor();
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
});
|
|
457
|
+
|
|
458
|
+
// Fullscreen change handler
|
|
459
|
+
document.addEventListener('fullscreenchange', () => {
|
|
460
|
+
if (!document.fullscreenElement) {
|
|
461
|
+
document.getElementById('mainHeader').classList.remove('hidden');
|
|
462
|
+
document.getElementById('navControls').style.opacity = '1';
|
|
463
|
+
}
|
|
464
|
+
});
|
|
465
|
+
|
|
466
|
+
// Initialize
|
|
467
|
+
renderSlides();
|
|
468
|
+
</script>
|
|
469
|
+
</body>
|
|
470
|
+
</html>`;
|
|
471
|
+
|
|
472
|
+
// Create HTTP server
|
|
473
|
+
const server = http.createServer((req, res) => {
|
|
474
|
+
if (req.url === '/') {
|
|
475
|
+
res.writeHead(200, { 'Content-Type': 'text/html' });
|
|
476
|
+
res.end(html);
|
|
477
|
+
} else {
|
|
478
|
+
res.writeHead(404);
|
|
479
|
+
res.end('Not Found');
|
|
480
|
+
}
|
|
481
|
+
});
|
|
482
|
+
|
|
483
|
+
server.listen(opts.port, () => {
|
|
484
|
+
const url = `http://localhost:${opts.port}`;
|
|
485
|
+
console.log(`β
Server running at ${url}\n`);
|
|
486
|
+
|
|
487
|
+
// Open browser
|
|
488
|
+
const command = process.platform === 'darwin' ? 'open' :
|
|
489
|
+
process.platform === 'win32' ? 'start' : 'xdg-open';
|
|
490
|
+
exec(`${command} ${url}`, (err) => {
|
|
491
|
+
if (err) console.log('Please open the URL manually in your browser');
|
|
492
|
+
});
|
|
493
|
+
|
|
494
|
+
console.log('Press Ctrl+C to stop the server\n');
|
|
495
|
+
console.log('Keyboard shortcuts:');
|
|
496
|
+
console.log(' β / Space Next slide');
|
|
497
|
+
console.log(' β Previous slide');
|
|
498
|
+
console.log(' Home First slide');
|
|
499
|
+
console.log(' End Last slide');
|
|
500
|
+
console.log(' F / F11 Fullscreen');
|
|
501
|
+
console.log(' E Open editor');
|
|
502
|
+
console.log(' M Toggle minimap');
|
|
503
|
+
console.log(' ESC Close editor');
|
|
504
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "markdown-slides-cli",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Interactive markdown slide presentation with live editing and minimap view",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"publisher": "mohanchinnappan",
|
|
7
|
+
"author": "Mohan Chinnappan",
|
|
8
|
+
|
|
9
|
+
"bin": {
|
|
10
|
+
"markdown-slides": "./markdown-slides.js",
|
|
11
|
+
"md-slides": "./markdown-slides.js"
|
|
12
|
+
},
|
|
13
|
+
"scripts": {
|
|
14
|
+
"start": "node markdown-slides.js",
|
|
15
|
+
"demo": "node markdown-slides.js -f example.md"
|
|
16
|
+
},
|
|
17
|
+
"keywords": [
|
|
18
|
+
"markdown",
|
|
19
|
+
"slides",
|
|
20
|
+
"presentation",
|
|
21
|
+
"reveal",
|
|
22
|
+
"slideshow",
|
|
23
|
+
"presenter",
|
|
24
|
+
"monaco",
|
|
25
|
+
"editor",
|
|
26
|
+
"cli"
|
|
27
|
+
],
|
|
28
|
+
"license": "MIT",
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"commander": "^11.1.0"
|
|
31
|
+
},
|
|
32
|
+
"engines": {
|
|
33
|
+
"node": ">=14.0.0"
|
|
34
|
+
}
|
|
35
|
+
}
|
package/slides/NOTES.md
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
Perfect! I've created a comprehensive **Markdown Slides Viewer & Editor** with all the features you requested:
|
|
2
|
+
|
|
3
|
+
## π― Key Features:
|
|
4
|
+
|
|
5
|
+
### π **Slide Viewing**
|
|
6
|
+
- Parses markdown file into slides (split by `---` or `***` or by `#` headers)
|
|
7
|
+
- Beautiful rendered slides with full markdown support
|
|
8
|
+
- Smooth slide transitions
|
|
9
|
+
- Slide counter display
|
|
10
|
+
|
|
11
|
+
### πΊοΈ **Minimap/Thumbnail View**
|
|
12
|
+
- Collapsible sidebar with slide thumbnails
|
|
13
|
+
- Click thumbnails to jump to specific slides
|
|
14
|
+
- Active slide highlighting
|
|
15
|
+
- Compact preview of each slide's content
|
|
16
|
+
|
|
17
|
+
### βοΈ **Monaco Editor Integration**
|
|
18
|
+
- Full-featured code editor (same as VS Code)
|
|
19
|
+
- Syntax highlighting for markdown
|
|
20
|
+
- Minimap in editor
|
|
21
|
+
- Word wrap and automatic layout
|
|
22
|
+
- Live preview after applying changes
|
|
23
|
+
|
|
24
|
+
### π¬ **Fullscreen Mode**
|
|
25
|
+
- F11 or click button to enter fullscreen
|
|
26
|
+
- Auto-hide header in fullscreen
|
|
27
|
+
- Semi-transparent controls
|
|
28
|
+
- Exit with ESC
|
|
29
|
+
|
|
30
|
+
### πΎ **Download Edited Slides**
|
|
31
|
+
- Download button in editor
|
|
32
|
+
- Saves as original filename
|
|
33
|
+
- Preserves all edits
|
|
34
|
+
|
|
35
|
+
### β¨οΈ **Keyboard Shortcuts**
|
|
36
|
+
- `β / Space` - Next slide
|
|
37
|
+
- `β` - Previous slide
|
|
38
|
+
- `Home` - First slide
|
|
39
|
+
- `End` - Last slide
|
|
40
|
+
- `F / F11` - Toggle fullscreen
|
|
41
|
+
- `E` - Open editor
|
|
42
|
+
- `M` - Toggle minimap
|
|
43
|
+
- `ESC` - Close editor
|
|
44
|
+
|
|
45
|
+
## π¦ Usage:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
# Basic usage
|
|
49
|
+
./markdown-slides.js -f slides.md
|
|
50
|
+
|
|
51
|
+
# Custom port and title
|
|
52
|
+
./markdown-slides.js -f presentation.md -p 8080 -t "My Presentation"
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## π Example Markdown Format:
|
|
56
|
+
|
|
57
|
+
```markdown
|
|
58
|
+
# Welcome Slide
|
|
59
|
+
This is the first slide
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
# Second Slide
|
|
64
|
+
- Point 1
|
|
65
|
+
- Point 2
|
|
66
|
+
- Point 3
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
# Code Example
|
|
71
|
+
```javascript
|
|
72
|
+
console.log('Hello World');
|
|
73
|
+
```
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
The app automatically splits slides by `---` dividers or top-level headers! π
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
## Introduction to AI Agents
|
|
4
|
+
|
|
5
|
+
Exploring autonomous systems that perceive, reason, and act to achieve goals.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## What Are AI Agents?
|
|
10
|
+
|
|
11
|
+
* **AI Agents** are autonomous software entities that perceive their environment, make decisions, and perform actions to achieve specific objectives.
|
|
12
|
+
* They can operate independently or collaborate with humans and other agents.
|
|
13
|
+
* Examples include chatbots, recommendation systems, and autonomous vehicles.
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Core Components of AI Agents
|
|
18
|
+
|
|
19
|
+
* **Perception**: Gathering data from the environment through sensors or inputs.
|
|
20
|
+
* **Knowledge Base**: Storing information and learned experiences.
|
|
21
|
+
* **Reasoning Engine**: Making decisions based on goals and available data.
|
|
22
|
+
* **Action Module**: Executing tasks to influence the environment.
|
|
23
|
+
* **Learning Mechanism**: Adapting behavior based on new information.
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## Types of AI Agents
|
|
28
|
+
|
|
29
|
+
* **Reactive Agents**: Respond to stimuli without internal representation.
|
|
30
|
+
* **Deliberative Agents**: Use internal models to plan actions.
|
|
31
|
+
* **Hybrid Agents**: Combine reactive and deliberative approaches.
|
|
32
|
+
* **Collaborative Agents**: Work with other agents or humans to achieve goals.
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## Real-World Applications
|
|
37
|
+
|
|
38
|
+
* **Healthcare**: AI agents assist in diagnostics, patient monitoring, and personalized treatment plans.
|
|
39
|
+
* **Finance**: Automate trading, fraud detection, and customer service.
|
|
40
|
+
* **Retail**: Personalize shopping experiences and manage inventory.
|
|
41
|
+
* **Transportation**: Enable autonomous driving and traffic management.
|
|
42
|
+
* **Customer Support**: Provide 24/7 assistance through chatbots and virtual assistants.
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## Benefits of AI Agents
|
|
47
|
+
|
|
48
|
+
* **Efficiency**: Automate repetitive tasks, freeing up human resources.
|
|
49
|
+
* **Scalability**: Handle increasing workloads without proportional resource increases.
|
|
50
|
+
* **Consistency**: Provide uniform performance without fatigue.
|
|
51
|
+
* **Adaptability**: Learn from new data to improve over time.
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## Challenges and Considerations
|
|
56
|
+
|
|
57
|
+
* **Ethical Concerns**: Ensuring decisions align with human values.
|
|
58
|
+
* **Transparency**: Understanding decision-making processes.
|
|
59
|
+
* **Security**: Protecting against malicious use or data breaches.
|
|
60
|
+
* **Dependence**: Avoiding over-reliance on automated systems.
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## Future of AI Agents
|
|
65
|
+
|
|
66
|
+
* **Integration**: Seamless collaboration between humans and AI agents.
|
|
67
|
+
* **Advancements**: Improved learning algorithms and decision-making capabilities.
|
|
68
|
+
* **Regulation**: Establishing guidelines for ethical and responsible use.
|
|
69
|
+
* **Ubiquity**: AI agents becoming commonplace in daily life and various industries.
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## Thank You!
|
|
74
|
+
|
|
75
|
+
Embracing AI agents paves the way for innovative solutions and enhanced productivity.
|
|
76
|
+
|
|
77
|
+
> "The best way to predict the future is to invent it." β Alan Kay
|
|
78
|
+
|
|
79
|
+
|