react-cheminfo 0.7.0 → 0.9.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 (308) hide show
  1. package/README.md +60 -2
  2. package/bin/check-tokens.mjs +105 -0
  3. package/lib/about/core/about.d.ts +95 -0
  4. package/lib/about/core/about.d.ts.map +1 -0
  5. package/lib/about/core/about.js +78 -0
  6. package/lib/about/core/about.js.map +1 -0
  7. package/lib/about/core/index.d.ts +3 -0
  8. package/lib/about/core/index.d.ts.map +1 -0
  9. package/lib/about/core/index.js +2 -0
  10. package/lib/about/core/index.js.map +1 -0
  11. package/lib/about/ui/AboutCitations.d.ts +14 -0
  12. package/lib/about/ui/AboutCitations.d.ts.map +1 -0
  13. package/lib/about/ui/AboutCitations.js +40 -0
  14. package/lib/about/ui/AboutCitations.js.map +1 -0
  15. package/lib/about/ui/AboutPage.d.ts +32 -0
  16. package/lib/about/ui/AboutPage.d.ts.map +1 -0
  17. package/lib/about/ui/AboutPage.js +70 -0
  18. package/lib/about/ui/AboutPage.js.map +1 -0
  19. package/lib/about/ui/AboutSection.d.ts +23 -0
  20. package/lib/about/ui/AboutSection.d.ts.map +1 -0
  21. package/lib/about/ui/AboutSection.js +28 -0
  22. package/lib/about/ui/AboutSection.js.map +1 -0
  23. package/lib/about/ui/index.d.ts +7 -0
  24. package/lib/about/ui/index.d.ts.map +1 -0
  25. package/lib/about/ui/index.js +4 -0
  26. package/lib/about/ui/index.js.map +1 -0
  27. package/lib/chrome/ui/index.d.ts +1 -0
  28. package/lib/chrome/ui/index.d.ts.map +1 -1
  29. package/lib/chrome/ui/index.js +3 -0
  30. package/lib/chrome/ui/index.js.map +1 -1
  31. package/lib/citation/core/index.d.ts +1 -0
  32. package/lib/citation/core/index.d.ts.map +1 -1
  33. package/lib/citation/core/index.js +1 -0
  34. package/lib/citation/core/index.js.map +1 -1
  35. package/lib/citation/core/teachingPaper.d.ts +15 -0
  36. package/lib/citation/core/teachingPaper.d.ts.map +1 -0
  37. package/lib/citation/core/teachingPaper.js +32 -0
  38. package/lib/citation/core/teachingPaper.js.map +1 -0
  39. package/lib/clipboard/ui/CodeBlock.d.ts.map +1 -1
  40. package/lib/clipboard/ui/CodeBlock.js +4 -1
  41. package/lib/clipboard/ui/CodeBlock.js.map +1 -1
  42. package/lib/color/ui/ColorScaleLegend.js +1 -1
  43. package/lib/color/ui/ColorScaleLegend.js.map +1 -1
  44. package/lib/core.d.ts +3 -0
  45. package/lib/core.d.ts.map +1 -1
  46. package/lib/core.js +5 -0
  47. package/lib/core.js.map +1 -1
  48. package/lib/credits/core/credits.d.ts +36 -0
  49. package/lib/credits/core/credits.d.ts.map +1 -1
  50. package/lib/credits/core/credits.js +42 -0
  51. package/lib/credits/core/credits.js.map +1 -1
  52. package/lib/credits/ui/CreditsList.js +1 -1
  53. package/lib/credits/ui/CreditsList.js.map +1 -1
  54. package/lib/delimited/ui/DelimitedTextPanel.js +1 -1
  55. package/lib/delimited/ui/DelimitedTextPanel.js.map +1 -1
  56. package/lib/ecosystem/core/sites.d.ts +1 -1
  57. package/lib/ecosystem/core/sites.d.ts.map +1 -1
  58. package/lib/ecosystem/core/sites.js +10 -0
  59. package/lib/ecosystem/core/sites.js.map +1 -1
  60. package/lib/ecosystem/core/tokens.d.ts.map +1 -1
  61. package/lib/ecosystem/core/tokens.js +1 -0
  62. package/lib/ecosystem/core/tokens.js.map +1 -1
  63. package/lib/ecosystem/ui/EcosystemLinks.js +2 -2
  64. package/lib/ecosystem/ui/EcosystemLinks.js.map +1 -1
  65. package/lib/ecosystem/ui/EcosystemMenu.js +1 -1
  66. package/lib/ecosystem/ui/EcosystemMenu.js.map +1 -1
  67. package/lib/ecosystem/ui/SiteTile.d.ts.map +1 -1
  68. package/lib/ecosystem/ui/SiteTile.js +5 -5
  69. package/lib/ecosystem/ui/SiteTile.js.map +1 -1
  70. package/lib/ecosystem/ui/glyphs.d.ts.map +1 -1
  71. package/lib/ecosystem/ui/glyphs.js +3 -0
  72. package/lib/ecosystem/ui/glyphs.js.map +1 -1
  73. package/lib/orbital/core/index.d.ts +1 -1
  74. package/lib/orbital/core/index.d.ts.map +1 -1
  75. package/lib/orbital/core/index.js +1 -1
  76. package/lib/orbital/core/index.js.map +1 -1
  77. package/lib/orbital/core/realHarmonics.d.ts +5 -2
  78. package/lib/orbital/core/realHarmonics.d.ts.map +1 -1
  79. package/lib/orbital/core/realHarmonics.js.map +1 -1
  80. package/lib/orbital/ui/AtomicOrbitalCanvas.d.ts +18 -0
  81. package/lib/orbital/ui/AtomicOrbitalCanvas.d.ts.map +1 -1
  82. package/lib/orbital/ui/AtomicOrbitalCanvas.js +84 -7
  83. package/lib/orbital/ui/AtomicOrbitalCanvas.js.map +1 -1
  84. package/lib/orbital/ui/AtomicOrbitalViewer.d.ts +13 -0
  85. package/lib/orbital/ui/AtomicOrbitalViewer.d.ts.map +1 -1
  86. package/lib/orbital/ui/AtomicOrbitalViewer.js +1 -1
  87. package/lib/orbital/ui/AtomicOrbitalViewer.js.map +1 -1
  88. package/lib/orbital/ui/camera.d.ts +15 -0
  89. package/lib/orbital/ui/camera.d.ts.map +1 -1
  90. package/lib/orbital/ui/camera.js +68 -0
  91. package/lib/orbital/ui/camera.js.map +1 -1
  92. package/lib/orbital/ui/renderVolume.d.ts.map +1 -1
  93. package/lib/orbital/ui/renderVolume.js +8 -1
  94. package/lib/orbital/ui/renderVolume.js.map +1 -1
  95. package/lib/orbital/ui/serial.d.ts +25 -0
  96. package/lib/orbital/ui/serial.d.ts.map +1 -0
  97. package/lib/orbital/ui/serial.js +25 -0
  98. package/lib/orbital/ui/serial.js.map +1 -0
  99. package/lib/orbital/ui/viewer.d.ts +23 -0
  100. package/lib/orbital/ui/viewer.d.ts.map +1 -1
  101. package/lib/orbital/ui/viewer.js +70 -17
  102. package/lib/orbital/ui/viewer.js.map +1 -1
  103. package/lib/pedagogy/ui/ExerciseProgressHeader.js +1 -1
  104. package/lib/pedagogy/ui/ExerciseProgressHeader.js.map +1 -1
  105. package/lib/pedagogy/ui/GlossaryText.js +2 -2
  106. package/lib/pedagogy/ui/GlossaryText.js.map +1 -1
  107. package/lib/pedagogy/ui/ReferenceSectionBlock.js +5 -2
  108. package/lib/pedagogy/ui/ReferenceSectionBlock.js.map +1 -1
  109. package/lib/pedagogy/ui/SyntaxTooltip.js +2 -2
  110. package/lib/pedagogy/ui/SyntaxTooltip.js.map +1 -1
  111. package/lib/pedagogy/ui/TutorialStepStrip.d.ts +15 -2
  112. package/lib/pedagogy/ui/TutorialStepStrip.d.ts.map +1 -1
  113. package/lib/pedagogy/ui/TutorialStepStrip.js +19 -5
  114. package/lib/pedagogy/ui/TutorialStepStrip.js.map +1 -1
  115. package/lib/pedagogy/ui/index.d.ts +1 -1
  116. package/lib/pedagogy/ui/index.d.ts.map +1 -1
  117. package/lib/pedagogy/ui/index.js.map +1 -1
  118. package/lib/periodic/ui/CategoryLegend.js +1 -1
  119. package/lib/periodic/ui/CategoryLegend.js.map +1 -1
  120. package/lib/periodic/ui/PeriodicTableChrome.js +2 -2
  121. package/lib/periodic/ui/PeriodicTableChrome.js.map +1 -1
  122. package/lib/seo/vite/ogCard.d.ts.map +1 -1
  123. package/lib/seo/vite/ogCard.js +1 -0
  124. package/lib/seo/vite/ogCard.js.map +1 -1
  125. package/lib/share/ui/ShareDialogContent.d.ts.map +1 -1
  126. package/lib/share/ui/ShareDialogContent.js +5 -2
  127. package/lib/share/ui/ShareDialogContent.js.map +1 -1
  128. package/lib/share/ui/SharePartOptions.js +1 -1
  129. package/lib/share/ui/SharePartOptions.js.map +1 -1
  130. package/lib/slides/core/demoLinks.d.ts +43 -0
  131. package/lib/slides/core/demoLinks.d.ts.map +1 -0
  132. package/lib/slides/core/demoLinks.js +104 -0
  133. package/lib/slides/core/demoLinks.js.map +1 -0
  134. package/lib/slides/core/index.d.ts +13 -0
  135. package/lib/slides/core/index.d.ts.map +1 -0
  136. package/lib/slides/core/index.js +7 -0
  137. package/lib/slides/core/index.js.map +1 -0
  138. package/lib/slides/core/sectionHeading.d.ts +19 -0
  139. package/lib/slides/core/sectionHeading.d.ts.map +1 -0
  140. package/lib/slides/core/sectionHeading.js +19 -0
  141. package/lib/slides/core/sectionHeading.js.map +1 -0
  142. package/lib/slides/core/slideNavigation.d.ts +38 -0
  143. package/lib/slides/core/slideNavigation.d.ts.map +1 -0
  144. package/lib/slides/core/slideNavigation.js +65 -0
  145. package/lib/slides/core/slideNavigation.js.map +1 -0
  146. package/lib/slides/core/talk.d.ts +82 -0
  147. package/lib/slides/core/talk.d.ts.map +1 -0
  148. package/lib/slides/core/talk.js +134 -0
  149. package/lib/slides/core/talk.js.map +1 -0
  150. package/lib/slides/core/talkManifest.d.ts +90 -0
  151. package/lib/slides/core/talkManifest.d.ts.map +1 -0
  152. package/lib/slides/core/talkManifest.js +109 -0
  153. package/lib/slides/core/talkManifest.js.map +1 -0
  154. package/lib/slides/core/talkOrigin.d.ts +50 -0
  155. package/lib/slides/core/talkOrigin.d.ts.map +1 -0
  156. package/lib/slides/core/talkOrigin.js +62 -0
  157. package/lib/slides/core/talkOrigin.js.map +1 -0
  158. package/lib/slides/ui/BackToSlides.d.ts +26 -0
  159. package/lib/slides/ui/BackToSlides.d.ts.map +1 -0
  160. package/lib/slides/ui/BackToSlides.js +24 -0
  161. package/lib/slides/ui/BackToSlides.js.map +1 -0
  162. package/lib/slides/ui/DemoLink.d.ts +42 -0
  163. package/lib/slides/ui/DemoLink.d.ts.map +1 -0
  164. package/lib/slides/ui/DemoLink.js +17 -0
  165. package/lib/slides/ui/DemoLink.js.map +1 -0
  166. package/lib/slides/ui/EmbedSlide.d.ts +19 -0
  167. package/lib/slides/ui/EmbedSlide.d.ts.map +1 -0
  168. package/lib/slides/ui/EmbedSlide.js +56 -0
  169. package/lib/slides/ui/EmbedSlide.js.map +1 -0
  170. package/lib/slides/ui/SectionSlide.d.ts +18 -0
  171. package/lib/slides/ui/SectionSlide.d.ts.map +1 -0
  172. package/lib/slides/ui/SectionSlide.js +18 -0
  173. package/lib/slides/ui/SectionSlide.js.map +1 -0
  174. package/lib/slides/ui/Slide.d.ts +52 -0
  175. package/lib/slides/ui/Slide.d.ts.map +1 -0
  176. package/lib/slides/ui/Slide.js +58 -0
  177. package/lib/slides/ui/Slide.js.map +1 -0
  178. package/lib/slides/ui/SlideBody.d.ts +32 -0
  179. package/lib/slides/ui/SlideBody.d.ts.map +1 -0
  180. package/lib/slides/ui/SlideBody.js +27 -0
  181. package/lib/slides/ui/SlideBody.js.map +1 -0
  182. package/lib/slides/ui/Slideshow.d.ts +93 -0
  183. package/lib/slides/ui/Slideshow.d.ts.map +1 -0
  184. package/lib/slides/ui/Slideshow.js +122 -0
  185. package/lib/slides/ui/Slideshow.js.map +1 -0
  186. package/lib/slides/ui/SlideshowBar.d.ts +33 -0
  187. package/lib/slides/ui/SlideshowBar.d.ts.map +1 -0
  188. package/lib/slides/ui/SlideshowBar.js +20 -0
  189. package/lib/slides/ui/SlideshowBar.js.map +1 -0
  190. package/lib/slides/ui/TalkList.d.ts +37 -0
  191. package/lib/slides/ui/TalkList.d.ts.map +1 -0
  192. package/lib/slides/ui/TalkList.js +68 -0
  193. package/lib/slides/ui/TalkList.js.map +1 -0
  194. package/lib/slides/ui/index.d.ts +19 -0
  195. package/lib/slides/ui/index.d.ts.map +1 -0
  196. package/lib/slides/ui/index.js +10 -0
  197. package/lib/slides/ui/index.js.map +1 -0
  198. package/lib/slides/vite/index.d.ts +3 -0
  199. package/lib/slides/vite/index.d.ts.map +1 -0
  200. package/lib/slides/vite/index.js +2 -0
  201. package/lib/slides/vite/index.js.map +1 -0
  202. package/lib/slides/vite/talks.d.ts +50 -0
  203. package/lib/slides/vite/talks.d.ts.map +1 -0
  204. package/lib/slides/vite/talks.js +87 -0
  205. package/lib/slides/vite/talks.js.map +1 -0
  206. package/lib/slides.d.ts +3 -0
  207. package/lib/slides.d.ts.map +1 -0
  208. package/lib/slides.js +3 -0
  209. package/lib/slides.js.map +1 -0
  210. package/lib/structure/ui/StructureEditor.js +2 -2
  211. package/lib/structure/ui/StructureEditor.js.map +1 -1
  212. package/lib/structure/ui/StructurePlaceholder.js +1 -1
  213. package/lib/structure/ui/StructurePlaceholder.js.map +1 -1
  214. package/lib/tokens/core/checkTokens.d.ts +51 -0
  215. package/lib/tokens/core/checkTokens.d.ts.map +1 -0
  216. package/lib/tokens/core/checkTokens.js +188 -0
  217. package/lib/tokens/core/checkTokens.js.map +1 -0
  218. package/lib/tokens/core/colors.d.ts +42 -0
  219. package/lib/tokens/core/colors.d.ts.map +1 -0
  220. package/lib/tokens/core/colors.js +119 -0
  221. package/lib/tokens/core/colors.js.map +1 -0
  222. package/lib/tokens/core/index.d.ts +3 -0
  223. package/lib/tokens/core/index.d.ts.map +1 -0
  224. package/lib/tokens/core/index.js +2 -0
  225. package/lib/tokens/core/index.js.map +1 -0
  226. package/lib/tokens/core/rules.d.ts +23 -0
  227. package/lib/tokens/core/rules.d.ts.map +1 -0
  228. package/lib/tokens/core/rules.js +90 -0
  229. package/lib/tokens/core/rules.js.map +1 -0
  230. package/lib/ui.d.ts +1 -0
  231. package/lib/ui.d.ts.map +1 -1
  232. package/lib/ui.js +1 -0
  233. package/lib/ui.js.map +1 -1
  234. package/lib/vite.d.ts +1 -0
  235. package/lib/vite.d.ts.map +1 -1
  236. package/lib/vite.js +1 -0
  237. package/lib/vite.js.map +1 -1
  238. package/package.json +11 -3
  239. package/src/about/core/about.ts +176 -0
  240. package/src/about/core/index.ts +2 -0
  241. package/src/about/ui/AboutCitations.tsx +79 -0
  242. package/src/about/ui/AboutPage.tsx +177 -0
  243. package/src/about/ui/AboutSection.tsx +56 -0
  244. package/src/about/ui/index.ts +6 -0
  245. package/src/chrome/ui/index.ts +3 -0
  246. package/src/citation/core/index.ts +1 -0
  247. package/src/citation/core/teachingPaper.ts +36 -0
  248. package/src/clipboard/ui/CodeBlock.tsx +4 -1
  249. package/src/color/ui/ColorScaleLegend.tsx +1 -1
  250. package/src/core.ts +5 -0
  251. package/src/credits/core/credits.ts +42 -0
  252. package/src/credits/ui/CreditsList.tsx +1 -1
  253. package/src/delimited/ui/DelimitedTextPanel.tsx +1 -1
  254. package/src/ecosystem/core/sites.ts +12 -0
  255. package/src/ecosystem/core/tokens.ts +1 -0
  256. package/src/ecosystem/ui/EcosystemLinks.tsx +2 -2
  257. package/src/ecosystem/ui/EcosystemMenu.tsx +1 -1
  258. package/src/ecosystem/ui/SiteTile.tsx +7 -5
  259. package/src/ecosystem/ui/glyphs.tsx +40 -0
  260. package/src/orbital/core/index.ts +4 -1
  261. package/src/orbital/core/realHarmonics.ts +5 -2
  262. package/src/orbital/ui/AtomicOrbitalCanvas.tsx +126 -4
  263. package/src/orbital/ui/AtomicOrbitalViewer.tsx +14 -1
  264. package/src/orbital/ui/camera.ts +81 -0
  265. package/src/orbital/ui/renderVolume.ts +8 -1
  266. package/src/orbital/ui/serial.ts +35 -0
  267. package/src/orbital/ui/viewer.ts +72 -13
  268. package/src/pedagogy/ui/ExerciseProgressHeader.tsx +1 -1
  269. package/src/pedagogy/ui/GlossaryText.tsx +2 -2
  270. package/src/pedagogy/ui/ReferenceSectionBlock.tsx +5 -2
  271. package/src/pedagogy/ui/SyntaxTooltip.tsx +2 -2
  272. package/src/pedagogy/ui/TutorialStepStrip.tsx +39 -10
  273. package/src/pedagogy/ui/index.ts +4 -1
  274. package/src/periodic/ui/CategoryLegend.tsx +1 -1
  275. package/src/periodic/ui/PeriodicTableChrome.tsx +2 -2
  276. package/src/seo/vite/ogCard.ts +1 -0
  277. package/src/share/ui/ShareDialogContent.tsx +5 -2
  278. package/src/share/ui/SharePartOptions.tsx +1 -1
  279. package/src/slides/core/demoLinks.ts +113 -0
  280. package/src/slides/core/index.ts +22 -0
  281. package/src/slides/core/sectionHeading.ts +29 -0
  282. package/src/slides/core/slideNavigation.ts +77 -0
  283. package/src/slides/core/talk.ts +203 -0
  284. package/src/slides/core/talkManifest.ts +158 -0
  285. package/src/slides/core/talkOrigin.ts +83 -0
  286. package/src/slides/ui/BackToSlides.tsx +49 -0
  287. package/src/slides/ui/DemoLink.tsx +67 -0
  288. package/src/slides/ui/EmbedSlide.tsx +85 -0
  289. package/src/slides/ui/SectionSlide.tsx +44 -0
  290. package/src/slides/ui/Slide.tsx +143 -0
  291. package/src/slides/ui/SlideBody.tsx +64 -0
  292. package/src/slides/ui/Slideshow.tsx +282 -0
  293. package/src/slides/ui/SlideshowBar.tsx +83 -0
  294. package/src/slides/ui/TalkList.tsx +146 -0
  295. package/src/slides/ui/index.ts +18 -0
  296. package/src/slides/vite/index.ts +2 -0
  297. package/src/slides/vite/talks.ts +126 -0
  298. package/src/slides.ts +2 -0
  299. package/src/structure/ui/StructureEditor.tsx +2 -2
  300. package/src/structure/ui/StructurePlaceholder.tsx +1 -1
  301. package/src/tokens/core/checkTokens.ts +242 -0
  302. package/src/tokens/core/colors.ts +122 -0
  303. package/src/tokens/core/index.ts +6 -0
  304. package/src/tokens/core/rules.ts +103 -0
  305. package/src/ui.ts +1 -0
  306. package/src/vite.ts +1 -0
  307. package/styles/chrome.css +1 -0
  308. package/styles/slides.css +667 -0
