feat(content): add places, code mode, mobile context tab, and detail views
- Add Places/Restaurants content type with PlaceCard, PlaceDetail, PlaceGrid - Add WebsiteDetail and MagazineSectionDetail views for Context panel - Enhance MagazineGrid hero with background image and 3x taller header - Add mobile 3-tab layout (Chat, Content, Context) with detail navigation - Add /code command system: useCodeContext composable, ProjectGrid, FileTreeNode, CodeDetail for IDE-style code viewing across all three panels - Fix /code bubble and prompt index clicks to re-activate code mode - Fix updatePanelFromText overwriting code tab by skipping command messages Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
48dd7a9c68
commit
e8fc54cade
@@ -1,5 +1,5 @@
|
||||
import { ref } from 'vue'
|
||||
import type { Film, Song, Podcast, Book, TVSeries, ImageItem } from '@aiui/core/types/content'
|
||||
import type { Film, Song, Podcast, Book, TVSeries, ImageItem, Place } from '@aiui/core/types/content'
|
||||
import type { WebSearchResult } from '@aiui/core/types/message'
|
||||
import { mockFilms } from '@/mocks/films'
|
||||
import { mockSongs } from '@/mocks/songs'
|
||||
@@ -7,7 +7,7 @@ import { mockPodcasts } from '@/mocks/podcasts'
|
||||
import { generatePosterFallback, generateSongCoverFallback, generateBookCoverFallback } from '@/composables/useImageFallback'
|
||||
import { fetchRssFromUrls } from '@/composables/useRssFetch'
|
||||
|
||||
export type ContentTab = 'film' | 'song' | 'podcast' | 'book' | 'tvshow' | 'image' | 'news' | 'websites' | 'magazine'
|
||||
export type ContentTab = 'film' | 'song' | 'podcast' | 'book' | 'tvshow' | 'image' | 'place' | 'news' | 'websites' | 'magazine' | 'code'
|
||||
|
||||
export interface MagazineSection {
|
||||
title: string
|
||||
@@ -34,6 +34,7 @@ const panelMagazineHeroImage = ref<string | null>(null)
|
||||
const panelSongs = ref<Song[]>([])
|
||||
const panelPodcasts = ref<Podcast[]>([])
|
||||
const panelImages = ref<ImageItem[]>([])
|
||||
const panelPlaces = ref<Place[]>([])
|
||||
const selectedFilm = ref<Film | null>(null)
|
||||
const selectedBook = ref<Book | null>(null)
|
||||
const selectedTVSeries = ref<TVSeries | null>(null)
|
||||
@@ -41,6 +42,10 @@ const selectedSong = ref<Song | null>(null)
|
||||
const selectedPodcast = ref<Podcast | null>(null)
|
||||
const selectedArticle = ref<WebSearchResult | null>(null)
|
||||
const selectedImage = ref<ImageItem | null>(null)
|
||||
const selectedPlace = ref<Place | null>(null)
|
||||
const selectedWebsite = ref<WebSearchResult | null>(null)
|
||||
const selectedMagazineSection = ref<MagazineSection | null>(null)
|
||||
const magazineSectionIndex = ref(0)
|
||||
const panelTitle = ref('Recommended Films')
|
||||
const panelQuery = ref('')
|
||||
const contentType = ref<'film' | 'song' | 'podcast'>('film')
|
||||
@@ -295,6 +300,7 @@ function preferredFirstTab(userQuery: string): ContentTab | null {
|
||||
if (/\b(book|books|read|reading|novel|author|nonfiction|non-fiction)\b/.test(q)) return 'book'
|
||||
if (/\b(tv show|tv series|series|television|streaming|binge|watch)\b/.test(q)) return 'tvshow'
|
||||
if (/\b(image|images|photo|photos|picture|pictures|screenshot|gallery|artwork|illustration)\b/.test(q)) return 'image'
|
||||
if (/\b(restaurant|restaurants|place|places|food|eat|dining|cafe|cafes|bar|bars|pub|pubs|brunch|lunch|dinner|bistro|pizzeria|sushi|ramen|tacos|burger|bakery|deli|steakhouse)\b/.test(q)) return 'place'
|
||||
if (isNewsQuery(q)) return 'news'
|
||||
if (isWebsitesQuery(q)) return 'websites'
|
||||
return null
|
||||
@@ -310,6 +316,7 @@ function filterTabsByContext(
|
||||
hasBooks: boolean,
|
||||
hasTVSeries: boolean,
|
||||
hasImages: boolean,
|
||||
hasPlaces: boolean,
|
||||
hasNews: boolean,
|
||||
hasWebsites: boolean,
|
||||
hasMagazine: boolean,
|
||||
@@ -326,11 +333,11 @@ function filterTabsByContext(
|
||||
return tabs
|
||||
}
|
||||
|
||||
if (hasMagazine && !hasFilms && !hasSongs && !hasPodcasts && !hasBooks && !hasTVSeries && !hasImages && !hasNews && !hasWebsites) {
|
||||
if (hasMagazine && !hasFilms && !hasSongs && !hasPodcasts && !hasBooks && !hasTVSeries && !hasImages && !hasPlaces && !hasNews && !hasWebsites) {
|
||||
return ['magazine']
|
||||
}
|
||||
|
||||
if (hasWebsites && !hasFilms && !hasSongs && !hasPodcasts && !hasBooks && !hasTVSeries && !hasImages && !hasNews && !hasMagazine) {
|
||||
if (hasWebsites && !hasFilms && !hasSongs && !hasPodcasts && !hasBooks && !hasTVSeries && !hasImages && !hasPlaces && !hasNews && !hasMagazine) {
|
||||
return ['websites']
|
||||
}
|
||||
|
||||
@@ -339,6 +346,7 @@ function filterTabsByContext(
|
||||
if (hasBooks) all.push('book')
|
||||
if (hasTVSeries) all.push('tvshow')
|
||||
if (hasImages) all.push('image')
|
||||
if (hasPlaces) all.push('place')
|
||||
if (hasSongs) all.push('song')
|
||||
if (hasPodcasts) all.push('podcast')
|
||||
if (hasMagazine) all.push('magazine')
|
||||
@@ -386,6 +394,7 @@ const BOOK_TAG_RE = /\[\[book:(b?\d+)\]\]/gi
|
||||
const BOOK_EXT_RE = /\[\[book_ext:([^|]+)\|([^|]+)(?:\|(\d{4}))?\]\]/gi
|
||||
|
||||
const TV_EXT_RE = /\[\[tv_ext:([^|]+)\|([^|]*)(?:\|(\d{4}))?\]\]/gi
|
||||
const PLACE_EXT_RE = /\[\[place_ext:([^|]+)\|([^|]*)(?:\|([^|]*))?(?:\|([^|]*))?(?:\|([^|]*))?(?:\|([^|]*))?\]\]/gi
|
||||
|
||||
/** Reject obvious non-podcast phrases (documentation, mailing lists, etc.) */
|
||||
function looksLikePodcast(title: string, host: string): boolean {
|
||||
@@ -972,6 +981,101 @@ export function useContentPanel() {
|
||||
return []
|
||||
}
|
||||
|
||||
function isPlaceQuery(q: string): boolean {
|
||||
return /\b(restaurant|restaurants|place|places|food|eat|eating|dining|cafe|cafes|bar|bars|pub|pubs|brunch|lunch|dinner|bistro|pizzeria|sushi|ramen|tacos|burger|bakery|deli|steakhouse|where to eat|good food|best food|where should i eat|recommend.*eat|recommend.*restaurant|recommend.*place)\b/i.test(q)
|
||||
}
|
||||
|
||||
function isPlaceLikeResponse(text: string): boolean {
|
||||
return /\b(restaurant|cuisine|menu|reserv|dining|address|open|hours|price range|\$\$|\$\$\$|michelin|yelp|rating)\b/i.test(text) &&
|
||||
(text.match(/\b(?:restaurant|cafe|bar|bistro|pub|pizzeria|bakery|deli|steakhouse|grill)\b/gi)?.length ?? 0) >= 2
|
||||
}
|
||||
|
||||
/** Extract places from [[place_ext:Name|Cuisine|City|Rating|PriceLevel|Address]] tags */
|
||||
function extractExternalPlaces(text: string): Place[] {
|
||||
const places: Place[] = []
|
||||
const seen = new Set<string>()
|
||||
let match: RegExpExecArray | null
|
||||
const re = new RegExp(PLACE_EXT_RE.source, 'gi')
|
||||
while ((match = re.exec(text)) !== null) {
|
||||
const name = match[1].trim()
|
||||
const cuisine = match[2]?.trim() || undefined
|
||||
const city = match[3]?.trim() || undefined
|
||||
const rating = match[4] ? parseFloat(match[4]) : undefined
|
||||
const priceLevel = match[5] ? parseInt(match[5], 10) : undefined
|
||||
const address = match[6]?.trim() || undefined
|
||||
const key = name.toLowerCase()
|
||||
if (seen.has(key)) continue
|
||||
seen.add(key)
|
||||
places.push({
|
||||
id: `ext-place-${key.replace(/\W/g, '-')}`,
|
||||
name,
|
||||
cuisine,
|
||||
city,
|
||||
rating: rating && !isNaN(rating) ? rating : undefined,
|
||||
priceLevel: priceLevel && priceLevel >= 1 && priceLevel <= 4 ? priceLevel : undefined,
|
||||
address,
|
||||
description: extractDescriptionForTag(text, match.index, match[0].length),
|
||||
sources: [],
|
||||
})
|
||||
}
|
||||
return places
|
||||
}
|
||||
|
||||
/** Extract place-like patterns from AI response text */
|
||||
function extractPlacesFromPatterns(text: string): Place[] {
|
||||
const places: { name: string; cuisine?: string; city?: string; rating?: number; priceLevel?: number; desc: string; pos: number }[] = []
|
||||
const seen = new Set<string>()
|
||||
|
||||
const patterns: RegExp[] = [
|
||||
// **Name** — cuisine/category, details
|
||||
/\*\*([^*]{2,60})\*\*\s*[-–—:]\s*(?:a |an )?(?:(\w[\w\s]{1,30}?)\s+)?(?:restaurant|cafe|bar|bistro|pub|pizzeria|bakery|deli|steakhouse|grill|eatery|spot|joint)/gi,
|
||||
// Numbered list: 1. **Name** (cuisine) or 1. Name — description
|
||||
/(?:^|\n)\s*(?:\d+\.\s*|[-•]\s*)\*{0,2}([^*\n]{2,60}?)\*{0,2}\s*[-–—(]\s*(?:(\w[\w\s&]{1,30}?)\s+)?(?:restaurant|cafe|bar|bistro|pub|pizzeria|bakery|deli|steakhouse|grill|cuisine|food|dining)/gim,
|
||||
]
|
||||
|
||||
for (const re of patterns) {
|
||||
let m: RegExpExecArray | null
|
||||
const rx = new RegExp(re.source, re.flags)
|
||||
while ((m = rx.exec(text)) !== null) {
|
||||
const name = m[1].trim().replace(/^\*\*|\*\*$/g, '').replace(/^\[|\]$/g, '')
|
||||
if (name.length < 2) continue
|
||||
if (/\[\[(film|song|podcast|book|tv|place)(_ext)?:/.test(name)) continue
|
||||
const key = name.toLowerCase()
|
||||
if (seen.has(key)) continue
|
||||
seen.add(key)
|
||||
const cuisine = m[2]?.trim()
|
||||
const desc = extractDescriptionForTag(text, m.index, m[0].length)
|
||||
// Try to extract rating from nearby text
|
||||
const nearby = text.slice(m.index, m.index + 300)
|
||||
const ratingMatch = /(\d\.?\d?)\s*(?:\/\s*5|stars?|★)/i.exec(nearby)
|
||||
const rating = ratingMatch ? parseFloat(ratingMatch[1]) : undefined
|
||||
const priceMatch = /(\${1,4})\b/.exec(nearby)
|
||||
const priceLevel = priceMatch ? priceMatch[1].length : undefined
|
||||
places.push({ name, cuisine, desc, rating, priceLevel, pos: m.index })
|
||||
}
|
||||
}
|
||||
|
||||
return places
|
||||
.sort((a, b) => a.pos - b.pos)
|
||||
.map(({ name, cuisine, desc, rating, priceLevel }) => ({
|
||||
id: `ext-place-${name.toLowerCase().replace(/\W/g, '-')}`,
|
||||
name,
|
||||
cuisine,
|
||||
rating,
|
||||
priceLevel,
|
||||
description: desc,
|
||||
sources: [],
|
||||
}))
|
||||
}
|
||||
|
||||
function extractAllPlaces(text: string, userQuery: string): Place[] {
|
||||
const external = extractExternalPlaces(text)
|
||||
if (external.length > 0) return external
|
||||
if (!isPlaceQuery(userQuery) && !isPlaceLikeResponse(text)) return []
|
||||
if (isNewsLikeResponse(text)) return []
|
||||
return extractPlacesFromPatterns(text)
|
||||
}
|
||||
|
||||
function updatePanelFromText(text: string, userQuery = '', webResults: WebSearchResult[] = []) {
|
||||
panelQuery.value = userQuery.trim()
|
||||
const songs = extractAllSongs(text)
|
||||
@@ -1021,8 +1125,9 @@ export function useContentPanel() {
|
||||
}
|
||||
|
||||
const images = extractAllImages(text, userQuery)
|
||||
const places = extractAllPlaces(text, userQuery)
|
||||
|
||||
const tabs = filterTabsByContext(userQuery, films.length > 0, songs.length > 0, podcasts.length > 0, books.length > 0, tvSeries.length > 0, images.length > 0, hasNews, hasWebsites, hasMagazine)
|
||||
const tabs = filterTabsByContext(userQuery, films.length > 0, songs.length > 0, podcasts.length > 0, books.length > 0, tvSeries.length > 0, images.length > 0, places.length > 0, hasNews, hasWebsites, hasMagazine)
|
||||
availableTabs.value = tabs.length > 0 ? tabs : ['film']
|
||||
activeTab.value = tabs[0] ?? 'film'
|
||||
|
||||
@@ -1030,6 +1135,7 @@ export function useContentPanel() {
|
||||
const showBooks = tabs.includes('book')
|
||||
const showTVSeries = tabs.includes('tvshow')
|
||||
const showImages = tabs.includes('image')
|
||||
const showPlaces = tabs.includes('place')
|
||||
const showSongs = tabs.includes('song')
|
||||
const showPodcasts = tabs.includes('podcast')
|
||||
const showNews = tabs.includes('news')
|
||||
@@ -1040,6 +1146,7 @@ export function useContentPanel() {
|
||||
const visibleBooks = showBooks ? books : []
|
||||
const visibleTVSeries = showTVSeries ? tvSeries : []
|
||||
const visibleImages = showImages ? images : []
|
||||
const visiblePlaces = showPlaces ? places : []
|
||||
const visibleSongs = showSongs ? songs : []
|
||||
const visiblePodcasts = showPodcasts ? podcasts : []
|
||||
const visibleNews = showNews ? mergedNews : []
|
||||
@@ -1050,6 +1157,7 @@ export function useContentPanel() {
|
||||
panelBooks.value = visibleBooks
|
||||
panelTVSeries.value = visibleTVSeries
|
||||
panelImages.value = visibleImages
|
||||
panelPlaces.value = visiblePlaces
|
||||
panelSongs.value = visibleSongs
|
||||
panelPodcasts.value = visiblePodcasts
|
||||
panelWebResults.value = visibleNews
|
||||
@@ -1062,6 +1170,7 @@ export function useContentPanel() {
|
||||
selectedBook.value = null
|
||||
selectedTVSeries.value = null
|
||||
selectedImage.value = null
|
||||
selectedPlace.value = null
|
||||
selectedSong.value = null
|
||||
selectedPodcast.value = null
|
||||
|
||||
@@ -1075,7 +1184,9 @@ export function useContentPanel() {
|
||||
|
||||
// Title follows the primary (first) tab
|
||||
const primary = tabs[0]
|
||||
if (primary === 'tvshow' && visibleTVSeries.length > 0) {
|
||||
if (primary === 'place' && visiblePlaces.length > 0) {
|
||||
panelTitle.value = visiblePlaces.length === 1 ? visiblePlaces[0].name : `${visiblePlaces.length} Places`
|
||||
} else if (primary === 'tvshow' && visibleTVSeries.length > 0) {
|
||||
panelTitle.value = visibleTVSeries.length === 1 ? visibleTVSeries[0].title : `${visibleTVSeries.length} TV Series`
|
||||
} else if (primary === 'book' && visibleBooks.length > 0) {
|
||||
panelTitle.value = visibleBooks.length === 1 ? visibleBooks[0].title : `${visibleBooks.length} Books`
|
||||
@@ -1089,6 +1200,8 @@ export function useContentPanel() {
|
||||
else if (visibleTVSeries.length > 1) panelTitle.value = `${visibleTVSeries.length} TV Series`
|
||||
else if (visibleSongs.length === 1) panelTitle.value = visibleSongs[0].title
|
||||
else if (visibleSongs.length > 1) panelTitle.value = `${visibleSongs.length} Songs`
|
||||
else if (visiblePlaces.length === 1) panelTitle.value = visiblePlaces[0].name
|
||||
else if (visiblePlaces.length > 1) panelTitle.value = `${visiblePlaces.length} Places`
|
||||
else if (visiblePodcasts.length === 1) panelTitle.value = visiblePodcasts[0].title
|
||||
else if (visiblePodcasts.length > 1) panelTitle.value = `${visiblePodcasts.length} Podcasts`
|
||||
else if (visibleNews.length > 0) {
|
||||
@@ -1130,12 +1243,14 @@ export function useContentPanel() {
|
||||
const websitesLinks = mergeNewsResults(websitesFromMd, boldDomains)
|
||||
const hasWebsites = websitesLinks.length > 0
|
||||
const images = extractAllImages(text, userQuery)
|
||||
const tabs = filterTabsByContext(userQuery, films.length > 0, songs.length > 0, podcasts.length > 0, books.length > 0, tvSeries.length > 0, images.length > 0, hasNews, hasWebsites, hasMagazine)
|
||||
const places = extractAllPlaces(text, userQuery)
|
||||
const tabs = filterTabsByContext(userQuery, films.length > 0, songs.length > 0, podcasts.length > 0, books.length > 0, tvSeries.length > 0, images.length > 0, places.length > 0, hasNews, hasWebsites, hasMagazine)
|
||||
return {
|
||||
films: tabs.includes('film') ? films : [],
|
||||
books: tabs.includes('book') ? books : [],
|
||||
tvSeries: tabs.includes('tvshow') ? tvSeries : [],
|
||||
images: tabs.includes('image') ? images : [],
|
||||
places: tabs.includes('place') ? places : [],
|
||||
songs: tabs.includes('song') ? songs : [],
|
||||
podcasts: tabs.includes('podcast') ? podcasts : [],
|
||||
newsLinks: tabs.includes('news') ? newsLinks : [],
|
||||
@@ -1183,8 +1298,15 @@ export function useContentPanel() {
|
||||
.trim()
|
||||
}
|
||||
|
||||
function stripPlaceTags(text: string): string {
|
||||
return text
|
||||
.replace(PLACE_EXT_RE, '')
|
||||
.replace(/\n{3,}/g, '\n\n')
|
||||
.trim()
|
||||
}
|
||||
|
||||
function stripContentTags(text: string): string {
|
||||
return stripFilmTags(stripSongTags(stripPodcastTags(stripBookTags(stripTVTags(text)))))
|
||||
return stripFilmTags(stripSongTags(stripPodcastTags(stripBookTags(stripTVTags(stripPlaceTags(text))))))
|
||||
}
|
||||
|
||||
/** Remove markdown links when surfacing as inline cards to avoid duplication */
|
||||
@@ -1201,9 +1323,12 @@ export function useContentPanel() {
|
||||
selectedBook.value = null
|
||||
selectedTVSeries.value = null
|
||||
selectedImage.value = null
|
||||
selectedPlace.value = null
|
||||
selectedSong.value = null
|
||||
selectedPodcast.value = null
|
||||
selectedArticle.value = null
|
||||
selectedWebsite.value = null
|
||||
selectedMagazineSection.value = null
|
||||
}
|
||||
|
||||
function closeFilmDetail() {
|
||||
@@ -1215,9 +1340,12 @@ export function useContentPanel() {
|
||||
selectedFilm.value = null
|
||||
selectedTVSeries.value = null
|
||||
selectedImage.value = null
|
||||
selectedPlace.value = null
|
||||
selectedSong.value = null
|
||||
selectedPodcast.value = null
|
||||
selectedArticle.value = null
|
||||
selectedWebsite.value = null
|
||||
selectedMagazineSection.value = null
|
||||
}
|
||||
|
||||
function closeBookDetail() {
|
||||
@@ -1230,8 +1358,11 @@ export function useContentPanel() {
|
||||
selectedBook.value = null
|
||||
selectedTVSeries.value = null
|
||||
selectedImage.value = null
|
||||
selectedPlace.value = null
|
||||
selectedPodcast.value = null
|
||||
selectedArticle.value = null
|
||||
selectedWebsite.value = null
|
||||
selectedMagazineSection.value = null
|
||||
}
|
||||
|
||||
function closeSongDetail() {
|
||||
@@ -1244,8 +1375,11 @@ export function useContentPanel() {
|
||||
selectedBook.value = null
|
||||
selectedTVSeries.value = null
|
||||
selectedImage.value = null
|
||||
selectedPlace.value = null
|
||||
selectedSong.value = null
|
||||
selectedArticle.value = null
|
||||
selectedWebsite.value = null
|
||||
selectedMagazineSection.value = null
|
||||
}
|
||||
|
||||
function closePodcastDetail() {
|
||||
@@ -1258,8 +1392,11 @@ export function useContentPanel() {
|
||||
selectedBook.value = null
|
||||
selectedTVSeries.value = null
|
||||
selectedImage.value = null
|
||||
selectedPlace.value = null
|
||||
selectedSong.value = null
|
||||
selectedPodcast.value = null
|
||||
selectedWebsite.value = null
|
||||
selectedMagazineSection.value = null
|
||||
panelOpen.value = true
|
||||
}
|
||||
|
||||
@@ -1267,14 +1404,63 @@ export function useContentPanel() {
|
||||
selectedArticle.value = null
|
||||
}
|
||||
|
||||
function openWebsiteDetail(website: WebSearchResult) {
|
||||
selectedWebsite.value = website
|
||||
selectedFilm.value = null
|
||||
selectedBook.value = null
|
||||
selectedTVSeries.value = null
|
||||
selectedImage.value = null
|
||||
selectedPlace.value = null
|
||||
selectedSong.value = null
|
||||
selectedPodcast.value = null
|
||||
selectedArticle.value = null
|
||||
panelOpen.value = true
|
||||
}
|
||||
|
||||
function closeWebsiteDetail() {
|
||||
selectedWebsite.value = null
|
||||
}
|
||||
|
||||
function openMagazineSectionDetail(section: MagazineSection, index: number) {
|
||||
selectedMagazineSection.value = section
|
||||
magazineSectionIndex.value = index
|
||||
selectedFilm.value = null
|
||||
selectedBook.value = null
|
||||
selectedTVSeries.value = null
|
||||
selectedImage.value = null
|
||||
selectedPlace.value = null
|
||||
selectedSong.value = null
|
||||
selectedPodcast.value = null
|
||||
selectedArticle.value = null
|
||||
selectedWebsite.value = null
|
||||
}
|
||||
|
||||
function closeMagazineSectionDetail() {
|
||||
selectedMagazineSection.value = null
|
||||
}
|
||||
|
||||
function navigateMagazineSection(direction: 'prev' | 'next') {
|
||||
const sections = panelMagazineSections.value
|
||||
if (!sections.length) return
|
||||
let idx = magazineSectionIndex.value
|
||||
idx += direction === 'next' ? 1 : -1
|
||||
if (idx < 0) idx = sections.length - 1
|
||||
if (idx >= sections.length) idx = 0
|
||||
magazineSectionIndex.value = idx
|
||||
selectedMagazineSection.value = sections[idx]
|
||||
}
|
||||
|
||||
function openTVSeriesDetail(series: TVSeries) {
|
||||
selectedTVSeries.value = series
|
||||
selectedFilm.value = null
|
||||
selectedBook.value = null
|
||||
selectedImage.value = null
|
||||
selectedPlace.value = null
|
||||
selectedSong.value = null
|
||||
selectedPodcast.value = null
|
||||
selectedArticle.value = null
|
||||
selectedWebsite.value = null
|
||||
selectedMagazineSection.value = null
|
||||
}
|
||||
|
||||
function closeTVSeriesDetail() {
|
||||
@@ -1286,24 +1472,47 @@ export function useContentPanel() {
|
||||
selectedFilm.value = null
|
||||
selectedBook.value = null
|
||||
selectedTVSeries.value = null
|
||||
selectedPlace.value = null
|
||||
selectedSong.value = null
|
||||
selectedPodcast.value = null
|
||||
selectedArticle.value = null
|
||||
selectedWebsite.value = null
|
||||
selectedMagazineSection.value = null
|
||||
}
|
||||
|
||||
function closeImageDetail() {
|
||||
selectedImage.value = null
|
||||
}
|
||||
|
||||
function openPlaceDetail(place: Place) {
|
||||
selectedPlace.value = place
|
||||
selectedFilm.value = null
|
||||
selectedBook.value = null
|
||||
selectedTVSeries.value = null
|
||||
selectedImage.value = null
|
||||
selectedSong.value = null
|
||||
selectedPodcast.value = null
|
||||
selectedArticle.value = null
|
||||
selectedWebsite.value = null
|
||||
selectedMagazineSection.value = null
|
||||
}
|
||||
|
||||
function closePlaceDetail() {
|
||||
selectedPlace.value = null
|
||||
}
|
||||
|
||||
function closePanel() {
|
||||
panelOpen.value = false
|
||||
selectedFilm.value = null
|
||||
selectedBook.value = null
|
||||
selectedTVSeries.value = null
|
||||
selectedImage.value = null
|
||||
selectedPlace.value = null
|
||||
selectedSong.value = null
|
||||
selectedPodcast.value = null
|
||||
selectedArticle.value = null
|
||||
selectedWebsite.value = null
|
||||
selectedMagazineSection.value = null
|
||||
activeTab.value = 'film'
|
||||
availableTabs.value = []
|
||||
}
|
||||
@@ -1319,6 +1528,8 @@ export function useContentPanel() {
|
||||
selectedSong.value = null
|
||||
selectedPodcast.value = null
|
||||
selectedArticle.value = null
|
||||
selectedWebsite.value = null
|
||||
selectedMagazineSection.value = null
|
||||
}
|
||||
|
||||
function showAllSongs() {
|
||||
@@ -1332,6 +1543,8 @@ export function useContentPanel() {
|
||||
selectedSong.value = null
|
||||
selectedPodcast.value = null
|
||||
selectedArticle.value = null
|
||||
selectedWebsite.value = null
|
||||
selectedMagazineSection.value = null
|
||||
}
|
||||
|
||||
function showAllPodcasts() {
|
||||
@@ -1353,6 +1566,7 @@ export function useContentPanel() {
|
||||
panelBooks,
|
||||
panelTVSeries,
|
||||
panelImages,
|
||||
panelPlaces,
|
||||
panelSongs,
|
||||
panelPodcasts,
|
||||
panelWebResults,
|
||||
@@ -1363,9 +1577,13 @@ export function useContentPanel() {
|
||||
selectedBook,
|
||||
selectedTVSeries,
|
||||
selectedImage,
|
||||
selectedPlace,
|
||||
selectedSong,
|
||||
selectedPodcast,
|
||||
selectedArticle,
|
||||
selectedWebsite,
|
||||
selectedMagazineSection,
|
||||
magazineSectionIndex,
|
||||
panelTitle,
|
||||
panelQuery,
|
||||
contentType,
|
||||
@@ -1383,6 +1601,8 @@ export function useContentPanel() {
|
||||
closeTVSeriesDetail,
|
||||
openImageDetail,
|
||||
closeImageDetail,
|
||||
openPlaceDetail,
|
||||
closePlaceDetail,
|
||||
extractSongIds,
|
||||
resolveSongs,
|
||||
extractAllSongs,
|
||||
@@ -1404,6 +1624,11 @@ export function useContentPanel() {
|
||||
closePodcastDetail,
|
||||
openArticleDetail,
|
||||
closeArticleDetail,
|
||||
openWebsiteDetail,
|
||||
closeWebsiteDetail,
|
||||
openMagazineSectionDetail,
|
||||
closeMagazineSectionDetail,
|
||||
navigateMagazineSection,
|
||||
closePanel,
|
||||
showAllFilms,
|
||||
showAllSongs,
|
||||
|
||||
Reference in New Issue
Block a user