Design review fixes (#172)

* Design review fixes

* Adding styles for mozjpeg & fixing some merge errors
This commit is contained in:
Jason Miller
2018-10-02 15:53:21 +02:00
committed by Jake Archibald
parent b25d1eaf86
commit 37f5c0dd76
7 changed files with 151 additions and 74 deletions

View File

@@ -1,6 +1,7 @@
import { h, Component } from 'preact'; import { h, Component } from 'preact';
import { bind, inputFieldChecked, inputFieldValueAsNumber } from '../../lib/util'; import { bind, inputFieldChecked, inputFieldValueAsNumber } from '../../lib/util';
import { EncodeOptions, MozJpegColorSpace } from './encoder'; import { EncodeOptions, MozJpegColorSpace } from './encoder';
import '../../components/output/custom-els/RangeInput';
type Props = { type Props = {
options: EncodeOptions, options: EncodeOptions,
@@ -40,9 +41,8 @@ export default class MozJPEGEncoderOptions extends Component<Props, {}> {
<form> <form>
<label> <label>
Quality: Quality:
<input <range-input
name="quality" name="quality"
type="range"
min="0" min="0"
max="100" max="100"
value={'' + options.quality} value={'' + options.quality}
@@ -56,7 +56,7 @@ export default class MozJPEGEncoderOptions extends Component<Props, {}> {
checked={options.baseline} checked={options.baseline}
onChange={this.onChange} onChange={this.onChange}
/> />
Baseline (worse but legacy-compatible) <span>Baseline (worse but legacy-compatible)</span>
</label> </label>
<label style={{ display: options.baseline ? 'none' : '' }}> <label style={{ display: options.baseline ? 'none' : '' }}>
<input <input
@@ -65,7 +65,7 @@ export default class MozJPEGEncoderOptions extends Component<Props, {}> {
checked={options.progressive} checked={options.progressive}
onChange={this.onChange} onChange={this.onChange}
/> />
Progressive multi-pass rendering <span>Progressive multi-pass rendering</span>
</label> </label>
<label style={{ display: options.baseline ? '' : 'none' }}> <label style={{ display: options.baseline ? '' : 'none' }}>
<input <input
@@ -74,13 +74,12 @@ export default class MozJPEGEncoderOptions extends Component<Props, {}> {
checked={options.optimize_coding} checked={options.optimize_coding}
onChange={this.onChange} onChange={this.onChange}
/> />
Optimize Huffman table <span>Optimize Huffman table</span>
</label> </label>
<label> <label>
Smoothing: Smoothing:
<input <range-input
name="smoothing" name="smoothing"
type="range"
min="0" min="0"
max="100" max="100"
value={'' + options.smoothing} value={'' + options.smoothing}
@@ -124,7 +123,7 @@ export default class MozJPEGEncoderOptions extends Component<Props, {}> {
checked={options.trellis_multipass} checked={options.trellis_multipass}
onChange={this.onChange} onChange={this.onChange}
/> />
Consider multiple scans during trellis quantization <span>Consider multiple scans during trellis quantization</span>
</label> </label>
<label style={{ display: options.trellis_multipass ? '' : 'none' }}> <label style={{ display: options.trellis_multipass ? '' : 'none' }}>
<input <input
@@ -133,7 +132,7 @@ export default class MozJPEGEncoderOptions extends Component<Props, {}> {
checked={options.trellis_opt_zero} checked={options.trellis_opt_zero}
onChange={this.onChange} onChange={this.onChange}
/> />
Optimize runs of zero blocks <span>Optimize runs of zero blocks</span>
</label> </label>
<label> <label>
<input <input
@@ -142,13 +141,12 @@ export default class MozJPEGEncoderOptions extends Component<Props, {}> {
checked={options.trellis_opt_table} checked={options.trellis_opt_table}
onChange={this.onChange} onChange={this.onChange}
/> />
Optimize after trellis quantization <span>Optimize after trellis quantization</span>
</label> </label>
<label> <label>
Trellis quantization passes: Trellis quantization passes:
<input <range-input
name="trellis_loops" name="trellis_loops"
type="range"
min="1" min="1"
max="50" max="50"
value={'' + options.trellis_loops} value={'' + options.trellis_loops}

View File

@@ -2,6 +2,7 @@ import { h, Component } from 'preact';
import { bind, inputFieldCheckedAsNumber, inputFieldValueAsNumber } from '../../lib/util'; import { bind, inputFieldCheckedAsNumber, inputFieldValueAsNumber } from '../../lib/util';
import { EncodeOptions, WebPImageHint } from './encoder'; import { EncodeOptions, WebPImageHint } from './encoder';
import * as styles from './styles.scss'; import * as styles from './styles.scss';
import '../../components/output/custom-els/RangeInput';
type Props = { type Props = {
options: EncodeOptions, options: EncodeOptions,
@@ -105,7 +106,7 @@ export default class WebPEncoderOptions extends Component<Props, {}> {
value={'' + WebPImageHint.WEBP_HINT_GRAPH} value={'' + WebPImageHint.WEBP_HINT_GRAPH}
onChange={this.onChange} onChange={this.onChange}
/> />
Discrete tone image (graph, map-tile etc) <span>Discrete tone image (graph, map-tile etc)</span>
</label> </label>
</div> </div>
); );
@@ -135,6 +136,7 @@ export default class WebPEncoderOptions extends Component<Props, {}> {
onChange={this.onChange} onChange={this.onChange}
/> />
</label> </label>
<hr />
<label> <label>
<input <input
name="alpha_compression" name="alpha_compression"
@@ -164,16 +166,7 @@ export default class WebPEncoderOptions extends Component<Props, {}> {
onChange={this.onChange} onChange={this.onChange}
/> />
</label> </label>
<label> <hr />
Spacial noise shaping:
<range-input
name="sns_strength"
min="0"
max="100"
value={'' + options.sns_strength}
onChange={this.onChange}
/>
</label>
<label> <label>
<input <input
name="autofilter" name="autofilter"
@@ -181,7 +174,7 @@ export default class WebPEncoderOptions extends Component<Props, {}> {
checked={!!options.autofilter} checked={!!options.autofilter}
onChange={this.onChange} onChange={this.onChange}
/> />
Auto adjust filter strength <span>Auto adjust filter strength</span>
</label> </label>
<label> <label>
Filter strength: Filter strength:
@@ -222,6 +215,7 @@ export default class WebPEncoderOptions extends Component<Props, {}> {
/> />
Sharp RGB->YUV conversion Sharp RGB->YUV conversion
</label> </label>
<hr />
<label> <label>
Passes: Passes:
<range-input <range-input
@@ -232,6 +226,16 @@ export default class WebPEncoderOptions extends Component<Props, {}> {
onChange={this.onChange} onChange={this.onChange}
/> />
</label> </label>
<label>
Spacial noise shaping:
<range-input
name="sns_strength"
min="0"
max="100"
value={'' + options.sns_strength}
onChange={this.onChange}
/>
</label>
<label> <label>
Preprocessing type: Preprocessing type:
<select <select
@@ -295,7 +299,9 @@ export default class WebPEncoderOptions extends Component<Props, {}> {
checked={!!options.exact} checked={!!options.exact}
onChange={this.onChange} onChange={this.onChange}
/> />
Preserve transparent data. Otherwise, pixels with zero alpha will have RGB also zeroed. <span>
Preserve transparent data. Otherwise, pixels with zero alpha will have RGB also zeroed.
</span>
</label> </label>
</form> </form>
); );

View File

@@ -25,13 +25,13 @@ import * as browserJP2 from '../../codecs/browser-jp2/encoder';
import * as browserBMP from '../../codecs/browser-bmp/encoder'; import * as browserBMP from '../../codecs/browser-bmp/encoder';
import * as browserPDF from '../../codecs/browser-pdf/encoder'; import * as browserPDF from '../../codecs/browser-pdf/encoder';
import { import {
EncoderState, EncoderState,
EncoderType, EncoderType,
EncoderOptions, EncoderOptions,
encoders, encoders,
encodersSupported, encodersSupported,
EncoderSupportMap, EncoderSupportMap,
encoderMap, encoderMap,
} from '../../codecs/encoders'; } from '../../codecs/encoders';
import { QuantizeOptions } from '../../codecs/imagequant/quantizer'; import { QuantizeOptions } from '../../codecs/imagequant/quantizer';
import { ResizeOptions } from '../../codecs/resize/resize'; import { ResizeOptions } from '../../codecs/resize/resize';
@@ -150,20 +150,9 @@ export default class Options extends Component<Props, State> {
{titles[orientation][imageIndex]} {titles[orientation][imageIndex]}
{', '} {', '}
{encoderMap[encoderState.type].label} {encoderMap[encoderState.type].label}
{(downloadUrl && imageFile) && (
<a
class={style.download}
href={downloadUrl}
download={imageFile.name}
title="Download"
>
<DownloadIcon />
</a>
)}
</h2> </h2>
<div class={style.inner}> <div class={style.content}>
<section class={style.picker}> <section class={style.picker}>
{encoderSupportMap ? {encoderSupportMap ?
<select value={encoderState.type} onChange={this.onEncoderTypeChange}> <select value={encoderState.type} onChange={this.onEncoderTypeChange}>
@@ -236,6 +225,17 @@ export default class Options extends Component<Props, State> {
file={imageFile} file={imageFile}
compareTo={imageFile === sourceImageFile ? undefined : sourceImageFile} compareTo={imageFile === sourceImageFile ? undefined : sourceImageFile}
/> />
{(downloadUrl && imageFile) && (
<a
class={style.download}
href={downloadUrl}
download={imageFile.name}
title="Download"
>
<DownloadIcon />
</a>
)}
</div> </div>
</div> </div>
); );

View File

@@ -49,24 +49,82 @@ Note: These styles are temporary. They will be replaced before going live.
} }
} }
.content {
max-height: calc(75vh - 100px);
overflow: auto;
touch-action: pan-y;
-webkit-overflow-scrolling: touch;
}
.picker {
margin: 5px 15px;
select {
display: block;
width: 100%;
box-sizing: border-box;
-webkit-appearance: none;
appearance: none;
padding: 10px 30px 10px 10px;
background: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="25" height="5"><polygon fill="#fff" points="10,0 5,5 0,0"/></svg>') right center no-repeat;
background-color: var(--gray-dark);
opacity: 0.9;
border: none;
font: inherit;
color: white;
transition: box-shadow 150ms ease;
&:hover {
opacity: 1;
}
&:focus {
opacity: 1;
outline: none;
box-shadow: 0 0 0 2px var(--button-fg, #ccc);
}
}
}
.title {
display: flex;
align-items: center;
padding: 10px 15px;
margin: 0 0 12px;
background: rgba(0,0,0,0.9);
font: inherit;
}
label { label {
display: block; display: block;
@extend .row; padding: 5px;
margin: 0 10px;
display: flex;
flex-wrap: wrap;
input { // prevent labels from wrapping below checkboxes
vertical-align: middle; > span {
flex: 1;
} }
input[type=checkbox], input[type=checkbox],
input[type=radio] { input[type=radio] {
margin-right: 8px; flex: 0;
margin: 2px 8px 0 0;
} }
range-input { range-input {
display: block; display: block;
width: 90%; flex: 1 0 100%;
margin: 2px 0;
} }
} }
hr {
height: 1px;
border: none;
margin: 5px 0;
box-shadow: inset 0 0.5px 0 rgba(0, 0, 0, 0.4), inset 0 -0.5px 0 rgba(255, 255, 255, 0.2);
}
} }
.picker { .picker {
@@ -85,31 +143,27 @@ Note: These styles are temporary. They will be replaced before going live.
border: none; border: none;
font: inherit; font: inherit;
color: white; color: white;
}
&:hover { hr {
opacity: 1; height: 1px;
} border: none;
&:focus { margin: 5px 0;
opacity: 1; box-shadow: inset 0 0.5px 0 rgba(0, 0, 0, 0.4), inset 0 -0.5px 0 rgba(255, 255, 255, 0.2);
outline: none;
box-shadow: 0 0 0 2px var(--button-fg, #ccc);
}
} }
} }
.title { .size-details {
display: flex; display: flex;
align-items: center; align-items: center;
padding: 10px 15px; padding: 5px 15px;
margin: 0 0 12px; background: rgba(0,0,0,0.5);
background: rgba(0,0,0,0.9);
font: inherit;
} }
.download { .download {
flex: 0; flex: 0;
margin: 0 0 0 auto; margin: 0 0 0 auto;
background: rgba(0,0,0,0.7); background: rgba(255,255,255,0.1);
border-radius: 50%; border-radius: 50%;
padding: 5px; padding: 5px;
width: 16px; width: 16px;
@@ -159,7 +213,7 @@ Note: These styles are temporary. They will be replaced before going live.
.preprocessors { .preprocessors {
padding: 5px 0; padding: 5px 0;
margin: 5px 0; margin: 5px 0;
box-shadow: inset 0 -.5px 0 rgba(0,0,0,0.25), 0 .5px 0 rgba(255,255,255,0.15); box-shadow: inset 0 -.5px 0 rgba(0,0,0,0.4), 0 .5px 0 rgba(255,255,255,0.2);
} }
.toggle { .toggle {
@@ -167,4 +221,5 @@ Note: These styles are temporary. They will be replaced before going live.
position: relative; position: relative;
align-content: center; align-content: center;
font-size: 14px; font-size: 14px;
box-shadow: inset 0 -.5px 0 rgba(0,0,0,0.4), 0 .5px 0 rgba(255,255,255,0.2);
} }

View File

@@ -73,8 +73,9 @@ class RangeInputElement extends HTMLElement {
const displayValue = labelPrecision ? value.toPrecision(labelPrecision) : const displayValue = labelPrecision ? value.toPrecision(labelPrecision) :
Math.round(value).toString(); Math.round(value).toString();
this.style.setProperty('--value-percent', percent + '%');
this._valueDisplay.textContent = displayValue; this._valueDisplay.textContent = displayValue;
this.style.setProperty('--value-percent', percent + '%');
this.style.setProperty('--value-width', '' + displayValue.length);
} }
private _reflectAttributes() { private _reflectAttributes() {

View File

@@ -1,5 +1,9 @@
declare namespace JSX { declare namespace JSX {
interface RangeInputAttributes extends HTMLAttributes {
reversed?: boolean;
}
interface IntrinsicElements { interface IntrinsicElements {
'range-input': HTMLAttributes; 'range-input': RangeInputAttributes;
} }
} }

View File

@@ -9,9 +9,29 @@ range-input {
overflow: visible; overflow: visible;
} }
/* Disabled inputs are greyed out */
range-input[disabled] {
filter: grayscale(1);
}
/* Reversed Variant */
range-input[reversed] input,
range-input[reversed]::before,
range-input[reversed] > div {
transform: scaleX(-1);
}
range-input[reversed] > div > span {
transform: scaleX(-1) scale(.2);
}
range-input[reversed] input:focus + div span {
transform: scaleX(-1) scale(1);
}
range-input input { range-input input {
position: relative; position: relative;
flex: 1; flex: 1;
vertical-align: middle;
width: 100%; width: 100%;
padding: 0 !important; padding: 0 !important;
margin: 0 !important; margin: 0 !important;
@@ -20,7 +40,6 @@ range-input input {
-webkit-appearance: none; -webkit-appearance: none;
outline: none; outline: none;
} }
range-input input::-webkit-slider-runnable-track, range-input input::-webkit-slider-runnable-track,
range-input input::-moz-range-track, range-input input::-moz-range-track,
range-input input::-ms-track { range-input input::-ms-track {
@@ -45,9 +64,6 @@ range-input::before {
box-shadow: 0 -.5px 0 rgba(0,0,0,0.3), inset 0 .5px 0 rgba(255,255,255,0.2), 0 .5px 0 rgba(255,255,255,0.3); box-shadow: 0 -.5px 0 rgba(0,0,0,0.3), inset 0 .5px 0 rgba(255,255,255,0.2), 0 .5px 0 rgba(255,255,255,0.3);
background: linear-gradient(#34B9EB, #218ab1) 0/ var(--value-percent, 0%) 100% no-repeat #eee; background: linear-gradient(#34B9EB, #218ab1) 0/ var(--value-percent, 0%) 100% no-repeat #eee;
} }
range-input[disabled]::before {
background: linear-gradient(#aaa, #888) 0/ var(--value-percent, 0%) 100% no-repeat #eee;
}
range-input input::-webkit-slider-thumb { range-input input::-webkit-slider-thumb {
appearance: none; appearance: none;
@@ -62,10 +78,6 @@ range-input input::-webkit-slider-thumb {
outline: none; outline: none;
} }
range-input[disabled] input::-webkit-slider-thumb {
background: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="10" height="10"><circle cx="5" cy="5" r="1" fill="#666" /></svg>') center no-repeat #999;
}
range-input input:focus::-webkit-slider-thumb { range-input input:focus::-webkit-slider-thumb {
box-shadow: 0 1px 3px rgba(0,0,0,0.5); box-shadow: 0 1px 3px rgba(0,0,0,0.5);
} }
@@ -96,6 +108,7 @@ range-input > div > span {
transform: scale(.2); transform: scale(.2);
color: #fff; color: #fff;
font: inherit; font: inherit;
font-size: calc(100% - var(--value-width, 3) / 5 * .2em);
text-overflow: clip; text-overflow: clip;
text-shadow: 0 -.5px 0 rgba(0,0,0,0.4); text-shadow: 0 -.5px 0 rgba(0,0,0,0.4);
transition: transform 200ms ease, opacity 200ms ease; transition: transform 200ms ease, opacity 200ms ease;