Compare commits

...

3 Commits

Author SHA1 Message Date
7e91f4e5c5 Whoops 2018-11-06 13:38:32 +00:00
854d20af12 Download button on the outside. 2018-11-06 13:38:32 +00:00
97778c5ba6 Copy settings to other side button 2018-11-06 13:38:31 +00:00
6 changed files with 110 additions and 47 deletions

View File

@ -59,13 +59,11 @@ const encoderOptionsComponentMap = {
interface Props {
mobileView: boolean;
source?: SourceImage;
imageIndex: number;
encoderState: EncoderState;
preprocessorState: PreprocessorState;
onEncoderTypeChange(newType: EncoderType): void;
onEncoderOptionsChange(newOptions: EncoderOptions): void;
onPreprocessorOptionsChange(newOptions: PreprocessorState): void;
onCopyToOtherClick(): void;
}
interface State {
@ -116,16 +114,9 @@ export default class Options extends Component<Props, State> {
);
}
@bind
onCopyToOtherClick(event: Event) {
event.preventDefault();
this.props.onCopyToOtherClick();
}
render(
{
source,
imageIndex,
encoderState,
preprocessorState,
onEncoderOptionsChange,
@ -205,14 +196,6 @@ export default class Options extends Component<Props, State> {
/>
: null}
</Expander>
<div class={style.optionsCopy}>
<button onClick={this.onCopyToOtherClick} class={style.copyButton}>
{imageIndex === 1 && '← '}
Copy settings across
{imageIndex === 0 && ' →'}
</button>
</div>
</div>
);
}

View File

@ -55,18 +55,3 @@ $horizontalPadding: 15px;
overflow-x: hidden;
overflow-y: auto;
}
.options-copy {
display: grid;
background: rgba(0, 0, 0, 0.9);
padding: 5px;
}
.copy-button {
composes: unbutton from '../../lib/util.scss';
background: #484848;
border-radius: 4px;
color: #fff;
text-align: left;
padding: 5px 10px;
}

View File

