feat: add comprehensive conversion options and enhanced UI

This major update adds powerful format-specific controls, quality presets,
file metadata display, and enhanced progress feedback to significantly
improve the user experience.

New Components:
- ConversionOptionsPanel: Format-specific controls with collapsible advanced options
  - Video options: codec selection (H.264, H.265, VP8, VP9), bitrate, resolution, FPS
  - Audio options: codec selection, bitrate, sample rate, channels
  - Image options: quality slider, width/height controls
- Quality Presets: One-click presets (High Quality, Balanced, Small File, Web Optimized)
- FileInfo: Displays file metadata including size, duration, dimensions
- Slider: Reusable slider component for quality/bitrate controls
- Select: Reusable dropdown component for codec/format selection

Enhanced Features:
- ConversionPreview improvements:
  - Real-time elapsed time display
  - Estimated time remaining calculation
  - File size comparison (input vs output with % reduction/increase)
  - Better visual status indicators with icons
  - Enhanced loading states with detailed progress
- FileConverter integration:
  - Passes conversion options to converter services
  - Manages conversion options state
  - Resets options on file reset

UI/UX Improvements:
- Format-specific option panels that adapt to selected output format
- Visual preset buttons with icons and descriptions
- Collapsible advanced options to reduce clutter
- Better progress feedback with time estimates
- File size comparison badges showing compression results
- Smooth animations and transitions (existing animations already in place)
- Responsive design for all new components

Technical Details:
- Options are properly typed and integrated with ConversionOptions interface
- All components support disabled states during conversion
- Preview component calculates speed and estimates remaining time
- Metadata extraction for video/audio/image files using browser APIs
- Proper cleanup of object URLs and timers

User Benefits:
- Power users can fine-tune codec, bitrate, resolution settings
- Beginners can use quality presets with confidence
- Better understanding of conversion progress and file size impact
- Informed decisions with file metadata display
- Professional-grade control over output quality

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-11-17 11:46:10 +01:00
parent 594a0ca314
commit f253285c25
6 changed files with 864 additions and 22 deletions

View File

@@ -7,6 +7,8 @@ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/com
import { FileUpload } from './FileUpload';
import { FormatSelector } from './FormatSelector';
import { ConversionPreview } from './ConversionPreview';
import { ConversionOptionsPanel } from './ConversionOptions';
import { FileInfo } from './FileInfo';
import { useToast } from '@/components/ui/Toast';
import {
SUPPORTED_FORMATS,
@@ -17,7 +19,7 @@ import {
import { convertWithFFmpeg } from '@/lib/converters/ffmpegService';
import { convertWithImageMagick } from '@/lib/converters/imagemagickService';
import { addToHistory } from '@/lib/storage/history';
import type { ConversionJob, ConversionFormat } from '@/types/conversion';
import type { ConversionJob, ConversionFormat, ConversionOptions } from '@/types/conversion';
export function FileConverter() {
const { addToast } = useToast();
@@ -27,6 +29,7 @@ export function FileConverter() {
const [outputFormat, setOutputFormat] = React.useState<ConversionFormat | undefined>();
const [compatibleFormats, setCompatibleFormats] = React.useState<ConversionFormat[]>([]);
const [conversionJob, setConversionJob] = React.useState<ConversionJob | undefined>();
const [conversionOptions, setConversionOptions] = React.useState<ConversionOptions>({});
// Detect input format when file is selected
React.useEffect(() => {
@@ -77,7 +80,7 @@ export function FileConverter() {
inputFile: selectedFile,
inputFormat,
outputFormat,
options: {},
options: conversionOptions,
status: 'loading',
progress: 0,
startTime: Date.now(),
@@ -94,7 +97,7 @@ export function FileConverter() {
switch (outputFormat.converter) {
case 'ffmpeg':
result = await convertWithFFmpeg(selectedFile, outputFormat.extension, {}, (progress) => {
result = await convertWithFFmpeg(selectedFile, outputFormat.extension, conversionOptions, (progress) => {
setConversionJob((prev) => prev && { ...prev, progress });
});
break;
@@ -103,7 +106,7 @@ export function FileConverter() {
result = await convertWithImageMagick(
selectedFile,
outputFormat.extension,
{},
conversionOptions,
(progress) => {
setConversionJob((prev) => prev && { ...prev, progress });
}
@@ -165,6 +168,7 @@ export function FileConverter() {
setOutputFormat(undefined);
setCompatibleFormats([]);
setConversionJob(undefined);
setConversionOptions({});
};
const isConvertDisabled =
@@ -189,6 +193,11 @@ export function FileConverter() {
disabled={conversionJob?.status === 'processing' || conversionJob?.status === 'loading'}
/>
{/* File Info */}
{selectedFile && inputFormat && (
<FileInfo file={selectedFile} format={inputFormat} />
)}
{/* Format selection */}
{inputFormat && compatibleFormats.length > 0 && (
<div className="grid grid-cols-1 md:grid-cols-[1fr_auto_1fr] gap-4 items-start">
@@ -217,6 +226,17 @@ export function FileConverter() {
</div>
)}
{/* Conversion Options */}
{inputFormat && outputFormat && (
<ConversionOptionsPanel
inputFormat={inputFormat}
outputFormat={outputFormat}
options={conversionOptions}
onOptionsChange={setConversionOptions}
disabled={conversionJob?.status === 'processing' || conversionJob?.status === 'loading'}
/>
)}
{/* Convert button */}
{inputFormat && outputFormat && (
<div className="flex gap-3">