NeuralFalcon commited on
Commit
541e778
·
verified ·
1 Parent(s): b7c43fd

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +232 -175
index.html CHANGED
@@ -1,45 +1,72 @@
1
  <!DOCTYPE html>
2
- <html lang="en">
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>Italian Brinarot</title>
7
  <script src="https://cdn.tailwindcss.com"></script>
8
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
9
  <style>
10
  @import url('https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap');
11
 
 
12
  body {
13
  font-family: 'Poppins', sans-serif;
14
- background: linear-gradient(135deg, #f5f7fa 0%, #e4e8f0 100%);
 
 
 
 
 
 
 
 
 
 
 
15
  }
16
 
17
  .character-card {
18
  transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
19
  perspective: 1000px;
 
20
  }
21
 
22
  .character-card:hover {
23
  transform: translateY(-8px);
24
- box-shadow: 0 15px 30px rgba(0,0,0,0.12);
 
25
  }
26
 
 
 
27
  .image-container {
28
- /* REMOVED clip-path: circle(50% at 50% 50%); */
29
- background: linear-gradient(145deg, #ffffff, #e6e6e6);
30
- box-shadow: 0 4px 15px rgba(0,0,0,0.1);
31
- /* Tailwind classes will handle rounding and overflow */
 
 
 
 
32
  }
33
 
 
34
  .play-btn {
35
  transition: all 0.2s ease;
36
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
37
  }
 
 
 
38
 
39
  .play-btn:hover {
40
  transform: translateY(-2px);
41
  box-shadow: 0 5px 15px rgba(118, 75, 162, 0.4);
42
  }
 
 
 
43
 
44
  .play-btn:active {
45
  transform: translateY(0);
@@ -51,247 +78,277 @@
51
  background-clip: text;
52
  color: transparent;
53
  }
 
 
 
54
 
55
  .header-divider {
56
  height: 4px;
57
  background: linear-gradient(90deg, #667eea 0%, #764ba2 100%);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
58
  }
 
 
 
59
 
60
  @media (max-width: 640px) {
61
  .character-name {
62
- font-size: 1rem;
 
 
 
63
  }
 
 
 
64
  }
65
  </style>
66
  </head>
67
- <body class="min-h-screen">
68
- <div class="container mx-auto px-4 py-8">
 
 
 
 
 
 
 
69
  <!-- Header -->
70
- <header class="text-center mb-12">
71
- <h1 class="text-4xl md:text-5xl font-bold gradient-text mb-2">Italian Brinarot</h1>
72
- <div class="header-divider w-32 mx-auto rounded-full mb-6"></div>
73
- <p class="text-gray-600 max-w-2xl mx-auto">Discover the magical sounds of Italian Brinarot characters</p>
 
 
74
  </header>
75
 
76
  <!-- Character Grid -->
77
- <div id="characterGrid" class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-8"></div>
 
 
78
  </div>
79
 
80
  <!-- Embedded Character Data -->
81
  <script>
82
  const characterData = {
83
- "Bombardiro Crocodilo": {
84
- "image_path": "./assets/Bombardiro_Crocodilo.png",
85
- "audio_path": "./assets/Bombardiro_Crocodilo.wav"
86
- },
87
- "Tralalero Tralala": {
88
- "image_path": "./assets/Tralalero_Tralala.png",
89
- "audio_path": "./assets/Tralalero_Tralala.wav"
90
- },
91
- "Bombombini Gusini": {
92
- "image_path": "./assets/Bombombini_Gusini.png",
93
- "audio_path": "./assets/Bombombini_Gusini.wav"
94
- },
95
- "Tung Tung Tung Tung Tung Tung Tung Tung Tung Sahur": {
96
- "image_path": "./assets/Tung_Tung_Tung_Tung_Tung_Tung_Tung_Tung_Tung_Sahur.png",
97
- "audio_path": "./assets/Tung_Tung_Tung_Tung_Tung_Tung_Tung_Tung_Tung_Sahur.wav"
98
- },
99
- "Brr Brr Patapim": {
100
- "image_path": "./assets/Brr_Brr_Patapim.png",
101
- "audio_path": "./assets/Brr_Brr_Patapim.wav"
102
- },
103
- "Cappuccino Assassino": {
104
- "image_path": "./assets/Cappuccino_Assassino.png",
105
- "audio_path": "./assets/Cappuccino_Assassino.wav"
106
- },
107
- "Lirili Larila": {
108
- "image_path": "./assets/Lirili_Larila.png",
109
- "audio_path": "./assets/Lirili_Larila.wav"
110
- },
111
- "Trulimero Trulichina": {
112
- "image_path": "./assets/Trulimero_Trulichina.png",
113
- "audio_path": "./assets/Trulimero_Trulichina.wav"
114
- },
115
- "Boneca Ambalabu": {
116
- "image_path": "./assets/Boneca_Ambalabu.png",
117
- "audio_path": "./assets/Boneca_Ambalabu.wav"
118
- },
119
- "Chimpanzini Bananini": {
120
- "image_path": "./assets/Chimpanzini_Bananini.png",
121
- "audio_path": "./assets/Chimpanzini_Bananini.wav"
122
- },
123
- "Bananita Dolfinita": {
124
- "image_path": "./assets/Bananita_Dolfinita.png",
125
- "audio_path": "./assets/Bananita_Dolfinita.wav"
126
- },
127
- "Bluberini Octopusini": {
128
- "image_path": "./assets/Bluberini_Octopusini.png",
129
- "audio_path": "./assets/Bluberini_Octopusini.wav"
130
- },
131
- "Bobrito Bandito": {
132
- "image_path": "./assets/Bobrito_Bandito.png",
133
- "audio_path": "./assets/Bobrito_Bandito.wav"
134
- },
135
- "Brri Brri Bicus Dicus": {
136
- "image_path": "./assets/Brri_Brri_Bicus_Dicus.png",
137
- "audio_path": "./assets/Brri_Brri_Bicus_Dicus.wav"
138
- },
139
- "Burbaloni Luliloli": {
140
- "image_path": "./assets/Burbaloni_Luliloli.png",
141
- "audio_path": "./assets/Burbaloni_Luliloli.wav"
142
- },
143
- "Chimpanzini Annasini": {
144
- "image_path": "./assets/Chimpanzini_Annasini.png",
145
- "audio_path": "./assets/Chimpanzini_Annasini.wav"
146
- },
147
- "Chimpanzini Cocosini": {
148
- "image_path": "./assets/Chimpanzini_Cocosini.png",
149
- "audio_path": "./assets/Chimpanzini_Cocosini.wav"
150
- },
151
- "Cocofanto Elefanto": {
152
- "image_path": "./assets/Cocofanto_Elefanto.png",
153
- "audio_path": "./assets/Cocofanto_Elefanto.wav"
154
- },
155
- "Frigo Camelo Buffardello": {
156
- "image_path": "./assets/frigo_camelo_buffardello.png",
157
- "audio_path": "./assets/frigo_camelo_buffardello.wav"
158
- },
159
- "Giraffe Celeste": {
160
- "image_path": "./assets/Giraffe_Celeste.png",
161
- "audio_path": "./assets/Giraffe_Celeste.wav"
162
- },
163
- "Glorbo Fruttodrillo": {
164
- "image_path": "./assets/Glorbo_Fruttodrillo.png",
165
- "audio_path": "./assets/Glorbo_Fruttodrillo.wav"
166
- },
167
- "Il Cacto Hipopotoma": {
168
- "image_path": "./assets/il_cacto_hipopotoma.png",
169
- "audio_path": "./assets/il_cacto_hipopotoma.wav"
170
- },
171
- "Trippi Troppi Troppa Trippa": {
172
- "image_path": "./assets/Trippi_Troppi_Troppa_Trippa.png",
173
- "audio_path": "./assets/Trippi_Troppi_Troppa_Trippa.wav"
174
- }
175
  };
176
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
177
  // Function to load and display characters
178
  function loadCharacters() {
179
- const characterGrid = document.getElementById('characterGrid');
180
-
181
- // Clear any existing content
182
- characterGrid.innerHTML = '';
183
 
184
- // Create cards for each character
185
  Object.entries(characterData).forEach(([name, data]) => {
186
  const card = document.createElement('div');
187
- card.className = 'character-card bg-white rounded-2xl overflow-hidden shadow-md flex flex-col items-center p-6';
188
-
189
- // Image container - **MODIFIED** for square with rounded corners
 
 
 
 
 
 
 
 
 
190
  const imageContainer = document.createElement('div');
191
- // Added rounded-xl (you can change this) and overflow-hidden
192
- imageContainer.className = 'image-container mb-4 w-40 h-40 flex items-center justify-center rounded-2xl overflow-hidden'; // <-- MODIFIED LINE
 
 
 
 
193
 
194
  const image = document.createElement('img');
195
  image.src = data.image_path.replace(/\\/g, '/');
196
  image.alt = name;
197
- image.className = 'w-full h-full object-cover'; // object-cover ensures the image fills the square container
 
 
 
 
198
  imageContainer.appendChild(image);
199
 
200
  // Character name
201
  const nameElement = document.createElement('h3');
202
- nameElement.className = 'character-name text-lg md:text-xl font-semibold text-gray-800 mb-3 text-center';
 
 
 
 
203
  nameElement.textContent = name;
204
 
205
  // Play/Pause button
206
  const playButton = document.createElement('button');
207
- // **MODIFIED** - Adjusted button gradient for better contrast/look (Optional)
208
- playButton.className = 'play-btn text-white font-medium py-2 px-6 rounded-full flex items-center';
 
 
 
209
 
210
  const playIcon = document.createElement('i');
211
- playIcon.className = 'fas fa-play mr-2';
212
 
213
  playButton.appendChild(playIcon);
214
  playButton.appendChild(document.createTextNode('Play'));
215
 
216
- // Audio element
217
  const audio = new Audio(data.audio_path.replace(/\\/g, '/'));
218
- let isPlaying = false;
 
 
 
 
 
 
 
219
 
220
- // Keep track of all audios and buttons to manage pause state
221
- let currentAudio = null;
222
- let currentButton = null;
223
 
224
- // Play/Pause button click handler - **REVISED** for better pause handling
225
  playButton.addEventListener('click', () => {
226
- // Stop any other audio that might be playing
227
- document.querySelectorAll('audio').forEach(a => {
228
- if (a !== audio && !a.paused) {
229
- a.pause();
230
- // Reset the button associated with that audio
231
- const relatedButton = a.nextElementSibling; // Assuming button is the next sibling
232
- if (relatedButton && relatedButton.classList.contains('play-btn')) {
233
- relatedButton.innerHTML = '<i class="fas fa-play mr-2"></i>Play';
234
- relatedButton.style.background = 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)'; // Reset background
235
- // Find the 'isPlaying' state for that audio (more complex, simplified here)
236
- }
237
- }
238
- });
239
- // Find *all* buttons and reset their state visually if they aren't the current one
240
- document.querySelectorAll('.play-btn').forEach(btn => {
241
- if (btn !== playButton && !btn.previousElementSibling.paused) { // Check if audio associated with *other* button is playing
242
- // This part is tricky without a direct link; the logic below handles the active one better.
243
- } else if (btn !== playButton) {
244
- btn.innerHTML = '<i class="fas fa-play mr-2"></i>Play';
245
- btn.style.background = 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)';
246
- }
247
- });
248
-
249
-
250
- if (isPlaying) {
251
  audio.pause();
 
 
 
252
  playButton.innerHTML = '<i class="fas fa-play mr-2"></i>Play';
253
- playButton.style.background = 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)'; // Reset background
254
- isPlaying = false;
255
- currentAudio = null;
256
- currentButton = null;
257
  } else {
 
 
 
 
 
 
 
 
 
 
 
258
  audio.currentTime = 0;
259
- audio.play();
 
 
 
260
  playButton.innerHTML = '<i class="fas fa-pause mr-2"></i>Pause';
261
- playButton.style.background = '#ef4444'; // Example: Red background for pause state
262
- isPlaying = true;
263
- currentAudio = audio;
264
- currentButton = playButton;
265
  }
266
  });
267
 
268
- // When audio ends, reset button
269
  audio.addEventListener('ended', () => {
270
- playButton.innerHTML = '<i class="fas fa-play mr-2"></i>Play';
271
- playButton.style.background = 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)'; // Reset background
272
- isPlaying = false;
273
- currentAudio = null;
274
- currentButton = null;
 
275
  });
 
 
276
 
277
  // Assemble the card
278
  card.appendChild(imageContainer);
279
  card.appendChild(nameElement);
280
- card.appendChild(audio); // Keep audio in DOM for easier access if needed, hide it
281
- audio.style.display = 'none';
282
  card.appendChild(playButton);
283
-
284
 
285
  // Add card to the grid
286
  characterGrid.appendChild(card);
287
  });
 
 
 
 
 
 
 
