diff --git a/src/app/components/DeviceDetailOverlay.tsx b/src/app/components/DeviceDetailOverlay.tsx index d81615a..09379c4 100644 --- a/src/app/components/DeviceDetailOverlay.tsx +++ b/src/app/components/DeviceDetailOverlay.tsx @@ -4,7 +4,7 @@ import { motion, AnimatePresence } from 'motion/react'; import { toast } from 'sonner'; import { fileExists, getFileContents, joinPath } from '../webdav'; import MediaBrowser from './MediaBrowser'; -import MediaSet from './MediaSet'; +import MediaSet, { type MediaSetEntry } from './MediaSet'; interface Device { id: string; @@ -122,11 +122,11 @@ export default function DeviceDetailOverlay({ }; // Prefer an explicit .lst-derived mediaSet stored in config; fall back to pattern detection. - const [mediaSetFiles, setMediaSetFiles] = useState(null); + const [mediaSetFiles, setMediaSetFiles] = useState(null); useEffect(() => { if (Array.isArray(deviceData.media_set) && deviceData.media_set.length > 0) { - setMediaSetFiles(deviceData.media_set as string[]); + setMediaSetFiles(deviceData.media_set as MediaSetEntry[]); return; } if (!deviceData.url) { setMediaSetFiles(null); return; } diff --git a/src/app/components/MediaSet.tsx b/src/app/components/MediaSet.tsx index 1de5c45..4768419 100644 --- a/src/app/components/MediaSet.tsx +++ b/src/app/components/MediaSet.tsx @@ -1,7 +1,20 @@ +export type MediaSetEntry = string | { url: string; name?: string }; + +export function mediaSetEntryUrl(e: MediaSetEntry): string { + return typeof e === 'string' ? e : e.url; +} + +function entryLabel(e: MediaSetEntry, index: number): string { + if (typeof e === 'object' && e.name) return `${index + 1}: ${e.name}`; + const file = mediaSetEntryUrl(e); + const fileName = file.split('/').pop() || file; + return `${index + 1}: ${fileName.replace(/\.[^.]+$/, '')}`; +} + interface MediaSetProps { - files: string[]; + files: MediaSetEntry[]; activeUrl: string; - onSwitch: (file: string) => void; + onSwitch: (url: string) => void; } export default function MediaSet({ files, activeUrl, onSwitch }: MediaSetProps) { @@ -9,21 +22,21 @@ export default function MediaSet({ files, activeUrl, onSwitch }: MediaSetProps)
Media Set
- {files.map((file, index) => { - const fileName = file.split('/').pop() || file; - const title = fileName.replace(/\.[^.]+$/, ''); - const active = activeUrl === file; + {files.map((entry, index) => { + const url = mediaSetEntryUrl(entry); + const label = entryLabel(entry, index); + const active = activeUrl === url; return ( ); })} diff --git a/src/app/components/StatusPage.tsx b/src/app/components/StatusPage.tsx index 402d705..7ace78b 100644 --- a/src/app/components/StatusPage.tsx +++ b/src/app/components/StatusPage.tsx @@ -6,7 +6,7 @@ import { MediaEntry } from './MediaEntry'; import DirectorySlideshow from './DirectorySlideshow'; import { useWs } from '../ws'; import DeviceDetailOverlay from './DeviceDetailOverlay'; -import MediaSet from './MediaSet'; +import MediaSet, { type MediaSetEntry } from './MediaSet'; import { ImageWithFallback } from './figma/ImageWithFallback'; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription } from './ui/dialog'; import { ConfirmDialog, type ConfirmOptions } from './ui/confirm-dialog'; @@ -45,10 +45,10 @@ export default function StatusPage({ config, setConfig, onOpenFileManager }: Sta ? (activeDevice.base_url || splitPath(activeDevice.url || '/').parent) : null; - const mediaSetFiles: string[] | null = (() => { + const mediaSetFiles: MediaSetEntry[] | null = (() => { if (!activeDevice?.url) return null; if (Array.isArray(activeDevice.media_set) && activeDevice.media_set.length > 0) - return activeDevice.media_set as string[]; + return activeDevice.media_set as MediaSetEntry[]; const match = (activeDevice.url as string).match(/^(.+?)(\d+)(\.[^.]+)$/); if (!match) return null; const [, prefix, , ext] = match;