PronounsPage/components/PronunciationSpeaker.vue
Valentyne Stigloher f24ced9f3f (fix) propagate properties to reference element of <Popover> (was wrong for german grammar tables)
ideally, there would be some auto-detection for the root of the provided slot, but apparently this isn’t easy to get
2024-10-06 22:59:27 +02:00

87 lines
2.3 KiB
Vue
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<script setup lang="ts">
import { Base64 } from 'js-base64';
const props = withDefaults(defineProps<{
pronunciation?: string | null;
voice: string;
button?: boolean;
}>(), {
pronunciation: null,
});
const pronunciationLink = computed((): string | undefined => {
if (!props.pronunciation) {
return undefined;
}
return `/api/pronounce/${props.voice}/${Base64.encodeURI(props.pronunciation)}`;
});
const state = ref<'idle' | 'loading' | 'playing'>('idle');
const sound = ref<HTMLAudioElement>();
const pronounce = () => {
if (!pronunciationLink.value) {
return;
}
if (sound.value && sound.value.src.endsWith(pronunciationLink.value) && !sound.value.error) {
// reuse the sound object if it has the same source and has been loaded without an error
sound.value.pause();
sound.value.currentTime = 0;
sound.value.play();
return;
}
sound.value = new Audio(pronunciationLink.value);
sound.value.addEventListener('canplay', () => sound.value!.play());
sound.value.addEventListener('play', () => state.value = 'playing');
sound.value.addEventListener('ended', () => state.value = 'idle');
sound.value.addEventListener('error', () => state.value = 'idle');
state.value = 'loading';
sound.value.load();
};
const icon = computed((): string => {
switch (state.value) {
case 'loading':
return 'spinner fa-spin';
case 'playing':
return 'volume-up';
case 'idle':
default:
return 'volume';
}
});
const config = useConfig();
const name = computed((): string | null => {
if (!config.pronunciation?.enabled) {
return props.voice;
}
const voices = Object.keys(config.pronunciation.voices);
if (voices.length === 1 && props.voice === voices[0]) {
// dont show voice name if it is considered the main voice for this locale
return null;
}
return props.voice;
});
</script>
<template>
<Tooltip
tag="a"
:text="$t('pronunciation.play')"
:class="!pronunciation ? 'disabled' : ''"
dir="ltr"
:href="pronunciationLink"
target="_blank"
@click.prevent="pronounce"
>
<Icon :v="icon" /><sub v-if="name">{{ name }}</sub>
</Tooltip>
</template>