@ -34,7 +34,7 @@ import Processor from '../../codecs/processor';
import { VectorResizeOptions, BitmapResizeOptions } from '../../codecs/resize/processor-meta';
import './custom-els/MultiPanel';
import Results from '../results';
import { ExpandIcon } from '../../lib/icons';
import { ExpandIcon, CopyAcrossIconProps } from '../../lib/icons';
export interface SourceImage {
file: File | Fileish;
@ -136,7 +136,7 @@ async function processSvg(blob: Blob): Promise<HTMLImageElement> {
const parser = new DOMParser();
const text = await blobToText(blob);
const document = parser.parseFromString(text, 'image/svg+xml');
const svg = document.documentElement;
const svg = document.documentElement!;
if (svg.hasAttribute('width') && svg.hasAttribute('height')) {
return blobToImg(blob);
@ -156,6 +156,9 @@ async function processSvg(blob: Blob): Promise<HTMLImageElement> {
// These are only used in the mobile view
const resultTitles = ['Top', 'Bottom'];
// These are only used in the desktop view
const buttonPositions =
['download-left', 'download-right'] as ('download-left' | 'download-right')[];
export default class Compress extends Component<Props, State> {
widthQuery = window.matchMedia('(max-width: 599px)');
@ -405,26 +408,30 @@ export default class Compress extends Component<Props, State> {
<Options
source={source}
mobileView={mobileView}
imageIndex={index}
preprocessorState={image.preprocessorState}
encoderState={image.encoderState}
onEncoderTypeChange={this.onEncoderTypeChange.bind(this, index)}
onEncoderOptionsChange={this.onEncoderOptionsChange.bind(this, index)}
onPreprocessorOptionsChange={this.onPreprocessorOptionsChange.bind(this, index)}
onCopyToOtherClick={this.onCopyToOtherClick.bind(this, index)}
/>
));
const results = images.map((image, i) => (
const copyDirections =
(mobileView ? ['down', 'up'] : ['right', 'left']) as CopyAcrossIconProps['copyDirection'][];
const results = images.map((image, index) => (
<Results
downloadUrl={image.downloadUrl}
imageFile={image.file}
source={source}
loading={loading || image.loading}
copyDirection={copyDirections[index]}
onCopyToOtherClick={this.onCopyToOtherClick.bind(this, index)}
buttonPosition={mobileView ? 'stack-right' : buttonPositions[index]}
>
{!mobileView ? null : [
<ExpandIcon class={style.expandIcon} key="expand-icon"/>,
`${resultTitles[i]} (${encoderMap[image.encoderState.type].label})`,
`${resultTitles[index]} (${encoderMap[image.encoderState.type].label})`,
]}
</Results>
));

View File

@ -2,10 +2,10 @@ import { h, Component, ComponentChildren, ComponentChild } from 'preact';
import * as style from './style.scss';
import FileSize from './FileSize';
import { DownloadIcon } from '../../lib/icons';
import { DownloadIcon, CopyAcrossIcon, CopyAcrossIconProps } from '../../lib/icons';
import '../custom-els/LoadingSpinner';
import { SourceImage } from '../compress';
import { Fileish } from '../../lib/initial-util';
import { Fileish, bind } from '../../lib/initial-util';
interface Props {
loading: boolean;
@ -13,12 +13,21 @@ interface Props {
imageFile?: Fileish;
downloadUrl?: string;
children: ComponentChildren;
copyDirection: CopyAcrossIconProps['copyDirection'];
buttonPosition: keyof typeof buttonPositionClass;
onCopyToOtherClick(): void;
}
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> {
@ -43,9 +52,19 @@ export default class Results extends Component<Props, State> {
}
}
render({ source, imageFile, downloadUrl, children }: Props, { showLoadingState }: State) {
@bind
private onCopyToOtherClick(event: Event) {
event.preventDefault();
this.props.onCopyToOtherClick();
}
render(
{ source, imageFile, downloadUrl, children, copyDirection, buttonPosition }: Props,
{ showLoadingState }: State,
) {
return (
<div class={style.results}>
<div class={`${style.results} ${buttonPositionClass[buttonPosition]}`}>
<div class={style.resultData}>
{(children as ComponentChild[])[0]
? <div class={style.resultTitle}>{children}</div>
@ -59,6 +78,14 @@ export default class Results extends Component<Props, State> {
}
</div>
<button
class={style.copyToOther}
title="Copy settings to other side"
onClick={this.onCopyToOtherClick}
>
<CopyAcrossIcon class={style.copyIcon} copyDirection={copyDirection} />
</button>
<div class={style.download}>
{(downloadUrl && imageFile) && (
<a

View File

@ -16,9 +16,17 @@
.results {
display: grid;
grid-template-columns: 1fr auto;
grid-template-columns: [text] 1fr [copy-button] auto [download-button] auto;
background: rgba(0, 0, 0, 0.9);
font-size: 1.4rem;
font-size: 1rem;
@media (min-width: 400px) {
font-size: 1.2rem;
}
@media (min-width: 600px) {
font-size: 1.4rem;
}
&:focus {
outline: none;
@ -26,13 +34,29 @@
}
.result-data {
grid-row: 1;
grid-column: text;
display: flex;
align-items: center;
padding: 0 15px;
padding: 0 10px;
white-space: nowrap;
overflow: hidden;
}
.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;
}
}
.result-title {
display: flex;
align-items: center;
@ -40,7 +64,7 @@
}
.size-delta {
font-size: 1.1rem;
font-size: 0.8em;
font-style: italic;
position: relative;
top: -1px;
@ -56,6 +80,8 @@
}
.download {
grid-row: 1;
grid-column: download-button;
background: #34B9EB;
--size: 38px;
width: var(--size);
@ -77,7 +103,8 @@
animation: action-leave 0.2s;
}
.download-icon {
.download-icon,
.copy-icon {
color: #fff;
display: block;
--size: 24px;
@ -93,3 +120,12 @@
--size: 22px;
grid-area: 1/1;
}
.copy-to-other {
grid-row: 1;
grid-column: copy-button;
composes: unbutton from '../../lib/util.scss';
composes: download;
background: #656565;
}

View File

@ -47,3 +47,28 @@ export const ExpandIcon = (props: JSX.HTMLAttributes) => (
<path d="M16.6 8.6L12 13.2 7.4 8.6 6 10l6 6 6-6z"/>
</Icon>
);
const copyAcrossRotations = {
up: 90, right: 180, down: -90, left: 0,
};
export interface CopyAcrossIconProps extends JSX.HTMLAttributes {
copyDirection: keyof typeof copyAcrossRotations;
}
export const CopyAcrossIcon = (props: CopyAcrossIconProps) => {
const { copyDirection, ...otherProps } = props;
const id = 'point-' + copyDirection;
const rotation = copyAcrossRotations[copyDirection];
return (
<Icon {...otherProps}>
<defs>
<clipPath id={id}>
<path d="M-12-12v24h24v-24zM4.5 2h-4v3l-5-5 5-5v3h4z" transform={`translate(12 13) rotate(${rotation})`}/>
</clipPath>
</defs>
<path clip-path={`url(#${id})`} d="M19 3h-4.2c-.4-1.2-1.5-2-2.8-2s-2.4.8-2.8 2H5a2 2 0 0 0-2 2v14c0 1.1.9 2 2 2h14a2 2 0 0 0 2-2V5a2 2 0 0 0-2-2zm-7 0a1 1 0 0 1 0 2c-.6 0-1-.4-1-1s.4-1 1-1z"/>
</Icon>
);
};