forked from external-repos/squoosh
* Move gzipped size calculations into a worker and wrap it up in a `<GzipSize />` component that will also handle showing % of original size once that info is plumbed * A couple tweaks for the app welcome (drop files) screen. We don't have mocks for this one, but this is at least a minor improvement. * Prettier "pop" effect and styling for the drop zone/indicator. * Styling for the quantization toggle to make it look like a disclosure triangle/button. * Add controls bar (zoom in/out/to, background toggle). @todo: extract into its own component. * When clicking/tapping the image area, give it focus. * Utilities used by this PR * Add a `two-up-handle` attribute to the handle for easier styling (classname gets mangled so it doesn't make for a good public API) * Add a dummy comment to test netlify deploy * Remove commented-out code. * Fix styling of vertical split (which as it turns out is slightly different in the mocks anyway) * Use a composited overlay for the dark background instead of animating background-color * Move grayscale styling into `<two-up>` by default, then set colors via custom properties * Remove commented-out svg fill * Remove dummy comment * Change `<GzipSize>` to be `<FileSize>`, add `compress` option that lets us show gzipped sizes later if we need. Defaults to `false`, and the gzip worker is only lazily instantiated the first time a compressed size calculation is requested. * Dependency updates * Remove color animations from dnd overlay * Don't use a cyclical import for EncodedImage, instead just specify the types of the properties we Options actually uses. * Pass source image through to FileSize component so it can compute delta * Stylize size display with colors based on delta amount/direction * Remove box-shadow animation. * Simplify font stack * Remove commented out code * Remove gzip compression from size component * Remove memoization bits * Use specific flattend props instead of passing large context objects around. * Remove unused packages. * Remove unreachable String case in FileSize, and omit redundant File type * Simplify calculateSize() * Fix types for FileSize! * Remove FileSize title * Make delta variable consistent. * Skip passing compareTo value for original image * Remove manual focus * Fix whitespace * remove unused keyframes * remove pointless flex-wrap property * Remove unused resetZoom() method * Remove pointless flex properties * Use `on` prefix for event handling * Remove pointless justify-self property * Use an inline SVG for TwoUp's handle icon so it can be colored from outside the component.. * Move orientation state up from `<Output>` into `<App>` and share it with `<Options>`. * Make the options panels responsive :) * Show a plus sign for size increases `(+8%)` * Use inline SVG for the zoom +/- icons, collect SVG icons into one file now that I've verified they get tree-shaken properly. * Fix top/bottom options panels being reversed * remove commented out code * lockfile * Revert quanitzation toggle styles so it's just a checkbox. * Remove minimum delta for compare size * Rename data prop to file. * scale int -> float * remove tabIndex * Remove old icon files * Add width to options panels * Add vertical scrolling when options are taller than 80% of the screen height.
88 lines
2.2 KiB
TypeScript
88 lines
2.2 KiB
TypeScript
import { h, Component } from 'preact';
|
|
import * as prettyBytes from 'pretty-bytes';
|
|
|
|
type FileContents = ArrayBuffer | Blob;
|
|
|
|
interface Props extends Pick<JSX.HTMLAttributes, Exclude<keyof JSX.HTMLAttributes, 'data'>> {
|
|
file?: FileContents;
|
|
compareTo?: FileContents;
|
|
increaseClass?: string;
|
|
decreaseClass?: string;
|
|
}
|
|
|
|
interface State {
|
|
size?: number;
|
|
sizeFormatted?: string;
|
|
compareSize?: number;
|
|
compareSizeFormatted?: string;
|
|
}
|
|
|
|
function calculateSize(data: FileContents): number {
|
|
return data instanceof ArrayBuffer ? data.byteLength : data.size;
|
|
}
|
|
|
|
export default class FileSize extends Component<Props, State> {
|
|
constructor(props: Props) {
|
|
super(props);
|
|
if (props.file) {
|
|
this.computeSize('size', props.file);
|
|
}
|
|
if (props.compareTo) {
|
|
this.computeSize('compareSize', props.compareTo);
|
|
}
|
|
}
|
|
|
|
componentWillReceiveProps({ file, compareTo }: Props) {
|
|
if (file !== this.props.file) {
|
|
this.computeSize('size', file);
|
|
}
|
|
if (compareTo !== this.props.compareTo) {
|
|
this.computeSize('compareSize', compareTo);
|
|
}
|
|
}
|
|
|
|
componentDidMount() {
|
|
this.applyStyles();
|
|
}
|
|
|
|
componentDidUpdate() {
|
|
this.applyStyles();
|
|
}
|
|
|
|
applyStyles() {
|
|
const { size, compareSize = 0 } = this.state;
|
|
if (size != null && this.base) {
|
|
const delta = size && compareSize ? (size - compareSize) / compareSize : 0;
|
|
this.base.style.setProperty('--size', '' + size);
|
|
this.base.style.setProperty('--size-delta', '' + Math.round(Math.abs(delta * 100)));
|
|
}
|
|
}
|
|
|
|
computeSize(prop: keyof State, data?: FileContents) {
|
|
const size = data ? calculateSize(data) : 0;
|
|
const pretty = prettyBytes(size);
|
|
this.setState({
|
|
[prop]: size,
|
|
[prop + 'Formatted']: pretty,
|
|
});
|
|
}
|
|
|
|
render(
|
|
{ file, compareTo, increaseClass, decreaseClass, ...props }: Props,
|
|
{ size, sizeFormatted = '', compareSize }: State,
|
|
) {
|
|
const delta = size && compareSize ? (size - compareSize) / compareSize : 0;
|
|
return (
|
|
<span {...props}>
|
|
{sizeFormatted}
|
|
{compareTo && (
|
|
<span class={delta > 0 ? increaseClass : decreaseClass}>
|
|
{delta > 0 && '+'}
|
|
{Math.round(delta * 100)}%
|
|
</span>
|
|
)}
|
|
</span>
|
|
);
|
|
}
|
|
}
|