"use client" import { useState, useEffect } from "react" import { Settings2, Headphones, X, Menu, ArrowUp } from "lucide-react" import { Button } from "@/components/ui/button" import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover" import { cn } from "@/lib/utils" import { ReadingSettingsContent } from "./reading-settings" import { TTSPlayer } from "./tts-player" import { ReaderTOC } from "./reader-toc" interface ReaderFABProps { novelId: string novelSlug: string // TTS Props paragraphs: string[] currentChapter: number maxChapter: number chapterTitle: string } export function ReaderFAB({ novelId, novelSlug, paragraphs, currentChapter, maxChapter, chapterTitle }: ReaderFABProps) { const [isOpen, setIsOpen] = useState(false) const [isTTSOpen, setIsTTSOpen] = useState(false) const [isTTSExpanded, setIsTTSExpanded] = useState(false) const [showScrollTop, setShowScrollTop] = useState(false) const [isMobileControlsVisible, setIsMobileControlsVisible] = useState(true) useEffect(() => { let lastScrollY = window.scrollY const handleScroll = () => { const currentY = window.scrollY setShowScrollTop(currentY > 400) const isMobile = window.innerWidth < 768 if (!isMobile) { setIsMobileControlsVisible(true) lastScrollY = currentY return } const delta = currentY - lastScrollY if (Math.abs(delta) < 12) { return } if (currentY < 120) { setIsMobileControlsVisible(true) } else if (delta > 0 && !isOpen && !isTTSOpen) { setIsMobileControlsVisible(false) } else if (delta < 0) { setIsMobileControlsVisible(true) } lastScrollY = currentY } window.addEventListener("scroll", handleScroll, { passive: true }) return () => window.removeEventListener("scroll", handleScroll) }, [isOpen, isTTSOpen]) const handleScrollToTop = () => { window.scrollTo({ top: 0, behavior: "smooth" }) } // Reading settings state lifted up for persistence const [fontSize, setFontSize] = useState(18) const [lineHeight, setLineHeight] = useState(1.8) const [letterSpacing, setLetterSpacing] = useState(0) const [fontFamily, setFontFamily] = useState("font-serif") useEffect(() => { // Dùng local storage chạy tạm thời gian đầu để khỏi giật màn hình const savedFontSize = localStorage.getItem("reader_fontSize") const savedLineHeight = localStorage.getItem("reader_lineHeight") const savedLetterSpacing = localStorage.getItem("reader_letterSpacing") const savedFontFamily = localStorage.getItem("reader_fontFamily") if (savedFontSize) setFontSize(Number(savedFontSize)) if (savedLineHeight) setLineHeight(Number(savedLineHeight)) if (savedLetterSpacing) setLetterSpacing(Number(savedLetterSpacing)) if (savedFontFamily) setFontFamily(savedFontFamily) // Đồng bộ Settings từ DB về (Ghi đè nếu có) fetch("/api/user/settings") .then(res => res.json()) .then(data => { if (data && !data.error && data.fontSize) { setFontSize(data.fontSize) setLineHeight(data.lineHeight) setLetterSpacing(data.letterSpacing) setFontFamily(data.fontFamily) localStorage.setItem("reader_fontSize", data.fontSize.toString()) localStorage.setItem("reader_lineHeight", data.lineHeight.toString()) localStorage.setItem("reader_letterSpacing", data.letterSpacing.toString()) localStorage.setItem("reader_fontFamily", data.fontFamily) } }) .catch(() => {}) }, []) useEffect(() => { localStorage.setItem("reader_fontSize", fontSize.toString()) localStorage.setItem("reader_lineHeight", lineHeight.toString()) localStorage.setItem("reader_letterSpacing", letterSpacing.toString()) localStorage.setItem("reader_fontFamily", fontFamily) const timer = setTimeout(() => { fetch("/api/user/settings", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ fontSize, lineHeight, letterSpacing, fontFamily }) }).catch(() => {}) }, 1000) return () => clearTimeout(timer) }, [fontSize, lineHeight, letterSpacing, fontFamily]) return ( <>