Vrda's picture
Feature: EN/HR language toggle on login + full app i18n
81046e2
<script setup lang="ts">
import { ref } from 'vue'
import { marked } from 'marked'
import type { Citation } from '../types'
import type { Lang } from '../i18n'
import { t } from '../i18n'
import { analyzeImage } from '../api'
import Wc3Button from '../wc3/base/Button.vue'
import CitationPanel from './CitationPanel.vue'
const props = defineProps<{
model: string
showCitations: boolean
lang: Lang
}>()
const selectedFile = ref<File | null>(null)
const imagePreview = ref('')
const question = ref('')
const analysis = ref('')
const citations = ref<Citation[]>([])
const isLoading = ref(false)
const error = ref('')
const fileInput = ref<HTMLInputElement | null>(null)
function renderMd(text: string): string {
return marked.parse(text) as string
}
function handleFileSelect(e: Event) {
const input = e.target as HTMLInputElement
if (input.files?.[0]) {
selectedFile.value = input.files[0]
imagePreview.value = URL.createObjectURL(input.files[0])
analysis.value = ''
citations.value = []
error.value = ''
}
}
function handleDrop(e: DragEvent) {
e.preventDefault()
if (e.dataTransfer?.files[0]) {
selectedFile.value = e.dataTransfer.files[0]
imagePreview.value = URL.createObjectURL(e.dataTransfer.files[0])
analysis.value = ''
citations.value = []
error.value = ''
}
}
async function handleAnalyze() {
if (!selectedFile.value || isLoading.value) return
isLoading.value = true
error.value = ''
analysis.value = ''
citations.value = []
try {
const res = await analyzeImage(selectedFile.value, question.value, props.model)
analysis.value = res.analysis
citations.value = res.citations
} catch (e: any) {
error.value = e.message || t('image.error', props.lang)
} finally {
isLoading.value = false
}
}
</script>
<template>
<div class="image-tab">
<div
class="upload-zone"
@click="fileInput?.click()"
@drop="handleDrop"
@dragover.prevent
>
<input ref="fileInput" type="file" accept="image/*" @change="handleFileSelect" />
<div v-if="!imagePreview">
<div class="icon">📄</div>
<p>{{ t('image.dropHint', lang) }}</p>
<p style="font-size: 0.8rem; color: var(--wc3-text-muted);">
{{ t('image.uploadHint', lang) }}
</p>
</div>
<img v-else :src="imagePreview" class="image-preview" alt="Preview" />
</div>
<div v-if="selectedFile" style="margin-bottom: 1rem;">
<input
class="wc3-input"
v-model="question"
:placeholder="t('image.questionPlaceholder', lang)"
/>
</div>
<div v-if="selectedFile" style="margin-bottom: 1.5rem; height: 38px; min-width: 160px; display: inline-block;">
<Wc3Button size="s" @click="handleAnalyze" :disabled="isLoading">
{{ isLoading ? t('image.analyzing', lang) : t('image.analyze', lang) }}
</Wc3Button>
</div>
<div v-if="isLoading" class="loading">
<span>{{ t('image.analyzingStatus', lang) }}</span>
<span class="dot-pulse"><span></span><span></span><span></span></span>
</div>
<div v-if="error" class="error-msg" style="margin-bottom: 1rem;">⚠️ {{ error }}</div>
<div v-if="analysis" class="analysis-result">
<div v-html="renderMd(analysis)"></div>
<CitationPanel
v-if="showCitations && citations.length"
:citations="citations"
:lang="lang"
style="margin-top: 0.75rem;"
/>
</div>
</div>
</template>