Merge pull request #44 from Moe-Sakura/dev

Dev
This commit is contained in:
Asuna
2025-12-26 18:57:37 +08:00
committed by GitHub

View File

@@ -319,58 +319,6 @@
</div>
</div>
<!-- 角色配音 -->
<div v-if="searchStore.vndbInfo.va && searchStore.vndbInfo.va.length > 0" class="vndb-card">
<div class="flex items-center gap-2 mb-3">
<Mic :size="18" class="text-cyan-500" />
<h3 class="font-bold text-gray-800 dark:text-white">角色配音</h3>
<span class="text-xs text-gray-400 dark:text-slate-500">({{ searchStore.vndbInfo.va.length }})</span>
</div>
<div class="grid grid-cols-3 sm:grid-cols-4 md:grid-cols-5 gap-2">
<a
v-for="(voiceActor, index) in (expandedSections.va ? searchStore.vndbInfo.va : searchStore.vndbInfo.va.slice(0, 10))"
:key="index"
:href="`https://vndb.org/${voiceActor.character?.id}`"
target="_blank"
rel="noopener noreferrer"
class="relative rounded-xl overflow-hidden shadow-md hover:shadow-lg hover:scale-105 transition-all group"
>
<!-- 图片区域 -->
<div class="w-full relative">
<!-- 骨架屏占位 (padding-bottom: 133.33% = 3:4 比例) -->
<div class="w-full pb-[133.33%] skeleton bg-cyan-100 dark:bg-cyan-900/30" />
<img
v-if="getCharacterImage(voiceActor.character?.id)"
:src="getCharacterImage(voiceActor.character?.id)!"
:alt="voiceActor.character?.name"
class="absolute inset-0 w-full h-full object-cover"
loading="lazy"
@load="($event.target as HTMLElement).parentElement?.querySelector('.skeleton')?.classList.add('hidden')"
/>
<div v-else class="absolute inset-0 flex items-center justify-center bg-cyan-50 dark:bg-cyan-900/30">
<Users :size="24" class="text-cyan-400 dark:text-cyan-600" />
</div>
</div>
<!-- 文字覆盖层 -->
<div class="absolute bottom-0 left-0 right-0 bg-gradient-to-t from-black/80 via-black/50 to-transparent p-2 pt-6">
<p class="text-xs font-medium text-white text-center truncate group-hover:underline">
{{ voiceActor.character?.original || voiceActor.character?.name }}
</p>
<p class="text-[10px] text-white/70 text-center truncate">
CV: {{ voiceActor.staff?.original || voiceActor.staff?.name }}
</p>
</div>
</a>
</div>
<button
v-if="searchStore.vndbInfo.va.length > 10"
class="w-full mt-2 py-1.5 text-xs font-medium text-cyan-600 dark:text-cyan-400 bg-cyan-50 dark:bg-cyan-900/20 hover:bg-cyan-100 dark:hover:bg-cyan-900/30 rounded-lg transition-colors"
@click="toggleSection('va')"
>
{{ expandedSections.va ? '收起' : `显示全部 ${searchStore.vndbInfo.va.length} 个角色` }}
</button>
</div>
<!-- 相关作品 -->
<div v-if="searchStore.vndbInfo.relations && searchStore.vndbInfo.relations.length > 0" class="vndb-card">
<div class="flex items-center gap-2 mb-3">
@@ -453,7 +401,7 @@
loading="lazy"
@load="($event.target as HTMLElement).parentElement?.querySelector('.skeleton')?.classList.add('hidden')"
/>
<div v-else class="absolute inset-0 flex items-center justify-center">
<div v-else class="absolute inset-0 flex items-center justify-center bg-rose-50 dark:bg-rose-900/30">
<Users :size="24" class="text-rose-400 dark:text-rose-600" />
</div>
</div>
@@ -611,7 +559,6 @@ import {
Minimize2,
X,
Tag,
Mic,
Link2,
GitBranch,
Globe,
@@ -687,7 +634,6 @@ const screenshotsReady = ref(false)
// 展开/收起状态
const expandedSections = ref({
names: false,
va: false,
relations: false,
characters: false,
quotes: false,
@@ -756,7 +702,6 @@ watch(() => searchStore.vndbInfo, async (newInfo) => {
// 重置展开状态
expandedSections.value = {
names: false,
va: false,
relations: false,
characters: false,
quotes: false,
@@ -772,11 +717,15 @@ watch(() => searchStore.vndbInfo, async (newInfo) => {
nextTick(() => {
// 延迟一帧确保 DOM 已渲染
requestAnimationFrame(() => {
const vndbContent = document.querySelector('.vndb-content')
if (vndbContent) {
const firstScreenshot = vndbContent.querySelector('img[loading="lazy"]') as HTMLImageElement
if (firstScreenshot?.complete && firstScreenshot.naturalHeight > 0) {
screenshotsReady.value = true
// 在当前面板内查找截图图片
const screenshotImgs = modalRef.value?.querySelectorAll('img[alt*="截图"]')
if (screenshotImgs) {
for (let i = 0; i < screenshotImgs.length; i++) {
const img = screenshotImgs[i] as HTMLImageElement
if (img.complete && img.naturalHeight > 0) {
screenshotsReady.value = true
break
}
}
}
})
@@ -1028,15 +977,6 @@ function openGallery(startIndex: number) {
}
}
// 根据角色ID获取角色图片
function getCharacterImage(characterId: string | undefined): string | undefined {
if (!characterId) {
return undefined
}
const char = characters.value.find(c => c.id === characterId)
return char?.image
}
// 格式化性别
function formatSex(sex: string): string {
const sexMap: Record<string, string> = {