feat(chat): enhance chat functionality with song integration and UI improvements
- Updated ChatHeader and ChatMessage components to support song selection and display. - Enhanced useContentPanel to handle both film and song content, allowing for richer interactions. - Improved FilmCard and added SongCard components for better media representation. - Refactored environment variables for better configuration management. - Updated .gitignore to include development chat history. Made-with: Cursor
This commit is contained in:
@@ -12,7 +12,7 @@
|
||||
<p class="text-sm leading-relaxed whitespace-pre-wrap break-words"
|
||||
:class="isDark ? 'text-white/90' : 'text-gray-800'">{{ displayText }}</p>
|
||||
|
||||
<div v-if="inlineFilms.length > 0" class="mt-3 space-y-1">
|
||||
<div v-if="inlineFilms.length > 0" class="mt-3 space-y-1" @click.stop>
|
||||
<FilmCard
|
||||
v-for="film in inlineFilms"
|
||||
:key="film.id"
|
||||
@@ -21,16 +21,32 @@
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div v-if="inlineSongs.length > 0" class="mt-3 space-y-1" @click.stop>
|
||||
<SongCard
|
||||
v-for="song in inlineSongs"
|
||||
:key="song.id"
|
||||
:song="song"
|
||||
@select="handleSongSelect"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center gap-2 mt-1.5">
|
||||
<span class="text-[10px] select-none"
|
||||
:class="isDark ? 'text-white/30' : 'text-gray-400'">{{ formattedTime }}</span>
|
||||
<button
|
||||
v-if="inlineFilms.length > 1"
|
||||
class="text-[10px] text-accent/70 hover:text-accent transition-colors"
|
||||
@click="openPanel"
|
||||
@click.stop="openPanel"
|
||||
>
|
||||
View all {{ inlineFilms.length }} films →
|
||||
</button>
|
||||
<button
|
||||
v-else-if="inlineSongs.length > 1"
|
||||
class="text-[10px] text-accent/70 hover:text-accent transition-colors"
|
||||
@click.stop="openPanel"
|
||||
>
|
||||
View all {{ inlineSongs.length }} songs →
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -39,10 +55,11 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import type { Message } from '@aiui/core/types/message'
|
||||
import type { Film } from '@aiui/core/types/content'
|
||||
import type { Film, Song } from '@aiui/core/types/content'
|
||||
import { useTheme } from '@/composables/useTheme'
|
||||
import { useContentPanel } from '@/composables/useContentPanel'
|
||||
import FilmCard from '@/components/content/FilmCard.vue'
|
||||
import SongCard from '@/components/content/SongCard.vue'
|
||||
|
||||
const props = defineProps<{
|
||||
message: Message
|
||||
@@ -50,7 +67,7 @@ const props = defineProps<{
|
||||
}>()
|
||||
|
||||
const { isDark } = useTheme()
|
||||
const { extractFilmIds, resolveFilms, stripFilmTags, updatePanelFromText, openFilmDetail } = useContentPanel()
|
||||
const { extractAllFilms, extractAllSongs, stripContentTags, updatePanelFromText, openFilmDetail, openSongDetail, closeFilmDetail, closeSongDetail } = useContentPanel()
|
||||
|
||||
const isUser = computed(() => props.message.role === 'user')
|
||||
|
||||
@@ -62,15 +79,19 @@ const bubbleClasses = computed(() =>
|
||||
|
||||
const inlineFilms = computed(() => {
|
||||
if (isUser.value) return []
|
||||
const ids = extractFilmIds(props.message.content)
|
||||
return resolveFilms(ids)
|
||||
return extractAllFilms(props.message.content)
|
||||
})
|
||||
|
||||
const hasContext = computed(() => !isUser.value && inlineFilms.value.length > 0)
|
||||
const inlineSongs = computed(() => {
|
||||
if (isUser.value) return []
|
||||
return extractAllSongs(props.message.content)
|
||||
})
|
||||
|
||||
const hasContext = computed(() => !isUser.value && (inlineFilms.value.length > 0 || inlineSongs.value.length > 0))
|
||||
|
||||
const displayText = computed(() => {
|
||||
if (isUser.value) return props.message.content
|
||||
return stripFilmTags(props.message.content)
|
||||
return stripContentTags(props.message.content)
|
||||
})
|
||||
|
||||
const formattedTime = computed(() => {
|
||||
@@ -80,10 +101,19 @@ const formattedTime = computed(() => {
|
||||
|
||||
function handleFilmSelect(film: Film) {
|
||||
updatePanelFromText(props.message.content)
|
||||
closeSongDetail()
|
||||
openFilmDetail(film)
|
||||
}
|
||||
|
||||
function handleSongSelect(song: Song) {
|
||||
updatePanelFromText(props.message.content)
|
||||
closeFilmDetail()
|
||||
openSongDetail(song)
|
||||
}
|
||||
|
||||
function openPanel() {
|
||||
closeFilmDetail()
|
||||
closeSongDetail()
|
||||
updatePanelFromText(props.message.content)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user