128 lines
2.8 KiB
Vue
128 lines
2.8 KiB
Vue
<!-- SideBarExplanation.vue -->
|
|
<template>
|
|
<div class="sidebar-explanation">
|
|
<div
|
|
v-if="isLoading"
|
|
class="explanation-loading"
|
|
>
|
|
🔄 Translating...
|
|
</div>
|
|
<div
|
|
v-else
|
|
class="explanation-content"
|
|
v-html="renderedExplanation"
|
|
></div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { ref, computed, watch, onMounted } from 'vue';
|
|
import { useTranslationClient } from '../js/composables/useTranslation.js';
|
|
|
|
const props = defineProps({
|
|
originalText: {
|
|
type: String,
|
|
default: ''
|
|
},
|
|
currentLanguage: {
|
|
type: String,
|
|
default: 'nl'
|
|
},
|
|
apiPrefix: {
|
|
type: String,
|
|
default: ''
|
|
}
|
|
});
|
|
|
|
const { translateSafe } = useTranslationClient();
|
|
const translatedText = ref(props.originalText);
|
|
const isLoading = ref(false);
|
|
|
|
// Render markdown content
|
|
const renderedExplanation = computed(() => {
|
|
if (!translatedText.value) return '';
|
|
|
|
// Use marked if available, otherwise return plain text
|
|
if (typeof window.marked === 'function') {
|
|
return window.marked(translatedText.value);
|
|
} else if (window.marked && typeof window.marked.parse === 'function') {
|
|
return window.marked.parse(translatedText.value.replace(/\[\[(.*?)\]\]/g, '<strong>$1</strong>'));
|
|
} else {
|
|
return translatedText.value;
|
|
}
|
|
});
|
|
|
|
// Watch for language changes
|
|
watch(() => props.currentLanguage, async (newLanguage) => {
|
|
await updateTranslation(newLanguage);
|
|
});
|
|
|
|
// Watch for text changes
|
|
watch(() => props.originalText, async () => {
|
|
await updateTranslation(props.currentLanguage);
|
|
});
|
|
|
|
const updateTranslation = async (targetLanguage) => {
|
|
if (!props.originalText || targetLanguage === 'nl') {
|
|
translatedText.value = props.originalText;
|
|
return;
|
|
}
|
|
|
|
isLoading.value = true;
|
|
try {
|
|
const result = await translateSafe(props.originalText, targetLanguage, {
|
|
context: 'sidebar_explanation',
|
|
apiPrefix: props.apiPrefix,
|
|
fallbackText: props.originalText
|
|
});
|
|
|
|
translatedText.value = result;
|
|
} catch (error) {
|
|
console.warn('Sidebar explanation translation failed:', error);
|
|
translatedText.value = props.originalText;
|
|
} finally {
|
|
isLoading.value = false;
|
|
}
|
|
};
|
|
|
|
onMounted(() => {
|
|
updateTranslation(props.currentLanguage);
|
|
});
|
|
</script>
|
|
|
|
<style scoped>
|
|
.sidebar-explanation {
|
|
padding: 15px;
|
|
overflow-y: auto;
|
|
}
|
|
|
|
.explanation-loading {
|
|
color: var(--sidebar-color);
|
|
font-style: italic;
|
|
text-align: center;
|
|
padding: 20px;
|
|
}
|
|
|
|
.explanation-content {
|
|
color: var(--sidebar-color);
|
|
font-size: 0.9rem;
|
|
line-height: 1.5;
|
|
}
|
|
|
|
.explanation-content :deep(h1),
|
|
.explanation-content :deep(h2),
|
|
.explanation-content :deep(h3) {
|
|
color: var(--sidebar-color);
|
|
margin-top: 1rem;
|
|
margin-bottom: 0.5rem;
|
|
}
|
|
|
|
.explanation-content :deep(p) {
|
|
margin-bottom: 1rem;
|
|
}
|
|
|
|
.explanation-content :deep(strong) {
|
|
color: var(--primary-color);
|
|
font-weight: 600;
|
|
}
|
|
</style> |