Skip to content

Commit ff150ee

Browse files
committed
refactor(audiobook): standardize chapter regeneration APIs and UX
- Removed `onProgress` callback from `regenerateChapter` and related functions across `TTS`, `EPUB`, and `PDF` contexts to simplify the chapter regeneration API. - Updated `AudiobookExportModal` to align with the refined regeneration API, including removing granular chapter progress display and adding a hint about TTS caching behavior. - Introduced `TTSAudiobookChapter` interface and renamed `ContinuationMergeResult` to `TTSSmartMergeResult` and `PageTurnEstimate` to `TTSPageTurnEstimate` for better type consistency and clarity. - Applied minor styling adjustments to buttons and listbox components in modals for visual consistency. - Added `'use client'` directive to several client-side components for Next.js 13+ compatibility. - Updated Dockerfile build command from `pnpm run build` to `pnpm build`. - Added Playwright tests to verify backend chapter state after regeneration.
1 parent 04def62 commit ff150ee

File tree

16 files changed

+381
-344
lines changed

16 files changed

+381
-344
lines changed

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ COPY . .
2121

2222
# Build the Next.js application
2323
RUN pnpm exec next telemetry disable
24-
RUN pnpm run build
24+
RUN pnpm build
2525

2626
# Expose the port the app runs on
2727
EXPOSE 3003

src/app/epub/[id]/page.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,10 +94,9 @@ export default function EPUBPage() {
9494
chapterIndex: number,
9595
bookId: string,
9696
format: 'mp3' | 'm4b',
97-
onProgress: (progress: number) => void,
9897
signal: AbortSignal
9998
) => {
100-
return regenerateEPUBChapter(chapterIndex, bookId, format, onProgress, signal);
99+
return regenerateEPUBChapter(chapterIndex, bookId, format, signal);
101100
}, [regenerateEPUBChapter]);
102101

