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