feat: add week 3 audio and timeline enhancements

This commit is contained in:
2026-04-18 22:10:48 +08:00
parent 4d54c144a8
commit 70efaf3ccf
20 changed files with 606 additions and 56 deletions

View File

@@ -6,18 +6,19 @@ import BaseButton from '../components/ui/BaseButton.vue'
import LoadingSpinner from '../components/ui/LoadingSpinner.vue'
import EmptyState from '../components/ui/EmptyState.vue'
import {
SparklesIcon,
BookOpenIcon,
TrophyIcon,
FlagIcon,
CalendarIcon,
SparklesIcon,
BookOpenIcon,
TrophyIcon,
FlagIcon,
HeartIcon,
CalendarIcon,
ChevronLeftIcon,
ExclamationCircleIcon
} from '@heroicons/vue/24/solid'
interface TimelineEvent {
date: string
type: 'story' | 'achievement' | 'milestone'
interface TimelineEvent {
date: string
type: 'story' | 'achievement' | 'milestone' | 'reading_event' | 'memory'
title: string
description: string | null
image_url: string | null
@@ -41,19 +42,23 @@ const profileId = route.params.id as string
const profileName = ref('') // We might need to fetch profile details separately or store it
function getIcon(type: string) {
switch (type) {
case 'milestone': return FlagIcon
case 'story': return BookOpenIcon
case 'achievement': return TrophyIcon
switch (type) {
case 'milestone': return FlagIcon
case 'story': return BookOpenIcon
case 'reading_event': return CalendarIcon
case 'memory': return HeartIcon
case 'achievement': return TrophyIcon
default: return SparklesIcon
}
}
function getColor(type: string) {
switch (type) {
case 'milestone': return 'text-blue-500'
case 'story': return 'text-purple-500'
case 'achievement': return 'text-yellow-500'
switch (type) {
case 'milestone': return 'text-blue-500'
case 'story': return 'text-purple-500'
case 'reading_event': return 'text-emerald-500'
case 'memory': return 'text-pink-500'
case 'achievement': return 'text-yellow-500'
default: return 'text-gray-500'
}
}
@@ -83,7 +88,7 @@ async function fetchTimeline() {
}
function handleEventClick(event: TimelineEvent) {
if (event.type === 'story' && event.metadata?.story_id) {
if ((event.type === 'story' || event.type === 'reading_event' || event.type === 'memory') && event.metadata?.story_id) {
if (event.metadata.mode === 'storybook') {
router.push(`/storybook/view/${event.metadata.story_id}`)
} else {
@@ -175,11 +180,17 @@ onMounted(fetchTimeline)
</div>
<!-- Role Badge -->
<div v-if="event.type === 'achievement'" class="mt-4 inline-flex items-center px-3 py-1 rounded-full bg-yellow-50 text-yellow-700 text-xs font-bold border border-yellow-200">
<TrophyIcon class="h-3 w-3 mr-1" /> 成就解锁
</div>
</div>
</div>
<div v-if="event.type === 'achievement'" class="mt-4 inline-flex items-center px-3 py-1 rounded-full bg-yellow-50 text-yellow-700 text-xs font-bold border border-yellow-200">
<TrophyIcon class="h-3 w-3 mr-1" /> 成就解锁
</div>
<div v-else-if="event.type === 'reading_event'" class="mt-4 inline-flex items-center px-3 py-1 rounded-full bg-emerald-50 text-emerald-700 text-xs font-bold border border-emerald-200">
<CalendarIcon class="h-3 w-3 mr-1" /> 阅读记录
</div>
<div v-else-if="event.type === 'memory'" class="mt-4 inline-flex items-center px-3 py-1 rounded-full bg-pink-50 text-pink-700 text-xs font-bold border border-pink-200">
<HeartIcon class="h-3 w-3 mr-1" /> 记忆沉淀
</div>
</div>
</div>
</div>
</div>
</template>