Vrda's picture
Feature: EN/HR language toggle on login + full app i18n
81046e2
<script setup lang="ts">
import type { ModelInfo, StatsResponse, AuthUser } from '../types'
import type { Lang } from '../i18n'
import { t, storeLang } from '../i18n'
import Wc3Button from '../wc3/base/Button.vue'
import { RACE_KEY } from '../wc3/consts'
defineProps<{
models: Record<string, ModelInfo>
stats: StatsResponse
user: AuthUser | null
lang: Lang
}>()
const model = defineModel<string>('model', { required: true })
const showCitations = defineModel<boolean>('showCitations', { required: true })
const race = defineModel<RACE_KEY>('race', { required: true })
const emit = defineEmits<{
'clear-chat': []
'logout': []
'update:lang': [lang: Lang]
}>()
const races = [
{ key: RACE_KEY.HUMAN, label: 'Human' },
{ key: RACE_KEY.ORC, label: 'Orc' },
{ key: RACE_KEY.NIGHT_ELF, label: 'Night Elf' },
{ key: RACE_KEY.UNDEAD, label: 'Undead' },
]
function switchLang(newLang: Lang) {
storeLang(newLang)
emit('update:lang', newLang)
}
</script>
<template>
<div>
<!-- User info -->
<div v-if="user" class="user-badge">
<img v-if="user.picture" :src="user.picture" class="user-avatar" referrerpolicy="no-referrer" alt="" />
<div class="user-info">
<span class="user-name">{{ user.name }}</span>
<button class="logout-btn" @click="emit('logout')">{{ t('sidebar.logout', lang) }}</button>
</div>
</div>
<div v-if="user" class="gold-divider"></div>
<!-- Language -->
<h2>{{ t('sidebar.language', lang) }}</h2>
<div class="lang-switch">
<button
:class="['lang-switch-btn', { active: lang === 'en' }]"
@click="switchLang('en')"
>🇬🇧 English</button>
<button
:class="['lang-switch-btn', { active: lang === 'hr' }]"
@click="switchLang('hr')"
>🇭🇷 Hrvatski</button>
</div>
<div class="gold-divider"></div>
<!-- Model -->
<h2>{{ t('sidebar.selectModel', lang) }}</h2>
<select class="wc3-select" :value="model" @change="model = ($event.target as HTMLSelectElement).value">
<option v-for="(info, key) in models" :key="key" :value="key">
{{ info.name }}
</option>
</select>
<p class="model-caption" v-if="models[model]">
{{ models[model].description }}
</p>
<div class="gold-divider"></div>
<!-- Theme -->
<h2>{{ t('sidebar.theme', lang) }}</h2>
<select class="wc3-select" :value="race" @change="race = ($event.target as HTMLSelectElement).value as RACE_KEY">
<option v-for="r in races" :key="r.key" :value="r.key">
{{ r.label }}
</option>
</select>
<div class="gold-divider"></div>
<!-- Options -->
<h2>{{ t('sidebar.options', lang) }}</h2>
<label class="wc3-checkbox">
<input type="checkbox" :checked="showCitations" @change="showCitations = ($event.target as HTMLInputElement).checked" />
{{ t('sidebar.showSources', lang) }}
</label>
<div style="margin-top: 0.75rem; height: 32px; min-width: 100%;">
<Wc3Button size="s" @click="emit('clear-chat')">
{{ t('sidebar.newChat', lang) }}
</Wc3Button>
</div>
<div class="gold-divider"></div>
<!-- Stats -->
<h2>{{ t('sidebar.knowledgeBase', lang) }}</h2>
<div class="resource-bar">
{{ stats.documents.toLocaleString() }} {{ t('sidebar.documents', lang) }}
</div>
<!-- Footer -->
<div class="sidebar-footer">
<div class="gold-divider"></div>
Learn Pathophysiology<br>
Powered by Gemini AI
</div>
</div>
</template>
<style scoped>
.lang-switch {
display: flex;
gap: 0.4rem;
}
.lang-switch-btn {
flex: 1;
background: linear-gradient(180deg, #1a1a32, #13132a);
border: 1px solid var(--wc3-border-dim, #3a2e1e);
border-radius: 3px;
color: var(--wc3-text-dim, #7a6e5a);
font-family: var(--font-body, 'Crimson Text', serif);
font-size: 0.85rem;
padding: 0.4rem 0.5rem;
cursor: pointer;
transition: all 0.15s;
}
.lang-switch-btn:hover {
border-color: var(--wc3-gold-dim, #8b7b4f);
color: var(--wc3-text, #d4c4a0);
}
.lang-switch-btn.active {
border-color: var(--wc3-gold, #c8aa6e);
color: var(--wc3-gold, #c8aa6e);
background: rgba(200, 170, 110, 0.08);
}
</style>