taleem-slides 0.3.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/README.md +266 -127
  2. package/package.json +2 -2
  3. package/src/{registry.js → SlideTemplates.js} +1 -1
  4. package/src/getSlideTemplate.js +12 -0
  5. package/src/index.js +3 -3
  6. package/src/resolveBackground.js +10 -0
  7. package/src/slides/BarChartSlide.js +44 -42
  8. package/src/slides/BigNumberSlide.js +25 -23
  9. package/src/slides/BulletListSlide.js +36 -24
  10. package/src/slides/ContactSlide.js +23 -20
  11. package/src/slides/CornerWordsSlide.js +28 -25
  12. package/src/slides/DonutChartSlide.js +39 -26
  13. package/src/slides/EqSlide.js +33 -20
  14. package/src/slides/FillImageSlide.js +20 -22
  15. package/src/slides/ImageLeftBulletsRightSlide.js +39 -26
  16. package/src/slides/ImageRightBulletsLeftSlide.js +40 -26
  17. package/src/slides/ImageSlide.js +21 -21
  18. package/src/slides/ImageWithCaptionSlide.js +25 -24
  19. package/src/slides/ImageWithTitleSlide.js +25 -24
  20. package/src/slides/QuoteSlide.js +24 -23
  21. package/src/slides/QuoteWithImageSlide.js +31 -28
  22. package/src/slides/StatisticSlide.js +26 -24
  23. package/src/slides/SvgPointerSlide.js +21 -21
  24. package/src/slides/TableSlide.js +38 -25
  25. package/src/slides/TitleAndParaSlide.js +26 -24
  26. package/src/slides/TitleAndSubtitleSlide.js +27 -24
  27. package/src/slides/TitleSlide.js +20 -38
  28. package/src/slides/TwoColumnTextSlide.js +58 -25
  29. package/tests/slides.barChart.test.js +7 -42
  30. package/tests/slides.bigNumber.test.js +16 -16
  31. package/tests/slides.bulletList.test.js +19 -20
  32. package/tests/slides.contactSlide.test.js +12 -32
  33. package/tests/slides.cornerWordsSlide.test.js +12 -16
  34. package/tests/slides.donutChart.test.js +3 -2
  35. package/tests/slides.eq.test.js +10 -7
  36. package/tests/slides.fillImage.test.js +13 -17
  37. package/tests/slides.imageLeftBulletsRight.test.js +5 -11
  38. package/tests/slides.imageRightBulletsLeft.test.js +3 -8
  39. package/tests/slides.imageSlide.test.js +14 -17
  40. package/tests/slides.imageWithCaption.test.js +10 -26
  41. package/tests/slides.imageWithTitle.test.js +9 -26
  42. package/tests/slides.quoteSlide.test.js +17 -17
  43. package/tests/slides.quoteWithImage.test.js +9 -27
  44. package/tests/slides.statistic.test.js +10 -26
  45. package/tests/slides.svgPointer.test.js +7 -19
  46. package/tests/slides.test.js +18 -32
  47. package/tests/slides.titleAndPara.test.js +19 -25
  48. package/tests/slides.titleAndSubtitle.test.js +14 -17
  49. package/tests/slides.twoColumnText.test.js +14 -20
  50. package/src/interpreter/slideBuilder.js +0 -65
  51. package/src/slideManager/SlideManager.js +0 -62
  52. package/tests/interpreter.test.js +0 -47
package/README.md CHANGED
@@ -1,224 +1,363 @@
1
1
 
2
+
2
3
  # 📦 taleem-slides
3
4
 
