Add support for multiple wallpaper variations.

This commit is contained in:
Matt Swensen 2019-03-09 13:06:17 -07:00
parent 877da25b3d
commit a651887d31
No known key found for this signature in database
GPG Key ID: 3F9E482BFC526F35
4 changed files with 102 additions and 21 deletions

26
web/src/Radio.js Normal file

@ -0,0 +1,26 @@
import React from 'react';
import { RadioIcon } from './Icons';
import styles from './Radio.module.css';
export default ({ className, color, value, onChange, label }) => (
<label
className={ [styles.wrapper, className].join(' ') }
style={{ color }}
tabIndex="0"
onKeyDown={ evt => {
if (evt.key === ' ' || evt.key === 'Enter') {
evt.preventDefault();
onChange(true);
}
} }
>
<input
type="radio"
className={ styles.input }
checked={ value }
onChange={ evt => onChange(evt.target.checked) }
/>
<RadioIcon selected={ value } />
<span className={ styles.label }>{ label }</span>
</label>
);

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

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

@ -1,13 +1,14 @@
import React, { useState, useEffect, useRef, useContext } from 'react';
import Button from './Button';
import Radio from './Radio';
import styles from './WallpaperModal.module.css';
import ThemeContext from './ThemeContext';
import { render as blockWaveRender } from 'themer-wallpaper-block-wave';
import { render as octagonRender } from 'themer-wallpaper-octagon';
import { render as shirtsRender } from 'themer-wallpaper-shirts';
import { render as trianglesRender } from 'themer-wallpaper-triangles';
import { render as trianglifyRender } from 'themer-wallpaper-trianglify';
import ThemeContext from './ThemeContext';
const getImagePromises = (pkg, colors, width, height) => {
const options = { [`${pkg}-size`]: `${width}x${height}` };
@ -28,7 +29,8 @@ const getImagePromises = (pkg, colors, width, height) => {
}
export default ({ onClose, wallpaper, colors }) => {
const [image, setImage] = useState(null);
const [images, setImages] = useState([]);
const [imageIndex, setImageIndex] = useState(0);
const escListener = evt => {
if (evt.key === 'Escape') {
@ -49,29 +51,28 @@ export default ({ onClose, wallpaper, colors }) => {
useEffect(() => {
(async () => {
try {
const { devicePixelRatio } = window;
const { width, height } = node.current.getBoundingClientRect();
const images = await Promise.all(
const { devicePixelRatio } = window;
const { width, height } = node.current.getBoundingClientRect();
setImages(
await Promise.all(
getImagePromises(
wallpaper,
colors,
width * devicePixelRatio,
height * devicePixelRatio,
)
);
setImage(
`url('data:image/svg+xml;utf8,${encodeURIComponent(images[0].contents.toString('utf8'))}')`,
);
} catch {
setImage('none');
}
),
);
})();
}, [node, wallpaper, colors]);
useEffect(() => {
button.current.focus();
}, [button]);
const backgroundImage = images[imageIndex]
? `url('data:image/svg+xml;utf8,${encodeURIComponent(images[imageIndex].contents.toString('utf8'))}')`
: 'none';
return (
<div
@ -79,19 +80,43 @@ export default ({ onClose, wallpaper, colors }) => {
style={{ backgroundColor: getActiveColorOrFallback(['shade0'], true) }}
ref={ node }
>
{ image ? (
{ backgroundImage ? (
<div
className={ styles.image }
style={{ backgroundImage: image }}
style={{ backgroundImage }}
/>
) : (
<span style={{ color: getActiveColorOrFallback(['shade2']) }}>loading...</span>
) }
<Button
className={ styles.close }
onClick={ onClose }
ref={ button }
>close</Button>
<span className={ styles.options }>
{ images.length > 1
? (
<span
className={ styles.variations }
style={{
backgroundColor: getActiveColorOrFallback(['shade2'], true),
borderColor: getActiveColorOrFallback(['shade4']),
}}
>
{ images.map((_, i) => (
<Radio
key={ `${wallpaper}-${i}` }
className={ styles.variation }
color={ getActiveColorOrFallback(['shade7']) }
onChange={ () => setImageIndex(i) }
value={ i === imageIndex }
label={ `Variation ${i + 1}` }
/>
)) }
</span>
)
: null
}
<Button
onClick={ onClose }
ref={ button }
>Close</Button>
</span>
</div>
);
}

@ -19,8 +19,24 @@
background-size: cover;
}
.close {
.options {
position: absolute;
top: var(--size-large-1);
right: var(--size-large-1);
display: flex;
align-items: center;
}
.variations {
border-radius: var(--border-radius-size);
padding: var(--size-small-4) var(--size-small-1);
margin-right: var(--size-regular);
border-style: solid;
border-width: var(--border-size);
display: flex;
align-items: center;
}
.variation:not(:last-child) {
margin-right: var(--size-large-1);
}