Plumbing for wallpaper previews.
This commit is contained in:
parent
84961f5dad
commit
cd123ab971
@ -5,6 +5,7 @@ import { UrlStateProvider } from './UrlState';
|
|||||||
import ColorState from './ColorState';
|
import ColorState from './ColorState';
|
||||||
import ColorSetInputs from './ColorSetInputs';
|
import ColorSetInputs from './ColorSetInputs';
|
||||||
import TextPreviews from './TextPreviews';
|
import TextPreviews from './TextPreviews';
|
||||||
|
import WallpaperPreview from './WallpaperPreview';
|
||||||
|
|
||||||
export default class App extends PureComponent {
|
export default class App extends PureComponent {
|
||||||
render() {
|
render() {
|
||||||
@ -35,7 +36,10 @@ export default class App extends PureComponent {
|
|||||||
<h2 className={ styles.h2 } style={{ color: getColor('shade7')}}>1. Define colors</h2>
|
<h2 className={ styles.h2 } style={{ color: getColor('shade7')}}>1. Define colors</h2>
|
||||||
<ColorSetInputs />
|
<ColorSetInputs />
|
||||||
<h2 className={ styles.h2 } style={{ color: getColor('shade7')}}>2. Preview</h2>
|
<h2 className={ styles.h2 } style={{ color: getColor('shade7')}}>2. Preview</h2>
|
||||||
<TextPreviews />
|
<div className={ styles.previewsContainer }>
|
||||||
|
<TextPreviews />
|
||||||
|
<WallpaperPreview />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
) }
|
) }
|
||||||
|
@ -23,4 +23,10 @@
|
|||||||
.h2 {
|
.h2 {
|
||||||
font-size: var(--size-large-1);
|
font-size: var(--size-large-1);
|
||||||
margin: var(--size-regular) 0;
|
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 React, { PureComponent } from 'react';
|
||||||
import { Check } from './Icons';
|
import { CheckIcon } from './Icons';
|
||||||
import styles from './Checkbox.module.css';
|
import styles from './Checkbox.module.css';
|
||||||
import ColorState from './ColorState';
|
import ColorState from './ColorState';
|
||||||
|
|
||||||
@ -18,7 +18,7 @@ export default class Checkbox extends PureComponent {
|
|||||||
checked={ this.props.value }
|
checked={ this.props.value }
|
||||||
onChange={ evt => this.props.onChange(evt.target.checked) }
|
onChange={ evt => this.props.onChange(evt.target.checked) }
|
||||||
/>
|
/>
|
||||||
<Check
|
<CheckIcon
|
||||||
backgroundColor={ this.props.value ? getColor('shade7') : 'transparent' }
|
backgroundColor={ this.props.value ? getColor('shade7') : 'transparent' }
|
||||||
outlineColor={ this.props.value ? 'transparent' : getColor('shade7') }
|
outlineColor={ this.props.value ? 'transparent' : getColor('shade7') }
|
||||||
checkColor={ this.props.value ? getColor('shade0') : 'transparent' }
|
checkColor={ this.props.value ? getColor('shade0') : 'transparent' }
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import React, { PureComponent } from 'react';
|
import React, { PureComponent } from 'react';
|
||||||
import ColorState from './ColorState';
|
import ColorState from './ColorState';
|
||||||
import { Droplet } from './Icons';
|
import { DropletIcon } from './Icons';
|
||||||
import styles from './ColorInput.module.css';
|
import styles from './ColorInput.module.css';
|
||||||
import getBestForeground from './getBestForeground';
|
import getBestForeground from './getBestForeground';
|
||||||
|
|
||||||
@ -36,7 +36,7 @@ export default class ColorInput extends PureComponent {
|
|||||||
}}
|
}}
|
||||||
tabIndex="0"
|
tabIndex="0"
|
||||||
>
|
>
|
||||||
<Droplet />
|
<DropletIcon />
|
||||||
<input
|
<input
|
||||||
type="color"
|
type="color"
|
||||||
className={ styles.colorInput }
|
className={ styles.colorInput }
|
||||||
|
@ -1,18 +1,18 @@
|
|||||||
import React from 'react';
|
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">
|
<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"/>
|
<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>
|
</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' }}>
|
<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"/>
|
<path d="M4 9l2 2M6 11l6-6" stroke={ checkColor } strokeWidth="2" fill="none" fillRule="evenodd" strokeLinecap="square"/>
|
||||||
</svg>
|
</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">
|
<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
|
||||||
<g fill="none" fillRule="evenodd">
|
<g fill="none" fillRule="evenodd">
|
||||||
<circle stroke="currentColor" cx="8" cy="8" r="7.5"/>
|
<circle stroke="currentColor" cx="8" cy="8" r="7.5"/>
|
||||||
|
28
web/src/Radio.js
Normal file
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
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'),
|
borderLeftColor: getColor('shade7'),
|
||||||
}),
|
}),
|
||||||
contentClassName: styles.tabContent,
|
contentClassName: styles.tabContent,
|
||||||
contentStyle: { borderColor: getColor('shade7') },
|
contentStyle: {
|
||||||
|
borderColor: getColor('shade7'),
|
||||||
|
backgroundColor: getColor('shade0'),
|
||||||
|
},
|
||||||
}) }
|
}) }
|
||||||
</ColorState>
|
</ColorState>
|
||||||
);
|
);
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
.tab {
|
.tab {
|
||||||
|
display: inline-block;
|
||||||
font-size: var(--size-regular);
|
font-size: var(--size-regular);
|
||||||
|
line-height: var(--line-height);
|
||||||
font-family: 'Fira Code', monospace;
|
font-family: 'Fira Code', monospace;
|
||||||
padding: var(--size-small-4) var(--size-small-1);
|
padding: var(--size-small-4) var(--size-small-1);
|
||||||
border-width: var(--border-size);
|
border-width: var(--border-size);
|
||||||
@ -19,4 +21,5 @@
|
|||||||
border-top-right-radius: var(--border-radius-size);
|
border-top-right-radius: var(--border-radius-size);
|
||||||
border-bottom-right-radius: var(--border-radius-size);
|
border-bottom-right-radius: var(--border-radius-size);
|
||||||
border-bottom-left-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 CodePreview from './CodePreview';
|
||||||
import TerminalPreview from './TerminalPreview';
|
import TerminalPreview from './TerminalPreview';
|
||||||
import Tabs from './Tabs';
|
import Tabs from './Tabs';
|
||||||
import styles from './TextPreviews.module.css';
|
|
||||||
|
|
||||||
export default class TextPreviews extends PureComponent {
|
export default class TextPreviews extends PureComponent {
|
||||||
|
|
||||||
@ -12,7 +11,7 @@ export default class TextPreviews extends PureComponent {
|
|||||||
return (
|
return (
|
||||||
<Tabs>
|
<Tabs>
|
||||||
{ ({ tabClassName, getTabStyle, contentClassName, contentStyle }) => (
|
{ ({ tabClassName, getTabStyle, contentClassName, contentStyle }) => (
|
||||||
<>
|
<div>
|
||||||
<div>
|
<div>
|
||||||
<button
|
<button
|
||||||
className={ tabClassName }
|
className={ tabClassName }
|
||||||
@ -25,7 +24,7 @@ export default class TextPreviews extends PureComponent {
|
|||||||
onClick={ () => this.setState({ activePreview: 'terminal' }) }
|
onClick={ () => this.setState({ activePreview: 'terminal' }) }
|
||||||
>Terminal</button>
|
>Terminal</button>
|
||||||
</div>
|
</div>
|
||||||
<div className={ `${styles.previewContainer} ${contentClassName}` } style={ contentStyle }>
|
<div className={ contentClassName } style={ contentStyle }>
|
||||||
{ this.state.activePreview === 'code' ? (
|
{ this.state.activePreview === 'code' ? (
|
||||||
<CodePreview />
|
<CodePreview />
|
||||||
) : null }
|
) : null }
|
||||||
@ -33,7 +32,7 @@ export default class TextPreviews extends PureComponent {
|
|||||||
<TerminalPreview />
|
<TerminalPreview />
|
||||||
) : null }
|
) : null }
|
||||||
</div>
|
</div>
|
||||||
</>
|
</div>
|
||||||
) }
|
) }
|
||||||
</Tabs>
|
</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 qs from 'qs';
|
||||||
import { merge } from 'lodash';
|
import { merge } from 'lodash';
|
||||||
import getValueOrFallback from './getValueOrFallback';
|
import getValueOrFallback from './getValueOrFallback';
|
||||||
@ -52,9 +52,10 @@ const fallbackState = {
|
|||||||
dark: true,
|
dark: true,
|
||||||
light: true,
|
light: true,
|
||||||
},
|
},
|
||||||
|
activeWallpaper: 'none',
|
||||||
};
|
};
|
||||||
|
|
||||||
export class UrlStateProvider extends Component {
|
export class UrlStateProvider extends PureComponent {
|
||||||
constructor(props, ...args) {
|
constructor(props, ...args) {
|
||||||
super(props, ...args);
|
super(props, ...args);
|
||||||
this.state = stateFromParams(props.history.location.search);
|
this.state = stateFromParams(props.history.location.search);
|
||||||
|
28
web/src/WallpaperPreview.js
Normal file
28
web/src/WallpaperPreview.js
Normal file
@ -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-size: var(--size-small-6);
|
||||||
--border-radius-size: var(--size-small-3);
|
--border-radius-size: var(--size-small-3);
|
||||||
|
|
||||||
|
--line-height: calc(1 / var(--size-ratio));
|
||||||
|
|
||||||
height: 100%;
|
height: 100%;
|
||||||
font-family: 'Fira Code', monospace;
|
font-family: 'Fira Code', monospace;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
line-height: calc(1 / var(--size-ratio));
|
line-height: var(--line-height);
|
||||||
}
|
}
|
||||||
|
|
||||||
* {
|
* {
|
||||||
|
Loading…
Reference in New Issue
Block a user