mdeck 2.3.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.
Files changed (268) hide show
  1. package/CHANGELOG.md +259 -0
  2. package/LICENSE +21 -0
  3. package/README.md +156 -0
  4. package/assets/base.css +196 -0
  5. package/assets/extensions/layouts/chapter/extension.toml +26 -0
  6. package/assets/extensions/layouts/chapter/layout.jsx +21 -0
  7. package/assets/extensions/layouts/chapter/starter.md +8 -0
  8. package/assets/extensions/layouts/focus/extension.toml +8 -0
  9. package/assets/extensions/layouts/focus/layout.jsx +10 -0
  10. package/assets/extensions/layouts/focus/starter.md +4 -0
  11. package/assets/extensions/layouts/full-bleed-image/extension.toml +31 -0
  12. package/assets/extensions/layouts/full-bleed-image/layout.jsx +19 -0
  13. package/assets/extensions/layouts/full-bleed-image/starter.md +6 -0
  14. package/assets/extensions/layouts/generic/extension.toml +8 -0
  15. package/assets/extensions/layouts/generic/layout.jsx +8 -0
  16. package/assets/extensions/layouts/generic/starter.md +4 -0
  17. package/assets/extensions/layouts/image-text/extension.toml +25 -0
  18. package/assets/extensions/layouts/image-text/layout.jsx +17 -0
  19. package/assets/extensions/layouts/image-text/starter.md +6 -0
  20. package/assets/extensions/layouts/split/extension.toml +25 -0
  21. package/assets/extensions/layouts/split/layout.jsx +19 -0
  22. package/assets/extensions/layouts/split/starter.md +14 -0
  23. package/assets/extensions/layouts/title/extension.toml +26 -0
  24. package/assets/extensions/layouts/title/layout.jsx +14 -0
  25. package/assets/extensions/layouts/title/starter.md +5 -0
  26. package/assets/extensions/palettes/brand/extension.toml +29 -0
  27. package/assets/extensions/palettes/cobalt/extension.toml +27 -0
  28. package/assets/extensions/palettes/ember/extension.toml +27 -0
  29. package/assets/extensions/palettes/forest/extension.toml +27 -0
  30. package/assets/extensions/palettes/graphite/extension.toml +27 -0
  31. package/assets/extensions/palettes/lagoon/extension.toml +27 -0
  32. package/assets/extensions/palettes/neon/extension.toml +27 -0
  33. package/assets/extensions/palettes/nordic/extension.toml +27 -0
  34. package/assets/extensions/palettes/pastel/extension.toml +30 -0
  35. package/assets/extensions/palettes/phosphor/extension.toml +27 -0
  36. package/assets/extensions/palettes/swiss/extension.toml +27 -0
  37. package/assets/extensions/palettes/terra/extension.toml +27 -0
  38. package/assets/extensions/themes/academic/extension.toml +53 -0
  39. package/assets/extensions/themes/academic/styles.css +631 -0
  40. package/assets/extensions/themes/aurora/extension.toml +37 -0
  41. package/assets/extensions/themes/aurora/styles.css +644 -0
  42. package/assets/extensions/themes/duet/extension.toml +46 -0
  43. package/assets/extensions/themes/duet/styles.css +573 -0
  44. package/assets/extensions/themes/editorial/extension.toml +46 -0
  45. package/assets/extensions/themes/editorial/styles.css +574 -0
  46. package/assets/extensions/themes/fhnw/extension.toml +61 -0
  47. package/assets/extensions/themes/fhnw/styles.css +604 -0
  48. package/assets/extensions/themes/neue/extension.toml +46 -0
  49. package/assets/extensions/themes/neue/styles.css +489 -0
  50. package/assets/extensions/themes/sketch/extension.toml +48 -0
  51. package/assets/extensions/themes/sketch/styles.css +633 -0
  52. package/assets/extensions/themes/terminal/extension.toml +38 -0
  53. package/assets/extensions/themes/terminal/styles.css +550 -0
  54. package/assets/logo/avatar.png +0 -0
  55. package/assets/logo/logo-dark.svg +10 -0
  56. package/assets/logo/logo-light.svg +10 -0
  57. package/assets/logo/mark.svg +15 -0
  58. package/bin/mdeck.js +2 -0
  59. package/docs/README.md +8 -0
  60. package/docs/reference/authoring.md +795 -0
  61. package/docs/reference/claude-skill.md +96 -0
  62. package/docs/reference/extensions.md +250 -0
  63. package/docs/reference/layouts.md +153 -0
  64. package/docs/reference/palettes.md +106 -0
  65. package/docs/reference/structured-slides.md +120 -0
  66. package/docs/reference/themes.md +133 -0
  67. package/docs/site/assets/favicon.svg +15 -0
  68. package/docs/site/assets/github-logo.svg +1 -0
  69. package/docs/site/assets/site.css +162 -0
  70. package/docs/site/assets/site.js +123 -0
  71. package/docs/site/build.js +148 -0
  72. package/docs/site/content/appearance.md +203 -0
  73. package/docs/site/content/audience.md +178 -0
  74. package/docs/site/content/commands.md +153 -0
  75. package/docs/site/content/components.md +134 -0
  76. package/docs/site/content/drawing.md +72 -0
  77. package/docs/site/content/editing.md +59 -0
  78. package/docs/site/content/getting-started.md +103 -0
  79. package/docs/site/content/layouts.md +126 -0
  80. package/docs/site/content/media.md +107 -0
  81. package/docs/site/content/more-content.md +130 -0
  82. package/docs/site/content/presenting.md +93 -0
  83. package/docs/site/content/reusable-layouts.md +74 -0
  84. package/docs/site/content/sharing.md +88 -0
  85. package/docs/site/content/theme-authoring.md +144 -0
  86. package/docs/site/content/theme-repository.md +76 -0
  87. package/docs/site/content/troubleshooting.md +92 -0
  88. package/docs/site/content/views.md +56 -0
  89. package/docs/site/content/welcome.md +71 -0
  90. package/docs/site/content/writing.md +121 -0
  91. package/docs/site/examples/first-talk.md +88 -0
  92. package/docs/site/examples/notebook.svg +58 -0
  93. package/docs/site/images/themes/academic-dark.webp +0 -0
  94. package/docs/site/images/themes/academic-light.webp +0 -0
  95. package/docs/site/images/themes/academic.webp +0 -0
  96. package/docs/site/images/themes/aurora-dark.webp +0 -0
  97. package/docs/site/images/themes/aurora-light.webp +0 -0
  98. package/docs/site/images/themes/aurora.webp +0 -0
  99. package/docs/site/images/themes/duet-dark.webp +0 -0
  100. package/docs/site/images/themes/duet-light.webp +0 -0
  101. package/docs/site/images/themes/duet.webp +0 -0
  102. package/docs/site/images/themes/editorial-dark.webp +0 -0
  103. package/docs/site/images/themes/editorial-light.webp +0 -0
  104. package/docs/site/images/themes/editorial.webp +0 -0
  105. package/docs/site/images/themes/fhnw.webp +0 -0
  106. package/docs/site/images/themes/neue-dark.webp +0 -0
  107. package/docs/site/images/themes/neue-light.webp +0 -0
  108. package/docs/site/images/themes/neue.webp +0 -0
  109. package/docs/site/images/themes/sketch-dark.webp +0 -0
  110. package/docs/site/images/themes/sketch-light.webp +0 -0
  111. package/docs/site/images/themes/sketch.webp +0 -0
  112. package/docs/site/images/themes/terminal-dark.webp +0 -0
  113. package/docs/site/images/themes/terminal-light.webp +0 -0
  114. package/docs/site/images/themes/terminal.webp +0 -0
  115. package/docs/site/package.json +9 -0
  116. package/docs/site/pages.js +27 -0
  117. package/docs/site/server.js +58 -0
  118. package/examples/custom-layouts/extensions/comparison/extension.toml +35 -0
  119. package/examples/custom-layouts/extensions/comparison/layout.jsx +15 -0
  120. package/examples/custom-layouts/extensions/comparison/starter.md +17 -0
  121. package/examples/custom-layouts/extensions/comparison/styles.css +4 -0
  122. package/examples/custom-layouts/slides.md +60 -0
  123. package/examples/poll/slides.md +127 -0
  124. package/examples/python/.mdeck-backups/slides.drawings-2026-10-06T08-36-47Z.json +19 -0
  125. package/examples/python/.mdeck-backups/slides.drawings-2026-10-06T11-27-30Z.json +6 -0
  126. package/examples/python/slides.drawings.json +6 -0
  127. package/examples/python/slides.md +493 -0
  128. package/examples/showcase/.mdeck-backups/slides.drawings-2026-10-06T08-08-30Z.json +10 -0
  129. package/examples/showcase/.mdeck-backups/slides.drawings-2026-10-06T11-41-35Z.json +13 -0
  130. package/examples/showcase/img/image.jpg +0 -0
  131. package/examples/showcase/img/mdeck.svg +66 -0
  132. package/examples/showcase/slides.drawings.json +11 -0
  133. package/examples/showcase/slides.md +427 -0
  134. package/package.json +75 -0
  135. package/skills/write-slides/SKILL.md +144 -0
  136. package/src/build/check.js +49 -0
  137. package/src/build/chrome.js +130 -0
  138. package/src/build/components.js +44 -0
  139. package/src/build/config.js +61 -0
  140. package/src/build/drawings.js +14 -0
  141. package/src/build/editorPlugin.js +272 -0
  142. package/src/build/editorServer.js +36 -0
  143. package/src/build/fonts.js +84 -0
  144. package/src/build/homePlugin.js +208 -0
  145. package/src/build/inkPlugin.js +192 -0
  146. package/src/build/ownWrites.js +18 -0
  147. package/src/build/pairing.js +81 -0
  148. package/src/build/pdf.js +34 -0
  149. package/src/build/relayAccess.js +85 -0
  150. package/src/build/slidesPlugin.js +371 -0
  151. package/src/build/themeCheck.js +151 -0
  152. package/src/build/tunnelClient.js +184 -0
  153. package/src/cli/args.js +76 -0
  154. package/src/cli/index.js +758 -0
  155. package/src/cli/migrate.js +123 -0
  156. package/src/cli/skill.js +40 -0
  157. package/src/cli/themes.js +140 -0
  158. package/src/components/CodeBlock.jsx +168 -0
  159. package/src/components/ConnectedViews.jsx +25 -0
  160. package/src/components/Icon.jsx +8 -0
  161. package/src/components/Poll.jsx +67 -0
  162. package/src/components/QrCode.jsx +29 -0
  163. package/src/components/QrCodeTag.jsx +27 -0
  164. package/src/components/Question.jsx +28 -0
  165. package/src/components/Scale.jsx +47 -0
  166. package/src/components/VideoPlayer.jsx +108 -0
  167. package/src/components/WordCloud.jsx +106 -0
  168. package/src/components/activity.jsx +35 -0
  169. package/src/components/callout.css +78 -0
  170. package/src/components/code-block.css +123 -0
  171. package/src/components/columns.css +11 -0
  172. package/src/components/poll.css +81 -0
  173. package/src/components/video-player.css +14 -0
  174. package/src/core/devPath.js +4 -0
  175. package/src/core/editDeck.js +230 -0
  176. package/src/core/icons.js +69 -0
  177. package/src/core/ink.js +221 -0
  178. package/src/core/labels.js +144 -0
  179. package/src/core/outline.js +33 -0
  180. package/src/core/parseSlides.js +152 -0
  181. package/src/core/source.js +137 -0
  182. package/src/core/urls.js +34 -0
  183. package/src/core/validateDeck.js +139 -0
  184. package/src/editor/api.js +67 -0
  185. package/src/editor/components/App.jsx +75 -0
  186. package/src/editor/components/ConflictBanner.jsx +10 -0
  187. package/src/editor/components/DeckSettings.jsx +108 -0
  188. package/src/editor/components/DesignApp.jsx +252 -0
  189. package/src/editor/components/Diagnostics.jsx +10 -0
  190. package/src/editor/components/ExtensionEditor.jsx +66 -0
  191. package/src/editor/components/ExtensionForms.jsx +134 -0
  192. package/src/editor/components/ExtensionsPanel.jsx +114 -0
  193. package/src/editor/components/Field.jsx +24 -0
  194. package/src/editor/components/Inspector.jsx +36 -0
  195. package/src/editor/components/LayoutPicker.jsx +23 -0
  196. package/src/editor/components/LayoutSelect.jsx +25 -0
  197. package/src/editor/components/LookThumbnail.jsx +8 -0
  198. package/src/editor/components/MetaFields.jsx +24 -0
  199. package/src/editor/components/Outline.jsx +28 -0
  200. package/src/editor/components/PalettePicker.jsx +32 -0
  201. package/src/editor/components/Preview.jsx +63 -0
  202. package/src/editor/components/PropsForm.jsx +46 -0
  203. package/src/editor/components/RawSlideEditor.jsx +9 -0
  204. package/src/editor/components/RegionEditor.jsx +15 -0
  205. package/src/editor/components/Resizer.jsx +18 -0
  206. package/src/editor/designLink.js +19 -0
  207. package/src/editor/editor.css +139 -0
  208. package/src/editor/extensions.js +86 -0
  209. package/src/editor/keyboard.js +21 -0
  210. package/src/editor/model.js +38 -0
  211. package/src/editor/sampleDeck.js +165 -0
  212. package/src/editor/saveQueue.js +47 -0
  213. package/src/editor/schema.js +36 -0
  214. package/src/editor/state.js +92 -0
  215. package/src/editor/useDeckDocument.js +67 -0
  216. package/src/extensions/appearance.js +79 -0
  217. package/src/extensions/contrast.js +57 -0
  218. package/src/extensions/discover.js +126 -0
  219. package/src/extensions/manifest.js +209 -0
  220. package/src/extensions/packs.js +268 -0
  221. package/src/extensions/tokens.js +25 -0
  222. package/src/home/Home.jsx +362 -0
  223. package/src/home/home.css +148 -0
  224. package/src/layouts/layoutApi.jsx +205 -0
  225. package/src/layouts/layoutProps.js +30 -0
  226. package/src/layouts/renderSlide.jsx +17 -0
  227. package/src/live/answer/answer.css +34 -0
  228. package/src/live/answer/answer.html +14 -0
  229. package/src/live/answer/answer.js +130 -0
  230. package/src/live/client.js +290 -0
  231. package/src/live/code.js +19 -0
  232. package/src/live/follow.js +17 -0
  233. package/src/live/pairing.js +34 -0
  234. package/src/live/presence.js +33 -0
  235. package/src/live/roomTag.js +38 -0
  236. package/src/live/rooms.js +249 -0
  237. package/src/live/server.js +82 -0
  238. package/src/live/tunnel.js +180 -0
  239. package/src/paths.js +9 -0
  240. package/src/runtime/ReaderView.jsx +193 -0
  241. package/src/runtime/SlideErrorBoundary.jsx +28 -0
  242. package/src/runtime/chrome.jsx +55 -0
  243. package/src/runtime/deck-stage.js +1533 -0
  244. package/src/runtime/design.html +12 -0
  245. package/src/runtime/design.jsx +5 -0
  246. package/src/runtime/editor.html +12 -0
  247. package/src/runtime/editor.jsx +5 -0
  248. package/src/runtime/editorBridge.js +58 -0
  249. package/src/runtime/fit.js +149 -0
  250. package/src/runtime/home.html +13 -0
  251. package/src/runtime/home.jsx +5 -0
  252. package/src/runtime/index.html +15 -0
  253. package/src/runtime/ink/InkLayer.jsx +17 -0
  254. package/src/runtime/ink/Toolbar.jsx +145 -0
  255. package/src/runtime/ink/attach.js +69 -0
  256. package/src/runtime/ink/bus.js +126 -0
  257. package/src/runtime/ink/controller.js +132 -0
  258. package/src/runtime/ink/room.js +101 -0
  259. package/src/runtime/ink/select.js +124 -0
  260. package/src/runtime/ink/server.js +75 -0
  261. package/src/runtime/ink/store.js +55 -0
  262. package/src/runtime/ink/toolbar.css +79 -0
  263. package/src/runtime/main.jsx +863 -0
  264. package/src/runtime/markedSetup.js +147 -0
  265. package/src/runtime/reader.css +59 -0
  266. package/src/runtime/registry.jsx +26 -0
  267. package/src/runtime/syncOrder.js +32 -0
  268. package/src/runtime/themeLoader.js +68 -0
