@slidejs/runner-revealjs 0.1.2 → 0.1.4
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/.turbo/turbo-build.log +8 -10
- package/.turbo/turbo-test.log +15 -0
- package/.turbo/turbo-typecheck.log +4 -0
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +104 -85
- package/dist/index.mjs.map +1 -1
- package/package.json +12 -8
- package/src/__tests__/adapter.test.ts +299 -0
- package/src/__tests__/runner.test.ts +238 -0
- package/src/env.d.ts +17 -0
- package/src/index.ts +1 -3
- package/src/runner.ts +43 -2
- package/src/style.css +107 -4
- package/tsconfig.json +1 -1
- package/tsconfig.tsbuildinfo +1 -0
- package/vite.config.ts +5 -2
- package/vitest.config.ts +9 -0
- package/dist/style.css +0 -1
package/dist/index.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { parseSlideDSL as
|
|
1
|
+
import g from "reveal.js";
|
|
2
|
+
import { parseSlideDSL as h, compile as m } from "@slidejs/dsl";
|
|
3
3
|
import { SlideRunner as u } from "@slidejs/runner";
|
|
4
|
-
class
|
|
4
|
+
class f {
|
|
5
5
|
constructor() {
|
|
6
6
|
this.name = "revealjs", this.eventHandlers = /* @__PURE__ */ new Map();
|
|
7
7
|
}
|
|
@@ -11,22 +11,22 @@ class m {
|
|
|
11
11
|
* @param container - 容器元素
|
|
12
12
|
* @param options - reveal.js 选项
|
|
13
13
|
*/
|
|
14
|
-
async initialize(
|
|
14
|
+
async initialize(a, t) {
|
|
15
15
|
try {
|
|
16
|
-
if (this.createRevealStructure(
|
|
16
|
+
if (this.createRevealStructure(a), !this.revealContainer)
|
|
17
17
|
throw new Error("Reveal container not created");
|
|
18
|
-
this.reveal = new
|
|
18
|
+
this.reveal = new g(this.revealContainer, {
|
|
19
19
|
// 默认配置
|
|
20
20
|
controls: !0,
|
|
21
21
|
progress: !0,
|
|
22
22
|
center: !0,
|
|
23
23
|
hash: !1,
|
|
24
24
|
transition: "slide",
|
|
25
|
-
...t
|
|
25
|
+
...t?.revealConfig
|
|
26
26
|
}), await this.reveal.initialize(), this.setupEventListeners(), this.emit("ready");
|
|
27
27
|
} catch (e) {
|
|
28
|
-
const
|
|
29
|
-
throw this.emit("error", { message:
|
|
28
|
+
const o = e instanceof Error ? e.message : String(e);
|
|
29
|
+
throw this.emit("error", { message: o }), new Error(`Failed to initialize RevealJsAdapter: ${o}`);
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
32
|
/**
|
|
@@ -34,16 +34,16 @@ class m {
|
|
|
34
34
|
*
|
|
35
35
|
* @param slides - 幻灯片定义数组
|
|
36
36
|
*/
|
|
37
|
-
async render(
|
|
37
|
+
async render(a) {
|
|
38
38
|
if (!this.slidesContainer || !this.reveal)
|
|
39
39
|
throw new Error("RevealJsAdapter not initialized");
|
|
40
40
|
try {
|
|
41
41
|
this.slidesContainer.innerHTML = "";
|
|
42
|
-
for (const t of
|
|
42
|
+
for (const t of a) {
|
|
43
43
|
const e = await this.renderSlide(t);
|
|
44
44
|
this.slidesContainer.appendChild(e);
|
|
45
45
|
}
|
|
46
|
-
this.reveal.sync(), this.emit("slideRendered", { totalSlides:
|
|
46
|
+
this.reveal.sync(), this.emit("slideRendered", { totalSlides: a.length });
|
|
47
47
|
} catch (t) {
|
|
48
48
|
const e = t instanceof Error ? t.message : String(t);
|
|
49
49
|
throw this.emit("error", { message: e }), new Error(`Failed to render slides: ${e}`);
|
|
@@ -60,10 +60,10 @@ class m {
|
|
|
60
60
|
*
|
|
61
61
|
* @param index - 幻灯片索引
|
|
62
62
|
*/
|
|
63
|
-
navigateTo(
|
|
63
|
+
navigateTo(a) {
|
|
64
64
|
if (!this.reveal)
|
|
65
65
|
throw new Error("RevealJsAdapter not initialized");
|
|
66
|
-
this.reveal.slide(
|
|
66
|
+
this.reveal.slide(a, 0);
|
|
67
67
|
}
|
|
68
68
|
/**
|
|
69
69
|
* 获取当前幻灯片索引
|
|
@@ -83,18 +83,18 @@ class m {
|
|
|
83
83
|
* @param index - 幻灯片索引
|
|
84
84
|
* @param slide - 新的幻灯片定义
|
|
85
85
|
*/
|
|
86
|
-
async updateSlide(
|
|
86
|
+
async updateSlide(a, t) {
|
|
87
87
|
if (!this.slidesContainer || !this.reveal)
|
|
88
88
|
throw new Error("RevealJsAdapter not initialized");
|
|
89
89
|
try {
|
|
90
|
-
const
|
|
91
|
-
if (!
|
|
92
|
-
throw new Error(`Slide at index ${
|
|
93
|
-
const
|
|
94
|
-
|
|
90
|
+
const o = this.slidesContainer.querySelectorAll("section")[a];
|
|
91
|
+
if (!o)
|
|
92
|
+
throw new Error(`Slide at index ${a} not found`);
|
|
93
|
+
const r = await this.renderSlide(t);
|
|
94
|
+
o.replaceWith(r), this.reveal.sync();
|
|
95
95
|
} catch (e) {
|
|
96
|
-
const
|
|
97
|
-
throw this.emit("error", { message:
|
|
96
|
+
const o = e instanceof Error ? e.message : String(e);
|
|
97
|
+
throw this.emit("error", { message: o }), new Error(`Failed to update slide: ${o}`);
|
|
98
98
|
}
|
|
99
99
|
}
|
|
100
100
|
/**
|
|
@@ -103,8 +103,8 @@ class m {
|
|
|
103
103
|
* @param event - 事件类型
|
|
104
104
|
* @param handler - 事件处理器
|
|
105
105
|
*/
|
|
106
|
-
on(
|
|
107
|
-
this.eventHandlers.has(
|
|
106
|
+
on(a, t) {
|
|
107
|
+
this.eventHandlers.has(a) || this.eventHandlers.set(a, /* @__PURE__ */ new Set()), this.eventHandlers.get(a).add(t);
|
|
108
108
|
}
|
|
109
109
|
/**
|
|
110
110
|
* 移除事件监听器
|
|
@@ -112,8 +112,8 @@ class m {
|
|
|
112
112
|
* @param event - 事件类型
|
|
113
113
|
* @param handler - 事件处理器
|
|
114
114
|
*/
|
|
115
|
-
off(
|
|
116
|
-
const e = this.eventHandlers.get(
|
|
115
|
+
off(a, t) {
|
|
116
|
+
const e = this.eventHandlers.get(a);
|
|
117
117
|
e && e.delete(t);
|
|
118
118
|
}
|
|
119
119
|
/**
|
|
@@ -130,24 +130,23 @@ class m {
|
|
|
130
130
|
*
|
|
131
131
|
* @param container - 容器元素
|
|
132
132
|
*/
|
|
133
|
-
createRevealStructure(
|
|
133
|
+
createRevealStructure(a) {
|
|
134
134
|
const t = document.createElement("div");
|
|
135
135
|
t.className = "reveal-viewport";
|
|
136
136
|
const e = document.createElement("div");
|
|
137
137
|
e.className = "reveal";
|
|
138
|
-
const
|
|
139
|
-
|
|
138
|
+
const o = document.createElement("div");
|
|
139
|
+
o.className = "slides", e.appendChild(o), t.appendChild(e), a.appendChild(t), this.revealContainer = e, this.slidesContainer = o;
|
|
140
140
|
}
|
|
141
141
|
/**
|
|
142
142
|
* 设置 reveal.js 事件监听
|
|
143
143
|
*/
|
|
144
144
|
setupEventListeners() {
|
|
145
|
-
this.reveal && (this.reveal.on("slidechanged", (
|
|
146
|
-
|
|
147
|
-
const t = n;
|
|
145
|
+
this.reveal && (this.reveal.on("slidechanged", (a) => {
|
|
146
|
+
const t = a;
|
|
148
147
|
this.emit("slideChanged", {
|
|
149
148
|
index: t.indexh,
|
|
150
|
-
previousIndex:
|
|
149
|
+
previousIndex: t.previousSlide?.dataset.index
|
|
151
150
|
});
|
|
152
151
|
}), this.reveal.on("ready", () => {
|
|
153
152
|
this.emit("ready");
|
|
@@ -159,19 +158,18 @@ class m {
|
|
|
159
158
|
* @param slide - 幻灯片定义
|
|
160
159
|
* @returns section 元素
|
|
161
160
|
*/
|
|
162
|
-
async renderSlide(
|
|
163
|
-
var e;
|
|
161
|
+
async renderSlide(a) {
|
|
164
162
|
const t = document.createElement("section");
|
|
165
|
-
if (
|
|
166
|
-
const
|
|
167
|
-
t.setAttribute("data-transition",
|
|
163
|
+
if (a.behavior?.transition) {
|
|
164
|
+
const e = this.mapTransition(a.behavior.transition.type);
|
|
165
|
+
t.setAttribute("data-transition", e);
|
|
168
166
|
}
|
|
169
|
-
if (
|
|
170
|
-
const
|
|
171
|
-
t.appendChild(
|
|
167
|
+
if (a.content.type === "dynamic") {
|
|
168
|
+
const e = this.renderDynamicContent(a.content.component, a.content.props);
|
|
169
|
+
t.appendChild(e);
|
|
172
170
|
} else {
|
|
173
|
-
const
|
|
174
|
-
t.appendChild(
|
|
171
|
+
const e = this.renderTextContent(a.content.lines);
|
|
172
|
+
t.appendChild(e);
|
|
175
173
|
}
|
|
176
174
|
return t;
|
|
177
175
|
}
|
|
@@ -182,10 +180,10 @@ class m {
|
|
|
182
180
|
* @param props - 组件属性
|
|
183
181
|
* @returns 组件元素
|
|
184
182
|
*/
|
|
185
|
-
renderDynamicContent(
|
|
186
|
-
const e = document.createElement(
|
|
187
|
-
for (const [
|
|
188
|
-
typeof
|
|
183
|
+
renderDynamicContent(a, t) {
|
|
184
|
+
const e = document.createElement(a);
|
|
185
|
+
for (const [o, r] of Object.entries(t))
|
|
186
|
+
typeof r == "string" || typeof r == "number" ? e.setAttribute(o, String(r)) : typeof r == "boolean" ? r && e.setAttribute(o, "") : e[o] = r;
|
|
189
187
|
return e;
|
|
190
188
|
}
|
|
191
189
|
/**
|
|
@@ -202,50 +200,50 @@ class m {
|
|
|
202
200
|
* @param lines - 文本行数组
|
|
203
201
|
* @returns 内容容器元素
|
|
204
202
|
*/
|
|
205
|
-
renderTextContent(
|
|
203
|
+
renderTextContent(a) {
|
|
206
204
|
const t = document.createElement("div");
|
|
207
205
|
t.className = "slide-content";
|
|
208
206
|
let e = null;
|
|
209
|
-
for (const
|
|
210
|
-
const
|
|
211
|
-
if (!
|
|
207
|
+
for (const o of a) {
|
|
208
|
+
const r = o.trim();
|
|
209
|
+
if (!r) {
|
|
212
210
|
e = null;
|
|
213
211
|
continue;
|
|
214
212
|
}
|
|
215
|
-
if (
|
|
213
|
+
if (r.startsWith("# ")) {
|
|
216
214
|
e = null;
|
|
217
|
-
const
|
|
218
|
-
|
|
215
|
+
const i = document.createElement("h1");
|
|
216
|
+
i.textContent = r.substring(2), t.appendChild(i);
|
|
219
217
|
continue;
|
|
220
218
|
}
|
|
221
|
-
if (
|
|
219
|
+
if (r.startsWith("## ")) {
|
|
222
220
|
e = null;
|
|
223
|
-
const
|
|
224
|
-
|
|
221
|
+
const i = document.createElement("h2");
|
|
222
|
+
i.textContent = r.substring(3), t.appendChild(i);
|
|
225
223
|
continue;
|
|
226
224
|
}
|
|
227
|
-
if (
|
|
225
|
+
if (r.startsWith("### ")) {
|
|
228
226
|
e = null;
|
|
229
|
-
const
|
|
230
|
-
|
|
227
|
+
const i = document.createElement("h3");
|
|
228
|
+
i.textContent = r.substring(4), t.appendChild(i);
|
|
231
229
|
continue;
|
|
232
230
|
}
|
|
233
|
-
const
|
|
234
|
-
if (
|
|
231
|
+
const l = r.match(/^!\[(.*?)\]\((.*?)\)$/);
|
|
232
|
+
if (l) {
|
|
235
233
|
e = null;
|
|
236
|
-
const
|
|
237
|
-
|
|
234
|
+
const i = document.createElement("img");
|
|
235
|
+
i.alt = l[1], i.src = l[2], i.style.maxWidth = "80%", i.style.maxHeight = "500px", t.appendChild(i);
|
|
238
236
|
continue;
|
|
239
237
|
}
|
|
240
|
-
if (
|
|
238
|
+
if (r.startsWith("- ")) {
|
|
241
239
|
e || (e = document.createElement("ul"), t.appendChild(e));
|
|
242
|
-
const
|
|
243
|
-
|
|
240
|
+
const i = document.createElement("li");
|
|
241
|
+
i.textContent = r.substring(2), e.appendChild(i);
|
|
244
242
|
continue;
|
|
245
243
|
}
|
|
246
244
|
e = null;
|
|
247
|
-
const
|
|
248
|
-
|
|
245
|
+
const s = document.createElement("p");
|
|
246
|
+
s.textContent = r, t.appendChild(s);
|
|
249
247
|
}
|
|
250
248
|
return t;
|
|
251
249
|
}
|
|
@@ -255,11 +253,11 @@ class m {
|
|
|
255
253
|
* @param transition - Slide DSL 过渡效果
|
|
256
254
|
* @returns reveal.js 过渡效果
|
|
257
255
|
*/
|
|
258
|
-
mapTransition(
|
|
259
|
-
return
|
|
256
|
+
mapTransition(a) {
|
|
257
|
+
return a ? {
|
|
260
258
|
cube: "convex",
|
|
261
259
|
flip: "concave"
|
|
262
|
-
}[
|
|
260
|
+
}[a] || a : "slide";
|
|
263
261
|
}
|
|
264
262
|
/**
|
|
265
263
|
* 触发事件
|
|
@@ -267,29 +265,50 @@ class m {
|
|
|
267
265
|
* @param event - 事件类型
|
|
268
266
|
* @param data - 事件数据
|
|
269
267
|
*/
|
|
270
|
-
emit(
|
|
271
|
-
const e = this.eventHandlers.get(
|
|
268
|
+
emit(a, t) {
|
|
269
|
+
const e = this.eventHandlers.get(a);
|
|
272
270
|
if (e)
|
|
273
|
-
for (const
|
|
271
|
+
for (const o of e)
|
|
274
272
|
try {
|
|
275
|
-
|
|
276
|
-
} catch (
|
|
277
|
-
console.error(`Error in ${
|
|
273
|
+
o(t);
|
|
274
|
+
} catch (r) {
|
|
275
|
+
console.error(`Error in ${a} handler:`, r);
|
|
278
276
|
}
|
|
279
277
|
}
|
|
280
278
|
}
|
|
281
|
-
async function C(o, n, t) {
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
279
|
+
const b = '.reveal .r-stretch,.reveal .stretch{max-width:none;max-height:none}.reveal pre.r-stretch code,.reveal pre.stretch code{height:100%;max-height:100%;box-sizing:border-box}.reveal .r-fit-text{display:inline-block;white-space:nowrap}.reveal .r-stack{display:grid;grid-template-rows:100%}.reveal .r-stack>*{grid-area:1/1;margin:auto}.reveal .r-hstack,.reveal .r-vstack{display:flex}.reveal .r-hstack img,.reveal .r-hstack video,.reveal .r-vstack img,.reveal .r-vstack video{min-width:0;min-height:0;object-fit:contain}.reveal .r-vstack{flex-direction:column;align-items:center;justify-content:center}.reveal .r-hstack{flex-direction:row;align-items:center;justify-content:center}.reveal .items-stretch{align-items:stretch}.reveal .items-start{align-items:flex-start}.reveal .items-center{align-items:center}.reveal .items-end{align-items:flex-end}.reveal .justify-between{justify-content:space-between}.reveal .justify-around{justify-content:space-around}.reveal .justify-start{justify-content:flex-start}.reveal .justify-center{justify-content:center}.reveal .justify-end{justify-content:flex-end}html.reveal-full-page{width:100%;height:100%;height:100vh;height:calc(var(--vh,1vh) * 100);height:100dvh;overflow:hidden}.reveal-viewport{height:100%;overflow:hidden;position:relative;line-height:1;margin:0;background-color:#fff;color:#000;--r-controls-spacing:12px;--r-overlay-header-height:40px;--r-overlay-margin:0px;--r-overlay-padding:6px;--r-overlay-gap:5px}@media screen and (max-width:1024px),(max-height:768px){.reveal-viewport{--r-overlay-header-height:26px}}.reveal-viewport:fullscreen{top:0!important;left:0!important;width:100%!important;height:100%!important;transform:none!important}.reveal .fragment{transition:all .2s ease}.reveal .fragment:not(.custom){opacity:0;visibility:hidden;will-change:opacity}.reveal .fragment.visible{opacity:1;visibility:inherit}.reveal .fragment.disabled{transition:none}.reveal .fragment.grow{opacity:1;visibility:inherit}.reveal .fragment.grow.visible{transform:scale(1.3)}.reveal .fragment.shrink{opacity:1;visibility:inherit}.reveal .fragment.shrink.visible{transform:scale(.7)}.reveal .fragment.zoom-in{transform:scale(.1)}.reveal .fragment.zoom-in.visible{transform:none}.reveal .fragment.fade-out{opacity:1;visibility:inherit}.reveal .fragment.fade-out.visible{opacity:0;visibility:hidden}.reveal .fragment.semi-fade-out{opacity:1;visibility:inherit}.reveal .fragment.semi-fade-out.visible{opacity:.5;visibility:inherit}.reveal .fragment.strike{opacity:1;visibility:inherit}.reveal .fragment.strike.visible{text-decoration:line-through}.reveal .fragment.fade-up{transform:translateY(40px)}.reveal .fragment.fade-up.visible{transform:translate(0)}.reveal .fragment.fade-down{transform:translateY(-40px)}.reveal .fragment.fade-down.visible{transform:translate(0)}.reveal .fragment.fade-right{transform:translate(-40px)}.reveal .fragment.fade-right.visible{transform:translate(0)}.reveal .fragment.fade-left{transform:translate(40px)}.reveal .fragment.fade-left.visible{transform:translate(0)}.reveal .fragment.current-visible,.reveal .fragment.fade-in-then-out{opacity:0;visibility:hidden}.reveal .fragment.current-visible.current-fragment,.reveal .fragment.fade-in-then-out.current-fragment{opacity:1;visibility:inherit}.reveal .fragment.fade-in-then-semi-out{opacity:0;visibility:hidden}.reveal .fragment.fade-in-then-semi-out.visible{opacity:.5;visibility:inherit}.reveal .fragment.fade-in-then-semi-out.current-fragment,.reveal .fragment.highlight-blue,.reveal .fragment.highlight-current-blue,.reveal .fragment.highlight-current-green,.reveal .fragment.highlight-current-red,.reveal .fragment.highlight-green,.reveal .fragment.highlight-red{opacity:1;visibility:inherit}.reveal .fragment.highlight-red.visible{color:#ff2c2d}.reveal .fragment.highlight-green.visible{color:#17ff2e}.reveal .fragment.highlight-blue.visible{color:#1b91ff}.reveal .fragment.highlight-current-red.current-fragment{color:#ff2c2d}.reveal .fragment.highlight-current-green.current-fragment{color:#17ff2e}.reveal .fragment.highlight-current-blue.current-fragment{color:#1b91ff}.reveal:after{content:"";font-style:italic}.reveal iframe{z-index:1}.reveal a{position:relative}@keyframes bounce-right{0%,10%,25%,40%,50%{transform:translate(0)}20%{transform:translate(10px)}30%{transform:translate(-5px)}}@keyframes bounce-left{0%,10%,25%,40%,50%{transform:translate(0)}20%{transform:translate(-10px)}30%{transform:translate(5px)}}@keyframes bounce-down{0%,10%,25%,40%,50%{transform:translateY(0)}20%{transform:translateY(10px)}30%{transform:translateY(-5px)}}.reveal .controls{display:none;position:absolute;top:auto;bottom:var(--r-controls-spacing);right:var(--r-controls-spacing);left:auto;z-index:11;color:#000;pointer-events:none;font-size:10px}.reveal .controls button{position:absolute;padding:0;background-color:transparent;border:0;outline:0;cursor:pointer;color:currentColor;transform:scale(.9999);transition:color .2s ease,opacity .2s ease,transform .2s ease;z-index:2;pointer-events:auto;font-size:inherit;visibility:hidden;opacity:0;-webkit-appearance:none;-webkit-tap-highlight-color:transparent}.reveal .controls .controls-arrow:after,.reveal .controls .controls-arrow:before{content:"";position:absolute;top:0;left:0;width:2.6em;height:.5em;border-radius:.25em;background-color:currentColor;transition:all .15s ease,background-color .8s ease;transform-origin:.2em 50%;will-change:transform}.reveal .controls .controls-arrow{position:relative;width:3.6em;height:3.6em}.reveal .controls .controls-arrow:before{transform:translate(.5em) translateY(1.55em) rotate(45deg)}.reveal .controls .controls-arrow:after{transform:translate(.5em) translateY(1.55em) rotate(-45deg)}.reveal .controls .controls-arrow:hover:before{transform:translate(.5em) translateY(1.55em) rotate(40deg)}.reveal .controls .controls-arrow:hover:after{transform:translate(.5em) translateY(1.55em) rotate(-40deg)}.reveal .controls .controls-arrow:active:before{transform:translate(.5em) translateY(1.55em) rotate(36deg)}.reveal .controls .controls-arrow:active:after{transform:translate(.5em) translateY(1.55em) rotate(-36deg)}.reveal .controls .navigate-left{right:6.4em;bottom:3.2em;transform:translate(-10px)}.reveal .controls .navigate-left.highlight{animation:bounce-left 2s 50 both ease-out}.reveal .controls .navigate-right{right:0;bottom:3.2em;transform:translate(10px)}.reveal .controls .navigate-right .controls-arrow{transform:rotate(180deg)}.reveal .controls .navigate-right.highlight{animation:bounce-right 2s 50 both ease-out}.reveal .controls .navigate-up{right:3.2em;bottom:6.4em;transform:translateY(-10px)}.reveal .controls .navigate-up .controls-arrow{transform:rotate(90deg)}.reveal .controls .navigate-down{right:3.2em;bottom:-1.4em;padding-bottom:1.4em;transform:translateY(10px)}.reveal .controls .navigate-down .controls-arrow{transform:rotate(-90deg)}.reveal .controls .navigate-down.highlight{animation:bounce-down 2s 50 both ease-out}.reveal .controls[data-controls-back-arrows=faded] .navigate-up.enabled{opacity:.3}.reveal .controls[data-controls-back-arrows=faded] .navigate-up.enabled:hover{opacity:1}.reveal .controls[data-controls-back-arrows=hidden] .navigate-up.enabled{opacity:0;visibility:hidden}.reveal .controls .enabled{visibility:visible;opacity:.9;cursor:pointer;transform:none}.reveal .controls .enabled.fragmented{opacity:.5}.reveal .controls .enabled.fragmented:hover,.reveal .controls .enabled:hover{opacity:1}.reveal:not(.rtl) .controls[data-controls-back-arrows=faded] .navigate-left.enabled{opacity:.3}.reveal:not(.rtl) .controls[data-controls-back-arrows=faded] .navigate-left.enabled:hover{opacity:1}.reveal:not(.rtl) .controls[data-controls-back-arrows=hidden] .navigate-left.enabled{opacity:0;visibility:hidden}.reveal.rtl .controls[data-controls-back-arrows=faded] .navigate-right.enabled{opacity:.3}.reveal.rtl .controls[data-controls-back-arrows=faded] .navigate-right.enabled:hover{opacity:1}.reveal.rtl .controls[data-controls-back-arrows=hidden] .navigate-right.enabled{opacity:0;visibility:hidden}.reveal[data-navigation-mode=linear].has-horizontal-slides .navigate-down,.reveal[data-navigation-mode=linear].has-horizontal-slides .navigate-up{display:none}.reveal:not(.has-vertical-slides) .controls .navigate-left,.reveal[data-navigation-mode=linear].has-horizontal-slides .navigate-left{bottom:1.4em;right:5.5em}.reveal:not(.has-vertical-slides) .controls .navigate-right,.reveal[data-navigation-mode=linear].has-horizontal-slides .navigate-right{bottom:1.4em;right:.5em}.reveal:not(.has-horizontal-slides) .controls .navigate-up{right:1.4em;bottom:5em}.reveal:not(.has-horizontal-slides) .controls .navigate-down{right:1.4em;bottom:.5em}.reveal.has-dark-background .controls{color:#fff}.reveal.has-light-background .controls{color:#000}.reveal.no-hover .controls .controls-arrow:active:before,.reveal.no-hover .controls .controls-arrow:hover:before{transform:translate(.5em) translateY(1.55em) rotate(45deg)}.reveal.no-hover .controls .controls-arrow:active:after,.reveal.no-hover .controls .controls-arrow:hover:after{transform:translate(.5em) translateY(1.55em) rotate(-45deg)}@media screen and (min-width:500px){.reveal-viewport{--r-controls-spacing:.8em}.reveal .controls[data-controls-layout=edges]{inset:0}.reveal .controls[data-controls-layout=edges] .navigate-down,.reveal .controls[data-controls-layout=edges] .navigate-left,.reveal .controls[data-controls-layout=edges] .navigate-right,.reveal .controls[data-controls-layout=edges] .navigate-up{bottom:auto;right:auto}.reveal .controls[data-controls-layout=edges] .navigate-left{top:50%;left:var(--r-controls-spacing);margin-top:-1.8em}.reveal .controls[data-controls-layout=edges] .navigate-right{top:50%;right:var(--r-controls-spacing);margin-top:-1.8em}.reveal .controls[data-controls-layout=edges] .navigate-up{top:var(--r-controls-spacing);left:50%;margin-left:-1.8em}.reveal .controls[data-controls-layout=edges] .navigate-down{bottom:calc(var(--r-controls-spacing) - 1.4em + .3em);left:50%;margin-left:-1.8em}}.reveal .progress{position:absolute;display:none;height:3px;width:100%;bottom:0;left:0;z-index:10;background-color:#0003;color:#fff}.reveal .progress:after{content:"";display:block;position:absolute;height:10px;width:100%;top:-10px}.reveal .progress span{display:block;height:100%;width:100%;background-color:currentColor;transition:transform .8s cubic-bezier(.26,.86,.44,.985);transform-origin:0 0;transform:scaleX(0)}.reveal .slide-number{position:absolute;display:block;right:8px;bottom:8px;z-index:31;font-family:Helvetica,sans-serif;font-size:12px;line-height:1;color:#fff;background-color:#0006;padding:5px}.reveal .slide-number a{color:currentColor}.reveal .slide-number-delimiter{margin:0 3px}.reveal{position:relative;width:100%;height:100%;overflow:hidden;touch-action:pinch-zoom}.reveal.embedded{touch-action:pan-y}.reveal.embedded.is-vertical-slide{touch-action:none}.reveal .slides{position:absolute;width:100%;height:100%;inset:0;margin:auto;pointer-events:none;overflow:visible;z-index:1;text-align:center;perspective:600px;perspective-origin:50% 40%}.reveal .slides>section{perspective:600px}.reveal .slides>section,.reveal .slides>section>section{display:none;position:absolute;width:100%;pointer-events:auto;z-index:10;transform-style:flat;transition:transform-origin .8s cubic-bezier(.26,.86,.44,.985),transform .8s cubic-bezier(.26,.86,.44,.985),visibility .8s cubic-bezier(.26,.86,.44,.985),opacity .8s cubic-bezier(.26,.86,.44,.985)}.reveal[data-transition-speed=fast] .slides section{transition-duration:.4s}.reveal[data-transition-speed=slow] .slides section{transition-duration:1.2s}.reveal .slides section[data-transition-speed=fast]{transition-duration:.4s}.reveal .slides section[data-transition-speed=slow]{transition-duration:1.2s}.reveal .slides>section.stack{padding-top:0;padding-bottom:0;pointer-events:none;height:100%}.reveal .slides>section.present,.reveal .slides>section>section.present{display:block;z-index:11;opacity:1}.reveal .slides>section:empty,.reveal .slides>section>section:empty,.reveal .slides>section>section[data-background-interactive],.reveal .slides>section[data-background-interactive]{pointer-events:none}.reveal.center,.reveal.center .slides,.reveal.center .slides section{min-height:0!important}.reveal .slides>section:not(.present),.reveal .slides>section>section:not(.present){pointer-events:none}.reveal.overview .slides>section,.reveal.overview .slides>section>section{pointer-events:auto}.reveal .slides>section.future,.reveal .slides>section.future>section,.reveal .slides>section.past,.reveal .slides>section.past>section,.reveal .slides>section>section.future,.reveal .slides>section>section.past{opacity:0}.reveal .slides>section[data-transition=slide].past,.reveal .slides>section[data-transition~=slide-out].past,.reveal.slide .slides>section:not([data-transition]).past{transform:translate(-150%)}.reveal .slides>section[data-transition=slide].future,.reveal .slides>section[data-transition~=slide-in].future,.reveal.slide .slides>section:not([data-transition]).future{transform:translate(150%)}.reveal .slides>section>section[data-transition=slide].past,.reveal .slides>section>section[data-transition~=slide-out].past,.reveal.slide .slides>section>section:not([data-transition]).past{transform:translateY(-150%)}.reveal .slides>section>section[data-transition=slide].future,.reveal .slides>section>section[data-transition~=slide-in].future,.reveal.slide .slides>section>section:not([data-transition]).future{transform:translateY(150%)}.reveal .slides>section[data-transition=linear].past,.reveal .slides>section[data-transition~=linear-out].past,.reveal.linear .slides>section:not([data-transition]).past{transform:translate(-150%)}.reveal .slides>section[data-transition=linear].future,.reveal .slides>section[data-transition~=linear-in].future,.reveal.linear .slides>section:not([data-transition]).future{transform:translate(150%)}.reveal .slides>section>section[data-transition=linear].past,.reveal .slides>section>section[data-transition~=linear-out].past,.reveal.linear .slides>section>section:not([data-transition]).past{transform:translateY(-150%)}.reveal .slides>section>section[data-transition=linear].future,.reveal .slides>section>section[data-transition~=linear-in].future,.reveal.linear .slides>section>section:not([data-transition]).future{transform:translateY(150%)}.reveal .slides section[data-transition=default].stack,.reveal.default .slides section.stack{transform-style:preserve-3d}.reveal .slides>section[data-transition=default].past,.reveal .slides>section[data-transition~=default-out].past,.reveal.default .slides>section:not([data-transition]).past{transform:translate3d(-100%,0,0) rotateY(-90deg) translate3d(-100%,0,0)}.reveal .slides>section[data-transition=default].future,.reveal .slides>section[data-transition~=default-in].future,.reveal.default .slides>section:not([data-transition]).future{transform:translate3d(100%,0,0) rotateY(90deg) translate3d(100%,0,0)}.reveal .slides>section>section[data-transition=default].past,.reveal .slides>section>section[data-transition~=default-out].past,.reveal.default .slides>section>section:not([data-transition]).past{transform:translate3d(0,-300px,0) rotateX(70deg) translate3d(0,-300px,0)}.reveal .slides>section>section[data-transition=default].future,.reveal .slides>section>section[data-transition~=default-in].future,.reveal.default .slides>section>section:not([data-transition]).future{transform:translate3d(0,300px,0) rotateX(-70deg) translate3d(0,300px,0)}.reveal .slides section[data-transition=convex].stack,.reveal.convex .slides section.stack{transform-style:preserve-3d}.reveal .slides>section[data-transition=convex].past,.reveal .slides>section[data-transition~=convex-out].past,.reveal.convex .slides>section:not([data-transition]).past{transform:translate3d(-100%,0,0) rotateY(-90deg) translate3d(-100%,0,0)}.reveal .slides>section[data-transition=convex].future,.reveal .slides>section[data-transition~=convex-in].future,.reveal.convex .slides>section:not([data-transition]).future{transform:translate3d(100%,0,0) rotateY(90deg) translate3d(100%,0,0)}.reveal .slides>section>section[data-transition=convex].past,.reveal .slides>section>section[data-transition~=convex-out].past,.reveal.convex .slides>section>section:not([data-transition]).past{transform:translate3d(0,-300px,0) rotateX(70deg) translate3d(0,-300px,0)}.reveal .slides>section>section[data-transition=convex].future,.reveal .slides>section>section[data-transition~=convex-in].future,.reveal.convex .slides>section>section:not([data-transition]).future{transform:translate3d(0,300px,0) rotateX(-70deg) translate3d(0,300px,0)}.reveal .slides section[data-transition=concave].stack,.reveal.concave .slides section.stack{transform-style:preserve-3d}.reveal .slides>section[data-transition=concave].past,.reveal .slides>section[data-transition~=concave-out].past,.reveal.concave .slides>section:not([data-transition]).past{transform:translate3d(-100%,0,0) rotateY(90deg) translate3d(-100%,0,0)}.reveal .slides>section[data-transition=concave].future,.reveal .slides>section[data-transition~=concave-in].future,.reveal.concave .slides>section:not([data-transition]).future{transform:translate3d(100%,0,0) rotateY(-90deg) translate3d(100%,0,0)}.reveal .slides>section>section[data-transition=concave].past,.reveal .slides>section>section[data-transition~=concave-out].past,.reveal.concave .slides>section>section:not([data-transition]).past{transform:translate3d(0,-80%,0) rotateX(-70deg) translate3d(0,-80%,0)}.reveal .slides>section>section[data-transition=concave].future,.reveal .slides>section>section[data-transition~=concave-in].future,.reveal.concave .slides>section>section:not([data-transition]).future{transform:translate3d(0,80%,0) rotateX(70deg) translate3d(0,80%,0)}.reveal .slides section[data-transition=zoom],.reveal.zoom .slides section:not([data-transition]){transition-timing-function:ease}.reveal .slides>section[data-transition=zoom].past,.reveal .slides>section[data-transition~=zoom-out].past,.reveal.zoom .slides>section:not([data-transition]).past{visibility:hidden;transform:scale(16)}.reveal .slides>section[data-transition=zoom].future,.reveal .slides>section[data-transition~=zoom-in].future,.reveal.zoom .slides>section:not([data-transition]).future{visibility:hidden;transform:scale(.2)}.reveal .slides>section>section[data-transition=zoom].past,.reveal .slides>section>section[data-transition~=zoom-out].past,.reveal.zoom .slides>section>section:not([data-transition]).past{transform:scale(16)}.reveal .slides>section>section[data-transition=zoom].future,.reveal .slides>section>section[data-transition~=zoom-in].future,.reveal.zoom .slides>section>section:not([data-transition]).future{transform:scale(.2)}.reveal.cube .slides{perspective:1300px}.reveal.cube .slides section{padding:30px;min-height:700px;backface-visibility:hidden;box-sizing:border-box;transform-style:preserve-3d}.reveal.center.cube .slides section{min-height:0}.reveal.cube .slides section:not(.stack):before{content:"";position:absolute;display:block;width:100%;height:100%;left:0;top:0;background:#0000001a;border-radius:4px;transform:translateZ(-20px)}.reveal.cube .slides section:not(.stack):after{content:"";position:absolute;display:block;width:90%;height:30px;left:5%;bottom:0;background:0 0;z-index:1;border-radius:4px;box-shadow:0 95px 25px #0003;transform:translateZ(-90px) rotateX(65deg)}.reveal.cube .slides>section.stack{padding:0;background:0 0}.reveal.cube .slides>section.past{transform-origin:100% 0;transform:translate3d(-100%,0,0) rotateY(-90deg)}.reveal.cube .slides>section.future{transform-origin:0 0;transform:translate3d(100%,0,0) rotateY(90deg)}.reveal.cube .slides>section>section.past{transform-origin:0 100%;transform:translate3d(0,-100%,0) rotateX(90deg)}.reveal.cube .slides>section>section.future{transform-origin:0 0;transform:translate3d(0,100%,0) rotateX(-90deg)}.reveal.page .slides{perspective-origin:0 50%;perspective:3000px}.reveal.page .slides section{padding:30px;min-height:700px;box-sizing:border-box;transform-style:preserve-3d}.reveal.page .slides section.past{z-index:12}.reveal.page .slides section:not(.stack):before{content:"";position:absolute;display:block;width:100%;height:100%;left:0;top:0;background:#0000001a;transform:translateZ(-20px)}.reveal.page .slides section:not(.stack):after{content:"";position:absolute;display:block;width:90%;height:30px;left:5%;bottom:0;background:0 0;z-index:1;border-radius:4px;box-shadow:0 95px 25px #0003;transform:translateZ(-90px) rotateX(65deg)}.reveal.page .slides>section.stack{padding:0;background:0 0}.reveal.page .slides>section.past{transform-origin:0 0;transform:translate3d(-40%,0,0) rotateY(-80deg)}.reveal.page .slides>section.future{transform-origin:100% 0;transform:translateZ(0)}.reveal.page .slides>section>section.past{transform-origin:0 0;transform:translate3d(0,-40%,0) rotateX(80deg)}.reveal.page .slides>section>section.future{transform-origin:0 100%;transform:translateZ(0)}.reveal .slides section[data-transition=fade],.reveal.fade .slides section:not([data-transition]),.reveal.fade .slides>section>section:not([data-transition]){transform:none;transition:opacity .5s}.reveal.fade.overview .slides section,.reveal.fade.overview .slides>section>section{transition:none}.reveal .slides section[data-transition=none],.reveal.none .slides section:not([data-transition]){transform:none;transition:none}.reveal .pause-overlay{position:absolute;top:0;left:0;width:100%;height:100%;background:#000;visibility:hidden;opacity:0;z-index:100;transition:all 1s ease}.reveal .pause-overlay .resume-button{position:absolute;bottom:20px;right:20px;color:#ccc;border-radius:2px;padding:6px 14px;border:2px solid #ccc;font-size:16px;background:0 0;cursor:pointer}.reveal .pause-overlay .resume-button:hover{color:#fff;border-color:#fff}.reveal.paused .pause-overlay{visibility:visible;opacity:1}.reveal .no-transition,.reveal .no-transition *,.reveal .slides.disable-slide-transitions section{transition:none!important}.reveal .slides.disable-slide-transitions section{transform:none!important}.reveal .backgrounds{position:absolute;width:100%;height:100%;top:0;left:0;perspective:600px}.reveal .slide-background{display:none;position:absolute;width:100%;height:100%;opacity:0;visibility:hidden;overflow:hidden;background-color:#0000;transition:all .8s cubic-bezier(.26,.86,.44,.985)}.reveal .slide-background-content{position:absolute;width:100%;height:100%;background-position:50% 50%;background-repeat:no-repeat;background-size:cover}.reveal .slide-background.stack{display:block}.reveal .slide-background.present{opacity:1;visibility:visible;z-index:2}.print-pdf .reveal .slide-background{opacity:1!important;visibility:visible!important}.reveal .slide-background video{position:absolute;width:100%;height:100%;max-width:none;max-height:none;top:0;left:0;object-fit:cover}.reveal .slide-background[data-background-size=contain] video{object-fit:contain}.reveal>.backgrounds .slide-background[data-background-transition=none],.reveal[data-background-transition=none]>.backgrounds .slide-background:not([data-background-transition]){transition:none}.reveal>.backgrounds .slide-background[data-background-transition=slide],.reveal[data-background-transition=slide]>.backgrounds .slide-background:not([data-background-transition]){opacity:1}.reveal>.backgrounds .slide-background.past[data-background-transition=slide],.reveal[data-background-transition=slide]>.backgrounds .slide-background.past:not([data-background-transition]){transform:translate(-100%)}.reveal>.backgrounds .slide-background.future[data-background-transition=slide],.reveal[data-background-transition=slide]>.backgrounds .slide-background.future:not([data-background-transition]){transform:translate(100%)}.reveal>.backgrounds .slide-background>.slide-background.past[data-background-transition=slide],.reveal[data-background-transition=slide]>.backgrounds .slide-background>.slide-background.past:not([data-background-transition]){transform:translateY(-100%)}.reveal>.backgrounds .slide-background>.slide-background.future[data-background-transition=slide],.reveal[data-background-transition=slide]>.backgrounds .slide-background>.slide-background.future:not([data-background-transition]){transform:translateY(100%)}.reveal>.backgrounds .slide-background.past[data-background-transition=convex],.reveal[data-background-transition=convex]>.backgrounds .slide-background.past:not([data-background-transition]){opacity:0;transform:translate3d(-100%,0,0) rotateY(-90deg) translate3d(-100%,0,0)}.reveal>.backgrounds .slide-background.future[data-background-transition=convex],.reveal[data-background-transition=convex]>.backgrounds .slide-background.future:not([data-background-transition]){opacity:0;transform:translate3d(100%,0,0) rotateY(90deg) translate3d(100%,0,0)}.reveal>.backgrounds .slide-background>.slide-background.past[data-background-transition=convex],.reveal[data-background-transition=convex]>.backgrounds .slide-background>.slide-background.past:not([data-background-transition]){opacity:0;transform:translate3d(0,-100%,0) rotateX(90deg) translate3d(0,-100%,0)}.reveal>.backgrounds .slide-background>.slide-background.future[data-background-transition=convex],.reveal[data-background-transition=convex]>.backgrounds .slide-background>.slide-background.future:not([data-background-transition]){opacity:0;transform:translate3d(0,100%,0) rotateX(-90deg) translate3d(0,100%,0)}.reveal>.backgrounds .slide-background.past[data-background-transition=concave],.reveal[data-background-transition=concave]>.backgrounds .slide-background.past:not([data-background-transition]){opacity:0;transform:translate3d(-100%,0,0) rotateY(90deg) translate3d(-100%,0,0)}.reveal>.backgrounds .slide-background.future[data-background-transition=concave],.reveal[data-background-transition=concave]>.backgrounds .slide-background.future:not([data-background-transition]){opacity:0;transform:translate3d(100%,0,0) rotateY(-90deg) translate3d(100%,0,0)}.reveal>.backgrounds .slide-background>.slide-background.past[data-background-transition=concave],.reveal[data-background-transition=concave]>.backgrounds .slide-background>.slide-background.past:not([data-background-transition]){opacity:0;transform:translate3d(0,-100%,0) rotateX(-90deg) translate3d(0,-100%,0)}.reveal>.backgrounds .slide-background>.slide-background.future[data-background-transition=concave],.reveal[data-background-transition=concave]>.backgrounds .slide-background>.slide-background.future:not([data-background-transition]){opacity:0;transform:translate3d(0,100%,0) rotateX(90deg) translate3d(0,100%,0)}.reveal>.backgrounds .slide-background[data-background-transition=zoom],.reveal[data-background-transition=zoom]>.backgrounds .slide-background:not([data-background-transition]){transition-timing-function:ease}.reveal>.backgrounds .slide-background.past[data-background-transition=zoom],.reveal[data-background-transition=zoom]>.backgrounds .slide-background.past:not([data-background-transition]){opacity:0;visibility:hidden;transform:scale(16)}.reveal>.backgrounds .slide-background.future[data-background-transition=zoom],.reveal[data-background-transition=zoom]>.backgrounds .slide-background.future:not([data-background-transition]){opacity:0;visibility:hidden;transform:scale(.2)}.reveal>.backgrounds .slide-background>.slide-background.past[data-background-transition=zoom],.reveal[data-background-transition=zoom]>.backgrounds .slide-background>.slide-background.past:not([data-background-transition]){opacity:0;visibility:hidden;transform:scale(16)}.reveal>.backgrounds .slide-background>.slide-background.future[data-background-transition=zoom],.reveal[data-background-transition=zoom]>.backgrounds .slide-background>.slide-background.future:not([data-background-transition]){opacity:0;visibility:hidden;transform:scale(.2)}.reveal[data-transition-speed=fast]>.backgrounds .slide-background{transition-duration:.4s}.reveal[data-transition-speed=slow]>.backgrounds .slide-background{transition-duration:1.2s}.reveal [data-auto-animate-target^=unmatched]{will-change:opacity}.reveal section[data-auto-animate]:not(.stack):not([data-auto-animate=running]) [data-auto-animate-target^=unmatched]{opacity:0}.reveal.overview{perspective-origin:50% 50%;perspective:700px}.reveal.overview .slides section{height:100%;top:0!important;opacity:1!important;overflow:hidden;visibility:visible!important;cursor:pointer;box-sizing:border-box}.reveal.overview .slides section.present,.reveal.overview .slides section:hover{outline:10px solid rgba(150,150,150,.4);outline-offset:10px}.reveal.overview .slides section .fragment{opacity:1;transition:none}.reveal.overview .slides section:after,.reveal.overview .slides section:before{display:none!important}.reveal.overview .slides>section.stack{padding:0;top:0!important;background:0 0;outline:0;overflow:visible}.reveal.overview .backgrounds{perspective:inherit}.reveal.overview .backgrounds .slide-background{opacity:1;visibility:visible;outline:10px solid rgba(150,150,150,.1);outline-offset:10px}.reveal.overview .backgrounds .slide-background.stack{overflow:visible}.reveal.overview .slides section,.reveal.overview-deactivating .slides section{transition:none}.reveal.overview .backgrounds .slide-background,.reveal.overview-deactivating .backgrounds .slide-background{transition:none}.reveal.rtl .slides,.reveal.rtl .slides h1,.reveal.rtl .slides h2,.reveal.rtl .slides h3,.reveal.rtl .slides h4,.reveal.rtl .slides h5,.reveal.rtl .slides h6{direction:rtl;font-family:sans-serif}.reveal.rtl code,.reveal.rtl pre{direction:ltr}.reveal.rtl ol,.reveal.rtl ul{text-align:right}.reveal.rtl .progress span{transform-origin:100% 0}.reveal.has-parallax-background .backgrounds{transition:all .8s ease}.reveal.has-parallax-background[data-transition-speed=fast] .backgrounds{transition-duration:.4s}.reveal.has-parallax-background[data-transition-speed=slow] .backgrounds{transition-duration:1.2s}@keyframes fade-in{0%{opacity:0}to{opacity:1}}@keyframes scale-up{0%{transform:scale(.95)}to{transform:scale(1)}}.reveal [data-preview-image],.reveal [data-preview-link]:not(a):not([data-preview-link=false]),.reveal [data-preview-video]{cursor:zoom-in}.r-overlay{position:absolute;top:var(--r-overlay-margin);right:var(--r-overlay-margin);bottom:var(--r-overlay-margin);left:var(--r-overlay-margin);border-radius:min(var(--r-overlay-margin),6px);z-index:99;background:#000000f2;-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);transition:all .3s ease;color:#fff;animation:fade-in .3s ease;font-family:ui-sans-serif,system-ui,-apple-system,Helvetica,sans-serif}.r-overlay-viewport{position:absolute;top:var(--r-overlay-padding);right:var(--r-overlay-padding);bottom:var(--r-overlay-padding);left:var(--r-overlay-padding);gap:var(--r-overlay-gap);display:flex;flex-direction:column}.r-overlay-header{display:flex;z-index:2;box-sizing:border-box;align-items:center;justify-content:flex-end;height:var(--r-overlay-header-height);gap:6px}.r-overlay-header .r-overlay-button{all:unset;display:flex;align-items:center;justify-content:center;min-width:var(--r-overlay-header-height);min-height:var(--r-overlay-header-height);padding:0 calc(var(--r-overlay-header-height)/ 4);opacity:1;border-radius:6px;font-size:18px;gap:8px;cursor:pointer;box-sizing:border-box}.r-overlay-header .r-overlay-button:hover{opacity:1;background-color:#ffffff26}.r-overlay-header .icon{display:inline-block;width:20px;height:20px;background-position:50% 50%;background-size:100%;background-repeat:no-repeat}.r-overlay-close .icon{background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNSIgaGVpZ2h0PSIxNSIgZmlsbD0ibm9uZSI+PHBhdGggZmlsbD0iI2ZmZiIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMTIuODU0IDIuODU0YS41LjUgMCAwIDAtLjcwOC0uNzA4TDcuNSA2Ljc5MyAyLjg1NCAyLjE0NmEuNS41IDAgMSAwLS43MDguNzA4TDYuNzkzIDcuNWwtNC42NDcgNC42NDZhLjUuNSAwIDAgMCAuNzA4LjcwOEw3LjUgOC4yMDdsNC42NDYgNC42NDdhLjUuNSAwIDAgMCAuNzA4LS43MDhMOC4yMDcgNy41bDQuNjQ3LTQuNjQ2WiIgY2xpcC1ydWxlPSJldmVub2RkIi8+PC9zdmc+)}.r-overlay-external .icon{background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNSIgaGVpZ2h0PSIxNSIgZmlsbD0ibm9uZSI+PHBhdGggZmlsbD0iI2ZmZiIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMyAyYTEgMSAwIDAgMC0xIDF2OWExIDEgMCAwIDAgMSAxaDlhMSAxIDAgMCAwIDEtMVY4LjVhLjUuNSAwIDAgMC0xIDBWMTJIM1YzaDMuNWEuNS41IDAgMCAwIDAtMUgzWm05Ljg1NC4xNDZhLjUuNSAwIDAgMSAuMTQ2LjM1MVY1LjVhLjUuNSAwIDAgMS0xIDBWMy43MDdMNi44NTQgOC44NTRhLjUuNSAwIDEgMS0uNzA4LS43MDhMMTEuMjkzIDNIOS41YS41LjUgMCAwIDEgMC0xaDNhLjQ5OS40OTkgMCAwIDEgLjM1NC4xNDZaIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiLz48L3N2Zz4=)}.r-overlay-content{position:relative;display:grid;place-items:center;border-radius:6px;overflow:hidden;flex-grow:1;background-color:#141414cc;animation:scale-up .5s cubic-bezier(.26,.86,.44,.985)}.r-overlay-spinner{position:absolute;display:block;top:50%;left:50%;width:32px;height:32px;margin:-16px 0 0 -16px;z-index:10;background-image:url(data:image/gif;base64,R0lGODlhIAAgAPMAAJmZmf%2F%2F%2F6%2Bvr8nJybW1tcDAwOjo6Nvb26ioqKOjo7Ozs%2FLy8vz8%2FAAAAAAAAAAAACH%2FC05FVFNDQVBFMi4wAwEAAAAh%2FhpDcmVhdGVkIHdpdGggYWpheGxvYWQuaW5mbwAh%2BQQJCgAAACwAAAAAIAAgAAAE5xDISWlhperN52JLhSSdRgwVo1ICQZRUsiwHpTJT4iowNS8vyW2icCF6k8HMMBkCEDskxTBDAZwuAkkqIfxIQyhBQBFvAQSDITM5VDW6XNE4KagNh6Bgwe60smQUB3d4Rz1ZBApnFASDd0hihh12BkE9kjAJVlycXIg7CQIFA6SlnJ87paqbSKiKoqusnbMdmDC2tXQlkUhziYtyWTxIfy6BE8WJt5YJvpJivxNaGmLHT0VnOgSYf0dZXS7APdpB309RnHOG5gDqXGLDaC457D1zZ%2FV%2FnmOM82XiHRLYKhKP1oZmADdEAAAh%2BQQJCgAAACwAAAAAIAAgAAAE6hDISWlZpOrNp1lGNRSdRpDUolIGw5RUYhhHukqFu8DsrEyqnWThGvAmhVlteBvojpTDDBUEIFwMFBRAmBkSgOrBFZogCASwBDEY%2FCZSg7GSE0gSCjQBMVG023xWBhklAnoEdhQEfyNqMIcKjhRsjEdnezB%2BA4k8gTwJhFuiW4dokXiloUepBAp5qaKpp6%2BHo7aWW54wl7obvEe0kRuoplCGepwSx2jJvqHEmGt6whJpGpfJCHmOoNHKaHx61WiSR92E4lbFoq%2BB6QDtuetcaBPnW6%2BO7wDHpIiK9SaVK5GgV543tzjgGcghAgAh%2BQQJCgAAACwAAAAAIAAgAAAE7hDISSkxpOrN5zFHNWRdhSiVoVLHspRUMoyUakyEe8PTPCATW9A14E0UvuAKMNAZKYUZCiBMuBakSQKG8G2FzUWox2AUtAQFcBKlVQoLgQReZhQlCIJesQXI5B0CBnUMOxMCenoCfTCEWBsJColTMANldx15BGs8B5wlCZ9Po6OJkwmRpnqkqnuSrayqfKmqpLajoiW5HJq7FL1Gr2mMMcKUMIiJgIemy7xZtJsTmsM4xHiKv5KMCXqfyUCJEonXPN2rAOIAmsfB3uPoAK%2B%2BG%2Bw48edZPK%2BM6hLJpQg484enXIdQFSS1u6UhksENEQAAIfkECQoAAAAsAAAAACAAIAAABOcQyEmpGKLqzWcZRVUQnZYg1aBSh2GUVEIQ2aQOE%2BG%2BcD4ntpWkZQj1JIiZIogDFFyHI0UxQwFugMSOFIPJftfVAEoZLBbcLEFhlQiqGp1Vd140AUklUN3eCA51C1EWMzMCezCBBmkxVIVHBWd3HHl9JQOIJSdSnJ0TDKChCwUJjoWMPaGqDKannasMo6WnM562R5YluZRwur0wpgqZE7NKUm%2BFNRPIhjBJxKZteWuIBMN4zRMIVIhffcgojwCF117i4nlLnY5ztRLsnOk%2BaV%2BoJY7V7m76PdkS4trKcdg0Zc0tTcKkRAAAIfkECQoAAAAsAAAAACAAIAAABO4QyEkpKqjqzScpRaVkXZWQEximw1BSCUEIlDohrft6cpKCk5xid5MNJTaAIkekKGQkWyKHkvhKsR7ARmitkAYDYRIbUQRQjWBwJRzChi9CRlBcY1UN4g0%2FVNB0AlcvcAYHRyZPdEQFYV8ccwR5HWxEJ02YmRMLnJ1xCYp0Y5idpQuhopmmC2KgojKasUQDk5BNAwwMOh2RtRq5uQuPZKGIJQIGwAwGf6I0JXMpC8C7kXWDBINFMxS4DKMAWVWAGYsAdNqW5uaRxkSKJOZKaU3tPOBZ4DuK2LATgJhkPJMgTwKCdFjyPHEnKxFCDhEAACH5BAkKAAAALAAAAAAgACAAAATzEMhJaVKp6s2nIkolIJ2WkBShpkVRWqqQrhLSEu9MZJKK9y1ZrqYK9WiClmvoUaF8gIQSNeF1Er4MNFn4SRSDARWroAIETg1iVwuHjYB1kYc1mwruwXKC9gmsJXliGxc%2BXiUCby9ydh1sOSdMkpMTBpaXBzsfhoc5l58Gm5yToAaZhaOUqjkDgCWNHAULCwOLaTmzswadEqggQwgHuQsHIoZCHQMMQgQGubVEcxOPFAcMDAYUA85eWARmfSRQCdcMe0zeP1AAygwLlJtPNAAL19DARdPzBOWSm1brJBi45soRAWQAAkrQIykShQ9wVhHCwCQCACH5BAkKAAAALAAAAAAgACAAAATrEMhJaVKp6s2nIkqFZF2VIBWhUsJaTokqUCoBq%2BE71SRQeyqUToLA7VxF0JDyIQh%2FMVVPMt1ECZlfcjZJ9mIKoaTl1MRIl5o4CUKXOwmyrCInCKqcWtvadL2SYhyASyNDJ0uIiRMDjI0Fd30%2FiI2UA5GSS5UDj2l6NoqgOgN4gksEBgYFf0FDqKgHnyZ9OX8HrgYHdHpcHQULXAS2qKpENRg7eAMLC7kTBaixUYFkKAzWAAnLC7FLVxLWDBLKCwaKTULgEwbLA4hJtOkSBNqITT3xEgfLpBtzE%2FjiuL04RGEBgwWhShRgQExHBAAh%2BQQJCgAAACwAAAAAIAAgAAAE7xDISWlSqerNpyJKhWRdlSAVoVLCWk6JKlAqAavhO9UkUHsqlE6CwO1cRdCQ8iEIfzFVTzLdRAmZX3I2SfZiCqGk5dTESJeaOAlClzsJsqwiJwiqnFrb2nS9kmIcgEsjQydLiIlHehhpejaIjzh9eomSjZR%2BipslWIRLAgMDOR2DOqKogTB9pCUJBagDBXR6XB0EBkIIsaRsGGMMAxoDBgYHTKJiUYEGDAzHC9EACcUGkIgFzgwZ0QsSBcXHiQvOwgDdEwfFs0sDzt4S6BK4xYjkDOzn0unFeBzOBijIm1Dgmg5YFQwsCMjp1oJ8LyIAACH5BAkKAAAALAAAAAAgACAAAATwEMhJaVKp6s2nIkqFZF2VIBWhUsJaTokqUCoBq%2BE71SRQeyqUToLA7VxF0JDyIQh%2FMVVPMt1ECZlfcjZJ9mIKoaTl1MRIl5o4CUKXOwmyrCInCKqcWtvadL2SYhyASyNDJ0uIiUd6GGl6NoiPOH16iZKNlH6KmyWFOggHhEEvAwwMA0N9GBsEC6amhnVcEwavDAazGwIDaH1ipaYLBUTCGgQDA8NdHz0FpqgTBwsLqAbWAAnIA4FWKdMLGdYGEgraigbT0OITBcg5QwPT4xLrROZL6AuQAPUS7bxLpoWidY0JtxLHKhwwMJBTHgPKdEQAACH5BAkKAAAALAAAAAAgACAAAATrEMhJaVKp6s2nIkqFZF2VIBWhUsJaTokqUCoBq%2BE71SRQeyqUToLA7VxF0JDyIQh%2FMVVPMt1ECZlfcjZJ9mIKoaTl1MRIl5o4CUKXOwmyrCInCKqcWtvadL2SYhyASyNDJ0uIiUd6GAULDJCRiXo1CpGXDJOUjY%2BYip9DhToJA4RBLwMLCwVDfRgbBAaqqoZ1XBMHswsHtxtFaH1iqaoGNgAIxRpbFAgfPQSqpbgGBqUD1wBXeCYp1AYZ19JJOYgH1KwA4UBvQwXUBxPqVD9L3sbp2BNk2xvvFPJd%2BMFCN6HAAIKgNggY0KtEBAAh%2BQQJCgAAACwAAAAAIAAgAAAE6BDISWlSqerNpyJKhWRdlSAVoVLCWk6JKlAqAavhO9UkUHsqlE6CwO1cRdCQ8iEIfzFVTzLdRAmZX3I2SfYIDMaAFdTESJeaEDAIMxYFqrOUaNW4E4ObYcCXaiBVEgULe0NJaxxtYksjh2NLkZISgDgJhHthkpU4mW6blRiYmZOlh4JWkDqILwUGBnE6TYEbCgevr0N1gH4At7gHiRpFaLNrrq8HNgAJA70AWxQIH1%2BvsYMDAzZQPC9VCNkDWUhGkuE5PxJNwiUK4UfLzOlD4WvzAHaoG9nxPi5d%2BjYUqfAhhykOFwJWiAAAIfkECQoAAAAsAAAAACAAIAAABPAQyElpUqnqzaciSoVkXVUMFaFSwlpOCcMYlErAavhOMnNLNo8KsZsMZItJEIDIFSkLGQoQTNhIsFehRww2CQLKF0tYGKYSg%2BygsZIuNqJksKgbfgIGepNo2cIUB3V1B3IvNiBYNQaDSTtfhhx0CwVPI0UJe0%2Bbm4g5VgcGoqOcnjmjqDSdnhgEoamcsZuXO1aWQy8KAwOAuTYYGwi7w5h%2BKr0SJ8MFihpNbx%2B4Erq7BYBuzsdiH1jCAzoSfl0rVirNbRXlBBlLX%2BBP0XJLAPGzTkAuAOqb0WT5AH7OcdCm5B8TgRwSRKIHQtaLCwg1RAAAOwAAAAAAAAAAAA%3D%3D);visibility:hidden;opacity:0}.r-overlay-preview .r-overlay-content iframe{width:100%;height:100%;max-width:100%;max-height:100%;border:0;opacity:0;visibility:hidden;transition:all .3s ease}.r-overlay-preview[data-state=loaded] iframe{opacity:1;visibility:visible}.r-overlay-preview .r-overlay-content img,.r-overlay-preview .r-overlay-content video{position:absolute;max-width:100%;max-height:100%;width:100%;height:100%;margin:0;object-fit:scale-down}.r-overlay-preview[data-preview-fit=none] img,.r-overlay-preview[data-preview-fit=none] video{object-fit:none}.r-overlay-preview[data-preview-fit=scale-down] img,.r-overlay-preview[data-preview-fit=scale-down] video{object-fit:scale-down}.r-overlay-preview[data-preview-fit=contain] img,.r-overlay-preview[data-preview-fit=contain] video{object-fit:contain}.r-overlay-preview[data-preview-fit=cover] img,.r-overlay-preview[data-preview-fit=cover] video{object-fit:cover}.r-overlay-preview[data-state=loaded] .r-overlay-content-inner{position:absolute;z-index:-1;left:0;top:45%;width:100%;text-align:center;letter-spacing:normal}.r-overlay-preview .r-overlay-error{font-size:18px;color:orange}.r-overlay-preview .x-frame-error{opacity:0;transition:opacity .3s ease .3s}.r-overlay-preview[data-state=loaded] .x-frame-error{opacity:1}.r-overlay-preview[data-state=loading] .r-overlay-spinner{opacity:.6;visibility:visible}.r-overlay-help .r-overlay-content{overflow:auto}.r-overlay-help-content{max-width:560px;padding:20px 0;margin:auto;text-align:center;letter-spacing:normal}.r-overlay-help-content .title{font-size:20px;margin-top:0}.r-overlay-help .r-overlay-help-content table{border:1px solid #fff;border-collapse:collapse;font-size:16px;text-align:left}.r-overlay-help .r-overlay-help-content table td,.r-overlay-help .r-overlay-help-content table th{width:240px;padding:14px;border:1px solid #fff;vertical-align:middle}.r-overlay-help .r-overlay-help-content table th{padding-top:20px;padding-bottom:20px}.reveal .playback{position:absolute;left:15px;bottom:20px;z-index:30;cursor:pointer;transition:all .4s ease;-webkit-tap-highlight-color:transparent}.reveal.overview .playback{opacity:0;visibility:hidden}.reveal .hljs{min-height:100%}.reveal .hljs table{margin:initial}.reveal .hljs-ln-code,.reveal .hljs-ln-numbers{padding:0;border:0}.reveal .hljs-ln-numbers{opacity:.6;padding-right:.75em;text-align:right;vertical-align:top}.reveal .hljs.has-highlights tr:not(.highlight-line){opacity:.4}.reveal .hljs.has-highlights.fragment{transition:all .2s ease}.reveal .hljs:not(:first-child).fragment{position:absolute;top:0;left:0;width:100%;box-sizing:border-box}.reveal pre[data-auto-animate-target]{overflow:hidden}.reveal pre[data-auto-animate-target] code{height:100%}.reveal .roll{display:inline-block;line-height:1.2;overflow:hidden;vertical-align:top;perspective:400px;perspective-origin:50% 50%}.reveal .roll:hover{background:0 0;text-shadow:none}.reveal .roll span{display:block;position:relative;padding:0 2px;pointer-events:none;transition:all .4s ease;transform-origin:50% 0;transform-style:preserve-3d;backface-visibility:hidden}.reveal .roll:hover span{background:#00000080;transform:translateZ(-45px) rotateX(90deg)}.reveal .roll span:after{content:attr(data-title);display:block;position:absolute;left:0;top:0;padding:0 2px;backface-visibility:hidden;transform-origin:50% 0;transform:translate3d(0,110%,0) rotateX(-90deg)}.reveal aside.notes{display:none}.reveal .speaker-notes{display:none;position:absolute;width:33.3333333333%;height:100%;top:0;left:100%;padding:14px 18px;z-index:1;font-size:18px;line-height:1.4;border:1px solid rgba(0,0,0,.05);color:#222;background-color:#f5f5f5;overflow:auto;box-sizing:border-box;text-align:left;font-family:Helvetica,sans-serif;-webkit-overflow-scrolling:touch}.reveal .speaker-notes .notes-placeholder{color:#ccc;font-style:italic}.reveal .speaker-notes:focus{outline:0}.reveal .speaker-notes:before{content:"Speaker notes";display:block;margin-bottom:10px;opacity:.5}.reveal.show-notes{max-width:75%;overflow:visible}.reveal.show-notes .speaker-notes{display:block}@media screen and (min-width:1600px){.reveal .speaker-notes{font-size:20px}}@media screen and (max-width:1024px){.reveal.show-notes{border-left:0;max-width:none;max-height:70%;max-height:70vh;overflow:visible}.reveal.show-notes .speaker-notes{top:100%;left:0;width:100%;height:30vh;border:0}}@media screen and (max-width:600px){.reveal.show-notes{max-height:60%;max-height:60vh}.reveal.show-notes .speaker-notes{top:100%;height:40vh}.reveal .speaker-notes{font-size:14px}}.reveal .jump-to-slide{position:absolute;top:15px;left:15px;z-index:30;font-size:32px;-webkit-tap-highlight-color:transparent}.reveal .jump-to-slide-input{background:0 0;padding:8px;font-size:inherit;color:currentColor;border:0}.reveal .jump-to-slide-input::placeholder{color:currentColor;opacity:.5}.reveal.has-dark-background .jump-to-slide-input{color:#fff}.reveal.has-light-background .jump-to-slide-input{color:#222}.reveal .jump-to-slide-input:focus{outline:0}.zoomed .reveal *,.zoomed .reveal :after,.zoomed .reveal :before{backface-visibility:visible!important}.zoomed .reveal .controls,.zoomed .reveal .progress{opacity:0}.zoomed .reveal .roll span{background:0 0}.zoomed .reveal .roll span:after{visibility:hidden}.reveal-viewport.loading-scroll-mode{visibility:hidden}.reveal-viewport.reveal-scroll{margin:0 auto;overflow:auto;overflow-x:hidden;overflow-y:auto;z-index:1;--r-scrollbar-width:7px;--r-scrollbar-trigger-size:5px;--r-controls-spacing:8px}@media screen and (max-width:500px){.reveal-viewport.reveal-scroll{--r-scrollbar-width:3px;--r-scrollbar-trigger-size:3px}}.reveal-viewport.reveal-scroll .backgrounds,.reveal-viewport.reveal-scroll .controls,.reveal-viewport.reveal-scroll .playback,.reveal-viewport.reveal-scroll .progress,.reveal-viewport.reveal-scroll .slide-number,.reveal-viewport.reveal-scroll .speaker-notes{display:none!important}.reveal-viewport.reveal-scroll .pause-overlay,.reveal-viewport.reveal-scroll .r-overlay{position:fixed}.reveal-viewport.reveal-scroll .reveal{overflow:visible;touch-action:manipulation}.reveal-viewport.reveal-scroll .slides{position:static;pointer-events:initial;left:auto;top:auto;width:100%!important;margin:0;padding:0;overflow:visible;display:block;perspective:none;perspective-origin:50% 50%}.reveal-viewport.reveal-scroll .scroll-page{position:relative;width:100%;height:calc(var(--page-height) + var(--page-scroll-padding));z-index:1;overflow:visible}.reveal-viewport.reveal-scroll .scroll-page-sticky{position:sticky;height:var(--page-height);top:0}.reveal-viewport.reveal-scroll .scroll-page-content{position:absolute;top:0;left:0;width:100%;height:100%;overflow:hidden}.reveal-viewport.reveal-scroll .scroll-page section{visibility:visible!important;display:block!important;position:absolute!important;width:var(--slide-width)!important;height:var(--slide-height)!important;top:50%!important;left:50%!important;opacity:1!important;transform:scale(var(--slide-scale)) translate(-50%,-50%)!important;transform-style:flat!important;transform-origin:0 0!important}.reveal-viewport.reveal-scroll .slide-background{display:block!important;position:absolute;top:0;left:0;width:100%;height:100%;z-index:auto!important;visibility:visible;opacity:1;touch-action:manipulation}.reveal-viewport.reveal-scroll[data-scrollbar=auto]::-webkit-scrollbar,.reveal-viewport.reveal-scroll[data-scrollbar=true]::-webkit-scrollbar{display:none}.reveal-viewport.reveal-scroll[data-scrollbar=auto],.reveal-viewport.reveal-scroll[data-scrollbar=true]{scrollbar-width:none}.reveal-viewport.has-dark-background,.reveal.has-dark-background{--r-overlay-element-bg-color:240,240,240;--r-overlay-element-fg-color:0,0,0}.reveal-viewport.has-light-background,.reveal.has-light-background{--r-overlay-element-bg-color:0,0,0;--r-overlay-element-fg-color:240,240,240}.reveal-viewport.reveal-scroll .scrollbar{position:sticky;top:50%;z-index:20;opacity:0;transition:all .3s ease}.reveal-viewport.reveal-scroll .scrollbar.visible,.reveal-viewport.reveal-scroll .scrollbar:hover{opacity:1}.reveal-viewport.reveal-scroll .scrollbar .scrollbar-inner{position:absolute;width:var(--r-scrollbar-width);height:calc(var(--viewport-height) - var(--r-controls-spacing) * 2);right:var(--r-controls-spacing);top:0;transform:translateY(-50%);border-radius:var(--r-scrollbar-width);z-index:10}.reveal-viewport.reveal-scroll .scrollbar .scrollbar-playhead{position:absolute;width:var(--r-scrollbar-width);height:var(--r-scrollbar-width);top:0;left:0;border-radius:var(--r-scrollbar-width);background-color:rgba(var(--r-overlay-element-bg-color),1);z-index:11;transition:background-color .2s ease}.reveal-viewport.reveal-scroll .scrollbar .scrollbar-slide{position:absolute;width:100%;background-color:rgba(var(--r-overlay-element-bg-color),.2);box-shadow:0 0 0 1px rgba(var(--r-overlay-element-fg-color),.1);border-radius:var(--r-scrollbar-width);transition:background-color .2s ease}.reveal-viewport.reveal-scroll .scrollbar .scrollbar-slide:after{content:"";position:absolute;width:200%;height:100%;top:0;left:-50%;background:#0000;z-index:-1}.reveal-viewport.reveal-scroll .scrollbar .scrollbar-slide.active,.reveal-viewport.reveal-scroll .scrollbar .scrollbar-slide:hover{background-color:rgba(var(--r-overlay-element-bg-color),.4)}.reveal-viewport.reveal-scroll .scrollbar .scrollbar-trigger{position:absolute;width:100%;transition:background-color .2s ease}.reveal-viewport.reveal-scroll .scrollbar .scrollbar-slide.active.has-triggers{background-color:rgba(var(--r-overlay-element-bg-color),.4);z-index:10}.reveal-viewport.reveal-scroll .scrollbar .scrollbar-slide.active .scrollbar-trigger:after{content:"";position:absolute;width:var(--r-scrollbar-trigger-size);height:var(--r-scrollbar-trigger-size);border-radius:20px;top:50%;left:50%;transform:translate(-50%,-50%);background-color:rgba(var(--r-overlay-element-bg-color),1);transition:transform .2s ease,opacity .2s ease;opacity:.4}.reveal-viewport.reveal-scroll .scrollbar .scrollbar-slide.active .scrollbar-trigger.active:after,.reveal-viewport.reveal-scroll .scrollbar .scrollbar-slide.active .scrollbar-trigger.active~.scrollbar-trigger:after{opacity:1}.reveal-viewport.reveal-scroll .scrollbar .scrollbar-slide.active .scrollbar-trigger~.scrollbar-trigger.active:after{transform:translate(calc(var(--r-scrollbar-width) * -2));background-color:rgba(var(--r-overlay-element-bg-color),1)}html.reveal-print *{-webkit-print-color-adjust:exact}html.reveal-print{width:100%;height:100%;overflow:visible}html.reveal-print body{margin:0 auto!important;border:0;padding:0;float:none!important;overflow:visible}html.reveal-print .nestedarrow,html.reveal-print .reveal .controls,html.reveal-print .reveal .playback,html.reveal-print .reveal .progress,html.reveal-print .reveal.overview,html.reveal-print .state-background{display:none!important}html.reveal-print .reveal pre code{overflow:hidden!important}html.reveal-print .reveal{width:auto!important;height:auto!important;overflow:hidden!important}html.reveal-print .reveal .slides{position:static;width:100%!important;height:auto!important;zoom:1!important;pointer-events:initial;left:auto;top:auto;margin:0!important;padding:0!important;overflow:visible;display:block;perspective:none;perspective-origin:50% 50%}html.reveal-print .reveal .slides .pdf-page{position:relative;overflow:hidden;z-index:1;page-break-after:always}html.reveal-print .reveal .slides .pdf-page:last-of-type{page-break-after:avoid}html.reveal-print .reveal .slides section{visibility:visible!important;display:block!important;position:absolute!important;margin:0!important;padding:0!important;box-sizing:border-box!important;min-height:1px;opacity:1!important;transform-style:flat!important;transform:none!important}html.reveal-print .reveal section.stack{position:relative!important;margin:0!important;padding:0!important;page-break-after:avoid!important;height:auto!important;min-height:auto!important}html.reveal-print .reveal img{box-shadow:none}html.reveal-print .reveal .backgrounds{display:none}html.reveal-print .reveal .slide-background{display:block!important;position:absolute;top:0;left:0;width:100%;height:100%;z-index:auto!important}html.reveal-print .reveal.show-notes{max-width:none;max-height:none}html.reveal-print .reveal .speaker-notes-pdf{display:block;width:100%;height:auto;max-height:none;inset:auto;z-index:100}html.reveal-print .reveal .speaker-notes-pdf[data-layout=separate-page]{position:relative;color:inherit;background-color:transparent;padding:20px;page-break-after:always;border:0}html.reveal-print .reveal .slide-number-pdf{display:block;position:absolute;font-size:14px;visibility:visible}html.reveal-print .aria-status{display:none}@media print{html:not(.print-pdf){overflow:visible;width:auto;height:auto}html:not(.print-pdf) body{margin:0;padding:0;overflow:visible}html:not(.print-pdf) .reveal{background:#fff;font-size:20pt}html:not(.print-pdf) .reveal .backgrounds,html:not(.print-pdf) .reveal .controls,html:not(.print-pdf) .reveal .progress,html:not(.print-pdf) .reveal .slide-number,html:not(.print-pdf) .reveal .state-background{display:none!important}html:not(.print-pdf) .reveal li,html:not(.print-pdf) .reveal p,html:not(.print-pdf) .reveal td{font-size:20pt!important;color:#000}html:not(.print-pdf) .reveal h1,html:not(.print-pdf) .reveal h2,html:not(.print-pdf) .reveal h3,html:not(.print-pdf) .reveal h4,html:not(.print-pdf) .reveal h5,html:not(.print-pdf) .reveal h6{color:#000!important;height:auto;line-height:normal;text-align:left;letter-spacing:normal}html:not(.print-pdf) .reveal h1{font-size:28pt!important}html:not(.print-pdf) .reveal h2{font-size:24pt!important}html:not(.print-pdf) .reveal h3{font-size:22pt!important}html:not(.print-pdf) .reveal h4{font-size:22pt!important;font-variant:small-caps}html:not(.print-pdf) .reveal h5{font-size:21pt!important}html:not(.print-pdf) .reveal h6{font-size:20pt!important;font-style:italic}html:not(.print-pdf) .reveal a:link,html:not(.print-pdf) .reveal a:visited{color:#000!important;font-weight:700;text-decoration:underline}html:not(.print-pdf) .reveal div,html:not(.print-pdf) .reveal ol,html:not(.print-pdf) .reveal p,html:not(.print-pdf) .reveal ul{visibility:visible;position:static;width:auto;height:auto;display:block;overflow:visible;margin:0;text-align:left!important}html:not(.print-pdf) .reveal pre,html:not(.print-pdf) .reveal table{margin-left:0;margin-right:0}html:not(.print-pdf) .reveal pre code{padding:20px}html:not(.print-pdf) .reveal blockquote{margin:20px 0}html:not(.print-pdf) .reveal .slides{position:static!important;width:auto!important;height:auto!important;left:0!important;top:0!important;margin-left:0!important;margin-top:0!important;padding:0!important;zoom:1!important;transform:none!important;overflow:visible!important;display:block!important;text-align:left!important;perspective:none;perspective-origin:50% 50%}html:not(.print-pdf) .reveal .slides section{visibility:visible!important;position:static!important;width:auto!important;height:auto!important;display:block!important;overflow:visible!important;left:0!important;top:0!important;margin-left:0!important;margin-top:0!important;padding:60px 20px!important;z-index:auto!important;opacity:1!important;page-break-after:always!important;transform-style:flat!important;transform:none!important;transition:none!important}html:not(.print-pdf) .reveal .slides section.stack{padding:0!important}html:not(.print-pdf) .reveal .slides section:last-of-type{page-break-after:avoid!important}html:not(.print-pdf) .reveal .slides section .fragment{opacity:1!important;visibility:visible!important;transform:none!important}html:not(.print-pdf) .reveal .r-fit-text{white-space:normal!important}html:not(.print-pdf) .reveal section img{display:block;margin:15px 0;background:#fff;border:1px solid #666;box-shadow:none}html:not(.print-pdf) .reveal section small{font-size:.8em}html:not(.print-pdf) .reveal .hljs{max-height:100%;white-space:pre-wrap;word-wrap:break-word;word-break:break-word;font-size:15pt}html:not(.print-pdf) .reveal .hljs .hljs-ln-numbers{white-space:nowrap}html:not(.print-pdf) .reveal .hljs td{font-size:inherit!important;color:inherit!important}}', k = ".reveal{width:100%;height:100%;--slidejs-revealjs-background-color: var(--slidejs-background-color, #191919);--slidejs-revealjs-text-color: var(--slidejs-text-color, #ffffff);--slidejs-revealjs-link-color: var(--slidejs-link-color, #42affa);--slidejs-revealjs-heading-color: var(--slidejs-heading-color, #ffffff);--slidejs-revealjs-code-background: var(--slidejs-code-background, #3f3f3f)}.reveal{background-color:var(--slidejs-revealjs-background-color, #191919);color:var(--slidejs-revealjs-text-color, #ffffff)}.reveal h1,.reveal h2,.reveal h3,.reveal h4,.reveal h5,.reveal h6{color:var(--slidejs-revealjs-heading-color, #ffffff)}.reveal a{color:var(--slidejs-revealjs-link-color, #42affa)}.reveal pre code{background-color:var(--slidejs-revealjs-code-background, #3f3f3f)}.slide-content{width:100%;height:100%;display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;padding:2rem}.slide-content h1{font-size:3rem;margin-bottom:1rem;color:var(--slidejs-heading-color, #ffffff)}.slide-content h2{font-size:2rem;margin-bottom:1rem;color:var(--slidejs-heading-color, #ffffff)}.slide-content h3{font-size:1.5rem;margin-bottom:.5rem;color:var(--slidejs-heading-color, #ffffff)}.slide-content p{font-size:1.2rem;line-height:1.6;color:var(--slidejs-text-color, #ffffff);margin-bottom:1rem}.slide-content ul{text-align:left;display:inline-block;font-size:1.2rem;line-height:1.8;color:var(--slidejs-text-color, #ffffff)}.slide-content li{margin-bottom:.5rem}.slide-content img{border-radius:8px;box-shadow:0 4px 12px #0000001a}";
|
|
280
|
+
async function x(c, a, t) {
|
|
281
|
+
const e = await h(c), o = m(e), r = "reveal-styles";
|
|
282
|
+
if (!document.head.querySelector(`#${r}`)) {
|
|
283
|
+
const n = document.createElement("style");
|
|
284
|
+
n.id = r, n.textContent = b, document.head.appendChild(n);
|
|
285
|
+
}
|
|
286
|
+
let s;
|
|
287
|
+
if (typeof t.container == "string") {
|
|
288
|
+
const n = document.querySelector(t.container);
|
|
289
|
+
if (!n)
|
|
290
|
+
throw new Error(`Container not found: ${t.container}`);
|
|
291
|
+
s = n;
|
|
292
|
+
} else
|
|
293
|
+
s = t.container;
|
|
294
|
+
const i = "slidejs-runner-revealjs-styles";
|
|
295
|
+
if (!s.querySelector(`#${i}`)) {
|
|
296
|
+
const n = document.createElement("style");
|
|
297
|
+
n.id = i, n.textContent = k, s.appendChild(n);
|
|
298
|
+
}
|
|
299
|
+
const d = document.createElement("div");
|
|
300
|
+
d.style.width = "100%", d.style.height = "100%", s.appendChild(d);
|
|
301
|
+
const p = new f(), v = new u({
|
|
302
|
+
container: d,
|
|
303
|
+
adapter: p,
|
|
285
304
|
adapterOptions: {
|
|
286
305
|
revealConfig: t.revealOptions
|
|
287
306
|
}
|
|
288
307
|
});
|
|
289
|
-
return await
|
|
308
|
+
return await v.run(o, a), v;
|
|
290
309
|
}
|
|
291
310
|
export {
|
|
292
|
-
|
|
293
|
-
|
|
311
|
+
f as RevealJsAdapter,
|
|
312
|
+
x as createSlideRunner
|
|
294
313
|
};
|
|
295
314
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","sources":["../src/adapter.ts","../src/runner.ts"],"sourcesContent":["/**\n * @slidejs/runner-revealjs - RevealJsAdapter 适配器实现\n *\n * 将 Slide DSL 渲染为 reveal.js 演示文稿\n */\n\nimport Reveal from 'reveal.js';\n// CSS 现在通过 index.ts 中的 style.css 导入,不需要在这里重复导入\nimport type { SlideDefinition } from '@slidejs/core';\nimport type { SlideAdapter, AdapterEvent, EventHandler } from '@slidejs/runner';\nimport type { RevealJsOptions } from './types';\n\n/**\n * reveal.js 适配器\n *\n * 实现 SlideAdapter 接口,将 SlideDefinition 渲染为 reveal.js 幻灯片\n */\nexport class RevealJsAdapter implements SlideAdapter {\n readonly name = 'revealjs';\n\n private reveal?: Reveal.Api;\n private revealContainer?: HTMLElement;\n private slidesContainer?: HTMLElement;\n private eventHandlers: Map<AdapterEvent, Set<EventHandler>> = new Map();\n\n /**\n * 初始化 reveal.js 适配器\n *\n * @param container - 容器元素\n * @param options - reveal.js 选项\n */\n async initialize(container: HTMLElement, options?: RevealJsOptions): Promise<void> {\n try {\n // 创建 reveal.js DOM 结构\n this.createRevealStructure(container);\n\n // 初始化 reveal.js\n if (!this.revealContainer) {\n throw new Error('Reveal container not created');\n }\n\n this.reveal = new Reveal(this.revealContainer, {\n // 默认配置\n controls: true,\n progress: true,\n center: true,\n hash: false,\n transition: 'slide',\n ...options?.revealConfig,\n });\n\n await this.reveal.initialize();\n\n // 设置事件监听\n this.setupEventListeners();\n\n // 触发 ready 事件\n this.emit('ready');\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n this.emit('error', { message: errorMessage });\n throw new Error(`Failed to initialize RevealJsAdapter: ${errorMessage}`);\n }\n }\n\n /**\n * 渲染幻灯片\n *\n * @param slides - 幻灯片定义数组\n */\n async render(slides: SlideDefinition[]): Promise<void> {\n if (!this.slidesContainer || !this.reveal) {\n throw new Error('RevealJsAdapter not initialized');\n }\n\n try {\n // 清空现有幻灯片\n this.slidesContainer.innerHTML = '';\n\n // 渲染每张幻灯片\n for (const slide of slides) {\n const section = await this.renderSlide(slide);\n this.slidesContainer.appendChild(section);\n }\n\n // 同步 reveal.js\n this.reveal.sync();\n\n // 触发 slideRendered 事件\n this.emit('slideRendered', { totalSlides: slides.length });\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n this.emit('error', { message: errorMessage });\n throw new Error(`Failed to render slides: ${errorMessage}`);\n }\n }\n\n /**\n * 销毁适配器\n */\n async destroy(): Promise<void> {\n if (this.reveal) {\n this.reveal.destroy();\n this.reveal = undefined;\n }\n\n if (this.revealContainer) {\n this.revealContainer.innerHTML = '';\n this.revealContainer = undefined;\n }\n\n this.slidesContainer = undefined;\n this.eventHandlers.clear();\n }\n\n /**\n * 导航到指定幻灯片\n *\n * @param index - 幻灯片索引\n */\n navigateTo(index: number): void {\n if (!this.reveal) {\n throw new Error('RevealJsAdapter not initialized');\n }\n\n // reveal.js 的 slide 方法需要 (indexh, indexv) 两个参数\n // 对于单层幻灯片,indexv 为 0\n this.reveal.slide(index, 0);\n }\n\n /**\n * 获取当前幻灯片索引\n */\n getCurrentIndex(): number {\n if (!this.reveal) {\n return 0;\n }\n\n const indices = this.reveal.getIndices();\n return indices.h;\n }\n\n /**\n * 获取幻灯片总数\n */\n getTotalSlides(): number {\n if (!this.reveal) {\n return 0;\n }\n\n return this.reveal.getTotalSlides();\n }\n\n /**\n * 更新指定幻灯片\n *\n * @param index - 幻灯片索引\n * @param slide - 新的幻灯片定义\n */\n async updateSlide(index: number, slide: SlideDefinition): Promise<void> {\n if (!this.slidesContainer || !this.reveal) {\n throw new Error('RevealJsAdapter not initialized');\n }\n\n try {\n // 获取指定索引的 section 元素\n const sections = this.slidesContainer.querySelectorAll('section');\n const targetSection = sections[index];\n\n if (!targetSection) {\n throw new Error(`Slide at index ${index} not found`);\n }\n\n // 渲染新的幻灯片内容\n const newSection = await this.renderSlide(slide);\n\n // 替换旧的 section\n targetSection.replaceWith(newSection);\n\n // 同步 reveal.js\n this.reveal.sync();\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n this.emit('error', { message: errorMessage });\n throw new Error(`Failed to update slide: ${errorMessage}`);\n }\n }\n\n /**\n * 注册事件监听器\n *\n * @param event - 事件类型\n * @param handler - 事件处理器\n */\n on(event: AdapterEvent, handler: EventHandler): void {\n if (!this.eventHandlers.has(event)) {\n this.eventHandlers.set(event, new Set());\n }\n this.eventHandlers.get(event)!.add(handler);\n }\n\n /**\n * 移除事件监听器\n *\n * @param event - 事件类型\n * @param handler - 事件处理器\n */\n off(event: AdapterEvent, handler: EventHandler): void {\n const handlers = this.eventHandlers.get(event);\n if (handlers) {\n handlers.delete(handler);\n }\n }\n\n /**\n * 创建 reveal.js DOM 结构\n *\n * reveal.js 5.x 需要以下 DOM 结构:\n * <div class=\"reveal-viewport\">\n * <div class=\"reveal\">\n * <div class=\"slides\">\n * <section>...</section>\n * </div>\n * </div>\n * </div>\n *\n * @param container - 容器元素\n */\n private createRevealStructure(container: HTMLElement): void {\n // 创建 .reveal-viewport 包装器(reveal.js 5.x 要求)\n const viewportDiv = document.createElement('div');\n viewportDiv.className = 'reveal-viewport';\n\n // 创建 .reveal 容器\n const revealDiv = document.createElement('div');\n revealDiv.className = 'reveal';\n\n // 创建 .slides 容器\n const slidesDiv = document.createElement('div');\n slidesDiv.className = 'slides';\n\n revealDiv.appendChild(slidesDiv);\n viewportDiv.appendChild(revealDiv);\n container.appendChild(viewportDiv);\n\n this.revealContainer = revealDiv;\n this.slidesContainer = slidesDiv;\n }\n\n /**\n * 设置 reveal.js 事件监听\n */\n private setupEventListeners(): void {\n if (!this.reveal) {\n return;\n }\n\n // 监听幻灯片切换事件\n this.reveal.on('slidechanged', (event: unknown) => {\n const revealEvent = event as { indexh: number; previousSlide?: HTMLElement };\n this.emit('slideChanged', {\n index: revealEvent.indexh,\n previousIndex: revealEvent.previousSlide?.dataset.index,\n });\n });\n\n // 监听 ready 事件\n this.reveal.on('ready', () => {\n this.emit('ready');\n });\n }\n\n /**\n * 渲染单张幻灯片\n *\n * @param slide - 幻灯片定义\n * @returns section 元素\n */\n private async renderSlide(slide: SlideDefinition): Promise<HTMLElement> {\n const section = document.createElement('section');\n\n // 设置过渡效果\n if (slide.behavior?.transition) {\n const transition = this.mapTransition(slide.behavior.transition.type);\n section.setAttribute('data-transition', transition);\n }\n\n // 渲染内容\n if (slide.content.type === 'dynamic') {\n // 动态内容(Web Components)\n const content = this.renderDynamicContent(slide.content.component, slide.content.props);\n section.appendChild(content);\n } else {\n // 静态文本内容\n const content = this.renderTextContent(slide.content.lines);\n section.appendChild(content);\n }\n\n return section;\n }\n\n /**\n * 渲染动态内容(Web Components)\n *\n * @param component - 组件名称\n * @param props - 组件属性\n * @returns 组件元素\n */\n private renderDynamicContent(component: string, props: Record<string, unknown>): HTMLElement {\n const element = document.createElement(component);\n\n // 设置属性\n for (const [key, value] of Object.entries(props)) {\n if (typeof value === 'string' || typeof value === 'number') {\n element.setAttribute(key, String(value));\n } else if (typeof value === 'boolean') {\n if (value) {\n element.setAttribute(key, '');\n }\n } else {\n // 对于对象和数组,设置为属性而不是 attribute\n (element as unknown as Record<string, unknown>)[key] = value;\n }\n }\n\n return element;\n }\n\n /**\n * 渲染文本内容\n *\n * 支持以下格式:\n * - # 标题 -> h1\n * - ## 标题 -> h2\n * - ### 标题 -> h3\n * -  -> img\n * - - 列表项 -> ul/li\n * - 普通文本 -> p\n *\n * @param lines - 文本行数组\n * @returns 内容容器元素\n */\n private renderTextContent(lines: string[]): HTMLElement {\n const container = document.createElement('div');\n container.className = 'slide-content';\n\n let listContainer: HTMLUListElement | null = null;\n\n for (const line of lines) {\n const trimmedLine = line.trim();\n\n // 空行,结束列表\n if (!trimmedLine) {\n listContainer = null;\n continue;\n }\n\n // 标题 - # H1\n if (trimmedLine.startsWith('# ')) {\n listContainer = null;\n const h1 = document.createElement('h1');\n h1.textContent = trimmedLine.substring(2);\n container.appendChild(h1);\n continue;\n }\n\n // 标题 - ## H2\n if (trimmedLine.startsWith('## ')) {\n listContainer = null;\n const h2 = document.createElement('h2');\n h2.textContent = trimmedLine.substring(3);\n container.appendChild(h2);\n continue;\n }\n\n // 标题 - ### H3\n if (trimmedLine.startsWith('### ')) {\n listContainer = null;\n const h3 = document.createElement('h3');\n h3.textContent = trimmedLine.substring(4);\n container.appendChild(h3);\n continue;\n }\n\n // 图片 - \n const imageMatch = trimmedLine.match(/^!\\[(.*?)\\]\\((.*?)\\)$/);\n if (imageMatch) {\n listContainer = null;\n const img = document.createElement('img');\n img.alt = imageMatch[1];\n img.src = imageMatch[2];\n img.style.maxWidth = '80%';\n img.style.maxHeight = '500px';\n container.appendChild(img);\n continue;\n }\n\n // 列表项 - - 项目\n if (trimmedLine.startsWith('- ')) {\n if (!listContainer) {\n listContainer = document.createElement('ul');\n container.appendChild(listContainer);\n }\n const li = document.createElement('li');\n li.textContent = trimmedLine.substring(2);\n listContainer.appendChild(li);\n continue;\n }\n\n // 普通文本\n listContainer = null;\n const p = document.createElement('p');\n p.textContent = trimmedLine;\n container.appendChild(p);\n }\n\n return container;\n }\n\n /**\n * 映射 Slide DSL 过渡效果到 reveal.js 过渡效果\n *\n * @param transition - Slide DSL 过渡效果\n * @returns reveal.js 过渡效果\n */\n private mapTransition(transition?: 'slide' | 'zoom' | 'fade' | 'cube' | 'flip' | 'none'): string {\n if (!transition) {\n return 'slide';\n }\n\n // 映射特殊过渡效果\n const transitionMap: Record<string, string> = {\n cube: 'convex',\n flip: 'concave',\n };\n\n return transitionMap[transition] || transition;\n }\n\n /**\n * 触发事件\n *\n * @param event - 事件类型\n * @param data - 事件数据\n */\n private emit(event: AdapterEvent, data?: unknown): void {\n const handlers = this.eventHandlers.get(event);\n if (handlers) {\n for (const handler of handlers) {\n try {\n handler(data);\n } catch (error) {\n console.error(`Error in ${event} handler:`, error);\n }\n }\n }\n }\n}\n","/**\n * @slidejs/runner-revealjs - SlideRunner 工厂函数\n *\n * 提供创建配置好的 SlideRunner 实例的便捷方法\n */\n\nimport { parseSlideDSL, compile } from '@slidejs/dsl';\nimport { SlideRunner } from '@slidejs/runner';\nimport type { SlideContext } from '@slidejs/context';\nimport { RevealJsAdapter } from './adapter';\nimport type { RevealJsOptions } from './types';\n\n/**\n * SlideRunner 配置选项\n */\nexport interface SlideRunnerConfig {\n /**\n * 容器选择器或 HTMLElement\n */\n container: string | HTMLElement;\n\n /**\n * reveal.js 配置选项\n */\n revealOptions?: RevealJsOptions['revealConfig'];\n}\n\n/**\n * 从 DSL 源代码创建并运行 SlideRunner\n *\n * @example\n * ```typescript\n * import { createSlideRunner } from '@slidejs/runner-revealjs';\n *\n * const dslSource = `\n * present quiz \"demo\" {\n * rules {\n * rule start \"intro\" {\n * slide {\n * content text { \"Hello World!\" }\n * }\n * }\n * }\n * }\n * `;\n *\n * const context = { sourceType: 'quiz', sourceId: 'demo', items: [] };\n * const runner = await createSlideRunner(dslSource, context, {\n * container: '#app',\n * revealOptions: {\n * controls: true,\n * progress: true,\n * },\n * });\n * ```\n */\nexport async function createSlideRunner<TContext extends SlideContext = SlideContext>(\n dslSource: string,\n context: TContext,\n config: SlideRunnerConfig\n): Promise<SlideRunner<TContext>> {\n // 1. 解析 DSL\n const ast = await parseSlideDSL(dslSource);\n\n // 2. 编译为 SlideDSL\n const slideDSL = compile<TContext>(ast);\n\n // 3. 创建适配器和 Runner\n const adapter = new RevealJsAdapter();\n const runner = new SlideRunner<TContext>({\n container: config.container,\n adapter,\n adapterOptions: {\n revealConfig: config.revealOptions,\n },\n });\n\n // 4. 运行演示(这会初始化适配器并渲染幻灯片)\n await runner.run(slideDSL, context);\n\n // 注意:需要手动调用 runner.play() 来启动演示(导航到第一张幻灯片)\n // 返回 runner 以便用户可以控制演示\n return runner;\n}\n"],"names":["RevealJsAdapter","container","options","Reveal","error","errorMessage","slides","slide","section","index","targetSection","newSection","event","handler","handlers","viewportDiv","revealDiv","slidesDiv","revealEvent","_a","transition","content","component","props","element","key","value","lines","listContainer","line","trimmedLine","h1","h2","h3","imageMatch","img","li","p","data","createSlideRunner","dslSource","context","config","ast","parseSlideDSL","slideDSL","compile","adapter","runner","SlideRunner"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","sources":["../src/adapter.ts","../src/runner.ts"],"sourcesContent":["/**\n * @slidejs/runner-revealjs - RevealJsAdapter 适配器实现\n *\n * 将 Slide DSL 渲染为 reveal.js 演示文稿\n */\n\nimport Reveal from 'reveal.js';\n// CSS 现在通过 index.ts 中的 style.css 导入,不需要在这里重复导入\nimport type { SlideDefinition } from '@slidejs/core';\nimport type { SlideAdapter, AdapterEvent, EventHandler } from '@slidejs/runner';\nimport type { RevealJsOptions } from './types';\n\n/**\n * reveal.js 适配器\n *\n * 实现 SlideAdapter 接口,将 SlideDefinition 渲染为 reveal.js 幻灯片\n */\nexport class RevealJsAdapter implements SlideAdapter {\n readonly name = 'revealjs';\n\n private reveal?: Reveal.Api;\n private revealContainer?: HTMLElement;\n private slidesContainer?: HTMLElement;\n private eventHandlers: Map<AdapterEvent, Set<EventHandler>> = new Map();\n\n /**\n * 初始化 reveal.js 适配器\n *\n * @param container - 容器元素\n * @param options - reveal.js 选项\n */\n async initialize(container: HTMLElement, options?: RevealJsOptions): Promise<void> {\n try {\n // 创建 reveal.js DOM 结构\n this.createRevealStructure(container);\n\n // 初始化 reveal.js\n if (!this.revealContainer) {\n throw new Error('Reveal container not created');\n }\n\n this.reveal = new Reveal(this.revealContainer, {\n // 默认配置\n controls: true,\n progress: true,\n center: true,\n hash: false,\n transition: 'slide',\n ...options?.revealConfig,\n });\n\n await this.reveal.initialize();\n\n // 设置事件监听\n this.setupEventListeners();\n\n // 触发 ready 事件\n this.emit('ready');\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n this.emit('error', { message: errorMessage });\n throw new Error(`Failed to initialize RevealJsAdapter: ${errorMessage}`);\n }\n }\n\n /**\n * 渲染幻灯片\n *\n * @param slides - 幻灯片定义数组\n */\n async render(slides: SlideDefinition[]): Promise<void> {\n if (!this.slidesContainer || !this.reveal) {\n throw new Error('RevealJsAdapter not initialized');\n }\n\n try {\n // 清空现有幻灯片\n this.slidesContainer.innerHTML = '';\n\n // 渲染每张幻灯片\n for (const slide of slides) {\n const section = await this.renderSlide(slide);\n this.slidesContainer.appendChild(section);\n }\n\n // 同步 reveal.js\n this.reveal.sync();\n\n // 触发 slideRendered 事件\n this.emit('slideRendered', { totalSlides: slides.length });\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n this.emit('error', { message: errorMessage });\n throw new Error(`Failed to render slides: ${errorMessage}`);\n }\n }\n\n /**\n * 销毁适配器\n */\n async destroy(): Promise<void> {\n if (this.reveal) {\n this.reveal.destroy();\n this.reveal = undefined;\n }\n\n if (this.revealContainer) {\n this.revealContainer.innerHTML = '';\n this.revealContainer = undefined;\n }\n\n this.slidesContainer = undefined;\n this.eventHandlers.clear();\n }\n\n /**\n * 导航到指定幻灯片\n *\n * @param index - 幻灯片索引\n */\n navigateTo(index: number): void {\n if (!this.reveal) {\n throw new Error('RevealJsAdapter not initialized');\n }\n\n // reveal.js 的 slide 方法需要 (indexh, indexv) 两个参数\n // 对于单层幻灯片,indexv 为 0\n this.reveal.slide(index, 0);\n }\n\n /**\n * 获取当前幻灯片索引\n */\n getCurrentIndex(): number {\n if (!this.reveal) {\n return 0;\n }\n\n const indices = this.reveal.getIndices();\n return indices.h;\n }\n\n /**\n * 获取幻灯片总数\n */\n getTotalSlides(): number {\n if (!this.reveal) {\n return 0;\n }\n\n return this.reveal.getTotalSlides();\n }\n\n /**\n * 更新指定幻灯片\n *\n * @param index - 幻灯片索引\n * @param slide - 新的幻灯片定义\n */\n async updateSlide(index: number, slide: SlideDefinition): Promise<void> {\n if (!this.slidesContainer || !this.reveal) {\n throw new Error('RevealJsAdapter not initialized');\n }\n\n try {\n // 获取指定索引的 section 元素\n const sections = this.slidesContainer.querySelectorAll('section');\n const targetSection = sections[index];\n\n if (!targetSection) {\n throw new Error(`Slide at index ${index} not found`);\n }\n\n // 渲染新的幻灯片内容\n const newSection = await this.renderSlide(slide);\n\n // 替换旧的 section\n targetSection.replaceWith(newSection);\n\n // 同步 reveal.js\n this.reveal.sync();\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n this.emit('error', { message: errorMessage });\n throw new Error(`Failed to update slide: ${errorMessage}`);\n }\n }\n\n /**\n * 注册事件监听器\n *\n * @param event - 事件类型\n * @param handler - 事件处理器\n */\n on(event: AdapterEvent, handler: EventHandler): void {\n if (!this.eventHandlers.has(event)) {\n this.eventHandlers.set(event, new Set());\n }\n this.eventHandlers.get(event)!.add(handler);\n }\n\n /**\n * 移除事件监听器\n *\n * @param event - 事件类型\n * @param handler - 事件处理器\n */\n off(event: AdapterEvent, handler: EventHandler): void {\n const handlers = this.eventHandlers.get(event);\n if (handlers) {\n handlers.delete(handler);\n }\n }\n\n /**\n * 创建 reveal.js DOM 结构\n *\n * reveal.js 5.x 需要以下 DOM 结构:\n * <div class=\"reveal-viewport\">\n * <div class=\"reveal\">\n * <div class=\"slides\">\n * <section>...</section>\n * </div>\n * </div>\n * </div>\n *\n * @param container - 容器元素\n */\n private createRevealStructure(container: HTMLElement): void {\n // 创建 .reveal-viewport 包装器(reveal.js 5.x 要求)\n const viewportDiv = document.createElement('div');\n viewportDiv.className = 'reveal-viewport';\n\n // 创建 .reveal 容器\n const revealDiv = document.createElement('div');\n revealDiv.className = 'reveal';\n\n // 创建 .slides 容器\n const slidesDiv = document.createElement('div');\n slidesDiv.className = 'slides';\n\n revealDiv.appendChild(slidesDiv);\n viewportDiv.appendChild(revealDiv);\n container.appendChild(viewportDiv);\n\n this.revealContainer = revealDiv;\n this.slidesContainer = slidesDiv;\n }\n\n /**\n * 设置 reveal.js 事件监听\n */\n private setupEventListeners(): void {\n if (!this.reveal) {\n return;\n }\n\n // 监听幻灯片切换事件\n this.reveal.on('slidechanged', (event: unknown) => {\n const revealEvent = event as { indexh: number; previousSlide?: HTMLElement };\n this.emit('slideChanged', {\n index: revealEvent.indexh,\n previousIndex: revealEvent.previousSlide?.dataset.index,\n });\n });\n\n // 监听 ready 事件\n this.reveal.on('ready', () => {\n this.emit('ready');\n });\n }\n\n /**\n * 渲染单张幻灯片\n *\n * @param slide - 幻灯片定义\n * @returns section 元素\n */\n private async renderSlide(slide: SlideDefinition): Promise<HTMLElement> {\n const section = document.createElement('section');\n\n // 设置过渡效果\n if (slide.behavior?.transition) {\n const transition = this.mapTransition(slide.behavior.transition.type);\n section.setAttribute('data-transition', transition);\n }\n\n // 渲染内容\n if (slide.content.type === 'dynamic') {\n // 动态内容(Web Components)\n const content = this.renderDynamicContent(slide.content.component, slide.content.props);\n section.appendChild(content);\n } else {\n // 静态文本内容\n const content = this.renderTextContent(slide.content.lines);\n section.appendChild(content);\n }\n\n return section;\n }\n\n /**\n * 渲染动态内容(Web Components)\n *\n * @param component - 组件名称\n * @param props - 组件属性\n * @returns 组件元素\n */\n private renderDynamicContent(component: string, props: Record<string, unknown>): HTMLElement {\n const element = document.createElement(component);\n\n // 设置属性\n for (const [key, value] of Object.entries(props)) {\n if (typeof value === 'string' || typeof value === 'number') {\n element.setAttribute(key, String(value));\n } else if (typeof value === 'boolean') {\n if (value) {\n element.setAttribute(key, '');\n }\n } else {\n // 对于对象和数组,设置为属性而不是 attribute\n (element as unknown as Record<string, unknown>)[key] = value;\n }\n }\n\n return element;\n }\n\n /**\n * 渲染文本内容\n *\n * 支持以下格式:\n * - # 标题 -> h1\n * - ## 标题 -> h2\n * - ### 标题 -> h3\n * -  -> img\n * - - 列表项 -> ul/li\n * - 普通文本 -> p\n *\n * @param lines - 文本行数组\n * @returns 内容容器元素\n */\n private renderTextContent(lines: string[]): HTMLElement {\n const container = document.createElement('div');\n container.className = 'slide-content';\n\n let listContainer: HTMLUListElement | null = null;\n\n for (const line of lines) {\n const trimmedLine = line.trim();\n\n // 空行,结束列表\n if (!trimmedLine) {\n listContainer = null;\n continue;\n }\n\n // 标题 - # H1\n if (trimmedLine.startsWith('# ')) {\n listContainer = null;\n const h1 = document.createElement('h1');\n h1.textContent = trimmedLine.substring(2);\n container.appendChild(h1);\n continue;\n }\n\n // 标题 - ## H2\n if (trimmedLine.startsWith('## ')) {\n listContainer = null;\n const h2 = document.createElement('h2');\n h2.textContent = trimmedLine.substring(3);\n container.appendChild(h2);\n continue;\n }\n\n // 标题 - ### H3\n if (trimmedLine.startsWith('### ')) {\n listContainer = null;\n const h3 = document.createElement('h3');\n h3.textContent = trimmedLine.substring(4);\n container.appendChild(h3);\n continue;\n }\n\n // 图片 - \n const imageMatch = trimmedLine.match(/^!\\[(.*?)\\]\\((.*?)\\)$/);\n if (imageMatch) {\n listContainer = null;\n const img = document.createElement('img');\n img.alt = imageMatch[1];\n img.src = imageMatch[2];\n img.style.maxWidth = '80%';\n img.style.maxHeight = '500px';\n container.appendChild(img);\n continue;\n }\n\n // 列表项 - - 项目\n if (trimmedLine.startsWith('- ')) {\n if (!listContainer) {\n listContainer = document.createElement('ul');\n container.appendChild(listContainer);\n }\n const li = document.createElement('li');\n li.textContent = trimmedLine.substring(2);\n listContainer.appendChild(li);\n continue;\n }\n\n // 普通文本\n listContainer = null;\n const p = document.createElement('p');\n p.textContent = trimmedLine;\n container.appendChild(p);\n }\n\n return container;\n }\n\n /**\n * 映射 Slide DSL 过渡效果到 reveal.js 过渡效果\n *\n * @param transition - Slide DSL 过渡效果\n * @returns reveal.js 过渡效果\n */\n private mapTransition(transition?: 'slide' | 'zoom' | 'fade' | 'cube' | 'flip' | 'none'): string {\n if (!transition) {\n return 'slide';\n }\n\n // 映射特殊过渡效果\n const transitionMap: Record<string, string> = {\n cube: 'convex',\n flip: 'concave',\n };\n\n return transitionMap[transition] || transition;\n }\n\n /**\n * 触发事件\n *\n * @param event - 事件类型\n * @param data - 事件数据\n */\n private emit(event: AdapterEvent, data?: unknown): void {\n const handlers = this.eventHandlers.get(event);\n if (handlers) {\n for (const handler of handlers) {\n try {\n handler(data);\n } catch (error) {\n console.error(`Error in ${event} handler:`, error);\n }\n }\n }\n }\n}\n","/**\n * @slidejs/runner-revealjs - SlideRunner 工厂函数\n *\n * 提供创建配置好的 SlideRunner 实例的便捷方法\n */\n\nimport { parseSlideDSL, compile } from '@slidejs/dsl';\nimport { SlideRunner } from '@slidejs/runner';\nimport type { SlideContext } from '@slidejs/context';\nimport { RevealJsAdapter } from './adapter';\nimport type { RevealJsOptions } from './types';\n// 导入 CSS 内容用于注入\nimport revealCSS from 'reveal.js/dist/reveal.css?inline';\nimport customCSS from './style.css?inline';\n\n/**\n * SlideRunner 配置选项\n */\nexport interface SlideRunnerConfig {\n /**\n * 容器选择器或 HTMLElement\n */\n container: string | HTMLElement;\n\n /**\n * reveal.js 配置选项\n */\n revealOptions?: RevealJsOptions['revealConfig'];\n}\n\n/**\n * 从 DSL 源代码创建并运行 SlideRunner\n *\n * @example\n * ```typescript\n * import { createSlideRunner } from '@slidejs/runner-revealjs';\n *\n * const dslSource = `\n * present quiz \"demo\" {\n * rules {\n * rule start \"intro\" {\n * slide {\n * content text { \"Hello World!\" }\n * }\n * }\n * }\n * }\n * `;\n *\n * const context = { sourceType: 'quiz', sourceId: 'demo', items: [] };\n * const runner = await createSlideRunner(dslSource, context, {\n * container: '#app',\n * revealOptions: {\n * controls: true,\n * progress: true,\n * },\n * });\n * ```\n */\nexport async function createSlideRunner<TContext extends SlideContext = SlideContext>(\n dslSource: string,\n context: TContext,\n config: SlideRunnerConfig\n): Promise<SlideRunner<TContext>> {\n // 1. 解析 DSL\n const ast = await parseSlideDSL(dslSource);\n\n // 2. 编译为 SlideDSL\n const slideDSL = compile<TContext>(ast);\n\n // 2.1 注入 Reveal.js CSS 到 document.head(全局,如果尚未注入)\n const globalStyleId = 'reveal-styles';\n const globalStyles = document.head.querySelector(`#${globalStyleId}`);\n if (!globalStyles) {\n const style = document.createElement('style');\n style.id = globalStyleId;\n style.textContent = revealCSS;\n document.head.appendChild(style);\n }\n\n // 2.2 获取用户提供的容器元素\n let userContainer: HTMLElement;\n if (typeof config.container === 'string') {\n const element = document.querySelector(config.container);\n if (!element) {\n throw new Error(`Container not found: ${config.container}`);\n }\n userContainer = element as HTMLElement;\n } else {\n userContainer = config.container;\n }\n\n // 2.3 注入自定义 CSS 样式到容器\n const styleId = 'slidejs-runner-revealjs-styles';\n if (!userContainer.querySelector(`#${styleId}`)) {\n const style = document.createElement('style');\n style.id = styleId;\n style.textContent = customCSS;\n userContainer.appendChild(style);\n }\n\n // 2.4 创建一个新的 div 节点用于 Reveal.js(Reveal.js 会接管这个 div)\n const revealContainer = document.createElement('div');\n // 确保容器占满父元素的高度和宽度\n revealContainer.style.width = '100%';\n revealContainer.style.height = '100%';\n userContainer.appendChild(revealContainer);\n\n // 3. 创建适配器和 Runner(将 revealContainer 传给 Runner,而不是 userContainer)\n const adapter = new RevealJsAdapter();\n const runner = new SlideRunner<TContext>({\n container: revealContainer,\n adapter,\n adapterOptions: {\n revealConfig: config.revealOptions,\n },\n });\n\n // 4. 运行演示(这会初始化适配器并渲染幻灯片)\n await runner.run(slideDSL, context);\n\n // 注意:需要手动调用 runner.play() 来启动演示(导航到第一张幻灯片)\n // 返回 runner 以便用户可以控制演示\n return runner;\n}\n"],"names":["RevealJsAdapter","container","options","Reveal","error","errorMessage","slides","slide","section","index","targetSection","newSection","event","handler","handlers","viewportDiv","revealDiv","slidesDiv","revealEvent","transition","content","component","props","element","key","value","lines","listContainer","line","trimmedLine","h1","h2","h3","imageMatch","img","li","p","data","createSlideRunner","dslSource","context","config","ast","parseSlideDSL","slideDSL","compile","globalStyleId","style","revealCSS","userContainer","styleId","customCSS","revealContainer","adapter","runner","SlideRunner"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@slidejs/runner-revealjs",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.cjs",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -15,17 +15,18 @@
|
|
|
15
15
|
},
|
|
16
16
|
"dependencies": {
|
|
17
17
|
"reveal.js": "^5.0.0",
|
|
18
|
-
"@slidejs/
|
|
19
|
-
"@slidejs/
|
|
20
|
-
"@slidejs/
|
|
21
|
-
"@slidejs/
|
|
18
|
+
"@slidejs/core": "0.1.4",
|
|
19
|
+
"@slidejs/dsl": "0.1.4",
|
|
20
|
+
"@slidejs/runner": "0.1.4",
|
|
21
|
+
"@slidejs/context": "0.1.4"
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
24
24
|
"@types/node": "^20.10.0",
|
|
25
25
|
"@types/reveal.js": "^5.0.0",
|
|
26
|
+
"jsdom": "^24.0.0",
|
|
26
27
|
"typescript": "^5.3.3",
|
|
27
|
-
"vite": "^
|
|
28
|
-
"vite-plugin-dts": "^
|
|
28
|
+
"vite": "^7.3.1",
|
|
29
|
+
"vite-plugin-dts": "^4.5.4",
|
|
29
30
|
"vitest": "^1.0.0"
|
|
30
31
|
},
|
|
31
32
|
"publishConfig": {
|
|
@@ -33,6 +34,9 @@
|
|
|
33
34
|
},
|
|
34
35
|
"scripts": {
|
|
35
36
|
"build": "vite build",
|
|
36
|
-
"dev": "vite build --watch"
|
|
37
|
+
"dev": "vite build --watch",
|
|
38
|
+
"test": "vitest run",
|
|
39
|
+
"test:watch": "vitest",
|
|
40
|
+
"typecheck": "tsc --noEmit"
|
|
37
41
|
}
|
|
38
42
|
}
|