taleem-slides 1.0.0 β†’ 1.0.2

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 CHANGED
@@ -1,28 +1,29 @@
1
-
2
1
  # πŸ“¦ taleem-slides
3
2
 
4
3
  > **Render slide JSON β†’ HTML (nothing more, nothing less)**
5
4
 
6
- `taleem-slides` is a **small, focused rendering library**.
5
+ `taleem-slides` is a **small, focused rendering library**.
7
6
  It takes **validated slide JSON** and returns **HTML strings** using fixed, opinionated layouts.
8
7
 
9
- No player.
10
- No timing.
11
- No DOM.
8
+ No player.
9
+ No timing.
10
+ No DOM.
12
11
  Just HTML.
12
+
13
13
  > Assumes slide JSON is already validated by upstream tools.
14
+
14
15
  ---
15
16
 
16
17
  ## 🌐 Live Reference (Authoritative)
17
18
 
18
- πŸ‘‰ **[https://bilza2023.github.io/taleem](https://bilza2023.github.io/taleem)**
19
+ πŸ‘‰ **https://bilza2023.github.io/taleem**
19
20
 
20
21
  This site is the **source of truth** for:
21
22
 
22
- * supported slide types
23
- * exact visual layouts
24
- * real rendered output
25
- * examples and behavior
23
+ - supported slide types
24
+ - exact visual layouts
25
+ - real rendered output
26
+ - examples and behavior
26
27
 
27
28
  If something here and the site disagree, **the site wins**.
28
29
 
@@ -30,10 +31,10 @@ If something here and the site disagree, **the site wins**.
30
31
 
31
32
  ## βœ… What taleem-slides DOES
32
33
 
33
- * Converts slide JSON into HTML
34
- * Implements fixed slide layouts
35
- * Applies minimal state-based CSS classes
36
- * Works in browser, player, SSR, or Node
34
+ - Converts slide JSON into HTML
35
+ - Implements fixed slide layouts
36
+ - Applies minimal state-based CSS classes
37
+ - Works in browser, player, SSR, or Node
37
38
 
38
39
  ---
39
40
 
@@ -41,12 +42,12 @@ If something here and the site disagree, **the site wins**.
41
42
 
42
43
  `taleem-slides` does **not**:
43
44
 
44
- * manage time or animations
45
- * navigate slides
46
- * validate decks or schemas
47
- * apply CSS
48
- * touch the DOM
49
- * control presentation flow
45
+ - manage time or animations
46
+ - navigate slides
47
+ - validate decks or schemas
48
+ - apply CSS
49
+ - touch the DOM
50
+ - control presentation flow
50
51
 
51
52
  Those responsibilities live **outside** this library.
52
53
 
@@ -55,21 +56,23 @@ Those responsibilities live **outside** this library.
55
56
  ## 🧠 Mental Model
56
57
 
57
58
  ```
59
+
58
60
  slide JSON
59
61
  ↓
60
62
  taleem-slides
61
63
  ↓
62
64
  HTML string
63
- ```
65
+
66
+ ````
64
67
 
65
68
  That’s it.
66
69
 
67
70
  How the HTML is:
68
71
 
69
- * shown
70
- * styled
71
- * animated
72
- * timed
72
+ - shown
73
+ - styled
74
+ - animated
75
+ - timed
73
76
 
74
77
  …is **your responsibility**.
75
78
 
@@ -79,7 +82,7 @@ How the HTML is:
79
82
 
80
83
  ```bash
81
84
  npm install taleem-slides
82
- ```
85
+ ````
83
86
 
84
87
  ---
85
88
 
@@ -146,7 +149,9 @@ Each slide reads only the fields it cares about.
146
149
 
147
150
  ## 🎨 CSS Contract (Very Small)
148
151
 
149
- Slides may emit these state classes only:
152
+ Slides may emit **state classes and slide-specific structural classes** only.
153
+
154
+ State classes:
150
155
 
151
156
  ```text
152
157
  .is-active
@@ -171,7 +176,31 @@ Categories include:
171
176
  * images and image+text layouts
172
177
  * tables and charts
173
178
  * quotes, stats, and numbers
174
- * equation slides
179
+ * equation slides (**experimental**)
180
+
181
+ ---
182
+
183
+ ### ⚠️ Note on equation (`eq`) slides
184
+
185
+ The `eq` slide type is **experimental**.
186
+
187
+ In v1 it is intentionally limited to:
188
+
189
+ * time-based line reveal
190
+ * a single active (highlighted) line
191
+ * optional side-panel annotations (`spItems`)
192
+ * deterministic windowing (older lines drop off)
193
+
194
+ It does **not** include:
195
+
196
+ * math rendering (KaTeX / MathJax)
197
+ * semantic math/text interpretation
198
+ * scrolling or centering behavior
199
+
200
+ The `eq` slide exists to validate the renderer contract,
201
+ not as a finished math presentation system.
202
+
203
+ ---
175
204
 
176
205
  Layouts are **fixed by design**.
177
206
  New layouts = new slide templates.
@@ -208,4 +237,4 @@ It is intentionally small so it can sit **anywhere**.
208
237
  > **Render HTML only.
209
238
  > Never control presentation logic.**
210
239
 
211
- ---
240
+ ---
package/package.json CHANGED
@@ -1,17 +1,12 @@
1
1
  {
2
2
  "name": "taleem-slides",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "type": "module",
5
5
  "description": "Convert Taleem schema into HTML slides",
6
6
  "exports": {
7
- ".": "./src/index.js",
8
- "./styles/taleem.css": "./dist/taleem.css",
9
- "./styles/themes/dark.css": "./dist/themes/dark.css",
10
- "./styles/themes/light.css": "./dist/themes/light.css",
11
- "./styles/themes/paper.css": "./dist/themes/paper.css"
7
+ ".": "./src/index.js"
12
8
  },
13
9
  "files": [
14
- "dist",
15
10
  "src"
16
11
  ],
17
12
  "scripts": {
@@ -22,20 +17,19 @@
22
17
  "lint": "echo \"no lint yet\""
23
18
  },
24
19
  "dependencies": {
25
- "taleem-core": "^1.5.0",
26
- "zod": "^4.3.5"
20
+ "taleem-core": "^1.5.1"
27
21
  },
28
22
  "devDependencies": {
29
23
  "vite": "^5.0.0",
30
- "vitest": "^1.5.0"
24
+ "vitest": "^1.5.0",
25
+ "zod": "^4.3.5"
31
26
  },
32
27
  "keywords": [
33
- "slides",
34
- "presentation",
35
- "education",
36
- "html",
37
- "renderer",
38
- "taleem"
39
- ]
40
-
28
+ "slides",
29
+ "presentation",
30
+ "education",
31
+ "html",
32
+ "renderer",
33
+ "taleem"
34
+ ]
41
35
  }
@@ -1,3 +1,4 @@
1
+
1
2
  export const DonutChartSlide = {
2
3
  type: "donutChart",
3
4
 
@@ -1,36 +1,68 @@
1
+ const WINDOW_SIZE = 3;
1
2
 
2
3
  export const EqSlide = {
3
4
  type: "eq",
4
5
 
5
6
  fromJSON(raw) {
6
- const lines = raw.data
7
- ?.filter(d => d.name === "line")
8
- .map(d => ({
9
- type: d.type,
10
- content: d.content
11
- }));
12
-
13
- if (!lines || lines.length === 0) {
14
- throw new Error("eq: requires at least one line");
15
- }
7
+ const lines = raw.data ?? [];
16
8
 
17
9
  return Object.freeze({
18
10
  type: "eq",
19
11
  lines,
20
12
 
21
- render({ visibleCount = lines.length, activeIndex = null } = {}) {
13
+ render(time = null) {
14
+ let activeIndex = -1;
15
+
16
+ if (typeof time === "number") {
17
+ for (let i = 0; i < lines.length; i++) {
18
+ if (lines[i].showAt <= time) {
19
+ activeIndex = i;
20
+ }
21
+ }
22
+ }
23
+
24
+ const isTimed = activeIndex !== -1;
25
+
26
+ let start = 0;
27
+ let end = lines.length;
28
+
29
+ if (isTimed && activeIndex >= WINDOW_SIZE) {
30
+ start = activeIndex - (WINDOW_SIZE - 1);
31
+ end = activeIndex + 1;
32
+ }
33
+
34
+ const visible = lines.slice(start, end);
35
+
22
36
  return `
23
37
  <section class="slide eq">
24
- ${lines.map((l, i) => {
25
- if (i >= visibleCount) return "";
26
- const cls =
27
- i === activeIndex
28
- ? "is-active"
29
- : activeIndex !== null && i < activeIndex
30
- ? "is-dim"
31
- : "";
32
- return `<div class="eq-line ${cls}">${l.content}</div>`;
33
- }).join("")}
38
+ <div class="eq-slide">
39
+ ${visible
40
+ .map((line, localIndex) => {
41
+ const index = start + localIndex;
42
+ const isActive = isTimed && index === activeIndex;
43
+ const hasSp =
44
+ Array.isArray(line.spItems) && line.spItems.length > 0;
45
+
46
+ return `
47
+ <div class="eq-line ${isActive ? "active" : ""}">
48
+ <div class="eq-line-content">${line.content}</div>
49
+ ${
50
+ hasSp && (!isTimed || isActive)
51
+ ? `<div class="eq-sp-items">
52
+ ${line.spItems
53
+ .map(
54
+ sp =>
55
+ `<div class="eq-sp-item">${sp.content}</div>`
56
+ )
57
+ .join("")}
58
+ </div>`
59
+ : ""
60
+ }
61
+ </div>
62
+ `;
63
+ })
64
+ .join("")}
65
+ </div>
34
66
  </section>
35
67
  `;
36
68
  }
package/dist/taleem.css DELETED
@@ -1,347 +0,0 @@
1
-
2
- /* =====================================================
3
- TALEEM β€” Single Public Stylesheet
4
-
5
- /* -------------------------------
6
- Global Page Reset
7
- ------------------------------- */
8
-
9
- html,body {
10
- height: 100%;
11
- overflow: hidden;
12
- margin: 0;
13
- font-family: system-ui, -apple-system, Segoe UI, Roboto, sans-serif;
14
- background: var(--backgroundColor, #0b1220);
15
- color: var(--primaryColor, #e6e9ff);
16
- }
17
-
18
- #app {
19
- position: relative;
20
- width: 100vw;
21
- min-height: 100vh;
22
- overflow: hidden;
23
- }
24
-
25
- /* -------------------------------
26
- Browser / Player Layers
27
- ------------------------------- */
28
- .taleem-browser-bg {
29
- position: absolute;
30
- inset: 0;
31
- z-index: 0;
32
- background-size: cover;
33
- background-position: center;
34
- }
35
-
36
- .taleem-browser-slide {
37
- position: relative;
38
- z-index: 1;
39
- }
40
-
41
- /* -------------------------------
42
- Base Slide Grammar
43
- ------------------------------- */
44
- .slide {
45
- height: 100vh;
46
- box-sizing: border-box;
47
-
48
- display: flex;
49
- flex-direction: column;
50
- justify-content: center;
51
- align-items: center;
52
-
53
- padding: 64px 80px;
54
- gap: 32px;
55
-
56
- overflow: hidden;
57
- background: transparent;
58
- color: var(--primaryColor, #e6e9ff);
59
-
60
- font-size: 2.4rem;
61
- line-height: 1.6;
62
- letter-spacing: 0.01em;
63
- text-align: center;
64
- }
65
-
66
- /* -------------------------------
67
- Global Image Safety
68
- ------------------------------- */
69
- .slide img {
70
- max-width: 100%;
71
- max-height: 100%;
72
- height: auto;
73
- width: auto;
74
- display: block;
75
- }
76
-
77
- /* -------------------------------
78
- Headings
79
- ------------------------------- */
80
- .slide h1 {
81
- margin: 0;
82
- letter-spacing: -0.015em;
83
- }
84
-
85
- /* -------------------------------
86
- Slide Types
87
- ------------------------------- */
88
- .slide.titleSlide h1 {
89
- font-size: 5.6rem;
90
- font-weight: 700;
91
- line-height: 1.2;
92
- }
93
-
94
- .slide.titleAndSubtitle h1 {
95
- font-size: 5.8rem;
96
- font-weight: 700;
97
- }
98
-
99
- .slide.titleAndSubtitle h2 {
100
- font-size: 3.8rem;
101
- font-weight: 400;
102
- opacity: 0.8;
103
- margin: 0;
104
- }
105
-
106
- .slide.titleAndPara h1 {
107
- font-size: 4.8rem;
108
- font-weight: 600;
109
- }
110
-
111
- .slide.titleAndPara p {
112
- font-size: 3rem;
113
- max-width: 70ch;
114
- opacity: 0.9;
115
- margin: 0;
116
- }
117
-
118
- /* -------------------------------
119
- Bullet List
120
- ------------------------------- */
121
- .slide.bulletList ul {
122
- list-style: disc;
123
- padding-left: 2rem;
124
- margin: 0;
125
- }
126
-
127
- .slide.bulletList li {
128
- font-size: 3.6rem;
129
- margin-bottom: 1rem;
130
- text-align: left;
131
- font-weight: 500;
132
- }
133
-
134
- /* -------------------------------
135
- Image Variants
136
- ------------------------------- */
137
- .slide.imageSlide {
138
- padding: 0;
139
- }
140
-
141
- .slide.imageSlide img {
142
- object-fit: contain;
143
- }
144
-
145
- .slide.imageWithTitle {
146
- position: relative;
147
- padding: 48px;
148
- }
149
-
150
- .slide.imageWithTitle img {
151
- height: calc(100vh - 96px);
152
- border-radius: 12px;
153
- }
154
-
155
- .slide.imageWithTitle h1 {
156
- position: absolute;
157
- bottom: 64px;
158
- left: 50%;
159
- transform: translateX(-50%);
160
- font-size: 4.6rem;
161
- background: rgba(0, 0, 0, 0.45);
162
- padding: 0.4em 0.8em;
163
- border-radius: 6px;
164
- }
165
-
166
- .slide.imageWithCaption {
167
- display: flex;
168
- flex-direction: column;
169
- justify-content: center;
170
- gap: 32px;
171
- height: 100vh;
172
- overflow: hidden;
173
- }
174
-
175
- .slide.imageWithCaption img {
176
- max-height: 55vh; /* reduce slightly */
177
- object-fit: contain;
178
- flex-shrink: 0;
179
- }
180
-
181
- .slide.imageWithCaption p {
182
- max-height: 20vh; /* hard cap text */
183
- overflow: hidden;
184
- text-overflow: ellipsis;
185
- }
186
-
187
- /* -------------------------------
188
- Two Column Text
189
- ------------------------------- */
190
-
191
-
192
- .slide.twoColumnText {
193
- flex-direction: row;
194
- justify-content: center; /* center the columns block */
195
- align-items: center;
196
- gap: 64px;
197
- }
198
-
199
- .slide.twoColumnText > div {
200
- flex: 1;
201
- max-width: 520px; /* keeps columns visually centered */
202
- }
203
-
204
-
205
- /* QUOTE SLIDE */
206
- .slide.quoteSlide {
207
- display: flex;
208
- flex-direction: column;
209
- justify-content: center;
210
- gap: 32px;
211
- height: 100vh;
212
- overflow: hidden;
213
- }
214
-
215
- .slide.quoteSlide blockquote {
216
- max-height: 60vh;
217
- overflow: hidden;
218
- }
219
-
220
- .slide.quoteSlide cite {
221
- flex-shrink: 0;
222
- }
223
-
224
- /* -------------------------------
225
- Quote Slide
226
- ------------------------------- */
227
- .slide.quoteSlide blockquote {
228
- font-size: 3.8rem;
229
- font-style: italic;
230
- max-width: 60ch;
231
- }
232
-
233
- .slide.quoteSlide cite {
234
- font-size: 2.4rem;
235
- opacity: 0.75;
236
- }
237
-
238
- /* -------------------------------
239
- Big Number
240
- ------------------------------- */
241
- .slide.bigNumber .number {
242
- font-size: 9rem;
243
- font-weight: 700;
244
- }
245
-
246
- /* -------------------------------
247
- Fill Image (Full Bleed)
248
- ------------------------------- */
249
- .slide.fillImage {
250
- padding: 0;
251
- height: 100vh;
252
- display: block;
253
- }
254
-
255
- .slide.fillImage img {
256
- width: 100%;
257
- height: 100%;
258
- object-fit: cover;
259
- }
260
-
261
- /* -------------------------------
262
- Demo / Player UI (Optional)
263
- ------------------------------- */
264
- #timebar {
265
- position: fixed;
266
- bottom: 0;
267
- left: 0;
268
- right: 0;
269
- height: 32px;
270
- background: rgba(0, 0, 0, 0.6);
271
- backdrop-filter: blur(6px);
272
- z-index: 10;
273
- }
274
-
275
-
276
-
277
- /* ///////fixes */
278
-
279
- /* -------------------------------
280
- Image + Bullets (Side by Side)
281
- ------------------------------- */
282
-
283
- .slide.imageRightBulletsLeft,
284
- .slide.imageLeftBulletsRight {
285
- display: flex;
286
- flex-direction: row;
287
- align-items: center;
288
- gap: 64px;
289
- text-align: left;
290
- }
291
-
292
- /* image on right */
293
- .slide.imageRightBulletsLeft img {
294
- order: 2;
295
- }
296
- /* -------------------------------
297
- Table Slide
298
- ------------------------------- */
299
-
300
- .slide.table {
301
- display: flex;
302
- justify-content: center;
303
- align-items: center;
304
-
305
- width: 100%;
306
- height: 100vh;
307
-
308
- padding: 64px 80px;
309
- box-sizing: border-box;
310
- }
311
-
312
- /* actual table */
313
- .slide.table table {
314
- border-collapse: collapse;
315
- width: 100%;
316
- max-width: 1200px;
317
-
318
- font-size: 2.8rem;
319
- line-height: 1.4;
320
- text-align: center;
321
-
322
- color: var(--primaryColor, #e6e9ff);
323
- }
324
-
325
- /* header cells (title row) */
326
- .slide.table thead th {
327
- font-weight: 700; /* title row bold */
328
- padding: 20px 24px;
329
-
330
- border: 2px solid rgba(255, 255, 255, 0.35);
331
- }
332
-
333
- /* body cells */
334
- .slide.table tbody td {
335
- padding: 20px 24px;
336
-
337
- border: 2px solid rgba(255, 255, 255, 0.25);
338
- }
339
- /* hide empty table header row */
340
- .slide.table thead th:empty {
341
- display: none;
342
- }
343
-
344
- .slide.table thead tr:has(th:empty) {
345
- display: none;
346
- }
347
-
@@ -1,6 +0,0 @@
1
-
2
- :root {
3
- --backgroundColor: #081b7a;
4
- --primaryColor: #ccd0e4;
5
- }
6
-
@@ -1,6 +0,0 @@
1
-
2
- :root {
3
- --backgroundColor: #15df1b;
4
- --primaryColor: #cbd44b;
5
- }
6
-
@@ -1,6 +0,0 @@
1
-
2
- :root {
3
- --backgroundColor: #f8f9fb;
4
- --primaryColor: #1a1f36;
5
- }
6
-