'use client'; import { Fragment, useState, useCallback, useEffect } from 'react'; import { Dialog, DialogPanel, Transition, TransitionChild, Listbox, ListboxButton, ListboxOptions, ListboxOption, Button } from '@headlessui/react'; import { useConfig, ViewType } from '@/contexts/ConfigContext'; import { ChevronUpDownIcon, CheckIcon } from '@/components/icons/Icons'; import { useEPUB } from '@/contexts/EPUBContext'; import { usePDF } from '@/contexts/PDFContext'; import { AudiobookExportModal } from '@/components/AudiobookExportModal'; import { useParams } from 'next/navigation'; const isDev = process.env.NEXT_PUBLIC_NODE_ENV !== 'production' || process.env.NODE_ENV == null; const viewTypes = [ { id: 'single', name: 'Single Page' }, { id: 'dual', name: 'Two Pages' }, { id: 'scroll', name: 'Continuous Scroll' }, ]; export function DocumentSettings({ isOpen, setIsOpen, epub, html }: { isOpen: boolean, setIsOpen: (isOpen: boolean) => void, epub?: boolean, html?: boolean }) { const { viewType, skipBlank, epubTheme, headerMargin, footerMargin, leftMargin, rightMargin, updateConfigKey } = useConfig(); const { createFullAudioBook: createEPUBAudioBook, regenerateChapter: regenerateEPUBChapter } = useEPUB(); const { createFullAudioBook: createPDFAudioBook, regenerateChapter: regeneratePDFChapter } = usePDF(); const { id } = useParams(); const [localMargins, setLocalMargins] = useState({ header: headerMargin, footer: footerMargin, left: leftMargin, right: rightMargin }); const [isAudiobookModalOpen, setIsAudiobookModalOpen] = useState(false); const selectedView = viewTypes.find(v => v.id === viewType) || viewTypes[0]; // Sync local margins with global state useEffect(() => { setLocalMargins({ header: headerMargin, footer: footerMargin, left: leftMargin, right: rightMargin }); }, [headerMargin, footerMargin, leftMargin, rightMargin]); // Handler for slider change (updates local state only) const handleMarginChange = (margin: keyof typeof localMargins) => (event: React.ChangeEvent) => { setLocalMargins(prev => ({ ...prev, [margin]: Number(event.target.value) })); }; // Handler for slider release const handleMarginChangeComplete = (margin: keyof typeof localMargins) => () => { const value = localMargins[margin]; const configKey = `${margin}Margin`; if (value !== (useConfig)[configKey as keyof typeof useConfig]) { updateConfigKey(configKey as 'headerMargin' | 'footerMargin' | 'leftMargin' | 'rightMargin', value); } }; const handleGenerateAudiobook = useCallback(async ( onProgress: (progress: number) => void, signal: AbortSignal, onChapterComplete: (chapter: { index: number; title: string; duration?: number; status: 'pending' | 'generating' | 'completed' | 'error'; bookId?: string; format?: 'mp3' | 'm4b' }) => void, format: 'mp3' | 'm4b' ) => { if (epub) { return createEPUBAudioBook(onProgress, signal, onChapterComplete, id as string, format); } else { return createPDFAudioBook(onProgress, signal, onChapterComplete, id as string, format); } }, [epub, createEPUBAudioBook, createPDFAudioBook, id]); const handleRegenerateChapter = useCallback(async ( chapterIndex: number, bookId: string, format: 'mp3' | 'm4b', onProgress: (progress: number) => void, signal: AbortSignal ) => { if (epub) { return regenerateEPUBChapter(chapterIndex, bookId, format, onProgress, signal); } else { return regeneratePDFChapter(chapterIndex, bookId, format, onProgress, signal); } }, [epub, regenerateEPUBChapter, regeneratePDFChapter]); return ( <> setIsOpen(false)}>
{isDev && !html &&
}
{!epub && !html &&
{/* Header Margin */}
Header {Math.round(localMargins.header * 100)}%
{/* Footer Margin */}
Footer {Math.round(localMargins.footer * 100)}%
{/* Left Margin */}
Left {Math.round(localMargins.left * 100)}%
{/* Right Margin */}
Right {Math.round(localMargins.right * 100)}%

Adjust margins to exclude content from edges of the page during text extraction (experimental)

updateConfigKey('viewType', newView.id as ViewType)} >
{selectedView.name} {viewTypes.map((view) => ( `relative cursor-pointer select-none py-2 pl-10 pr-4 ${active ? 'bg-accent/10 text-accent' : 'text-foreground' }` } value={view} > {({ selected }) => ( <> {view.name} {selected ? ( ) : null} )} ))} {selectedView.id === 'scroll' && (

Note: Continuous scroll may perform poorly for larger documents.

)}
} {!html &&

Automatically skip pages with no text content

} {epub && (

Apply the current app theme to the EPUB viewer

)}
); }