fix: compression UI — proper before/after display with folds tokens
Always shows Original size pill even before checkbox is checked. After checking: shows 'compressing...' then reveals Compressed pill with exact size and percentage saved. Green tint on compressed pill when >5% saving; neutral when minimal gain. Replaced all var(--bg-*) / var(--tc-*) CSS vars with folds color.Surface.* and color.SurfaceVariant.* tokens so the UI renders correctly in all themes. Blob cleanup is automatic — the compressed Blob is referenced only during upload and GC'd with the upload atom. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -117,7 +117,6 @@ function CompressionCheckbox({ fileItem, metadata, setMetadata }: CompressionChe
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Optimistically mark as enabled; kick off compression in background
|
|
||||||
setMetadata(fileItem, { ...metadata, compressImage: true, compressionResult: undefined });
|
setMetadata(fileItem, { ...metadata, compressImage: true, compressionResult: undefined });
|
||||||
setCompressing(true);
|
setCompressing(true);
|
||||||
|
|
||||||
@@ -136,63 +135,108 @@ function CompressionCheckbox({ fileItem, metadata, setMetadata }: CompressionChe
|
|||||||
? Math.round(((result.originalSize - result.compressedSize) / result.originalSize) * 100)
|
? Math.round(((result.originalSize - result.compressedSize) / result.originalSize) * 100)
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
|
const originalSize = formatFileSize(originalFile.size);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box
|
<Box
|
||||||
direction="Column"
|
direction="Column"
|
||||||
gap="100"
|
gap="200"
|
||||||
style={{
|
style={{
|
||||||
marginTop: '4px',
|
marginTop: config.space.S100,
|
||||||
padding: '6px 8px',
|
padding: `${config.space.S200} ${config.space.S300}`,
|
||||||
background: 'var(--bg-surface-low)',
|
background: color.SurfaceVariant.Container,
|
||||||
borderRadius: '6px',
|
borderRadius: config.radii.R300,
|
||||||
border: '1px solid var(--bg-surface-border)',
|
border: `1px solid ${color.SurfaceVariant.ContainerLine}`,
|
||||||
fontSize: '0.8rem',
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
{/* Checkbox row */}
|
||||||
<Box alignItems="Center" gap="200">
|
<Box alignItems="Center" gap="200">
|
||||||
<input
|
<input
|
||||||
id={`compress-${originalFile.name}-${originalFile.size}`}
|
id={`compress-${originalFile.name}-${originalFile.size}`}
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
checked={checked}
|
checked={checked}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
style={{ cursor: 'pointer', accentColor: 'var(--bg-secondary)' }}
|
style={{ cursor: 'pointer', flexShrink: 0 }}
|
||||||
/>
|
/>
|
||||||
<label
|
<label
|
||||||
htmlFor={`compress-${originalFile.name}-${originalFile.size}`}
|
htmlFor={`compress-${originalFile.name}-${originalFile.size}`}
|
||||||
style={{ cursor: 'pointer', color: 'var(--text-primary)', userSelect: 'none' }}
|
style={{
|
||||||
|
cursor: 'pointer',
|
||||||
|
color: color.SurfaceVariant.OnContainer,
|
||||||
|
userSelect: 'none',
|
||||||
|
fontSize: '0.8rem',
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
Compress before uploading
|
Compress before uploading
|
||||||
</label>
|
</label>
|
||||||
{compressing && (
|
{compressing && (
|
||||||
<Text size="T200" style={{ color: 'var(--text-secondary)', marginLeft: '4px' }}>
|
<Text size="T200" style={{ opacity: 0.6, marginLeft: 'auto' }}>
|
||||||
estimating…
|
compressing…
|
||||||
</Text>
|
</Text>
|
||||||
)}
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
{checked && !compressing && result !== undefined && (
|
|
||||||
<Text
|
{/* Before / after row — always show original; show compressed when ready */}
|
||||||
size="T200"
|
<Box gap="200" alignItems="Center" wrap="Wrap">
|
||||||
|
<Box
|
||||||
|
gap="100"
|
||||||
|
alignItems="Center"
|
||||||
style={{
|
style={{
|
||||||
color: result
|
padding: `2px ${config.space.S200}`,
|
||||||
? savingPct !== null && savingPct > 0
|
borderRadius: config.radii.R300,
|
||||||
? 'var(--tc-success-normal, #2e7d32)'
|
background: color.Surface.Container,
|
||||||
: 'var(--text-secondary)'
|
border: `1px solid ${color.Surface.ContainerLine}`,
|
||||||
: 'var(--tc-danger-normal)',
|
|
||||||
paddingLeft: '20px',
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{result
|
<Text size="T200" style={{ opacity: 0.6 }}>
|
||||||
? savingPct !== null && savingPct > 0
|
Original
|
||||||
? `→ ~${formatFileSize(result.compressedSize)} (${savingPct}% smaller)`
|
</Text>
|
||||||
: `→ ${formatFileSize(result.compressedSize)} (no significant saving)`
|
<Text size="T200" style={{ fontWeight: 600 }}>
|
||||||
: 'Compression not available for this file'}
|
{originalSize}
|
||||||
</Text>
|
</Text>
|
||||||
)}
|
</Box>
|
||||||
{checked && !compressing && result === undefined && (
|
|
||||||
<Text size="T200" style={{ color: 'var(--text-secondary)', paddingLeft: '20px' }}>
|
{checked && !compressing && result !== undefined && (
|
||||||
Original: {formatFileSize(originalFile.size)}
|
<>
|
||||||
</Text>
|
<Text size="T200" style={{ opacity: 0.5 }}>
|
||||||
)}
|
→
|
||||||
|
</Text>
|
||||||
|
<Box
|
||||||
|
gap="100"
|
||||||
|
alignItems="Center"
|
||||||
|
style={{
|
||||||
|
padding: `2px ${config.space.S200}`,
|
||||||
|
borderRadius: config.radii.R300,
|
||||||
|
background:
|
||||||
|
savingPct !== null && savingPct > 5
|
||||||
|
? (color.Success?.Container ?? color.Primary.Container)
|
||||||
|
: color.Surface.Container,
|
||||||
|
border: `1px solid ${
|
||||||
|
savingPct !== null && savingPct > 5
|
||||||
|
? (color.Success?.ContainerLine ?? color.Primary.ContainerLine)
|
||||||
|
: color.Surface.ContainerLine
|
||||||
|
}`,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Text size="T200" style={{ opacity: 0.6 }}>
|
||||||
|
Compressed
|
||||||
|
</Text>
|
||||||
|
{result ? (
|
||||||
|
<Text size="T200" style={{ fontWeight: 600 }}>
|
||||||
|
{formatFileSize(result.compressedSize)}
|
||||||
|
{savingPct !== null && savingPct > 0 && (
|
||||||
|
<span style={{ opacity: 0.7, marginLeft: 4 }}>({savingPct}% smaller)</span>
|
||||||
|
)}
|
||||||
|
</Text>
|
||||||
|
) : (
|
||||||
|
<Text size="T200" style={{ opacity: 0.6 }}>
|
||||||
|
unavailable
|
||||||
|
</Text>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user