288
 
289
- // Improved pause handling: Add a global listener if needed, or rely on the button click logic above.
290
- // The revised click handler above should now pause other audios when a new one is played.
 
 
 
 
291
  }
292
 
293
- // Load characters when the page loads
 
 
 
294
  window.addEventListener('DOMContentLoaded', loadCharacters);
 
295
  </script>
296
  </body>
297
  </html>
 
1
  <!DOCTYPE html>
2
+ <html lang="en" class=""> <!-- Start without 'dark' class -->
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Italian Brinarot - Soundboard</title>
7
  <script src="https://cdn.tailwindcss.com"></script>
8
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
9
  <style>
10
  @import url('https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap');
11
 
12
+ /* Base styles */
13
  body {
14
  font-family: 'Poppins', sans-serif;
15
+ /* Smooth transition for theme changes */
16
+ @apply transition-colors duration-300 ease-in-out;
17
+ }
18
+
19
+ /* Light theme base */
20
+ body {
21
+ background: linear-gradient(135deg, #f5f7fa 0%, #e4e8f0 100%);
22
+ }
23
+
24
+ /* Dark theme base */
25
+ .dark body {
26
+ background: linear-gradient(135deg, #1f2937 0%, #111827 100%); /* Dark gradient */
27
  }
28
 
29
  .character-card {
30
  transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
31
  perspective: 1000px;
32
+ @apply transition-colors duration-300 ease-in-out; /* Transition background */
33
  }
34
 
35
  .character-card:hover {
36
  transform: translateY(-8px);
37
+ /* Enhanced hover shadow for both themes */
38
+ @apply shadow-xl dark:shadow-2xl dark:shadow-indigo-500/20;
39
  }
40
 
41
+ /* Specific light/dark styles will be applied via Tailwind classes directly */
42
+
43
  .image-container {
44
+ /* Keep the gradient or simplify */
45
+ background: linear-gradient(145deg, #ffffff, #e6e6e6);
46
+ box-shadow: 0 4px 15px rgba(0,0,0,0.08);
47
+ @apply transition-colors duration-300 ease-in-out;
48
+ }
49
+ .dark .image-container {
50
+ background: linear-gradient(145deg, #4b5563, #374151); /* Darker bg for image */
51
+ box-shadow: 0 4px 15px rgba(0,0,0,0.2);
52
  }
53
 
54
+
55
  .play-btn {
56
  transition: all 0.2s ease;
57
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
58
  }
59
+ .play-btn.playing {
60
+ background: linear-gradient(135deg, #ef4444 0%, #dc2626 100%); /* Red gradient for playing */
61
+ }
62
 
63
  .play-btn:hover {
64
  transform: translateY(-2px);
65
  box-shadow: 0 5px 15px rgba(118, 75, 162, 0.4);
66
  }
67
+ .play-btn.playing:hover {
68
+ box-shadow: 0 5px 15px rgba(239, 68, 68, 0.4); /* Red shadow */
69
+ }
70
 
71
  .play-btn:active {
72
  transform: translateY(0);
 
78
  background-clip: text;
79
  color: transparent;
80
  }
81
+ /* Optional: Slightly adjust gradient text for dark mode if needed */
82
+ /* .dark .gradient-text { ... } */
83
+
84
 
85
  .header-divider {
86
  height: 4px;
87
  background: linear-gradient(90deg, #667eea 0%, #764ba2 100%);
88
+ @apply transition-all duration-300 ease-in-out;
89
+ }
90
+ .dark .header-divider {
91
+ background: linear-gradient(90deg, #818cf8 0%, #a78bfa 100%); /* Brighter gradient for dark */
92
+ }
93
+
94
+ /* Theme toggle button */
95
+ #theme-toggle {
96
+ @apply fixed top-5 right-5 z-50;
97
+ @apply w-12 h-12 rounded-full ;
98
+ @apply flex items-center justify-center;
99
+ @apply bg-white/80 dark:bg-gray-800/80 backdrop-blur-sm; /* Semi-transparent background */
100
+ @apply text-gray-600 dark:text-gray-300;
101
+ @apply hover:bg-white dark:hover:bg-gray-700;
102
+ @apply shadow-md hover:shadow-lg;
103
+ @apply transition-all duration-300 ease-in-out;
104
+ @apply cursor-pointer;
105
  }
106
+ #theme-toggle i {
107
+ @apply text-xl;
108
+ }
109
 
110
  @media (max-width: 640px) {
111
  .character-name {
112
+ font-size: 1rem; /* Already adjusted */
113
+ }
114
+ #theme-toggle {
115
+ @apply top-3 right-3 w-10 h-10; /* Smaller on mobile */
116
  }
117
+ #theme-toggle i {
118
+ @apply text-lg;
119
+ }
120
  }
121
  </style>
122
  </head>
123
+ <body class="min-h-screen"> <!-- Body class will be updated by JS -->
124
+
125
+ <!-- Theme Toggle Button -->
126
+ <button id="theme-toggle" aria-label="Toggle dark mode">
127
+ <i class="fas fa-moon"></i> <!-- Moon icon for light theme -->
128
+ <i class="fas fa-sun hidden"></i> <!-- Sun icon for dark theme -->
129
+ </button>
130
+
131
+ <div class="container mx-auto px-4 py-12 md:py-16">
132
  <!-- Header -->
133
+ <header class="text-center mb-12 md:mb-16">
134
+ <h1 class="text-4xl md:text-5xl lg:text-6xl font-bold gradient-text mb-3">Italian Brinarot</h1>
135
+ <div class="header-divider w-32 md:w-40 mx-auto rounded-full mb-6"></div>
136
+ <p class="text-lg text-gray-600 dark:text-gray-400 max-w-2xl mx-auto">
137
+ Discover the magical sounds of Italian Brinarot characters
138
+ </p>
139
  </header>
140
 
141
  <!-- Character Grid -->
142
+ <div id="characterGrid" class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-8">
143
+ <!-- Character cards will be injected here by JS -->
144
+ </div>
145
  </div>
146
 
147
  <!-- Embedded Character Data -->
148
  <script>
149
  const characterData = {
150
+ // ... (Keep your characterData object exactly the same)
151
+ "Bombardiro Crocodilo": { "image_path": "./assets/Bombardiro_Crocodilo.png", "audio_path": "./assets/Bombardiro_Crocodilo.wav" },
152
+ "Tralalero Tralala": { "image_path": "./assets/Tralalero_Tralala.png", "audio_path": "./assets/Tralalero_Tralala.wav" },
153
+ "Bombombini Gusini": { "image_path": "./assets/Bombombini_Gusini.png", "audio_path": "./assets/Bombombini_Gusini.wav" },
154
+ "Tung Tung Tung Tung Tung Tung Tung Tung Tung Sahur": { "image_path": "./assets/Tung_Tung_Tung_Tung_Tung_Tung_Tung_Tung_Tung_Sahur.png", "audio_path": "./assets/Tung_Tung_Tung_Tung_Tung_Tung_Tung_Tung_Tung_Sahur.wav" },
155
+ "Brr Brr Patapim": { "image_path": "./assets/Brr_Brr_Patapim.png", "audio_path": "./assets/Brr_Brr_Patapim.wav" },
156
+ "Cappuccino Assassino": { "image_path": "./assets/Cappuccino_Assassino.png", "audio_path": "./assets/Cappuccino_Assassino.wav" },
157
+ "Lirili Larila": { "image_path": "./assets/Lirili_Larila.png", "audio_path": "./assets/Lirili_Larila.wav" },
158
+ "Trulimero Trulichina": { "image_path": "./assets/Trulimero_Trulichina.png", "audio_path": "./assets/Trulimero_Trulichina.wav" },
159
+ "Boneca Ambalabu": { "image_path": "./assets/Boneca_Ambalabu.png", "audio_path": "./assets/Boneca_Ambalabu.wav" },
160
+ "Chimpanzini Bananini": { "image_path": "./assets/Chimpanzini_Bananini.png", "audio_path": "./assets/Chimpanzini_Bananini.wav" },
161
+ "Bananita Dolfinita": { "image_path": "./assets/Bananita_Dolfinita.png", "audio_path": "./assets/Bananita_Dolfinita.wav" },
162
+ "Bluberini Octopusini": { "image_path": "./assets/Bluberini_Octopusini.png", "audio_path": "./assets/Bluberini_Octopusini.wav" },
163
+ "Bobrito Bandito": { "image_path": "./assets/Bobrito_Bandito.png", "audio_path": "./assets/Bobrito_Bandito.wav" },
164
+ "Brri Brri Bicus Dicus": { "image_path": "./assets/Brri_Brri_Bicus_Dicus.png", "audio_path": "./assets/Brri_Brri_Bicus_Dicus.wav" },
165
+ "Burbaloni Luliloli": { "image_path": "./assets/Burbaloni_Luliloli.png", "audio_path": "./assets/Burbaloni_Luliloli.wav" },
166
+ "Chimpanzini Annasini": { "image_path": "./assets/Chimpanzini_Annasini.png", "audio_path": "./assets/Chimpanzini_Annasini.wav" },
167
+ "Chimpanzini Cocosini": { "image_path": "./assets/Chimpanzini_Cocosini.png", "audio_path": "./assets/Chimpanzini_Cocosini.wav" },
168
+ "Cocofanto Elefanto": { "image_path": "./assets/Cocofanto_Elefanto.png", "audio_path": "./assets/Cocofanto_Elefanto.wav" },
169
+ "Frigo Camelo Buffardello": { "image_path": "./assets/frigo_camelo_buffardello.png", "audio_path": "./assets/frigo_camelo_buffardello.wav" },
170
+ "Giraffe Celeste": { "image_path": "./assets/Giraffe_Celeste.png", "audio_path": "./assets/Giraffe_Celeste.wav" },
171
+ "Glorbo Fruttodrillo": { "image_path": "./assets/Glorbo_Fruttodrillo.png", "audio_path": "./assets/Glorbo_Fruttodrillo.wav" },
172
+ "Il Cacto Hipopotoma": { "image_path": "./assets/il_cacto_hipopotoma.png", "audio_path": "./assets/il_cacto_hipopotoma.wav" },
173
+ "Trippi Troppi Troppa Trippa": { "image_path": "./assets/Trippi_Troppi_Troppa_Trippa.png", "audio_path": "./assets/Trippi_Troppi_Troppa_Trippa.wav" }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
174
  };
175
 
176
+ const characterGrid = document.getElementById('characterGrid');
177
+ const themeToggleButton = document.getElementById('theme-toggle');
178
+ const sunIcon = themeToggleButton.querySelector('.fa-sun');
179
+ const moonIcon = themeToggleButton.querySelector('.fa-moon');
180
+ const htmlElement = document.documentElement; // Target <html> for dark class
181
+
182
+ let currentlyPlayingAudio = null;
183
+ let currentlyPlayingButton = null;
184
+
185
+ // Function to apply the theme
186
+ function applyTheme(theme) {
187
+ if (theme === 'dark') {
188
+ htmlElement.classList.add('dark');
189
+ moonIcon.classList.add('hidden');
190
+ sunIcon.classList.remove('hidden');
191
+ localStorage.setItem('theme', 'dark');
192
+ } else {
193
+ htmlElement.classList.remove('dark');
194
+ moonIcon.classList.remove('hidden');
195
+ sunIcon.classList.add('hidden');
196
+ localStorage.setItem('theme', 'light');
197
+ }
198
+ }
199
+
200
+ // Function to toggle the theme
201
+ function toggleTheme() {
202
+ const currentTheme = htmlElement.classList.contains('dark') ? 'dark' : 'light';
203
+ applyTheme(currentTheme === 'dark' ? 'light' : 'dark');
204
+ }
205
+
206
  // Function to load and display characters
207
  function loadCharacters() {
208
+ characterGrid.innerHTML = ''; // Clear existing
 
 
 
209
 
 
210
  Object.entries(characterData).forEach(([name, data]) => {
211
  const card = document.createElement('div');
212
+ // Apply base and dark mode classes using Tailwind
213
+ card.className = `
214
+ character-card
215
+ bg-white dark:bg-gray-800
216
+ rounded-2xl overflow-hidden
217
+ shadow-md hover:shadow-xl dark:hover:shadow-2xl dark:hover:shadow-indigo-500/20
218
+ border border-gray-200 dark:border-gray-700/50
219
+ flex flex-col items-center p-6
220
+ transition-all duration-300 ease-in-out
221
+ `;
222
+
223
+ // Image container
224
  const imageContainer = document.createElement('div');
225
+ imageContainer.className = `
226
+ image-container mb-5 w-40 h-40 lg:w-44 lg:h-44
227
+ flex items-center justify-center
228
+ rounded-2xl overflow-hidden
229
+ border-4 border-white/50 dark:border-gray-700/50
230
+ `; // Added slightly larger size on larger screens and border
231
 
232
  const image = document.createElement('img');
233
  image.src = data.image_path.replace(/\\/g, '/');
234
  image.alt = name;
235
+ image.className = 'w-full h-full object-cover';
236
+ image.onerror = () => { // Basic error handling for images
237
+ image.src = 'placeholder.png'; // Provide a fallback image path
238
+ console.warn(`Image not found: ${data.image_path}`);
239
+ };
240
  imageContainer.appendChild(image);
241
 
242
  // Character name
243
  const nameElement = document.createElement('h3');
244
+ nameElement.className = `
245
+ character-name text-lg md:text-xl font-semibold
246
+ text-gray-800 dark:text-gray-100
247
+ mb-4 text-center transition-colors duration-300
248
+ `;
249
  nameElement.textContent = name;
250
 
251
  // Play/Pause button
252
  const playButton = document.createElement('button');
253
+ playButton.className = `
254
+ play-btn text-white font-medium py-2.5 px-7
255
+ rounded-full flex items-center justify-center
256
+ w-32 /* Fixed width for consistency */
257
+ `;
258
 
259
  const playIcon = document.createElement('i');
260
+ playIcon.className = 'fas fa-play mr-2'; // Start with play
261
 
262
  playButton.appendChild(playIcon);
263
  playButton.appendChild(document.createTextNode('Play'));
264
 
265
+ // Audio element (keep it hidden)
266
  const audio = new Audio(data.audio_path.replace(/\\/g, '/'));
267
+ audio.preload = 'metadata'; // Improve loading slightly
268
+ audio.style.display = 'none';
269
+ audio.onerror = () => {
270
+ console.error(`Error loading audio: ${data.audio_path}`);
271
+ playButton.disabled = true; // Disable button if audio fails
272
+ playButton.textContent = 'Error';
273
+ playButton.classList.add('opacity-50', 'cursor-not-allowed');
274
+ };
275
 
 
 
 
276
 
277
+ // --- Refined Play/Pause Logic ---
278
  playButton.addEventListener('click', () => {
279
+ // If this audio is currently playing, pause it
280
+ if (currentlyPlayingAudio === audio) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
281
  audio.pause();
282
+ currentlyPlayingAudio = null;
283
+ currentlyPlayingButton = null;
284
+ // Reset this button visually
285
  playButton.innerHTML = '<i class="fas fa-play mr-2"></i>Play';
286
+ playButton.classList.remove('playing');
 
 
 
287
  } else {
288
+ // If another audio is playing, stop it first
289
+ if (currentlyPlayingAudio) {
290
+ currentlyPlayingAudio.pause();
291
+ currentlyPlayingAudio.currentTime = 0; // Reset time
292
+ // Reset the *other* button visually
293
+ if (currentlyPlayingButton) {
294
+ currentlyPlayingButton.innerHTML = '<i class="fas fa-play mr-2"></i>Play';
295
+ currentlyPlayingButton.classList.remove('playing');
296
+ }
297
+ }
298
+ // Now play this audio
299
  audio.currentTime = 0;
300
+ audio.play().catch(e => console.error("Audio play failed:", e)); // Catch potential play errors
301
+ currentlyPlayingAudio = audio;
302
+ currentlyPlayingButton = playButton;
303
+ // Update this button visually to 'Pause'
304
  playButton.innerHTML = '<i class="fas fa-pause mr-2"></i>Pause';
305
+ playButton.classList.add('playing');
 
 
 
306
  }
307
  });
308
 
309
+ // When audio naturally ends, reset the button
310
  audio.addEventListener('ended', () => {
311
+ if (currentlyPlayingAudio === audio) { // Ensure it's the one that just ended
312
+ playButton.innerHTML = '<i class="fas fa-play mr-2"></i>Play';
313
+ playButton.classList.remove('playing');
314
+ currentlyPlayingAudio = null;
315
+ currentlyPlayingButton = null;
316
+ }
317
  });
318
+ // --- End Refined Play/Pause Logic ---
319
+
320
 
321
  // Assemble the card
322
  card.appendChild(imageContainer);
323
  card.appendChild(nameElement);
 
 
324
  card.appendChild(playButton);
325
+ card.appendChild(audio); // Add hidden audio element
326
 
327
  // Add card to the grid
328
  characterGrid.appendChild(card);
329
  });
330
+ }
331
+
332
+ // --- Initialization ---
333
+
334
+ // 1. Set initial theme based on localStorage or system preference
335
+ const savedTheme = localStorage.getItem('theme');
336
+ const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
337
 
338
+ if (savedTheme) {
339
+ applyTheme(savedTheme);
340
+ } else if (prefersDark) {
341
+ applyTheme('dark');
342
+ } else {
343
+ applyTheme('light'); // Default to light
344
  }
345
 
346
+ // 2. Add listener for the theme toggle button
347
+ themeToggleButton.addEventListener('click', toggleTheme);
348
+
349
+ // 3. Load characters when the page loads
350
  window.addEventListener('DOMContentLoaded', loadCharacters);
351
+
352
  </script>
353
  </body>
354
  </html>