add viewer navigation and doom scroll mode
- Add prev/next arrow buttons and ArrowLeft/ArrowRight keyboard shortcuts to ImageLightbox and VideoPlayerModal - Wire prev/next navigation in MixedView (through filtered media entries), TvView (through season episodes), and MoviesView/MovieDetailModal (through filtered movie list) - Add new DoomScrollView component: fullscreen random-media mode with scroll/swipe/keyboard navigation, 100-item back-history, and per-library mute settings - Add Doom Scroll button to mixed, movies, and TV library views - Doom scroll respects active filters: mixed uses filtered entries, movies uses filtered movie list, TV fetches episodes from matching series only Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -9,11 +9,13 @@ interface Props {
|
||||
movie: Movie
|
||||
libraryId: string
|
||||
onClose: () => void
|
||||
onPrev?: () => void
|
||||
onNext?: () => void
|
||||
onTagsChanged?: () => void
|
||||
onDeleted: (movieId: string) => void
|
||||
}
|
||||
|
||||
export default function MovieDetailModal({ movie, libraryId, onClose, onTagsChanged, onDeleted }: Props) {
|
||||
export default function MovieDetailModal({ movie, libraryId, onClose, onPrev, onNext, onTagsChanged, onDeleted }: Props) {
|
||||
const overlayRef = useRef<HTMLDivElement>(null)
|
||||
const menuRef = useRef<HTMLDivElement>(null)
|
||||
const [playing, setPlaying] = useState(false)
|
||||
@@ -72,6 +74,8 @@ export default function MovieDetailModal({ movie, libraryId, onClose, onTagsChan
|
||||
mediaKey={`${libraryId}:${movie.id}`}
|
||||
onTagsChanged={onTagsChanged}
|
||||
onClose={() => setPlaying(false)}
|
||||
onPrev={onPrev}
|
||||
onNext={onNext}
|
||||
context="movies"
|
||||
/>
|
||||
)
|
||||
@@ -102,6 +106,32 @@ export default function MovieDetailModal({ movie, libraryId, onClose, onTagsChan
|
||||
✕
|
||||
</button>
|
||||
|
||||
{/* Prev / Next buttons on the detail card */}
|
||||
{onPrev && (
|
||||
<button
|
||||
onClick={onPrev}
|
||||
className="absolute top-3 left-3 z-10 w-8 h-8 rounded-full flex items-center justify-center text-sm transition-colors"
|
||||
style={{ backgroundColor: 'rgba(0,0,0,0.5)', color: 'var(--text-primary)' }}
|
||||
onMouseEnter={(e) => ((e.currentTarget as HTMLElement).style.backgroundColor = 'rgba(0,0,0,0.8)')}
|
||||
onMouseLeave={(e) => ((e.currentTarget as HTMLElement).style.backgroundColor = 'rgba(0,0,0,0.5)')}
|
||||
aria-label="Previous movie"
|
||||
>
|
||||
‹
|
||||
</button>
|
||||
)}
|
||||
{onNext && (
|
||||
<button
|
||||
onClick={onNext}
|
||||
className="absolute top-3 z-10 w-8 h-8 rounded-full flex items-center justify-center text-sm transition-colors"
|
||||
style={{ backgroundColor: 'rgba(0,0,0,0.5)', color: 'var(--text-primary)', right: onPrev ? '3rem' : undefined }}
|
||||
onMouseEnter={(e) => ((e.currentTarget as HTMLElement).style.backgroundColor = 'rgba(0,0,0,0.8)')}
|
||||
onMouseLeave={(e) => ((e.currentTarget as HTMLElement).style.backgroundColor = 'rgba(0,0,0,0.5)')}
|
||||
aria-label="Next movie"
|
||||
>
|
||||
›
|
||||
</button>
|
||||
)}
|
||||
|
||||
{/* Hero image */}
|
||||
<div className="w-full" style={{ backgroundColor: 'var(--border)' }}>
|
||||
{heroUrl ? (
|
||||
|
||||
Reference in New Issue
Block a user