Files
lidify/frontend/app/audiobooks/[id]/page.tsx
2025-12-25 18:58:06 -06:00

134 lines
4.8 KiB
TypeScript

"use client";
import { GradientSpinner } from "@/components/ui/GradientSpinner";
import { useImageColor } from "@/hooks/useImageColor";
import { formatTime } from "@/utils/formatTime";
// Hooks
import { useAudiobookData } from "@/features/audiobook/hooks/useAudiobookData";
import { useAudiobookActions } from "@/features/audiobook/hooks/useAudiobookActions";
// Components
import { AudiobookHero } from "@/features/audiobook/components/AudiobookHero";
import { AudiobookActionBar } from "@/features/audiobook/components/AudiobookActionBar";
export default function AudiobookDetailPage() {
// Data hook
const { audiobookId, audiobook, isLoading, refetch, heroImage, metadata } =
useAudiobookData();
// Extract colors from the hero image
const { colors } = useImageColor(heroImage);
// Action hooks
const {
isThisBookPlaying,
isPlaying,
currentTime,
handlePlayPause,
handleMarkAsCompleted,
handleResetProgress,
} = useAudiobookActions(audiobookId, audiobook, refetch);
// Loading state
if (isLoading) {
return (
<div className="flex items-center justify-center min-h-screen">
<GradientSpinner size="md" />
</div>
);
}
if (!audiobook) {
return (
<div className="flex items-center justify-center min-h-screen">
<p className="text-gray-500">Audiobook not found</p>
</div>
);
}
// Clean up description - strip HTML and clean whitespace
const cleanDescription = audiobook.description
? audiobook.description
.replace(/<[^>]*>/g, " ")
.replace(/\s+/g, " ")
.trim()
: null;
const showDescription =
cleanDescription &&
!cleanDescription.match(/^(Read by|Narrated by):/i) &&
cleanDescription.length > 20;
return (
<div className="min-h-screen flex flex-col">
<AudiobookHero
audiobook={audiobook}
heroImage={heroImage}
colors={colors}
metadata={metadata}
formatTime={formatTime}
>
<AudiobookActionBar
audiobook={audiobook}
isThisBookPlaying={isThisBookPlaying}
isPlaying={isPlaying}
currentTime={currentTime}
onPlayPause={handlePlayPause}
onResetProgress={handleResetProgress}
onMarkAsCompleted={handleMarkAsCompleted}
formatTime={formatTime}
/>
</AudiobookHero>
{/* Main Content */}
<div className="relative flex-1">
<div
className="absolute inset-0 pointer-events-none"
style={{
background: colors
? `linear-gradient(to bottom, ${colors.vibrant}15 0%, ${colors.vibrant}08 15%, ${colors.darkVibrant}05 30%, transparent 50%)`
: "transparent",
}}
/>
<div className="relative px-4 md:px-8 py-8 space-y-6">
{/* Description / About */}
{showDescription && (
<section className="hidden md:block">
<h2 className="text-xl font-bold mb-4">About</h2>
<div className="bg-white/5 rounded-md p-4">
<p className="text-sm text-white/70 leading-relaxed">
{cleanDescription}
</p>
</div>
</section>
)}
{/* Series info */}
{audiobook.series && (
<section>
<h2 className="text-xl font-bold mb-4">Series</h2>
<div className="flex items-center gap-3 text-sm">
<span className="text-[#ecb200] font-medium">
{audiobook.series.name}
</span>
<span className="text-white/40"></span>
<span className="text-white/70">
Book {audiobook.series.sequence}
</span>
</div>
</section>
)}
{/* Playback hint - more subtle */}
<p className="text-xs text-white/40 pt-4">
Use the player controls in the bottom bar for playback
speed, seeking, and volume.
</p>
</div>
</div>
</div>
);
}