vite-plugin-react-deck 1.1.5 → 1.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/config.d.ts +1 -1
- package/helpers.d.ts +26 -2
- package/index.cjs +569 -147
- package/index.d.ts +2 -2
- package/index.mjs +570 -148
- package/package.json +11 -11
- package/slides.d.ts +1 -1
- package/themes/index.d.ts +1 -0
- package/themes/solarized-light.d.ts +11 -0
- package/types.d.ts +20 -7
package/index.cjs
CHANGED
|
@@ -27,12 +27,411 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
27
27
|
|
|
28
28
|
// src/index.ts
|
|
29
29
|
var fs2 = __toESM(require("fs/promises"), 1);
|
|
30
|
+
var glob = __toESM(require("glob"), 1);
|
|
31
|
+
var import_gray_matter2 = __toESM(require("gray-matter"), 1);
|
|
32
|
+
|
|
33
|
+
// src/themes/green.ts
|
|
34
|
+
var green_exports = {};
|
|
35
|
+
__export(green_exports, {
|
|
36
|
+
themeTokens: () => themeTokens
|
|
37
|
+
});
|
|
38
|
+
var colors = {
|
|
39
|
+
primary: "#FFFFFF",
|
|
40
|
+
secondary: "#F49676",
|
|
41
|
+
tertiary: "#042F3B"
|
|
42
|
+
};
|
|
43
|
+
var themeTokens = {
|
|
44
|
+
colors
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
// src/themes/purple.ts
|
|
48
|
+
var purple_exports = {};
|
|
49
|
+
__export(purple_exports, {
|
|
50
|
+
themeTokens: () => themeTokens2
|
|
51
|
+
});
|
|
52
|
+
var colors2 = {
|
|
53
|
+
//primary: "#56D4F8",
|
|
54
|
+
primary: "#ffffff",
|
|
55
|
+
secondary: "#F530EC",
|
|
56
|
+
tertiary: "#2B135A"
|
|
57
|
+
};
|
|
58
|
+
var themeTokens2 = {
|
|
59
|
+
colors: colors2
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
// src/themes/solarized-light.ts
|
|
63
|
+
var solarized_light_exports = {};
|
|
64
|
+
__export(solarized_light_exports, {
|
|
65
|
+
themeTokens: () => themeTokens3
|
|
66
|
+
});
|
|
67
|
+
var colors3 = {
|
|
68
|
+
primary: "#073642",
|
|
69
|
+
// base02 - dark text on light background
|
|
70
|
+
secondary: "#268bd2",
|
|
71
|
+
// blue accent
|
|
72
|
+
tertiary: "#fdf6e3"
|
|
73
|
+
// base3 - light background
|
|
74
|
+
};
|
|
75
|
+
var fonts = {
|
|
76
|
+
header: '"Source Sans Pro", "Helvetica Neue", Helvetica, Arial, sans-serif',
|
|
77
|
+
text: '"Source Sans Pro", "Helvetica Neue", Helvetica, Arial, sans-serif'
|
|
78
|
+
};
|
|
79
|
+
var themeTokens3 = {
|
|
80
|
+
colors: colors3,
|
|
81
|
+
fonts
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
// src/helpers.ts
|
|
85
|
+
var themes = {
|
|
86
|
+
green: green_exports,
|
|
87
|
+
purple: purple_exports,
|
|
88
|
+
"solarized-light": solarized_light_exports
|
|
89
|
+
};
|
|
90
|
+
function createDecksIndexFile() {
|
|
91
|
+
return `<!DOCTYPE html>
|
|
92
|
+
<html lang="en">
|
|
93
|
+
<head>
|
|
94
|
+
<meta charset="utf-8" />
|
|
95
|
+
<title>Pestacle - Decks</title>
|
|
96
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
97
|
+
<link rel="icon" type="image/x-icon" href="favicon.ico" />
|
|
98
|
+
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
99
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
|
100
|
+
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet" />
|
|
101
|
+
<style>* { margin: 0; padding: 0; box-sizing: border-box; }</style>
|
|
102
|
+
</head>
|
|
103
|
+
<body>
|
|
104
|
+
<div id="root"></div>
|
|
105
|
+
<script type="module" src="__decks.tsx"></script>
|
|
106
|
+
</body>
|
|
107
|
+
</html>
|
|
108
|
+
`;
|
|
109
|
+
}
|
|
110
|
+
function createDecksPageFile({
|
|
111
|
+
decks,
|
|
112
|
+
theme
|
|
113
|
+
}) {
|
|
114
|
+
var _a;
|
|
115
|
+
const themeModule = themes[theme];
|
|
116
|
+
const colors4 = (_a = themeModule == null ? void 0 : themeModule.themeTokens) == null ? void 0 : _a.colors;
|
|
117
|
+
const primary = (colors4 == null ? void 0 : colors4.primary) ?? "#ffffff";
|
|
118
|
+
const secondary = (colors4 == null ? void 0 : colors4.secondary) ?? "#F49676";
|
|
119
|
+
const tertiary = (colors4 == null ? void 0 : colors4.tertiary) ?? "#042F3B";
|
|
120
|
+
return `import React, { StrictMode, useState } from "react";
|
|
121
|
+
import * as ReactDOM from "react-dom/client";
|
|
122
|
+
|
|
123
|
+
const decks = ${JSON.stringify(decks)};
|
|
124
|
+
|
|
125
|
+
function DeckCard({ deck }) {
|
|
126
|
+
const [hovered, setHovered] = useState(false);
|
|
127
|
+
const title = deck.title || deck.name;
|
|
128
|
+
const hasMeta = deck.author || deck.slideCount > 0;
|
|
129
|
+
|
|
130
|
+
return (
|
|
131
|
+
<a
|
|
132
|
+
href={deck.path}
|
|
133
|
+
onMouseEnter={() => setHovered(true)}
|
|
134
|
+
onMouseLeave={() => setHovered(false)}
|
|
135
|
+
style={{
|
|
136
|
+
display: "flex",
|
|
137
|
+
flexDirection: "column",
|
|
138
|
+
padding: "1.5rem",
|
|
139
|
+
borderRadius: 16,
|
|
140
|
+
backgroundColor: hovered ? "${secondary}18" : "${secondary}0a",
|
|
141
|
+
border: hovered ? "1px solid ${secondary}88" : "1px solid ${secondary}22",
|
|
142
|
+
color: "${primary}",
|
|
143
|
+
textDecoration: "none",
|
|
144
|
+
transition: "all 0.2s ease",
|
|
145
|
+
transform: hovered ? "translateY(-2px)" : "translateY(0)",
|
|
146
|
+
boxShadow: hovered
|
|
147
|
+
? "0 8px 24px rgba(0,0,0,0.2)"
|
|
148
|
+
: "0 2px 8px rgba(0,0,0,0.1)",
|
|
149
|
+
minHeight: 140,
|
|
150
|
+
justifyContent: "space-between",
|
|
151
|
+
}}
|
|
152
|
+
>
|
|
153
|
+
<div>
|
|
154
|
+
<div style={{
|
|
155
|
+
fontSize: "1.25rem",
|
|
156
|
+
fontWeight: 600,
|
|
157
|
+
marginBottom: "0.5rem",
|
|
158
|
+
lineHeight: 1.3,
|
|
159
|
+
color: "${primary}",
|
|
160
|
+
}}>
|
|
161
|
+
{title}
|
|
162
|
+
</div>
|
|
163
|
+
{deck.description && (
|
|
164
|
+
<div style={{
|
|
165
|
+
fontSize: "0.875rem",
|
|
166
|
+
opacity: 0.6,
|
|
167
|
+
lineHeight: 1.5,
|
|
168
|
+
marginBottom: "0.75rem",
|
|
169
|
+
}}>
|
|
170
|
+
{deck.description}
|
|
171
|
+
</div>
|
|
172
|
+
)}
|
|
173
|
+
</div>
|
|
174
|
+
<div style={{
|
|
175
|
+
display: "flex",
|
|
176
|
+
alignItems: "center",
|
|
177
|
+
gap: "1rem",
|
|
178
|
+
flexWrap: "wrap",
|
|
179
|
+
marginTop: "auto",
|
|
180
|
+
}}>
|
|
181
|
+
{deck.author && (
|
|
182
|
+
<span style={{
|
|
183
|
+
fontSize: "0.8rem",
|
|
184
|
+
opacity: 0.5,
|
|
185
|
+
display: "flex",
|
|
186
|
+
alignItems: "center",
|
|
187
|
+
gap: "0.35rem",
|
|
188
|
+
}}>
|
|
189
|
+
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
|
190
|
+
<path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2" />
|
|
191
|
+
<circle cx="12" cy="7" r="4" />
|
|
192
|
+
</svg>
|
|
193
|
+
{deck.author}
|
|
194
|
+
</span>
|
|
195
|
+
)}
|
|
196
|
+
{deck.slideCount > 0 && (
|
|
197
|
+
<span style={{
|
|
198
|
+
fontSize: "0.8rem",
|
|
199
|
+
opacity: 0.5,
|
|
200
|
+
display: "flex",
|
|
201
|
+
alignItems: "center",
|
|
202
|
+
gap: "0.35rem",
|
|
203
|
+
}}>
|
|
204
|
+
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
|
205
|
+
<rect x="2" y="3" width="20" height="14" rx="2" ry="2" />
|
|
206
|
+
<line x1="8" y1="21" x2="16" y2="21" />
|
|
207
|
+
<line x1="12" y1="17" x2="12" y2="21" />
|
|
208
|
+
</svg>
|
|
209
|
+
{deck.slideCount} slide{deck.slideCount !== 1 ? "s" : ""}
|
|
210
|
+
</span>
|
|
211
|
+
)}
|
|
212
|
+
{deck.date && (
|
|
213
|
+
<span style={{
|
|
214
|
+
fontSize: "0.8rem",
|
|
215
|
+
opacity: 0.5,
|
|
216
|
+
}}>
|
|
217
|
+
{deck.date}
|
|
218
|
+
</span>
|
|
219
|
+
)}
|
|
220
|
+
</div>
|
|
221
|
+
</a>
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
function DecksPage() {
|
|
226
|
+
const [search, setSearch] = useState("");
|
|
227
|
+
const [searchFocused, setSearchFocused] = useState(false);
|
|
228
|
+
const filtered = decks.filter((d) => {
|
|
229
|
+
const q = search.toLowerCase();
|
|
230
|
+
return (
|
|
231
|
+
d.name.toLowerCase().includes(q) ||
|
|
232
|
+
(d.title || "").toLowerCase().includes(q) ||
|
|
233
|
+
(d.author || "").toLowerCase().includes(q) ||
|
|
234
|
+
(d.description || "").toLowerCase().includes(q)
|
|
235
|
+
);
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
return (
|
|
239
|
+
<div style={{
|
|
240
|
+
minHeight: "100vh",
|
|
241
|
+
backgroundColor: "${tertiary}",
|
|
242
|
+
color: "${primary}",
|
|
243
|
+
fontFamily: "'Inter', 'Helvetica Neue', Helvetica, Arial, sans-serif",
|
|
244
|
+
}}>
|
|
245
|
+
<div style={{
|
|
246
|
+
maxWidth: 960,
|
|
247
|
+
margin: "0 auto",
|
|
248
|
+
padding: "4rem 2rem 3rem",
|
|
249
|
+
}}>
|
|
250
|
+
<div style={{ marginBottom: "3rem" }}>
|
|
251
|
+
<div style={{
|
|
252
|
+
display: "flex",
|
|
253
|
+
alignItems: "center",
|
|
254
|
+
gap: "0.75rem",
|
|
255
|
+
marginBottom: "0.75rem",
|
|
256
|
+
}}>
|
|
257
|
+
<svg width="36" height="36" viewBox="0 0 24 24" fill="none" stroke="${secondary}" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
|
258
|
+
<polygon points="23 7 16 12 23 17 23 7" />
|
|
259
|
+
<rect x="1" y="5" width="15" height="14" rx="2" ry="2" />
|
|
260
|
+
</svg>
|
|
261
|
+
<h1 style={{
|
|
262
|
+
fontSize: "2.5rem",
|
|
263
|
+
fontWeight: 700,
|
|
264
|
+
margin: 0,
|
|
265
|
+
background: "linear-gradient(135deg, ${secondary}, ${primary})",
|
|
266
|
+
WebkitBackgroundClip: "text",
|
|
267
|
+
WebkitTextFillColor: "transparent",
|
|
268
|
+
backgroundClip: "text",
|
|
269
|
+
}}>Pestacle</h1>
|
|
270
|
+
</div>
|
|
271
|
+
<p style={{
|
|
272
|
+
fontSize: "1rem",
|
|
273
|
+
opacity: 0.5,
|
|
274
|
+
margin: 0,
|
|
275
|
+
}}>{decks.length} presentation{decks.length !== 1 ? "s" : ""} available</p>
|
|
276
|
+
</div>
|
|
277
|
+
|
|
278
|
+
<div style={{
|
|
279
|
+
position: "relative",
|
|
280
|
+
marginBottom: "2rem",
|
|
281
|
+
}}>
|
|
282
|
+
<svg
|
|
283
|
+
width="18" height="18"
|
|
284
|
+
viewBox="0 0 24 24"
|
|
285
|
+
fill="none"
|
|
286
|
+
stroke="${primary}"
|
|
287
|
+
strokeWidth="2"
|
|
288
|
+
strokeLinecap="round"
|
|
289
|
+
strokeLinejoin="round"
|
|
290
|
+
style={{
|
|
291
|
+
position: "absolute",
|
|
292
|
+
left: 16,
|
|
293
|
+
top: "50%",
|
|
294
|
+
transform: "translateY(-50%)",
|
|
295
|
+
opacity: 0.4,
|
|
296
|
+
}}
|
|
297
|
+
>
|
|
298
|
+
<circle cx="11" cy="11" r="8" />
|
|
299
|
+
<line x1="21" y1="21" x2="16.65" y2="16.65" />
|
|
300
|
+
</svg>
|
|
301
|
+
<input
|
|
302
|
+
type="text"
|
|
303
|
+
placeholder="Search presentations..."
|
|
304
|
+
value={search}
|
|
305
|
+
onChange={(e) => setSearch(e.target.value)}
|
|
306
|
+
onFocus={() => setSearchFocused(true)}
|
|
307
|
+
onBlur={() => setSearchFocused(false)}
|
|
308
|
+
autoFocus
|
|
309
|
+
style={{
|
|
310
|
+
width: "100%",
|
|
311
|
+
padding: "0.875rem 1rem 0.875rem 2.75rem",
|
|
312
|
+
fontSize: "1rem",
|
|
313
|
+
borderRadius: 12,
|
|
314
|
+
border: searchFocused ? "2px solid ${secondary}" : "2px solid ${secondary}33",
|
|
315
|
+
backgroundColor: "${secondary}08",
|
|
316
|
+
color: "${primary}",
|
|
317
|
+
outline: "none",
|
|
318
|
+
boxSizing: "border-box",
|
|
319
|
+
transition: "border-color 0.2s ease, background-color 0.2s ease",
|
|
320
|
+
}}
|
|
321
|
+
/>
|
|
322
|
+
</div>
|
|
323
|
+
|
|
324
|
+
<div style={{
|
|
325
|
+
display: "grid",
|
|
326
|
+
gridTemplateColumns: "repeat(auto-fill, minmax(280px, 1fr))",
|
|
327
|
+
gap: "1rem",
|
|
328
|
+
}}>
|
|
329
|
+
{filtered.map((deck) => (
|
|
330
|
+
<DeckCard key={deck.path} deck={deck} />
|
|
331
|
+
))}
|
|
332
|
+
</div>
|
|
333
|
+
|
|
334
|
+
{filtered.length === 0 && (
|
|
335
|
+
<div style={{
|
|
336
|
+
textAlign: "center",
|
|
337
|
+
padding: "4rem 2rem",
|
|
338
|
+
opacity: 0.4,
|
|
339
|
+
}}>
|
|
340
|
+
<svg width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" style={{ marginBottom: "1rem" }}>
|
|
341
|
+
<circle cx="11" cy="11" r="8" />
|
|
342
|
+
<line x1="21" y1="21" x2="16.65" y2="16.65" />
|
|
343
|
+
</svg>
|
|
344
|
+
<p style={{ fontSize: "1.1rem" }}>No presentations matching “{search}”</p>
|
|
345
|
+
</div>
|
|
346
|
+
)}
|
|
347
|
+
</div>
|
|
348
|
+
</div>
|
|
349
|
+
);
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
const root = ReactDOM.createRoot(
|
|
353
|
+
document.getElementById("root") as HTMLElement
|
|
354
|
+
);
|
|
355
|
+
root.render(
|
|
356
|
+
<StrictMode>
|
|
357
|
+
<DecksPage />
|
|
358
|
+
</StrictMode>
|
|
359
|
+
);
|
|
360
|
+
`;
|
|
361
|
+
}
|
|
362
|
+
function createIndexFile({ entrypoint }) {
|
|
363
|
+
return `<!DOCTYPE html>
|
|
364
|
+
<html lang="en">
|
|
365
|
+
<head>
|
|
366
|
+
<meta charset="utf-8" />
|
|
367
|
+
<title>Title</title>
|
|
368
|
+
|
|
369
|
+
<style>
|
|
370
|
+
html {
|
|
371
|
+
--code-preview-background-color: #222;
|
|
372
|
+
}
|
|
373
|
+
</style>
|
|
374
|
+
|
|
375
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
376
|
+
<link rel="icon" type="image/x-icon" href="favicon.ico" />
|
|
377
|
+
</head>
|
|
378
|
+
<body>
|
|
379
|
+
<div id="root"></div>
|
|
380
|
+
<script type="module" src="${entrypoint}"></script>
|
|
381
|
+
</body>
|
|
382
|
+
</html>
|
|
383
|
+
`;
|
|
384
|
+
}
|
|
385
|
+
function createAppDeckFile({
|
|
386
|
+
slidePath,
|
|
387
|
+
theme,
|
|
388
|
+
deckTheme,
|
|
389
|
+
config
|
|
390
|
+
}) {
|
|
391
|
+
const resolvedThemeName = deckTheme ?? theme;
|
|
392
|
+
const isBuiltinTheme = resolvedThemeName in themes;
|
|
393
|
+
const isCustomThemePath = !isBuiltinTheme && (resolvedThemeName.startsWith("./") || resolvedThemeName.startsWith("../") || resolvedThemeName.startsWith("/"));
|
|
394
|
+
if (!isBuiltinTheme && !isCustomThemePath) {
|
|
395
|
+
const available = Object.keys(themes).join(", ");
|
|
396
|
+
throw new Error(
|
|
397
|
+
`Theme "${resolvedThemeName}" not found. Available built-in themes: ${available}. For custom themes, use a relative path (e.g. "./pestacle/themes/my-theme").`
|
|
398
|
+
);
|
|
399
|
+
}
|
|
400
|
+
const layoutImport = config.layoutsFile ? `import layouts from "${config.layoutsFile}";` : "import { layouts } from '@gpichot/spectacle-deck';";
|
|
401
|
+
const themeCode = isBuiltinTheme ? `const theme = ${JSON.stringify(themes[resolvedThemeName])};` : `import { themeTokens as _customThemeTokens } from "${resolvedThemeName}";
|
|
402
|
+
const theme = { themeTokens: _customThemeTokens };`;
|
|
403
|
+
return `import React, { StrictMode } from "react";
|
|
404
|
+
import * as ReactDOM from "react-dom/client";
|
|
405
|
+
import { Deck } from '@gpichot/spectacle-deck';
|
|
406
|
+
${layoutImport};
|
|
407
|
+
|
|
408
|
+
import deck from "${slidePath}";
|
|
409
|
+
${themeCode}
|
|
410
|
+
|
|
411
|
+
const root = ReactDOM.createRoot(
|
|
412
|
+
document.getElementById("root") as HTMLElement
|
|
413
|
+
);
|
|
414
|
+
root.render(
|
|
415
|
+
<StrictMode>
|
|
416
|
+
<Deck deck={deck} theme={theme} layouts={layouts}${config.transition ? ` transition="${config.transition}"` : ""} />
|
|
417
|
+
</StrictMode>
|
|
418
|
+
)
|
|
419
|
+
|
|
420
|
+
let link = document.createElement('link')
|
|
421
|
+
link.rel = 'stylesheet'
|
|
422
|
+
link.type = 'text/css'
|
|
423
|
+
link.href = 'https://cdn.jsdelivr.net/npm/katex@0.16.8/dist/katex.min.css'
|
|
424
|
+
document.head.appendChild(link)
|
|
425
|
+
`;
|
|
426
|
+
}
|
|
30
427
|
|
|
31
428
|
// src/slides.ts
|
|
429
|
+
var import_node_fs = __toESM(require("fs"), 1);
|
|
430
|
+
var import_mdx = require("@mdx-js/mdx");
|
|
32
431
|
var import_gray_matter = __toESM(require("gray-matter"), 1);
|
|
33
432
|
var import_remark_directive = __toESM(require("remark-directive"), 1);
|
|
34
|
-
var
|
|
35
|
-
var
|
|
433
|
+
var import_remark_gfm = __toESM(require("remark-gfm"), 1);
|
|
434
|
+
var import_unist_util_visit = require("unist-util-visit");
|
|
36
435
|
|
|
37
436
|
// src/codegen.ts
|
|
38
437
|
var Patterns = {
|
|
@@ -70,13 +469,14 @@ ${header}
|
|
|
70
469
|
}
|
|
71
470
|
|
|
72
471
|
// src/slides.ts
|
|
73
|
-
var import_remark_gfm = __toESM(require("remark-gfm"), 1);
|
|
74
|
-
var import_unist_util_visit = require("unist-util-visit");
|
|
75
472
|
function myRemarkPlugin() {
|
|
76
473
|
return (tree) => {
|
|
77
474
|
(0, import_unist_util_visit.visit)(tree, (node) => {
|
|
78
475
|
if (node.type === "containerDirective" || node.type === "leafDirective" || node.type === "textDirective") {
|
|
79
|
-
|
|
476
|
+
if (!node.data) {
|
|
477
|
+
node.data = {};
|
|
478
|
+
}
|
|
479
|
+
const data = node.data;
|
|
80
480
|
data.hName = "directive";
|
|
81
481
|
data.hProperties = node.attributes;
|
|
82
482
|
data.hProperties._name = node.name;
|
|
@@ -95,10 +495,9 @@ async function transformSlidesMdxToReact(sourceContent, {
|
|
|
95
495
|
);
|
|
96
496
|
const slides = finalContent.split("---\n");
|
|
97
497
|
const enrichedSlides = [];
|
|
98
|
-
const LAYOUT_REGEX = /\S*\nlayout: (.*)/g;
|
|
99
498
|
let frontmatterForNextSlide = null;
|
|
100
499
|
for (const slide of slides) {
|
|
101
|
-
if (
|
|
500
|
+
if (isFrontmatterBlock(slide)) {
|
|
102
501
|
frontmatterForNextSlide = (0, import_gray_matter.default)(`---
|
|
103
502
|
${slide}
|
|
104
503
|
---`).data;
|
|
@@ -111,12 +510,12 @@ ${slide}
|
|
|
111
510
|
frontmatterForNextSlide = null;
|
|
112
511
|
}
|
|
113
512
|
const compiledSlides = await Promise.all(
|
|
114
|
-
enrichedSlides.map(async (slide,
|
|
513
|
+
enrichedSlides.map(async (slide, _index) => {
|
|
115
514
|
const code = addInlineModules(slide.content, inlineModules);
|
|
116
515
|
const normalizedCode = code.replace("process.env", "process\u200B.env");
|
|
117
516
|
const result = await (0, import_mdx.compile)(normalizedCode, {
|
|
118
517
|
outputFormat: "program",
|
|
119
|
-
jsx:
|
|
518
|
+
jsx: false,
|
|
120
519
|
providerImportSource: "@mdx-js/react",
|
|
121
520
|
...options,
|
|
122
521
|
remarkPlugins: [
|
|
@@ -127,7 +526,7 @@ ${slide}
|
|
|
127
526
|
]
|
|
128
527
|
});
|
|
129
528
|
const mainCode = extractMainCodeAsChildren(result.value.toString(), {
|
|
130
|
-
isJsx:
|
|
529
|
+
isJsx: false
|
|
131
530
|
});
|
|
132
531
|
return {
|
|
133
532
|
...slide,
|
|
@@ -138,7 +537,8 @@ ${slide}
|
|
|
138
537
|
const output = addInlineModules(
|
|
139
538
|
`
|
|
140
539
|
import React from 'react';
|
|
141
|
-
|
|
540
|
+
import {Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs} from "react/jsx-runtime";
|
|
541
|
+
import {useMDXComponents as _provideComponents} from "@mdx-js/react";
|
|
142
542
|
|
|
143
543
|
${compiledSlides.map(
|
|
144
544
|
(slide, index) => `
|
|
@@ -163,7 +563,7 @@ Deck.slides = [
|
|
|
163
563
|
`,
|
|
164
564
|
inlineModules
|
|
165
565
|
);
|
|
166
|
-
|
|
566
|
+
import_node_fs.default.writeFileSync("slides.js", output);
|
|
167
567
|
return output;
|
|
168
568
|
}
|
|
169
569
|
var MOD_REG = /\\`|`(?:\\`|[^`])*`|(^(?:import|export).*$)/gm;
|
|
@@ -186,122 +586,30 @@ ${[...inlineModules.keys()].join("\n")}
|
|
|
186
586
|
${source}
|
|
187
587
|
`;
|
|
188
588
|
}
|
|
589
|
+
function isFrontmatterBlock(text) {
|
|
590
|
+
const lines = text.split("\n").map((l) => l.trim()).filter((l) => l.length > 0);
|
|
591
|
+
return lines.length > 0 && lines.every((l) => /^[\w][\w-]*\s*:/.test(l));
|
|
592
|
+
}
|
|
189
593
|
var CRLF = "\r\n";
|
|
190
594
|
function normalizeNewline(input) {
|
|
191
595
|
return input.replace(new RegExp(CRLF, "g"), "\n");
|
|
192
596
|
}
|
|
193
597
|
|
|
194
|
-
// src/themes/index.ts
|
|
195
|
-
var themes_exports = {};
|
|
196
|
-
__export(themes_exports, {
|
|
197
|
-
green: () => green_exports,
|
|
198
|
-
purple: () => purple_exports
|
|
199
|
-
});
|
|
200
|
-
|
|
201
|
-
// src/themes/green.ts
|
|
202
|
-
var green_exports = {};
|
|
203
|
-
__export(green_exports, {
|
|
204
|
-
themeTokens: () => themeTokens
|
|
205
|
-
});
|
|
206
|
-
var colors = {
|
|
207
|
-
primary: "#FFFFFF",
|
|
208
|
-
secondary: "#F49676",
|
|
209
|
-
tertiary: "#042F3B"
|
|
210
|
-
};
|
|
211
|
-
var themeTokens = {
|
|
212
|
-
colors
|
|
213
|
-
};
|
|
214
|
-
|
|
215
|
-
// src/themes/purple.ts
|
|
216
|
-
var purple_exports = {};
|
|
217
|
-
__export(purple_exports, {
|
|
218
|
-
themeTokens: () => themeTokens2
|
|
219
|
-
});
|
|
220
|
-
var colors2 = {
|
|
221
|
-
//primary: "#56D4F8",
|
|
222
|
-
primary: "#ffffff",
|
|
223
|
-
secondary: "#F530EC",
|
|
224
|
-
tertiary: "#2B135A"
|
|
225
|
-
};
|
|
226
|
-
var themeTokens2 = {
|
|
227
|
-
colors: colors2
|
|
228
|
-
};
|
|
229
|
-
|
|
230
|
-
// src/helpers.ts
|
|
231
|
-
function createIndexFile({ entrypoint }) {
|
|
232
|
-
return `<!DOCTYPE html>
|
|
233
|
-
<html lang="en">
|
|
234
|
-
<head>
|
|
235
|
-
<meta charset="utf-8" />
|
|
236
|
-
<title>Title</title>
|
|
237
|
-
|
|
238
|
-
<style>
|
|
239
|
-
html {
|
|
240
|
-
--code-preview-background-color: #222;
|
|
241
|
-
}
|
|
242
|
-
</style>
|
|
243
|
-
|
|
244
|
-
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
245
|
-
<link rel="icon" type="image/x-icon" href="favicon.ico" />
|
|
246
|
-
</head>
|
|
247
|
-
<body>
|
|
248
|
-
<div id="root"></div>
|
|
249
|
-
<script type="module" src="${entrypoint}"></script>
|
|
250
|
-
</body>
|
|
251
|
-
</html>
|
|
252
|
-
`;
|
|
253
|
-
}
|
|
254
|
-
function createAppDeckFile({
|
|
255
|
-
slidePath,
|
|
256
|
-
theme,
|
|
257
|
-
config
|
|
258
|
-
}) {
|
|
259
|
-
if (!themes_exports[theme]) {
|
|
260
|
-
throw new Error(`Theme ${theme} not found`);
|
|
261
|
-
}
|
|
262
|
-
const themeObject = themes_exports[theme];
|
|
263
|
-
const layoutImport = config.layoutsFile ? `import layouts from "${config.layoutsFile}";` : "import { layouts } from '@gpichot/spectacle-deck';";
|
|
264
|
-
return `import React, { StrictMode } from "react";
|
|
265
|
-
import * as ReactDOM from "react-dom/client";
|
|
266
|
-
import { Deck } from '@gpichot/spectacle-deck';
|
|
267
|
-
${layoutImport};
|
|
268
|
-
|
|
269
|
-
import deck from "${slidePath}";
|
|
270
|
-
|
|
271
|
-
const root = ReactDOM.createRoot(
|
|
272
|
-
document.getElementById("root") as HTMLElement
|
|
273
|
-
);
|
|
274
|
-
root.render(
|
|
275
|
-
<StrictMode>
|
|
276
|
-
<Deck deck={deck} theme={${JSON.stringify(themeObject)}} layouts={layouts} />
|
|
277
|
-
</StrictMode>
|
|
278
|
-
)
|
|
279
|
-
|
|
280
|
-
let link = document.createElement('link')
|
|
281
|
-
link.rel = 'stylesheet'
|
|
282
|
-
link.type = 'text/css'
|
|
283
|
-
link.href = 'https://cdn.jsdelivr.net/npm/katex@0.16.8/dist/katex.min.css'
|
|
284
|
-
document.head.appendChild(link)
|
|
285
|
-
`;
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
// src/index.ts
|
|
289
|
-
var glob = __toESM(require("glob"), 1);
|
|
290
|
-
var import_node_path = __toESM(require("path"), 1);
|
|
291
|
-
|
|
292
598
|
// src/config.ts
|
|
293
599
|
var import_lodash = __toESM(require("lodash"), 1);
|
|
294
600
|
|
|
295
601
|
// src/types.ts
|
|
296
602
|
var import_zod = require("zod");
|
|
297
603
|
var PestacleConfigSchema = import_zod.z.object({
|
|
298
|
-
theme: import_zod.z.enum(["green", "purple"]).default("green")
|
|
604
|
+
theme: import_zod.z.enum(["green", "purple", "solarized-light"]).default("green"),
|
|
605
|
+
startupPage: import_zod.z.boolean().optional(),
|
|
606
|
+
transition: import_zod.z.enum(["fade", "slide", "drop", "none"]).optional()
|
|
299
607
|
});
|
|
300
608
|
|
|
301
609
|
// src/index.ts
|
|
302
|
-
async function checkIfDirectoryExists(
|
|
610
|
+
async function checkIfDirectoryExists(path) {
|
|
303
611
|
try {
|
|
304
|
-
await fs2.access(
|
|
612
|
+
await fs2.access(path);
|
|
305
613
|
return true;
|
|
306
614
|
} catch {
|
|
307
615
|
return false;
|
|
@@ -314,15 +622,45 @@ async function findDecks({ port }) {
|
|
|
314
622
|
deckUrl: `http://localhost:${port}/${deck.replace("src/", "").replace("deck.mdx", "")}`
|
|
315
623
|
}));
|
|
316
624
|
}
|
|
317
|
-
async function
|
|
625
|
+
async function extractDeckMeta(filePath) {
|
|
626
|
+
try {
|
|
627
|
+
const raw = await fs2.readFile(filePath, "utf-8");
|
|
628
|
+
const { data, content } = (0, import_gray_matter2.default)(raw);
|
|
629
|
+
const slides = content.split("---\n");
|
|
630
|
+
const LAYOUT_REGEX = /\S*\nlayout: (.*)/g;
|
|
631
|
+
let slideCount = 0;
|
|
632
|
+
for (const slide of slides) {
|
|
633
|
+
if (!LAYOUT_REGEX.test(slide) && slide.trim().length > 0) {
|
|
634
|
+
slideCount++;
|
|
635
|
+
}
|
|
636
|
+
LAYOUT_REGEX.lastIndex = 0;
|
|
637
|
+
}
|
|
638
|
+
let title = data.title;
|
|
639
|
+
if (!title) {
|
|
640
|
+
const headingMatch = content.match(/^#\s+\*{0,2}(.+?)\*{0,2}\s*$/m);
|
|
641
|
+
if (headingMatch) {
|
|
642
|
+
title = headingMatch[1].replace(/\*+/g, "").trim();
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
return {
|
|
646
|
+
title,
|
|
647
|
+
author: data.author,
|
|
648
|
+
date: data.date,
|
|
649
|
+
description: data.description,
|
|
650
|
+
slideCount
|
|
651
|
+
};
|
|
652
|
+
} catch {
|
|
653
|
+
return { slideCount: 0 };
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
async function fileExists(_name, path) {
|
|
318
657
|
const candidateExts = [".ts", ".tsx", ".js", ".jsx"];
|
|
319
658
|
for await (const ext of candidateExts) {
|
|
320
|
-
const fullPath = `${
|
|
659
|
+
const fullPath = `${path}${ext}`;
|
|
321
660
|
try {
|
|
322
661
|
await fs2.access(fullPath);
|
|
323
662
|
return fullPath.replace(/^\./, "");
|
|
324
663
|
} catch {
|
|
325
|
-
continue;
|
|
326
664
|
}
|
|
327
665
|
}
|
|
328
666
|
}
|
|
@@ -334,30 +672,37 @@ async function loadCustomConfig() {
|
|
|
334
672
|
}
|
|
335
673
|
var src_default = async (options) => {
|
|
336
674
|
let isProd = false;
|
|
675
|
+
const showStartupPage = options.startupPage;
|
|
337
676
|
const deckConfig = {
|
|
338
677
|
decks: []
|
|
339
678
|
};
|
|
340
679
|
return {
|
|
341
680
|
name: "react-deck",
|
|
342
|
-
async config(config) {
|
|
343
|
-
var _a, _b
|
|
681
|
+
async config(config, env) {
|
|
682
|
+
var _a, _b;
|
|
344
683
|
const decks = await glob.glob("./src/**/deck.mdx");
|
|
345
|
-
const inputs = ((_b = (_a = config.build) == null ? void 0 : _a.
|
|
346
|
-
deckConfig.decks = decks.map((deck) =>
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
684
|
+
const inputs = ((_b = (_a = config.build) == null ? void 0 : _a.rolldownOptions) == null ? void 0 : _b.input) || {};
|
|
685
|
+
deckConfig.decks = decks.map((deck) => {
|
|
686
|
+
const name = deck.replace("./src/", "").replace("/deck.mdx", "").replace(/\//g, " / ");
|
|
687
|
+
return {
|
|
688
|
+
originalFile: deck,
|
|
689
|
+
index: deck.replace("/deck.mdx", "/index.html").replace("src/", ""),
|
|
690
|
+
name
|
|
691
|
+
};
|
|
692
|
+
});
|
|
693
|
+
const isProduction = env.mode === "production";
|
|
694
|
+
const startupPageEnabled = showStartupPage !== void 0 ? showStartupPage : !isProduction;
|
|
695
|
+
const newInputs = decks.map((deck) => {
|
|
351
696
|
const deckPath = deck.replace("/deck.mdx", "");
|
|
352
|
-
return
|
|
353
|
-
}
|
|
697
|
+
return `${deckPath.replace("src/", "")}/index.html`;
|
|
698
|
+
});
|
|
699
|
+
if (startupPageEnabled) {
|
|
700
|
+
newInputs.unshift("index.html");
|
|
701
|
+
}
|
|
354
702
|
const finalInputs = typeof inputs === "string" ? [inputs, ...decks] : Array.isArray(inputs) ? [...inputs, ...decks] : { ...inputs, ...newInputs };
|
|
355
703
|
return {
|
|
356
|
-
...config,
|
|
357
704
|
build: {
|
|
358
|
-
|
|
359
|
-
rollupOptions: {
|
|
360
|
-
...(_c = config.build) == null ? void 0 : _c.rollupOptions,
|
|
705
|
+
rolldownOptions: {
|
|
361
706
|
input: finalInputs
|
|
362
707
|
}
|
|
363
708
|
}
|
|
@@ -367,6 +712,9 @@ var src_default = async (options) => {
|
|
|
367
712
|
isProd = config.isProduction;
|
|
368
713
|
},
|
|
369
714
|
resolveId(id) {
|
|
715
|
+
if (id === "index.html" || id === "__decks.tsx" || id === "/__decks.tsx") {
|
|
716
|
+
return id.replace(/^\//, "");
|
|
717
|
+
}
|
|
370
718
|
if (deckConfig.decks.some((deck) => deck.index === id)) {
|
|
371
719
|
return id;
|
|
372
720
|
}
|
|
@@ -378,6 +726,27 @@ var src_default = async (options) => {
|
|
|
378
726
|
}
|
|
379
727
|
},
|
|
380
728
|
async load(id) {
|
|
729
|
+
const shouldShowStartupPage = showStartupPage !== void 0 ? showStartupPage : !isProd;
|
|
730
|
+
if (id === "index.html" && shouldShowStartupPage) {
|
|
731
|
+
return createDecksIndexFile();
|
|
732
|
+
}
|
|
733
|
+
if (id === "__decks.tsx") {
|
|
734
|
+
const decks = await Promise.all(
|
|
735
|
+
deckConfig.decks.map(async (d) => {
|
|
736
|
+
const meta = await extractDeckMeta(d.originalFile);
|
|
737
|
+
return {
|
|
738
|
+
name: d.name,
|
|
739
|
+
path: `/${d.index.replace("/index.html", "/")}`,
|
|
740
|
+
title: meta.title,
|
|
741
|
+
author: meta.author,
|
|
742
|
+
date: meta.date,
|
|
743
|
+
description: meta.description,
|
|
744
|
+
slideCount: meta.slideCount
|
|
745
|
+
};
|
|
746
|
+
})
|
|
747
|
+
);
|
|
748
|
+
return createDecksPageFile({ decks, theme: options.theme });
|
|
749
|
+
}
|
|
381
750
|
const config = await loadCustomConfig();
|
|
382
751
|
const deck = deckConfig.decks.find((deck2) => deck2.index === id);
|
|
383
752
|
if (deck) {
|
|
@@ -387,18 +756,27 @@ var src_default = async (options) => {
|
|
|
387
756
|
}
|
|
388
757
|
if (id.endsWith("__deck.tsx")) {
|
|
389
758
|
const directory = id.replace("/__deck.tsx", "");
|
|
390
|
-
const
|
|
391
|
-
const
|
|
392
|
-
if (!await checkIfDirectoryExists(
|
|
393
|
-
|
|
759
|
+
const dir = directory.startsWith(".") ? directory : `./${directory}`;
|
|
760
|
+
const deckMdxPath = `${dir}/deck.mdx`;
|
|
761
|
+
if (!await checkIfDirectoryExists(deckMdxPath)) {
|
|
762
|
+
this.warn(`No deck.mdx file found in ${deckMdxPath}`);
|
|
394
763
|
return;
|
|
395
764
|
}
|
|
765
|
+
let deckTheme;
|
|
766
|
+
try {
|
|
767
|
+
const raw = await fs2.readFile(deckMdxPath, "utf-8");
|
|
768
|
+
const { data: data2 } = (0, import_gray_matter2.default)(raw);
|
|
769
|
+
if (typeof data2.theme === "string") {
|
|
770
|
+
deckTheme = data2.theme;
|
|
771
|
+
}
|
|
772
|
+
} catch {
|
|
773
|
+
}
|
|
396
774
|
const contentIndex = createAppDeckFile({
|
|
397
775
|
slidePath: `${directory}/deck.mdx`,
|
|
398
776
|
theme: options.theme,
|
|
399
|
-
|
|
777
|
+
deckTheme,
|
|
778
|
+
config: { ...config, transition: options.transition }
|
|
400
779
|
});
|
|
401
|
-
console.log({ contentIndex });
|
|
402
780
|
return contentIndex;
|
|
403
781
|
}
|
|
404
782
|
if (!id.endsWith("deck.mdx")) {
|
|
@@ -409,32 +787,76 @@ var src_default = async (options) => {
|
|
|
409
787
|
production: isProd,
|
|
410
788
|
...options
|
|
411
789
|
});
|
|
412
|
-
const dir = import_node_path.default.relative(process.cwd(), id);
|
|
413
790
|
return data;
|
|
414
791
|
},
|
|
415
792
|
transformIndexHtml: {
|
|
416
793
|
order: "pre",
|
|
417
|
-
|
|
418
|
-
transform: async (html, ctx) => {
|
|
794
|
+
handler: async (html, ctx) => {
|
|
419
795
|
var _a;
|
|
420
796
|
const originalUrl = ((_a = ctx.originalUrl) == null ? void 0 : _a.split("?")[0]) || "";
|
|
797
|
+
if (originalUrl === "/" || originalUrl === "") {
|
|
798
|
+
const shouldShow = showStartupPage !== void 0 ? showStartupPage : !isProd;
|
|
799
|
+
if (shouldShow) {
|
|
800
|
+
return html.replace("__SCRIPT__", `__decks.tsx`);
|
|
801
|
+
}
|
|
802
|
+
}
|
|
421
803
|
const deckDir = ctx.path.replace("/index.html", "");
|
|
422
804
|
const dir = originalUrl ? `./src${originalUrl}` : `.${deckDir}`;
|
|
423
|
-
const
|
|
424
|
-
if (
|
|
425
|
-
|
|
805
|
+
const deckPath = `${dir}/deck.mdx`;
|
|
806
|
+
if (await checkIfDirectoryExists(deckPath)) {
|
|
807
|
+
const resolvedDeckPath = dir.startsWith(".") ? dir : `.${dir}`;
|
|
808
|
+
return html.replace("__SCRIPT__", `${resolvedDeckPath}/__deck.tsx`);
|
|
426
809
|
}
|
|
427
|
-
const
|
|
428
|
-
|
|
810
|
+
const decks = await glob.glob("./src/**/deck.mdx");
|
|
811
|
+
const deckLinks = decks.map((d) => {
|
|
812
|
+
const url = `/${d.replace("src/", "").replace("/deck.mdx", "")}/`;
|
|
813
|
+
const name = d.replace("src/", "").replace("/deck.mdx", "");
|
|
814
|
+
return `<li><a href="${url}">${name}</a></li>`;
|
|
815
|
+
}).join("\n");
|
|
816
|
+
return html.replace('<script type="module" src="__SCRIPT__"></script>', "").replace(
|
|
817
|
+
'<div id="root"></div>',
|
|
818
|
+
`<div id="root">
|
|
819
|
+
<h1>Available Decks</h1>
|
|
820
|
+
<ul>${deckLinks}</ul>
|
|
821
|
+
</div>`
|
|
822
|
+
);
|
|
429
823
|
}
|
|
430
824
|
},
|
|
431
825
|
configureServer(server) {
|
|
432
826
|
var _a;
|
|
827
|
+
const shouldShow = showStartupPage !== void 0 ? showStartupPage : true;
|
|
828
|
+
if (shouldShow) {
|
|
829
|
+
server.middlewares.use(async (req, res, next) => {
|
|
830
|
+
var _a2;
|
|
831
|
+
const url = ((_a2 = req.url) == null ? void 0 : _a2.split("?")[0]) || "";
|
|
832
|
+
if (url === "/" || url === "/index.html") {
|
|
833
|
+
const html = createDecksIndexFile();
|
|
834
|
+
const transformed = await server.transformIndexHtml(
|
|
835
|
+
url,
|
|
836
|
+
html,
|
|
837
|
+
req.originalUrl
|
|
838
|
+
);
|
|
839
|
+
res.setHeader("Content-Type", "text/html");
|
|
840
|
+
res.statusCode = 200;
|
|
841
|
+
res.end(transformed);
|
|
842
|
+
return;
|
|
843
|
+
}
|
|
844
|
+
next();
|
|
845
|
+
});
|
|
846
|
+
}
|
|
433
847
|
(_a = server.httpServer) == null ? void 0 : _a.once("listening", async () => {
|
|
434
848
|
const port = server.config.server.port || 5173;
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
849
|
+
if (shouldShow) {
|
|
850
|
+
server.config.logger.info(
|
|
851
|
+
`
|
|
852
|
+
Decks available at http://localhost:${port}/
|
|
853
|
+
`
|
|
854
|
+
);
|
|
855
|
+
} else {
|
|
856
|
+
const decks = await findDecks({ port });
|
|
857
|
+
for (const deck of decks) {
|
|
858
|
+
server.config.logger.info(`Deck available at ${deck.deckUrl}`);
|
|
859
|
+
}
|
|
438
860
|
}
|
|
439
861
|
});
|
|
440
862
|
}
|