react-cheminfo 0.8.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.
- package/README.md +60 -2
- package/bin/check-tokens.mjs +105 -0
- package/lib/about/core/about.d.ts +95 -0
- package/lib/about/core/about.d.ts.map +1 -0
- package/lib/about/core/about.js +78 -0
- package/lib/about/core/about.js.map +1 -0
- package/lib/about/core/index.d.ts +3 -0
- package/lib/about/core/index.d.ts.map +1 -0
- package/lib/about/core/index.js +2 -0
- package/lib/about/core/index.js.map +1 -0
- package/lib/about/ui/AboutCitations.d.ts +14 -0
- package/lib/about/ui/AboutCitations.d.ts.map +1 -0
- package/lib/about/ui/AboutCitations.js +40 -0
- package/lib/about/ui/AboutCitations.js.map +1 -0
- package/lib/about/ui/AboutPage.d.ts +32 -0
- package/lib/about/ui/AboutPage.d.ts.map +1 -0
- package/lib/about/ui/AboutPage.js +70 -0
- package/lib/about/ui/AboutPage.js.map +1 -0
- package/lib/about/ui/AboutSection.d.ts +23 -0
- package/lib/about/ui/AboutSection.d.ts.map +1 -0
- package/lib/about/ui/AboutSection.js +28 -0
- package/lib/about/ui/AboutSection.js.map +1 -0
- package/lib/about/ui/index.d.ts +7 -0
- package/lib/about/ui/index.d.ts.map +1 -0
- package/lib/about/ui/index.js +4 -0
- package/lib/about/ui/index.js.map +1 -0
- package/lib/chrome/ui/index.d.ts +1 -0
- package/lib/chrome/ui/index.d.ts.map +1 -1
- package/lib/chrome/ui/index.js +3 -0
- package/lib/chrome/ui/index.js.map +1 -1
- package/lib/clipboard/ui/CodeBlock.d.ts.map +1 -1
- package/lib/clipboard/ui/CodeBlock.js +4 -1
- package/lib/clipboard/ui/CodeBlock.js.map +1 -1
- package/lib/color/ui/ColorScaleLegend.js +1 -1
- package/lib/color/ui/ColorScaleLegend.js.map +1 -1
- package/lib/core.d.ts +3 -0
- package/lib/core.d.ts.map +1 -1
- package/lib/core.js +5 -0
- package/lib/core.js.map +1 -1
- package/lib/credits/core/credits.d.ts +36 -0
- package/lib/credits/core/credits.d.ts.map +1 -1
- package/lib/credits/core/credits.js +42 -0
- package/lib/credits/core/credits.js.map +1 -1
- package/lib/credits/ui/CreditsList.js +1 -1
- package/lib/credits/ui/CreditsList.js.map +1 -1
- package/lib/delimited/ui/DelimitedTextPanel.js +1 -1
- package/lib/delimited/ui/DelimitedTextPanel.js.map +1 -1
- package/lib/ecosystem/core/sites.d.ts +1 -1
- package/lib/ecosystem/core/sites.d.ts.map +1 -1
- package/lib/ecosystem/core/sites.js +10 -0
- package/lib/ecosystem/core/sites.js.map +1 -1
- package/lib/ecosystem/core/tokens.d.ts.map +1 -1
- package/lib/ecosystem/core/tokens.js +1 -0
- package/lib/ecosystem/core/tokens.js.map +1 -1
- package/lib/ecosystem/ui/EcosystemLinks.js +2 -2
- package/lib/ecosystem/ui/EcosystemLinks.js.map +1 -1
- package/lib/ecosystem/ui/EcosystemMenu.js +1 -1
- package/lib/ecosystem/ui/EcosystemMenu.js.map +1 -1
- package/lib/ecosystem/ui/SiteTile.d.ts.map +1 -1
- package/lib/ecosystem/ui/SiteTile.js +5 -5
- package/lib/ecosystem/ui/SiteTile.js.map +1 -1
- package/lib/ecosystem/ui/glyphs.d.ts.map +1 -1
- package/lib/ecosystem/ui/glyphs.js +3 -0
- package/lib/ecosystem/ui/glyphs.js.map +1 -1
- package/lib/orbital/core/index.d.ts +1 -1
- package/lib/orbital/core/index.d.ts.map +1 -1
- package/lib/orbital/core/index.js +1 -1
- package/lib/orbital/core/index.js.map +1 -1
- package/lib/orbital/core/realHarmonics.d.ts +5 -2
- package/lib/orbital/core/realHarmonics.d.ts.map +1 -1
- package/lib/orbital/core/realHarmonics.js.map +1 -1
- package/lib/orbital/ui/AtomicOrbitalCanvas.d.ts +18 -0
- package/lib/orbital/ui/AtomicOrbitalCanvas.d.ts.map +1 -1
- package/lib/orbital/ui/AtomicOrbitalCanvas.js +84 -7
- package/lib/orbital/ui/AtomicOrbitalCanvas.js.map +1 -1
- package/lib/orbital/ui/AtomicOrbitalViewer.d.ts +13 -0
- package/lib/orbital/ui/AtomicOrbitalViewer.d.ts.map +1 -1
- package/lib/orbital/ui/AtomicOrbitalViewer.js +1 -1
- package/lib/orbital/ui/AtomicOrbitalViewer.js.map +1 -1
- package/lib/orbital/ui/camera.d.ts +15 -0
- package/lib/orbital/ui/camera.d.ts.map +1 -1
- package/lib/orbital/ui/camera.js +68 -0
- package/lib/orbital/ui/camera.js.map +1 -1
- package/lib/orbital/ui/renderVolume.d.ts.map +1 -1
- package/lib/orbital/ui/renderVolume.js +8 -1
- package/lib/orbital/ui/renderVolume.js.map +1 -1
- package/lib/orbital/ui/serial.d.ts +25 -0
- package/lib/orbital/ui/serial.d.ts.map +1 -0
- package/lib/orbital/ui/serial.js +25 -0
- package/lib/orbital/ui/serial.js.map +1 -0
- package/lib/orbital/ui/viewer.d.ts +23 -0
- package/lib/orbital/ui/viewer.d.ts.map +1 -1
- package/lib/orbital/ui/viewer.js +70 -17
- package/lib/orbital/ui/viewer.js.map +1 -1
- package/lib/pedagogy/ui/ExerciseProgressHeader.js +1 -1
- package/lib/pedagogy/ui/ExerciseProgressHeader.js.map +1 -1
- package/lib/pedagogy/ui/GlossaryText.js +2 -2
- package/lib/pedagogy/ui/GlossaryText.js.map +1 -1
- package/lib/pedagogy/ui/ReferenceSectionBlock.js +5 -2
- package/lib/pedagogy/ui/ReferenceSectionBlock.js.map +1 -1
- package/lib/pedagogy/ui/SyntaxTooltip.js +2 -2
- package/lib/pedagogy/ui/SyntaxTooltip.js.map +1 -1
- package/lib/pedagogy/ui/TutorialStepStrip.js +4 -1
- package/lib/pedagogy/ui/TutorialStepStrip.js.map +1 -1
- package/lib/periodic/ui/CategoryLegend.js +1 -1
- package/lib/periodic/ui/CategoryLegend.js.map +1 -1
- package/lib/periodic/ui/PeriodicTableChrome.js +2 -2
- package/lib/periodic/ui/PeriodicTableChrome.js.map +1 -1
- package/lib/seo/vite/ogCard.d.ts.map +1 -1
- package/lib/seo/vite/ogCard.js +1 -0
- package/lib/seo/vite/ogCard.js.map +1 -1
- package/lib/share/ui/ShareDialogContent.d.ts.map +1 -1
- package/lib/share/ui/ShareDialogContent.js +5 -2
- package/lib/share/ui/ShareDialogContent.js.map +1 -1
- package/lib/share/ui/SharePartOptions.js +1 -1
- package/lib/share/ui/SharePartOptions.js.map +1 -1
- package/lib/slides/core/demoLinks.d.ts +43 -0
- package/lib/slides/core/demoLinks.d.ts.map +1 -0
- package/lib/slides/core/demoLinks.js +104 -0
- package/lib/slides/core/demoLinks.js.map +1 -0
- package/lib/slides/core/index.d.ts +13 -0
- package/lib/slides/core/index.d.ts.map +1 -0
- package/lib/slides/core/index.js +7 -0
- package/lib/slides/core/index.js.map +1 -0
- package/lib/slides/core/sectionHeading.d.ts +19 -0
- package/lib/slides/core/sectionHeading.d.ts.map +1 -0
- package/lib/slides/core/sectionHeading.js +19 -0
- package/lib/slides/core/sectionHeading.js.map +1 -0
- package/lib/slides/core/slideNavigation.d.ts +38 -0
- package/lib/slides/core/slideNavigation.d.ts.map +1 -0
- package/lib/slides/core/slideNavigation.js +65 -0
- package/lib/slides/core/slideNavigation.js.map +1 -0
- package/lib/slides/core/talk.d.ts +82 -0
- package/lib/slides/core/talk.d.ts.map +1 -0
- package/lib/slides/core/talk.js +134 -0
- package/lib/slides/core/talk.js.map +1 -0
- package/lib/slides/core/talkManifest.d.ts +90 -0
- package/lib/slides/core/talkManifest.d.ts.map +1 -0
- package/lib/slides/core/talkManifest.js +109 -0
- package/lib/slides/core/talkManifest.js.map +1 -0
- package/lib/slides/core/talkOrigin.d.ts +50 -0
- package/lib/slides/core/talkOrigin.d.ts.map +1 -0
- package/lib/slides/core/talkOrigin.js +62 -0
- package/lib/slides/core/talkOrigin.js.map +1 -0
- package/lib/slides/ui/BackToSlides.d.ts +26 -0
- package/lib/slides/ui/BackToSlides.d.ts.map +1 -0
- package/lib/slides/ui/BackToSlides.js +24 -0
- package/lib/slides/ui/BackToSlides.js.map +1 -0
- package/lib/slides/ui/DemoLink.d.ts +42 -0
- package/lib/slides/ui/DemoLink.d.ts.map +1 -0
- package/lib/slides/ui/DemoLink.js +17 -0
- package/lib/slides/ui/DemoLink.js.map +1 -0
- package/lib/slides/ui/EmbedSlide.d.ts +19 -0
- package/lib/slides/ui/EmbedSlide.d.ts.map +1 -0
- package/lib/slides/ui/EmbedSlide.js +56 -0
- package/lib/slides/ui/EmbedSlide.js.map +1 -0
- package/lib/slides/ui/SectionSlide.d.ts +18 -0
- package/lib/slides/ui/SectionSlide.d.ts.map +1 -0
- package/lib/slides/ui/SectionSlide.js +18 -0
- package/lib/slides/ui/SectionSlide.js.map +1 -0
- package/lib/slides/ui/Slide.d.ts +52 -0
- package/lib/slides/ui/Slide.d.ts.map +1 -0
- package/lib/slides/ui/Slide.js +58 -0
- package/lib/slides/ui/Slide.js.map +1 -0
- package/lib/slides/ui/SlideBody.d.ts +32 -0
- package/lib/slides/ui/SlideBody.d.ts.map +1 -0
- package/lib/slides/ui/SlideBody.js +27 -0
- package/lib/slides/ui/SlideBody.js.map +1 -0
- package/lib/slides/ui/Slideshow.d.ts +93 -0
- package/lib/slides/ui/Slideshow.d.ts.map +1 -0
- package/lib/slides/ui/Slideshow.js +122 -0
- package/lib/slides/ui/Slideshow.js.map +1 -0
- package/lib/slides/ui/SlideshowBar.d.ts +33 -0
- package/lib/slides/ui/SlideshowBar.d.ts.map +1 -0
- package/lib/slides/ui/SlideshowBar.js +20 -0
- package/lib/slides/ui/SlideshowBar.js.map +1 -0
- package/lib/slides/ui/TalkList.d.ts +37 -0
- package/lib/slides/ui/TalkList.d.ts.map +1 -0
- package/lib/slides/ui/TalkList.js +68 -0
- package/lib/slides/ui/TalkList.js.map +1 -0
- package/lib/slides/ui/index.d.ts +19 -0
- package/lib/slides/ui/index.d.ts.map +1 -0
- package/lib/slides/ui/index.js +10 -0
- package/lib/slides/ui/index.js.map +1 -0
- package/lib/slides/vite/index.d.ts +3 -0
- package/lib/slides/vite/index.d.ts.map +1 -0
- package/lib/slides/vite/index.js +2 -0
- package/lib/slides/vite/index.js.map +1 -0
- package/lib/slides/vite/talks.d.ts +50 -0
- package/lib/slides/vite/talks.d.ts.map +1 -0
- package/lib/slides/vite/talks.js +87 -0
- package/lib/slides/vite/talks.js.map +1 -0
- package/lib/slides.d.ts +3 -0
- package/lib/slides.d.ts.map +1 -0
- package/lib/slides.js +3 -0
- package/lib/slides.js.map +1 -0
- package/lib/structure/ui/StructureEditor.js +2 -2
- package/lib/structure/ui/StructureEditor.js.map +1 -1
- package/lib/structure/ui/StructurePlaceholder.js +1 -1
- package/lib/structure/ui/StructurePlaceholder.js.map +1 -1
- package/lib/tokens/core/checkTokens.d.ts +51 -0
- package/lib/tokens/core/checkTokens.d.ts.map +1 -0
- package/lib/tokens/core/checkTokens.js +188 -0
- package/lib/tokens/core/checkTokens.js.map +1 -0
- package/lib/tokens/core/colors.d.ts +42 -0
- package/lib/tokens/core/colors.d.ts.map +1 -0
- package/lib/tokens/core/colors.js +119 -0
- package/lib/tokens/core/colors.js.map +1 -0
- package/lib/tokens/core/index.d.ts +3 -0
- package/lib/tokens/core/index.d.ts.map +1 -0
- package/lib/tokens/core/index.js +2 -0
- package/lib/tokens/core/index.js.map +1 -0
- package/lib/tokens/core/rules.d.ts +23 -0
- package/lib/tokens/core/rules.d.ts.map +1 -0
- package/lib/tokens/core/rules.js +90 -0
- package/lib/tokens/core/rules.js.map +1 -0
- package/lib/ui.d.ts +1 -0
- package/lib/ui.d.ts.map +1 -1
- package/lib/ui.js +1 -0
- package/lib/ui.js.map +1 -1
- package/lib/vite.d.ts +1 -0
- package/lib/vite.d.ts.map +1 -1
- package/lib/vite.js +1 -0
- package/lib/vite.js.map +1 -1
- package/package.json +11 -3
- package/src/about/core/about.ts +176 -0
- package/src/about/core/index.ts +2 -0
- package/src/about/ui/AboutCitations.tsx +79 -0
- package/src/about/ui/AboutPage.tsx +177 -0
- package/src/about/ui/AboutSection.tsx +56 -0
- package/src/about/ui/index.ts +6 -0
- package/src/chrome/ui/index.ts +3 -0
- package/src/clipboard/ui/CodeBlock.tsx +4 -1
- package/src/color/ui/ColorScaleLegend.tsx +1 -1
- package/src/core.ts +5 -0
- package/src/credits/core/credits.ts +42 -0
- package/src/credits/ui/CreditsList.tsx +1 -1
- package/src/delimited/ui/DelimitedTextPanel.tsx +1 -1
- package/src/ecosystem/core/sites.ts +12 -0
- package/src/ecosystem/core/tokens.ts +1 -0
- package/src/ecosystem/ui/EcosystemLinks.tsx +2 -2
- package/src/ecosystem/ui/EcosystemMenu.tsx +1 -1
- package/src/ecosystem/ui/SiteTile.tsx +7 -5
- package/src/ecosystem/ui/glyphs.tsx +40 -0
- package/src/orbital/core/index.ts +4 -1
- package/src/orbital/core/realHarmonics.ts +5 -2
- package/src/orbital/ui/AtomicOrbitalCanvas.tsx +126 -4
- package/src/orbital/ui/AtomicOrbitalViewer.tsx +14 -1
- package/src/orbital/ui/camera.ts +81 -0
- package/src/orbital/ui/renderVolume.ts +8 -1
- package/src/orbital/ui/serial.ts +35 -0
- package/src/orbital/ui/viewer.ts +72 -13
- package/src/pedagogy/ui/ExerciseProgressHeader.tsx +1 -1
- package/src/pedagogy/ui/GlossaryText.tsx +2 -2
- package/src/pedagogy/ui/ReferenceSectionBlock.tsx +5 -2
- package/src/pedagogy/ui/SyntaxTooltip.tsx +2 -2
- package/src/pedagogy/ui/TutorialStepStrip.tsx +4 -1
- package/src/periodic/ui/CategoryLegend.tsx +1 -1
- package/src/periodic/ui/PeriodicTableChrome.tsx +2 -2
- package/src/seo/vite/ogCard.ts +1 -0
- package/src/share/ui/ShareDialogContent.tsx +5 -2
- package/src/share/ui/SharePartOptions.tsx +1 -1
- package/src/slides/core/demoLinks.ts +113 -0
- package/src/slides/core/index.ts +22 -0
- package/src/slides/core/sectionHeading.ts +29 -0
- package/src/slides/core/slideNavigation.ts +77 -0
- package/src/slides/core/talk.ts +203 -0
- package/src/slides/core/talkManifest.ts +158 -0
- package/src/slides/core/talkOrigin.ts +83 -0
- package/src/slides/ui/BackToSlides.tsx +49 -0
- package/src/slides/ui/DemoLink.tsx +67 -0
- package/src/slides/ui/EmbedSlide.tsx +85 -0
- package/src/slides/ui/SectionSlide.tsx +44 -0
- package/src/slides/ui/Slide.tsx +143 -0
- package/src/slides/ui/SlideBody.tsx +64 -0
- package/src/slides/ui/Slideshow.tsx +282 -0
- package/src/slides/ui/SlideshowBar.tsx +83 -0
- package/src/slides/ui/TalkList.tsx +146 -0
- package/src/slides/ui/index.ts +18 -0
- package/src/slides/vite/index.ts +2 -0
- package/src/slides/vite/talks.ts +126 -0
- package/src/slides.ts +2 -0
- package/src/structure/ui/StructureEditor.tsx +2 -2
- package/src/structure/ui/StructurePlaceholder.tsx +1 -1
- package/src/tokens/core/checkTokens.ts +242 -0
- package/src/tokens/core/colors.ts +122 -0
- package/src/tokens/core/index.ts +6 -0
- package/src/tokens/core/rules.ts +103 -0
- package/src/ui.ts +1 -0
- package/src/vite.ts +1 -0
- package/styles/chrome.css +1 -0
- package/styles/slides.css +667 -0
package/src/orbital/ui/viewer.ts
CHANGED
|
@@ -26,12 +26,14 @@ import {
|
|
|
26
26
|
DEFAULT_CAMERA_DURATION,
|
|
27
27
|
DEFAULT_SPIN_SPEED,
|
|
28
28
|
frameOrbital,
|
|
29
|
+
refitOrbital,
|
|
29
30
|
setSpin,
|
|
30
31
|
} from './camera.ts';
|
|
31
32
|
import type { AxesStyle } from './renderAxes.ts';
|
|
32
33
|
import { clearOrbitalAxes, renderOrbitalAxes } from './renderAxes.ts';
|
|
33
34
|
import type { VolumeStyle } from './renderVolume.ts';
|
|
34
35
|
import { clearSampledVolume, renderSampledVolume } from './renderVolume.ts';
|
|
36
|
+
import { createSerialRunner } from './serial.ts';
|
|
35
37
|
|
|
36
38
|
/** Settings fixed for the life of a viewer. */
|
|
37
39
|
export interface OrbitalViewerOptions {
|
|
@@ -64,7 +66,12 @@ export function createOrbitalViewer(
|
|
|
64
66
|
*/
|
|
65
67
|
export class OrbitalViewer {
|
|
66
68
|
readonly #model: PluginViewModel;
|
|
69
|
+
// One canvas, so one operation at a time — see `serial.ts` for what
|
|
70
|
+
// interleaving two of them does to the scene.
|
|
71
|
+
readonly #serial = createSerialRunner();
|
|
67
72
|
#disposed = false;
|
|
73
|
+
/** Extent the camera was last fitted to; `null` before it has been placed. */
|
|
74
|
+
#fittedRadius: number | null = null;
|
|
68
75
|
|
|
69
76
|
/** Resolves once the canvas exists; every method awaits it internally. */
|
|
70
77
|
readonly ready: Promise<void>;
|
|
@@ -78,7 +85,16 @@ export class OrbitalViewer {
|
|
|
78
85
|
canvas3d: {
|
|
79
86
|
...spec.canvas3d,
|
|
80
87
|
renderer: { backgroundColor: Color.fromHexStyle(background) },
|
|
81
|
-
camera: {
|
|
88
|
+
camera: {
|
|
89
|
+
helper: { axes: { name: 'off', params: {} } },
|
|
90
|
+
// The camera is ours alone. Molstar reframes itself whenever a
|
|
91
|
+
// scene commit leaves the renderable count at zero, which is what
|
|
92
|
+
// replacing one orbital by another does — the old surfaces are
|
|
93
|
+
// removed and committed before the new ones exist — and it frames
|
|
94
|
+
// the whole sampled box rather than the isosurface inside it,
|
|
95
|
+
// which leaves the orbital a fifth of the frame wide.
|
|
96
|
+
manualReset: true,
|
|
97
|
+
},
|
|
82
98
|
},
|
|
83
99
|
},
|
|
84
100
|
});
|
|
@@ -159,9 +175,49 @@ export class OrbitalViewer {
|
|
|
159
175
|
): Promise<void> {
|
|
160
176
|
return this.#run((plugin) => {
|
|
161
177
|
frameOrbital(plugin, orbitalRadius, durationMs);
|
|
178
|
+
this.#fittedRadius = orbitalRadius ?? null;
|
|
162
179
|
});
|
|
163
180
|
}
|
|
164
181
|
|
|
182
|
+
/**
|
|
183
|
+
* Fit a newly drawn orbital without disturbing the view.
|
|
184
|
+
*
|
|
185
|
+
* The first call frames the orbital, since there is no view to keep yet.
|
|
186
|
+
* Later ones leave the rotation and the zoom the student set and only rescale
|
|
187
|
+
* them when the drawn extent changed — clicking through a shell must not
|
|
188
|
+
* throw their view away.
|
|
189
|
+
* @param orbitalRadius - Extent of the drawn surface, as `showOrbital`
|
|
190
|
+
* returned it.
|
|
191
|
+
* @param durationMs - Transition length; 0 jumps.
|
|
192
|
+
* @returns Nothing, once the camera has been set.
|
|
193
|
+
*/
|
|
194
|
+
refit(
|
|
195
|
+
orbitalRadius?: number,
|
|
196
|
+
durationMs = DEFAULT_CAMERA_DURATION,
|
|
197
|
+
): Promise<void> {
|
|
198
|
+
const fitted = this.#fittedRadius;
|
|
199
|
+
if (fitted === null || orbitalRadius === undefined) {
|
|
200
|
+
return this.frame(orbitalRadius, durationMs);
|
|
201
|
+
}
|
|
202
|
+
return this.#run((plugin) => {
|
|
203
|
+
refitOrbital(plugin, fitted, orbitalRadius, durationMs);
|
|
204
|
+
this.#fittedRadius = orbitalRadius;
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Put the camera back where the orbital was first framed from.
|
|
210
|
+
*
|
|
211
|
+
* The counterpart of `refit`: since a view is now kept across a change of
|
|
212
|
+
* orbital, a student who has turned the atom into an unreadable angle needs
|
|
213
|
+
* one way back.
|
|
214
|
+
* @param durationMs - Transition length; 0 jumps.
|
|
215
|
+
* @returns Nothing, once the camera has been set.
|
|
216
|
+
*/
|
|
217
|
+
resetView(durationMs = DEFAULT_CAMERA_DURATION): Promise<void> {
|
|
218
|
+
return this.frame(this.#fittedRadius ?? undefined, durationMs);
|
|
219
|
+
}
|
|
220
|
+
|
|
165
221
|
/**
|
|
166
222
|
* Turn the automatic spin on or off.
|
|
167
223
|
* @param spinning - Whether the scene should keep turning.
|
|
@@ -199,23 +255,26 @@ export class OrbitalViewer {
|
|
|
199
255
|
}
|
|
200
256
|
|
|
201
257
|
/**
|
|
202
|
-
* Wait for
|
|
203
|
-
* `
|
|
204
|
-
* was
|
|
258
|
+
* Wait for the operations queued before this one and for initialisation,
|
|
259
|
+
* then run `action` on the plugin. Resolves to `undefined` when the viewer
|
|
260
|
+
* was disposed, before the call or while `action` was still running; an
|
|
261
|
+
* initialisation failure still reaches the caller.
|
|
205
262
|
* @param action - What to run once the canvas is ready.
|
|
206
263
|
* @returns What `action` returned, or `undefined` when disposed.
|
|
207
264
|
*/
|
|
208
|
-
|
|
265
|
+
#run<Result>(
|
|
209
266
|
action: (plugin: PluginContext) => Result | Promise<Result>,
|
|
210
267
|
): Promise<Result | undefined> {
|
|
211
|
-
|
|
212
|
-
await this.ready;
|
|
213
|
-
if (this.#disposed) return undefined;
|
|
214
|
-
try {
|
|
215
|
-
return await action(this.#model.plugin);
|
|
216
|
-
} catch (error) {
|
|
268
|
+
return this.#serial.run(async () => {
|
|
217
269
|
if (this.#disposed) return undefined;
|
|
218
|
-
|
|
219
|
-
|
|
270
|
+
await this.ready;
|
|
271
|
+
if (this.#disposed) return undefined;
|
|
272
|
+
try {
|
|
273
|
+
return await action(this.#model.plugin);
|
|
274
|
+
} catch (error) {
|
|
275
|
+
if (this.#disposed) return undefined;
|
|
276
|
+
throw error;
|
|
277
|
+
}
|
|
278
|
+
});
|
|
220
279
|
}
|
|
221
280
|
}
|
|
@@ -140,7 +140,7 @@ const TITLE_STYLE: CSSProperties = { fontWeight: 600, fontSize: 13 };
|
|
|
140
140
|
const SUMMARY_STYLE: CSSProperties = {
|
|
141
141
|
fontSize: 12,
|
|
142
142
|
lineHeight: 1.45,
|
|
143
|
-
color: '#d3d8de',
|
|
143
|
+
color: 'var(--border, #d3d8de)',
|
|
144
144
|
};
|
|
145
145
|
|
|
146
146
|
const LIST_STYLE: CSSProperties = {
|
|
@@ -159,6 +159,6 @@ const CODE_STYLE: CSSProperties = {
|
|
|
159
159
|
color: '#8abbff',
|
|
160
160
|
};
|
|
161
161
|
|
|
162
|
-
const INPUT_STYLE: CSSProperties = { color: '#f6f7f9' };
|
|
162
|
+
const INPUT_STYLE: CSSProperties = { color: 'var(--surface-sunken, #f6f7f9)' };
|
|
163
163
|
|
|
164
164
|
const NOTE_STYLE: CSSProperties = { fontStyle: 'italic', color: '#abb3bf' };
|
|
@@ -140,7 +140,10 @@ function syntaxStyle(
|
|
|
140
140
|
fontWeight: 600,
|
|
141
141
|
color: '#1c2127',
|
|
142
142
|
...(interactive
|
|
143
|
-
? {
|
|
143
|
+
? {
|
|
144
|
+
borderBottom: '1px dotted var(--text-muted, #5b6875)',
|
|
145
|
+
alignSelf: 'flex-start',
|
|
146
|
+
}
|
|
144
147
|
: {}),
|
|
145
148
|
};
|
|
146
149
|
}
|
|
@@ -153,7 +156,7 @@ const SECTION_STYLE: CSSProperties = {
|
|
|
153
156
|
|
|
154
157
|
const INTRO_STYLE: CSSProperties = {
|
|
155
158
|
margin: '0 0 4px',
|
|
156
|
-
color: '#5b6875',
|
|
159
|
+
color: 'var(--text-muted, #5b6875)',
|
|
157
160
|
fontSize: 12,
|
|
158
161
|
};
|
|
159
162
|
|
|
@@ -191,7 +191,7 @@ const TAG_STYLE: CSSProperties = { color: '#abb3bf', fontSize: 11 };
|
|
|
191
191
|
const SUMMARY_STYLE: CSSProperties = { fontSize: 12, lineHeight: 1.4 };
|
|
192
192
|
|
|
193
193
|
const DETAIL_STYLE: CSSProperties = {
|
|
194
|
-
color: '#d3d8de',
|
|
194
|
+
color: 'var(--border, #d3d8de)',
|
|
195
195
|
fontSize: 12,
|
|
196
196
|
lineHeight: 1.45,
|
|
197
197
|
};
|
|
@@ -209,7 +209,7 @@ const ROW_STYLE: CSSProperties = { display: 'flex', gap: 6, fontSize: 12 };
|
|
|
209
209
|
const LABEL_STYLE: CSSProperties = { color: '#abb3bf', flex: '0 0 68px' };
|
|
210
210
|
|
|
211
211
|
const VALUE_STYLE: CSSProperties = {
|
|
212
|
-
color: '#f6f7f9',
|
|
212
|
+
color: 'var(--surface-sunken, #f6f7f9)',
|
|
213
213
|
fontFamily: MONOSPACE,
|
|
214
214
|
overflowWrap: 'anywhere',
|
|
215
215
|
};
|
|
@@ -145,7 +145,7 @@ function HeaderCell(props: HeaderCellProps): ReactElement {
|
|
|
145
145
|
|
|
146
146
|
const headerStyle = {
|
|
147
147
|
alignItems: 'center',
|
|
148
|
-
color: 'rgb(95 107 124)',
|
|
148
|
+
color: 'var(--text-muted, rgb(95 107 124))',
|
|
149
149
|
display: 'flex',
|
|
150
150
|
fontSize: 'clamp(0.4rem, 1.9cqw, 0.62rem)',
|
|
151
151
|
justifyContent: 'center',
|
|
@@ -163,7 +163,7 @@ const markerStyle = {
|
|
|
163
163
|
alignItems: 'center',
|
|
164
164
|
border: '1px dashed rgb(182 191 204)',
|
|
165
165
|
borderRadius: 3,
|
|
166
|
-
color: 'rgb(95 107 124)',
|
|
166
|
+
color: 'var(--text-muted, rgb(95 107 124))',
|
|
167
167
|
display: 'flex',
|
|
168
168
|
fontSize: 'clamp(0.36rem, 1.7cqw, 0.55rem)',
|
|
169
169
|
justifyContent: 'center',
|
package/src/seo/vite/ogCard.ts
CHANGED
|
@@ -28,7 +28,10 @@ import type { ShareDialogProps, ShareDraft } from './ShareDialog.tsx';
|
|
|
28
28
|
import { SharePartOptions } from './SharePartOptions.tsx';
|
|
29
29
|
import { withPart } from './draft.ts';
|
|
30
30
|
|
|
31
|
-
const LEAD_STYLE: CSSProperties = {
|
|
31
|
+
const LEAD_STYLE: CSSProperties = {
|
|
32
|
+
marginTop: 0,
|
|
33
|
+
color: 'var(--text-muted, #5b6875)',
|
|
34
|
+
};
|
|
32
35
|
const SECTION_STYLE: CSSProperties = { marginBottom: 18 };
|
|
33
36
|
const ACTIONS_STYLE: CSSProperties = {
|
|
34
37
|
display: 'flex',
|
|
@@ -39,7 +42,7 @@ const ACTIONS_STYLE: CSSProperties = {
|
|
|
39
42
|
const HINT_STYLE: CSSProperties = {
|
|
40
43
|
display: 'block',
|
|
41
44
|
marginLeft: 26,
|
|
42
|
-
color: '#5b6875',
|
|
45
|
+
color: 'var(--text-muted, #5b6875)',
|
|
43
46
|
fontSize: 12,
|
|
44
47
|
};
|
|
45
48
|
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The links a slide hands over to the live tool.
|
|
3
|
+
*
|
|
4
|
+
* A demo link is a paragraph that is exactly one Markdown link to an in-app
|
|
5
|
+
* route. It is parsed by hand rather than by a Markdown library because the
|
|
6
|
+
* labels are chemistry — `[M+H]⁺` opens a bracket the label closes itself, and
|
|
7
|
+
* a formula such as `H(OCH2CH2)10` puts parentheses inside the URL — and both
|
|
8
|
+
* defeat a naive `\[(.*)\]\((.*)\)` pattern.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/** One link a slide offers as a live demo. */
|
|
12
|
+
export interface DemoLinkSpec {
|
|
13
|
+
/** The link text, which may itself contain balanced brackets. */
|
|
14
|
+
label: string;
|
|
15
|
+
/** Where it goes; a demo link always targets an in-app route. */
|
|
16
|
+
href: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Read a paragraph that is exactly one Markdown link `[label](url)` and nothing
|
|
21
|
+
* else, counting brackets so a label may hold its own pair, and accepting the
|
|
22
|
+
* angle-bracketed URL form `[label](<url>)` for a URL holding parentheses.
|
|
23
|
+
* @param text - The paragraph text.
|
|
24
|
+
* @returns The link, or `null` when the paragraph is anything else.
|
|
25
|
+
*/
|
|
26
|
+
export function parseSingleLink(text: string): DemoLinkSpec | null {
|
|
27
|
+
const source = text.trim();
|
|
28
|
+
if (!source.startsWith('[')) return null;
|
|
29
|
+
|
|
30
|
+
let depth = 0;
|
|
31
|
+
let labelEnd = -1;
|
|
32
|
+
for (let index = 0; index < source.length; index++) {
|
|
33
|
+
const char = source[index];
|
|
34
|
+
if (char === '[') {
|
|
35
|
+
depth++;
|
|
36
|
+
} else if (char === ']') {
|
|
37
|
+
depth--;
|
|
38
|
+
if (depth === 0) {
|
|
39
|
+
labelEnd = index;
|
|
40
|
+
break;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
if (labelEnd === -1 || source[labelEnd + 1] !== '(') return null;
|
|
45
|
+
|
|
46
|
+
const label = source.slice(1, labelEnd);
|
|
47
|
+
let rest = source.slice(labelEnd + 2);
|
|
48
|
+
let href: string;
|
|
49
|
+
|
|
50
|
+
if (rest.startsWith('<')) {
|
|
51
|
+
const close = rest.indexOf('>');
|
|
52
|
+
if (close === -1 || rest[close + 1] !== ')') return null;
|
|
53
|
+
href = rest.slice(1, close);
|
|
54
|
+
rest = rest.slice(close + 2);
|
|
55
|
+
} else {
|
|
56
|
+
let parenDepth = 1;
|
|
57
|
+
let urlEnd = -1;
|
|
58
|
+
for (let index = 0; index < rest.length; index++) {
|
|
59
|
+
const char = rest[index];
|
|
60
|
+
if (char === '(') {
|
|
61
|
+
parenDepth++;
|
|
62
|
+
} else if (char === ')') {
|
|
63
|
+
parenDepth--;
|
|
64
|
+
if (parenDepth === 0) {
|
|
65
|
+
urlEnd = index;
|
|
66
|
+
break;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
if (urlEnd === -1) return null;
|
|
71
|
+
href = rest.slice(0, urlEnd);
|
|
72
|
+
rest = rest.slice(urlEnd + 1);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (rest.trim() !== '') return null;
|
|
76
|
+
return { label, href };
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Split a slide body into its Markdown and the run of demo links that closes
|
|
81
|
+
* it. External links and ordinary paragraphs stay in the body, so a slide that
|
|
82
|
+
* merely cites a URL keeps it where the author wrote it.
|
|
83
|
+
* @param body - The slide Markdown body.
|
|
84
|
+
* @returns The body without its trailing demo links, and those links in order.
|
|
85
|
+
*/
|
|
86
|
+
export function splitDemoLinks(body: string): {
|
|
87
|
+
body: string;
|
|
88
|
+
demos: DemoLinkSpec[];
|
|
89
|
+
} {
|
|
90
|
+
const blocks = body.split(/\n{2,}/);
|
|
91
|
+
let firstDemo = blocks.length;
|
|
92
|
+
const demos: DemoLinkSpec[] = [];
|
|
93
|
+
for (let index = blocks.length - 1; index >= 0; index--) {
|
|
94
|
+
const link = parseSingleLink(blocks[index] ?? '');
|
|
95
|
+
if (!link?.href.startsWith('/')) break;
|
|
96
|
+
demos.unshift(link);
|
|
97
|
+
firstDemo = index;
|
|
98
|
+
}
|
|
99
|
+
return { body: blocks.slice(0, firstDemo).join('\n\n').trim(), demos };
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* The displayed form of a demo link label: the `Demo:` prefix an author writes
|
|
104
|
+
* to mark the paragraph is dropped, and the first character is uppercased.
|
|
105
|
+
* @param label - The raw link label.
|
|
106
|
+
* @returns What the button shows.
|
|
107
|
+
*/
|
|
108
|
+
export function demoLabel(label: string): string {
|
|
109
|
+
const text = label.replace(DEMO_PREFIX, '');
|
|
110
|
+
return text.charAt(0).toUpperCase() + text.slice(1);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const DEMO_PREFIX = /^Demo:\s*/i;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export type { DemoLinkSpec } from './demoLinks.ts';
|
|
2
|
+
export { demoLabel, parseSingleLink, splitDemoLinks } from './demoLinks.ts';
|
|
3
|
+
export type { SectionHeading } from './sectionHeading.ts';
|
|
4
|
+
export { parseSectionHeading } from './sectionHeading.ts';
|
|
5
|
+
export type { SlideAction } from './slideNavigation.ts';
|
|
6
|
+
export { clampSlideIndex, slideActionForKey } from './slideNavigation.ts';
|
|
7
|
+
export type { Slide, Talk, TalkMeta } from './talk.ts';
|
|
8
|
+
export { parseTalk } from './talk.ts';
|
|
9
|
+
export type { TalkManifest, TalkSummary } from './talkManifest.ts';
|
|
10
|
+
export {
|
|
11
|
+
buildTalkManifest,
|
|
12
|
+
parseTalkManifest,
|
|
13
|
+
talkSourceUrl,
|
|
14
|
+
talkSummary,
|
|
15
|
+
} from './talkManifest.ts';
|
|
16
|
+
export type { TalkOrigin } from './talkOrigin.ts';
|
|
17
|
+
export {
|
|
18
|
+
TALK_ORIGIN_PARAM,
|
|
19
|
+
formatTalkOrigin,
|
|
20
|
+
parseTalkOrigin,
|
|
21
|
+
withTalkOrigin,
|
|
22
|
+
} from './talkOrigin.ts';
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/** The parts of a section divider's heading. */
|
|
2
|
+
export interface SectionHeading {
|
|
3
|
+
/** The section number, as written; empty when the heading carries none. */
|
|
4
|
+
number: string;
|
|
5
|
+
/** The section title, without its number; empty when the heading carries none. */
|
|
6
|
+
title: string;
|
|
7
|
+
/** Whatever the body holds besides that heading. */
|
|
8
|
+
rest: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Split a section-divider body into its leading number, its title and the rest
|
|
13
|
+
* of the Markdown, so a template can set the number apart from the title.
|
|
14
|
+
* `·`, `.`, `:`, `—` and `-` all separate the two.
|
|
15
|
+
* @param body - Markdown body, normally starting with `# N · Title`.
|
|
16
|
+
* @returns The parsed heading; a body with no numbered heading keeps all of
|
|
17
|
+
* itself in `rest`, leaving `number` and `title` empty.
|
|
18
|
+
*/
|
|
19
|
+
export function parseSectionHeading(body: string): SectionHeading {
|
|
20
|
+
const match = HEAD_RE.exec(body);
|
|
21
|
+
const number = match?.groups?.number;
|
|
22
|
+
const title = match?.groups?.title;
|
|
23
|
+
if (match === null || number === undefined || title === undefined) {
|
|
24
|
+
return { number: '', title: '', rest: body.trim() };
|
|
25
|
+
}
|
|
26
|
+
return { number, title, rest: body.replace(match[0], '').trim() };
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const HEAD_RE = /^#\s+(?<number>\d+)\s*[.:·—-]\s*(?<title>.+?)\s*$/m;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a key does during a presentation, decided without a DOM.
|
|
3
|
+
*
|
|
4
|
+
* The current slide lives in the address, so it arrives as whatever a link
|
|
5
|
+
* carried — a missing number, a negative one, one past the end of a talk that
|
|
6
|
+
* has since been shortened. Every move is therefore clamped here rather than
|
|
7
|
+
* trusted, and the player only ever renders a slide that exists.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* The slide a requested index resolves to.
|
|
12
|
+
* @param index - The index asked for, from a link or a keystroke.
|
|
13
|
+
* @param total - How many slides the talk holds.
|
|
14
|
+
* @returns A zero-based index that exists, or `0` for a talk with no slides.
|
|
15
|
+
*/
|
|
16
|
+
export function clampSlideIndex(index: number, total: number): number {
|
|
17
|
+
if (!Number.isFinite(total) || total < 1) return 0;
|
|
18
|
+
if (Number.isNaN(index) || index < 0) return 0;
|
|
19
|
+
const last = total - 1;
|
|
20
|
+
return index > last ? last : Math.trunc(index);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** What a key press asks the player to do. */
|
|
24
|
+
export type SlideAction =
|
|
25
|
+
| { kind: 'go'; index: number }
|
|
26
|
+
| { kind: 'blank'; color: 'black' | 'white' }
|
|
27
|
+
| { kind: 'fullscreen' }
|
|
28
|
+
| { kind: 'notes' }
|
|
29
|
+
| null;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* The action a key press means, with every move already clamped: stepping past
|
|
33
|
+
* the last slide, or back from the first, stays on the slide it is on rather
|
|
34
|
+
* than leaving the talk.
|
|
35
|
+
* @param key - The `key` of the keyboard event.
|
|
36
|
+
* @param index - Which slide is showing.
|
|
37
|
+
* @param total - How many slides the talk holds.
|
|
38
|
+
* @returns The action, or `null` when the key means nothing here.
|
|
39
|
+
*/
|
|
40
|
+
export function slideActionForKey(
|
|
41
|
+
key: string,
|
|
42
|
+
index: number,
|
|
43
|
+
total: number,
|
|
44
|
+
): SlideAction {
|
|
45
|
+
switch (key) {
|
|
46
|
+
case 'ArrowRight':
|
|
47
|
+
case 'ArrowDown':
|
|
48
|
+
case 'PageDown':
|
|
49
|
+
case ' ':
|
|
50
|
+
return { kind: 'go', index: clampSlideIndex(index + 1, total) };
|
|
51
|
+
case 'ArrowLeft':
|
|
52
|
+
case 'ArrowUp':
|
|
53
|
+
case 'PageUp':
|
|
54
|
+
return { kind: 'go', index: clampSlideIndex(index - 1, total) };
|
|
55
|
+
case 'Home':
|
|
56
|
+
return { kind: 'go', index: 0 };
|
|
57
|
+
case 'End':
|
|
58
|
+
return { kind: 'go', index: clampSlideIndex(total - 1, total) };
|
|
59
|
+
default:
|
|
60
|
+
return letterAction(key);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function letterAction(key: string): SlideAction {
|
|
65
|
+
switch (key.toLowerCase()) {
|
|
66
|
+
case 'f':
|
|
67
|
+
return { kind: 'fullscreen' };
|
|
68
|
+
case 'b':
|
|
69
|
+
return { kind: 'blank', color: 'black' };
|
|
70
|
+
case 'w':
|
|
71
|
+
return { kind: 'blank', color: 'white' };
|
|
72
|
+
case 'n':
|
|
73
|
+
return { kind: 'notes' };
|
|
74
|
+
default:
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
}
|