Skip to content

Commit c92e416

Browse files
authored
DAB: Implement audio link clips (#930)
* TEMP: found where to process audio-link * Update to clickable icon to play audio * Fix position of audio icon * Switch audio UI element from anchor to button
1 parent b7f8277 commit c92e416

1 file changed

Lines changed: 32 additions & 2 deletions

File tree

src/lib/lexicon/components/EntryView.svelte

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,12 @@
1010
} from '$lib/data/stores/lexicon.svelte';
1111
import type { SqlValue } from 'sql.js';
1212
13+
const clips = import.meta.glob('./*', {
14+
import: 'default',
15+
eager: true,
16+
base: '/src/gen-assets/clips'
17+
}) as Record<string, string>;
18+
1319
interface Props {
1420
wordIds: number[] | null;
1521
onSelectWord: (word: SelectedWord) => void;
@@ -27,7 +33,6 @@
2733
const dynamicQuery = wordIds.map(() => `id = ?`).join(' OR ');
2834
const dynamicParams = wordIds.map((id) => id);
2935
const results = db.exec(`SELECT xml FROM entries WHERE ${dynamicQuery}`, dynamicParams);
30-
console.log('results:', results[0].values);
3136
3237
return results[0].values;
3338
} catch (error) {
@@ -42,6 +47,9 @@
4247
const parser = new DOMParser();
4348
const xmlDoc = parser.parseFromString(xmlString, 'text/xml');
4449
50+
// Collect audio elements to add at the end
51+
let audioElements = '';
52+
4553
const parseError = xmlDoc.querySelector('parsererror');
4654
if (parseError) {
4755
console.error('XML parsing error:', parseError.textContent);
@@ -89,6 +97,17 @@
8997
9098
output += `<span class="clickable cursor-pointer" style="background-color: var(--BackgroundColor);" data-word="${word}" data-index="${index}" data-homonym="${homonymIndex}">${linkText}</span>`;
9199
}
100+
} else if (node.tagName === 'audio-link' && node.hasAttribute('src')) {
101+
// Handle audio-link tag - create audio element and clickable link
102+
const audioFile = node.getAttribute('src');
103+
const src = clips[`./${audioFile}`] ?? 'clips/' + audioFile;
104+
const audioId = 'audio-' + Math.random().toString(36).substr(2, 9); // Generate unique ID
105+
106+
// Collect audio element to add at the very end
107+
audioElements += `<audio id="${audioId}" src="${src}" preload="auto" style="display: none;"></audio>`;
108+
109+
// Add just the inline clickable icon - no audio element here
110+
output += `<button type="button" class="audio-link" data-audio-id="${audioId}" aria-label="Play audio" style="display: inline-block; vertical-align: middle; margin: 0 2px; width: 24px; height: 24px; overflow: visible;"><svg fill="currentColor" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24" style="display: block; overflow: visible;"><path d="M14 20.725v-2.05q2.25-.65 3.625-2.5t1.375-4.2q0-2.35-1.375-4.2T14 5.275v-2.05q3.1.7 5.05 3.137Q21 8.8 21 11.975q0 3.175-1.95 5.612-1.95 2.438-5.05 3.138ZM3 15V9h4l5-5v16l-5-5Zm11 1V7.95q1.175.55 1.838 1.65.662 1.1.662 2.4q0 1.275-.662 2.362Q15.175 15.45 14 16Z"/></svg></button>`;
92111
} else {
93112
output += `<${node.tagName}`;
94113
for (let attr of node.attributes) {
@@ -123,7 +142,7 @@
123142
return output;
124143
}
125144
126-
return processNode(xmlDoc.documentElement);
145+
return processNode(xmlDoc.documentElement) + audioElements;
127146
}
128147
129148
async function updateXmlData() {
@@ -166,6 +185,17 @@
166185
});
167186
});
168187
});
188+
189+
const audioButtons = document.querySelectorAll('.audio-link');
190+
audioButtons.forEach((button) => {
191+
button.addEventListener('click', () => {
192+
const audioId = button.getAttribute('data-audio-id');
193+
const audioElement = document.getElementById(audioId) as HTMLAudioElement;
194+
if (audioElement) {
195+
audioElement.play();
196+
}
197+
});
198+
});
169199
}
170200
171201
function applyStyles() {

0 commit comments

Comments
 (0)