feat: add per-format compression controls to the frontend
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
+74
-2
@@ -3,10 +3,25 @@ import { fetchFormats, uploadFiles } from './api.js';
|
||||
import { FileCard } from './FileCard.jsx';
|
||||
import './App.css';
|
||||
|
||||
const DEFAULT_QUALITY = {
|
||||
jpg: 80,
|
||||
jpeg: 80,
|
||||
webp: 80,
|
||||
avif: 50,
|
||||
tiff: 80,
|
||||
png: 6,
|
||||
};
|
||||
|
||||
const QUALITY_FORMATS = ['jpg', 'jpeg', 'webp', 'avif', 'tiff'];
|
||||
|
||||
function extensionOf(fileName) {
|
||||
return fileName.split('.').pop().toLowerCase();
|
||||
}
|
||||
|
||||
function defaultQualityFor(targetFormat) {
|
||||
return DEFAULT_QUALITY[targetFormat] ?? null;
|
||||
}
|
||||
|
||||
export default function App() {
|
||||
const [pendingFiles, setPendingFiles] = useState([]);
|
||||
const [submittedJobs, setSubmittedJobs] = useState([]);
|
||||
@@ -16,14 +31,23 @@ export default function App() {
|
||||
const withTargets = await Promise.all(
|
||||
files.map(async (file) => {
|
||||
const targets = await fetchFormats(extensionOf(file.name));
|
||||
return { file, targets, targetFormat: targets[0] ?? null };
|
||||
const targetFormat = targets[0] ?? null;
|
||||
return { file, targets, targetFormat, quality: defaultQualityFor(targetFormat) };
|
||||
})
|
||||
);
|
||||
setPendingFiles(withTargets);
|
||||
}
|
||||
|
||||
function updateTargetFormat(index, targetFormat) {
|
||||
setPendingFiles((current) => current.map((item, i) => (i === index ? { ...item, targetFormat } : item)));
|
||||
setPendingFiles((current) =>
|
||||
current.map((item, i) =>
|
||||
i === index ? { ...item, targetFormat, quality: defaultQualityFor(targetFormat) } : item
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function updateQuality(index, quality) {
|
||||
setPendingFiles((current) => current.map((item, i) => (i === index ? { ...item, quality } : item)));
|
||||
}
|
||||
|
||||
async function handleConvert() {
|
||||
@@ -46,6 +70,7 @@ export default function App() {
|
||||
<li key={`${item.file.name}-${index}`}>
|
||||
{item.file.name}
|
||||
{item.targets.length > 0 ? (
|
||||
<>
|
||||
<select
|
||||
value={item.targetFormat ?? ''}
|
||||
onChange={(event) => updateTargetFormat(index, event.target.value)}
|
||||
@@ -56,6 +81,53 @@ export default function App() {
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
|
||||
{QUALITY_FORMATS.includes(item.targetFormat) && (
|
||||
<label>
|
||||
Qualité ({item.quality})
|
||||
<input
|
||||
type="range"
|
||||
min="1"
|
||||
max="100"
|
||||
value={item.quality}
|
||||
onChange={(event) => updateQuality(index, Number(event.target.value))}
|
||||
/>
|
||||
</label>
|
||||
)}
|
||||
|
||||
{item.targetFormat === 'png' && (
|
||||
<label>
|
||||
Compression ({item.quality})
|
||||
<input
|
||||
type="range"
|
||||
min="0"
|
||||
max="9"
|
||||
value={item.quality}
|
||||
onChange={(event) => updateQuality(index, Number(event.target.value))}
|
||||
/>
|
||||
</label>
|
||||
)}
|
||||
|
||||
{item.targetFormat === 'pdf' && (
|
||||
<label>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={item.quality !== null}
|
||||
onChange={(event) => updateQuality(index, event.target.checked ? 90 : null)}
|
||||
/>
|
||||
Compresser en JPEG
|
||||
{item.quality !== null && (
|
||||
<input
|
||||
type="range"
|
||||
min="1"
|
||||
max="100"
|
||||
value={item.quality}
|
||||
onChange={(event) => updateQuality(index, Number(event.target.value))}
|
||||
/>
|
||||
)}
|
||||
</label>
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
<span className="error">Format non supporté</span>
|
||||
)}
|
||||
|
||||
@@ -7,11 +7,14 @@ export async function fetchFormats(source) {
|
||||
export async function uploadFiles(items) {
|
||||
const formData = new FormData();
|
||||
const targetFormats = [];
|
||||
const qualities = [];
|
||||
for (const item of items) {
|
||||
formData.append('files', item.file);
|
||||
targetFormats.push(item.targetFormat);
|
||||
qualities.push(item.quality ?? null);
|
||||
}
|
||||
formData.append('targetFormats', JSON.stringify(targetFormats));
|
||||
formData.append('qualities', JSON.stringify(qualities));
|
||||
|
||||
const response = await fetch('/api/jobs', { method: 'POST', body: formData });
|
||||
const data = await response.json();
|
||||
|
||||
Reference in New Issue
Block a user