supadeck 0.0.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.
Files changed (139) hide show
  1. package/README.md +338 -0
  2. package/dist/cli/export.d.ts +7 -0
  3. package/dist/cli/export.js +36 -0
  4. package/dist/cli/export.js.map +1 -0
  5. package/dist/cli/index.d.ts +14 -0
  6. package/dist/cli/index.js +104 -0
  7. package/dist/cli/index.js.map +1 -0
  8. package/dist/cli/serve.d.ts +8 -0
  9. package/dist/cli/serve.js +13 -0
  10. package/dist/cli/serve.js.map +1 -0
  11. package/dist/cli/templates.d.ts +1 -0
  12. package/dist/cli/templates.js +36 -0
  13. package/dist/cli/templates.js.map +1 -0
  14. package/dist/cli/workspace.d.ts +2 -0
  15. package/dist/cli/workspace.js +27 -0
  16. package/dist/cli/workspace.js.map +1 -0
  17. package/dist/content/parse-deck.d.ts +36 -0
  18. package/dist/content/parse-deck.js +137 -0
  19. package/dist/content/parse-deck.js.map +1 -0
  20. package/dist/content/remark-unwrap-jsx-paragraphs.d.ts +7 -0
  21. package/dist/content/remark-unwrap-jsx-paragraphs.js +64 -0
  22. package/dist/content/remark-unwrap-jsx-paragraphs.js.map +1 -0
  23. package/dist/export/pdf.d.ts +6 -0
  24. package/dist/export/pdf.js +41 -0
  25. package/dist/export/pdf.js.map +1 -0
  26. package/dist/index.d.ts +13 -0
  27. package/dist/index.js +12 -0
  28. package/dist/index.js.map +1 -0
  29. package/dist/runtime/App.d.ts +8 -0
  30. package/dist/runtime/App.js +46 -0
  31. package/dist/runtime/App.js.map +1 -0
  32. package/dist/runtime/components/Callout.d.ts +7 -0
  33. package/dist/runtime/components/Callout.js +14 -0
  34. package/dist/runtime/components/Callout.js.map +1 -0
  35. package/dist/runtime/components/Center.d.ts +4 -0
  36. package/dist/runtime/components/Center.js +5 -0
  37. package/dist/runtime/components/Center.js.map +1 -0
  38. package/dist/runtime/components/Columns.d.ts +6 -0
  39. package/dist/runtime/components/Columns.js +5 -0
  40. package/dist/runtime/components/Columns.js.map +1 -0
  41. package/dist/runtime/components/Disclosure.d.ts +6 -0
  42. package/dist/runtime/components/Disclosure.js +6 -0
  43. package/dist/runtime/components/Disclosure.js.map +1 -0
  44. package/dist/runtime/components/Frame.d.ts +5 -0
  45. package/dist/runtime/components/Frame.js +5 -0
  46. package/dist/runtime/components/Frame.js.map +1 -0
  47. package/dist/runtime/components/index.d.ts +8 -0
  48. package/dist/runtime/components/index.js +5 -0
  49. package/dist/runtime/components/index.js.map +1 -0
  50. package/dist/runtime/default-components.d.ts +3 -0
  51. package/dist/runtime/default-components.js +39 -0
  52. package/dist/runtime/default-components.js.map +1 -0
  53. package/dist/runtime/hooks/slides.d.ts +1 -0
  54. package/dist/runtime/hooks/slides.js +46 -0
  55. package/dist/runtime/hooks/slides.js.map +1 -0
  56. package/dist/runtime/index.html +12 -0
  57. package/dist/runtime/layout/DeckSlide.d.ts +2 -0
  58. package/dist/runtime/layout/DeckSlide.js +7 -0
  59. package/dist/runtime/layout/DeckSlide.js.map +1 -0
  60. package/dist/runtime/layout/SlideFrame.d.ts +2 -0
  61. package/dist/runtime/layout/SlideFrame.js +7 -0
  62. package/dist/runtime/layout/SlideFrame.js.map +1 -0
  63. package/dist/runtime/main.d.ts +1 -0
  64. package/dist/runtime/main.js +32 -0
  65. package/dist/runtime/main.js.map +1 -0
  66. package/dist/runtime/mdx-components.d.ts +2 -0
  67. package/dist/runtime/mdx-components.js +17 -0
  68. package/dist/runtime/mdx-components.js.map +1 -0
  69. package/dist/runtime/primitives/DeckChrome.d.ts +7 -0
  70. package/dist/runtime/primitives/DeckChrome.js +7 -0
  71. package/dist/runtime/primitives/DeckChrome.js.map +1 -0
  72. package/dist/runtime/primitives/DeckNavigation.d.ts +6 -0
  73. package/dist/runtime/primitives/DeckNavigation.js +5 -0
  74. package/dist/runtime/primitives/DeckNavigation.js.map +1 -0
  75. package/dist/runtime/primitives/DeckProgress.d.ts +6 -0
  76. package/dist/runtime/primitives/DeckProgress.js +6 -0
  77. package/dist/runtime/primitives/DeckProgress.js.map +1 -0
  78. package/dist/runtime/primitives/DeckTitle.d.ts +5 -0
  79. package/dist/runtime/primitives/DeckTitle.js +5 -0
  80. package/dist/runtime/primitives/DeckTitle.js.map +1 -0
  81. package/dist/runtime/public-components.d.ts +22 -0
  82. package/dist/runtime/public-components.js +24 -0
  83. package/dist/runtime/public-components.js.map +1 -0
  84. package/dist/runtime/styles/base.css +201 -0
  85. package/dist/runtime/tailwind-hmr.d.ts +18 -0
  86. package/dist/runtime/tailwind-hmr.js +68 -0
  87. package/dist/runtime/tailwind-hmr.js.map +1 -0
  88. package/dist/runtime/tailwind-sources.d.ts +4 -0
  89. package/dist/runtime/tailwind-sources.js +43 -0
  90. package/dist/runtime/tailwind-sources.js.map +1 -0
  91. package/dist/runtime/theme-components.d.ts +3 -0
  92. package/dist/runtime/theme-components.js +18 -0
  93. package/dist/runtime/theme-components.js.map +1 -0
  94. package/dist/runtime/theme-resolution.d.ts +2 -0
  95. package/dist/runtime/theme-resolution.js +63 -0
  96. package/dist/runtime/theme-resolution.js.map +1 -0
  97. package/dist/runtime/theme-types.d.ts +48 -0
  98. package/dist/runtime/theme-types.js +2 -0
  99. package/dist/runtime/theme-types.js.map +1 -0
  100. package/dist/runtime/themes/base/DefaultDeck.d.ts +2 -0
  101. package/dist/runtime/themes/base/DefaultDeck.js +11 -0
  102. package/dist/runtime/themes/base/DefaultDeck.js.map +1 -0
  103. package/dist/runtime/themes/base/theme.css +245 -0
  104. package/dist/runtime/themes/default/DefaultDeck.d.ts +2 -0
  105. package/dist/runtime/themes/default/DefaultDeck.js +11 -0
  106. package/dist/runtime/themes/default/DefaultDeck.js.map +1 -0
  107. package/dist/runtime/themes/default/DefaultThemeDeck.d.ts +2 -0
  108. package/dist/runtime/themes/default/DefaultThemeDeck.js +23 -0
  109. package/dist/runtime/themes/default/DefaultThemeDeck.js.map +1 -0
  110. package/dist/runtime/themes/default/components.d.ts +65 -0
  111. package/dist/runtime/themes/default/components.js +80 -0
  112. package/dist/runtime/themes/default/components.js.map +1 -0
  113. package/dist/runtime/themes/default/index.d.ts +4 -0
  114. package/dist/runtime/themes/default/index.js +18 -0
  115. package/dist/runtime/themes/default/index.js.map +1 -0
  116. package/dist/runtime/themes/default/theme.css +577 -0
  117. package/dist/runtime/themes/default.css +10 -0
  118. package/dist/runtime/themes/sunset/index.d.ts +4 -0
  119. package/dist/runtime/themes/sunset/index.js +13 -0
  120. package/dist/runtime/themes/sunset/index.js.map +1 -0
  121. package/dist/runtime/themes/sunset/theme.css +12 -0
  122. package/dist/runtime/themes/sunset.css +10 -0
  123. package/dist/runtime/themes/supabase/SupabaseDeck.d.ts +2 -0
  124. package/dist/runtime/themes/supabase/SupabaseDeck.js +23 -0
  125. package/dist/runtime/themes/supabase/SupabaseDeck.js.map +1 -0
  126. package/dist/runtime/themes/supabase/components.d.ts +65 -0
  127. package/dist/runtime/themes/supabase/components.js +80 -0
  128. package/dist/runtime/themes/supabase/components.js.map +1 -0
  129. package/dist/runtime/themes/supabase/index.d.ts +4 -0
  130. package/dist/runtime/themes/supabase/index.js +17 -0
  131. package/dist/runtime/themes/supabase/index.js.map +1 -0
  132. package/dist/runtime/themes/supabase/theme.css +523 -0
  133. package/dist/runtime/utils/use-current-slide.d.ts +3 -0
  134. package/dist/runtime/utils/use-current-slide.js +20 -0
  135. package/dist/runtime/utils/use-current-slide.js.map +1 -0
  136. package/dist/runtime/vite-config.d.ts +10 -0
  137. package/dist/runtime/vite-config.js +218 -0
  138. package/dist/runtime/vite-config.js.map +1 -0
  139. package/package.json +60 -0