4
- > **Deterministic slide interpretation & rendering engine for deck-v1**
5
+ ## ⚠️ Warning: Work in Progress expect breaking changes
6
+
7
+ > **Pure slide template library for Taleem decks**
8
+
9
+ `taleem-slides` is a **simple, deterministic template library** that turns
10
+ **deck-style slide JSON** into **HTML**.
11
+
12
+ It does **one thing only**:
13
+
14
+ > **Given slide data + render state → return HTML**
15
+
16
+ It does **not** manage time, indexes, playback, or decks.
17
+
18
+ ---
19
+
20
+ ## 🌐 Live Display Center (Important)
21
+
22
+ 👉 **Official live display & reference implementation**
23
+ **[https://bilza2023.github.io/taleem/](https://bilza2023.github.io/taleem/)**
24
+
25
+ This is **not a mock demo**.
26
+ This link is the **active display center** where:
27
+
28
+ * slide templates are rendered in real browsers
29
+ * visual behavior is validated
30
+ * browser / player integration is tested
31
+
32
+ ---
33
+
34
+ ## ✨ Taleem.help Philosophy
35
+
36
+ **Taleem.help** is an educational technology initiative focused on making
37
+ **content-first learning tools**.
38
+
39
+ The goal of the `taleem-*` libraries is simple:
40
+
41
+ > Enable educators to create **JSON-based presentations**
42
+ > and display them online using **free, open tools**.
43
+
44
+ ### Key ideas
45
+
46
+ * Slides already encode *layout + structure*
47
+ * Users provide **content only**
48
+ * There are **no configuration knobs**
49
+ * What you see is what the template decides
5
50
 
6
- `taleem-slides` is a **pure, test-locked rendering layer**.
7
- It takes a validated `deck-v1` JSON and produces **deterministic HTML output** through a strict public API.
51
+ This removal of choice is **intentional**.
8
52
 
9
- This project does **not**:
53
+ It makes the system:
54
+
55
+ * easy to learn
56
+ * hard to misuse
57
+ * consistent across platforms
58
+
59
+ If a different layout is needed, the solution is **not configuration** —
60
+ it is **a new slide template**.
61
+
62
+ Templates are cheap.
63
+ Even hundreds of templates add no runtime cost.
64
+
65
+ ---
66
+
67
+ ## ✨ What this library is
68
+
69
+ * A collection of **slide templates**
70
+ * Each template:
71
+
72
+ * reads slide JSON
73
+ * renders HTML
74
+ * applies CSS classes based on a given state
75
+ * Fully **stateless** and **pure**
76
+
77
+ Think of it as:
78
+
79
+ > *Handlebars / JSX for Taleem slides*
80
+
81
+ ---
82
+
83
+ ## ❌ What this library is NOT
84
+
85
+ `taleem-slides` does **not**:
10
86
 
11
87
  * build decks
88
+ * validate full decks
89
+ * manage timing (`showAt`)
90
+ * decide which slide is active
91
+ * manage playback
12
92
  * mutate data
13
- * manage timing state
14
- * expose slide internals
15
93
 
16
- It only **interprets** and **renders**.
94
+ All of that belongs elsewhere.
17
95
 
18
96
  ---
19
97
 
20
98
  ## 🧠 Mental Model
21
99
 
22
100
  ```
23
- deck-v1 JSON
24
-
25
- slideBuilder()
26
-
27
- SlideManager
28
-
29
- renderSlide(index [, showAt])
101
+ slide JSON + render state
102
+
103
+ slide template
104
+
105
+ HTML
30
106
  ```
31
107
 
32
- Key idea:
33
- **Slides are private. Rendering is the only contract.**
108
+ How the state is calculated is **not this library’s concern**.
34
109
 
35
110
  ---
36
111
 
37
- ## What This Project Guarantees
112
+ ## 📦 Installation
38
113
 
39
- * Deterministic rendering (same input → same HTML)
40
- * Strict validation per slide type
41
- * Zero mutation after build
42
- * No access to internal slide objects
43
- * Full test coverage across all slide types
114
+ ```bash
115
+ npm install taleem-slides
116
+ ```
44
117
 
45
118
  ---
46
119
 
47
- ## 🔑 Public API
120
+ ## 🚀 Basic Usage
48
121
 
49
- ### `slideBuilder(deckV1Json) SlideManager`
50
-
51
- Builds and validates a deck, returning a `SlideManager`.
122
+ ### 1️⃣ Import a template
52
123
 
53
124
  ```js
54
- import { slideBuilder } from "taleem-slides";
55
-
56
- const manager = slideBuilder(deckJson);
125
+ import { getSlideTemplate } from "taleem-slides";
57
126
  ```
58
127
 
59
- Throws immediately on:
128
+ ---
60
129
 
61
- * invalid deck structure
62
- * unsupported slide types
63
- * invalid slide data
130
+ ### 2️⃣ Load slide data (once)
64
131
 
65
- ---
132
+ ```js
133
+ const SlideTemplate = getSlideTemplate("bulletList");
134
+
135
+ const slide = SlideTemplate.fromJSON({
136
+ type: "bulletList",
137
+ data: [
138
+ { name: "bullet", content: "First point" },
139
+ { name: "bullet", content: "Second point" },
140
+ { name: "bullet", content: "Third point" }
141
+ ]
142
+ });
143
+ ```
144
+
145
+ > `fromJSON()` only **reads and stores structure**.
146
+ > No timing. No logic.
66
147
 
67
- ### `SlideManager.renderSlide(index, showAt?) → string`
148
+ ---
68
149
 
69
- Renders **one slide** to HTML.
150
+ ### 3️⃣ Render with state
70
151
 
71
152
  ```js
72
- const html = manager.renderSlide(0);
153
+ const html = slide.render({
154
+ visibleCount: 2,
155
+ activeIndex: 1
156
+ });
73
157
  ```
74
158
 
75
- Notes:
159
+ This will:
76
160
 
77
- * `index` is zero-based
78
- * `showAt` is optional (for time-aware slides)
79
- * return value is **plain HTML string**
161
+ * render first 2 bullets
162
+ * highlight the second bullet
163
+ * dim the first
80
164
 
81
165
  ---
82
166
 
83
- ### `SlideManager.renderAll() string`
167
+ ## 🎨 Render State Contract
84
168
 
85
- Renders **all slides** as a static HTML dump.
169
+ Templates accept a **render state object**.
86
170
 
87
- ```js
88
- const fullHtml = manager.renderAll();
171
+ Common fields:
172
+
173
+ ```ts
174
+ {
175
+ visibleCount?: number; // how many items exist
176
+ activeIndex?: number; // which item is highlighted
177
+ }
89
178
  ```
90
179
 
180
+ Slides may choose to use one or both.
181
+
91
182
  ---
92
183
 
93
- ## 🔒 Encapsulation Rules (By Design)
184
+ ## 🎯 Class Name Contract
185
+
186
+ Templates apply **standard class names only**:
94
187
 
95
- * `SlideManager` does **not** expose slides
96
- * Slides are frozen internally
97
- * Rendered output is a string (immutable by nature)
188
+ ```text
189
+ .is-active
190
+ .is-dim
191
+ .is-hidden
192
+ ```
98
193
 
99
- If you want to *inspect structure*, that belongs in **taleem-core**, not here.
194
+ Styling is handled entirely by the consuming app.
100
195
 
101
196
  ---
102
197
 
103
- ## 🧪 Testing Philosophy
198
+ ## 🧭 How this fits in the ecosystem
104
199
 
105
- This project has **56 passing tests** covering:
200
+ `taleem-slides` is intentionally **small** and **focused**.
106
201
 
107
- * slideBuilder validation
108
- * every slide type
109
- * deterministic rendering
110
- * error handling
111
- * edge cases
202
+ It is used by higher-level projects:
112
203
 
113
- Tests assert **behavior**, not snapshots.
204
+ ### 🧩 Sister Projects
114
205
 
115
- This test suite is the **living specification**.
206
+ * **taleem-browser**
207
+ Index-based slide viewer (manual navigation)
116
208
 
117
- ---
209
+ * **taleem-player**
210
+ Time-based slide player (audio / video synced)
211
+
212
+ Both projects:
118
213
 
119
- ## 🎞️ Supported Slide Types
214
+ * compute render state (`activeIndex`, `visibleCount`)
215
+ * pass it to `taleem-slides`
216
+ * receive consistent HTML output
120
217
 
121
- `taleem-slides` supports all canonical `deck-v1` slide types, including:
218
+ ---
219
+
220
+ ## 🧪 Demo & Reference Projects
122
221
 
123
- * titleSlide
124
- * titleAndSubtitle
125
- * titleAndPara
126
- * bulletList
127
- * twoColumnText
128
- * imageSlide
129
- * imageWithTitle
130
- * imageWithCaption
131
- * imageLeftBulletsRight
132
- * imageRightBulletsLeft
133
- * table
134
- * statistic
135
- * donutChart
136
- * barChart
137
- * bigNumber
138
- * quoteSlide
139
- * quoteWithImage
140
- * cornerWordsSlide
141
- * contactSlide
142
- * fillImage
143
- * eq
144
- * svgPointer
222
+ * 🌐 **Live Display Center**
223
+ [https://bilza2023.github.io/taleem/](https://bilza2023.github.io/taleem/)
145
224
 
146
- All validation rules are enforced at build time.
225
+ * 📁 **GitHub Demo / Playground**
226
+ *(link can be added here when ready)*
147
227
 
148
228
  ---
149
229
 
150
- ## 🧊 Versioning & Stability
230
+ ## 🧊 Stability & Versioning
151
231
 
152
- * This project targets **deck-v1 only**
153
- * No breaking changes without `deck-v2`
154
- * Rendering output is intentionally simple HTML
155
- * Styling is the responsibility of the consuming app
232
+ * Targets **deck-v1**
233
+ * Breaking changes allowed during WIP phase
234
+ * HTML output is intentionally simple and predictable
156
235
 
157
236
  ---
158
237
 
159
- ## 📍 When to Use This
238
+ ## 🧠 Design Principle (Locked)
160
239
 
161
- Use `taleem-slides` when you want:
240
+ > **taleem-slides renders HTML.
241
+ > It does not decide *when* or *why*.**
162
242
 
163
- * a **trustworthy rendering engine**
164
- * clean separation from content generation
165
- * confidence that slides behave exactly as specified
243
+ ---
166
244
 
167
- Do **not** use it for:
245
+ ## 🔳 Deck Background Support (NEW)
168
246
 
169
- * authoring decks
170
- * editing slides
171
- * managing playback state
247
+ `taleem-slides` also defines **how deck backgrounds are resolved**, while remaining fully **DOM-agnostic**.
248
+
249
+ A deck background is **optional** and applies to the **entire deck**, not individual slides.
172
250
 
173
251
  ---
174
252
 
253
+ ### Background responsibility split
254
+
255
+ #### taleem-slides
256
+
257
+ * decides **what background should be used**
258
+ * exposes a **pure resolver function**
259
+ * returns **plain background data**
260
+
261
+ #### player / browser
262
+
263
+ * renders the background into the DOM
264
+ * applies styles and layout
265
+ * handles mounting and lifecycle
266
+
267
+ This keeps slide rendering **pure and portable**.
268
+
175
269
  ---
176
270
 
177
- # 🧠 taleem-core (Contextual Overview)
271
+ ## 🎨 Background Resolution API
178
272
 
179
- > **Authoring & specification layer for deck-v1**
273
+ `taleem-slides` exports a small helper:
180
274
 
181
- `taleem-core` is responsible for **creating valid decks**.
182
- `taleem-slides` is responsible for **rendering them**.
275
+ ```js
276
+ import { resolveBackground } from "taleem-slides";
277
+ ```
278
+
279
+ ### Purpose
280
+
281
+ `resolveBackground` answers one question only:
282
+
283
+ > **“What background should be used for this deck?”**
183
284
 
184
- They are intentionally separate.
285
+ It does **not**:
286
+
287
+ * touch the DOM
288
+ * inject styles
289
+ * manage themes
290
+ * animate or time anything
291
+
292
+ ---
293
+
294
+ ### Input (conceptual)
295
+
296
+ ```ts
297
+ {
298
+ deckBackground?: {
299
+ backgroundColor?: string
300
+ backgroundImage?: string
301
+ backgroundImageOpacity?: number
302
+ },
303
+ themeSurfaceColor?: string
304
+ }
305
+ ```
185
306
 
186
307
  ---
187
308
 
188
- ## Responsibility Split
309
+ ### Output
189
310
 
190
- | Concern | taleem-core | taleem-slides |
191
- | ------------------- | ----------- | ------------- |
192
- | Deck creation | ✅ | ❌ |
193
- | Schema validation | ✅ | ❌ |
194
- | EQ expansion | ✅ | ❌ |
195
- | Timing rules | ✅ | ❌ |
196
- | Rendering HTML | ❌ | ✅ |
197
- | Slide encapsulation | ❌ | ✅ |
311
+ ```ts
312
+ {
313
+ backgroundColor?: string
314
+ backgroundImage?: string
315
+ backgroundImageOpacity?: number
316
+ }
317
+ ```
198
318
 
199
319
  ---
200
320
 
201
- ## Core Artifacts
321
+ ### Resolution rules (locked)
322
+
323
+ * If the deck defines a background → **use it**
324
+ * Otherwise → **fall back to the theme’s surface color**
325
+
326
+ These rules are **format-level guarantees**, not rendering behavior.
327
+
328
+ ---
202
329
 
203
- From the docs you uploaded:
330
+ ## 🧠 Mental Model (Updated)
204
331
 
205
- * `api.md` → defines **deck-v1 contract**
206
- * `eq.md` defines **EQ slide expansion rules**
207
- * `timings.md` → defines **global timing semantics**
332
+ ```
333
+ deck JSON + render state + theme surface
334
+
335
+ taleem-slides
336
+
337
+ HTML + resolved background data
338
+
339
+ player / browser
340
+
341
+ DOM
342
+ ```
208
343
 
209
- `taleem-slides` **trusts** these documents.
210
- It does not reinterpret them.
344
+ `taleem-slides` decides **what exists**.
345
+ The player / browser decides **how it appears**.
211
346
 
212
347
  ---
213
348
 
214
- ## Architectural Law (Important)
349
+ ## 🔒 Design Principle (Extended)
215
350
 
216
- > **Authoring and rendering must never mix**
351
+ > **taleem-slides renders HTML and resolves deck-level intent.
352
+ > It never touches the DOM and never manages playback.**
217
353
 
218
- Once a deck enters `taleem-slides`, it is:
354
+ ---
219
355
 
220
- * assumed valid
221
- * treated as immutable
222
- * rendered deterministically
356
+ ## What this achieves
223
357
 
224
- This is why the system scales cleanly.
358
+ * background rules are centralized
359
+ * players remain simple
360
+ * browsers stay dumb
361
+ * future renderers (CLI, SSR, export) stay possible
362
+
363
+ ---
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "taleem-slides",
3
- "version": "0.3.0",
3
+ "version": "0.5.0",
4
4
  "type": "module",
5
- "description": "Pure slide interpretation engine for deck-v1 (no DOM, no UI)",
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 registry = {
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,5 +1,5 @@
1
-
2
1
  // src/index.js
3
2
 
4
- export { slideBuilder } from "./interpreter/slideBuilder.js";
5
-
3
+ export { SlideTemplates } from "./SlideTemplates.js";
4
+ export { getSlideTemplate } from "./getSlideTemplate.js";
5
+ export { resolveBackground } from "./resolveBackground.js";
@@ -0,0 +1,10 @@
1
+ export function resolveBackground({ deckBackground, theme }) {
2
+ if (deckBackground) return deckBackground;
3
+
4
+ return {
5
+ backgroundColor: theme.surfaceColor,
6
+ backgroundImage: null,
7
+ backgroundImageOpacity: 1
8
+ };
9
+ }
10
+
@@ -1,44 +1,46 @@
1
+ // BarChartSlide.js
1
2
  export const BarChartSlide = {
2
- type: "barChart",
3
-
4
- fromJSON(raw) {
5
- const bars = raw.data?.filter(d => d.name === "bar");
6
-
7
- if (!bars || bars.length === 0) {
8
- throw new Error("barChart: requires at least one bar");
9
- }
10
-
11
- // validate bar structure
12
- bars.forEach((b, i) => {
13
- if (
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
- type: "bigNumber",
3
-
4
- fromJSON(raw) {
5
- const value = raw.data?.find(d => d.name === "number")?.content;
6
- const label = raw.data?.find(d => d.name === "label")?.content;
7
-
8
- if (!value) throw new Error("bigNumber: number required");
9
-
10
- return Object.freeze({
11
- type: "bigNumber",
12
- render() {
13
- return `
14
- <section class="slide bigNumber">
15
- <div class="number">${value}</div>
16
- ${label ? `<div class="label">${label}</div>` : ""}
17
- </section>
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
+ };