mirror of
https://github.com/GoogleChromeLabs/squoosh.git
synced 2025-11-12 16:57:26 +00:00
Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2a1b6dc9da | ||
|
|
129c33fa12 | ||
|
|
3245987113 |
2
_redirects.ejs
Normal file
2
_redirects.ejs
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
/index.html / 301
|
||||||
|
/* /index.html 301
|
||||||
2
package-lock.json
generated
2
package-lock.json
generated
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "squoosh",
|
"name": "squoosh",
|
||||||
"version": "1.2.3",
|
"version": "1.3.0",
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"private": true,
|
"private": true,
|
||||||
"name": "squoosh",
|
"name": "squoosh",
|
||||||
"version": "1.2.3",
|
"version": "1.3.0",
|
||||||
"license": "apache-2.0",
|
"license": "apache-2.0",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "webpack-dev-server --host 0.0.0.0 --hot",
|
"start": "webpack-dev-server --host 0.0.0.0 --hot",
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ import '../../lib/SnackBar';
|
|||||||
import Intro from '../intro';
|
import Intro from '../intro';
|
||||||
import '../custom-els/LoadingSpinner';
|
import '../custom-els/LoadingSpinner';
|
||||||
|
|
||||||
|
const ROUTE_EDITOR = '/editor';
|
||||||
|
|
||||||
const compressPromise = import(
|
const compressPromise = import(
|
||||||
/* webpackChunkName: "main-app" */
|
/* webpackChunkName: "main-app" */
|
||||||
'../compress',
|
'../compress',
|
||||||
@@ -18,15 +20,21 @@ const offlinerPromise = import(
|
|||||||
'../../lib/offliner',
|
'../../lib/offliner',
|
||||||
);
|
);
|
||||||
|
|
||||||
|
function back() {
|
||||||
|
window.history.back();
|
||||||
|
}
|
||||||
|
|
||||||
interface Props {}
|
interface Props {}
|
||||||
|
|
||||||
interface State {
|
interface State {
|
||||||
file?: File | Fileish;
|
file?: File | Fileish;
|
||||||
|
isEditorOpen: Boolean;
|
||||||
Compress?: typeof import('../compress').default;
|
Compress?: typeof import('../compress').default;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class App extends Component<Props, State> {
|
export default class App extends Component<Props, State> {
|
||||||
state: State = {
|
state: State = {
|
||||||
|
isEditorOpen: false,
|
||||||
file: undefined,
|
file: undefined,
|
||||||
Compress: undefined,
|
Compress: undefined,
|
||||||
};
|
};
|
||||||
@@ -53,17 +61,20 @@ export default class App extends Component<Props, State> {
|
|||||||
window.STATE = this.state;
|
window.STATE = this.state;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
window.addEventListener('popstate', this.onPopState);
|
||||||
}
|
}
|
||||||
|
|
||||||
@bind
|
@bind
|
||||||
private onFileDrop(event: FileDropEvent) {
|
private onFileDrop({ file }: FileDropEvent) {
|
||||||
const { file } = event;
|
|
||||||
if (!file) return;
|
if (!file) return;
|
||||||
|
this.openEditor();
|
||||||
this.setState({ file });
|
this.setState({ file });
|
||||||
}
|
}
|
||||||
|
|
||||||
@bind
|
@bind
|
||||||
private onIntroPickFile(file: File | Fileish) {
|
private onIntroPickFile(file: File | Fileish) {
|
||||||
|
this.openEditor();
|
||||||
this.setState({ file });
|
this.setState({ file });
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,18 +85,25 @@ export default class App extends Component<Props, State> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@bind
|
@bind
|
||||||
private onBack() {
|
private onPopState() {
|
||||||
this.setState({ file: undefined });
|
this.setState({ isEditorOpen: location.pathname === ROUTE_EDITOR });
|
||||||
}
|
}
|
||||||
|
|
||||||
render({}: Props, { file, Compress }: State) {
|
@bind
|
||||||
|
private openEditor() {
|
||||||
|
if (this.state.isEditorOpen) return;
|
||||||
|
history.pushState(null, '', ROUTE_EDITOR);
|
||||||
|
this.setState({ isEditorOpen: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
render({}: Props, { file, isEditorOpen, Compress }: State) {
|
||||||
return (
|
return (
|
||||||
<div id="app" class={style.app}>
|
<div id="app" class={style.app}>
|
||||||
<file-drop accept="image/*" onfiledrop={this.onFileDrop} class={style.drop}>
|
<file-drop accept="image/*" onfiledrop={this.onFileDrop} class={style.drop}>
|
||||||
{(!file)
|
{!isEditorOpen
|
||||||
? <Intro onFile={this.onIntroPickFile} showSnack={this.showSnack} />
|
? <Intro onFile={this.onIntroPickFile} showSnack={this.showSnack} />
|
||||||
: (Compress)
|
: (Compress)
|
||||||
? <Compress file={file} showSnack={this.showSnack} onBack={this.onBack} />
|
? <Compress file={file!} showSnack={this.showSnack} onBack={back} />
|
||||||
: <loading-spinner class={style.appLoader}/>
|
: <loading-spinner class={style.appLoader}/>
|
||||||
}
|
}
|
||||||
<snack-bar ref={linkRef(this, 'snackbar')} />
|
<snack-bar ref={linkRef(this, 'snackbar')} />
|
||||||
|
|||||||
@@ -160,7 +160,7 @@ function stateForNewSourceData(state: State, newSource: SourceImage): State {
|
|||||||
for (const i of [0, 1]) {
|
for (const i of [0, 1]) {
|
||||||
// Ditch previous encodings
|
// Ditch previous encodings
|
||||||
const downloadUrl = state.sides[i].downloadUrl;
|
const downloadUrl = state.sides[i].downloadUrl;
|
||||||
if (downloadUrl) URL.revokeObjectURL(downloadUrl!);
|
if (downloadUrl) URL.revokeObjectURL(downloadUrl);
|
||||||
|
|
||||||
newState = cleanMerge(state, `sides.${i}`, {
|
newState = cleanMerge(state, `sides.${i}`, {
|
||||||
preprocessed: undefined,
|
preprocessed: undefined,
|
||||||
@@ -319,9 +319,14 @@ export default class Compress extends Component<Props, State> {
|
|||||||
private async onCopyToOtherClick(index: 0 | 1) {
|
private async onCopyToOtherClick(index: 0 | 1) {
|
||||||
const otherIndex = (index + 1) % 2;
|
const otherIndex = (index + 1) % 2;
|
||||||
const oldSettings = this.state.sides[otherIndex];
|
const oldSettings = this.state.sides[otherIndex];
|
||||||
|
const newSettings = { ...this.state.sides[index] };
|
||||||
|
|
||||||
|
// Create a new object URL for the new settings. This avoids both sides sharing a URL, which
|
||||||
|
// means it can be safely revoked without impacting the other side.
|
||||||
|
if (newSettings.file) newSettings.downloadUrl = URL.createObjectURL(newSettings.file);
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
sides: cleanSet(this.state.sides, otherIndex, this.state.sides[index]),
|
sides: cleanSet(this.state.sides, otherIndex, newSettings),
|
||||||
});
|
});
|
||||||
|
|
||||||
const result = await this.props.showSnack('Settings copied across', {
|
const result = await this.props.showSnack('Settings copied across', {
|
||||||
|
|||||||
@@ -251,6 +251,11 @@ module.exports = async function (_, env) {
|
|||||||
filename: '_headers',
|
filename: '_headers',
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
isProd && new AssetTemplatePlugin({
|
||||||
|
template: path.join(__dirname, '_redirects.ejs'),
|
||||||
|
filename: '_redirects',
|
||||||
|
}),
|
||||||
|
|
||||||
new ScriptExtHtmlPlugin({
|
new ScriptExtHtmlPlugin({
|
||||||
inline: ['first']
|
inline: ['first']
|
||||||
}),
|
}),
|
||||||
|
|||||||
Reference in New Issue
Block a user