Initial Options Flyout

This commit is contained in:
Jason Miller
2020-12-09 18:11:44 -05:00
parent 646747b039
commit 7de8fa9da3
7 changed files with 146 additions and 30 deletions

View File

@@ -1,6 +1,8 @@
.wrap {
display: inline;
position: relative;
display: flex;
align-items: center;
justify-items: center;
}
.wrap > aside:last-of-type {

View File

@@ -5,7 +5,6 @@ import 'add-css:./style.css';
import { cleanSet, cleanMerge } from '../../util/clean-modify';
import type { SourceImage, OutputType } from '..';
import type SnackBarElement from 'shared/initial-app/custom-els/snack-bar';
import {
EncoderOptions,
EncoderState,
@@ -14,17 +13,15 @@ import {
encoderMap,
} from '../../feature-meta';
import Expander from './Expander';
import Checkbox from './Checkbox';
import Toggle from './Toggle';
import Select from './Select';
import Flyout from '../Flyout';
import { Options as QuantOptionsComponent } from 'features/processors/quantize/client';
import { Options as ResizeOptionsComponent } from 'features/processors/resize/client';
import { generateCliInvocation } from '../../util/cli-invocation-generator';
import { CLIIcon, MoreIcon, SwapIcon } from 'client/lazy-app/icons';
interface Props {
index: 0 | 1;
showSnack: SnackBarElement['showSnackbar'];
mobileView: boolean;
source?: SourceImage;
encoderState?: EncoderState;
@@ -32,6 +29,8 @@ interface Props {
onEncoderTypeChange(index: 0 | 1, newType: OutputType): void;
onEncoderOptionsChange(index: 0 | 1, newOptions: EncoderOptions): void;
onProcessorOptionsChange(index: 0 | 1, newOptions: ProcessorState): void;
onCopyToOtherSideClick(index: 0 | 1): void;
onCopyCliClick(index: 0 | 1): void;
}
interface State {
@@ -110,20 +109,12 @@ export default class Options extends Component<Props, State> {
this.props.onEncoderOptionsChange(this.props.index, newOptions);
};
private onCreateCLIInvocation = () => {
if (!this.props.encoderState) {
return;
}
private onCopyCliClick = () => {
this.props.onCopyCliClick(this.props.index);
};
try {
const cliInvocation = generateCliInvocation(
this.props.encoderState,
this.props.processorState,
);
navigator.clipboard.writeText(cliInvocation);
} catch (e) {
this.props.showSnack(e);
}
private onCopyToOtherSideClick = () => {
this.props.onCopyToOtherSideClick(this.props.index);
};
render(
@@ -146,7 +137,31 @@ export default class Options extends Component<Props, State> {
{!encoderState ? null : (
<div>
<h3 class={style.optionsTitle}>
<button onClick={this.onCreateCLIInvocation}>CLI</button>Edit
Edit
<Flyout
direction={['up', 'left']}
anchor="right"
toggle={
<button class={style.titleButton}>
<MoreIcon />
</button>
}
>
<button
class={style.menuButton}
onClick={this.onCopyCliClick}
>
<CLIIcon />
Copy npx command
</button>
<button
class={style.menuButton}
onClick={this.onCopyToOtherSideClick}
>
<SwapIcon />
Copy settings to other side
</button>
</Flyout>
</h3>
<label class={style.sectionEnabler}>
Resize

View File

@@ -14,13 +14,21 @@
background-color: var(--main-theme-color);
color: var(--header-text-color);
margin: 0;
padding: 10px var(--horizontal-padding);
height: 38px;
padding: 0 0 0 var(--horizontal-padding);
font-weight: bold;
font-size: 1.4rem;
border-bottom: 1px solid var(--off-black);
transition: all 300ms ease-in-out;
transition-property: background-color, color;
display: grid;
align-items: center;
grid-template-columns: 1fr;
grid-auto-columns: max-content;
grid-auto-flow: column;
gap: 0.8rem 0;
position: sticky;
top: 0;
z-index: 1;
@@ -81,3 +89,63 @@
box-sizing: border-box;
border-radius: 4px;
}
.options-title aside {
right: 10px;
bottom: calc(100% + 10px);
}
.title-button {
composes: unbutton from global;
border-radius: 50%;
background: rgba(255, 255, 255, 0);
&:hover,
&:active {
background: rgba(255, 255, 255, 0.3);
}
svg {
--size: 24px;
fill: var(--header-text-color);
display: block;
width: var(--size);
height: var(--size);
padding: 5px;
}
}
.menu-button {
display: flex;
align-items: center;
box-sizing: border-box;
margin: 8px 0;
background-color: rgba(29, 29, 29, 0.92);
border: 1px solid rgba(0, 0, 0, 0.67);
border-radius: 2rem;
line-height: 1.1;
white-space: nowrap;
height: 39px;
padding: 0 16px;
font-size: 1.2rem;
cursor: pointer;
color: #fff;
&:hover {
background: rgba(50, 50, 50, 0.92);
}
&:focus {
box-shadow: 0 0 0 2px #fff;
outline: none;
z-index: 1;
}
& > svg {
position: relative;
width: 18px;
height: 18px;
margin-right: 12px;
color: var(--main-theme-color);
}
}

View File

@@ -176,7 +176,7 @@ input.zoom {
}
}
[data-flyout-open] {
.controls [data-flyout-open] {
.moreButton {
background: rgba(82, 82, 82, 0.92);

View File

@@ -33,6 +33,7 @@ import WorkerBridge from '../worker-bridge';
import { resize } from 'features/processors/resize/client';
import type SnackBarElement from 'shared/custom-els/snack-bar';
import Transform from './Transform';
import { generateCliInvocation } from '../util/cli';
export type OutputType = EncoderType | 'identity';
@@ -411,7 +412,7 @@ export default class Compress extends Component<Props, State> {
this.queueUpdateImage();
}
private async onCopyToOtherClick(index: 0 | 1) {
private onCopyToOtherClick = async (index: 0 | 1) => {
const otherIndex = index ? 0 : 1;
const oldSettings = this.state.sides[otherIndex];
const newSettings = { ...this.state.sides[index] };
@@ -436,7 +437,7 @@ export default class Compress extends Component<Props, State> {
this.setState({
sides: cleanSet(this.state.sides, otherIndex, oldSettings),
});
}
};
private onPreprocessorChange = async (
preprocessorState: PreprocessorState,
@@ -483,6 +484,29 @@ export default class Compress extends Component<Props, State> {
}));
};
private onCopyCliClick = async (index: 0 | 1) => {
try {
const cliInvocation = generateCliInvocation(
this.state.sides[index].latestSettings.encoderState!,
this.state.sides[index].latestSettings.processorState,
);
await navigator.clipboard.writeText(cliInvocation);
const result = await this.props.showSnack(
'CLI command copied to clipboard',
{
timeout: 8000,
actions: ['usage', 'dismiss'],
},
);
if (result === 'usage') {
open('https://github.com/GoogleChromeLabs/squoosh/tree/dev/cli');
}
} catch (e) {
this.props.showSnack(e);
}
};
/**
* Debounce the heavy lifting of updateImage.
* Otherwise, the thrashing causes jank, and sometimes crashes iOS Safari.
@@ -853,7 +877,6 @@ export default class Compress extends Component<Props, State> {
const options = sides.map((side, index) => (
<Options
index={index as 0 | 1}
showSnack={showSnack}
source={source}
mobileView={mobileView}
processorState={side.latestSettings.processorState}
@@ -861,6 +884,8 @@ export default class Compress extends Component<Props, State> {
onEncoderTypeChange={this.onEncoderTypeChange}
onEncoderOptionsChange={this.onEncoderOptionsChange}
onProcessorOptionsChange={this.onProcessorOptionsChange}
onCopyCliClick={this.onCopyCliClick}
onCopyToOtherSideClick={this.onCopyToOtherClick}
/>
));

View File

@@ -1,6 +1,6 @@
import { h } from 'preact';
const Icon = (props: preact.JSX.HTMLAttributes) => (
const Icon = (props: preact.JSX.HTMLAttributes | preact.JSX.SVGAttributes) => (
// @ts-ignore - TS bug https://github.com/microsoft/TypeScript/issues/16019
<svg
width="24"
@@ -11,9 +11,15 @@ const Icon = (props: preact.JSX.HTMLAttributes) => (
/>
);
export const CLIIcon = (props: preact.JSX.HTMLAttributes) => (
<Icon {...props}>
<path d="M1 2.7H23v18.5H1zm5.5 13l3.7-3.7-3.7-3.7m5.5 7.4h5.6" />
</Icon>
);
export const SwapIcon = (props: preact.JSX.HTMLAttributes) => (
<Icon {...props}>
<path d="M9.01 14H2v2h7.01v3L13 15l-3.99-4zm5.98-1v-3H22V8h-7.01V5L11 9z" />
<path d="M8.5 8.6v6.8L5.1 12l3.4-3.4M10 5l-7 7 7 7V5zm4 0v14l7-7-7-7z" />
</Icon>
);
@@ -77,9 +83,9 @@ export const RotateIcon = (props: preact.JSX.HTMLAttributes) => (
export const MoreIcon = (props: preact.JSX.HTMLAttributes) => (
<Icon {...props}>
<circle cx="12" cy="6" r="2" fill="#fff" />
<circle cx="12" cy="12" r="2" fill="#fff" />
<circle cx="12" cy="18" r="2" fill="#fff" />
<circle cx="12" cy="6" r="2" />
<circle cx="12" cy="12" r="2" />
<circle cx="12" cy="18" r="2" />
</Icon>
);