@@ -0,0 +1,90 @@
1
+ import type { Talk } from './talk.ts';
2
+ /**
3
+ * How one site publishes its talks so another can list them.
4
+ *
5
+ * The talks themselves are Markdown files served by the site that gave them;
6
+ * a manifest is the small JSON index a sibling site fetches to show them
7
+ * without holding a copy. It is read tolerantly, because the site fetching it
8
+ * has no control over the version of the file it gets.
9
+ */
10
+ /** One talk, as a listing shows it. */
11
+ export interface TalkSummary {
12
+ /** How the publishing site names the talk in its addresses. */
13
+ id: string;
14
+ /** The talk title. */
15
+ title: string;
16
+ /**
17
+ * A second line under the title.
18
+ * @default undefined
19
+ */
20
+ subtitle?: string;
21
+ /**
22
+ * Conference or event it was given at.
23
+ * @default undefined
24
+ */
25
+ event?: string;
26
+ /**
27
+ * When it was given, as an ISO date (`YYYY-MM-DD`).
28
+ * @default undefined
29
+ */
30
+ date?: string;
31
+ /**
32
+ * Who presented it.
33
+ * @default undefined
34
+ */
35
+ author?: string;
36
+ /** How many slides it holds. */
37
+ slideCount: number;
38
+ }
39
+ /** Every talk one site publishes. */
40
+ export interface TalkManifest {
41
+ /** The `ECOSYSTEM_SITES` id of the site that gave the talks. */
42
+ site: string;
43
+ /** Where that site is served from, as `https://host`. */
44
+ origin: string;
45
+ /** The talks, in the order the site lists them. */
46
+ talks: TalkSummary[];
47
+ }
48
+ /**
49
+ * The listing entry for one parsed talk.
50
+ * @param id - How the site names the talk in its addresses.
51
+ * @param talk - The parsed talk.
52
+ * @returns Its summary, carrying only the metadata a listing shows.
53
+ */
54
+ export declare function talkSummary(id: string, talk: Talk): TalkSummary;
55
+ /**
56
+ * Build the manifest a site publishes.
57
+ * @param input - The site, where it is served from, and its parsed talks.
58
+ * @param input.site - The `ECOSYSTEM_SITES` id of the publishing site.
59
+ * @param input.origin - Where that site is served from, as `https://host`.
60
+ * @param input.talks - The talks, each with the id the site names it by.
61
+ * @returns The manifest, ready to be written as JSON.
62
+ */
63
+ export declare function buildTalkManifest(input: {
64
+ /** The `ECOSYSTEM_SITES` id of the publishing site. */
65
+ site: string;
66
+ /** Where that site is served from, as `https://host`. */
67
+ origin: string;
68
+ /** The talks, each with the id the site names it by. */
69
+ talks: ReadonlyArray<{
70
+ id: string;
71
+ } & Talk>;
72
+ }): TalkManifest;
73
+ /**
74
+ * Read a manifest a sibling site published.
75
+ *
76
+ * Unknown keys are ignored and an entry missing what a listing needs is
77
+ * dropped, so a site running an older or newer version of the format still
78
+ * lists whatever it can understand instead of showing nothing.
79
+ * @param value - The parsed JSON, of unknown shape.
80
+ * @returns The manifest, or `null` when the value is not one.
81
+ */
82
+ export declare function parseTalkManifest(value: unknown): TalkManifest | null;
83
+ /**
84
+ * Where the Markdown source of one talk of a manifest is served.
85
+ * @param manifest - The manifest naming the publishing site.
86
+ * @param id - Which talk.
87
+ * @returns The absolute URL of the talk source.
88
+ */
89
+ export declare function talkSourceUrl(manifest: TalkManifest, id: string): string;
90
+ //# sourceMappingURL=talkManifest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"talkManifest.d.ts","sourceRoot":"","sources":["../../../src/slides/core/talkManifest.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEtC;;;;;;;GAOG;AAEH,uCAAuC;AACvC,MAAM,WAAW,WAAW;IAC1B,+DAA+D;IAC/D,EAAE,EAAE,MAAM,CAAC;IACX,sBAAsB;IACtB,KAAK,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gCAAgC;IAChC,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,qCAAqC;AACrC,MAAM,WAAW,YAAY;IAC3B,gEAAgE;IAChE,IAAI,EAAE,MAAM,CAAC;IACb,yDAAyD;IACzD,MAAM,EAAE,MAAM,CAAC;IACf,mDAAmD;IACnD,KAAK,EAAE,WAAW,EAAE,CAAC;CACtB;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,GAAG,WAAW,CAW/D;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE;IACvC,uDAAuD;IACvD,IAAI,EAAE,MAAM,CAAC;IACb,yDAAyD;IACzD,MAAM,EAAE,MAAM,CAAC;IACf,wDAAwD;IACxD,KAAK,EAAE,aAAa,CAAC;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC,CAAC;CAC7C,GAAG,YAAY,CAMf;AAED;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,YAAY,GAAG,IAAI,CAarE;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,YAAY,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAExE"}
@@ -0,0 +1,109 @@
1
+ /**
2
+ * The listing entry for one parsed talk.
3
+ * @param id - How the site names the talk in its addresses.
4
+ * @param talk - The parsed talk.
5
+ * @returns Its summary, carrying only the metadata a listing shows.
6
+ */
7
+ export function talkSummary(id, talk) {
8
+ const summary = {
9
+ id,
10
+ title: talk.meta.title,
11
+ slideCount: talk.slides.length,
12
+ };
13
+ if (talk.meta.subtitle !== undefined)
14
+ summary.subtitle = talk.meta.subtitle;
15
+ if (talk.meta.event !== undefined)
16
+ summary.event = talk.meta.event;
17
+ if (talk.meta.date !== undefined)
18
+ summary.date = talk.meta.date;
19
+ if (talk.meta.author !== undefined)
20
+ summary.author = talk.meta.author;
21
+ return summary;
22
+ }
23
+ /**
24
+ * Build the manifest a site publishes.
25
+ * @param input - The site, where it is served from, and its parsed talks.
26
+ * @param input.site - The `ECOSYSTEM_SITES` id of the publishing site.
27
+ * @param input.origin - Where that site is served from, as `https://host`.
28
+ * @param input.talks - The talks, each with the id the site names it by.
29
+ * @returns The manifest, ready to be written as JSON.
30
+ */
31
+ export function buildTalkManifest(input) {
32
+ const talks = [];
33
+ for (const talk of input.talks) {
34
+ talks.push(talkSummary(talk.id, talk));
35
+ }
36
+ return { site: input.site, origin: input.origin, talks };
37
+ }
38
+ /**
39
+ * Read a manifest a sibling site published.
40
+ *
41
+ * Unknown keys are ignored and an entry missing what a listing needs is
42
+ * dropped, so a site running an older or newer version of the format still
43
+ * lists whatever it can understand instead of showing nothing.
44
+ * @param value - The parsed JSON, of unknown shape.
45
+ * @returns The manifest, or `null` when the value is not one.
46
+ */
47
+ export function parseTalkManifest(value) {
48
+ if (typeof value !== 'object' || value === null)
49
+ return null;
50
+ const record = value;
51
+ const site = text(record.site);
52
+ const origin = text(record.origin);
53
+ if (site === undefined || origin === undefined)
54
+ return null;
55
+ if (!Array.isArray(record.talks))
56
+ return null;
57
+ const talks = [];
58
+ for (const entry of record.talks) {
59
+ const summary = parseSummary(entry);
60
+ if (summary !== null)
61
+ talks.push(summary);
62
+ }
63
+ return { site, origin, talks };
64
+ }
65
+ /**
66
+ * Where the Markdown source of one talk of a manifest is served.
67
+ * @param manifest - The manifest naming the publishing site.
68
+ * @param id - Which talk.
69
+ * @returns The absolute URL of the talk source.
70
+ */
71
+ export function talkSourceUrl(manifest, id) {
72
+ return `${manifest.origin.replace(TRAILING_SLASHES, '')}/talks/${id}.md`;
73
+ }
74
+ function parseSummary(value) {
75
+ if (typeof value !== 'object' || value === null)
76
+ return null;
77
+ const record = value;
78
+ const id = text(record.id);
79
+ const title = text(record.title);
80
+ const slideCount = record.slideCount;
81
+ if (id === undefined || title === undefined)
82
+ return null;
83
+ if (typeof slideCount !== 'number' || !Number.isFinite(slideCount)) {
84
+ return null;
85
+ }
86
+ const summary = {
87
+ id,
88
+ title,
89
+ slideCount: Math.max(Math.trunc(slideCount), 0),
90
+ };
91
+ const subtitle = text(record.subtitle);
92
+ const event = text(record.event);
93
+ const date = text(record.date);
94
+ const author = text(record.author);
95
+ if (subtitle !== undefined)
96
+ summary.subtitle = subtitle;
97
+ if (event !== undefined)
98
+ summary.event = event;
99
+ if (date !== undefined)
100
+ summary.date = date;
101
+ if (author !== undefined)
102
+ summary.author = author;
103
+ return summary;
104
+ }
105
+ function text(value) {
106
+ return typeof value === 'string' && value !== '' ? value : undefined;
107
+ }
108
+ const TRAILING_SLASHES = /\/+$/;
109
+ //# sourceMappingURL=talkManifest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"talkManifest.js","sourceRoot":"","sources":["../../../src/slides/core/talkManifest.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,50 @@
1
+ /**
2
+ * The round trip from a slide to a live demo and back.
3
+ *
4
+ * A demo link opens the real tool, so the presenter is then on an ordinary page
5
+ * of an ordinary site with no way back to the talk. One query parameter carries
6
+ * where they came from, which is enough for that page to offer the way back —
7
+ * and, because the site the talk lives on may not be the site the demo runs on,
8
+ * the parameter names both.
9
+ */
10
+ /** The query parameter a demo link carries its origin in. */
11
+ export declare const TALK_ORIGIN_PARAM = "from";
12
+ /** Where a demo was opened from. */
13
+ export interface TalkOrigin {
14
+ /** Which talk, as the publishing site names it. */
15
+ talkId: string;
16
+ /** Which slide of it, zero-based. */
17
+ slide: number;
18
+ /**
19
+ * The `ECOSYSTEM_SITES` id of the site the talk is published by, for a demo
20
+ * that runs on a different site than the talk.
21
+ * @default undefined — the talk lives on the site the demo runs on
22
+ */
23
+ site?: string;
24
+ }
25
+ /**
26
+ * Write an origin as the value of the `from` parameter.
27
+ * @param origin - Which talk and slide the demo was opened from.
28
+ * @returns `talk:<site>:<id>:<slide>`, or `talk:<id>:<slide>` when the talk
29
+ * lives on the site the link points at.
30
+ */
31
+ export declare function formatTalkOrigin(origin: TalkOrigin): string;
32
+ /**
33
+ * Read the origin out of an address's query string.
34
+ *
35
+ * Anything malformed reads as no origin at all: a link retyped from a slide, or
36
+ * one written before the talk was renamed, must still open the tool it points
37
+ * at rather than fail on its way in.
38
+ * @param search - The query string, with or without its leading `?`.
39
+ * @returns The origin, or `null` when the address carries none.
40
+ */
41
+ export declare function parseTalkOrigin(search: string): TalkOrigin | null;
42
+ /**
43
+ * Point a demo link at its target, carrying where it was opened from.
44
+ * @param href - The target, relative or absolute, with or without a query.
45
+ * @param origin - Which talk and slide the link sits on.
46
+ * @returns The same address with the `from` parameter added, its own
47
+ * parameters and its fragment untouched.
48
+ */
49
+ export declare function withTalkOrigin(href: string, origin: TalkOrigin): string;
50
+ //# sourceMappingURL=talkOrigin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"talkOrigin.d.ts","sourceRoot":"","sources":["../../../src/slides/core/talkOrigin.ts"],"names":[],"mappings":"AAEA;;;;;;;;GAQG;AAEH,6DAA6D;AAC7D,eAAO,MAAM,iBAAiB,SAAS,CAAC;AAExC,oCAAoC;AACpC,MAAM,WAAW,UAAU;IACzB,mDAAmD;IACnD,MAAM,EAAE,MAAM,CAAC;IACf,qCAAqC;IACrC,KAAK,EAAE,MAAM,CAAC;IACd;;;;OAIG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAI3D;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CASjE;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,MAAM,CAWvE"}
@@ -0,0 +1,62 @@
1
+ import { firstValues, parseQuery } from "../../share/core/query.js";
2
+ /**
3
+ * The round trip from a slide to a live demo and back.
4
+ *
5
+ * A demo link opens the real tool, so the presenter is then on an ordinary page
6
+ * of an ordinary site with no way back to the talk. One query parameter carries
7
+ * where they came from, which is enough for that page to offer the way back —
8
+ * and, because the site the talk lives on may not be the site the demo runs on,
9
+ * the parameter names both.
10
+ */
11
+ /** The query parameter a demo link carries its origin in. */
12
+ export const TALK_ORIGIN_PARAM = 'from';
13
+ /**
14
+ * Write an origin as the value of the `from` parameter.
15
+ * @param origin - Which talk and slide the demo was opened from.
16
+ * @returns `talk:<site>:<id>:<slide>`, or `talk:<id>:<slide>` when the talk
17
+ * lives on the site the link points at.
18
+ */
19
+ export function formatTalkOrigin(origin) {
20
+ const slide = Math.max(Math.trunc(origin.slide), 0);
21
+ const site = origin.site === undefined ? '' : `${origin.site}:`;
22
+ return `talk:${site}${origin.talkId}:${slide}`;
23
+ }
24
+ /**
25
+ * Read the origin out of an address's query string.
26
+ *
27
+ * Anything malformed reads as no origin at all: a link retyped from a slide, or
28
+ * one written before the talk was renamed, must still open the tool it points
29
+ * at rather than fail on its way in.
30
+ * @param search - The query string, with or without its leading `?`.
31
+ * @returns The origin, or `null` when the address carries none.
32
+ */
33
+ export function parseTalkOrigin(search) {
34
+ const value = firstValues(parseQuery(search)).get(TALK_ORIGIN_PARAM);
35
+ if (value === undefined)
36
+ return null;
37
+ const match = ORIGIN_RE.exec(value);
38
+ const talkId = match?.groups?.talkId;
39
+ const slide = Number.parseInt(match?.groups?.slide ?? '', 10);
40
+ if (talkId === undefined || !Number.isFinite(slide))
41
+ return null;
42
+ const site = match?.groups?.site;
43
+ return site === undefined ? { talkId, slide } : { talkId, slide, site };
44
+ }
45
+ /**
46
+ * Point a demo link at its target, carrying where it was opened from.
47
+ * @param href - The target, relative or absolute, with or without a query.
48
+ * @param origin - Which talk and slide the link sits on.
49
+ * @returns The same address with the `from` parameter added, its own
50
+ * parameters and its fragment untouched.
51
+ */
52
+ export function withTalkOrigin(href, origin) {
53
+ const cut = href.indexOf('#');
54
+ const address = cut === -1 ? href : href.slice(0, cut);
55
+ const fragment = cut === -1 ? '' : href.slice(cut);
56
+ const separator = address.includes('?') ? '&' : '?';
57
+ // A colon reads as a colon in these links, and parses back identically.
58
+ const value = encodeURIComponent(formatTalkOrigin(origin)).replaceAll('%3A', ':');
59
+ return `${address}${separator}${TALK_ORIGIN_PARAM}=${value}${fragment}`;
60
+ }
61
+ const ORIGIN_RE = /^talk:(?:(?<site>[\da-z-]+):)?(?<talkId>[^:]+):(?<slide>\d+)$/i;
62
+ //# sourceMappingURL=talkOrigin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"talkOrigin.js","sourceRoot":"","sources":["../../../src/slides/core/talkOrigin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAEpE;;;;;;;;GAQG;AAEH,6DAA6D;AAC7D,MAAM,CAAC,MAAM,iBAAiB,GAAG,MAAM,CAAC;AAgBxC;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAAC,MAAkB;IACjD,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC;IACpD,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,IAAI,GAAG,CAAC;IAChE,OAAO,QAAQ,IAAI,GAAG,MAAM,CAAC,MAAM,IAAI,KAAK,EAAE,CAAC;AACjD,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,eAAe,CAAC,MAAc;IAC5C,MAAM,KAAK,GAAG,WAAW,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;IACrE,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,IAAI,CAAC;IACrC,MAAM,KAAK,GAAG,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACpC,MAAM,MAAM,GAAG,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC;IACrC,MAAM,KAAK,GAAG,MAAM,CAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;IAC9D,IAAI,MAAM,KAAK,SAAS,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACjE,MAAM,IAAI,GAAG,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC;IACjC,OAAO,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;AAC1E,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,cAAc,CAAC,IAAY,EAAE,MAAkB;IAC7D,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAC9B,MAAM,OAAO,GAAG,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IACvD,MAAM,QAAQ,GAAG,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACnD,MAAM,SAAS,GAAG,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;IACpD,wEAAwE;IACxE,MAAM,KAAK,GAAG,kBAAkB,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC,CAAC,UAAU,CACnE,KAAK,EACL,GAAG,CACJ,CAAC;IACF,OAAO,GAAG,OAAO,GAAG,SAAS,GAAG,iBAAiB,IAAI,KAAK,GAAG,QAAQ,EAAE,CAAC;AAC1E,CAAC;AAED,MAAM,SAAS,GACb,gEAAgE,CAAC"}
@@ -0,0 +1,26 @@
1
+ import type { ReactElement } from 'react';
2
+ import type { TalkOrigin } from '../core/index.ts';
3
+ /** Where the visitor came from, and how to send them back. */
4
+ export interface BackToSlidesProps {
5
+ /** The talk and slide a demo link was opened from, or `null` for none. */
6
+ origin: TalkOrigin | null;
7
+ /** The address of that slide. */
8
+ href: string;
9
+ /**
10
+ * What the site does when the pill is clicked, for a site that routes in the
11
+ * browser. A modified click is left to the browser either way.
12
+ * @default undefined — the browser follows the address
13
+ */
14
+ onReturn?: () => void;
15
+ }
16
+ /**
17
+ * The way back to the slide a demo was opened from.
18
+ *
19
+ * A demo link drops the presenter on an ordinary page of an ordinary site, so
20
+ * during a talk the site stays fully browsable and the talk stays one click
21
+ * away. It renders nothing at all when the page was not reached from a slide.
22
+ * @param props - See {@link BackToSlidesProps}.
23
+ * @returns The pill, or nothing.
24
+ */
25
+ export declare function BackToSlides(props: BackToSlidesProps): ReactElement | null;
26
+ //# sourceMappingURL=BackToSlides.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BackToSlides.d.ts","sourceRoot":"","sources":["../../../src/slides/ui/BackToSlides.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,OAAO,CAAC;AAG1C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEnD,8DAA8D;AAC9D,MAAM,WAAW,iBAAiB;IAChC,0EAA0E;IAC1E,MAAM,EAAE,UAAU,GAAG,IAAI,CAAC;IAC1B,iCAAiC;IACjC,IAAI,EAAE,MAAM,CAAC;IACb;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;CACvB;AAED;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,iBAAiB,GAAG,YAAY,GAAG,IAAI,CAmB1E"}
@@ -0,0 +1,24 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Icon } from '@blueprintjs/core';
3
+ import { isModifiedClick } from "../../chrome/ui/navItem.js";
4
+ /**
5
+ * The way back to the slide a demo was opened from.
6
+ *
7
+ * A demo link drops the presenter on an ordinary page of an ordinary site, so
8
+ * during a talk the site stays fully browsable and the talk stays one click
9
+ * away. It renders nothing at all when the page was not reached from a slide.
10
+ * @param props - See {@link BackToSlidesProps}.
11
+ * @returns The pill, or nothing.
12
+ */
13
+ export function BackToSlides(props) {
14
+ const { origin, href, onReturn } = props;
15
+ if (origin === null)
16
+ return null;
17
+ return (_jsxs("a", { className: "back-to-slides no-print", href: href, title: `Back to slide ${origin.slide + 1}`, onClick: (event) => {
18
+ if (onReturn === undefined || isModifiedClick(event))
19
+ return;
20
+ event.preventDefault();
21
+ onReturn();
22
+ }, children: [_jsx(Icon, { icon: "presentation", size: 14 }), "Back to slides"] }));
23
+ }
24
+ //# sourceMappingURL=BackToSlides.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BackToSlides.js","sourceRoot":"","sources":["../../../src/slides/ui/BackToSlides.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAGzC,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAiB7D;;;;;;;;GAQG;AACH,MAAM,UAAU,YAAY,CAAC,KAAwB;IACnD,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,KAAK,CAAC;IACzC,IAAI,MAAM,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAEjC,OAAO,CACL,aACE,SAAS,EAAC,yBAAyB,EACnC,IAAI,EAAE,IAAI,EACV,KAAK,EAAE,iBAAiB,MAAM,CAAC,KAAK,GAAG,CAAC,EAAE,EAC1C,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE;YACjB,IAAI,QAAQ,KAAK,SAAS,IAAI,eAAe,CAAC,KAAK,CAAC;gBAAE,OAAO;YAC7D,KAAK,CAAC,cAAc,EAAE,CAAC;YACvB,QAAQ,EAAE,CAAC;QACb,CAAC,aAED,KAAC,IAAI,IAAC,IAAI,EAAC,cAAc,EAAC,IAAI,EAAE,EAAE,GAAI,sBAEpC,CACL,CAAC;AACJ,CAAC"}
@@ -0,0 +1,42 @@
1
+ import type { ReactElement, ReactNode } from 'react';
2
+ import type { TalkOrigin } from '../core/index.ts';
3
+ /**
4
+ * How a site draws a link that leaves a slide for one of its own pages.
5
+ *
6
+ * The player never navigates: a site that routes in the browser passes its own
7
+ * link here, and the address it is given already carries the slide it was
8
+ * opened from. The children arrive already wrapped in the deck's arrow and
9
+ * label spans, so a site's element only has to carry `slide-demo` for the
10
+ * styling to apply.
11
+ */
12
+ export type RenderSlideLink = (link: {
13
+ /** The address the link opens, `from` parameter included. */
14
+ href: string;
15
+ /** What the link reads. */
16
+ children: ReactNode;
17
+ }) => ReactElement;
18
+ /** What a demo link points at, and how it is drawn. */
19
+ export interface DemoLinkProps {
20
+ /** The in-app route the demo opens, as the slide wrote it. */
21
+ href: string;
22
+ /**
23
+ * Which slide the link sits on, added to the address so the tool it opens can
24
+ * offer the way back. Nothing is added when it is left out.
25
+ * @default undefined
26
+ */
27
+ origin?: TalkOrigin;
28
+ /**
29
+ * The site's own link, for a site that routes in the browser.
30
+ * @default undefined — a plain anchor
31
+ */
32
+ renderLink?: RenderSlideLink;
33
+ /** The link label. */
34
+ children: ReactNode;
35
+ }
36
+ /**
37
+ * A link from a slide into the live tool it demonstrates.
38
+ * @param props - See {@link DemoLinkProps}.
39
+ * @returns The link.
40
+ */
41
+ export declare function DemoLink(props: DemoLinkProps): ReactElement;
42
+ //# sourceMappingURL=DemoLink.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DemoLink.d.ts","sourceRoot":"","sources":["../../../src/slides/ui/DemoLink.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAErD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAGnD;;;;;;;;GAQG;AACH,MAAM,MAAM,eAAe,GAAG,CAAC,IAAI,EAAE;IACnC,6DAA6D;IAC7D,IAAI,EAAE,MAAM,CAAC;IACb,2BAA2B;IAC3B,QAAQ,EAAE,SAAS,CAAC;CACrB,KAAK,YAAY,CAAC;AAEnB,uDAAuD;AACvD,MAAM,WAAW,aAAa;IAC5B,8DAA8D;IAC9D,IAAI,EAAE,MAAM,CAAC;IACb;;;;OAIG;IACH,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB;;;OAGG;IACH,UAAU,CAAC,EAAE,eAAe,CAAC;IAC7B,sBAAsB;IACtB,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,aAAa,GAAG,YAAY,CAqB3D"}
@@ -0,0 +1,17 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { withTalkOrigin } from "../core/index.js";
3
+ /**
4
+ * A link from a slide into the live tool it demonstrates.
5
+ * @param props - See {@link DemoLinkProps}.
6
+ * @returns The link.
7
+ */
8
+ export function DemoLink(props) {
9
+ const { href, origin, renderLink, children } = props;
10
+ const address = origin === undefined ? href : withTalkOrigin(href, origin);
11
+ const label = (_jsxs(_Fragment, { children: [_jsx("span", { className: "slide-demo-arrow", "aria-hidden": "true", children: "\u25B8" }), _jsx("span", { className: "slide-demo-label", children: children })] }));
12
+ if (renderLink !== undefined) {
13
+ return renderLink({ href: address, children: label });
14
+ }
15
+ return (_jsx("a", { className: "slide-demo", href: address, children: label }));
16
+ }
17
+ //# sourceMappingURL=DemoLink.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DemoLink.js","sourceRoot":"","sources":["../../../src/slides/ui/DemoLink.tsx"],"names":[],"mappings":";AAGA,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAqClD;;;;GAIG;AACH,MAAM,UAAU,QAAQ,CAAC,KAAoB;IAC3C,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,GAAG,KAAK,CAAC;IACrD,MAAM,OAAO,GAAG,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,cAAc,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAC3E,MAAM,KAAK,GAAG,CACZ,8BACE,eAAM,SAAS,EAAC,kBAAkB,iBAAa,MAAM,uBAE9C,EACP,eAAM,SAAS,EAAC,kBAAkB,YAAE,QAAQ,GAAQ,IACnD,CACJ,CAAC;IAEF,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;QAC7B,OAAO,UAAU,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC;IACxD,CAAC;IAED,OAAO,CACL,YAAG,SAAS,EAAC,YAAY,EAAC,IAAI,EAAE,OAAO,YACpC,KAAK,GACJ,CACL,CAAC;AACJ,CAAC"}
@@ -0,0 +1,19 @@
1
+ import type { ReactElement } from 'react';
2
+ import type { Slide } from '../core/talk.ts';
3
+ /** What an embedded slide draws. */
4
+ export interface EmbedSlideProps {
5
+ /** The slide, whose body holds the prose and, on its own line, the address. */
6
+ slide: Slide;
7
+ }
8
+ /**
9
+ * A slide that is the tool itself, running.
10
+ *
11
+ * Every tool of the family takes `?embed`, so a lecture can show the real thing
12
+ * instead of a screenshot of it — which is also the only version of the slide
13
+ * that stays true after the tool is improved. The heading and any prose stay
14
+ * above the frame; the last bare URL of the body is what is framed.
15
+ * @param props - See {@link EmbedSlideProps}.
16
+ * @returns The slide.
17
+ */
18
+ export declare function EmbedSlide(props: EmbedSlideProps): ReactElement;
19
+ //# sourceMappingURL=EmbedSlide.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EmbedSlide.d.ts","sourceRoot":"","sources":["../../../src/slides/ui/EmbedSlide.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,OAAO,CAAC;AAE1C,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AAI7C,oCAAoC;AACpC,MAAM,WAAW,eAAe;IAC9B,+EAA+E;IAC/E,KAAK,EAAE,KAAK,CAAC;CACd;AAED;;;;;;;;;GASG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,eAAe,GAAG,YAAY,CAuB/D"}
@@ -0,0 +1,56 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { SlideBody } from "./SlideBody.js";
3
+ /**
4
+ * A slide that is the tool itself, running.
5
+ *
6
+ * Every tool of the family takes `?embed`, so a lecture can show the real thing
7
+ * instead of a screenshot of it — which is also the only version of the slide
8
+ * that stays true after the tool is improved. The heading and any prose stay
9
+ * above the frame; the last bare URL of the body is what is framed.
10
+ * @param props - See {@link EmbedSlideProps}.
11
+ * @returns The slide.
12
+ */
13
+ export function EmbedSlide(props) {
14
+ const { slide } = props;
15
+ const { prose, src } = splitEmbedAddress(slide.body);
16
+ return (_jsx("div", { className: "slide slide--embed", children: _jsxs("div", { className: "slide-content", children: [prose === '' ? null : _jsx(SlideBody, { body: prose }), src === null ? (_jsx("p", { className: "slide-embed-missing", children: "This slide frames a tool, but carries no address." })) : (_jsx("iframe", { className: "slide-embed-frame", src: src, title: frameTitle(src), allow: "clipboard-write; fullscreen" }))] }) }));
17
+ }
18
+ /**
19
+ * The prose and the address of an embedded slide.
20
+ *
21
+ * The address is written as a bare URL on its own line, because a teacher
22
+ * pastes what the tool's Share dialog gave them and nothing else.
23
+ * @param body - The slide body.
24
+ * @returns The prose without the address, and the address.
25
+ */
26
+ function splitEmbedAddress(body) {
27
+ const lines = body.split('\n');
28
+ for (let index = lines.length - 1; index >= 0; index--) {
29
+ const line = (lines[index] ?? '').trim();
30
+ if (line === '')
31
+ continue;
32
+ if (!line.startsWith('http://') && !line.startsWith('https://'))
33
+ break;
34
+ if (line.includes(' '))
35
+ break;
36
+ const prose = [...lines.slice(0, index), ...lines.slice(index + 1)]
37
+ .join('\n')
38
+ .trim();
39
+ return { prose, src: line };
40
+ }
41
+ return { prose: body.trim(), src: null };
42
+ }
43
+ /**
44
+ * A frame without a title is unreadable to a screen reader.
45
+ * @param src - The address being framed.
46
+ * @returns What the frame is called.
47
+ */
48
+ function frameTitle(src) {
49
+ try {
50
+ return `${new URL(src).hostname}, embedded`;
51
+ }
52
+ catch {
53
+ return 'Embedded tool';
54
+ }
55
+ }
56
+ //# sourceMappingURL=EmbedSlide.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EmbedSlide.js","sourceRoot":"","sources":["../../../src/slides/ui/EmbedSlide.tsx"],"names":[],"mappings":";AAIA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAiB,CAAC;AAQ5C;;;;;;;;;GASG;AACH,MAAM,UAAU,UAAU,CAAC,KAAsB;IAC/C,MAAM,EAAE,KAAK,EAAE,GAAG,KAAK,CAAC;IACxB,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,iBAAiB,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAErD,OAAO,CACL,cAAK,SAAS,EAAC,oBAAoB,YACjC,eAAK,SAAS,EAAC,eAAe,aAC3B,KAAK,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAC,SAAS,IAAC,IAAI,EAAE,KAAK,GAAI,EAChD,GAAG,KAAK,IAAI,CAAC,CAAC,CAAC,CACd,YAAG,SAAS,EAAC,qBAAqB,kEAE9B,CACL,CAAC,CAAC,CAAC,CACF,iBACE,SAAS,EAAC,mBAAmB,EAC7B,GAAG,EAAE,GAAG,EACR,KAAK,EAAE,UAAU,CAAC,GAAG,CAAC,EACtB,KAAK,EAAC,6BAA6B,GACnC,CACH,IACG,GACF,CACP,CAAC;AACJ,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,iBAAiB,CAAC,IAAY;IAIrC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC/B,KAAK,IAAI,KAAK,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,KAAK,IAAI,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC;QACvD,MAAM,IAAI,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;QACzC,IAAI,IAAI,KAAK,EAAE;YAAE,SAAS;QAC1B,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC;YAAE,MAAM;QACvE,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC;YAAE,MAAM;QAC9B,MAAM,KAAK,GAAG,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,GAAG,KAAK,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;aAChE,IAAI,CAAC,IAAI,CAAC;aACV,IAAI,EAAE,CAAC;QACV,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC;IAC9B,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,IAAI,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC;AAC3C,CAAC;AAED;;;;GAIG;AACH,SAAS,UAAU,CAAC,GAAW;IAC7B,IAAI,CAAC;QACH,OAAO,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,YAAY,CAAC;IAC9C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,eAAe,CAAC;IACzB,CAAC;AACH,CAAC"}
@@ -0,0 +1,18 @@
1
+ import type { ReactElement } from 'react';
2
+ /** The body of a section divider. */
3
+ export interface SectionSlideProps {
4
+ /** The Markdown body, normally starting with `# N · Title`. */
5
+ body: string;
6
+ }
7
+ /**
8
+ * The slide that says a new part of the talk starts here: the section number
9
+ * set huge and near-transparent, with the title, an accent rule and whatever
10
+ * else the body holds stacked beside it.
11
+ *
12
+ * The numeral is decoration, not text — the heading beside it already says
13
+ * where the talk is — so it is hidden from a screen reader.
14
+ * @param props - See {@link SectionSlideProps}.
15
+ * @returns The divider slide.
16
+ */
17
+ export declare function SectionSlide(props: SectionSlideProps): ReactElement;
18
+ //# sourceMappingURL=SectionSlide.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SectionSlide.d.ts","sourceRoot":"","sources":["../../../src/slides/ui/SectionSlide.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,OAAO,CAAC;AAM1C,qCAAqC;AACrC,MAAM,WAAW,iBAAiB;IAChC,+DAA+D;IAC/D,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,iBAAiB,GAAG,YAAY,CAqBnE"}
@@ -0,0 +1,18 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { parseSectionHeading } from "../core/index.js";
3
+ import { SlideBody } from "./SlideBody.js";
4
+ /**
5
+ * The slide that says a new part of the talk starts here: the section number
6
+ * set huge and near-transparent, with the title, an accent rule and whatever
7
+ * else the body holds stacked beside it.
8
+ *
9
+ * The numeral is decoration, not text — the heading beside it already says
10
+ * where the talk is — so it is hidden from a screen reader.
11
+ * @param props - See {@link SectionSlideProps}.
12
+ * @returns The divider slide.
13
+ */
14
+ export function SectionSlide(props) {
15
+ const { number, title, rest } = parseSectionHeading(props.body);
16
+ return (_jsx("div", { className: "slide slide--section", children: _jsxs("div", { className: "section-slide", children: [_jsx("div", { className: "section-number", "aria-hidden": "true", children: number }), _jsxs("div", { className: "section-body", children: [title === '' ? null : _jsx("h1", { className: "section-title", children: title }), _jsx("hr", { className: "section-rule" }), rest === '' ? null : (_jsx("div", { className: "section-sub", children: _jsx(SlideBody, { body: rest }) }))] })] }) }));
17
+ }
18
+ //# sourceMappingURL=SectionSlide.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SectionSlide.js","sourceRoot":"","sources":["../../../src/slides/ui/SectionSlide.tsx"],"names":[],"mappings":";AAEA,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAEvD,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAiB,CAAC;AAQ5C;;;;;;;;;GASG;AACH,MAAM,UAAU,YAAY,CAAC,KAAwB;IACnD,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,mBAAmB,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAEhE,OAAO,CACL,cAAK,SAAS,EAAC,sBAAsB,YACnC,eAAK,SAAS,EAAC,eAAe,aAC5B,cAAK,SAAS,EAAC,gBAAgB,iBAAa,MAAM,YAC/C,MAAM,GACH,EACN,eAAK,SAAS,EAAC,cAAc,aAC1B,KAAK,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,aAAI,SAAS,EAAC,eAAe,YAAE,KAAK,GAAM,EACjE,aAAI,SAAS,EAAC,cAAc,GAAG,EAC9B,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CACpB,cAAK,SAAS,EAAC,aAAa,YAC1B,KAAC,SAAS,IAAC,IAAI,EAAE,IAAI,GAAI,GACrB,CACP,IACG,IACF,GACF,CACP,CAAC;AACJ,CAAC"}