mirror of
https://github.com/GoogleChromeLabs/squoosh.git
synced 2025-11-19 12:08:57 +00:00
(Almost the) rest of the redesign (#880)
* Load demo img * two-up styles * Back button * Button size tweak * Move back btn * Move options and back button into a single grid * Simpler max height * Responsive grid * Feed index into options * Option heading themes * More option styles * Changing checkbox position * Theme range input & use transforms * Range input underline theme * Checkbox color * Add toggle * Reorder * Arrow revealer * Round two-up thumb * Don't bundle CSS urls starting # * Results in progress * Fix Safari bugs * Download blobs * Loading spinner * Hook up download button * Different style for original image * Mobile design for results * Remove demo auto-loader * Remove redundant colors * Sticky headings
This commit is contained in:
@@ -1,43 +0,0 @@
|
||||
import { h, Component } from 'preact';
|
||||
import prettyBytes from 'pretty-bytes';
|
||||
import * as style from './style.css';
|
||||
|
||||
interface Props {
|
||||
blob: Blob;
|
||||
compareTo?: Blob;
|
||||
}
|
||||
|
||||
interface State {}
|
||||
|
||||
export default class FileSize extends Component<Props, State> {
|
||||
render({ blob, compareTo }: Props) {
|
||||
let comparison: preact.JSX.Element | undefined;
|
||||
|
||||
if (compareTo) {
|
||||
const delta = blob.size / compareTo.size;
|
||||
if (delta > 1) {
|
||||
const percent = Math.round((delta - 1) * 100) + '%';
|
||||
comparison = (
|
||||
<span class={`${style.sizeDelta} ${style.sizeIncrease}`}>
|
||||
{percent === '0%' ? 'slightly' : percent} bigger
|
||||
</span>
|
||||
);
|
||||
} else if (delta < 1) {
|
||||
const percent = Math.round((1 - delta) * 100) + '%';
|
||||
comparison = (
|
||||
<span class={`${style.sizeDelta} ${style.sizeDecrease}`}>
|
||||
{percent === '0%' ? 'slightly' : percent} smaller
|
||||
</span>
|
||||
);
|
||||
} else {
|
||||
comparison = <span class={style.sizeDelta}>no change</span>;
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<span>
|
||||
{prettyBytes(blob.size)} {comparison}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,37 +1,25 @@
|
||||
import { h, Component, ComponentChildren, ComponentChild } from 'preact';
|
||||
import { h, Component, Fragment } from 'preact';
|
||||
|
||||
import * as style from './style.css';
|
||||
import 'add-css:./style.css';
|
||||
import FileSize from './FileSize';
|
||||
import {
|
||||
DownloadIcon,
|
||||
CopyAcrossIcon,
|
||||
CopyAcrossIconProps,
|
||||
} from 'client/lazy-app/icons';
|
||||
import 'shared/custom-els/loading-spinner';
|
||||
import { SourceImage } from '../';
|
||||
import prettyBytes from './pretty-bytes';
|
||||
import { Arrow, DownloadIcon } from 'client/lazy-app/icons';
|
||||
|
||||
interface Props {
|
||||
loading: boolean;
|
||||
source?: SourceImage;
|
||||
imageFile?: File;
|
||||
downloadUrl?: string;
|
||||
children: ComponentChildren;
|
||||
copyDirection: CopyAcrossIconProps['copyDirection'];
|
||||
buttonPosition: keyof typeof buttonPositionClass;
|
||||
onCopyToOtherClick(): void;
|
||||
flipSide: boolean;
|
||||
typeLabel: string;
|
||||
}
|
||||
|
||||
interface State {
|
||||
showLoadingState: boolean;
|
||||
}
|
||||
|
||||
const buttonPositionClass = {
|
||||
'stack-right': style.stackRight,
|
||||
'download-right': style.downloadRight,
|
||||
'download-left': style.downloadLeft,
|
||||
};
|
||||
|
||||
const loadingReactionDelay = 500;
|
||||
|
||||
export default class Results extends Component<Props, State> {
|
||||
@@ -56,11 +44,6 @@ export default class Results extends Component<Props, State> {
|
||||
}
|
||||
}
|
||||
|
||||
private onCopyToOtherClick = (event: Event) => {
|
||||
event.preventDefault();
|
||||
this.props.onCopyToOtherClick();
|
||||
};
|
||||
|
||||
private onDownload = () => {
|
||||
// GA can’t do floats. So we round to ints. We're deliberately rounding to nearest kilobyte to
|
||||
// avoid cases where exact image sizes leak something interesting about the user.
|
||||
@@ -76,59 +59,83 @@ export default class Results extends Component<Props, State> {
|
||||
};
|
||||
|
||||
render(
|
||||
{
|
||||
source,
|
||||
imageFile,
|
||||
downloadUrl,
|
||||
children,
|
||||
copyDirection,
|
||||
buttonPosition,
|
||||
}: Props,
|
||||
{ source, imageFile, downloadUrl, flipSide, typeLabel }: Props,
|
||||
{ showLoadingState }: State,
|
||||
) {
|
||||
const prettySize = imageFile && prettyBytes(imageFile.size);
|
||||
const isOriginal = !source || !imageFile || source.file === imageFile;
|
||||
let diff;
|
||||
let percent;
|
||||
|
||||
if (source && imageFile) {
|
||||
diff = imageFile.size / source.file.size;
|
||||
const absolutePercent = Math.round(Math.abs(diff) * 100);
|
||||
percent = diff > 1 ? absolutePercent - 100 : 100 - absolutePercent;
|
||||
}
|
||||
|
||||
return (
|
||||
<div class={`${style.results} ${buttonPositionClass[buttonPosition]}`}>
|
||||
<div class={style.resultData}>
|
||||
{children ? <div class={style.resultTitle}>{children}</div> : null}
|
||||
{!imageFile || showLoadingState ? (
|
||||
'Working…'
|
||||
) : (
|
||||
<FileSize
|
||||
blob={imageFile}
|
||||
compareTo={
|
||||
source && imageFile !== source.file ? source.file : undefined
|
||||
}
|
||||
/>
|
||||
)}
|
||||
<div
|
||||
class={
|
||||
(flipSide ? style.resultsRight : style.resultsLeft) +
|
||||
' ' +
|
||||
(isOriginal ? style.isOriginal : '')
|
||||
}
|
||||
>
|
||||
<div class={style.expandArrow}>
|
||||
<Arrow />
|
||||
</div>
|
||||
|
||||
<button
|
||||
class={style.copyToOther}
|
||||
title="Copy settings to other side"
|
||||
onClick={this.onCopyToOtherClick}
|
||||
<div class={style.bubble}>
|
||||
<div class={style.bubbleInner}>
|
||||
<div class={style.sizeInfo}>
|
||||
<div class={style.fileSize}>
|
||||
{prettySize ? (
|
||||
<Fragment>
|
||||
{prettySize.value}{' '}
|
||||
<span class={style.unit}>{prettySize.unit}</span>
|
||||
<span class={style.typeLabel}> {typeLabel}</span>
|
||||
</Fragment>
|
||||
) : (
|
||||
'…'
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div class={style.percentInfo}>
|
||||
<svg
|
||||
viewBox="0 0 1 2"
|
||||
class={style.bigArrow}
|
||||
preserveAspectRatio="none"
|
||||
>
|
||||
<path d="M1 0v2L0 1z" />
|
||||
</svg>
|
||||
<div class={style.percentOutput}>
|
||||
{diff && diff !== 1 && (
|
||||
<span class={style.sizeDirection}>
|
||||
{diff < 1 ? '↓' : '↑'}
|
||||
</span>
|
||||
)}
|
||||
<span class={style.sizeValue}>{percent || 0}</span>
|
||||
<span class={style.percentChar}>%</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<a
|
||||
class={showLoadingState ? style.downloadDisable : style.download}
|
||||
href={downloadUrl}
|
||||
download={imageFile ? imageFile.name : ''}
|
||||
title="Download"
|
||||
onClick={this.onDownload}
|
||||
>
|
||||
<CopyAcrossIcon
|
||||
class={style.copyIcon}
|
||||
copyDirection={copyDirection}
|
||||
/>
|
||||
</button>
|
||||
|
||||
<div class={style.download}>
|
||||
{downloadUrl && imageFile && (
|
||||
<a
|
||||
class={`${style.downloadLink} ${
|
||||
showLoadingState ? style.downloadLinkDisable : ''
|
||||
}`}
|
||||
href={downloadUrl}
|
||||
download={imageFile.name}
|
||||
title="Download"
|
||||
onClick={this.onDownload}
|
||||
>
|
||||
<DownloadIcon class={style.downloadIcon} />
|
||||
</a>
|
||||
)}
|
||||
{showLoadingState && <loading-spinner class={style.spinner} />}
|
||||
</div>
|
||||
<svg class={style.downloadBlobs} viewBox="0 0 89.6 86.9">
|
||||
<title>Download</title>
|
||||
<path d="M27.3 72c-8-4-15.6-12.3-16.9-21-1.2-8.7 4-17.8 10.5-26s14.4-15.6 24-16 21.2 6 28.6 16.5c7.4 10.5 10.8 25 6.6 34S64.1 71.8 54 73.6c-10.2 2-18.7 2.3-26.7-1.6z" />
|
||||
<path d="M19.8 24.8c4.3-7.8 13-15 21.8-15.7 8.7-.8 17.5 4.8 25.4 11.8 7.8 6.9 14.8 15.2 14.7 24.9s-7.1 20.7-18 27.6c-10.8 6.8-25.5 9.5-34.2 4.8S18.1 61.6 16.7 51.4c-1.3-10.3-1.3-18.8 3-26.6z" />
|
||||
</svg>
|
||||
<div class={style.downloadIcon}>
|
||||
<DownloadIcon />
|
||||
</div>
|
||||
{showLoadingState && <loading-spinner />}
|
||||
</a>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
27
src/client/lazy-app/Compress/Results/pretty-bytes.ts
Normal file
27
src/client/lazy-app/Compress/Results/pretty-bytes.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
// Based on https://www.npmjs.com/package/pretty-bytes
|
||||
// Modified so the units are returned separately.
|
||||
|
||||
const UNITS = ['B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
|
||||
|
||||
interface PrettyBytesResult {
|
||||
value: string;
|
||||
unit: string;
|
||||
}
|
||||
|
||||
export default function prettyBytes(number: number): PrettyBytesResult {
|
||||
const isNegative = number < 0;
|
||||
const prefix = isNegative ? '-' : '';
|
||||
|
||||
if (isNegative) number = -number;
|
||||
if (number < 1) return { value: prefix + number, unit: UNITS[0] };
|
||||
|
||||
const exponent = Math.min(
|
||||
Math.floor(Math.log10(number) / 3),
|
||||
UNITS.length - 1,
|
||||
);
|
||||
|
||||
return {
|
||||
unit: UNITS[exponent],
|
||||
value: prefix + (number / Math.pow(1000, exponent)).toPrecision(3),
|
||||
};
|
||||
}
|
||||
@@ -1,3 +1,12 @@
|
||||
@font-face {
|
||||
font-family: 'Roboto Mono Numbers';
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
/* Just 0132456789. https://fonts.googleapis.com/css2?family=Roboto+Mono:wght@700&text=0123456789 */
|
||||
src: url('data:font/woff;base64,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')
|
||||
format('woff');
|
||||
}
|
||||
|
||||
@keyframes action-enter {
|
||||
from {
|
||||
transform: rotate(-90deg);
|
||||
@@ -15,117 +24,336 @@
|
||||
}
|
||||
|
||||
.results {
|
||||
--download-overflow-size: 9px;
|
||||
background: rgba(0, 0, 0, 0.67);
|
||||
border-radius: 5px;
|
||||
display: grid;
|
||||
grid-template-columns: [text] 1fr [copy-button] auto [download-button] auto;
|
||||
background: rgba(0, 0, 0, 0.9);
|
||||
font-size: 1rem;
|
||||
|
||||
@media (min-width: 400px) {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
grid-template-columns: max-content [bubble] 1fr [download] max-content;
|
||||
|
||||
@media (min-width: 600px) {
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
--download-overflow-size: 30px;
|
||||
background: none;
|
||||
border-radius: none;
|
||||
grid-template-columns: [download] auto [bubble] 1fr;
|
||||
align-items: center;
|
||||
margin-bottom: calc(var(--download-overflow-size) / 2);
|
||||
}
|
||||
}
|
||||
|
||||
.result-data {
|
||||
.expand-arrow {
|
||||
fill: var(--white);
|
||||
transform: rotate(180deg);
|
||||
margin: 0 1rem;
|
||||
align-self: center;
|
||||
|
||||
@media (min-width: 600px) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
:focus & {
|
||||
fill: var(--main-theme-color);
|
||||
}
|
||||
|
||||
[content-expanded] & {
|
||||
transform: none;
|
||||
}
|
||||
|
||||
svg {
|
||||
display: block;
|
||||
--size: 15px;
|
||||
width: var(--size);
|
||||
height: var(--size);
|
||||
}
|
||||
}
|
||||
|
||||
.file-size {
|
||||
}
|
||||
|
||||
.bubble {
|
||||
align-self: center;
|
||||
|
||||
@media (min-width: 600px) {
|
||||
position: relative;
|
||||
width: max-content;
|
||||
grid-row: 1;
|
||||
grid-column: bubble;
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
border-image-source: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='186.5' height='280.3' viewBox='0 0 186.5 280.3'%3E%3Cpath fill='rgba(30,31,29,0.69)' d='M181.5 0H16.4a5 5 0 00-5 5v134L0 146.5h11.4v128.8a5 5 0 005 5h165.1a5 5 0 005-5V5a5 5 0 00-5-5z'/%3E%3Cpath fill='rgba(0,0,0,0.23)' d='M16.4 1a4 4 0 00-4 4v134.5l-.5.3-8.6 5.7h9v129.8a4 4 0 004 4h165.2a4 4 0 004-4V5a4 4 0 00-4-4H16.4m0-1h165.1a5 5 0 015 5v270.3a5 5 0 01-5 5H16.4a5 5 0 01-5-5V146.5H0l11.4-7.5V5a5 5 0 015-5z'/%3E%3C/svg%3E");
|
||||
border-image-slice: 12 12 12 17 fill;
|
||||
border-image-width: 12px 12px 12px 17px;
|
||||
border-image-repeat: repeat;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.bubble-inner {
|
||||
display: grid;
|
||||
grid-template-columns: [size-info] 1fr [percent-info] auto;
|
||||
|
||||
@media (min-width: 600px) {
|
||||
position: relative;
|
||||
--main-padding: 1px;
|
||||
--speech-padding: 2.1rem;
|
||||
padding: var(--main-padding) var(--main-padding) var(--main-padding)
|
||||
var(--speech-padding);
|
||||
gap: 0.9rem;
|
||||
}
|
||||
}
|
||||
|
||||
.unit {
|
||||
color: var(--main-theme-color);
|
||||
}
|
||||
|
||||
.type-label {
|
||||
@media (min-width: 600px) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.size-info {
|
||||
background: var(--dark-gray);
|
||||
border-radius: 19px;
|
||||
align-self: center;
|
||||
justify-self: start;
|
||||
grid-column: size-info;
|
||||
grid-row: 1;
|
||||
grid-column: text;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 10px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
}
|
||||
justify-self: start;
|
||||
padding: 0.6rem 1.2rem;
|
||||
margin: 0.4rem 0;
|
||||
|
||||
.download-right {
|
||||
grid-template-columns: [copy-button] auto [text] 1fr [download-button] auto;
|
||||
}
|
||||
|
||||
.download-left {
|
||||
grid-template-columns: [download-button] auto [text] 1fr [copy-button] auto;
|
||||
}
|
||||
|
||||
.stack-right {
|
||||
& .result-data {
|
||||
padding: 0 15px;
|
||||
@media (min-width: 600px) {
|
||||
border-radius: none;
|
||||
background: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.result-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-right: 0.4em;
|
||||
.percent-info {
|
||||
align-self: center;
|
||||
margin-left: 1rem;
|
||||
margin-right: 0.3rem;
|
||||
|
||||
@media (min-width: 600px) {
|
||||
margin: 0;
|
||||
display: grid;
|
||||
--arrow-width: 16px;
|
||||
grid-template-columns: [arrow] var(--arrow-width) [data] auto;
|
||||
grid-column: percent-info;
|
||||
grid-row: 1;
|
||||
--shadow-direction: -1px;
|
||||
filter: drop-shadow(var(--shadow-direction) 0 0 rgba(0, 0, 0, 0.67));
|
||||
}
|
||||
}
|
||||
|
||||
.size-delta {
|
||||
font-size: 0.8em;
|
||||
font-style: italic;
|
||||
.big-arrow {
|
||||
display: none;
|
||||
|
||||
@media (min-width: 600px) {
|
||||
display: block;
|
||||
width: 100%;
|
||||
fill: var(--main-theme-color);
|
||||
grid-column: arrow;
|
||||
grid-row: 1;
|
||||
align-self: stretch;
|
||||
}
|
||||
}
|
||||
|
||||
.percent-output {
|
||||
grid-column: data;
|
||||
grid-row: 1;
|
||||
display: grid;
|
||||
grid-template-columns: auto auto auto;
|
||||
line-height: 1;
|
||||
|
||||
@media (min-width: 600px) {
|
||||
background: var(--main-theme-color);
|
||||
--radius: 4px;
|
||||
border-radius: 0 var(--radius) var(--radius) 0;
|
||||
--padding-arrow-side: 0.6rem;
|
||||
--padding-other-side: 1.1rem;
|
||||
padding: 0.7rem var(--padding-other-side);
|
||||
padding-left: var(--padding-arrow-side);
|
||||
}
|
||||
}
|
||||
|
||||
.size-direction {
|
||||
font-weight: 700;
|
||||
align-self: center;
|
||||
font-family: sans-serif;
|
||||
opacity: 0.76;
|
||||
text-shadow: 0 2px rgba(0, 0, 0, 0.3);
|
||||
font-size: 1.5rem;
|
||||
position: relative;
|
||||
top: -1px;
|
||||
margin-left: 0.3em;
|
||||
top: 3px;
|
||||
}
|
||||
|
||||
.size-increase {
|
||||
color: #e35050;
|
||||
.size-value {
|
||||
font-family: 'Roboto Mono Numbers';
|
||||
font-size: 2.6rem;
|
||||
text-shadow: 0 2px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.size-decrease {
|
||||
color: #50e3c2;
|
||||
.percent-char {
|
||||
align-self: start;
|
||||
position: relative;
|
||||
top: 4px;
|
||||
opacity: 0.76;
|
||||
margin-left: 0.2rem;
|
||||
}
|
||||
|
||||
.download {
|
||||
--size: 59px;
|
||||
width: calc(var(--size) + var(--download-overflow-size));
|
||||
height: calc(var(--size) + var(--download-overflow-size));
|
||||
position: relative;
|
||||
grid-row: 1;
|
||||
grid-column: download-button;
|
||||
background: #34b9eb;
|
||||
--size: 38px;
|
||||
width: var(--size);
|
||||
height: var(--size);
|
||||
grid-column: download;
|
||||
margin: calc(var(--download-overflow-size) / -2) 0;
|
||||
margin-right: calc(var(--download-overflow-size) / -3);
|
||||
display: grid;
|
||||
align-items: center;
|
||||
justify-items: center;
|
||||
align-self: center;
|
||||
|
||||
@media (min-width: 600px) {
|
||||
--size: 63px;
|
||||
}
|
||||
|
||||
loading-spinner {
|
||||
grid-area: 1 / 1;
|
||||
position: relative;
|
||||
--color: var(--white);
|
||||
--size: 21px;
|
||||
top: 0px;
|
||||
left: 1px;
|
||||
|
||||
@media (min-width: 600px) {
|
||||
top: -1px;
|
||||
left: 2px;
|
||||
--size: 28px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.download-link {
|
||||
animation: action-enter 0.2s;
|
||||
grid-area: 1/1;
|
||||
.download-blobs {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
path {
|
||||
fill: var(--hot-theme-color);
|
||||
opacity: 0.7;
|
||||
}
|
||||
}
|
||||
|
||||
.download-link-disable {
|
||||
pointer-events: none;
|
||||
opacity: 0;
|
||||
transform: rotate(90deg);
|
||||
animation: action-leave 0.2s;
|
||||
.download-icon {
|
||||
grid-area: 1 / 1;
|
||||
|
||||
svg {
|
||||
--size: 19px;
|
||||
width: var(--size);
|
||||
height: var(--size);
|
||||
fill: var(--white);
|
||||
position: relative;
|
||||
top: 3px;
|
||||
left: 1px;
|
||||
animation: action-enter 0.2s;
|
||||
|
||||
@media (min-width: 600px) {
|
||||
--size: 27px;
|
||||
top: 2px;
|
||||
left: 2px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.download-icon,
|
||||
.copy-icon {
|
||||
color: #fff;
|
||||
display: block;
|
||||
--size: 24px;
|
||||
width: var(--size);
|
||||
height: var(--size);
|
||||
padding: 7px;
|
||||
filter: drop-shadow(0 1px 0 rgba(0, 0, 0, 0.7));
|
||||
}
|
||||
|
||||
.spinner {
|
||||
--color: #fff;
|
||||
--delay: 0;
|
||||
--size: 22px;
|
||||
grid-area: 1/1;
|
||||
}
|
||||
|
||||
.copy-to-other {
|
||||
grid-row: 1;
|
||||
grid-column: copy-button;
|
||||
composes: unbutton from global;
|
||||
.download-disable {
|
||||
composes: download;
|
||||
|
||||
background: #656565;
|
||||
pointer-events: none;
|
||||
|
||||
.download-icon svg {
|
||||
opacity: 0;
|
||||
transform: rotate(90deg);
|
||||
animation: action-leave 0.2s;
|
||||
}
|
||||
}
|
||||
|
||||
.results-left {
|
||||
composes: results;
|
||||
}
|
||||
|
||||
.results-right {
|
||||
composes: results;
|
||||
|
||||
@media (min-width: 600px) {
|
||||
grid-template-columns: [bubble] 1fr [download] auto;
|
||||
}
|
||||
|
||||
.bubble {
|
||||
@media (min-width: 600px) {
|
||||
justify-self: end;
|
||||
|
||||
&::before {
|
||||
transform: scaleX(-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.download {
|
||||
margin-left: calc(var(--download-overflow-size) / -3);
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.bubble-inner {
|
||||
@media (min-width: 600px) {
|
||||
padding: var(--main-padding) var(--speech-padding) var(--main-padding)
|
||||
var(--main-padding);
|
||||
grid-template-columns: [percent-info] auto [size-info] 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
.percent-info {
|
||||
@media (min-width: 600px) {
|
||||
grid-template-columns: [data] auto [arrow] var(--arrow-width);
|
||||
--shadow-direction: 1px;
|
||||
}
|
||||
}
|
||||
|
||||
.percent-output {
|
||||
@media (min-width: 600px) {
|
||||
border-radius: var(--radius) 0 0 var(--radius);
|
||||
padding-left: var(--padding-other-side);
|
||||
padding-right: var(--padding-arrow-side);
|
||||
}
|
||||
}
|
||||
|
||||
.big-arrow {
|
||||
transform: scaleX(-1);
|
||||
}
|
||||
}
|
||||
|
||||
.is-original {
|
||||
.big-arrow {
|
||||
fill: transparent;
|
||||
}
|
||||
.percent-output {
|
||||
background: none;
|
||||
}
|
||||
.download-blobs path {
|
||||
fill: var(--black);
|
||||
}
|
||||
.unit {
|
||||
color: var(--white);
|
||||
opacity: 0.76;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user