import React, { useEffect, useRef, useState } from 'react';
import { __, _n, sprintf } from '@wordpress/i18n';
import { ArrowRight, Check, ChevronsLeftRight, FlaskConical } from 'lucide-react';
import type { CompressionCheckResult, CompressionCheckSample } from '../../api';
import { formatBytes, numberFormat, percentFormat } from '../../lib/i18n';
/** The extension of a file name, upper-cased, for the size line under the picture. */
function formatOf( name: string ): string {
const dot = name.lastIndexOf( '.' );
return dot > -1 ? name.slice( dot + 1 ).toUpperCase() : '';
}
/**
* The user's own photos, before and after compression, side by side under one slider.
*
* Artefacts hide at fit-to-screen, so "View at 100%" shows a 1:1 crop: people who check the pixels
* trust the number more.
*/
export default function BeforeAfterModal( { samples, result, applied, pro = false, onClose }: {
samples: CompressionCheckSample[];
result: CompressionCheckResult;
/** How many free settings were just switched on. */
applied: number;
/** Pro is active: no upsell link. */
pro?: boolean;
onClose: () => void;
} ) {
const [ index, setIndex ] = useState( 0 );
const [ position, setPosition ] = useState( 50 );
const [ actual, setActual ] = useState( false );
const stage = useRef< HTMLDivElement >( null );
const dialog = useRef< HTMLDivElement >( null );
const dragging = useRef( false );
const sample = samples[ index ] ?? samples[ 0 ];
useEffect( () => {
dialog.current?.focus();
const onKey = ( event: KeyboardEvent ) => {
if ( event.key === 'Escape' ) {
onClose();
}
};
document.addEventListener( 'keydown', onKey );
return () => document.removeEventListener( 'keydown', onKey );
}, [] );
const moveTo = ( clientX: number ) => {
const box = stage.current?.getBoundingClientRect();
if ( box && box.width > 0 ) {
setPosition( Math.max( 0, Math.min( 100, ( ( clientX - box.left ) / box.width ) * 100 ) ) );
}
};
if ( ! sample ) {
return null;
}
const fit = actual ? 'none' : 'contain';
return (
{ applied > 0
? <>{ __( 'Free fixes applied.', 'image-sizes' ) } { sprintf(
/* translators: %s: number of settings switched on. */
_n( '%s setting is on.', '%s settings are on.', applied, 'image-sizes' ),
numberFormat( applied ),
) }>
: { __( 'Your free settings were already on.', 'image-sizes' ) } }
{ result.saved_bytes >= 1048576
? sprintf(
/* translators: %s: estimated size Pro would save, e.g. "2.1 GB". */
__( 'Here’s the ~%s, on your own photos', 'image-sizes' ),
formatBytes( result.saved_bytes, true ),
)
: __( 'Here’s the difference, on your own photos', 'image-sizes' ) }
{ sprintf(
/* translators: %s: number of photos compressed. */
__( 'We compressed %s of your photos on copies. Nothing on your site changed. Drag the handle, or zoom to 100%% and look closely.', 'image-sizes' ),
numberFormat( samples.length ),
) }