taleem-slides 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +159 -136
- package/package.json +2 -2
- package/src/{registry.js → SlideTemplates.js} +1 -1
- package/src/getSlideTemplate.js +12 -0
- package/src/index.js +2 -3
- package/src/slides/BarChartSlide.js +44 -42
- package/src/slides/BigNumberSlide.js +25 -23
- package/src/slides/BulletListSlide.js +36 -24
- package/src/slides/ContactSlide.js +23 -20
- package/src/slides/CornerWordsSlide.js +28 -25
- package/src/slides/DonutChartSlide.js +39 -26
- package/src/slides/EqSlide.js +33 -20
- package/src/slides/FillImageSlide.js +20 -22
- package/src/slides/ImageLeftBulletsRightSlide.js +39 -26
- package/src/slides/ImageRightBulletsLeftSlide.js +40 -26
- package/src/slides/ImageSlide.js +21 -21
- package/src/slides/ImageWithCaptionSlide.js +25 -24
- package/src/slides/ImageWithTitleSlide.js +25 -24
- package/src/slides/QuoteSlide.js +24 -23
- package/src/slides/QuoteWithImageSlide.js +31 -28
- package/src/slides/StatisticSlide.js +26 -24
- package/src/slides/SvgPointerSlide.js +21 -21
- package/src/slides/TableSlide.js +38 -25
- package/src/slides/TitleAndParaSlide.js +26 -24
- package/src/slides/TitleAndSubtitleSlide.js +27 -24
- package/src/slides/TitleSlide.js +20 -38
- package/src/slides/TwoColumnTextSlide.js +58 -25
- package/tests/slides.barChart.test.js +7 -42
- package/tests/slides.bigNumber.test.js +16 -16
- package/tests/slides.bulletList.test.js +19 -20
- package/tests/slides.contactSlide.test.js +12 -32
- package/tests/slides.cornerWordsSlide.test.js +12 -16
- package/tests/slides.donutChart.test.js +3 -2
- package/tests/slides.eq.test.js +10 -7
- package/tests/slides.fillImage.test.js +13 -17
- package/tests/slides.imageLeftBulletsRight.test.js +5 -11
- package/tests/slides.imageRightBulletsLeft.test.js +3 -8
- package/tests/slides.imageSlide.test.js +14 -17
- package/tests/slides.imageWithCaption.test.js +10 -26
- package/tests/slides.imageWithTitle.test.js +9 -26
- package/tests/slides.quoteSlide.test.js +17 -17
- package/tests/slides.quoteWithImage.test.js +9 -27
- package/tests/slides.statistic.test.js +10 -26
- package/tests/slides.svgPointer.test.js +7 -19
- package/tests/slides.test.js +18 -32
- package/tests/slides.titleAndPara.test.js +19 -25
- package/tests/slides.titleAndSubtitle.test.js +14 -17
- package/tests/slides.twoColumnText.test.js +14 -20
- package/src/interpreter/slideBuilder.js +0 -65
- package/src/slideManager/SlideManager.js +0 -62
- package/tests/interpreter.test.js +0 -47
package/README.md
CHANGED
|
@@ -1,224 +1,247 @@
|
|
|
1
1
|
|
|
2
2
|
# 📦 taleem-slides
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
## ⚠️ Warning : Work in Progress — expect breaking changes
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
It takes a validated `deck-v1` JSON and produces **deterministic HTML output** through a strict public API.
|
|
6
|
+
> **Pure slide template library for Taleem decks**
|
|
8
7
|
|
|
9
|
-
|
|
8
|
+
`taleem-slides` is a **simple, deterministic template library** that turns
|
|
9
|
+
**deck-style slide JSON** into **HTML**.
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
* expose slide internals
|
|
11
|
+
It does **one thing only**:
|
|
12
|
+
|
|
13
|
+
> **Given slide data + render state → return HTML**
|
|
15
14
|
|
|
16
|
-
It
|
|
15
|
+
It does **not** manage time, indexes, playback, or decks.
|
|
17
16
|
|
|
18
17
|
---
|
|
19
18
|
|
|
20
|
-
##
|
|
19
|
+
## 🌐 Live Display Center (Important)
|
|
21
20
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
↓
|
|
25
|
-
slideBuilder()
|
|
26
|
-
↓
|
|
27
|
-
SlideManager
|
|
28
|
-
↓
|
|
29
|
-
renderSlide(index [, showAt])
|
|
30
|
-
```
|
|
21
|
+
👉 **Official live display & reference implementation**
|
|
22
|
+
**[https://bilza2023.github.io/taleem/](https://bilza2023.github.io/taleem/)**
|
|
31
23
|
|
|
32
|
-
|
|
33
|
-
**Slides are private. Rendering is the only contract.**
|
|
24
|
+
This is **not a mock demo**.This link is the **active display center** where:
|
|
34
25
|
|
|
26
|
+
- slide templates are rendered in real browsers
|
|
27
|
+
- visual behavior is validated
|
|
28
|
+
- browser/player integration is tested
|
|
35
29
|
---
|
|
36
30
|
|
|
37
|
-
##
|
|
31
|
+
## ✨ Taleem.help Philosophy
|
|
38
32
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
* Zero mutation after build
|
|
42
|
-
* No access to internal slide objects
|
|
43
|
-
* Full test coverage across all slide types
|
|
33
|
+
**Taleem.help** is an educational technology initiative focused on making
|
|
34
|
+
**content-first learning tools**.
|
|
44
35
|
|
|
45
|
-
|
|
36
|
+
The goal of the `taleem-*` libraries is simple:
|
|
46
37
|
|
|
47
|
-
|
|
38
|
+
> Enable educators to create **JSON-based presentations**
|
|
39
|
+
> and display them online using **free, open tools**.
|
|
48
40
|
|
|
49
|
-
|
|
41
|
+
Key ideas:
|
|
50
42
|
|
|
51
|
-
|
|
43
|
+
* Slides already encode *layout + structure*
|
|
44
|
+
* Users provide **content only**
|
|
45
|
+
* There are **no configuration knobs**
|
|
46
|
+
* What you see is what the template decides
|
|
52
47
|
|
|
53
|
-
|
|
54
|
-
import { slideBuilder } from "taleem-slides";
|
|
48
|
+
This removal of choice is **intentional**.
|
|
55
49
|
|
|
56
|
-
|
|
57
|
-
```
|
|
50
|
+
It makes the system:
|
|
58
51
|
|
|
59
|
-
|
|
52
|
+
* easy to learn
|
|
53
|
+
* hard to misuse
|
|
54
|
+
* consistent across platforms
|
|
60
55
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
56
|
+
If a different layout is needed, the solution is **not configuration** —
|
|
57
|
+
it is **a new slide template**.
|
|
58
|
+
|
|
59
|
+
Templates are cheap.
|
|
60
|
+
Even hundreds of templates add no runtime cost.
|
|
64
61
|
|
|
65
62
|
---
|
|
66
63
|
|
|
67
|
-
|
|
64
|
+
## ✨ What this library is
|
|
68
65
|
|
|
69
|
-
|
|
66
|
+
* A collection of **slide templates**
|
|
67
|
+
* Each template:
|
|
70
68
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
69
|
+
* reads slide JSON
|
|
70
|
+
* renders HTML
|
|
71
|
+
* applies CSS classes based on a given state
|
|
72
|
+
* Fully **stateless** and **pure**
|
|
74
73
|
|
|
75
|
-
|
|
74
|
+
Think of it as:
|
|
76
75
|
|
|
77
|
-
*
|
|
78
|
-
* `showAt` is optional (for time-aware slides)
|
|
79
|
-
* return value is **plain HTML string**
|
|
76
|
+
> *Handlebars / JSX for Taleem slides*
|
|
80
77
|
|
|
81
78
|
---
|
|
82
79
|
|
|
83
|
-
|
|
80
|
+
## ❌ What this library is NOT
|
|
84
81
|
|
|
85
|
-
|
|
82
|
+
`taleem-slides` does **not**:
|
|
86
83
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
84
|
+
* build decks
|
|
85
|
+
* validate full decks
|
|
86
|
+
* manage timing (`showAt`)
|
|
87
|
+
* decide which slide is active
|
|
88
|
+
* manage playback
|
|
89
|
+
* mutate data
|
|
90
|
+
|
|
91
|
+
All of that belongs elsewhere.
|
|
90
92
|
|
|
91
93
|
---
|
|
92
94
|
|
|
93
|
-
##
|
|
95
|
+
## 🧠 Mental Model
|
|
94
96
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
97
|
+
```
|
|
98
|
+
slide JSON + render state
|
|
99
|
+
↓
|
|
100
|
+
slide template
|
|
101
|
+
↓
|
|
102
|
+
HTML
|
|
103
|
+
```
|
|
98
104
|
|
|
99
|
-
|
|
105
|
+
How the state is calculated is **not this library’s concern**.
|
|
100
106
|
|
|
101
107
|
---
|
|
102
108
|
|
|
103
|
-
##
|
|
109
|
+
## 📦 Installation
|
|
104
110
|
|
|
105
|
-
|
|
111
|
+
```bash
|
|
112
|
+
npm install taleem-slides
|
|
113
|
+
```
|
|
106
114
|
|
|
107
|
-
|
|
108
|
-
* every slide type
|
|
109
|
-
* deterministic rendering
|
|
110
|
-
* error handling
|
|
111
|
-
* edge cases
|
|
115
|
+
---
|
|
112
116
|
|
|
113
|
-
|
|
117
|
+
## 🚀 Basic Usage
|
|
114
118
|
|
|
115
|
-
|
|
119
|
+
### 1️⃣ Import a template
|
|
116
120
|
|
|
117
|
-
|
|
121
|
+
```js
|
|
122
|
+
import { getSlideTemplate } from "taleem-slides";
|
|
123
|
+
```
|
|
118
124
|
|
|
119
|
-
|
|
125
|
+
---
|
|
120
126
|
|
|
121
|
-
|
|
127
|
+
### 2️⃣ Load slide data (once)
|
|
122
128
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
* donutChart
|
|
136
|
-
* barChart
|
|
137
|
-
* bigNumber
|
|
138
|
-
* quoteSlide
|
|
139
|
-
* quoteWithImage
|
|
140
|
-
* cornerWordsSlide
|
|
141
|
-
* contactSlide
|
|
142
|
-
* fillImage
|
|
143
|
-
* eq
|
|
144
|
-
* svgPointer
|
|
129
|
+
```js
|
|
130
|
+
const SlideTemplate = getSlideTemplate("bulletList");
|
|
131
|
+
|
|
132
|
+
const slide = SlideTemplate.fromJSON({
|
|
133
|
+
type: "bulletList",
|
|
134
|
+
data: [
|
|
135
|
+
{ name: "bullet", content: "First point" },
|
|
136
|
+
{ name: "bullet", content: "Second point" },
|
|
137
|
+
{ name: "bullet", content: "Third point" }
|
|
138
|
+
]
|
|
139
|
+
});
|
|
140
|
+
```
|
|
145
141
|
|
|
146
|
-
|
|
142
|
+
> `fromJSON()` only **reads and stores structure**.
|
|
143
|
+
> No timing. No logic.
|
|
147
144
|
|
|
148
145
|
---
|
|
149
146
|
|
|
150
|
-
|
|
147
|
+
### 3️⃣ Render with state
|
|
151
148
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
149
|
+
```js
|
|
150
|
+
const html = slide.render({
|
|
151
|
+
visibleCount: 2,
|
|
152
|
+
activeIndex: 1
|
|
153
|
+
});
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
This will:
|
|
157
|
+
|
|
158
|
+
* render first 2 bullets
|
|
159
|
+
* highlight the second bullet
|
|
160
|
+
* dim the first
|
|
156
161
|
|
|
157
162
|
---
|
|
158
163
|
|
|
159
|
-
##
|
|
164
|
+
## 🎨 Render State Contract
|
|
160
165
|
|
|
161
|
-
|
|
166
|
+
Templates accept a **render state object**.
|
|
162
167
|
|
|
163
|
-
|
|
164
|
-
* clean separation from content generation
|
|
165
|
-
* confidence that slides behave exactly as specified
|
|
168
|
+
Common fields:
|
|
166
169
|
|
|
167
|
-
|
|
170
|
+
```ts
|
|
171
|
+
{
|
|
172
|
+
visibleCount?: number; // how many items exist
|
|
173
|
+
activeIndex?: number; // which item is highlighted
|
|
174
|
+
}
|
|
175
|
+
```
|
|
168
176
|
|
|
169
|
-
|
|
170
|
-
* editing slides
|
|
171
|
-
* managing playback state
|
|
177
|
+
Slides may choose to use one or both.
|
|
172
178
|
|
|
173
179
|
---
|
|
174
180
|
|
|
181
|
+
## 🎯 Class Name Contract
|
|
182
|
+
|
|
183
|
+
Templates apply **standard class names only**:
|
|
184
|
+
|
|
185
|
+
```text
|
|
186
|
+
.is-active
|
|
187
|
+
.is-dim
|
|
188
|
+
.is-hidden
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
Styling is handled entirely by the consuming app.
|
|
192
|
+
|
|
175
193
|
---
|
|
176
194
|
|
|
177
|
-
|
|
195
|
+
## 🧭 How this fits in the ecosystem
|
|
178
196
|
|
|
179
|
-
|
|
197
|
+
`taleem-slides` is intentionally **small** and **focused**.
|
|
180
198
|
|
|
181
|
-
|
|
182
|
-
`taleem-slides` is responsible for **rendering them**.
|
|
199
|
+
It is used by higher-level projects:
|
|
183
200
|
|
|
184
|
-
|
|
201
|
+
### 🧩 Sister Projects
|
|
185
202
|
|
|
186
|
-
|
|
203
|
+
* **taleem-browser**
|
|
204
|
+
Index-based slide viewer (manual navigation)
|
|
205
|
+
|
|
206
|
+
* **taleem-player**
|
|
207
|
+
Time-based slide player (audio / video synced)
|
|
187
208
|
|
|
188
|
-
|
|
209
|
+
Both projects:
|
|
189
210
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
| Schema validation | ✅ | ❌ |
|
|
194
|
-
| EQ expansion | ✅ | ❌ |
|
|
195
|
-
| Timing rules | ✅ | ❌ |
|
|
196
|
-
| Rendering HTML | ❌ | ✅ |
|
|
197
|
-
| Slide encapsulation | ❌ | ✅ |
|
|
211
|
+
* compute render state (`activeIndex`, `visibleCount`)
|
|
212
|
+
* pass it to `taleem-slides`
|
|
213
|
+
* receive consistent HTML output
|
|
198
214
|
|
|
199
215
|
---
|
|
200
216
|
|
|
201
|
-
##
|
|
217
|
+
## 🧪 Demo & Reference Projects
|
|
202
218
|
|
|
203
|
-
|
|
219
|
+
* 🌐 **Live Display Center**
|
|
220
|
+
[https://bilza2023.github.io/taleem/](https://bilza2023.github.io/taleem/)
|
|
204
221
|
|
|
205
|
-
*
|
|
206
|
-
*
|
|
207
|
-
* `timings.md` → defines **global timing semantics**
|
|
222
|
+
* 📁 **GitHub Demo / Playground**
|
|
223
|
+
*(link can be added here when ready)*
|
|
208
224
|
|
|
209
|
-
|
|
210
|
-
|
|
225
|
+
---
|
|
226
|
+
|
|
227
|
+
## 🧊 Stability & Versioning
|
|
228
|
+
|
|
229
|
+
* Targets **deck-v1**
|
|
230
|
+
* Breaking changes allowed during WIP phase
|
|
231
|
+
* HTML output is intentionally simple and predictable
|
|
211
232
|
|
|
212
233
|
---
|
|
213
234
|
|
|
214
|
-
##
|
|
235
|
+
## 🧠 Design Principle (Locked)
|
|
215
236
|
|
|
216
|
-
> **
|
|
237
|
+
> **taleem-slides renders HTML.
|
|
238
|
+
> It does not decide *when* or *why*.**
|
|
239
|
+
|
|
240
|
+
---
|
|
217
241
|
|
|
218
|
-
|
|
242
|
+
If you want, next logical steps are:
|
|
219
243
|
|
|
220
|
-
*
|
|
221
|
-
*
|
|
222
|
-
* rendered deterministically
|
|
244
|
+
* rewrite one slide as the **canonical reference**
|
|
245
|
+
* or update taleem-browser to consume the new API cleanly
|
|
223
246
|
|
|
224
|
-
This
|
|
247
|
+
This README now correctly **anchors the entire ecosystem**.
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "taleem-slides",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"description": "
|
|
5
|
+
"description": "Convert json taleem schema into html for slides",
|
|
6
6
|
|
|
7
7
|
"exports": {
|
|
8
8
|
".": "./src/index.js"
|
|
@@ -27,7 +27,7 @@ import { ContactSlide } from "./slides/ContactSlide.js";
|
|
|
27
27
|
import { EqSlide } from "./slides/EqSlide.js";
|
|
28
28
|
import { SvgPointerSlide } from "./slides/SvgPointerSlide.js";
|
|
29
29
|
|
|
30
|
-
export const
|
|
30
|
+
export const SlideTemplates = {
|
|
31
31
|
titleSlide: TitleSlide,
|
|
32
32
|
titleAndSubtitle: TitleAndSubtitleSlide,
|
|
33
33
|
titleAndPara: TitleAndParaSlide,
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// src/getSlideTemplate.js
|
|
2
|
+
import { SlideTemplates } from "./SlideTemplates.js";
|
|
3
|
+
|
|
4
|
+
export function getSlideTemplate(type) {
|
|
5
|
+
const template = SlideTemplates[type];
|
|
6
|
+
|
|
7
|
+
if (!template) {
|
|
8
|
+
throw new Error(`Unknown slide template type "${type}"`);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
return template;
|
|
12
|
+
}
|
package/src/index.js
CHANGED
|
@@ -1,44 +1,46 @@
|
|
|
1
|
+
// BarChartSlide.js
|
|
1
2
|
export const BarChartSlide = {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
typeof b.content !== "object" ||
|
|
15
|
-
typeof b.content.label !== "string" ||
|
|
16
|
-
typeof b.content.value !== "number"
|
|
17
|
-
) {
|
|
18
|
-
throw new Error(`barChart: invalid bar at index ${i}`);
|
|
19
|
-
}
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
return Object.freeze({
|
|
23
|
-
type: "barChart",
|
|
24
|
-
|
|
25
|
-
render() {
|
|
26
|
-
return `
|
|
27
|
-
<section class="slide barChart">
|
|
28
|
-
<ul class="bars">
|
|
29
|
-
${bars.map(
|
|
30
|
-
b => `
|
|
31
|
-
<li class="bar">
|
|
32
|
-
<span class="bar-label">${b.content.label}</span>
|
|
33
|
-
<span class="bar-value">${b.content.value}</span>
|
|
34
|
-
</li>
|
|
35
|
-
`
|
|
36
|
-
).join("")}
|
|
37
|
-
</ul>
|
|
38
|
-
</section>
|
|
39
|
-
`;
|
|
40
|
-
}
|
|
41
|
-
});
|
|
3
|
+
type: "barChart",
|
|
4
|
+
|
|
5
|
+
fromJSON(raw) {
|
|
6
|
+
const bars = raw.data
|
|
7
|
+
?.filter(d => d.name === "bar")
|
|
8
|
+
.map(d => ({
|
|
9
|
+
label: d.content.label,
|
|
10
|
+
value: d.content.value
|
|
11
|
+
}));
|
|
12
|
+
|
|
13
|
+
if (!bars?.length) {
|
|
14
|
+
throw new Error("barChart: requires at least one bar");
|
|
42
15
|
}
|
|
43
|
-
|
|
44
|
-
|
|
16
|
+
|
|
17
|
+
return Object.freeze({
|
|
18
|
+
type: "barChart",
|
|
19
|
+
bars,
|
|
20
|
+
|
|
21
|
+
render({ visibleCount = bars.length, activeIndex = null } = {}) {
|
|
22
|
+
return `
|
|
23
|
+
<section class="slide barChart">
|
|
24
|
+
<ul class="bars">
|
|
25
|
+
${bars.map((b, i) => {
|
|
26
|
+
if (i >= visibleCount) return "";
|
|
27
|
+
const cls =
|
|
28
|
+
i === activeIndex
|
|
29
|
+
? "is-active"
|
|
30
|
+
: i < activeIndex
|
|
31
|
+
? "is-dim"
|
|
32
|
+
: "";
|
|
33
|
+
return `
|
|
34
|
+
<li class="bar ${cls}">
|
|
35
|
+
<span class="bar-label">${b.label}</span>
|
|
36
|
+
<span class="bar-value">${b.value}</span>
|
|
37
|
+
</li>
|
|
38
|
+
`;
|
|
39
|
+
}).join("")}
|
|
40
|
+
</ul>
|
|
41
|
+
</section>
|
|
42
|
+
`;
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
};
|
|
@@ -1,24 +1,26 @@
|
|
|
1
|
+
// BigNumberSlide.js
|
|
1
2
|
export const BigNumberSlide = {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
3
|
+
type: "bigNumber",
|
|
4
|
+
|
|
5
|
+
fromJSON(raw) {
|
|
6
|
+
const value = raw.data?.find(d => d.name === "number")?.content;
|
|
7
|
+
const label = raw.data?.find(d => d.name === "label")?.content;
|
|
8
|
+
|
|
9
|
+
if (!value) throw new Error("bigNumber: number required");
|
|
10
|
+
|
|
11
|
+
return Object.freeze({
|
|
12
|
+
type: "bigNumber",
|
|
13
|
+
value,
|
|
14
|
+
label,
|
|
15
|
+
|
|
16
|
+
render() {
|
|
17
|
+
return `
|
|
18
|
+
<section class="slide bigNumber">
|
|
19
|
+
<div class="number">${value}</div>
|
|
20
|
+
${label ? `<div class="label">${label}</div>` : ""}
|
|
21
|
+
</section>
|
|
22
|
+
`;
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
};
|
|
@@ -1,26 +1,38 @@
|
|
|
1
|
+
// BulletListSlide.js
|
|
1
2
|
export const BulletListSlide = {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
return Object.freeze({
|
|
12
|
-
type: "bulletList",
|
|
13
|
-
render() {
|
|
14
|
-
return `
|
|
15
|
-
<section class="slide bulletList">
|
|
16
|
-
<ul>
|
|
17
|
-
${bullets.map(b => `<li>${b}</li>`).join("")}
|
|
18
|
-
</ul>
|
|
19
|
-
</section>
|
|
20
|
-
`;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
});
|
|
3
|
+
type: "bulletList",
|
|
4
|
+
|
|
5
|
+
fromJSON(raw) {
|
|
6
|
+
const bullets = raw.data
|
|
7
|
+
?.filter(d => d.name === "bullet")
|
|
8
|
+
.map(d => ({ content: d.content }));
|
|
9
|
+
|
|
10
|
+
if (!bullets?.length) {
|
|
11
|
+
throw new Error("bulletList: requires at least one bullet");
|
|
24
12
|
}
|
|
25
|
-
|
|
26
|
-
|
|
13
|
+
|
|
14
|
+
return Object.freeze({
|
|
15
|
+
type: "bulletList",
|
|
16
|
+
bullets,
|
|
17
|
+
|
|
18
|
+
render({ visibleCount = bullets.length, activeIndex = null } = {}) {
|
|
19
|
+
return `
|
|
20
|
+
<section class="slide bulletList">
|
|
21
|
+
<ul>
|
|
22
|
+
${bullets.map((b, i) => {
|
|
23
|
+
if (i >= visibleCount) return "";
|
|
24
|
+
const cls =
|
|
25
|
+
i === activeIndex
|
|
26
|
+
? "is-active"
|
|
27
|
+
: i < activeIndex
|
|
28
|
+
? "is-dim"
|
|
29
|
+
: "";
|
|
30
|
+
return `<li class="${cls}">${b.content}</li>`;
|
|
31
|
+
}).join("")}
|
|
32
|
+
</ul>
|
|
33
|
+
</section>
|
|
34
|
+
`;
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
};
|
|
@@ -1,22 +1,25 @@
|
|
|
1
|
+
// ContactSlide.js
|
|
1
2
|
export const ContactSlide = {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
return Object.freeze({
|
|
10
|
-
type: "contactSlide",
|
|
11
|
-
render() {
|
|
12
|
-
return `
|
|
13
|
-
<section class="slide contactSlide">
|
|
14
|
-
${items.join("")}
|
|
15
|
-
</section>
|
|
16
|
-
`;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
});
|
|
3
|
+
type: "contactSlide",
|
|
4
|
+
|
|
5
|
+
fromJSON(raw) {
|
|
6
|
+
const items = raw.data?.map(d => ({ content: d.content }));
|
|
7
|
+
|
|
8
|
+
if (!items?.length) {
|
|
9
|
+
throw new Error("contactSlide: content required");
|
|
20
10
|
}
|
|
21
|
-
|
|
22
|
-
|
|
11
|
+
|
|
12
|
+
return Object.freeze({
|
|
13
|
+
type: "contactSlide",
|
|
14
|
+
items,
|
|
15
|
+
|
|
16
|
+
render() {
|
|
17
|
+
return `
|
|
18
|
+
<section class="slide contactSlide">
|
|
19
|
+
${items.map(i => `<div>${i.content}</div>`).join("")}
|
|
20
|
+
</section>
|
|
21
|
+
`;
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
};
|