taleem-player 1.0.1 → 1.0.3
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 +26 -23
- package/dist/css/taleem.css +63 -0
- package/dist/taleem-player.esm.js +62 -12
- package/dist/taleem-player.umd.js +62 -12
- package/package.json +5 -4
package/README.md
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
|
|
2
1
|
# Taleem Player
|
|
3
2
|
|
|
4
3
|
<img src="./docs/images/taleem.webp"
|
|
@@ -7,7 +6,7 @@
|
|
|
7
6
|
|
|
8
7
|
**Taleem Player** converts **Taleem JSON slide data** into **web-based presentations**.
|
|
9
8
|
|
|
10
|
-
It renders the
|
|
9
|
+
It renders the _same taleem JSON_ in multiple ways using different display modes.
|
|
11
10
|
|
|
12
11
|
> **Stable 1.0 — API frozen.**
|
|
13
12
|
> Internal improvements may continue without breaking public contracts.
|
|
@@ -19,6 +18,7 @@ It renders the *same taleem JSON* in multiple ways using different display modes
|
|
|
19
18
|
👉 https://bilza2023.github.io/taleem/
|
|
20
19
|
|
|
21
20
|
The live demo shows:
|
|
21
|
+
|
|
22
22
|
- Browser Mode (index-based rendering)
|
|
23
23
|
- Player Mode (time-based rendering)
|
|
24
24
|
- Real production Taleem JSON
|
|
@@ -33,7 +33,7 @@ What you see is the real engine running in the browser.**
|
|
|
33
33
|
|
|
34
34
|
```bash
|
|
35
35
|
npm install taleem-player
|
|
36
|
-
|
|
36
|
+
```
|
|
37
37
|
|
|
38
38
|
---
|
|
39
39
|
|
|
@@ -48,7 +48,7 @@ import { createTaleemBrowser } from "taleem-player";
|
|
|
48
48
|
|
|
49
49
|
const browser = createTaleemBrowser({
|
|
50
50
|
mount: "#app",
|
|
51
|
-
deck
|
|
51
|
+
deck,
|
|
52
52
|
});
|
|
53
53
|
|
|
54
54
|
browser.render(0);
|
|
@@ -57,10 +57,10 @@ browser.getTotal();
|
|
|
57
57
|
|
|
58
58
|
**Ideal for**
|
|
59
59
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
60
|
+
- previews
|
|
61
|
+
- galleries
|
|
62
|
+
- editors
|
|
63
|
+
- syllabus pages
|
|
64
64
|
|
|
65
65
|
---
|
|
66
66
|
|
|
@@ -77,9 +77,9 @@ player.renderAt(12.5);
|
|
|
77
77
|
|
|
78
78
|
**Ideal for**
|
|
79
79
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
80
|
+
- narrated lessons
|
|
81
|
+
- video / audio sync
|
|
82
|
+
- recorded presentations
|
|
83
83
|
|
|
84
84
|
---
|
|
85
85
|
|
|
@@ -100,7 +100,6 @@ player.renderAt(12.5);
|
|
|
100
100
|
|
|
101
101
|
## Utilities (Runtime-safe)
|
|
102
102
|
|
|
103
|
-
|
|
104
103
|
These **Utilities (Runtime-safe)** are exported :
|
|
105
104
|
|
|
106
105
|
```js
|
|
@@ -108,14 +107,14 @@ import {
|
|
|
108
107
|
assignMockTimings,
|
|
109
108
|
resolveAssetPaths,
|
|
110
109
|
resolveBackground,
|
|
111
|
-
getDeckEndTime
|
|
110
|
+
getDeckEndTime,
|
|
112
111
|
} from "taleem-player";
|
|
113
112
|
```
|
|
114
113
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
114
|
+
- `assignMockTimings(deck, seconds)`
|
|
115
|
+
- `resolveAssetPaths(deck, basePath)`
|
|
116
|
+
- `resolveBackground(deck, basePath)`
|
|
117
|
+
- `getDeckEndTime(deck)`
|
|
119
118
|
|
|
120
119
|
These helpers prepare decks for real usage and runtime playback.
|
|
121
120
|
|
|
@@ -137,11 +136,11 @@ All modes share the same styling system.
|
|
|
137
136
|
|
|
138
137
|
## What Taleem Player does NOT do
|
|
139
138
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
139
|
+
- create slides
|
|
140
|
+
- edit JSON
|
|
141
|
+
- manage clocks or media playback
|
|
142
|
+
- handle audio or narration
|
|
143
|
+
- auto-validate or repair data
|
|
145
144
|
|
|
146
145
|
Those responsibilities belong to the **application layer**.
|
|
147
146
|
|
|
@@ -151,9 +150,13 @@ Those responsibilities belong to the **application layer**.
|
|
|
151
150
|
|
|
152
151
|
**Stable — Version 1.0**
|
|
153
152
|
|
|
153
|
+
The `eq` slide type is **experimental**:
|
|
154
|
+
- it is implemented but intentionally limited
|
|
155
|
+
- it should not be relied on for production math rendering
|
|
156
|
+
- its behavior may evolve without breaking the core player API
|
|
157
|
+
|
|
154
158
|
---
|
|
155
159
|
|
|
156
160
|
## License
|
|
157
161
|
|
|
158
162
|
MIT
|
|
159
|
-
|
package/dist/css/taleem.css
CHANGED
|
@@ -344,4 +344,67 @@
|
|
|
344
344
|
.slide.table thead tr:has(th:empty) {
|
|
345
345
|
display: none;
|
|
346
346
|
}
|
|
347
|
+
|
|
348
|
+
|
|
349
|
+
/* -------------------------------
|
|
350
|
+
Corner Words Slide (4 Quadrants)
|
|
351
|
+
------------------------------- */
|
|
352
|
+
|
|
353
|
+
.slide.cornerWordsSlide {
|
|
354
|
+
position: relative;
|
|
355
|
+
width: 100%;
|
|
356
|
+
height: 100vh;
|
|
357
|
+
padding: 0;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
/* base card */
|
|
361
|
+
.cornerWordsSlide .corner-card {
|
|
362
|
+
position: absolute;
|
|
363
|
+
width: 45%;
|
|
364
|
+
height: 45%;
|
|
365
|
+
|
|
366
|
+
display: flex;
|
|
367
|
+
flex-direction: column;
|
|
368
|
+
justify-content: center;
|
|
369
|
+
align-items: center;
|
|
370
|
+
gap: 16px;
|
|
371
|
+
|
|
372
|
+
font-size: 4.2rem;
|
|
373
|
+
font-weight: 700;
|
|
374
|
+
letter-spacing: 0.02em;
|
|
375
|
+
text-align: center;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
/* emoji / icon */
|
|
379
|
+
.cornerWordsSlide .corner-card .icon {
|
|
380
|
+
font-size: 5.2rem;
|
|
381
|
+
line-height: 1;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
/* label text */
|
|
385
|
+
.cornerWordsSlide .corner-card .label {
|
|
386
|
+
font-size: 3.6rem;
|
|
387
|
+
font-weight: 600;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
/* quadrants */
|
|
391
|
+
.cornerWordsSlide .corner-1 {
|
|
392
|
+
top: 0;
|
|
393
|
+
left: 0;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
.cornerWordsSlide .corner-2 {
|
|
397
|
+
top: 0;
|
|
398
|
+
right: 0;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
.cornerWordsSlide .corner-3 {
|
|
402
|
+
bottom: 0;
|
|
403
|
+
left: 0;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
.cornerWordsSlide .corner-4 {
|
|
407
|
+
bottom: 0;
|
|
408
|
+
right: 0;
|
|
409
|
+
}
|
|
347
410
|
|
|
@@ -532,23 +532,47 @@ var EqSlide = {
|
|
|
532
532
|
type: "eq",
|
|
533
533
|
fromJSON(raw) {
|
|
534
534
|
const lines = raw.data?.filter((d) => d.name === "line").map((d) => ({
|
|
535
|
-
|
|
536
|
-
|
|
535
|
+
content: d.content,
|
|
536
|
+
spItems: Array.isArray(d.spItems) ? d.spItems : []
|
|
537
537
|
}));
|
|
538
538
|
if (!lines || lines.length === 0) {
|
|
539
539
|
throw new Error("eq: requires at least one line");
|
|
540
540
|
}
|
|
541
|
+
const WINDOW_SIZE = 4;
|
|
541
542
|
return Object.freeze({
|
|
542
543
|
type: "eq",
|
|
543
544
|
lines,
|
|
544
|
-
render({ visibleCount = lines.length, activeIndex =
|
|
545
|
+
render({ visibleCount = lines.length, activeIndex = -1 } = {}) {
|
|
546
|
+
const end = Math.min(visibleCount, lines.length);
|
|
547
|
+
const start = Math.max(0, end - WINDOW_SIZE);
|
|
548
|
+
const windowed = lines.slice(start, end);
|
|
549
|
+
const localActive = activeIndex >= start && activeIndex < end ? activeIndex - start : -1;
|
|
550
|
+
const activeSpItems = activeIndex >= 0 && activeIndex < lines.length ? lines[activeIndex].spItems : [];
|
|
545
551
|
return `
|
|
546
552
|
<section class="slide eq">
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
553
|
+
<div class="eq-layout">
|
|
554
|
+
|
|
555
|
+
<div class="eq-left">
|
|
556
|
+
${windowed.map(
|
|
557
|
+
(l, i) => `
|
|
558
|
+
<div class="eq-line ${i === localActive ? "is-active" : ""}">
|
|
559
|
+
${l.content}
|
|
560
|
+
</div>
|
|
561
|
+
`
|
|
562
|
+
).join("")}
|
|
563
|
+
</div>
|
|
564
|
+
|
|
565
|
+
<div class="eq-right">
|
|
566
|
+
${activeSpItems.map(
|
|
567
|
+
(sp) => `
|
|
568
|
+
<div class="eq-sp-item eq-${sp.type || "item"}">
|
|
569
|
+
${sp.content}
|
|
570
|
+
</div>
|
|
571
|
+
`
|
|
572
|
+
).join("")}
|
|
573
|
+
</div>
|
|
574
|
+
|
|
575
|
+
</div>
|
|
552
576
|
</section>
|
|
553
577
|
`;
|
|
554
578
|
}
|
|
@@ -591,7 +615,7 @@ function getSlideTemplate(type) {
|
|
|
591
615
|
}
|
|
592
616
|
|
|
593
617
|
// src/engines/player/stage.js
|
|
594
|
-
function createStage(mount) {
|
|
618
|
+
function createStage(mount, background = {}) {
|
|
595
619
|
if (!mount) throw new Error("taleem-player: mount is required");
|
|
596
620
|
const root = typeof mount === "string" ? document.querySelector(mount) : mount;
|
|
597
621
|
if (!root) throw new Error("taleem-player: mount element not found");
|
|
@@ -601,15 +625,41 @@ function createStage(mount) {
|
|
|
601
625
|
stage.style.position = "relative";
|
|
602
626
|
stage.style.width = "100%";
|
|
603
627
|
stage.style.height = "100%";
|
|
628
|
+
stage.style.overflow = "hidden";
|
|
629
|
+
const bgLayer = document.createElement("div");
|
|
630
|
+
bgLayer.className = "taleem-player-bg";
|
|
631
|
+
bgLayer.style.position = "absolute";
|
|
632
|
+
bgLayer.style.inset = "0";
|
|
633
|
+
bgLayer.style.zIndex = "0";
|
|
634
|
+
bgLayer.style.backgroundRepeat = "no-repeat";
|
|
635
|
+
bgLayer.style.backgroundSize = "cover";
|
|
636
|
+
bgLayer.style.backgroundPosition = "center";
|
|
637
|
+
if (background.backgroundColor) {
|
|
638
|
+
bgLayer.style.backgroundColor = background.backgroundColor;
|
|
639
|
+
}
|
|
640
|
+
if (background.backgroundImage) {
|
|
641
|
+
bgLayer.style.backgroundImage = `url("${background.backgroundImage}")`;
|
|
642
|
+
}
|
|
643
|
+
if (typeof background.backgroundImageOpacity === "number" && background.backgroundImageOpacity < 1) {
|
|
644
|
+
bgLayer.style.opacity = String(background.backgroundImageOpacity);
|
|
645
|
+
}
|
|
646
|
+
const slideLayer = document.createElement("div");
|
|
647
|
+
slideLayer.className = "taleem-player-slides";
|
|
648
|
+
slideLayer.style.position = "relative";
|
|
649
|
+
slideLayer.style.zIndex = "1";
|
|
650
|
+
slideLayer.style.width = "100%";
|
|
651
|
+
slideLayer.style.height = "100%";
|
|
652
|
+
stage.appendChild(bgLayer);
|
|
653
|
+
stage.appendChild(slideLayer);
|
|
604
654
|
root.appendChild(stage);
|
|
605
655
|
function clear() {
|
|
606
|
-
|
|
656
|
+
slideLayer.innerHTML = "";
|
|
607
657
|
}
|
|
608
658
|
function destroy() {
|
|
609
659
|
root.innerHTML = "";
|
|
610
660
|
}
|
|
611
661
|
return {
|
|
612
|
-
el:
|
|
662
|
+
el: slideLayer,
|
|
613
663
|
clear,
|
|
614
664
|
destroy
|
|
615
665
|
};
|
|
@@ -617,7 +667,7 @@ function createStage(mount) {
|
|
|
617
667
|
|
|
618
668
|
// src/engines/player/player.js
|
|
619
669
|
function createTaleemPlayer({ mount, deck }) {
|
|
620
|
-
const stage = createStage(mount);
|
|
670
|
+
const stage = createStage(mount, deck.background);
|
|
621
671
|
let lastSlide = null;
|
|
622
672
|
let lastRenderedKey = null;
|
|
623
673
|
function getSlideAtTime(deck2, time) {
|
|
@@ -562,23 +562,47 @@ var TaleemPlayer = (() => {
|
|
|
562
562
|
type: "eq",
|
|
563
563
|
fromJSON(raw) {
|
|
564
564
|
const lines = raw.data?.filter((d) => d.name === "line").map((d) => ({
|
|
565
|
-
|
|
566
|
-
|
|
565
|
+
content: d.content,
|
|
566
|
+
spItems: Array.isArray(d.spItems) ? d.spItems : []
|
|
567
567
|
}));
|
|
568
568
|
if (!lines || lines.length === 0) {
|
|
569
569
|
throw new Error("eq: requires at least one line");
|
|
570
570
|
}
|
|
571
|
+
const WINDOW_SIZE = 4;
|
|
571
572
|
return Object.freeze({
|
|
572
573
|
type: "eq",
|
|
573
574
|
lines,
|
|
574
|
-
render({ visibleCount = lines.length, activeIndex =
|
|
575
|
+
render({ visibleCount = lines.length, activeIndex = -1 } = {}) {
|
|
576
|
+
const end = Math.min(visibleCount, lines.length);
|
|
577
|
+
const start = Math.max(0, end - WINDOW_SIZE);
|
|
578
|
+
const windowed = lines.slice(start, end);
|
|
579
|
+
const localActive = activeIndex >= start && activeIndex < end ? activeIndex - start : -1;
|
|
580
|
+
const activeSpItems = activeIndex >= 0 && activeIndex < lines.length ? lines[activeIndex].spItems : [];
|
|
575
581
|
return `
|
|
576
582
|
<section class="slide eq">
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
583
|
+
<div class="eq-layout">
|
|
584
|
+
|
|
585
|
+
<div class="eq-left">
|
|
586
|
+
${windowed.map(
|
|
587
|
+
(l, i) => `
|
|
588
|
+
<div class="eq-line ${i === localActive ? "is-active" : ""}">
|
|
589
|
+
${l.content}
|
|
590
|
+
</div>
|
|
591
|
+
`
|
|
592
|
+
).join("")}
|
|
593
|
+
</div>
|
|
594
|
+
|
|
595
|
+
<div class="eq-right">
|
|
596
|
+
${activeSpItems.map(
|
|
597
|
+
(sp) => `
|
|
598
|
+
<div class="eq-sp-item eq-${sp.type || "item"}">
|
|
599
|
+
${sp.content}
|
|
600
|
+
</div>
|
|
601
|
+
`
|
|
602
|
+
).join("")}
|
|
603
|
+
</div>
|
|
604
|
+
|
|
605
|
+
</div>
|
|
582
606
|
</section>
|
|
583
607
|
`;
|
|
584
608
|
}
|
|
@@ -621,7 +645,7 @@ var TaleemPlayer = (() => {
|
|
|
621
645
|
}
|
|
622
646
|
|
|
623
647
|
// src/engines/player/stage.js
|
|
624
|
-
function createStage(mount) {
|
|
648
|
+
function createStage(mount, background = {}) {
|
|
625
649
|
if (!mount) throw new Error("taleem-player: mount is required");
|
|
626
650
|
const root = typeof mount === "string" ? document.querySelector(mount) : mount;
|
|
627
651
|
if (!root) throw new Error("taleem-player: mount element not found");
|
|
@@ -631,15 +655,41 @@ var TaleemPlayer = (() => {
|
|
|
631
655
|
stage.style.position = "relative";
|
|
632
656
|
stage.style.width = "100%";
|
|
633
657
|
stage.style.height = "100%";
|
|
658
|
+
stage.style.overflow = "hidden";
|
|
659
|
+
const bgLayer = document.createElement("div");
|
|
660
|
+
bgLayer.className = "taleem-player-bg";
|
|
661
|
+
bgLayer.style.position = "absolute";
|
|
662
|
+
bgLayer.style.inset = "0";
|
|
663
|
+
bgLayer.style.zIndex = "0";
|
|
664
|
+
bgLayer.style.backgroundRepeat = "no-repeat";
|
|
665
|
+
bgLayer.style.backgroundSize = "cover";
|
|
666
|
+
bgLayer.style.backgroundPosition = "center";
|
|
667
|
+
if (background.backgroundColor) {
|
|
668
|
+
bgLayer.style.backgroundColor = background.backgroundColor;
|
|
669
|
+
}
|
|
670
|
+
if (background.backgroundImage) {
|
|
671
|
+
bgLayer.style.backgroundImage = `url("${background.backgroundImage}")`;
|
|
672
|
+
}
|
|
673
|
+
if (typeof background.backgroundImageOpacity === "number" && background.backgroundImageOpacity < 1) {
|
|
674
|
+
bgLayer.style.opacity = String(background.backgroundImageOpacity);
|
|
675
|
+
}
|
|
676
|
+
const slideLayer = document.createElement("div");
|
|
677
|
+
slideLayer.className = "taleem-player-slides";
|
|
678
|
+
slideLayer.style.position = "relative";
|
|
679
|
+
slideLayer.style.zIndex = "1";
|
|
680
|
+
slideLayer.style.width = "100%";
|
|
681
|
+
slideLayer.style.height = "100%";
|
|
682
|
+
stage.appendChild(bgLayer);
|
|
683
|
+
stage.appendChild(slideLayer);
|
|
634
684
|
root.appendChild(stage);
|
|
635
685
|
function clear() {
|
|
636
|
-
|
|
686
|
+
slideLayer.innerHTML = "";
|
|
637
687
|
}
|
|
638
688
|
function destroy() {
|
|
639
689
|
root.innerHTML = "";
|
|
640
690
|
}
|
|
641
691
|
return {
|
|
642
|
-
el:
|
|
692
|
+
el: slideLayer,
|
|
643
693
|
clear,
|
|
644
694
|
destroy
|
|
645
695
|
};
|
|
@@ -647,7 +697,7 @@ var TaleemPlayer = (() => {
|
|
|
647
697
|
|
|
648
698
|
// src/engines/player/player.js
|
|
649
699
|
function createTaleemPlayer({ mount, deck }) {
|
|
650
|
-
const stage = createStage(mount);
|
|
700
|
+
const stage = createStage(mount, deck.background);
|
|
651
701
|
let lastSlide = null;
|
|
652
702
|
let lastRenderedKey = null;
|
|
653
703
|
function getSlideAtTime(deck2, time) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "taleem-player",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/taleem-player.umd.js",
|
|
6
6
|
"module": "./dist/taleem-player.esm.js",
|
|
@@ -28,12 +28,13 @@
|
|
|
28
28
|
"test": "vitest run"
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"taleem-
|
|
32
|
-
"taleem-slides": "^0.6.2-rc.6"
|
|
31
|
+
"taleem-slides": "^1.0.1"
|
|
33
32
|
},
|
|
34
33
|
"devDependencies": {
|
|
35
34
|
"esbuild": "^0.27.2",
|
|
36
35
|
"jsdom": "^22.1.0",
|
|
37
|
-
"
|
|
36
|
+
"taleem-core": "^1.5.1",
|
|
37
|
+
"vitest": "^3.2.4",
|
|
38
|
+
"zod": "^4.3.6"
|
|
38
39
|
}
|
|
39
40
|
}
|