diff --git a/src/components/Options/index.tsx b/src/components/Options/index.tsx index 589b26b5..21dcb260 100644 --- a/src/components/Options/index.tsx +++ b/src/components/Options/index.tsx @@ -1,7 +1,7 @@ import { h, Component } from 'preact'; import * as style from './style.scss'; -import { bind, Fileish } from '../../lib/initial-util'; +import { bind } from '../../lib/initial-util'; import { cleanSet, cleanMerge } from '../../lib/clean-modify'; import OptiPNGEncoderOptions from '../../codecs/optipng/options'; import MozJpegEncoderOptions from '../../codecs/mozjpeg/options'; @@ -35,13 +35,10 @@ import { import { QuantizeOptions } from '../../codecs/imagequant/processor-meta'; import { ResizeOptions } from '../../codecs/resize/processor-meta'; import { PreprocessorState } from '../../codecs/preprocessors'; -import FileSize from './FileSize'; -import { DownloadIcon } from '../../lib/icons'; import { SourceImage } from '../App'; import Checkbox from '../checkbox'; import Expander from '../expander'; import Select from '../select'; -import '../custom-els/LoadingSpinner'; const encoderOptionsComponentMap = { [identity.type]: undefined, @@ -61,11 +58,8 @@ const encoderOptionsComponentMap = { interface Props { mobileView: boolean; - loading: boolean; source?: SourceImage; imageIndex: number; - imageFile?: Fileish; - downloadUrl?: string; encoderState: EncoderState; preprocessorState: PreprocessorState; onEncoderTypeChange(newType: EncoderType): void; @@ -76,39 +70,18 @@ interface Props { interface State { encoderSupportMap?: EncoderSupportMap; - showLoadingState: boolean; } -const loadingReactionDelay = 500; - export default class Options extends Component { state: State = { encoderSupportMap: undefined, - showLoadingState: false, }; - /** The timeout ID between entering the loading state, and changing UI */ - private loadingTimeoutId: number = 0; - constructor() { super(); encodersSupported.then(encoderSupportMap => this.setState({ encoderSupportMap })); } - componentDidUpdate(prevProps: Props, prevState: State) { - if (prevProps.loading && !this.props.loading) { - // Just stopped loading - clearTimeout(this.loadingTimeoutId); - this.setState({ showLoadingState: false }); - } else if (!prevProps.loading && this.props.loading) { - // Just started loading - this.loadingTimeoutId = self.setTimeout( - () => this.setState({ showLoadingState: true }), - loadingReactionDelay, - ); - } - } - @bind onEncoderTypeChange(event: Event) { const el = event.currentTarget as HTMLSelectElement; @@ -153,19 +126,17 @@ export default class Options extends Component { { source, imageIndex, - imageFile, - downloadUrl, encoderState, preprocessorState, onEncoderOptionsChange, }: Props, - { encoderSupportMap, showLoadingState }: State, + { encoderSupportMap }: State, ) { // tslint:disable variable-name const EncoderOptionComponent = encoderOptionsComponentMap[encoderState.type]; return ( -
+
{encoderState.type === identity.type ? null :
@@ -244,33 +215,6 @@ export default class Options extends Component { {imageIndex === 0 && ' →'}
- -
-
- {!imageFile || showLoadingState ? 'Working…' : - - } -
- -
- {(downloadUrl && imageFile) && ( - - - - )} - {showLoadingState && } -
- -
-
); } diff --git a/src/components/Options/style.scss b/src/components/Options/style.scss index 460e5916..d7f7180a 100644 --- a/src/components/Options/style.scss +++ b/src/components/Options/style.scss @@ -1,22 +1,5 @@ $horizontalPadding: 15px; -.options { - color: #fff; - opacity: 0.9; - font-size: 1.2rem; - max-height: 100%; - display: flex; - flex-flow: column; - max-width: 400px; - margin: 0 auto; - width: calc(100% - 60px); - - @media (min-width: 600px) { - width: 300px; - margin: 0; - } -} - .options-title { background: rgba(0, 0, 0, 0.9); margin: 0; @@ -73,35 +56,6 @@ $horizontalPadding: 15px; overflow-y: auto; } -.results { - display: grid; - grid-template-columns: 1fr auto; - background: rgba(0, 0, 0, 0.9); - font-size: 1.4rem; -} - -.result-data { - display: flex; - align-items: center; - padding: 0 $horizontalPadding; -} - -.size-delta { - font-size: 1.1rem; - font-style: italic; - position: relative; - top: -1px; - margin-left: 0.3em; -} - -.size-increase { - color: #e35050; -} - -.size-decrease { - color: #50e3c2; -} - .options-copy { display: grid; background: rgba(0, 0, 0, 0.9); @@ -116,58 +70,3 @@ $horizontalPadding: 15px; text-align: left; padding: 5px 10px; } - -@keyframes action-enter { - from { - transform: rotate(-90deg); - opacity: 0; - animation-timing-function: ease-out; - } -} - -@keyframes action-leave { - from { - transform: rotate(0deg); - opacity: 1; - animation-timing-function: ease-out; - } -} - -.download { - background: #34B9EB; - --size: 38px; - width: var(--size); - height: var(--size); - display: grid; - align-items: center; - justify-items: center; -} - -.download-link { - animation: action-enter 0.2s; - grid-area: 1/1; -} - -.download-link-disable { - pointer-events: none; - opacity: 0; - transform: rotate(90deg); - animation: action-leave 0.2s; -} - -.download-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; -} diff --git a/src/components/compress/index.tsx b/src/components/compress/index.tsx index 76ca993a..53b2e497 100644 --- a/src/components/compress/index.tsx +++ b/src/components/compress/index.tsx @@ -33,6 +33,7 @@ import { cleanMerge, cleanSet } from '../../lib/clean-modify'; import Processor from '../../codecs/processor'; import { VectorResizeOptions, BitmapResizeOptions } from '../../codecs/resize/processor-meta'; import './custom-els/MultiPanel'; +import Results from '../results'; export interface SourceImage { file: File | Fileish; @@ -398,12 +399,9 @@ export default class Compress extends Component { const options = images.map((image, index) => ( { /> )); + const results = images.map(image => ( + + )); + return (
{ /> {mobileView ? ( - -
Top
+
+ + {results[0]} + {options[0]} + {results[1]} + {options[1]} + +
+ ) : ([ +
{options[0]} -
Bottom
+ {results[0]} +
, +
{options[1]} - - ) : options + {results[1]} +
, + ]) }
); diff --git a/src/components/compress/style.scss b/src/components/compress/style.scss index 23ae1061..5a4b847b 100644 --- a/src/components/compress/style.scss +++ b/src/components/compress/style.scss @@ -17,6 +17,23 @@ } } +.options { + color: #fff; + opacity: 0.9; + font-size: 1.2rem; + max-height: 100%; + display: flex; + flex-flow: column; + max-width: 400px; + margin: 0 auto; + width: calc(100% - 60px); + + @media (min-width: 600px) { + width: 300px; + margin: 0; + } +} + .multi-panel { position: relative; } diff --git a/src/components/Options/FileSize.tsx b/src/components/results/FileSize.tsx similarity index 100% rename from src/components/Options/FileSize.tsx rename to src/components/results/FileSize.tsx diff --git a/src/components/results/index.tsx b/src/components/results/index.tsx new file mode 100644 index 00000000..c3ee0571 --- /dev/null +++ b/src/components/results/index.tsx @@ -0,0 +1,73 @@ +import { h, Component } from 'preact'; + +import * as style from './style.scss'; +import FileSize from './FileSize'; +import { DownloadIcon } from '../../lib/icons'; +import '../custom-els/LoadingSpinner'; +import { SourceImage } from '../compress'; +import { Fileish } from '../../lib/initial-util'; + +interface Props { + loading: boolean; + source?: SourceImage; + imageFile?: Fileish; + downloadUrl?: string; +} + +interface State { + showLoadingState: boolean; +} + +const loadingReactionDelay = 500; + +export default class Results extends Component { + state: State = { + showLoadingState: false, + }; + + /** The timeout ID between entering the loading state, and changing UI */ + private loadingTimeoutId: number = 0; + + componentDidUpdate(prevProps: Props, prevState: State) { + if (prevProps.loading && !this.props.loading) { + // Just stopped loading + clearTimeout(this.loadingTimeoutId); + this.setState({ showLoadingState: false }); + } else if (!prevProps.loading && this.props.loading) { + // Just started loading + this.loadingTimeoutId = self.setTimeout( + () => this.setState({ showLoadingState: true }), + loadingReactionDelay, + ); + } + } + + render({ source, imageFile, downloadUrl }: Props, { showLoadingState }: State) { + return ( +
+
+ {!imageFile || showLoadingState ? 'Working…' : + + } +
+ +
+ {(downloadUrl && imageFile) && ( + + + + )} + {showLoadingState && } +
+
+ ); + } +} diff --git a/src/components/results/style.scss b/src/components/results/style.scss new file mode 100644 index 00000000..dcf82a22 --- /dev/null +++ b/src/components/results/style.scss @@ -0,0 +1,83 @@ +@keyframes action-enter { + from { + transform: rotate(-90deg); + opacity: 0; + animation-timing-function: ease-out; + } +} + +@keyframes action-leave { + from { + transform: rotate(0deg); + opacity: 1; + animation-timing-function: ease-out; + } +} + +.results { + display: grid; + grid-template-columns: 1fr auto; + background: rgba(0, 0, 0, 0.9); + font-size: 1.4rem; +} + +.result-data { + display: flex; + align-items: center; + padding: 0 15px; +} + +.size-delta { + font-size: 1.1rem; + font-style: italic; + position: relative; + top: -1px; + margin-left: 0.3em; +} + +.size-increase { + color: #e35050; +} + +.size-decrease { + color: #50e3c2; +} + +.download { + background: #34B9EB; + --size: 38px; + width: var(--size); + height: var(--size); + display: grid; + align-items: center; + justify-items: center; +} + +.download-link { + animation: action-enter 0.2s; + grid-area: 1/1; +} + +.download-link-disable { + pointer-events: none; + opacity: 0; + transform: rotate(90deg); + animation: action-leave 0.2s; +} + +.download-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; +}