import { h, Component } from 'preact'; import { bind, linkRef, Fileish } from '../../lib/initial-util'; import '../custom-els/LoadingSpinner'; import logo from './imgs/logo.svg'; import largePhoto from './imgs/demos/demo-large-photo.jpg'; import artwork from './imgs/demos/demo-artwork.jpg'; import deviceScreen from './imgs/demos/demo-device-screen.png'; import largePhotoIcon from './imgs/demos/icon-demo-large-photo.jpg'; import artworkIcon from './imgs/demos/icon-demo-artwork.jpg'; import deviceScreenIcon from './imgs/demos/icon-demo-device-screen.jpg'; import logoIcon from './imgs/demos/icon-demo-logo.png'; import * as style from './style.scss'; import SnackBarElement from '../../lib/SnackBar'; const demos = [ { description: 'Large photo (2.8mb)', filename: 'photo.jpg', url: largePhoto, iconUrl: largePhotoIcon, }, { description: 'Artwork (2.9mb)', filename: 'art.jpg', url: artwork, iconUrl: artworkIcon, }, { description: 'Device screen (1.6mb)', filename: 'pixel3.png', url: deviceScreen, iconUrl: deviceScreenIcon, }, { description: 'SVG icon (13k)', filename: 'squoosh.svg', url: logo, iconUrl: logoIcon, }, ]; const installButtonSource = 'introInstallButton'; interface Props { onFile: (file: File | Fileish) => void; showSnack: SnackBarElement['showSnackbar']; } interface State { fetchingDemoIndex?: number; beforeInstallEvent?: BeforeInstallPromptEvent; } export default class Intro extends Component { state: State = {}; 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 private resetFileInput() { this.fileInput!.value = ''; } @bind private onFileChange(event: Event): void { const fileInput = event.target as HTMLInputElement; const file = fileInput.files && fileInput.files[0]; if (!file) return; this.resetFileInput(); this.props.onFile(file); } @bind private onButtonClick() { this.fileInput!.click(); } @bind private async onDemoClick(index: number, event: Event) { try { this.setState({ fetchingDemoIndex: index }); const demo = demos[index]; const blob = await fetch(demo.url).then(r => r.blob()); // Firefox doesn't like content types like 'image/png; charset=UTF-8', which Webpack's dev // server returns. https://bugzilla.mozilla.org/show_bug.cgi?id=1497925. const type = /[^;]*/.exec(blob.type)![0]; const file = new Fileish([blob], demo.filename, { type }); this.props.onFile(file); } catch (err) { this.setState({ fetchingDemoIndex: undefined }); this.props.showSnack("Couldn't fetch demo image"); } } @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 (
Squoosh

Drag & drop or{' '}

Or try one of these:

    {demos.map((demo, i) =>
  • , )}
{beforeInstallEvent && }
); } }