package/README.md ADDED
@@ -0,0 +1,338 @@
1
+ # Supadeck
2
+
3
+ Supadeck is a zero-config presentation toolkit for writing slide decks in MDX. You author your deck in `deck.mdx`, mix Markdown with React components, get a hot-reloading Vite runtime while you edit, pick from built-in themes or bring your own, and export the finished deck to PDF when it is ready to share.
4
+
5
+ ## Quickstart
6
+
7
+ ```bash
8
+ npx supadeck
9
+ ```
10
+
11
+ That single command looks for `deck.mdx` in the current directory, creates `deck.mdx` if it does not exist yet, and starts the local presentation runtime. As you edit the deck or update local components imported from your workspace, the deck reloads immediately.
12
+
13
+ ![Default theme preview](.github/assets/readme/theme-supabase.png)
14
+
15
+ ## Why Supadeck
16
+
17
+ - Write a deck in one `deck.mdx` file.
18
+ - Mix Markdown, JSX, and local React imports in the same slide deck.
19
+ - Use a themeable runtime instead of a fixed presentation shell.
20
+ - Start with built-in themes and switch with frontmatter or `--theme`.
21
+ - Use GitHub Flavored Markdown features like tables, task lists, and strikethrough.
22
+ - Navigate with the keyboard or directly via slide hashes like `#3`.
23
+ - Export the rendered deck to PDF with one command.
24
+
25
+ ## What's Supported
26
+
27
+ ### Authoring
28
+
29
+ - Frontmatter-driven deck config: `title`, `theme`, `aspectRatio`, `showSlideNumbers`, `transition`, and `sections`.
30
+ - Slide content written in MDX with JSX support.
31
+ - Optional import prelude after frontmatter for local components and helpers.
32
+ - Slide boundaries defined by thematic breaks (`---`).
33
+ - Built-in MDX components for headings, lists, tables, callouts, layout helpers, and more.
34
+ - GitHub Flavored Markdown through `remark-gfm`, including tables, task lists, and strikethrough.
35
+
36
+ ### Runtime
37
+
38
+ - Interactive browser presentation runtime powered by Vite and React.
39
+ - Keyboard navigation with `Arrow` keys, `PageUp`, `PageDown`, `Home`, `End`, and `Space`.
40
+ - URL hash navigation so slide state is reflected in the address bar.
41
+ - Theme-controlled deck rendering for both default and custom layouts.
42
+ - Interactive mode for presenting and print mode for export.
43
+
44
+ ### Export
45
+
46
+ - `supadeck export` builds the deck to HTML first, then prints it to PDF.
47
+ - PDF export uses Playwright Chromium in headless mode.
48
+ - Slide backgrounds are preserved during PDF generation.
49
+
50
+ ### Customization
51
+
52
+ - Theme selection by built-in id, relative theme file path, or theme directory.
53
+ - Theme-provided MDX component overrides and custom deck layouts.
54
+ - Workspace component imports inside `deck.mdx`.
55
+ - Theme setup hooks for runtime styling and root-level behavior.
56
+
57
+ ## Built-in Themes
58
+
59
+ Supadeck currently ships with two built-in themes:
60
+
61
+ | Theme | Best for | What makes it distinct |
62
+ | --- | --- | --- |
63
+ | `default` | Branded product or pitch decks | Custom stage layout, footer breadcrumbs, branded components, and optional section navigation. |
64
+ | `sunset` | Brighter keynote-style decks | Reuses the exported `DefaultDeck` shell with a warmer visual treatment and color palette. |
65
+
66
+ ![Default theme preview](.github/assets/readme/theme-supabase.png)
67
+ ![Sunset theme preview](.github/assets/readme/theme-sunset.png)
68
+
69
+ For the `default` theme, `sections` in frontmatter define 1-based inclusive slide ranges.
70
+
71
+ ```yaml
72
+ ---
73
+ title: supalite
74
+ theme: default
75
+ sections:
76
+ - label: Intro
77
+ start: 1
78
+ end: 1
79
+ - label: Goals
80
+ start: 2
81
+ end: 4
82
+ ---
83
+ ```
84
+
85
+ Those ranges are normalized onto the deck and used to render the footer breadcrumb navigation.
86
+
87
+ ![Supabase footer sections preview](.github/assets/readme/supabase-sections.png)
88
+
89
+ ## Quick Deck Authoring
90
+
91
+ Here is a compact `deck.mdx` that shows the core authoring model: frontmatter, a local React import, theme-provided components, GitHub Flavored Markdown, and a code block.
92
+
93
+ ````mdx
94
+ ---
95
+ title: Ship Review
96
+ theme: sunset
97
+ aspectRatio: 16:9
98
+ showSlideNumbers: true
99
+ transition: fade
100
+ ---
101
+
102
+ import ExampleCard from "./ExampleCard.tsx";
103
+
104
+ # Ship Review
105
+
106
+ <Callout tone="accent">
107
+ One file for the whole deck, with local components when you need them.
108
+ </Callout>
109
+
110
+ <Columns
111
+ left={
112
+ <ExampleCard title="Status">
113
+ Ready for internal review.
114
+ </ExampleCard>
115
+ }
116
+ right={
117
+ <Disclosure title="Next step">
118
+ Export a PDF for async feedback.
119
+ </Disclosure>
120
+ }
121
+ />
122
+
123
+ ---
124
+
125
+ ## Rollout snapshot
126
+
127
+ | Area | Status |
128
+ | --- | --- |
129
+ | Runtime | Ready |
130
+ | Theme | Sunset |
131
+ | Export | PDF |
132
+
133
+ - [x] Deck authored in MDX
134
+ - [ ] Final rehearsal
135
+
136
+ ```ts
137
+ export function ship() {
138
+ return "present";
139
+ }
140
+ ```
141
+ ````
142
+
143
+ ## Deck File Format
144
+
145
+ Supadeck reads `deck.mdx` using this model:
146
+
147
+ 1. Optional YAML frontmatter at the top defines deck config.
148
+ 2. An optional import prelude can come immediately after frontmatter.
149
+ 3. Slides are split by thematic breaks written as `---`.
150
+ 4. If no slide separators are present, the full file becomes a single slide.
151
+ 5. Anything imported in the prelude is available inside slide JSX and MDX.
152
+
153
+ Slide splitting is syntax-aware. A literal `---` inside fenced code does not create a new slide.
154
+
155
+ ## CLI Reference
156
+
157
+ ### Start a deck in the current directory
158
+
159
+ ```bash
160
+ npx supadeck
161
+ ```
162
+
163
+ Looks for `./deck.mdx` and scaffolds a starter deck unless you pass `--no-create`.
164
+
165
+ ### Start a deck from a workspace directory
166
+
167
+ ```bash
168
+ npx supadeck ./talks/keynote
169
+ ```
170
+
171
+ If the input has no extension, Supadeck resolves it as `./talks/keynote/deck.mdx`.
172
+
173
+ ### Start with overrides
174
+
175
+ ```bash
176
+ npx supadeck ./talks/keynote --theme sunset --open --port 4000
177
+ ```
178
+
179
+ ### Export the current deck
180
+
181
+ ```bash
182
+ npx supadeck export
183
+ ```
184
+
185
+ Exports to a PDF next to the input deck. For `deck.mdx`, the default output is `deck.pdf`.
186
+
187
+ ### Export a specific deck to a custom path
188
+
189
+ ```bash
190
+ npx supadeck export ./talks/keynote --output keynote.pdf
191
+ ```
192
+
193
+ Supadeck supports these CLI flags today:
194
+
195
+ | Flag | Meaning |
196
+ | --- | --- |
197
+ | `--open` | Open the dev server in a browser. |
198
+ | `--no-create` | Skip starter deck scaffolding in dev mode. |
199
+ | `--port <number>` | Choose the Vite dev server port. |
200
+ | `--output <path>` | Choose the PDF output path during export. |
201
+ | `--theme <id-or-path>` | Override the deck theme from the CLI. |
202
+
203
+ ## Custom Components
204
+
205
+ There are two supported ways to bring custom UI into a deck:
206
+
207
+ 1. Import local components directly inside `deck.mdx`.
208
+ 2. Expose components from a theme via `theme.components`.
209
+
210
+ One way to bring in your own component is a local import:
211
+
212
+ ```mdx
213
+ import ExampleCard from "./ExampleCard.tsx";
214
+
215
+ <ExampleCard title="Local import">
216
+ Your own React component.
217
+ </ExampleCard>
218
+ ```
219
+
220
+ When you edit imported workspace components, Supadeck updates the deck runtime as part of the normal development loop.
221
+
222
+ Themes can also inject components directly into MDX so you can write things like `<Callout />`, `<Disclosure />`, or a theme-specific component such as `<SupabaseMark />` without importing each usage manually.
223
+
224
+ ## GitHub Flavored Markdown
225
+
226
+ Supadeck enables GitHub Flavored Markdown through `remark-gfm`, so the following features work in deck content:
227
+
228
+ ```md
229
+ | Name | Value |
230
+ | --- | --- |
231
+ | Cold start | <1s |
232
+
233
+ ~~deprecated copy~~
234
+
235
+ - [x] Ship deck
236
+ - [ ] Rehearse
237
+
238
+ > This quote renders through the deck's blockquote component.
239
+ ```
240
+
241
+ These features render through the active theme's MDX component mapping, so tables and other elements pick up theme styling instead of falling back to unstyled raw HTML.
242
+
243
+ ## Creating Your Own Theme
244
+
245
+ A custom theme is just a module that matches the `ThemeModule` shape. It can provide a custom deck renderer, MDX components, and a setup hook.
246
+
247
+ Create a theme file such as `./themes/my-theme/index.tsx`:
248
+
249
+ ```tsx
250
+ import type { ThemeModule } from "supadeck";
251
+ import { DefaultDeck, createDefaultComponents } from "supadeck";
252
+ import "./theme.css";
253
+
254
+ const myTheme: ThemeModule = {
255
+ Deck: DefaultDeck,
256
+ components: {
257
+ ...createDefaultComponents(),
258
+ h1: (props) => <h1 className="text-7xl font-black tracking-tight" {...props} />,
259
+ },
260
+ setup({ config, rootElement, helpers }) {
261
+ rootElement.style.setProperty(
262
+ "--slide-aspect-ratio",
263
+ helpers.parseAspectRatio(config.aspectRatio)
264
+ );
265
+ rootElement.dataset.transition = config.transition ?? "fade";
266
+ },
267
+ };
268
+
269
+ export default myTheme;
270
+ ```
271
+
272
+ Then point your deck at it:
273
+
274
+ ```yaml
275
+ ---
276
+ theme: ./themes/my-theme
277
+ ---
278
+ ```
279
+
280
+ Theme resolution supports:
281
+
282
+ - Built-in ids like `default` and `sunset`
283
+ - Relative theme files like `./my-theme.tsx`
284
+ - Theme directories with an `index.tsx`, `index.ts`, `index.jsx`, or `index.js`
285
+
286
+ The `ThemeModule` contract supports these keys:
287
+
288
+ - `Deck` for a custom deck renderer
289
+ - `components` for MDX tag overrides and theme-provided components
290
+ - `setup` for runtime initialization and cleanup
291
+
292
+ Import your CSS from the theme entry so the theme can own its visual system in one place.
293
+
294
+ ## Public Runtime Exports for Theme Authors
295
+
296
+ Supadeck also exports a small toolbox for theme authors:
297
+
298
+ - `createDefaultComponents`
299
+ - `mergeComponents`
300
+ - `useCurrentSlide`
301
+ - `SlideFrame`
302
+ - `DeckSlide`
303
+ - `DeckChrome`
304
+ - `DeckNavigation`
305
+ - `DeckProgress`
306
+ - `DeckTitle`
307
+ - `DefaultDeck`
308
+ - `Callout`
309
+ - `Columns`
310
+ - `Disclosure`
311
+ - `Frame`
312
+
313
+ `DefaultDeck` is the reusable base deck shell used by `sunset` and available to custom theme authors as a building block.
314
+
315
+ ## Exporting to PDF
316
+
317
+ ```bash
318
+ npx supadeck export
319
+ ```
320
+
321
+ Export runs the deck in print mode, builds the static HTML output, opens it in headless Chromium, and writes a PDF with backgrounds enabled.
322
+
323
+ If Chromium is not available locally, install it first:
324
+
325
+ ```bash
326
+ npx playwright install chromium
327
+ ```
328
+
329
+ ## Limits / Current Boundaries
330
+
331
+ - PDF export depends on Playwright Chromium being installed and available locally.
332
+ - Only the documented built-in themes ship with the package.
333
+ - Supadeck supports the current theme transition model; it does not currently document speaker notes, presenter tools, remote control, or richer animation systems.
334
+
335
+ ## Examples
336
+
337
+ - [`examples/dev/deck.mdx`](examples/dev/deck.mdx)
338
+ - [`examples/default/deck.mdx`](examples/default/deck.mdx)
@@ -0,0 +1,7 @@
1
+ interface RunExportOptions {
2
+ deckPath: string;
3
+ outputPath: string;
4
+ themeOverride?: string;
5
+ }
6
+ export declare function runExport({ deckPath, outputPath, themeOverride, }: RunExportOptions): Promise<void>;
7
+ export {};
@@ -0,0 +1,36 @@
1
+ import { build, preview } from "vite";
2
+ import { exportDeckToPdf } from "../export/pdf.js";
3
+ import { createSupadeckViteConfig } from "../runtime/vite-config.js";
4
+ export async function runExport({ deckPath, outputPath, themeOverride, }) {
5
+ const config = createSupadeckViteConfig({
6
+ deckPath,
7
+ themeOverride,
8
+ outputDirName: ".supadeck-dist",
9
+ });
10
+ await build(config);
11
+ const previewServer = await preview({
12
+ ...config,
13
+ preview: {
14
+ host: "127.0.0.1",
15
+ port: 4173,
16
+ strictPort: false,
17
+ },
18
+ });
19
+ const urls = previewServer.resolvedUrls?.local ?? [];
20
+ const baseUrl = urls[0];
21
+ if (!baseUrl) {
22
+ await previewServer.httpServer?.close();
23
+ throw new Error("Unable to determine preview URL for PDF export.");
24
+ }
25
+ try {
26
+ await exportDeckToPdf({
27
+ url: `${baseUrl}?print=1`,
28
+ outputPath,
29
+ });
30
+ }
31
+ finally {
32
+ await previewServer.httpServer?.close();
33
+ }
34
+ console.log(`[supadeck] PDF exported to ${outputPath}`);
35
+ }
36
+ //# sourceMappingURL=export.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"export.js","sourceRoot":"","sources":["../../src/cli/export.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AACtC,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAAE,wBAAwB,EAAE,MAAM,2BAA2B,CAAC;AAQrE,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,EAC7B,QAAQ,EACR,UAAU,EACV,aAAa,GACG;IAChB,MAAM,MAAM,GAAG,wBAAwB,CAAC;QACrC,QAAQ;QACR,aAAa;QACb,aAAa,EAAE,gBAAgB;KACjC,CAAC,CAAC;IAEH,MAAM,KAAK,CAAC,MAAM,CAAC,CAAC;IAEpB,MAAM,aAAa,GAAG,MAAM,OAAO,CAAC;QACjC,GAAG,MAAM;QACT,OAAO,EAAE;YACN,IAAI,EAAE,WAAW;YACjB,IAAI,EAAE,IAAI;YACV,UAAU,EAAE,KAAK;SACnB;KACH,CAAC,CAAC;IAEH,MAAM,IAAI,GAAG,aAAa,CAAC,YAAY,EAAE,KAAK,IAAI,EAAE,CAAC;IACrD,MAAM,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;IAExB,IAAI,CAAC,OAAO,EAAE,CAAC;QACZ,MAAM,aAAa,CAAC,UAAU,EAAE,KAAK,EAAE,CAAC;QACxC,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC;IACtE,CAAC;IAED,IAAI,CAAC;QACF,MAAM,eAAe,CAAC;YACnB,GAAG,EAAE,GAAG,OAAO,UAAU;YACzB,UAAU;SACZ,CAAC,CAAC;IACN,CAAC;YAAS,CAAC;QACR,MAAM,aAAa,CAAC,UAAU,EAAE,KAAK,EAAE,CAAC;IAC3C,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,8BAA8B,UAAU,EAAE,CAAC,CAAC;AAC3D,CAAC"}
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env node
2
+ export interface CliOptions {
3
+ open: boolean;
4
+ create: boolean;
5
+ port: number | undefined;
6
+ output: string | undefined;
7
+ theme: string | undefined;
8
+ input: string | undefined;
9
+ }
10
+ export interface ParsedArguments {
11
+ command: "dev" | "export";
12
+ options: CliOptions;
13
+ }
14
+ export declare function parseArguments(argv: string[]): ParsedArguments;
@@ -0,0 +1,104 @@
1
+ #!/usr/bin/env node
2
+ import path from "node:path";
3
+ import process from "node:process";
4
+ import { pathToFileURL } from "node:url";
5
+ import { runDevServer } from "./serve.js";
6
+ import { runExport } from "./export.js";
7
+ import { ensureStarterDeck, resolveDeckPath } from "./workspace.js";
8
+ export function parseArguments(argv) {
9
+ const args = [...argv];
10
+ const command = args[0] === "export" ? "export" : "dev";
11
+ if (command === "export") {
12
+ args.shift();
13
+ }
14
+ const options = {
15
+ open: false,
16
+ create: true,
17
+ port: undefined,
18
+ output: undefined,
19
+ theme: undefined,
20
+ input: undefined,
21
+ };
22
+ while (args.length > 0) {
23
+ const token = args.shift();
24
+ if (!token) {
25
+ continue;
26
+ }
27
+ if (token === "--open") {
28
+ options.open = true;
29
+ continue;
30
+ }
31
+ if (token === "--no-create") {
32
+ options.create = false;
33
+ continue;
34
+ }
35
+ if (token === "--port") {
36
+ const value = args.shift();
37
+ options.port = value ? Number(value) : undefined;
38
+ continue;
39
+ }
40
+ if (token.startsWith("--port=")) {
41
+ options.port = Number(token.slice("--port=".length));
42
+ continue;
43
+ }
44
+ if (token === "--output") {
45
+ options.output = args.shift();
46
+ continue;
47
+ }
48
+ if (token.startsWith("--output=")) {
49
+ options.output = token.slice("--output=".length);
50
+ continue;
51
+ }
52
+ if (token === "--theme") {
53
+ options.theme = args.shift();
54
+ continue;
55
+ }
56
+ if (token.startsWith("--theme=")) {
57
+ options.theme = token.slice("--theme=".length);
58
+ continue;
59
+ }
60
+ if (token.startsWith("--")) {
61
+ throw new Error(`Unknown option: ${token}`);
62
+ }
63
+ if (!options.input) {
64
+ options.input = token;
65
+ continue;
66
+ }
67
+ throw new Error(`Unexpected argument: ${token}`);
68
+ }
69
+ return { command, options };
70
+ }
71
+ async function main() {
72
+ const { command, options } = parseArguments(process.argv.slice(2));
73
+ const deckPath = resolveDeckPath(options.input, process.cwd(), process.env.SUPADECK_DEFAULT_INPUT);
74
+ if (command === "dev" && options.create) {
75
+ await ensureStarterDeck(deckPath);
76
+ }
77
+ if (command === "export") {
78
+ await runExport({
79
+ deckPath,
80
+ outputPath: options.output
81
+ ? path.resolve(process.cwd(), options.output)
82
+ : path.resolve(path.dirname(deckPath), `${path.basename(deckPath, path.extname(deckPath))}.pdf`),
83
+ themeOverride: options.theme,
84
+ });
85
+ return;
86
+ }
87
+ await runDevServer({
88
+ deckPath,
89
+ port: options.port,
90
+ open: options.open,
91
+ themeOverride: options.theme,
92
+ });
93
+ }
94
+ if (process.argv[1] &&
95
+ pathToFileURL(process.argv[1]).href === import.meta.url) {
96
+ main().catch((error) => {
97
+ console.error(`\n[supadeck] ${error instanceof Error ? error.message : String(error)}`);
98
+ if (process.env.DEBUG) {
99
+ console.error(error);
100
+ }
101
+ process.exitCode = 1;
102
+ });
103
+ }
104
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ interface RunDevServerOptions {
2
+ deckPath: string;
3
+ port?: number;
4
+ open?: boolean;
5
+ themeOverride?: string;
6
+ }
7
+ export declare function runDevServer({ deckPath, port, open, themeOverride, }: RunDevServerOptions): Promise<void>;
8
+ export {};
@@ -0,0 +1,13 @@
1
+ import { createServer } from "vite";
2
+ import { createSupadeckViteConfig } from "../runtime/vite-config.js";
3
+ export async function runDevServer({ deckPath, port, open, themeOverride, }) {
4
+ const server = await createServer(createSupadeckViteConfig({
5
+ deckPath,
6
+ port,
7
+ open,
8
+ themeOverride,
9
+ }));
10
+ await server.listen();
11
+ server.printUrls();
12
+ }
13
+ //# sourceMappingURL=serve.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"serve.js","sourceRoot":"","sources":["../../src/cli/serve.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,MAAM,CAAC;AACpC,OAAO,EAAE,wBAAwB,EAAE,MAAM,2BAA2B,CAAC;AASrE,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,EAChC,QAAQ,EACR,IAAI,EACJ,IAAI,EACJ,aAAa,GACM;IACnB,MAAM,MAAM,GAAG,MAAM,YAAY,CAC9B,wBAAwB,CAAC;QACtB,QAAQ;QACR,IAAI;QACJ,IAAI;QACJ,aAAa;KACf,CAAC,CACJ,CAAC;IAEF,MAAM,MAAM,CAAC,MAAM,EAAE,CAAC;IACtB,MAAM,CAAC,SAAS,EAAE,CAAC;AACtB,CAAC"}
@@ -0,0 +1 @@
1
+ export declare function starterDeckTemplate(): string;
@@ -0,0 +1,36 @@
1
+ export function starterDeckTemplate() {
2
+ return `---
3
+ title: Supadeck
4
+ theme: default
5
+ aspectRatio: 16:9
6
+ showSlideNumbers: true
7
+ transition: fade
8
+ ---
9
+
10
+ # Supadeck
11
+
12
+ Write presentations in one \`deck.mdx\` file.
13
+
14
+ <Callout tone="accent">
15
+ Edit this file and the deck will hot reload automatically.
16
+ </Callout>
17
+
18
+ ---
19
+
20
+ ## Custom components
21
+
22
+ <Columns
23
+ left={<Frame label="Local imports">Import your own React components only when you need them.</Frame>}
24
+ right={<Disclosure title="Theme-provided components">Themes can expose components directly to MDX.</Disclosure>}
25
+ />
26
+
27
+ ---
28
+
29
+ ## Export
30
+
31
+ - Run \`npx supadeck export\`
32
+ - The deck is rendered as HTML first
33
+ - Then exported to PDF with headless Chromium
34
+ `;
35
+ }
36
+ //# sourceMappingURL=templates.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"templates.js","sourceRoot":"","sources":["../../src/cli/templates.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,mBAAmB;IAChC,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgCT,CAAC;AACF,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function resolveDeckPath(input?: string, cwd?: string, defaultInput?: string): string;
2
+ export declare function ensureStarterDeck(deckPath: string): Promise<void>;
@@ -0,0 +1,27 @@
1
+ import fs from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ import { starterDeckTemplate } from './templates.js';
4
+ export function resolveDeckPath(input, cwd = process.cwd(), defaultInput) {
5
+ const resolvedInput = input ?? defaultInput;
6
+ if (!resolvedInput) {
7
+ return path.resolve(cwd, 'deck.mdx');
8
+ }
9
+ const candidate = path.resolve(cwd, resolvedInput);
10
+ if (path.extname(candidate)) {
11
+ return candidate;
12
+ }
13
+ return path.join(candidate, 'deck.mdx');
14
+ }
15
+ async function writeFileIfMissing(filePath, contents) {
16
+ try {
17
+ await fs.access(filePath);
18
+ }
19
+ catch {
20
+ await fs.mkdir(path.dirname(filePath), { recursive: true });
21
+ await fs.writeFile(filePath, contents, 'utf8');
22
+ }
23
+ }
24
+ export async function ensureStarterDeck(deckPath) {
25
+ await writeFileIfMissing(deckPath, starterDeckTemplate());
26
+ }
27
+ //# sourceMappingURL=workspace.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workspace.js","sourceRoot":"","sources":["../../src/cli/workspace.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAErD,MAAM,UAAU,eAAe,CAC7B,KAAc,EACd,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,EACnB,YAAqB;IAErB,MAAM,aAAa,GAAG,KAAK,IAAI,YAAY,CAAC;IAE5C,IAAI,CAAC,aAAa,EAAE,CAAC;QACnB,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC;IACvC,CAAC;IAED,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,aAAa,CAAC,CAAC;IACnD,IAAI,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC;QAC5B,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,OAAO,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;AAC1C,CAAC;AAED,KAAK,UAAU,kBAAkB,CAAC,QAAgB,EAAE,QAAgB;IAClE,IAAI,CAAC;QACH,MAAM,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAC5B,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC5D,MAAM,EAAE,CAAC,SAAS,CAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC;IACjD,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,QAAgB;IACtD,MAAM,kBAAkB,CAAC,QAAQ,EAAE,mBAAmB,EAAE,CAAC,CAAC;AAC5D,CAAC"}
@@ -0,0 +1,36 @@
1
+ import type React from 'react';
2
+ export interface DeckConfig {
3
+ title: string;
4
+ theme: string;
5
+ aspectRatio: string;
6
+ showSlideNumbers: boolean;
7
+ transition: 'none' | 'fade' | 'slide' | string;
8
+ sections?: DeckSection[];
9
+ }
10
+ export interface DeckSection {
11
+ label: string;
12
+ start: number;
13
+ end: number;
14
+ }
15
+ export interface DeckSlide {
16
+ index: number;
17
+ body: string;
18
+ }
19
+ export interface ParsedDeck {
20
+ frontmatter: Record<string, unknown>;
21
+ config: DeckConfig;
22
+ prelude: string;
23
+ slides: DeckSlide[];
24
+ rawContent: string;
25
+ }
26
+ export interface DeckModule extends Omit<ParsedDeck, 'prelude' | 'rawContent' | 'frontmatter'> {
27
+ slides: Array<DeckSlide & {
28
+ Component: React.ComponentType<{
29
+ components?: Record<string, React.ComponentType<any>>;
30
+ }>;
31
+ }>;
32
+ }
33
+ export declare function normalizeDeckConfig(frontmatter?: Record<string, unknown>, themeOverride?: string): DeckConfig;
34
+ export declare function parseDeck(source: string, options?: {
35
+ themeOverride?: string;
36
+ }): ParsedDeck;