Files
tianshu-engine/src/components/AchievementToast.vue

112 lines
2.2 KiB
Vue

<script setup lang="ts">
import { computed, watch, ref } from 'vue'
import type { AchievementDef } from '@engine/types'
import { useI18n } from '@/composables/useI18n'
const { t } = useI18n()
const props = defineProps<{
achievementId: string
definitions: AchievementDef[]
}>()
const emit = defineEmits<{
done: []
}>()
const visible = ref(false)
const def = computed(() => props.definitions.find((d) => d.id === props.achievementId))
watch(() => props.achievementId, (id) => {
if (!id) return
visible.value = true
setTimeout(() => {
visible.value = false
setTimeout(() => emit('done'), 400)
}, 3000)
}, { immediate: true })
</script>
<template>
<div class="achievement-toast" v-if="visible && def" :class="{ show: visible }">
<div class="toast-icon">
<img v-if="def.icon" :src="def.icon" class="toast-img" />
<span v-else class="toast-star"></span>
</div>
<div class="toast-body">
<div class="toast-label">{{ t('ui.achievementUnlocked') }}</div>
<div class="toast-title">{{ def ? t(def.titleKey || def.title) : '' }}</div>
<div class="toast-desc">{{ def ? t(def.descKey || def.description) : '' }}</div>
</div>
</div>
</template>
<style scoped>
.achievement-toast {
position: fixed;
bottom: 24px;
left: 50%;
transform: translateX(-50%) translateY(100px);
background: rgba(20, 20, 40, 0.95);
border: 1px solid rgba(255, 193, 7, 0.4);
border-radius: 8px;
padding: 14px 20px;
display: flex;
align-items: center;
gap: 14px;
z-index: 300;
min-width: 320px;
opacity: 0;
transition: transform 0.4s ease, opacity 0.4s ease;
}
.achievement-toast.show {
transform: translateX(-50%) translateY(0);
opacity: 1;
}
.toast-icon {
width: 40px;
height: 40px;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
}
.toast-star {
font-size: 24px;
}
.toast-img {
width: 100%;
height: 100%;
object-fit: contain;
}
.toast-body {
display: flex;
flex-direction: column;
gap: 2px;
}
.toast-label {
font-size: 11px;
color: #ffc107;
text-transform: uppercase;
letter-spacing: 1px;
}
.toast-title {
font-size: 15px;
color: #fff;
font-weight: 600;
}
.toast-desc {
font-size: 12px;
color: #aaa;
}
</style>