feat(app): register film and song renderers via plugin system

Create film-renderer.ts and song-renderer.ts as RendererDefinition
plugins using defineAsyncComponent for lazy loading. ContentPanel.vue
now looks up film/song components via getRendererForContentType()
instead of direct imports, enabling future community renderer plugins.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Dorian
2026-03-03 20:39:28 +00:00
co-authored by Claude Opus 4.6
parent ad4612a5c2
commit 557f9e6220
4 changed files with 49 additions and 13 deletions
@@ -55,8 +55,9 @@
<div class="flex-1 min-h-0">
<ErrorBoundary title="Content failed to load">
<!-- Detail views (override tab content) -->
<FilmDetail
v-if="selectedFilm"
<component
:is="filmRenderer?.panelPlay"
v-if="selectedFilm && filmRenderer?.panelPlay"
:film="selectedFilm"
@back="closeFilmDetail"
/>
@@ -70,8 +71,9 @@
:series="selectedTVSeries"
@back="closeTVSeriesDetail"
/>
<SongDetail
v-else-if="selectedSong"
<component
:is="songRenderer?.panelPlay"
v-else-if="selectedSong && songRenderer?.panelPlay"
:song="selectedSong"
@back="closeSongDetail"
/>
@@ -87,8 +89,9 @@
/>
<!-- Grid views by active tab -->
<FilmGrid
v-else-if="activeTab === 'film'"
<component
:is="filmRenderer?.panelPreview"
v-else-if="activeTab === 'film' && filmRenderer?.panelPreview"
:films="panelFilms"
:title="panelTitle"
@select-film="openFilmDetail"
@@ -105,8 +108,9 @@
:title="panelTitle"
@select-series="openTVSeriesDetail"
/>
<SongGrid
v-else-if="activeTab === 'song'"
<component
:is="songRenderer?.panelPreview"
v-else-if="activeTab === 'song' && songRenderer?.panelPreview"
:songs="panelSongs"
:title="panelTitle"
@select-song="openSongDetail"
@@ -154,14 +158,11 @@
import { computed, onMounted, onUnmounted, ref } from 'vue'
import { useTheme } from '@/composables/useTheme'
import { useContentPanel, type ContentTab } from '@/composables/useContentPanel'
import FilmGrid from './FilmGrid.vue'
import FilmDetail from './FilmDetail.vue'
import { getRendererForContentType } from '@aiui/core'
import BookGrid from './BookGrid.vue'
import BookDetail from './BookDetail.vue'
import TVSeriesGrid from './TVSeriesGrid.vue'
import TVSeriesDetail from './TVSeriesDetail.vue'
import SongGrid from './SongGrid.vue'
import SongDetail from './SongDetail.vue'
import PodcastGrid from './PodcastGrid.vue'
import PodcastDetail from './PodcastDetail.vue'
import NewsGrid from './NewsGrid.vue'
@@ -171,6 +172,10 @@ import ProjectGrid from './ProjectGrid.vue'
import NostrGrid from './NostrGrid.vue'
import ErrorBoundary from '@/components/ui/ErrorBoundary.vue'
// Film and song renderers loaded from plugin registry
const filmRenderer = computed(() => getRendererForContentType('film'))
const songRenderer = computed(() => getRendererForContentType('song'))
const { isDark } = useTheme()
const {
panelOpen,