mirror of
https://github.com/GoogleChromeLabs/squoosh.git
synced 2025-11-12 16:57:26 +00:00
Compare commits
13 Commits
update-res
...
v1.9.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
eeb5e9f2ed | ||
|
|
8313246fd1 | ||
|
|
6ad28c0b5c | ||
|
|
c76dabf063 | ||
|
|
e6d8bac9c5 | ||
|
|
42e43730c8 | ||
|
|
5c17fba349 | ||
|
|
85eb94b725 | ||
|
|
4fa73be842 | ||
|
|
7c89d09139 | ||
|
|
079e56f1e1 | ||
|
|
6065ceabfe | ||
|
|
265e6db2bd |
@@ -10,6 +10,7 @@ Google Analytics is used to record the following:
|
|||||||
* [Basic visit data](https://support.google.com/analytics/answer/6004245?ref_topic=2919631).
|
* [Basic visit data](https://support.google.com/analytics/answer/6004245?ref_topic=2919631).
|
||||||
* Before and after image size once an image is downloaded. These values are rounded to the nearest
|
* Before and after image size once an image is downloaded. These values are rounded to the nearest
|
||||||
kilobyte.
|
kilobyte.
|
||||||
|
* If install is available, when Squoosh is installed, and what method was used to install Squoosh.
|
||||||
|
|
||||||
Image compression is handled locally; no additional data is sent to the server.
|
Image compression is handled locally; no additional data is sent to the server.
|
||||||
|
|
||||||
|
|||||||
2
package-lock.json
generated
2
package-lock.json
generated
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "squoosh",
|
"name": "squoosh",
|
||||||
"version": "1.9.1",
|
"version": "1.9.2",
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"private": true,
|
"private": true,
|
||||||
"name": "squoosh",
|
"name": "squoosh",
|
||||||
"version": "1.9.1",
|
"version": "1.9.2",
|
||||||
"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",
|
||||||
|
|||||||
@@ -270,7 +270,7 @@ export default class WebPEncoderOptions extends Component<Props, State> {
|
|||||||
value={options.sns_strength}
|
value={options.sns_strength}
|
||||||
onInput={this.onChange}
|
onInput={this.onChange}
|
||||||
>
|
>
|
||||||
Spacial noise shaping:
|
Spatial noise shaping:
|
||||||
</Range>
|
</Range>
|
||||||
</div>
|
</div>
|
||||||
<label class={style.optionTextFirst}>
|
<label class={style.optionTextFirst}>
|
||||||
|
|||||||
@@ -41,17 +41,31 @@ const demos = [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const installButtonSource = 'introInstallButton';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
onFile: (file: File | Fileish) => void;
|
onFile: (file: File | Fileish) => void;
|
||||||
showSnack: SnackBarElement['showSnackbar'];
|
showSnack: SnackBarElement['showSnackbar'];
|
||||||
}
|
}
|
||||||
interface State {
|
interface State {
|
||||||
fetchingDemoIndex?: number;
|
fetchingDemoIndex?: number;
|
||||||
|
beforeInstallEvent?: BeforeInstallPromptEvent;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class Intro extends Component<Props, State> {
|
export default class Intro extends Component<Props, State> {
|
||||||
state: State = {};
|
state: State = {};
|
||||||
private fileInput?: HTMLInputElement;
|
private fileInput?: HTMLInputElement;
|
||||||
|
private installingViaButton = false;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
// Listen for beforeinstallprompt events, indicating Squoosh is installable.
|
||||||
|
window.addEventListener('beforeinstallprompt', this.onBeforeInstallPromptEvent);
|
||||||
|
|
||||||
|
// Listen for the appinstalled event, indicating Squoosh has been installed.
|
||||||
|
window.addEventListener('appinstalled', this.onAppInstalled);
|
||||||
|
}
|
||||||
|
|
||||||
@bind
|
@bind
|
||||||
private resetFileInput() {
|
private resetFileInput() {
|
||||||
@@ -90,7 +104,52 @@ export default class Intro extends Component<Props, State> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
render({ }: Props, { fetchingDemoIndex }: State) {
|
@bind
|
||||||
|
private onBeforeInstallPromptEvent(event: BeforeInstallPromptEvent) {
|
||||||
|
// Don't show the mini-infobar on mobile
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
// Save the beforeinstallprompt event so it can be called later.
|
||||||
|
this.setState({ beforeInstallEvent: event });
|
||||||
|
|
||||||
|
// Log the event.
|
||||||
|
ga('send', 'event', 'pwa-install', 'available');
|
||||||
|
}
|
||||||
|
|
||||||
|
@bind
|
||||||
|
private async onInstallClick(event: Event) {
|
||||||
|
// Get the deferred beforeinstallprompt event
|
||||||
|
const beforeInstallEvent = this.state.beforeInstallEvent;
|
||||||
|
// If there's no deferred prompt, bail.
|
||||||
|
if (!beforeInstallEvent) return;
|
||||||
|
|
||||||
|
this.installingViaButton = true;
|
||||||
|
|
||||||
|
// Show the browser install prompt
|
||||||
|
beforeInstallEvent.prompt();
|
||||||
|
|
||||||
|
// Wait for the user to accept or dismiss the install prompt
|
||||||
|
const { outcome } = await beforeInstallEvent.userChoice;
|
||||||
|
ga('send', 'event', 'pwa-install', installButtonSource, outcome);
|
||||||
|
|
||||||
|
// If the prompt was dismissed, we aren't going to install via the button.
|
||||||
|
if (outcome === 'dismissed') {
|
||||||
|
this.installingViaButton = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@bind
|
||||||
|
private onAppInstalled() {
|
||||||
|
// Try to get the install, if it's not set, use 'browser'
|
||||||
|
const source = this.installingViaButton ? installButtonSource : 'browser';
|
||||||
|
ga('send', 'event', 'pwa-install', 'installed', source);
|
||||||
|
|
||||||
|
this.installingViaButton = false;
|
||||||
|
// We don't need the install button, if it's shown
|
||||||
|
this.setState({ beforeInstallEvent: undefined });
|
||||||
|
}
|
||||||
|
|
||||||
|
render({ }: Props, { fetchingDemoIndex, beforeInstallEvent }: State) {
|
||||||
return (
|
return (
|
||||||
<div class={style.intro}>
|
<div class={style.intro}>
|
||||||
<div>
|
<div>
|
||||||
@@ -120,7 +179,7 @@ export default class Intro extends Component<Props, State> {
|
|||||||
<img class={style.demoIcon} src={demo.iconUrl} alt="" decoding="async" />
|
<img class={style.demoIcon} src={demo.iconUrl} alt="" decoding="async" />
|
||||||
{fetchingDemoIndex === i &&
|
{fetchingDemoIndex === i &&
|
||||||
<div class={style.demoLoading}>
|
<div class={style.demoLoading}>
|
||||||
<loading-spinner class={style.demoLoadingSpinner}/>
|
<loading-spinner class={style.demoLoadingSpinner} />
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
@@ -132,6 +191,15 @@ export default class Intro extends Component<Props, State> {
|
|||||||
)}
|
)}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
{beforeInstallEvent &&
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class={style.installButton}
|
||||||
|
onClick={this.onInstallClick}
|
||||||
|
>
|
||||||
|
Install
|
||||||
|
</button>
|
||||||
|
}
|
||||||
<ul class={style.relatedLinks}>
|
<ul class={style.relatedLinks}>
|
||||||
<li><a href="https://github.com/GoogleChromeLabs/squoosh/">View the code</a></li>
|
<li><a href="https://github.com/GoogleChromeLabs/squoosh/">View the code</a></li>
|
||||||
<li><a href="https://github.com/GoogleChromeLabs/squoosh/issues">Report a bug</a></li>
|
<li><a href="https://github.com/GoogleChromeLabs/squoosh/issues">Report a bug</a></li>
|
||||||
|
|||||||
32
src/components/intro/missing-types.d.ts
vendored
Normal file
32
src/components/intro/missing-types.d.ts
vendored
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
/**
|
||||||
|
* The BeforeInstallPromptEvent is fired at the Window.onbeforeinstallprompt handler
|
||||||
|
* before a user is prompted to "install" a web site to a home screen on mobile.
|
||||||
|
*/
|
||||||
|
interface BeforeInstallPromptEvent extends Event {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an array of DOMString items containing the platforms on which the event was dispatched.
|
||||||
|
* This is provided for user agents that want to present a choice of versions to the user such as,
|
||||||
|
* for example, "web" or "play" which would allow the user to chose between a web version or
|
||||||
|
* an Android version.
|
||||||
|
*/
|
||||||
|
readonly platforms: Array<string>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a Promise that resolves to a DOMString containing either "accepted" or "dismissed".
|
||||||
|
*/
|
||||||
|
readonly userChoice: Promise<{
|
||||||
|
outcome: 'accepted' | 'dismissed',
|
||||||
|
platform: string
|
||||||
|
}>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows a developer to show the install prompt at a time of their own choosing.
|
||||||
|
* This method returns a Promise.
|
||||||
|
*/
|
||||||
|
prompt(): Promise<void>;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface WindowEventMap {
|
||||||
|
"beforeinstallprompt": BeforeInstallPromptEvent;
|
||||||
|
}
|
||||||
@@ -170,6 +170,30 @@
|
|||||||
--color: #fff;
|
--color: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.install-button {
|
||||||
|
composes: unbutton from '../../lib/util.scss';
|
||||||
|
|
||||||
|
&:hover,
|
||||||
|
&:focus {
|
||||||
|
background: #f5f5f5;
|
||||||
|
}
|
||||||
|
|
||||||
|
background: #fff;
|
||||||
|
border: 1px solid #e8e8e8;
|
||||||
|
padding: 14px;
|
||||||
|
font-size: 1.3rem;
|
||||||
|
|
||||||
|
position: absolute;
|
||||||
|
top: 1rem;
|
||||||
|
right: 1rem;
|
||||||
|
|
||||||
|
animation: fade-in .3s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes fade-in {
|
||||||
|
from { opacity: 0; }
|
||||||
|
}
|
||||||
|
|
||||||
.related-links {
|
.related-links {
|
||||||
display: flex;
|
display: flex;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
|||||||
10
src/index.ts
10
src/index.ts
@@ -13,11 +13,19 @@ if (!('customElements' in self)) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (typeof PRERENDER === 'undefined') {
|
if (typeof PRERENDER === 'undefined') {
|
||||||
|
// Determine the current display mode.
|
||||||
|
let displayMode = 'browser';
|
||||||
|
const mqStandAlone = '(display-mode: standalone)';
|
||||||
|
if (navigator.standalone || window.matchMedia(mqStandAlone).matches) {
|
||||||
|
displayMode = 'standalone';
|
||||||
|
}
|
||||||
|
// Setup analytics
|
||||||
window.ga = window.ga || ((...args) => (ga.q = ga.q || []).push(args));
|
window.ga = window.ga || ((...args) => (ga.q = ga.q || []).push(args));
|
||||||
ga('create', 'UA-128752250-1', 'auto');
|
ga('create', 'UA-128752250-1', 'auto');
|
||||||
ga('set', 'transport', 'beacon');
|
ga('set', 'transport', 'beacon');
|
||||||
|
ga('set', 'dimension1', displayMode);
|
||||||
ga('send', 'pageview');
|
ga('send', 'pageview');
|
||||||
// Load the GA script
|
// Load the GA script
|
||||||
const s = document.createElement('script');
|
const s = document.createElement('script');
|
||||||
s.src = 'https://www.google-analytics.com/analytics.js';
|
s.src = 'https://www.google-analytics.com/analytics.js';
|
||||||
document.head!.appendChild(s);
|
document.head!.appendChild(s);
|
||||||
|
|||||||
4
src/missing-types.d.ts
vendored
4
src/missing-types.d.ts
vendored
@@ -39,3 +39,7 @@ declare var ga: {
|
|||||||
(...args: any[]): void;
|
(...args: any[]): void;
|
||||||
q: any[];
|
q: any[];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
interface Navigator {
|
||||||
|
readonly standalone: boolean;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user