refactor: extract EncyclopediaProgressCard component and limit map pitch

- Create EncyclopediaProgressCard with dynamic progress color, reuse in
  encyclopedia and profile pages to unify styling
- Add skyColor and maxPitch to AMap 3D view to reduce empty tile area
  when tilting
- Extend AMap type declarations for skyColor, maxPitch, getPitch, getRotation
This commit is contained in:
2026-05-24 17:43:25 +08:00
parent 1e0da1fe36
commit 2a9f8d6a9c
5 changed files with 93 additions and 82 deletions
@@ -0,0 +1,65 @@
<script setup lang="ts">
import { computed } from 'vue'
import { NCard, NProgress } from 'naive-ui'
const props = defineProps<{
unlockedCount: number
totalCount: number
percent: number
isLoggedIn: boolean
}>()
function lerpHex(a: string, b: string, t: number) {
const ah = parseInt(a.slice(1), 16)
const bh = parseInt(b.slice(1), 16)
const r = Math.round(((ah >> 16) & 0xff) + (((bh >> 16) & 0xff) - ((ah >> 16) & 0xff)) * t)
const g = Math.round(((ah >> 8) & 0xff) + (((bh >> 8) & 0xff) - ((ah >> 8) & 0xff)) * t)
const bv = Math.round((ah & 0xff) + ((bh & 0xff) - (ah & 0xff)) * t)
return `#${((r << 16) | (g << 8) | bv).toString(16).padStart(6, '0')}`
}
function progressColor(pct: number) {
const t = Math.min(1, Math.max(0, pct / 100))
if (t <= 0.5) return lerpHex('#0ea5e9', '#f59e0b', t * 2)
return lerpHex('#f59e0b', '#ef4444', (t - 0.5) * 2)
}
const progressText = computed(() => `${props.unlockedCount}/${props.totalCount}`)
const currentColor = computed(() => progressColor(props.isLoggedIn ? props.percent : 0))
</script>
<template>
<NCard class="border border-white/80 bg-white/85 shadow-sm backdrop-blur" :bordered="false">
<div class="flex items-center justify-between">
<div>
<p class="text-sm text-slate-500">当前进度</p>
<p class="mt-1 text-3xl font-bold" :style="{ color: currentColor }">{{ progressText }}</p>
</div>
<div
class="flex h-16 w-16 items-center justify-center border text-xl font-semibold text-white transition-colors duration-500"
:style="{ backgroundColor: currentColor, borderColor: currentColor }"
>
{{ isLoggedIn ? percent : 0 }}%
</div>
</div>
<NProgress
class="mt-5"
type="line"
:show-indicator="false"
:percentage="isLoggedIn ? percent : 0"
:color="{ stops: ['#0ea5e9', currentColor] }"
:height="12"
rail-color="#e2e8f0"
/>
<p class="mt-4 text-sm text-slate-500">
<template v-if="isLoggedIn">
已解锁 {{ unlockedCount }} 枚徽章,还差 {{ Math.max(totalCount - unlockedCount, 0) }} 枚。
</template>
<template v-else>
登录后可同步你的个人图鉴进度。
</template>
</p>
</NCard>
</template>