vite-plugin-react-deck 1.1.5 → 1.4.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/config.d.ts +1 -1
- package/helpers.d.ts +25 -2
- package/index.cjs +562 -144
- package/index.d.ts +2 -2
- package/index.mjs +563 -145
- 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 +10 -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} />
|
|
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;
|
|
@@ -111,12 +511,12 @@ ${slide}
|
|
|
111
511
|
frontmatterForNextSlide = null;
|
|
112
512
|
}
|
|
113
513
|
const compiledSlides = await Promise.all(
|
|
114
|
-
enrichedSlides.map(async (slide,
|
|
514
|
+
enrichedSlides.map(async (slide, _index) => {
|
|
115
515
|
const code = addInlineModules(slide.content, inlineModules);
|
|
116
516
|
const normalizedCode = code.replace("process.env", "process\u200B.env");
|
|
117
517
|
const result = await (0, import_mdx.compile)(normalizedCode, {
|
|
118
518
|
outputFormat: "program",
|
|
119
|
-
jsx:
|
|
519
|
+
jsx: false,
|
|
120
520
|
providerImportSource: "@mdx-js/react",
|
|
121
521
|
...options,
|
|
122
522
|
remarkPlugins: [
|
|
@@ -127,7 +527,7 @@ ${slide}
|
|
|
127
527
|
]
|
|
128
528
|
});
|
|
129
529
|
const mainCode = extractMainCodeAsChildren(result.value.toString(), {
|
|
130
|
-
isJsx:
|
|
530
|
+
isJsx: false
|
|
131
531
|
});
|
|
132
532
|
return {
|
|
133
533
|
...slide,
|
|
@@ -138,7 +538,8 @@ ${slide}
|
|
|
138
538
|
const output = addInlineModules(
|
|
139
539
|
`
|
|
140
540
|
import React from 'react';
|
|
141
|
-
|
|
541
|
+
import {Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs} from "react/jsx-runtime";
|
|
542
|
+
import {useMDXComponents as _provideComponents} from "@mdx-js/react";
|
|
142
543
|
|
|
143
544
|
${compiledSlides.map(
|
|
144
545
|
(slide, index) => `
|
|
@@ -163,7 +564,7 @@ Deck.slides = [
|
|
|
163
564
|
`,
|
|
164
565
|
inlineModules
|
|
165
566
|
);
|
|
166
|
-
|
|
567
|
+
import_node_fs.default.writeFileSync("slides.js", output);
|
|
167
568
|
return output;
|
|
168
569
|
}
|
|
169
570
|
var MOD_REG = /\\`|`(?:\\`|[^`])*`|(^(?:import|export).*$)/gm;
|
|
@@ -191,117 +592,20 @@ function normalizeNewline(input) {
|
|
|
191
592
|
return input.replace(new RegExp(CRLF, "g"), "\n");
|
|
192
593
|
}
|
|
193
594
|
|
|
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
595
|
// src/config.ts
|
|
293
596
|
var import_lodash = __toESM(require("lodash"), 1);
|
|
294
597
|
|
|
295
598
|
// src/types.ts
|
|
296
599
|
var import_zod = require("zod");
|
|
297
600
|
var PestacleConfigSchema = import_zod.z.object({
|
|
298
|
-
theme: import_zod.z.enum(["green", "purple"]).default("green")
|
|
601
|
+
theme: import_zod.z.enum(["green", "purple", "solarized-light"]).default("green"),
|
|
602
|
+
startupPage: import_zod.z.boolean().optional()
|
|
299
603
|
});
|
|
300
604
|
|
|
301
605
|
// src/index.ts
|
|
302
|
-
async function checkIfDirectoryExists(
|
|
606
|
+
async function checkIfDirectoryExists(path) {
|
|
303
607
|
try {
|
|
304
|
-
await fs2.access(
|
|
608
|
+
await fs2.access(path);
|
|
305
609
|
return true;
|
|
306
610
|
} catch {
|
|
307
611
|
return false;
|
|
@@ -314,15 +618,45 @@ async function findDecks({ port }) {
|
|
|
314
618
|
deckUrl: `http://localhost:${port}/${deck.replace("src/", "").replace("deck.mdx", "")}`
|
|
315
619
|
}));
|
|
316
620
|
}
|
|
317
|
-
async function
|
|
621
|
+
async function extractDeckMeta(filePath) {
|
|
622
|
+
try {
|
|
623
|
+
const raw = await fs2.readFile(filePath, "utf-8");
|
|
624
|
+
const { data, content } = (0, import_gray_matter2.default)(raw);
|
|
625
|
+
const slides = content.split("---\n");
|
|
626
|
+
const LAYOUT_REGEX = /\S*\nlayout: (.*)/g;
|
|
627
|
+
let slideCount = 0;
|
|
628
|
+
for (const slide of slides) {
|
|
629
|
+
if (!LAYOUT_REGEX.test(slide) && slide.trim().length > 0) {
|
|
630
|
+
slideCount++;
|
|
631
|
+
}
|
|
632
|
+
LAYOUT_REGEX.lastIndex = 0;
|
|
633
|
+
}
|
|
634
|
+
let title = data.title;
|
|
635
|
+
if (!title) {
|
|
636
|
+
const headingMatch = content.match(/^#\s+\*{0,2}(.+?)\*{0,2}\s*$/m);
|
|
637
|
+
if (headingMatch) {
|
|
638
|
+
title = headingMatch[1].replace(/\*+/g, "").trim();
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
return {
|
|
642
|
+
title,
|
|
643
|
+
author: data.author,
|
|
644
|
+
date: data.date,
|
|
645
|
+
description: data.description,
|
|
646
|
+
slideCount
|
|
647
|
+
};
|
|
648
|
+
} catch {
|
|
649
|
+
return { slideCount: 0 };
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
async function fileExists(_name, path) {
|
|
318
653
|
const candidateExts = [".ts", ".tsx", ".js", ".jsx"];
|
|
319
654
|
for await (const ext of candidateExts) {
|
|
320
|
-
const fullPath = `${
|
|
655
|
+
const fullPath = `${path}${ext}`;
|
|
321
656
|
try {
|
|
322
657
|
await fs2.access(fullPath);
|
|
323
658
|
return fullPath.replace(/^\./, "");
|
|
324
659
|
} catch {
|
|
325
|
-
continue;
|
|
326
660
|
}
|
|
327
661
|
}
|
|
328
662
|
}
|
|
@@ -334,30 +668,37 @@ async function loadCustomConfig() {
|
|
|
334
668
|
}
|
|
335
669
|
var src_default = async (options) => {
|
|
336
670
|
let isProd = false;
|
|
671
|
+
const showStartupPage = options.startupPage;
|
|
337
672
|
const deckConfig = {
|
|
338
673
|
decks: []
|
|
339
674
|
};
|
|
340
675
|
return {
|
|
341
676
|
name: "react-deck",
|
|
342
|
-
async config(config) {
|
|
343
|
-
var _a, _b
|
|
677
|
+
async config(config, env) {
|
|
678
|
+
var _a, _b;
|
|
344
679
|
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
|
-
|
|
680
|
+
const inputs = ((_b = (_a = config.build) == null ? void 0 : _a.rolldownOptions) == null ? void 0 : _b.input) || {};
|
|
681
|
+
deckConfig.decks = decks.map((deck) => {
|
|
682
|
+
const name = deck.replace("./src/", "").replace("/deck.mdx", "").replace(/\//g, " / ");
|
|
683
|
+
return {
|
|
684
|
+
originalFile: deck,
|
|
685
|
+
index: deck.replace("/deck.mdx", "/index.html").replace("src/", ""),
|
|
686
|
+
name
|
|
687
|
+
};
|
|
688
|
+
});
|
|
689
|
+
const isProduction = env.mode === "production";
|
|
690
|
+
const startupPageEnabled = showStartupPage !== void 0 ? showStartupPage : !isProduction;
|
|
691
|
+
const newInputs = decks.map((deck) => {
|
|
351
692
|
const deckPath = deck.replace("/deck.mdx", "");
|
|
352
|
-
return
|
|
353
|
-
}
|
|
693
|
+
return `${deckPath.replace("src/", "")}/index.html`;
|
|
694
|
+
});
|
|
695
|
+
if (startupPageEnabled) {
|
|
696
|
+
newInputs.unshift("index.html");
|
|
697
|
+
}
|
|
354
698
|
const finalInputs = typeof inputs === "string" ? [inputs, ...decks] : Array.isArray(inputs) ? [...inputs, ...decks] : { ...inputs, ...newInputs };
|
|
355
699
|
return {
|
|
356
|
-
...config,
|
|
357
700
|
build: {
|
|
358
|
-
|
|
359
|
-
rollupOptions: {
|
|
360
|
-
...(_c = config.build) == null ? void 0 : _c.rollupOptions,
|
|
701
|
+
rolldownOptions: {
|
|
361
702
|
input: finalInputs
|
|
362
703
|
}
|
|
363
704
|
}
|
|
@@ -367,6 +708,9 @@ var src_default = async (options) => {
|
|
|
367
708
|
isProd = config.isProduction;
|
|
368
709
|
},
|
|
369
710
|
resolveId(id) {
|
|
711
|
+
if (id === "index.html" || id === "__decks.tsx" || id === "/__decks.tsx") {
|
|
712
|
+
return id.replace(/^\//, "");
|
|
713
|
+
}
|
|
370
714
|
if (deckConfig.decks.some((deck) => deck.index === id)) {
|
|
371
715
|
return id;
|
|
372
716
|
}
|
|
@@ -378,6 +722,27 @@ var src_default = async (options) => {
|
|
|
378
722
|
}
|
|
379
723
|
},
|
|
380
724
|
async load(id) {
|
|
725
|
+
const shouldShowStartupPage = showStartupPage !== void 0 ? showStartupPage : !isProd;
|
|
726
|
+
if (id === "index.html" && shouldShowStartupPage) {
|
|
727
|
+
return createDecksIndexFile();
|
|
728
|
+
}
|
|
729
|
+
if (id === "__decks.tsx") {
|
|
730
|
+
const decks = await Promise.all(
|
|
731
|
+
deckConfig.decks.map(async (d) => {
|
|
732
|
+
const meta = await extractDeckMeta(d.originalFile);
|
|
733
|
+
return {
|
|
734
|
+
name: d.name,
|
|
735
|
+
path: `/${d.index.replace("/index.html", "/")}`,
|
|
736
|
+
title: meta.title,
|
|
737
|
+
author: meta.author,
|
|
738
|
+
date: meta.date,
|
|
739
|
+
description: meta.description,
|
|
740
|
+
slideCount: meta.slideCount
|
|
741
|
+
};
|
|
742
|
+
})
|
|
743
|
+
);
|
|
744
|
+
return createDecksPageFile({ decks, theme: options.theme });
|
|
745
|
+
}
|
|
381
746
|
const config = await loadCustomConfig();
|
|
382
747
|
const deck = deckConfig.decks.find((deck2) => deck2.index === id);
|
|
383
748
|
if (deck) {
|
|
@@ -387,18 +752,27 @@ var src_default = async (options) => {
|
|
|
387
752
|
}
|
|
388
753
|
if (id.endsWith("__deck.tsx")) {
|
|
389
754
|
const directory = id.replace("/__deck.tsx", "");
|
|
390
|
-
const
|
|
391
|
-
const
|
|
392
|
-
if (!await checkIfDirectoryExists(
|
|
393
|
-
|
|
755
|
+
const dir = directory.startsWith(".") ? directory : `./${directory}`;
|
|
756
|
+
const deckMdxPath = `${dir}/deck.mdx`;
|
|
757
|
+
if (!await checkIfDirectoryExists(deckMdxPath)) {
|
|
758
|
+
this.warn(`No deck.mdx file found in ${deckMdxPath}`);
|
|
394
759
|
return;
|
|
395
760
|
}
|
|
761
|
+
let deckTheme;
|
|
762
|
+
try {
|
|
763
|
+
const raw = await fs2.readFile(deckMdxPath, "utf-8");
|
|
764
|
+
const { data: data2 } = (0, import_gray_matter2.default)(raw);
|
|
765
|
+
if (typeof data2.theme === "string") {
|
|
766
|
+
deckTheme = data2.theme;
|
|
767
|
+
}
|
|
768
|
+
} catch {
|
|
769
|
+
}
|
|
396
770
|
const contentIndex = createAppDeckFile({
|
|
397
771
|
slidePath: `${directory}/deck.mdx`,
|
|
398
772
|
theme: options.theme,
|
|
773
|
+
deckTheme,
|
|
399
774
|
config
|
|
400
775
|
});
|
|
401
|
-
console.log({ contentIndex });
|
|
402
776
|
return contentIndex;
|
|
403
777
|
}
|
|
404
778
|
if (!id.endsWith("deck.mdx")) {
|
|
@@ -409,32 +783,76 @@ var src_default = async (options) => {
|
|
|
409
783
|
production: isProd,
|
|
410
784
|
...options
|
|
411
785
|
});
|
|
412
|
-
const dir = import_node_path.default.relative(process.cwd(), id);
|
|
413
786
|
return data;
|
|
414
787
|
},
|
|
415
788
|
transformIndexHtml: {
|
|
416
789
|
order: "pre",
|
|
417
|
-
|
|
418
|
-
transform: async (html, ctx) => {
|
|
790
|
+
handler: async (html, ctx) => {
|
|
419
791
|
var _a;
|
|
420
792
|
const originalUrl = ((_a = ctx.originalUrl) == null ? void 0 : _a.split("?")[0]) || "";
|
|
793
|
+
if (originalUrl === "/" || originalUrl === "") {
|
|
794
|
+
const shouldShow = showStartupPage !== void 0 ? showStartupPage : !isProd;
|
|
795
|
+
if (shouldShow) {
|
|
796
|
+
return html.replace("__SCRIPT__", `__decks.tsx`);
|
|
797
|
+
}
|
|
798
|
+
}
|
|
421
799
|
const deckDir = ctx.path.replace("/index.html", "");
|
|
422
800
|
const dir = originalUrl ? `./src${originalUrl}` : `.${deckDir}`;
|
|
423
|
-
const
|
|
424
|
-
if (
|
|
425
|
-
|
|
801
|
+
const deckPath = `${dir}/deck.mdx`;
|
|
802
|
+
if (await checkIfDirectoryExists(deckPath)) {
|
|
803
|
+
const resolvedDeckPath = dir.startsWith(".") ? dir : `.${dir}`;
|
|
804
|
+
return html.replace("__SCRIPT__", `${resolvedDeckPath}/__deck.tsx`);
|
|
426
805
|
}
|
|
427
|
-
const
|
|
428
|
-
|
|
806
|
+
const decks = await glob.glob("./src/**/deck.mdx");
|
|
807
|
+
const deckLinks = decks.map((d) => {
|
|
808
|
+
const url = `/${d.replace("src/", "").replace("/deck.mdx", "")}/`;
|
|
809
|
+
const name = d.replace("src/", "").replace("/deck.mdx", "");
|
|
810
|
+
return `<li><a href="${url}">${name}</a></li>`;
|
|
811
|
+
}).join("\n");
|
|
812
|
+
return html.replace('<script type="module" src="__SCRIPT__"></script>', "").replace(
|
|
813
|
+
'<div id="root"></div>',
|
|
814
|
+
`<div id="root">
|
|
815
|
+
<h1>Available Decks</h1>
|
|
816
|
+
<ul>${deckLinks}</ul>
|
|
817
|
+
</div>`
|
|
818
|
+
);
|
|
429
819
|
}
|
|
430
820
|
},
|
|
431
821
|
configureServer(server) {
|
|
432
822
|
var _a;
|
|
823
|
+
const shouldShow = showStartupPage !== void 0 ? showStartupPage : true;
|
|
824
|
+
if (shouldShow) {
|
|
825
|
+
server.middlewares.use(async (req, res, next) => {
|
|
826
|
+
var _a2;
|
|
827
|
+
const url = ((_a2 = req.url) == null ? void 0 : _a2.split("?")[0]) || "";
|
|
828
|
+
if (url === "/" || url === "/index.html") {
|
|
829
|
+
const html = createDecksIndexFile();
|
|
830
|
+
const transformed = await server.transformIndexHtml(
|
|
831
|
+
url,
|
|
832
|
+
html,
|
|
833
|
+
req.originalUrl
|
|
834
|
+
);
|
|
835
|
+
res.setHeader("Content-Type", "text/html");
|
|
836
|
+
res.statusCode = 200;
|
|
837
|
+
res.end(transformed);
|
|
838
|
+
return;
|
|
839
|
+
}
|
|
840
|
+
next();
|
|
841
|
+
});
|
|
842
|
+
}
|
|
433
843
|
(_a = server.httpServer) == null ? void 0 : _a.once("listening", async () => {
|
|
434
844
|
const port = server.config.server.port || 5173;
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
845
|
+
if (shouldShow) {
|
|
846
|
+
server.config.logger.info(
|
|
847
|
+
`
|
|
848
|
+
Decks available at http://localhost:${port}/
|
|
849
|
+
`
|
|
850
|
+
);
|
|
851
|
+
} else {
|
|
852
|
+
const decks = await findDecks({ port });
|
|
853
|
+
for (const deck of decks) {
|
|
854
|
+
server.config.logger.info(`Deck available at ${deck.deckUrl}`);
|
|
855
|
+
}
|
|
438
856
|
}
|
|
439
857
|
});
|
|
440
858
|
}
|