-
-

+
+ ✦
- Ask about films or songs in the chat to see rich content here.
+ Ask about films, songs, or podcasts in the chat to see rich content here.
@@ -100,6 +189,8 @@ import FilmGrid from '@/components/content/FilmGrid.vue'
import FilmDetail from '@/components/content/FilmDetail.vue'
import SongGrid from '@/components/content/SongGrid.vue'
import SongDetail from '@/components/content/SongDetail.vue'
+import PodcastGrid from '@/components/content/PodcastGrid.vue'
+import PodcastDetail from '@/components/content/PodcastDetail.vue'
import ContextLoader from '@/components/content/ContextLoader.vue'
import PlayerBar from '@/components/player/PlayerBar.vue'
import { usePlayer } from '@/composables/usePlayer'
@@ -114,14 +205,19 @@ const {
panelOpen,
panelFilms,
panelSongs,
+ panelPodcasts,
panelTitle,
contentType,
selectedFilm,
selectedSong,
+ selectedPodcast,
openFilmDetail,
closeFilmDetail,
openSongDetail,
closeSongDetail,
+ openPodcastDetail,
+ closePodcastDetail,
+ closePanel,
} = useContentPanel()
const panelSide = computed(() => chatStore.panelSide)
@@ -132,6 +228,7 @@ const loaderContextType = computed(() => {
const lastUser = [...chatStore.messages].reverse().find((m) => m.role === 'user')
const q = (lastUser?.content ?? '').toLowerCase()
if (/\b(song|music|track|album|band|artist|listen)\b/.test(q)) return 'song'
+ if (/\b(podcast|episode|show|listen to)\b/.test(q)) return 'podcast'
return contentType.value
})
diff --git a/packages/app/src/styles/main.css b/packages/app/src/styles/main.css
index b32fb8ff..53beb48a 100644
--- a/packages/app/src/styles/main.css
+++ b/packages/app/src/styles/main.css
@@ -644,6 +644,38 @@ input:focus-visible {
inset 0 1px 0 rgba(255, 255, 255, 0.5);
}
+/* Empty state icon — app icon in glassmorphic square, white, path-glass border */
+.empty-state-icon {
+ position: relative;
+}
+
+/* Frosted glass center behind the icon */
+.empty-state-icon::before {
+ content: '';
+ position: absolute;
+ inset: 15%;
+ border-radius: 50%;
+ background: rgba(255, 255, 255, 0.06);
+ backdrop-filter: blur(12px);
+ -webkit-backdrop-filter: blur(12px);
+ pointer-events: none;
+}
+
+.empty-state-icon img {
+ position: relative;
+ z-index: 1;
+ filter: brightness(0) invert(1);
+}
+
+.light .empty-state-icon::before {
+ background: rgba(0, 0, 0, 0.04);
+}
+
+.light .empty-state-icon img {
+ filter: brightness(0) saturate(100%);
+ opacity: 0.75;
+}
+
.animate-fade-up {
animation: fadeUpIn 900ms cubic-bezier(0.22, 1, 0.36, 1) 120ms both;
}
diff --git a/packages/app/vite.config.ts b/packages/app/vite.config.ts
index 50183fdc..d8eb6732 100644
--- a/packages/app/vite.config.ts
+++ b/packages/app/vite.config.ts
@@ -72,7 +72,7 @@ export default defineConfig({
server: {
port: 5173,
host: true,
- open: true,
+ open: false,
proxy: {
'/api/claude': {
target: 'http://localhost:3141',
diff --git a/packages/core/src/types/content.ts b/packages/core/src/types/content.ts
index 8de724f0..de021155 100644
--- a/packages/core/src/types/content.ts
+++ b/packages/core/src/types/content.ts
@@ -52,3 +52,28 @@ export interface Song {
genres?: string[]
sources?: SongSource[]
}
+
+export interface PodcastSource {
+ type: 'fountain' | 'rumble' | 'youtube' | 'podcastindex' | 'castopod' | 'odysee' | 'podverse' | 'ipfs' | 'rss'
+ name: string
+ url: string
+ icon?: string
+}
+
+export interface Podcast {
+ id: string
+ title: string
+ host?: string
+ description?: string
+ coverUrl?: string
+ year?: number
+ episodeCount?: number
+ genres?: string[]
+ sources: PodcastSource[]
+}
+
+export interface PodcastRendererData {
+ podcasts: Podcast[]
+ query?: string
+ totalResults?: number
+}