2026-03-02 16:48:17 +00:00
|
|
|
import { ref, computed } from 'vue'
|
|
|
|
|
import type { Film } from '@aiui/core/types/content'
|
|
|
|
|
import { mockFilms } from '@/mocks/films'
|
|
|
|
|
|
|
|
|
|
const panelOpen = ref(false)
|
|
|
|
|
const panelFilms = ref<Film[]>([])
|
|
|
|
|
const selectedFilm = ref<Film | null>(null)
|
|
|
|
|
const panelTitle = ref('Recommended Films')
|
|
|
|
|
|
2026-03-02 16:49:47 +00:00
|
|
|
const FILM_TAG_RE = /\[\[film:(f?\d+)\]\]/gi
|
2026-03-02 16:48:17 +00:00
|
|
|
|
|
|
|
|
export function useContentPanel() {
|
2026-03-02 16:49:47 +00:00
|
|
|
function normalizeFilmId(raw: string): string {
|
|
|
|
|
return raw.startsWith('f') ? raw : `f${raw}`
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-02 16:48:17 +00:00
|
|
|
function extractFilmIds(text: string): string[] {
|
|
|
|
|
const ids: string[] = []
|
|
|
|
|
let match: RegExpExecArray | null
|
2026-03-02 16:49:47 +00:00
|
|
|
const re = new RegExp(FILM_TAG_RE.source, 'gi')
|
2026-03-02 16:48:17 +00:00
|
|
|
while ((match = re.exec(text)) !== null) {
|
2026-03-02 16:49:47 +00:00
|
|
|
const id = normalizeFilmId(match[1])
|
|
|
|
|
if (!ids.includes(id)) ids.push(id)
|
2026-03-02 16:48:17 +00:00
|
|
|
}
|
|
|
|
|
return ids
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function resolveFilms(ids: string[]): Film[] {
|
|
|
|
|
return ids
|
|
|
|
|
.map((id) => mockFilms.find((f) => f.id === id))
|
|
|
|
|
.filter((f): f is Film => !!f)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function updatePanelFromText(text: string) {
|
|
|
|
|
const ids = extractFilmIds(text)
|
|
|
|
|
if (ids.length > 0) {
|
|
|
|
|
const films = resolveFilms(ids)
|
|
|
|
|
if (films.length > 0) {
|
|
|
|
|
panelFilms.value = films
|
|
|
|
|
panelOpen.value = true
|
|
|
|
|
panelTitle.value = films.length === 1
|
|
|
|
|
? films[0].title
|
|
|
|
|
: `${films.length} Recommended Films`
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function stripFilmTags(text: string): string {
|
|
|
|
|
return text.replace(FILM_TAG_RE, '').replace(/\n{3,}/g, '\n\n').trim()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function openFilmDetail(film: Film) {
|
|
|
|
|
selectedFilm.value = film
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function closeFilmDetail() {
|
|
|
|
|
selectedFilm.value = null
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function closePanel() {
|
|
|
|
|
panelOpen.value = false
|
|
|
|
|
selectedFilm.value = null
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function showAllFilms() {
|
|
|
|
|
panelFilms.value = [...mockFilms]
|
|
|
|
|
panelTitle.value = 'Your Film Library'
|
|
|
|
|
panelOpen.value = true
|
|
|
|
|
selectedFilm.value = null
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
panelOpen,
|
|
|
|
|
panelFilms,
|
|
|
|
|
selectedFilm,
|
|
|
|
|
panelTitle,
|
|
|
|
|
extractFilmIds,
|
|
|
|
|
resolveFilms,
|
|
|
|
|
updatePanelFromText,
|
|
|
|
|
stripFilmTags,
|
|
|
|
|
openFilmDetail,
|
|
|
|
|
closeFilmDetail,
|
|
|
|
|
closePanel,
|
|
|
|
|
showAllFilms,
|
|
|
|
|
}
|
|
|
|
|
}
|