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;
|
||||
}
|
||||
|
||||
// Optimistically mark as enabled; kick off compression in background
|
||||
setMetadata(fileItem, { ...metadata, compressImage: true, compressionResult: undefined });
|
||||
setCompressing(true);
|
||||
|
||||
@@ -136,63 +135,108 @@ function CompressionCheckbox({ fileItem, metadata, setMetadata }: CompressionChe
|
||||
? Math.round(((result.originalSize - result.compressedSize) / result.originalSize) * 100)
|
||||
: null;
|
||||
|
||||
const originalSize = formatFileSize(originalFile.size);
|
||||
|
||||
return (
|
||||
<Box
|
||||
direction="Column"
|
||||
gap="100"
|
||||
gap="200"
|
||||
style={{
|
||||
marginTop: '4px',
|
||||
padding: '6px 8px',
|
||||
background: 'var(--bg-surface-low)',
|
||||
borderRadius: '6px',
|
||||
border: '1px solid var(--bg-surface-border)',
|
||||
fontSize: '0.8rem',
|
||||
marginTop: config.space.S100,
|
||||
padding: `${config.space.S200} ${config.space.S300}`,
|
||||
background: color.SurfaceVariant.Container,
|
||||
borderRadius: config.radii.R300,
|
||||
border: `1px solid ${color.SurfaceVariant.ContainerLine}`,
|
||||
}}
|
||||
>
|
||||
{/* Checkbox row */}
|
||||
<Box alignItems="Center" gap="200">
|
||||
<input
|
||||
id={`compress-${originalFile.name}-${originalFile.size}`}
|
||||
type="checkbox"
|
||||
checked={checked}
|
||||
onChange={handleChange}
|
||||
style={{ cursor: 'pointer', accentColor: 'var(--bg-secondary)' }}
|
||||
style={{ cursor: 'pointer', flexShrink: 0 }}
|
||||
/>
|
||||
<label
|
||||
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
|
||||
</label>
|
||||
{compressing && (
|
||||
<Text size="T200" style={{ color: 'var(--text-secondary)', marginLeft: '4px' }}>
|
||||
estimating…
|
||||
<Text size="T200" style={{ opacity: 0.6, marginLeft: 'auto' }}>
|
||||
compressing…
|
||||
</Text>
|
||||
)}
|
||||
</Box>
|
||||
{checked && !compressing && result !== undefined && (
|
||||
<Text
|
||||
size="T200"
|
||||
|
||||
{/* Before / after row — always show original; show compressed when ready */}
|
||||
<Box gap="200" alignItems="Center" wrap="Wrap">
|
||||
<Box
|
||||
gap="100"
|
||||
alignItems="Center"
|
||||
style={{
|
||||
color: result
|
||||
? savingPct !== null && savingPct > 0
|
||||
? 'var(--tc-success-normal, #2e7d32)'
|
||||
: 'var(--text-secondary)'
|
||||
: 'var(--tc-danger-normal)',
|
||||
paddingLeft: '20px',
|
||||
padding: `2px ${config.space.S200}`,
|
||||
borderRadius: config.radii.R300,
|
||||
background: color.Surface.Container,
|
||||
border: `1px solid ${color.Surface.ContainerLine}`,
|
||||
}}
|
||||
>
|
||||
{result
|
||||
? savingPct !== null && savingPct > 0
|
||||
? `→ ~${formatFileSize(result.compressedSize)} (${savingPct}% smaller)`
|
||||
: `→ ${formatFileSize(result.compressedSize)} (no significant saving)`
|
||||
: 'Compression not available for this file'}
|
||||
</Text>
|
||||
)}
|
||||
{checked && !compressing && result === undefined && (
|
||||
<Text size="T200" style={{ color: 'var(--text-secondary)', paddingLeft: '20px' }}>
|
||||
Original: {formatFileSize(originalFile.size)}
|
||||
</Text>
|
||||
)}
|
||||
<Text size="T200" style={{ opacity: 0.6 }}>
|
||||
Original
|
||||
</Text>
|
||||
<Text size="T200" style={{ fontWeight: 600 }}>
|
||||
{originalSize}
|
||||
</Text>
|
||||
</Box>
|
||||
|
||||
{checked && !compressing && result !== undefined && (
|
||||
<>
|
||||
<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>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user