From b6852da2a23bc6628e32b561d6f4ee66a6f57e23 Mon Sep 17 00:00:00 2001 From: Richard R Date: Thu, 19 Mar 2026 11:16:24 -0600 Subject: [PATCH] feat(ui): enhance AudiobookExportModal and ConfirmDialog with improved layout and styling; update VoicesControlBase for better dropdown handling --- src/components/AudiobookExportModal.tsx | 326 +++++++++++--------- src/components/ConfirmDialog.tsx | 4 +- src/components/ProgressCard.tsx | 2 +- src/components/player/VoicesControlBase.tsx | 86 +++++- 4 files changed, 250 insertions(+), 168 deletions(-) diff --git a/src/components/AudiobookExportModal.tsx b/src/components/AudiobookExportModal.tsx index 14be830..87f5ae1 100644 --- a/src/components/AudiobookExportModal.tsx +++ b/src/components/AudiobookExportModal.tsx @@ -491,161 +491,183 @@ export function AudiobookExportModal({

Export Audiobook

{!isGenerating && ( -
-
-
-
-

Generation settings

-

- These settings are saved per audiobook for consistent resumes across devices. -

-
- {settingsLocked && ( - - Locked - - )} -
+
+ {/* Header */} +
+

Generation settings

+ {settingsLocked && ( + + + Locked + + )} +
- {isLegacyAudiobookMissingSettings && ( -
-
Saved generation settings not found
-
- This audiobook was likely created before v1 metadata was introduced, so OpenReader can’t know - which voice/speeds/format were used. Consider resetting this audiobook to regenerate it with - v1 metadata (so settings are saved for resumes across devices). -
-
- )} - - {settingsLocked && savedSettings ? ( -
-
- Voice: {savedSettings.voice} -
-
- Native speed: {formatSpeed(savedSettings.nativeSpeed)}x -
-
- Post speed: {formatSpeed(savedSettings.postSpeed)}x -
-
- Format: {savedSettings.format.toUpperCase()} -
-

- Reset the audiobook to change generation settings. -

-
- ) : ( -
-
-
Voice
- -
- -
-
Output format
- {chapters.length === 0 ? ( - setFormat(newFormat)} - disabled={chapters.length > 0 || settingsLocked} - > -
- - {format.toUpperCase()} - - - - - - - - `relative cursor-pointer select-none py-2 pl-3 pr-4 ${active ? 'bg-offbase text-accent' : 'text-foreground' - }` - } - > - {({ selected }) => ( - - M4B - - )} - - - `relative cursor-pointer select-none py-2 pl-3 pr-4 ${active ? 'bg-offbase text-accent' : 'text-foreground' - }` - } - > - {({ selected }) => ( - - MP3 - - )} - - - -
-
- ) : ( -
{format.toUpperCase()}
- )} -
- -
-
-
Native model speed
-
• {formatSpeed(nativeSpeed)}x
-
- setNativeSpeed(parseFloat(e.target.value))} - className="w-full max-w-xs bg-offbase rounded-lg appearance-none cursor-pointer accent-accent [&::-webkit-slider-runnable-track]:bg-offbase [&::-webkit-slider-runnable-track]:rounded-lg [&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:h-4 [&::-webkit-slider-thumb]:w-4 [&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:bg-accent [&::-moz-range-track]:bg-offbase [&::-moz-range-track]:rounded-lg [&::-moz-range-thumb]:appearance-none [&::-moz-range-thumb]:h-4 [&::-moz-range-thumb]:w-4 [&::-moz-range-thumb]:rounded-full [&::-moz-range-thumb]:bg-accent" - /> -
- -
-
-
Post-generation speed
-
• {formatSpeed(postSpeed)}x
-
- setPostSpeed(parseFloat(e.target.value))} - className="w-full max-w-xs bg-offbase rounded-lg appearance-none cursor-pointer accent-accent [&::-webkit-slider-runnable-track]:bg-offbase [&::-webkit-slider-runnable-track]:rounded-lg [&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:h-4 [&::-webkit-slider-thumb]:w-4 [&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:bg-accent [&::-moz-range-track]:bg-offbase [&::-moz-range-track]:rounded-lg [&::-moz-range-thumb]:appearance-none [&::-moz-range-thumb]:h-4 [&::-moz-range-thumb]:w-4 [&::-moz-range-thumb]:rounded-full [&::-moz-range-thumb]:bg-accent" - /> +
+ {isLegacyAudiobookMissingSettings && ( +
+
Saved generation settings not found
+
+ This audiobook was likely created before v1 metadata was introduced, so OpenReader can't know + which voice/speeds/format were used. Consider resetting this audiobook to regenerate it with + v1 metadata (so settings are saved for resumes across devices).
)} -
+ {settingsLocked && savedSettings ? ( +
+
+
+
Voice
+
{savedSettings.voice}
+
+
+
Format
+
{savedSettings.format.toUpperCase()}
+
+
+
+
+
Native speed
+
{formatSpeed(savedSettings.nativeSpeed)}x
+
+
+
Post speed
+
{formatSpeed(savedSettings.postSpeed)}x
+
+
+

+ Reset the audiobook to change generation settings. +

+
+ ) : ( +
+ {/* Voice & Format row */} +
+
+ + +
+ +
+ + {chapters.length === 0 ? ( + setFormat(newFormat)} + disabled={chapters.length > 0 || settingsLocked} + > +
+ + {format.toUpperCase()} + + + + + + + + `relative cursor-pointer select-none py-2 pl-3 pr-4 ${active ? 'bg-offbase text-accent' : 'text-foreground'}` + } + > + {({ selected }) => ( + + M4B + + )} + + + `relative cursor-pointer select-none py-2 pl-3 pr-4 ${active ? 'bg-offbase text-accent' : 'text-foreground'}` + } + > + {({ selected }) => ( + + MP3 + + )} + + + +
+
+ ) : ( +
{format.toUpperCase()}
+ )} +
+
+ + {/* Speed controls */} +
+
+
+ + {formatSpeed(nativeSpeed)}x +
+ setNativeSpeed(parseFloat(e.target.value))} + className="w-full h-1.5 bg-offbase rounded-full appearance-none cursor-pointer [&::-webkit-slider-runnable-track]:bg-offbase [&::-webkit-slider-runnable-track]:rounded-full [&::-webkit-slider-runnable-track]:h-1.5 [&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:h-4 [&::-webkit-slider-thumb]:w-4 [&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:bg-accent [&::-webkit-slider-thumb]:-mt-[5px] [&::-webkit-slider-thumb]:shadow-sm [&::-moz-range-track]:bg-offbase [&::-moz-range-track]:rounded-full [&::-moz-range-track]:h-1.5 [&::-moz-range-thumb]:appearance-none [&::-moz-range-thumb]:h-4 [&::-moz-range-thumb]:w-4 [&::-moz-range-thumb]:rounded-full [&::-moz-range-thumb]:bg-accent [&::-moz-range-thumb]:border-0" + /> +
+ 0.5x + 3x +
+
+ +
+ +
+
+ + {formatSpeed(postSpeed)}x +
+ setPostSpeed(parseFloat(e.target.value))} + className="w-full h-1.5 bg-offbase rounded-full appearance-none cursor-pointer [&::-webkit-slider-runnable-track]:bg-offbase [&::-webkit-slider-runnable-track]:rounded-full [&::-webkit-slider-runnable-track]:h-1.5 [&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:h-4 [&::-webkit-slider-thumb]:w-4 [&::-webkit-slider-thumb]:rounded-full [&::-webkit-slider-thumb]:bg-accent [&::-webkit-slider-thumb]:-mt-[5px] [&::-webkit-slider-thumb]:shadow-sm [&::-moz-range-track]:bg-offbase [&::-moz-range-track]:rounded-full [&::-moz-range-track]:h-1.5 [&::-moz-range-thumb]:appearance-none [&::-moz-range-thumb]:h-4 [&::-moz-range-thumb]:w-4 [&::-moz-range-thumb]:rounded-full [&::-moz-range-thumb]:bg-accent [&::-moz-range-thumb]:border-0" + /> +
+ 0.5x + 3x +
+
+
+
+ )} + + {/* Action buttons */} +
{chapters.length === 0 && (