feat: build interactive documentary page with audio player and chapter navigation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
consultoria-as
2026-02-22 04:07:22 +00:00
parent e7e58bba29
commit 279ab5e822
9 changed files with 443 additions and 0 deletions

View File

@@ -0,0 +1,74 @@
"use client";
import { useEffect, useState } from "react";
import type { Documentary, Chapter } from "@afterlife/shared";
import { ChapterNav } from "./ChapterNav";
import { ChapterContent } from "./ChapterContent";
import { AudioPlayer } from "./AudioPlayer";
import { ReadingProgress } from "./ReadingProgress";
import { useAudioPlayer } from "@/hooks/useAudioPlayer";
interface DocumentaryLayoutProps {
documentary: Documentary;
}
export function DocumentaryLayout({ documentary }: DocumentaryLayoutProps) {
const chapters = [...documentary.chapters].sort((a, b) => a.order - b.order);
const [activeChapter, setActiveChapter] = useState<Chapter>(chapters[0]);
const audio = useAudioPlayer();
useEffect(() => {
const audioTracks = chapters
.filter((ch) => ch.audioFile)
.map((ch) => ({
id: ch.id,
title: ch.title,
url: ch.audioFile!.url,
duration: ch.audioDuration ?? 0,
}));
audio.setTracks(audioTracks);
if (audioTracks.length > 0) {
audio.loadTrack(0);
}
}, []); // eslint-disable-line react-hooks/exhaustive-deps
function handleSelectChapter(chapterId: number, index: number) {
const chapter = chapters.find((c) => c.id === chapterId);
if (chapter) {
setActiveChapter(chapter);
const trackIndex = audio.tracks.findIndex((t) => t.id === chapterId);
if (trackIndex !== -1) {
audio.goToTrack(trackIndex);
}
}
}
return (
<>
<ReadingProgress />
<div className="max-w-7xl mx-auto px-4 py-12 flex gap-8">
<ChapterNav
chapters={chapters}
activeChapterId={activeChapter.id}
onSelectChapter={handleSelectChapter}
/>
<div className="flex-1 pb-24">
<ChapterContent chapter={activeChapter} />
</div>
</div>
<AudioPlayer
trackTitle={audio.currentTrack?.title ?? null}
isPlaying={audio.isPlaying}
progress={audio.progress}
duration={audio.duration}
playbackRate={audio.playbackRate}
continuousMode={audio.continuousMode}
onToggle={audio.toggle}
onSeek={audio.seek}
onChangeRate={audio.changeRate}
onToggleContinuous={() => audio.setContinuousMode(!audio.continuousMode)}
/>
</>
);
}