mirror of
https://gitlab.com/PronounsPage/PronounsPage.git
synced 2025-09-22 12:03:25 -04:00

ideally, there would be some auto-detection for the root of the provided slot, but apparently this isn’t easy to get
87 lines
2.3 KiB
Vue
87 lines
2.3 KiB
Vue
<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]) {
|
||
// don’t 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>
|