forked from external-repos/squoosh
Paste button
This commit is contained in:
@@ -2,7 +2,6 @@ import { h, Component } from 'preact';
|
|||||||
|
|
||||||
import { linkRef } from 'shared/initial-app/util';
|
import { linkRef } from 'shared/initial-app/util';
|
||||||
import '../custom-els/loading-spinner';
|
import '../custom-els/loading-spinner';
|
||||||
|
|
||||||
import logo from 'url:./imgs/logo.svg';
|
import logo from 'url:./imgs/logo.svg';
|
||||||
import largePhoto from 'url:./imgs/demos/demo-large-photo.jpg';
|
import largePhoto from 'url:./imgs/demos/demo-large-photo.jpg';
|
||||||
import artwork from 'url:./imgs/demos/demo-artwork.jpg';
|
import artwork from 'url:./imgs/demos/demo-artwork.jpg';
|
||||||
@@ -43,6 +42,17 @@ const demos = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
const installButtonSource = 'introInstallButton-Purple';
|
const installButtonSource = 'introInstallButton-Purple';
|
||||||
|
const supportsClipboardAPI =
|
||||||
|
!__PRERENDER__ && navigator.clipboard && navigator.clipboard.read;
|
||||||
|
|
||||||
|
async function getImageClipboardItem(
|
||||||
|
items: ClipboardItem[],
|
||||||
|
): Promise<undefined | Blob> {
|
||||||
|
for (const item of items) {
|
||||||
|
const type = item.types.find((type) => type.startsWith('image/'));
|
||||||
|
if (type) return item.getType(type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
onFile?: (file: File) => void;
|
onFile?: (file: File) => void;
|
||||||
@@ -58,10 +68,7 @@ export default class Intro extends Component<Props, State> {
|
|||||||
private fileInput?: HTMLInputElement;
|
private fileInput?: HTMLInputElement;
|
||||||
private installingViaButton = false;
|
private installingViaButton = false;
|
||||||
|
|
||||||
constructor() {
|
componentDidMount() {
|
||||||
super();
|
|
||||||
|
|
||||||
if (__PRERENDER__) return;
|
|
||||||
// Listen for beforeinstallprompt events, indicating Squoosh is installable.
|
// Listen for beforeinstallprompt events, indicating Squoosh is installable.
|
||||||
window.addEventListener(
|
window.addEventListener(
|
||||||
'beforeinstallprompt',
|
'beforeinstallprompt',
|
||||||
@@ -72,15 +79,19 @@ export default class Intro extends Component<Props, State> {
|
|||||||
window.addEventListener('appinstalled', this.onAppInstalled);
|
window.addEventListener('appinstalled', this.onAppInstalled);
|
||||||
}
|
}
|
||||||
|
|
||||||
private resetFileInput = () => {
|
componentWillUnmount() {
|
||||||
this.fileInput!.value = '';
|
window.removeEventListener(
|
||||||
};
|
'beforeinstallprompt',
|
||||||
|
this.onBeforeInstallPromptEvent,
|
||||||
|
);
|
||||||
|
window.removeEventListener('appinstalled', this.onAppInstalled);
|
||||||
|
}
|
||||||
|
|
||||||
private onFileChange = (event: Event): void => {
|
private onFileChange = (event: Event): void => {
|
||||||
const fileInput = event.target as HTMLInputElement;
|
const fileInput = event.target as HTMLInputElement;
|
||||||
const file = fileInput.files && fileInput.files[0];
|
const file = fileInput.files && fileInput.files[0];
|
||||||
if (!file) return;
|
if (!file) return;
|
||||||
this.resetFileInput();
|
this.fileInput!.value = '';
|
||||||
this.props.onFile!(file);
|
this.props.onFile!(file);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -94,10 +105,8 @@ export default class Intro extends Component<Props, State> {
|
|||||||
const demo = demos[index];
|
const demo = demos[index];
|
||||||
const blob = await fetch(demo.url).then((r) => r.blob());
|
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
|
// TODO: test this is ok on both netlify and dev server in Firefox
|
||||||
// server returns. https://bugzilla.mozilla.org/show_bug.cgi?id=1497925.
|
const file = new File([blob], demo.filename, { type: blob.type });
|
||||||
const type = /[^;]*/.exec(blob.type)![0];
|
|
||||||
const file = new File([blob], demo.filename, { type });
|
|
||||||
this.props.onFile!(file);
|
this.props.onFile!(file);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this.setState({ fetchingDemoIndex: undefined });
|
this.setState({ fetchingDemoIndex: undefined });
|
||||||
@@ -154,9 +163,7 @@ export default class Intro extends Component<Props, State> {
|
|||||||
this.setState({ beforeInstallEvent: undefined });
|
this.setState({ beforeInstallEvent: undefined });
|
||||||
|
|
||||||
// Don't log analytics if page is not visible
|
// Don't log analytics if page is not visible
|
||||||
if (document.hidden) {
|
if (document.hidden) return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try to get the install, if it's not set, use 'browser'
|
// Try to get the install, if it's not set, use 'browser'
|
||||||
const source = this.installingViaButton ? installButtonSource : 'browser';
|
const source = this.installingViaButton ? installButtonSource : 'browser';
|
||||||
@@ -166,89 +173,65 @@ export default class Intro extends Component<Props, State> {
|
|||||||
this.installingViaButton = false;
|
this.installingViaButton = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private onPasteClick = async () => {
|
||||||
|
let clipboardItems: ClipboardItem[];
|
||||||
|
|
||||||
|
try {
|
||||||
|
clipboardItems = await navigator.clipboard.read();
|
||||||
|
} catch (err) {
|
||||||
|
this.props.showSnack!(`Cannot access clipboard`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const blob = await getImageClipboardItem(clipboardItems);
|
||||||
|
|
||||||
|
if (!blob) {
|
||||||
|
this.props.showSnack!(`No image found`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(blob);
|
||||||
|
|
||||||
|
this.props.onFile!(new File([blob], 'image.unknown'));
|
||||||
|
};
|
||||||
|
|
||||||
render({}: Props, { fetchingDemoIndex, beforeInstallEvent }: State) {
|
render({}: Props, { fetchingDemoIndex, beforeInstallEvent }: State) {
|
||||||
return (
|
return (
|
||||||
<div class={style.intro}>
|
<div class={style.intro}>
|
||||||
<div>
|
<input
|
||||||
<div class={style.logoSizer}>
|
class={style.hide}
|
||||||
<div class={style.logoContainer}>
|
ref={linkRef(this, 'fileInput')}
|
||||||
<img
|
type="file"
|
||||||
src={logo}
|
onChange={this.onFileChange}
|
||||||
class={style.logo}
|
/>
|
||||||
alt="Squoosh"
|
{beforeInstallEvent && (
|
||||||
decoding="async"
|
<button onClick={this.onInstallClick}>Install</button>
|
||||||
/>
|
)}
|
||||||
|
<div class={style.main}>
|
||||||
|
<div class={style.logo}>Logo Placeholder</div>
|
||||||
|
<div class={style.loadImg}>
|
||||||
|
<div
|
||||||
|
class={style.loadImgContent}
|
||||||
|
style={{ visibility: __PRERENDER__ ? 'hidden' : '' }}
|
||||||
|
>
|
||||||
|
<button class={style.loadBtn}>
|
||||||
|
<svg viewBox="0 0 24 24" class={style.loadIcon}>
|
||||||
|
<path d="M19 7v3h-2V7h-3V5h3V2h2v3h3v2h-3zm-3 4V8h-3V5H5a2 2 0 00-2 2v12c0 1.1.9 2 2 2h12a2 2 0 002-2v-8h-3zM5 19l3-4 2 3 3-4 4 5H5z" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
<div>
|
||||||
|
Drop OR{' '}
|
||||||
|
{supportsClipboardAPI ? (
|
||||||
|
<button class={style.pasteBtn} onClick={this.onPasteClick}>
|
||||||
|
Paste
|
||||||
|
</button>
|
||||||
|
) : (
|
||||||
|
'Paste'
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<p class={style.openImageGuide}>
|
|
||||||
Drag & drop or{' '}
|
|
||||||
<button class={style.selectButton} onClick={this.onButtonClick}>
|
|
||||||
select an image
|
|
||||||
</button>
|
|
||||||
<input
|
|
||||||
class={style.hide}
|
|
||||||
ref={linkRef(this, 'fileInput')}
|
|
||||||
type="file"
|
|
||||||
onChange={this.onFileChange}
|
|
||||||
/>
|
|
||||||
</p>
|
|
||||||
<p>Or try one of these:</p>
|
|
||||||
<ul class={style.demos}>
|
|
||||||
{demos.map((demo, i) => (
|
|
||||||
<li key={demo.url} class={style.demoItem}>
|
|
||||||
<button
|
|
||||||
class={style.demoButton}
|
|
||||||
onClick={this.onDemoClick.bind(this, i)}
|
|
||||||
>
|
|
||||||
<div class={style.demo}>
|
|
||||||
<div class={style.demoImgContainer}>
|
|
||||||
<div class={style.demoImgAspect}>
|
|
||||||
<img
|
|
||||||
class={style.demoIcon}
|
|
||||||
src={demo.iconUrl}
|
|
||||||
alt=""
|
|
||||||
decoding="async"
|
|
||||||
/>
|
|
||||||
{fetchingDemoIndex === i && (
|
|
||||||
<div class={style.demoLoading}>
|
|
||||||
<loading-spinner class={style.demoLoadingSpinner} />
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class={style.demoDescription}>{demo.description}</div>
|
|
||||||
</div>
|
|
||||||
</button>
|
|
||||||
</li>
|
|
||||||
))}
|
|
||||||
</ul>
|
|
||||||
</div>
|
</div>
|
||||||
{beforeInstallEvent && (
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
class={style.installButton}
|
|
||||||
onClick={this.onInstallClick}
|
|
||||||
>
|
|
||||||
Install
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
<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/issues">
|
|
||||||
Report a bug
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href="https://github.com/GoogleChromeLabs/squoosh/blob/dev/README.md#privacy">
|
|
||||||
Privacy
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,3 +29,12 @@ interface BeforeInstallPromptEvent extends Event {
|
|||||||
interface WindowEventMap {
|
interface WindowEventMap {
|
||||||
beforeinstallprompt: BeforeInstallPromptEvent;
|
beforeinstallprompt: BeforeInstallPromptEvent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface ClipboardItem {
|
||||||
|
types: string[];
|
||||||
|
getType(type: string): Promise<Blob>;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Clipboard {
|
||||||
|
read(): Promise<ClipboardItem[]>;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,228 +1,62 @@
|
|||||||
@font-face {
|
|
||||||
font-family: 'intro-text';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 300;
|
|
||||||
font-display: block;
|
|
||||||
/* This only contains the chars for "Drag & drop or" */
|
|
||||||
src: url('data:font/woff2;base64,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')
|
|
||||||
format('woff2');
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: 'intro-text';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 500;
|
|
||||||
font-display: block;
|
|
||||||
/* Only contains the chars for "select an image" */
|
|
||||||
src: url('data:font/woff2;base64,d09GMgABAAAAAAXMAA4AAAAACwQAAAV5AAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGhYbg1IcMAZgAGwRCAqJUId/CxoAATYCJAMwBCAFgnAHIBskCcjEh6dNff8Ou/9Tj9VZGnUhJeqFzWGiVVOkxkTthr9f6kWkRdsBbkIj3YuLaloFZWr7aBg22z7IOoWqBWCW5cZU3GBrh0n+dAcBYAUlzYHAzWTYchqKXEyAT0zOLIS1qqm+B8q2ur4OhEMy0PHHUH8KklaSr8T0mp/EU7kRvXlI1E09HXA1qLN8Djxa0AsSDOg3cJARb9mtQJoSK3gvEn372/gcAigg/gOnbsT/MYv491GTReW4rJC5LA+h5FFclF6QQgoZ5Kx7GbsuGeytUgFClkOomY2Gdake3m9HegkHieAx/a0hBTALsy4jvpxBcnFXUnjC+2ZS5zHnDeEaJVwi+ZWqzOm4Uvgy4k6kGv4kFDVkfjk1gkVRRkk2zlo42PBbRJmG30cClJQjak7BnfQqHza4ITKftQZ/ZMUaEiyy1+mYCh4clKhDA5rQglZ0oG9jw+qiNvT+SfxIXCeuFdeIq8VV4gpxyRaGOl0JiChiCocfc7e93DwZIPvWgPiZJLcJugxyjW7UQyl4TJk6dWqYU7Cn0WQiWnNJCdGeprqjW63fpVS3mKy4YGZ6I3ya4nbIVgM1mwkpNEBzixlNxfPmH7owvdE4973OM9quvk11dwvnzDUy/Zn5S5Ywpn/PeqXBQI2m4lna05CRtsI6+GIENjS9K4jWRHUGYA2ozdZm2Smmf0DI3aqpeNbsJfxe7YdFmcZAn5gXLCFa2/Umqiu017APFhMZ0rfQp4sJX0ZrJ+n9UtAljr5VYWb6oj1MrpvX3qe6u8WRJg0bj7aPkDOa7m+E0Oa9Y8eY/gbRbr+efH7hcO49bMd28fbDVHcUmm3XkozQGKjeBHSJ4TQnI879LIFmF2v/BJuEQlffJPfE9oKayS/PsPE44fvM4MsBESxbuEEV39d5pw6oW4vD6S1WQC3UpSbHNbK0Jikl0bphSs+0CGW8Ew4Kzw7zarmcVz873JHTFhKYay18R8vY0ozPiHPAGyROAqlW5fLj5+HbWBn9TpgekKsOy8N+4dlFfL9i/Nk3+gY1bwzZUAvLVNiFpvqHRenetSoVrgn2obGtPsltEVxEeHJAQFhyBIcHT9rDvTJm06e0TLgase2gd2RffGJNg0o1zrdRyi9s1bYE5bi85cK+o/nUwvBR5+jweEBaSMoCub29fEFISmib9Dn5yl5kVFpoGrPQSmZhafQ7WimttNCH7Cktohb6kFpoEfIsdDF7SgvZTbaY3mKFyLXQh+wpzWE3mUNQQkWnR+lgiW9Afkunej49Nz3sYlI8XFTRdkNhUR5d6h4oOpJc8OjcItMXVqoHW2fSW6ycWuiM8NDYoICouLAZ9BYrwwmhycvKlt4Q8hUlCV5nZ7vOm2ut2rizcFpuWpSrT3K1Z3xinbuHnXBTyGAljV/XzHZaNGu6y7vLDziMpIyUdOBBRXXlxznUQiOoheZsZk9njG8er1mNmz2eOCQ3x9BbLP+Zxt+VrbEz9aWxmimRvyl4/sumyoM/nw+LNzV4/uP0/9T/P5f08cvhl38USAS/xTYs2fL/VNFF0vd+SVsRB/khPwW4SCi5SHhx8fDgVPAiAqIJRQL/EuK5bsRzNnAiezD1i7u2VyHHAKRU+E2YUaA5DUsE2ZfbApAmsJcxjBwmQ2Xk4Y2BqZJ+oxSzsNEogz1O3/xkBMKEBHSiC8PoQStaoEIflPCHL/wQBCUKoUITlMhHP+olt5ojykUPOrEQTWgY+f449KMPKnSiB72jGrLQhEZO24925LtbkG5DndTkD2/4um+NQBEyUIJsRBxX24tcDGmbWtGJjq05jhzTaMgCcR+6EA4f+KAXDay5u6RsL7xJsm3w3mzvFvggB8nI/AYBdVnxNvx/2wA=')
|
|
||||||
format('woff2');
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes fade-in {
|
|
||||||
from {
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.intro {
|
.intro {
|
||||||
display: grid;
|
composes: abs-fill from '../util.css';
|
||||||
grid-template-rows: 1fr min-content;
|
|
||||||
align-items: center;
|
|
||||||
background: rgba(255, 255, 255, 0.25);
|
|
||||||
text-align: center;
|
|
||||||
font-size: 2rem;
|
|
||||||
-webkit-overflow-scrolling: touch;
|
-webkit-overflow-scrolling: touch;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
padding: 20px 0 0;
|
|
||||||
height: 100%;
|
|
||||||
box-sizing: border-box;
|
|
||||||
overscroll-behavior: contain;
|
overscroll-behavior: contain;
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.logo-container {
|
|
||||||
position: relative;
|
|
||||||
padding-top: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.logo-sizer {
|
|
||||||
width: 90%;
|
|
||||||
max-width: 52vh;
|
|
||||||
margin: 0 auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.logo {
|
|
||||||
composes: abs-fill from '../util.css';
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.open-image-guide {
|
|
||||||
font: 300 11vw intro-text, sans-serif;
|
|
||||||
margin-bottom: 0;
|
|
||||||
|
|
||||||
@media (min-width: 460px) {
|
|
||||||
font-size: 50.6px;
|
|
||||||
padding: 0 40px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.select-button {
|
|
||||||
composes: unbutton from '../util.css';
|
|
||||||
font-weight: 500;
|
|
||||||
color: #5d509e;
|
|
||||||
|
|
||||||
&:hover,
|
|
||||||
&:focus {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.hide {
|
.hide {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.demos {
|
.main {
|
||||||
display: block;
|
min-height: 50vh;
|
||||||
padding: 0;
|
display: grid;
|
||||||
border-top: 1px solid #e8e8e8;
|
grid-template-rows: max-content max-content;
|
||||||
margin: 0 auto;
|
justify-items: center;
|
||||||
|
align-content: center;
|
||||||
@media (min-width: 400px) {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: 1fr 1fr;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (min-width: 580px) {
|
|
||||||
border-top: none;
|
|
||||||
width: 523px;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (min-width: 900px) {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: 1fr 1fr 1fr 1fr;
|
|
||||||
width: 773px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.demo-item {
|
.logo {
|
||||||
background: #fff;
|
font-weight: bold;
|
||||||
display: flex;
|
font-size: 3rem;
|
||||||
border-bottom: 1px solid #e8e8e8;
|
margin: 4rem 0;
|
||||||
|
|
||||||
@media (min-width: 580px) {
|
|
||||||
border: 1px solid #e8e8e8;
|
|
||||||
border-radius: 4px;
|
|
||||||
margin: 3px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.demo-button {
|
.load-img {
|
||||||
|
background: var(--pink);
|
||||||
|
color: var(--white);
|
||||||
|
font-style: italic;
|
||||||
|
font-size: 1.2rem;
|
||||||
|
--size: 23rem;
|
||||||
|
border-radius: var(--size);
|
||||||
|
}
|
||||||
|
|
||||||
|
.load-img-content {
|
||||||
|
width: var(--size);
|
||||||
|
height: var(--size);
|
||||||
|
display: grid;
|
||||||
|
grid-template-rows: max-content max-content;
|
||||||
|
justify-items: center;
|
||||||
|
align-content: center;
|
||||||
|
gap: 0.7rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.load-btn {
|
||||||
composes: unbutton from '../util.css';
|
composes: unbutton from '../util.css';
|
||||||
flex: 1;
|
|
||||||
|
|
||||||
&:hover,
|
|
||||||
&:focus {
|
|
||||||
background: #f5f5f5;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.demo {
|
.load-icon {
|
||||||
display: flex;
|
--size: 5rem;
|
||||||
align-items: center;
|
width: var(--size);
|
||||||
padding: 7px;
|
height: var(--size);
|
||||||
font-size: 1.3rem;
|
fill: var(--white);
|
||||||
|
transform: translate(4.3%, -1%);
|
||||||
}
|
}
|
||||||
|
|
||||||
.demo-img-container {
|
.paste-btn {
|
||||||
overflow: hidden;
|
|
||||||
display: block;
|
|
||||||
width: 47px;
|
|
||||||
background: #ccc;
|
|
||||||
border-radius: 3px;
|
|
||||||
flex: 0 0 auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.demo-img-aspect {
|
|
||||||
position: relative;
|
|
||||||
padding-top: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.demo-icon {
|
|
||||||
composes: abs-fill from '../util.css';
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.demo-description {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: flex-start;
|
|
||||||
text-align: left;
|
|
||||||
flex: 1;
|
|
||||||
padding: 0 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.demo-loading {
|
|
||||||
composes: abs-fill from '../util.css';
|
|
||||||
background: rgba(0, 0, 0, 0.6);
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
animation: fade-in 300ms ease-in-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
.demo-loading-spinner {
|
|
||||||
--color: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.install-button {
|
|
||||||
composes: unbutton from '../util.css';
|
composes: unbutton from '../util.css';
|
||||||
|
text-decoration: underline;
|
||||||
&:hover,
|
font: inherit;
|
||||||
&:focus {
|
color: inherit;
|
||||||
background: #504488;
|
|
||||||
}
|
|
||||||
|
|
||||||
background: #5d509e;
|
|
||||||
border: 1px solid #e8e8e8;
|
|
||||||
color: #fff;
|
|
||||||
padding: 14px;
|
|
||||||
font-size: 1.3rem;
|
|
||||||
|
|
||||||
position: absolute;
|
|
||||||
top: 1rem;
|
|
||||||
right: 1rem;
|
|
||||||
|
|
||||||
animation: fade-in 0.3s ease-in-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes fade-in {
|
|
||||||
from {
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.related-links {
|
|
||||||
display: flex;
|
|
||||||
padding: 0;
|
|
||||||
justify-content: center;
|
|
||||||
font-size: 1.3rem;
|
|
||||||
|
|
||||||
& li {
|
|
||||||
display: block;
|
|
||||||
border-left: 1px solid #000;
|
|
||||||
padding: 0 0.6em;
|
|
||||||
|
|
||||||
&:first-child {
|
|
||||||
border-left: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
& a:link {
|
|
||||||
color: #5d509e;
|
|
||||||
text-decoration: none;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
4
src/shared/initial-app/colors.css
Normal file
4
src/shared/initial-app/colors.css
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
html {
|
||||||
|
--pink: #ff3385;
|
||||||
|
--white: #fff;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user