Series detail: one season at a time with 3D jukebox season selector

Render only the selected season's episodes; switch via a perspective-arc
poster carousel with floating season info, deferred video loading with
still-image fade-in, and spoiler fade for episodes ahead of the cursor.
This commit is contained in:
2026-09-10 03:34:52 +00:00
parent e6eadb2ecd
commit 2c28ab1f25
3 changed files with 665 additions and 491 deletions
+7 -2
View File
@@ -1122,10 +1122,15 @@ function focusDetailEntryTarget(item: MediaItem): boolean {
'[data-nav-release-item="true"][data-nav-row="2"][data-nav-col="0"][data-nav-focusable="true"]',
) as HTMLElement | null
} else if (item.type === "series") {
// Initial episode tile (first season, first episode) maps to row 2 / col 0.
// Row 2 is the season selector strip; land on the selected season poster.
target = detailPanel.querySelector(
'.episode-tile[data-nav-row="2"][data-nav-col="0"][data-nav-focusable="true"]',
'.season-poster-card.season-poster-card--selected[data-nav-focusable="true"]',
) as HTMLElement | null
if (!target) {
target = detailPanel.querySelector(
'.episode-tile[data-nav-focusable="true"]',
) as HTMLElement | null
}
}
if (target) {
-19
View File
@@ -883,14 +883,6 @@ const ratingClass = computed(() => {
return "rating-low"
})
const seasons = computed(() => {
if (props.item.type !== "series") return []
const series = props.item.data as Series
return series.seasons || []
})
const selectedSeasonIndex = ref<number>(0)
const versionActionMenu = ref<{
visible: boolean
x: number
@@ -977,17 +969,6 @@ function handleMovieMenuKeydown(event: KeyboardEvent) {
}
}
// Select first season by default
watch(
seasons,
(s) => {
if (s.length > 0 && selectedSeasonIndex.value >= s.length) {
selectedSeasonIndex.value = 0
}
},
{ immediate: true },
)
function handlePlay(filePath: string | null) {
if (filePath) {
emit("play", filePath)
File diff suppressed because it is too large Load Diff