gooookim commited on
Commit
df6a1f4
·
verified ·
1 Parent(s): 50e379b

Update static/app.js

Browse files
Files changed (1) hide show
  1. static/app.js +44 -143
static/app.js CHANGED
@@ -1,169 +1,70 @@
1
- const slidesContainer = document.getElementById("slidesContainer");
2
- const audioPlayer = document.getElementById("audioPlayer");
3
- const playBtn = document.getElementById("playBtn");
4
- const stopBtn = document.getElementById("stopBtn");
5
- const speedSelect = document.getElementById("speedSelect");
6
- const statusText = document.getElementById("status");
7
 
8
- let slides = [];
9
- let currentIndex = 0;
10
- let isPlaying = false;
11
-
12
- function speedRate(value) {
13
- return {
14
- "1": 0.75,
15
- "2": 0.9,
16
- "3": 1.0,
17
- "4": 1.15,
18
- "5": 1.3
19
- }[value] || 1.0;
20
- }
21
-
22
- async function loadSlides() {
23
- try {
24
- const response = await fetch("/api/slides");
25
- slides = await response.json();
26
-
27
- renderSlides();
28
-
29
- statusText.textContent = `Ready · ${slides.length} slides`;
30
- } catch (error) {
31
- statusText.textContent = "Failed to load scripts.txt";
32
- console.error(error);
33
- }
34
- }
35
-
36
- function renderSlides() {
37
- slidesContainer.innerHTML = "";
38
-
39
- slides.forEach((slide, index) => {
40
- const div = document.createElement("section");
41
- div.className = "slide";
42
- div.dataset.index = index;
43
-
44
- div.innerHTML = `
45
- <div class="slide-title">${escapeHtml(slide.title)}</div>
46
- <div class="slide-text">${escapeHtml(slide.speech).replace(/\n/g, "<br>")}</div>
47
- `;
48
-
49
- slidesContainer.appendChild(div);
50
- });
51
- }
52
-
53
- function escapeHtml(text) {
54
- return text
55
- .replaceAll("&", "&amp;")
56
- .replaceAll("<", "&lt;")
57
- .replaceAll(">", "&gt;")
58
- .replaceAll('"', "&quot;")
59
- .replaceAll("'", "&#039;");
60
- }
61
-
62
- function highlightSlide(index) {
63
- document.querySelectorAll(".slide").forEach(el => {
64
- el.classList.remove("active");
65
- });
66
-
67
- const current = document.querySelector(`.slide[data-index="${index}"]`);
68
 
69
- if (!current) return;
70
 
71
- current.classList.add("active");
72
 
73
- current.scrollIntoView({
74
- behavior: "smooth",
75
- block: "center"
76
- });
77
- }
78
 
79
- function findCenterSlide() {
80
- const slideEls = document.querySelectorAll(".slide");
81
- const center = window.innerHeight / 2;
82
 
83
- let bestIndex = 0;
84
- let bestDistance = Infinity;
85
 
86
- slideEls.forEach((el, index) => {
87
- const rect = el.getBoundingClientRect();
88
- const slideCenter = rect.top + rect.height / 2;
89
- const distance = Math.abs(center - slideCenter);
90
-
91
- if (distance < bestDistance) {
92
- bestDistance = distance;
93
- bestIndex = index;
94
- }
95
- });
96
 
97
- return bestIndex;
98
- }
99
-
100
- function playSlide(index) {
101
- if (index >= slides.length) {
102
- isPlaying = false;
103
- statusText.textContent = "Finished";
104
  return;
105
  }
106
 
107
- currentIndex = index;
108
-
109
- const slide = slides[index];
110
-
111
- highlightSlide(index);
112
 
113
- statusText.textContent = `Reading ${index + 1}/${slides.length}`;
114
 
115
- audioPlayer.pause();
116
- audioPlayer.currentTime = 0;
117
-
118
- audioPlayer.src = slide.audio;
119
- audioPlayer.playbackRate = speedRate(speedSelect.value);
120
-
121
- audioPlayer.play().catch(err => {
122
- statusText.textContent = "Audio play failed";
123
- console.error(err);
124
- });
125
  }
126
 
127
- playBtn.addEventListener("click", () => {
128
- if (isPlaying) return;
129
-
130
- currentIndex = findCenterSlide();
131
-
132
- isPlaying = true;
133
 
134
- playSlide(currentIndex);
135
- });
136
 
137
- stopBtn.addEventListener("click", () => {
138
- isPlaying = false;
139
 
140
- audioPlayer.pause();
141
- audioPlayer.currentTime = 0;
 
 
142
 
143
- statusText.textContent = "Stopped";
144
- });
145
 
146
- audioPlayer.addEventListener("ended", () => {
147
- if (!isPlaying) return;
148
 
149
- playSlide(currentIndex + 1);
150
- });
151
 
152
- speedSelect.addEventListener("change", () => {
153
- audioPlayer.playbackRate = speedRate(speedSelect.value);
154
- });
155
 
156
- let scrollTimer = null;
 
 
 
157
 
158
- window.addEventListener("scroll", () => {
159
- if (isPlaying) return;
160
-
161
- clearTimeout(scrollTimer);
162
-
163
- scrollTimer = setTimeout(() => {
164
- currentIndex = findCenterSlide();
165
- statusText.textContent = `Ready · Start from Slide ${currentIndex + 1}`;
166
- }, 120);
167
- });
168
 
169
  loadSlides();
 
1
+ const slidesContainer =
2
+ document.getElementById(
3
+ "slidesContainer"
4
+ );
 
 
5
 
6
+ const statusText =
7
+ document.getElementById(
8
+ "status"
9
+ );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10
 
11
+ let slides = [];
12
 
13
+ async function loadSlides(){
14
 
15
+ const res =
16
+ await fetch("/api/slides");
 
 
 
17
 
18
+ const data =
19
+ await res.json();
 
20
 
21
+ if(data.error){
 
22
 
23
+ statusText.textContent =
24
+ data.error;
 
 
 
 
 
 
 
 
25
 
 
 
 
 
 
 
 
26
  return;
27
  }
28
 
29
+ slides = data;
 
 
 
 
30
 
31
+ renderSlides();
32
 
33
+ statusText.textContent =
34
+ `Loaded ${slides.length} slides`;
 
 
 
 
 
 
 
 
35
  }
36
 
37
+ function renderSlides(){
 
 
 
 
 
38
 
39
+ slidesContainer.innerHTML="";
 
40
 
41
+ slides.forEach(slide=>{
 
42
 
43
+ const div =
44
+ document.createElement(
45
+ "div"
46
+ );
47
 
48
+ div.className =
49
+ "slide";
50
 
51
+ div.dataset.index =
52
+ slide.index;
53
 
54
+ div.innerHTML =
 
55
 
56
+ `<div class="slide-title">
57
+ ${slide.title}
58
+ </div>
59
 
60
+ <div class="slide-text">
61
+ ${slide.speech
62
+ .replace(/\n/g,"<br>")}
63
+ </div>`;
64
 
65
+ slidesContainer
66
+ .appendChild(div);
67
+ });
68
+ }
 
 
 
 
 
 
69
 
70
  loadSlides();