forked from external-repos/squoosh
Improving image open time (#185)
* Moving intro into its own component * Tidying JSX, and allowing image to render before first compression. Fixes #164.
This commit is contained in:
@@ -38,6 +38,7 @@ import {
|
|||||||
|
|
||||||
import { decodeImage } from '../../codecs/decoders';
|
import { decodeImage } from '../../codecs/decoders';
|
||||||
import { cleanMerge, cleanSet } from '../../lib/clean-modify';
|
import { cleanMerge, cleanSet } from '../../lib/clean-modify';
|
||||||
|
import Intro from '../intro';
|
||||||
|
|
||||||
type Orientation = 'horizontal' | 'vertical';
|
type Orientation = 'horizontal' | 'vertical';
|
||||||
|
|
||||||
@@ -209,14 +210,6 @@ export default class App extends Component<Props, State> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@bind
|
|
||||||
async onFileChange(event: Event): Promise<void> {
|
|
||||||
const fileInput = event.target as HTMLInputElement;
|
|
||||||
const file = fileInput.files && fileInput.files[0];
|
|
||||||
if (!file) return;
|
|
||||||
await this.updateFile(file);
|
|
||||||
}
|
|
||||||
|
|
||||||
@bind
|
@bind
|
||||||
async onFileDrop(event: FileDropEvent) {
|
async onFileDrop(event: FileDropEvent) {
|
||||||
const { file } = event;
|
const { file } = event;
|
||||||
@@ -342,38 +335,38 @@ export default class App extends Component<Props, State> {
|
|||||||
return (
|
return (
|
||||||
<file-drop accept="image/*" onfiledrop={this.onFileDrop}>
|
<file-drop accept="image/*" onfiledrop={this.onFileDrop}>
|
||||||
<div id="app" class={`${style.app} ${style[orientation]}`}>
|
<div id="app" class={`${style.app} ${style[orientation]}`}>
|
||||||
{(leftImageData && rightImageData && source) ? (
|
{source
|
||||||
<Output
|
?
|
||||||
orientation={orientation}
|
<div class={`${style.optionPair} ${style[orientation]}`}>
|
||||||
imgWidth={source.data.width}
|
<Output
|
||||||
imgHeight={source.data.height}
|
orientation={orientation}
|
||||||
leftImg={leftImageData}
|
imgWidth={source.data.width}
|
||||||
rightImg={rightImageData}
|
imgHeight={source.data.height}
|
||||||
leftImgContain={leftImage.preprocessorState.resize.fitMethod === 'cover'}
|
leftImg={leftImageData || source.data}
|
||||||
rightImgContain={rightImage.preprocessorState.resize.fitMethod === 'cover'}
|
rightImg={rightImageData || source.data}
|
||||||
/>
|
leftImgContain={leftImage.preprocessorState.resize.fitMethod === 'cover'}
|
||||||
) : (
|
rightImgContain={rightImage.preprocessorState.resize.fitMethod === 'cover'}
|
||||||
<div class={style.welcome}>
|
/>
|
||||||
<h1>Drop, paste or select an image</h1>
|
{images.map((image, index) => (
|
||||||
<input type="file" onChange={this.onFileChange} />
|
<Options
|
||||||
</div>
|
orientation={orientation}
|
||||||
)}
|
sourceAspect={source.data.width / source.data.height}
|
||||||
{(leftImageData && rightImageData && source) && images.map((image, index) => (
|
imageIndex={index}
|
||||||
<Options
|
imageFile={image.file}
|
||||||
orientation={orientation}
|
sourceImageFile={source && source.file}
|
||||||
sourceAspect={source.data.width / source.data.height}
|
downloadUrl={image.downloadUrl}
|
||||||
imageIndex={index}
|
preprocessorState={image.preprocessorState}
|
||||||
imageFile={image.file}
|
encoderState={image.encoderState}
|
||||||
sourceImageFile={source && source.file}
|
onEncoderTypeChange={this.onEncoderTypeChange.bind(this, index)}
|
||||||
downloadUrl={image.downloadUrl}
|
onEncoderOptionsChange={this.onEncoderOptionsChange.bind(this, index)}
|
||||||
preprocessorState={image.preprocessorState}
|
onPreprocessorOptionsChange={this.onPreprocessorOptionsChange.bind(this, index)}
|
||||||
encoderState={image.encoderState}
|
onCopyToOtherClick={this.onCopyToOtherClick.bind(this, index)}
|
||||||
onEncoderTypeChange={this.onEncoderTypeChange.bind(this, index)}
|
/>
|
||||||
onEncoderOptionsChange={this.onEncoderOptionsChange.bind(this, index)}
|
))}
|
||||||
onPreprocessorOptionsChange={this.onPreprocessorOptionsChange.bind(this, index)}
|
</div>
|
||||||
onCopyToOtherClick={this.onCopyToOtherClick.bind(this, index)}
|
:
|
||||||
/>
|
<Intro onFile={this.updateFile} />
|
||||||
))}
|
}
|
||||||
{anyLoading && <span style={{ position: 'fixed', top: 0, left: 0 }}>Loading...</span>}
|
{anyLoading && <span style={{ position: 'fixed', top: 0, left: 0 }}>Loading...</span>}
|
||||||
<snack-bar ref={linkRef(this, 'snackbar')} />
|
<snack-bar ref={linkRef(this, 'snackbar')} />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -11,39 +11,6 @@ Note: These styles are temporary. They will be replaced before going live.
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
contain: strict;
|
contain: strict;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-end;
|
|
||||||
|
|
||||||
&.horizontal {
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: flex-end;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.vertical {
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.welcome {
|
|
||||||
margin: auto;
|
|
||||||
text-align: center;
|
|
||||||
|
|
||||||
h1 {
|
|
||||||
font-weight: inherit;
|
|
||||||
font-size: 150%;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
input {
|
|
||||||
display: inline-block;
|
|
||||||
width: 16em;
|
|
||||||
padding: 10px;
|
|
||||||
margin: 0 auto;
|
|
||||||
-webkit-appearance: none;
|
|
||||||
border: 1px solid var(--button-fg);
|
|
||||||
background: rgba(var(--button-fg-color), 0.1);
|
|
||||||
border-radius: 3px;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
:global {
|
:global {
|
||||||
@@ -87,3 +54,18 @@ Note: These styles are temporary. They will be replaced before going live.
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.option-pair {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
&.horizontal {
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.vertical {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
27
src/components/intro/index.tsx
Normal file
27
src/components/intro/index.tsx
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
import { h, Component } from 'preact';
|
||||||
|
import * as style from './style.scss';
|
||||||
|
import { bind } from '../../lib/util';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
onFile: (file: File) => void;
|
||||||
|
}
|
||||||
|
interface State {}
|
||||||
|
|
||||||
|
export default class Intro extends Component<Props, State> {
|
||||||
|
@bind
|
||||||
|
onFileChange(event: Event): void {
|
||||||
|
const fileInput = event.target as HTMLInputElement;
|
||||||
|
const file = fileInput.files && fileInput.files[0];
|
||||||
|
if (!file) return;
|
||||||
|
this.props.onFile(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
render({ }: Props, { }: State) {
|
||||||
|
return (
|
||||||
|
<div class={style.welcome}>
|
||||||
|
<h1>Drop, paste or select an image</h1>
|
||||||
|
<input type="file" onChange={this.onFileChange} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
22
src/components/intro/style.scss
Normal file
22
src/components/intro/style.scss
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
.welcome {
|
||||||
|
margin: auto;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-weight: inherit;
|
||||||
|
font-size: 150%;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
display: inline-block;
|
||||||
|
width: 16em;
|
||||||
|
padding: 10px;
|
||||||
|
margin: 0 auto;
|
||||||
|
-webkit-appearance: none;
|
||||||
|
border: 1px solid var(--button-fg);
|
||||||
|
background: rgba(var(--button-fg-color), 0.1);
|
||||||
|
border-radius: 3px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user