Generate web slides from Markdoc
1import { assign, setup } from "xstate";
2import { Context, Events } from "./types.ts";
3
4export const machineBase = setup({
5 types: {
6 context: {} as Context,
7 events: {} as Events,
8 },
9 actions: {
10 registerSlides: assign(({ context, event }) => {
11 if (event.type === "presentation.start") {
12 const currentIndex = event.slides.findIndex((s) =>
13 s.id === event.currentSlide
14 );
15
16 return {
17 ...context,
18 presentationId: event.presentationId,
19 slides: event.slides,
20 currentIndex: Math.max(currentIndex, 0),
21 channel: new BroadcastChannel(event.presentationId),
22 };
23 } else {
24 return context;
25 }
26 }),
27 scrollToSlide({ context }) {
28 if (context.currentIndex > 0) {
29 const slide = context.slides[context.currentIndex];
30
31 document.querySelector(`#${slide.id}`)?.scrollIntoView({
32 behavior: "instant",
33 });
34 }
35 },
36 updateUrl({ context }) {
37 const url = new URL(document.URL);
38 const hash = `#${context.slides[context.currentIndex].id}`;
39
40 url.hash = hash;
41
42 location.replace(url);
43 },
44 updateCurrentSlide: assign({
45 currentIndex: ({ context, event }) => {
46 if (event.type === "navigate.scroll") {
47 const index = context.slides.findIndex((s) => s.id === event.slideId);
48
49 return Math.max(index, 0);
50 }
51
52 return context.currentIndex;
53 },
54 }),
55 nextSlide: assign({
56 currentIndex: ({ context }) => {
57 if (context.currentIndex + 1 > context.slides.length - 1) {
58 return context.currentIndex;
59 }
60
61 return context.currentIndex + 1;
62 },
63 }),
64 previousSlide: assign({
65 currentIndex: ({ context }) => {
66 if (context.currentIndex - 1 < 0) {
67 return context.currentIndex;
68 }
69
70 return context.currentIndex - 1;
71 },
72 }),
73 },
74});