@@ -0,0 +1,196 @@
1
+ /* ─────────────────────────────────────────────
2
+ BASE — shared structural skeleton
3
+ Loaded before tokens.css and templates.css so themes
4
+ can override anything here. Only universally-identical
5
+ rules live here; visual styling belongs in each theme.
6
+ ───────────────────────────────────────────── */
7
+
8
+ /* ── Reset ───────────────────────────────────────────────────────────────── */
9
+ html, body {
10
+ margin: 0;
11
+ padding: 0;
12
+ background: #000;
13
+ font-family: var(--font-body);
14
+ color: var(--ink);
15
+ -webkit-font-smoothing: antialiased;
16
+ -moz-osx-font-smoothing: grayscale;
17
+ }
18
+
19
+ deck-stage { background: #000; }
20
+
21
+ /* ── Slide shell ─────────────────────────────────────────────────────────── */
22
+ .slide {
23
+ background: var(--bg);
24
+ color: var(--ink);
25
+ padding: var(--pad-y) var(--pad-x);
26
+ box-sizing: border-box;
27
+ display: flex;
28
+ flex-direction: column;
29
+ overflow: hidden;
30
+ position: relative;
31
+ }
32
+
33
+ /* ── Ink: saved annotations, above the slide's content ─────────────────── */
34
+ .slide-ink { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; z-index: 50; overflow: visible; }
35
+ deck-stage[data-ink-hidden] .slide-ink { display: none; }
36
+
37
+ /* ── Header / footer rails ───────────────────────────────────────────────── */
38
+ /* Flex skeleton only — typography (font-weight, letter-spacing, etc.) is theme-specific */
39
+ .slide-header {
40
+ display: flex;
41
+ justify-content: space-between;
42
+ align-items: center;
43
+ font-family: var(--font-body);
44
+ font-size: var(--fs-eyebrow);
45
+ color: var(--muted);
46
+ }
47
+ .slide-header > span { white-space: nowrap; flex-shrink: 0; }
48
+
49
+ .slide-footer {
50
+ display: flex;
51
+ justify-content: space-between;
52
+ align-items: center;
53
+ gap: 40px;
54
+ }
55
+ .slide-footer > span { white-space: nowrap; flex-shrink: 0; }
56
+
57
+ /* ── Slide body ──────────────────────────────────────────────────────────── */
58
+ /* `safe center`: centred while the content fits; content that is too tall
59
+ starts at the top instead of growing over the heading (see fit.js). */
60
+ .slide-body {
61
+ flex: 1;
62
+ display: flex;
63
+ flex-direction: column;
64
+ justify-content: safe center;
65
+ min-height: 0;
66
+ font-family: var(--font-body);
67
+ font-size: var(--fs-body);
68
+ line-height: 1.45;
69
+ color: var(--ink-soft);
70
+ }
71
+
72
+ /* ── Image + text layout ─────────────────────────────────────────────────── */
73
+ /* Gap default 100px — FHNW and editorial override to 96px in their templates.css */
74
+ .slide--image-text .slide-body {
75
+ flex-direction: row;
76
+ gap: 100px;
77
+ align-items: stretch;
78
+ justify-content: stretch;
79
+ }
80
+ .image-pane img { width: 100%; height: 100%; object-fit: cover; display: block; }
81
+ .image-pane .themed-picture { width: 100%; height: 100%; }
82
+ .themed-picture:not(.themed-picture--inline) > svg { width: 100%; height: 100%; display: block; overflow: visible; }
83
+ .slide-bg .slide-bg-picture { position: absolute; inset: 0; }
84
+ .themed-picture--inline { display: inline-block; max-width: 100%; vertical-align: middle; }
85
+ .themed-picture--inline > svg { display: block; max-width: 100%; height: auto; }
86
+ /* Structural skeleton for placeholder — visual (background, colors) stays in theme */
87
+ .image-placeholder { width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; }
88
+ .text-pane {
89
+ flex: 1;
90
+ min-width: 0;
91
+ display: flex;
92
+ flex-direction: column;
93
+ justify-content: safe center;
94
+ gap: var(--gap-item);
95
+ }
96
+
97
+ /* ── Split layout ────────────────────────────────────────────────────────── */
98
+ /* The shared heading above, then the two columns side by side. */
99
+ .split-heading { flex: none; margin-bottom: var(--gap-item); }
100
+ .split-columns { flex: 1; min-height: 0; display: flex; flex-direction: row; align-items: stretch; gap: 100px; }
101
+ .split-left { flex: 1; min-width: 0; display: flex; flex-direction: column; justify-content: safe center; --code-size: 20px; }
102
+ .split-right { flex: 1; min-width: 0; display: flex; flex-direction: column; justify-content: safe center; gap: var(--gap-item); }
103
+
104
+ /* ── List containers ─────────────────────────────────────────────────────── */
105
+ .slide-body :is(ul, ol) + :is(ul, ol) { margin-top: var(--gap-item); }
106
+ /* Markers (::before), padding, and font styling are visual — defined per theme */
107
+ .slide-body ul {
108
+ list-style: none;
109
+ padding: 0;
110
+ margin: 0;
111
+ display: flex;
112
+ flex-direction: column;
113
+ gap: var(--gap-item);
114
+ }
115
+ .slide-body ul li { position: relative; }
116
+ .slide-body ol {
117
+ list-style: none;
118
+ padding: 0;
119
+ margin: 0;
120
+ counter-reset: slide-ol;
121
+ display: flex;
122
+ flex-direction: column;
123
+ gap: var(--gap-item);
124
+ }
125
+ .slide-body ol li { counter-increment: slide-ol; position: relative; }
126
+
127
+ /* ── Full-bleed image ────────────────────────────────────────────────────── */
128
+ .slide--full-bleed-image { padding: 0; }
129
+ .slide--full-bleed-image .slide-bg {
130
+ position: absolute;
131
+ inset: 0;
132
+ background: var(--ink); /* dark fallback before image loads */
133
+ background-size: cover;
134
+ background-position: center;
135
+ background-repeat: no-repeat;
136
+ }
137
+ /* Default body: content at bottom with standard padding — FHNW overrides padding: 0 */
138
+ .slide--full-bleed-image .slide-body {
139
+ position: relative;
140
+ z-index: 1;
141
+ padding: var(--pad-y) var(--pad-x);
142
+ justify-content: flex-end;
143
+ }
144
+
145
+ /* ── Footnotes ───────────────────────────────────────────────────────────── */
146
+ /* FHNW and editorial override padding-top and add font-weight/style in their templates.css */
147
+ .slide-footnotes {
148
+ font-size: var(--fs-small);
149
+ color: var(--muted);
150
+ border-top: 1px solid var(--rule);
151
+ padding-top: 20px;
152
+ margin-top: auto;
153
+ }
154
+ .slide-footnotes ol { margin: 0; padding-left: 1.5em; display: flex; flex-direction: column; gap: 4px; }
155
+ .slide-footnotes li { line-height: 1.4; }
156
+ .slide-footnotes p { margin: 0; }
157
+ .slide-footnotes .footnote-backref { display: none; }
158
+
159
+ /* ── Code blocks ─────────────────────────────────────────────────────────── */
160
+ .code-block { white-space: pre-wrap; overflow-x: hidden; }
161
+
162
+ /* ── Tables ──────────────────────────────────────────────────────────────── */
163
+ .slide-body table {
164
+ border-collapse: collapse;
165
+ width: 100%;
166
+ font-size: var(--fs-body);
167
+ }
168
+ .slide-body th,
169
+ .slide-body td {
170
+ text-align: left;
171
+ padding: 12px 16px;
172
+ border-bottom: 1px solid var(--rule);
173
+ }
174
+ .slide-body th {
175
+ font-weight: 600;
176
+ border-bottom: 2px solid var(--ink);
177
+ color: var(--ink);
178
+ }
179
+ .slide-body td { color: var(--ink-soft); }
180
+
181
+ /* ── Step reveals ────────────────────────────────────────────────────────── */
182
+ [data-step] {
183
+ opacity: 0;
184
+ transition: opacity 200ms ease;
185
+ }
186
+ [data-step][data-step-visible] {
187
+ opacity: 1;
188
+ }
189
+
190
+ /* ── Print ───────────────────────────────────────────────────────────────── */
191
+ @media print {
192
+ html, body, deck-stage { background: #fff !important; }
193
+ [data-step] { opacity: 1 !important; }
194
+ /* Pages are captured right after print mode reveals everything. */
195
+ *, *::before, *::after { transition: none !important; }
196
+ }
@@ -0,0 +1,26 @@
1
+ schema = 1
2
+ kind = "layout"
3
+ id = "chapter"
4
+ title = "Chapter divider"
5
+ description = "Section divider with a number, label and short description."
6
+ frame = "chapter"
7
+
8
+ [regions.body]
9
+ description = "Chapter heading and a short description"
10
+
11
+ [properties.image]
12
+ type = "string"
13
+ description = "Image path"
14
+
15
+ [properties.alt]
16
+ type = "string"
17
+ default = ""
18
+
19
+ [properties.fit]
20
+ type = "string"
21
+ enum = ["cover", "contain"]
22
+ default = "cover"
23
+
24
+ [properties.position]
25
+ type = "string"
26
+ default = "center"
@@ -0,0 +1,21 @@
1
+ import { h } from 'preact'
2
+ import { extractContent, HtmlContent, Picture, t } from 'mdeck/layout'
3
+
4
+ export default function ChapterLayout({ meta, content, props }) {
5
+ const { headings, paragraphs, bodyHtml } = extractContent(content, { headingLevels: [1], paragraph: meta.description == null })
6
+ // As written: 2 shows as 2; write "02" for a leading zero. A whole number
7
+ // is also given to themes as --chapter-number, for counters in another
8
+ // style (editorial shows it in Roman numerals).
9
+ const num = meta.number != null ? String(meta.number) : null
10
+ const desc = meta.description ?? paragraphs[0]
11
+ return <div class="slide-body">
12
+ <div class="chapter-content">
13
+ {num && <div class="chapter-num" style={/^\d+$/.test(num) ? { '--chapter-number': Number(num) } : undefined}>{num}</div>}
14
+ <div class="chapter-meta">{meta.label ?? t('slide.chapter')}</div>
15
+ {headings[1] && <h2 class="chapter-title" dangerouslySetInnerHTML={{ __html: headings[1] }} />}
16
+ {desc && <p class="chapter-desc" dangerouslySetInnerHTML={{ __html: desc }} />}
17
+ {bodyHtml && <HtmlContent html={bodyHtml} />}
18
+ </div>
19
+ {props.image && <Picture class="chapter-image" src={props.image} alt={props.alt} fit={props.fit} position={props.position} />}
20
+ </div>
21
+ }
@@ -0,0 +1,8 @@
1
+ :::meta
2
+ layout: chapter
3
+ number: 1
4
+ part: Part One
5
+ :::
6
+ # Chapter title
7
+
8
+ What this chapter covers.
@@ -0,0 +1,8 @@
1
+ schema = 1
2
+ kind = "layout"
3
+ id = "focus"
4
+ title = "Big statement"
5
+ description = "One strong idea, quote or conclusion in large type."
6
+
7
+ [regions.body]
8
+ description = "The statement"
@@ -0,0 +1,10 @@
1
+ import { h } from 'preact'
2
+ import { MarkdownRegion } from 'mdeck/layout'
3
+
4
+ export default function FocusLayout({ meta, regions }) {
5
+ return <div class="slide-body">
6
+ {meta.eyebrow && <div class="focus-eyebrow">{meta.eyebrow}</div>}
7
+ <MarkdownRegion class="focus-content" region={regions.body} />
8
+ {meta.attribution && <div class="focus-attribution">— {meta.attribution}</div>}
9
+ </div>
10
+ }
@@ -0,0 +1,4 @@
1
+ :::meta
2
+ layout: focus
3
+ :::
4
+ # One strong idea.
@@ -0,0 +1,31 @@
1
+ schema = 1
2
+ kind = "layout"
3
+ id = "full-bleed-image"
4
+ title = "Full-bleed image"
5
+ description = "A picture filling the whole slide with an optional overlay title."
6
+ frame = "none"
7
+
8
+ [regions.body]
9
+ description = "Overlay heading and text"
10
+
11
+ [properties.image]
12
+ type = "string"
13
+ description = "Image path"
14
+
15
+ [properties.alt]
16
+ type = "string"
17
+ default = ""
18
+
19
+ [properties.fit]
20
+ type = "string"
21
+ enum = ["cover", "contain"]
22
+ default = "cover"
23
+
24
+ [properties.position]
25
+ type = "string"
26
+ default = "center"
27
+
28
+ [properties.overlay]
29
+ type = "boolean"
30
+ description = "Darken the picture behind the text"
31
+ default = false
@@ -0,0 +1,19 @@
1
+ import { h } from 'preact'
2
+ import { extractContent, HtmlContent, Picture, themedSvg } from 'mdeck/layout'
3
+
4
+ export default function FullBleedLayout({ content, props }) {
5
+ const { headings, bodyHtml } = extractContent(content, { headingLevels: [1] })
6
+ // A drawing in the theme's colours is drawn inside the background box;
7
+ // other pictures are its CSS background.
8
+ const drawing = props.image && themedSvg(props.image)
9
+ return <>
10
+ <div class="slide-bg" style={{ backgroundImage: props.image && !drawing ? `url(${JSON.stringify(props.image)})` : undefined,
11
+ backgroundSize: props.fit, backgroundPosition: props.position }}>
12
+ {drawing && <Picture class="slide-bg-picture" src={props.image} alt={props.alt} fit={props.fit ?? 'cover'} />}
13
+ </div>
14
+ <div class="slide-body">
15
+ {headings[1] && <h2 class="overlay-title" dangerouslySetInnerHTML={{ __html: headings[1] }} />}
16
+ {bodyHtml && <HtmlContent html={bodyHtml} />}
17
+ </div>
18
+ </>
19
+ }
@@ -0,0 +1,6 @@
1
+ :::meta
2
+ layout: full-bleed-image
3
+ props:
4
+ overlay: true
5
+ :::
6
+ # Add an image using props.image
@@ -0,0 +1,8 @@
1
+ schema = 1
2
+ kind = "layout"
3
+ id = "generic"
4
+ title = "Content slide"
5
+ description = "Ordinary slide: heading, text, lists, tables, code or pictures."
6
+
7
+ [regions.body]
8
+ description = "Markdown content"
@@ -0,0 +1,8 @@
1
+ import { h } from 'preact'
2
+ import { MarkdownRegion } from 'mdeck/layout'
3
+
4
+ export default function GenericLayout({ regions }) {
5
+ if (Object.keys(regions).length === 1 && regions.body) return <MarkdownRegion class="slide-body" region={regions.body} />
6
+ // Unknown legacy layouts retain every region in source order.
7
+ return <div class="slide-body">{Object.values(regions).map(region => <MarkdownRegion key={region.name} region={region} />)}</div>
8
+ }
@@ -0,0 +1,4 @@
1
+ # Heading
2
+
3
+ - First point
4
+ - Second point
@@ -0,0 +1,25 @@
1
+ schema = 1
2
+ kind = "layout"
3
+ id = "image-text"
4
+ title = "Image + text"
5
+ description = "A picture beside a heading and text."
6
+
7
+ [regions.body]
8
+ description = "Heading, eyebrow and text beside the image"
9
+
10
+ [properties.image]
11
+ type = "string"
12
+ description = "Image path"
13
+
14
+ [properties.alt]
15
+ type = "string"
16
+ default = ""
17
+
18
+ [properties.fit]
19
+ type = "string"
20
+ enum = ["cover", "contain"]
21
+ default = "cover"
22
+
23
+ [properties.position]
24
+ type = "string"
25
+ default = "center"
@@ -0,0 +1,17 @@
1
+ import { h } from 'preact'
2
+ import { extractContent, HtmlContent, Picture } from 'mdeck/layout'
3
+
4
+ export default function ImageTextLayout({ meta, content, props }) {
5
+ const { headings, bodyHtml } = extractContent(content, { headingLevels: [1, 2] })
6
+ return <div class="slide-body">
7
+ <div class="image-pane">
8
+ {props.image ? <Picture src={props.image} alt={props.alt} fit={props.fit} position={props.position} />
9
+ : <div class="image-placeholder"><span>Image placeholder</span></div>}
10
+ </div>
11
+ <div class="text-pane">
12
+ {(headings[2] ?? meta.eyebrow) && <div class="eyebrow" dangerouslySetInnerHTML={{ __html: headings[2] ?? meta.eyebrow }} />}
13
+ {headings[1] && <h2 class="title" dangerouslySetInnerHTML={{ __html: headings[1] }} />}
14
+ <HtmlContent class="text-content" html={bodyHtml.replace(/<p>/g, '<p class="body-text">')} />
15
+ </div>
16
+ </div>
17
+ }
@@ -0,0 +1,6 @@
1
+ :::meta
2
+ layout: image-text
3
+ :::
4
+ # Visual context
5
+
6
+ Add an image using props.image.
@@ -0,0 +1,25 @@
1
+ schema = 1
2
+ kind = "layout"
3
+ id = "split"
4
+ title = "Split content"
5
+ description = "Two columns, with an optional shared heading above them."
6
+
7
+ [regions.body]
8
+ description = "Shared heading; without slots the first block goes left and the rest right"
9
+
10
+ [regions.left]
11
+ description = "Left column"
12
+
13
+ [regions.right]
14
+ description = "Right column"
15
+
16
+ [properties.ratio]
17
+ type = "array"
18
+ description = "Relative widths of the two columns"
19
+ minItems = 2
20
+ maxItems = 2
21
+ default = [1, 1]
22
+
23
+ [properties.ratio.items]
24
+ type = "number"
25
+ minimum = 0.01
@@ -0,0 +1,19 @@
1
+ import { h } from 'preact'
2
+ import { marked } from 'marked'
3
+ import { HtmlContent, MarkdownRegion } from 'mdeck/layout'
4
+
5
+ export default function SplitLayout({ content, regions, props }) {
6
+ const tokens = marked.lexer(content)
7
+ const [first, ...rest] = tokens.filter(token => token.type !== 'space')
8
+ const named = regions.left || regions.right
9
+ const left = named ? marked.parse(regions.left?.content ?? '') : marked.parser(Object.assign(first ? [first] : [], { links: tokens.links }))
10
+ const right = named ? marked.parse(regions.right?.content ?? '') : marked.parser(Object.assign(rest, { links: tokens.links }))
11
+ // The shared heading sits in the slide body, where themes style headings.
12
+ return <div class="slide-body">
13
+ {named && content && <MarkdownRegion class="split-heading" region={regions.body} />}
14
+ <div class="split-columns">
15
+ <div class="split-left" data-region="left" style={{ flex: props.ratio[0] }}><HtmlContent html={left} /></div>
16
+ <div class="split-right" data-region="right" style={{ flex: props.ratio[1] }}><HtmlContent html={right} /></div>
17
+ </div>
18
+ </div>
19
+ }
@@ -0,0 +1,14 @@
1
+ :::meta
2
+ layout: split
3
+ props:
4
+ ratio: [1, 1]
5
+ :::
6
+ # Compare
7
+
8
+ :::slot left
9
+ Left content
10
+ :::
11
+
12
+ :::slot right
13
+ Right content
14
+ :::
@@ -0,0 +1,26 @@
1
+ schema = 1
2
+ kind = "layout"
3
+ id = "title"
4
+ title = "Title slide"
5
+ description = "Opening slide with a headline, subtitle and optional picture."
6
+ frame = "title"
7
+
8
+ [regions.body]
9
+ description = "Headline, subtitle and any introduction"
10
+
11
+ [properties.image]
12
+ type = "string"
13
+ description = "Image path"
14
+
15
+ [properties.alt]
16
+ type = "string"
17
+ default = ""
18
+
19
+ [properties.fit]
20
+ type = "string"
21
+ enum = ["cover", "contain"]
22
+ default = "cover"
23
+
24
+ [properties.position]
25
+ type = "string"
26
+ default = "center"
@@ -0,0 +1,14 @@
1
+ import { h } from 'preact'
2
+ import { extractContent, HtmlContent, Picture } from 'mdeck/layout'
3
+
4
+ export default function TitleLayout({ content, props }) {
5
+ const { headings, paragraphs, bodyHtml } = extractContent(content, { headingLevels: [1, 2], paragraph: !/^##\s/m.test(content) })
6
+ return <div class="slide-body">
7
+ <div class="title-text">
8
+ {headings[1] && <h1 class="display" dangerouslySetInnerHTML={{ __html: headings[1] }} />}
9
+ {(headings[2] || paragraphs[0]) && <p class="subtitle" dangerouslySetInnerHTML={{ __html: headings[2] ?? paragraphs[0] }} />}
10
+ {bodyHtml && <HtmlContent html={bodyHtml} />}
11
+ </div>
12
+ {props.image && <Picture class="title-image" src={props.image} alt={props.alt} fit={props.fit} position={props.position} />}
13
+ </div>
14
+ }
@@ -0,0 +1,5 @@
1
+ :::meta
2
+ layout: title
3
+ :::
4
+ # My Talk
5
+ ## A clear subtitle
@@ -0,0 +1,29 @@
1
+ schema = 1
2
+ kind = "palette"
3
+ id = "brand"
4
+ title = "FHNW"
5
+ description = "The FHNW corporate colours: black, white and FHNW yellow."
6
+ # Only for the fhnw theme: its corporate colours.
7
+ theme = "fhnw"
8
+
9
+ [light]
10
+ "--bg" = "#ffffff"
11
+ "--surface" = "#f1f1ee"
12
+ "--ink" = "#000000"
13
+ "--ink-soft" = "#262626"
14
+ "--muted" = "#6e6e6e"
15
+ "--rule" = "#deded9"
16
+ "--accent" = "#fde70e"
17
+ "--accent-2" = "#000000"
18
+ "--on-accent" = "#000000"
19
+
20
+ [dark]
21
+ "--bg" = "#000000"
22
+ "--surface" = "#1c1c1c"
23
+ "--ink" = "#ffffff"
24
+ "--ink-soft" = "#dcdcdc"
25
+ "--muted" = "#9a9a9a"
26
+ "--rule" = "#333333"
27
+ "--accent" = "#fde70e"
28
+ "--accent-2" = "#ffffff"
29
+ "--on-accent" = "#000000"
@@ -0,0 +1,27 @@
1
+ schema = 1
2
+ kind = "palette"
3
+ id = "cobalt"
4
+ title = "Cobalt"
5
+ description = "Strong ultramarine on white, with vivid orange; bold and clear."
6
+
7
+ [light]
8
+ "--bg" = "#ffffff"
9
+ "--surface" = "#eef1fb"
10
+ "--ink" = "#0c1033"
11
+ "--ink-soft" = "#2a2f55"
12
+ "--muted" = "#5b6080"
13
+ "--rule" = "#d5dbf0"
14
+ "--accent" = "#1f3fd1"
15
+ "--accent-2" = "#e8590c"
16
+ "--on-accent" = "#ffffff"
17
+
18
+ [dark]
19
+ "--bg" = "#0a1030"
20
+ "--surface" = "#121a44"
21
+ "--ink" = "#eef1ff"
22
+ "--ink-soft" = "#c9cff0"
23
+ "--muted" = "#8e97c4"
24
+ "--rule" = "#212b5e"
25
+ "--accent" = "#6f8cff"
26
+ "--accent-2" = "#ff922b"
27
+ "--on-accent" = "#0a1030"
@@ -0,0 +1,27 @@
1
+ schema = 1
2
+ kind = "palette"
3
+ id = "ember"
4
+ title = "Ember"
5
+ description = "Sand and espresso with a glowing orange."
6
+
7
+ [light]
8
+ "--bg" = "#fbf6ef"
9
+ "--surface" = "#f1e7da"
10
+ "--ink" = "#2a1a10"
11
+ "--ink-soft" = "#4a3324"
12
+ "--muted" = "#7a6656"
13
+ "--rule" = "#e6d6c3"
14
+ "--accent" = "#c2410c"
15
+ "--accent-2" = "#8f5a3c"
16
+ "--on-accent" = "#ffffff"
17
+
18
+ [dark]
19
+ "--bg" = "#121005"
20
+ "--surface" = "#1f1e19"
21
+ "--ink" = "#eae0d5"
22
+ "--ink-soft" = "#c6ac8f"
23
+ "--muted" = "#9a8a77"
24
+ "--rule" = "#2b2a29"
25
+ "--accent" = "#eb5e28"
26
+ "--accent-2" = "#c98b6b"
27
+ "--on-accent" = "#0d0a05"
@@ -0,0 +1,27 @@
1
+ schema = 1
2
+ kind = "palette"
3
+ id = "forest"
4
+ title = "Forest"
5
+ description = "Deep green with moss and ochre; calm, with contrast."
6
+
7
+ [light]
8
+ "--bg" = "#f6f5ef"
9
+ "--surface" = "#e9eadf"
10
+ "--ink" = "#12261c"
11
+ "--ink-soft" = "#2c4436"
12
+ "--muted" = "#5a6c60"
13
+ "--rule" = "#d3d8c8"
14
+ "--accent" = "#2e7d32"
15
+ "--accent-2" = "#9a6b00"
16
+ "--on-accent" = "#ffffff"
17
+
18
+ [dark]
19
+ "--bg" = "#0e1a14"
20
+ "--surface" = "#16261d"
21
+ "--ink" = "#e9f1e6"
22
+ "--ink-soft" = "#c4d3c0"
23
+ "--muted" = "#8ea493"
24
+ "--rule" = "#24382c"
25
+ "--accent" = "#7bd389"
26
+ "--accent-2" = "#e6c35c"
27
+ "--on-accent" = "#0e1a14"