Plumbing for wallpaper previews.

This commit is contained in:
Matt Swensen 2018-11-24 11:29:07 -07:00
parent 84961f5dad
commit cd123ab971
No known key found for this signature in database
GPG Key ID: 3F9E482BFC526F35
14 changed files with 104 additions and 20 deletions

@ -5,6 +5,7 @@ import { UrlStateProvider } from './UrlState';
import ColorState from './ColorState';
import ColorSetInputs from './ColorSetInputs';
import TextPreviews from './TextPreviews';
import WallpaperPreview from './WallpaperPreview';
export default class App extends PureComponent {
render() {
@ -35,7 +36,10 @@ export default class App extends PureComponent {
<h2 className={ styles.h2 } style={{ color: getColor('shade7')}}>1. Define colors</h2>
<ColorSetInputs />
<h2 className={ styles.h2 } style={{ color: getColor('shade7')}}>2. Preview</h2>
<TextPreviews />
<div className={ styles.previewsContainer }>
<TextPreviews />
<WallpaperPreview />
</div>
</div>
</div>
) }

@ -23,4 +23,10 @@
.h2 {
font-size: var(--size-large-1);
margin: var(--size-regular) 0;
}
}
.previewsContainer {
display: grid;
grid-template-columns: calc((100% - var(--size-large-1)) * 2 / 3) calc((100% - var(--size-large-1)) / 3);
grid-column-gap: var(--size-large-1);
}

@ -1,5 +1,5 @@
import React, { PureComponent } from 'react';
import { Check } from './Icons';
import { CheckIcon } from './Icons';
import styles from './Checkbox.module.css';
import ColorState from './ColorState';
@ -18,7 +18,7 @@ export default class Checkbox extends PureComponent {
checked={ this.props.value }
onChange={ evt => this.props.onChange(evt.target.checked) }
/>
<Check
<CheckIcon
backgroundColor={ this.props.value ? getColor('shade7') : 'transparent' }
outlineColor={ this.props.value ? 'transparent' : getColor('shade7') }
checkColor={ this.props.value ? getColor('shade0') : 'transparent' }

@ -1,6 +1,6 @@
import React, { PureComponent } from 'react';
import ColorState from './ColorState';
import { Droplet } from './Icons';
import { DropletIcon } from './Icons';
import styles from './ColorInput.module.css';
import getBestForeground from './getBestForeground';
@ -36,7 +36,7 @@ export default class ColorInput extends PureComponent {
}}
tabIndex="0"
>
<Droplet />
<DropletIcon />
<input
type="color"
className={ styles.colorInput }

@ -1,18 +1,18 @@
import React from 'react';
export const Droplet = () => (
export const DropletIcon = () => (
<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
<path d="M8 3.004c.25.386.525.772.827 1.172.297.395 1.308 1.664 1.495 1.91C11.522 7.663 12 8.802 12 10.5c0 2.002-1.613 3.5-4 3.5s-4-1.498-4-3.5c0-1.698.48-2.837 1.678-4.414.187-.246 1.198-1.515 1.495-1.91.302-.4.576-.786.827-1.172z" stroke="currentColor" strokeWidth="2" fill="none" fillRule="evenodd"/>
</svg>
);
export const Check = ({ backgroundColor, outlineColor, checkColor }) => (
export const CheckIcon = ({ backgroundColor, outlineColor, checkColor }) => (
<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" style={{ backgroundColor, boxShadow: `inset 0 0 0 1px ${outlineColor}`, borderRadius: '2px' }}>
<path d="M4 9l2 2M6 11l6-6" stroke={ checkColor } strokeWidth="2" fill="none" fillRule="evenodd" strokeLinecap="square"/>
</svg>
);
export const Radio = ({ selected }) => (
export const RadioIcon = ({ selected }) => (
<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
<g fill="none" fillRule="evenodd">
<circle stroke="currentColor" cx="8" cy="8" r="7.5"/>

28
web/src/Radio.js Normal file

@ -0,0 +1,28 @@
import React, { PureComponent } from 'react';
import { RadioIcon } from './Icons';
import ColorState from './ColorState';
import styles from './Radio.module.css';
export default class Radio extends PureComponent {
render() {
return (
<ColorState>
{ ({ getColor }) => (
<label
className={ styles.wrapper }
style={{ color: getColor('shade7') }}
>
<input
type="radio"
className={ styles.input }
checked={ this.props.value }
onChange={ evt => this.props.onChange(evt.target.checked) }
/>
<RadioIcon selected={ this.props.value } />
<span className={ styles.label }>{ this.props.label }</span>
</label>
) }
</ColorState>
);
}
}

13
web/src/Radio.module.css Normal file

@ -0,0 +1,13 @@
.wrapper {
display: flex;
align-items: center;
}
.input {
display: none;
}
.label {
margin-left: var(--size-small-2);
flex-grow: 1;
}

@ -17,7 +17,10 @@ export default class Tabs extends PureComponent {
borderLeftColor: getColor('shade7'),
}),
contentClassName: styles.tabContent,
contentStyle: { borderColor: getColor('shade7') },
contentStyle: {
borderColor: getColor('shade7'),
backgroundColor: getColor('shade0'),
},
}) }
</ColorState>
);