103102
if (error) {

src/app/globals.css

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ html.light {
1010
--base: #f7fafc;
1111
--offbase: #e2e8f0;
1212
--accent: #ef4444;
13-
--secondary-accent: #3b82f6;
13+
--secondary-accent: #ed6868;
1414
--muted: #718096;
1515
--prism-gradient: linear-gradient(90deg,
1616
#fecaca,
@@ -25,7 +25,7 @@ html.dark {
2525
--base: #171717;
2626
--offbase: #343434;
2727
--accent: #f87171;
28-
--secondary-accent: #60a5fa;
28+
--secondary-accent: #eb6262;
2929
--muted: #a3a3a3;
3030
--prism-gradient: linear-gradient(90deg,
3131
#fca5a5,

src/app/pdf/[id]/page.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,10 +88,9 @@ export default function PDFViewerPage() {
8888
chapterIndex: number,
8989
bookId: string,
9090
format: 'mp3' | 'm4b',
91-
onProgress: (progress: number) => void,
9291
signal: AbortSignal
9392
) => {
94-
return regeneratePDFChapter(chapterIndex, bookId, format, onProgress, signal);
93+
return regeneratePDFChapter(chapterIndex, bookId, format, signal);
9594
}, [regeneratePDFChapter]);
9695

9796
if (error) {

src/components/AudiobookExportModal.tsx

Lines changed: 297 additions & 274 deletions
Large diffs are not rendered by default.

src/components/ConfirmDialog.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,8 @@ export function ConfirmDialog({
7575
<div className="mt-6 flex justify-end space-x-3">
7676
<button
7777
type="button"
78-
className="inline-flex justify-center rounded-lg bg-background px-4 py-2 text-sm
79-
font-medium text-foreground hover:bg-background/90 focus:outline-none
78+
className="inline-flex justify-center rounded-lg bg-background px-3 py-1.5 text-sm
79+
font-medium text-foreground hover:bg-offbase focus:outline-none
8080
focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2
8181
transform transition-transform duration-200 ease-in-out hover:scale-[1.04] hover:text-accent"
8282
onClick={onClose}
@@ -85,12 +85,12 @@ export function ConfirmDialog({
8585
</button>
8686
<button
8787
type="button"
88-
className={`inline-flex justify-center rounded-lg px-4 py-2 text-sm
88+
className={`inline-flex justify-center rounded-lg px-3 py-1.5 text-sm
8989
font-medium focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2
9090
transform transition-transform duration-200 ease-in-out hover:scale-[1.04]
9191
${isDangerous
92-
? 'bg-accent text-background hover:bg-accent/90 focus-visible:ring-accent'
93-
: 'bg-accent text-background hover:bg-accent/90 focus-visible:ring-accent'
92+
? 'bg-accent text-background hover:bg-secondary-accent focus-visible:ring-accent'
93+
: 'bg-accent text-background hover:bg-secondary-accent focus-visible:ring-accent'
9494
}`}
9595
onClick={onConfirm}
9696
>

src/components/DocumentSettings.tsx

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import { useParams } from 'next/navigation';
1111

1212
const isDev = process.env.NEXT_PUBLIC_NODE_ENV !== 'production' || process.env.NODE_ENV == null;
1313

14-
const viewTypes = [
14+
const viewTypeTextMapping = [
1515
{ id: 'single', name: 'Single Page' },
1616
{ id: 'dual', name: 'Two Pages' },
1717
{ id: 'scroll', name: 'Continuous Scroll' },
@@ -45,7 +45,7 @@ export function DocumentSettings({ isOpen, setIsOpen, epub, html }: {
4545
right: rightMargin
4646
});
4747
const [isAudiobookModalOpen, setIsAudiobookModalOpen] = useState(false);
48-
const selectedView = viewTypes.find(v => v.id === viewType) || viewTypes[0];
48+
const selectedView = viewTypeTextMapping.find(v => v.id === viewType) || viewTypeTextMapping[0];
4949

5050
// Sync local margins with global state
5151
useEffect(() => {
@@ -91,13 +91,12 @@ export function DocumentSettings({ isOpen, setIsOpen, epub, html }: {
9191
chapterIndex: number,
9292
bookId: string,
9393
format: 'mp3' | 'm4b',
94-
onProgress: (progress: number) => void,
9594
signal: AbortSignal
9695
) => {
9796
if (epub) {
98-
return regenerateEPUBChapter(chapterIndex, bookId, format, onProgress, signal);
97+
return regenerateEPUBChapter(chapterIndex, bookId, format, signal);
9998
} else {
100-
return regeneratePDFChapter(chapterIndex, bookId, format, onProgress, signal);
99+
return regeneratePDFChapter(chapterIndex, bookId, format, signal);
101100
}
102101
}, [epub, regenerateEPUBChapter, regeneratePDFChapter]);
103102

@@ -141,10 +140,10 @@ export function DocumentSettings({ isOpen, setIsOpen, epub, html }: {
141140
{isDev && !html && <div className="space-y-2 mb-4">
142141
<Button
143142
type="button"
144-
className="w-full inline-flex justify-center rounded-lg bg-accent px-4 py-2 text-sm
145-
font-medium text-background hover:opacity-95 focus:outline-none
143+
className="w-full inline-flex justify-center rounded-lg bg-accent px-3 py-1.5 text-sm
144+
font-medium text-background hover:bg-secondary-accent focus:outline-none
146145
focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2
147-
transform transition-transform duration-200 ease-in-out hover:scale-[1.04]"
146+
transform transition-transform duration-200 ease-in-out hover:scale-[1.04] hover:text-background"
148147
onClick={() => setIsAudiobookModalOpen(true)}
149148
>
150149
Export Audiobook
@@ -248,7 +247,7 @@ export function DocumentSettings({ isOpen, setIsOpen, epub, html }: {
248247
>
249248
<div className="relative z-10 space-y-2">
250249
<label className="block text-sm font-medium text-foreground">Mode</label>
251-
<ListboxButton className="relative w-full cursor-pointer rounded-lg bg-background py-2 pl-3 pr-10 text-left text-foreground shadow-sm focus:outline-none focus:ring-2 focus:ring-accent transform transition-transform duration-200 ease-in-out hover:scale-[1.01] hover:text-accent">
250+
<ListboxButton className="relative w-full cursor-pointer rounded-lg bg-background py-1.5 pl-3 pr-10 text-left text-foreground shadow-sm focus:outline-none focus:ring-2 focus:ring-accent transform transition-transform duration-200 ease-in-out hover:scale-[1.009] hover:text-accent hover:bg-offbase">
252251
<span className="block truncate">{selectedView.name}</span>
253252
<span className="pointer-events-none absolute inset-y-0 right-0 flex items-center pr-2">
254253
<ChevronUpDownIcon className="h-5 w-5 text-muted" />
@@ -261,11 +260,11 @@ export function DocumentSettings({ isOpen, setIsOpen, epub, html }: {
261260
leaveTo="opacity-0"
262261
>
263262
<ListboxOptions className="absolute mt-1 max-h-60 w-full overflow-auto rounded-md bg-background py-1 shadow-lg ring-1 ring-black/5 focus:outline-none">
264-
{viewTypes.map((view) => (
263+
{viewTypeTextMapping.map((view) => (
265264
<ListboxOption
266265
key={view.id}
267266
className={({ active }) =>
268-
`relative cursor-pointer select-none py-2 pl-10 pr-4 ${active ? 'bg-accent/10 text-accent' : 'text-foreground'
267+
`relative cursor-pointer select-none py-1.5 pl-10 pr-4 ${active ? 'bg-offbase text-accent' : 'text-foreground'
269268
}`
270269
}
271270
value={view}
@@ -365,8 +364,8 @@ export function DocumentSettings({ isOpen, setIsOpen, epub, html }: {
365364
<div className="mt-3 flex justify-end">
366365
<Button
367366
type="button"
368-
className="inline-flex justify-center rounded-lg bg-background px-4 py-2 text-sm
369-
font-medium text-foreground hover:bg-background/90 focus:outline-none
367+
className="inline-flex justify-center rounded-lg bg-background px-3 py-1.5 text-sm
368+
font-medium text-foreground hover:bg-offbase focus:outline-none
370369
focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2
371370
transform transition-transform duration-200 ease-in-out hover:scale-[1.04] hover:text-accent z-1"
372371
onClick={() => setIsOpen(false)}

src/components/Header.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
"use client";
2-
31
import { ReactNode } from "react";
42

53
export function Header({

0 commit comments

Comments
 (0)