@ -1,5 +1,7 @@
.tab {
display: inline-block;
font-size: var(--size-regular);
line-height: var(--line-height);
font-family: 'Fira Code', monospace;
padding: var(--size-small-4) var(--size-small-1);
border-width: var(--border-size);
@ -19,4 +21,5 @@
border-top-right-radius: var(--border-radius-size);
border-bottom-right-radius: var(--border-radius-size);
border-bottom-left-radius: var(--border-radius-size);
padding: var(--size-large-1);
}

@ -2,7 +2,6 @@ import React, { PureComponent } from 'react';
import CodePreview from './CodePreview';
import TerminalPreview from './TerminalPreview';
import Tabs from './Tabs';
import styles from './TextPreviews.module.css';
export default class TextPreviews extends PureComponent {
@ -12,7 +11,7 @@ export default class TextPreviews extends PureComponent {
return (
<Tabs>
{ ({ tabClassName, getTabStyle, contentClassName, contentStyle }) => (
<>
<div>
<div>
<button
className={ tabClassName }
@ -25,7 +24,7 @@ export default class TextPreviews extends PureComponent {
onClick={ () => this.setState({ activePreview: 'terminal' }) }
>Terminal</button>
</div>
<div className={ `${styles.previewContainer} ${contentClassName}` } style={ contentStyle }>
<div className={ contentClassName } style={ contentStyle }>
{ this.state.activePreview === 'code' ? (
<CodePreview />
) : null }
@ -33,7 +32,7 @@ export default class TextPreviews extends PureComponent {
<TerminalPreview />
) : null }
</div>
</>
</div>
) }
</Tabs>
);

@ -1,3 +0,0 @@
.previewContainer {
padding: var(--size-large-1);
}

@ -1,4 +1,4 @@
import React, { Component } from 'react';
import React, { PureComponent } from 'react';
import qs from 'qs';
import { merge } from 'lodash';
import getValueOrFallback from './getValueOrFallback';
@ -52,9 +52,10 @@ const fallbackState = {
dark: true,
light: true,
},
activeWallpaper: 'none',
};
export class UrlStateProvider extends Component {
export class UrlStateProvider extends PureComponent {
constructor(props, ...args) {
super(props, ...args);
this.state = stateFromParams(props.history.location.search);

@ -0,0 +1,28 @@
import React, { PureComponent } from 'react';
import { UrlStateConsumer } from './UrlState';
import Tabs from './Tabs';
import Radio from './Radio';
export default class WallpaperPreview extends PureComponent {
render() {
return (
<UrlStateConsumer>
{ ({ getValueOrFallback, mergeState }) => (
<Tabs>
{ ({ tabClassName, getTabStyle, contentClassName, contentStyle }) => (
<div>
<span
className={ tabClassName }
style={ getTabStyle(true) }
>Wallpaper</span>
<div className={ contentClassName } style={ contentStyle }>
<Radio value={ getValueOrFallback([['activeWallpaper']]) === 'none' } label="None" />
</div>
</div>
) }
</Tabs>
) }
</UrlStateConsumer>
);
}
}

@ -38,10 +38,12 @@ body,
--border-size: var(--size-small-6);
--border-radius-size: var(--size-small-3);
--line-height: calc(1 / var(--size-ratio));
height: 100%;
font-family: 'Fira Code', monospace;
font-size: 16px;
line-height: calc(1 / var(--size-ratio));
line-height: var(--line-height);
}
* {