Clean up state derivation abstractions.
This commit is contained in:
parent
4745429549
commit
8f95f562b1
116
web/src/App.js
116
web/src/App.js
@ -1,109 +1,9 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
import React from 'react';
|
||||||
import styles from './App.module.css';
|
import { ThemeProvider } from './ThemeContext';
|
||||||
import { UrlStateProvider } from './UrlState';
|
import Main from './Main';
|
||||||
|
|
||||||
import ColorState from './ColorState';
|
export default ({ history }) => (
|
||||||
import ColorSetInputs from './ColorSetInputs';
|
<ThemeProvider history={ history }>
|
||||||
import TextPreviews from './TextPreviews';
|
<Main />
|
||||||
import WallpaperPreview from './WallpaperPreview';
|
</ThemeProvider>
|
||||||
import PreBuiltList from './PreBuiltList';
|
);
|
||||||
import Download from './Download';
|
|
||||||
import Link from './Link';
|
|
||||||
import CopyUrl from './CopyUrl';
|
|
||||||
import StarCount from './StarCount';
|
|
||||||
|
|
||||||
export default ({ history }) => {
|
|
||||||
const [keyboarding, setKeyboarding] = useState(false);
|
|
||||||
const onKeyDown = (evt) => {
|
|
||||||
if (evt.key === 'Tab') {
|
|
||||||
setKeyboarding(true);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const onMouseDown = () => {
|
|
||||||
setKeyboarding(false);
|
|
||||||
}
|
|
||||||
useEffect(() => {
|
|
||||||
window.document.addEventListener('keydown', onKeyDown);
|
|
||||||
return () => {
|
|
||||||
window.document.removeEventListener('keydown', onKeyDown);
|
|
||||||
};
|
|
||||||
});
|
|
||||||
useEffect(() => {
|
|
||||||
window.document.addEventListener('mousedown', onMouseDown);
|
|
||||||
return () => {
|
|
||||||
window.document.removeEventListener('mousedown', onMouseDown);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return (
|
|
||||||
<UrlStateProvider history={ history }>
|
|
||||||
<ColorState>
|
|
||||||
{ ({ getColor }) => (
|
|
||||||
<div
|
|
||||||
className={ `${styles.app} ${keyboarding ? styles.keyboarding : ''}` }
|
|
||||||
style={{
|
|
||||||
backgroundColor: getColor('shade0'),
|
|
||||||
'--selection-foreground-color': getColor('shade0'),
|
|
||||||
'--selection-background-color': getColor('accent5'),
|
|
||||||
'--focus-outline-color': getColor('accent6'),
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div className={ styles.container }>
|
|
||||||
<header className={ styles.header }>
|
|
||||||
<h1 className={ styles.h1 } style={{ color: getColor('shade7') }}>themer</h1>
|
|
||||||
<StarCount />
|
|
||||||
</header>
|
|
||||||
<hr
|
|
||||||
className={ styles.hr }
|
|
||||||
style={{
|
|
||||||
backgroundImage: `
|
|
||||||
linear-gradient(
|
|
||||||
to right,
|
|
||||||
${getColor('accent0', 'shade2', 'shade7')},
|
|
||||||
${getColor('accent1', 'shade2', 'shade7')},
|
|
||||||
${getColor('accent2', 'shade2', 'shade7')},
|
|
||||||
${getColor('accent3', 'shade2', 'shade7')},
|
|
||||||
${getColor('accent4', 'shade2', 'shade7')},
|
|
||||||
${getColor('accent4', 'shade2', 'shade7')},
|
|
||||||
${getColor('accent5', 'shade2', 'shade7')},
|
|
||||||
${getColor('accent6', 'shade2', 'shade7')},
|
|
||||||
${getColor('accent7', 'shade2', 'shade7')}
|
|
||||||
)
|
|
||||||
`,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<p style={{ color: getColor('shade6', 'shade7')}}>themer takes a set of colors and generates themes for your apps (editors, terminals, wallpapers, and more).</p>
|
|
||||||
<h2 className={ styles.h2 } style={{ color: getColor('shade7') }}>1. Define colors</h2>
|
|
||||||
<p className={ styles.help } style={{ color: getColor('shade6', 'shade7') }}>Input your colors using any CSS format (keyword, hsl, rgb, etc.).</p>
|
|
||||||
<ColorSetInputs />
|
|
||||||
<p className={ styles.preBuilt } style={{ color: getColor('shade6', 'shade7') }}>
|
|
||||||
Or start with a pre-built color set:
|
|
||||||
</p>
|
|
||||||
<PreBuiltList />
|
|
||||||
<h2 className={ styles.h2 } style={{ color: getColor('shade7')}}>2. Preview</h2>
|
|
||||||
<div className={ styles.previewsContainer }>
|
|
||||||
<TextPreviews />
|
|
||||||
<WallpaperPreview />
|
|
||||||
</div>
|
|
||||||
<h2 className={ styles.h2 } style={{ color: getColor('shade7')}}>3. Download</h2>
|
|
||||||
<p className={ styles.help } style={{ color: getColor('shade6', 'shade7') }}>Select which themes you'd like to generate from your color set.</p>
|
|
||||||
<Download />
|
|
||||||
</div>
|
|
||||||
<div className={ styles.shape } style={{ '--shape-color': getColor('shade1', 'shade0') }}>
|
|
||||||
<div className={ styles.container }>
|
|
||||||
<p style={{ color: getColor('shade7') }}>
|
|
||||||
<span style={{ color: getColor('accent1', 'shade7') }}>Pro tip:</span>
|
|
||||||
{' '}
|
|
||||||
The current URL uniquely identifies your current theme. Bookmark it, email it, or share it however you like.
|
|
||||||
<CopyUrl className={ styles.copyUrl }/>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<footer className={ styles.footer } style={{ color: getColor('shade3', 'shade7') }}>
|
|
||||||
themer is free and open source software, made by <Link href="https://mjswensen.com">mjswensen</Link> with <Link href="https://github.com/mjswensen/themer/graphs/contributors">contributors</Link>, and is released under the MIT license
|
|
||||||
</footer>
|
|
||||||
</div>
|
|
||||||
) }
|
|
||||||
</ColorState>
|
|
||||||
</UrlStateProvider>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import React, { forwardRef } from 'react';
|
import React, { forwardRef, useContext } from 'react';
|
||||||
import ColorState from './ColorState';
|
|
||||||
import styles from './Button.module.css';
|
import styles from './Button.module.css';
|
||||||
|
import ThemeContext from './ThemeContext';
|
||||||
|
|
||||||
export default forwardRef(({
|
export default forwardRef(({
|
||||||
small,
|
small,
|
||||||
@ -10,39 +10,36 @@ export default forwardRef(({
|
|||||||
disabled,
|
disabled,
|
||||||
children,
|
children,
|
||||||
}, buttonRef) => {
|
}, buttonRef) => {
|
||||||
|
const { getActiveColorOrFallback } = useContext(ThemeContext);
|
||||||
const getColorKeys = () => {
|
const getColorKeys = () => {
|
||||||
if (disabled) {
|
if (disabled) {
|
||||||
return ['shade3', 'shade0'];
|
return ['shade3'];
|
||||||
} else if (small || special) {
|
} else if (small || special) {
|
||||||
return ['shade7'];
|
return ['shade7'];
|
||||||
} else {
|
} else {
|
||||||
return ['accent4', 'shade6', 'shade7'];
|
return ['accent4', 'shade6'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<ColorState>
|
<button
|
||||||
{ ({ getColor }) => (
|
className={ [
|
||||||
<button
|
styles.button,
|
||||||
className={ [
|
small && styles.small,
|
||||||
styles.button,
|
special && styles.special,
|
||||||
small && styles.small,
|
className,
|
||||||
special && styles.special,
|
].filter(Boolean).join(' ') }
|
||||||
className,
|
data-text="Download"
|
||||||
].filter(Boolean).join(' ') }
|
style={{
|
||||||
data-text="Download"
|
color: getActiveColorOrFallback(getColorKeys()),
|
||||||
style={{
|
'--button-resting-background-color': getActiveColorOrFallback(['shade1'], true),
|
||||||
color: getColor(...getColorKeys()),
|
'--button-hover-background-color': getActiveColorOrFallback(['shade2'], true),
|
||||||
'--button-resting-background-color': getColor('shade1', 'shade0'),
|
'--button-active-background-color': getActiveColorOrFallback(['shade0'], true),
|
||||||
'--button-hover-background-color': getColor('shade2', 'shade0'),
|
'--button-special-color-1': getActiveColorOrFallback(['accent1']),
|
||||||
'--button-active-background-color': getColor('shade0'),
|
'--button-special-color-2': getActiveColorOrFallback(['accent7']),
|
||||||
'--button-special-color-1': getColor('accent1', 'shade7'),
|
}}
|
||||||
'--button-special-color-2': getColor('accent7', 'shade7'),
|
onClick={ onClick }
|
||||||
}}
|
disabled={ disabled }
|
||||||
onClick={ onClick }
|
ref={ buttonRef }
|
||||||
disabled={ disabled }
|
>{ children }</button>
|
||||||
ref={ buttonRef }
|
|
||||||
>{ children }</button>
|
|
||||||
) }
|
|
||||||
</ColorState>
|
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -1,29 +0,0 @@
|
|||||||
import React from "react";
|
|
||||||
import { UrlStateConsumer } from "./UrlState";
|
|
||||||
|
|
||||||
export default ({ children }) => {
|
|
||||||
return (
|
|
||||||
<UrlStateConsumer>
|
|
||||||
{({ getValueOrFallback, mergeState }) =>
|
|
||||||
children({
|
|
||||||
getValue: () =>
|
|
||||||
getValueOrFallback(
|
|
||||||
[
|
|
||||||
[
|
|
||||||
"calculateIntermediaryShades",
|
|
||||||
getValueOrFallback([["activeColorSet"]])
|
|
||||||
]
|
|
||||||
],
|
|
||||||
v => v === "true"
|
|
||||||
),
|
|
||||||
setValue: v =>
|
|
||||||
mergeState({
|
|
||||||
calculateIntermediaryShades: {
|
|
||||||
[getValueOrFallback([["activeColorSet"]])]: v
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
</UrlStateConsumer>
|
|
||||||
);
|
|
||||||
};
|
|
@ -1,43 +1,44 @@
|
|||||||
import React from 'react';
|
import React, { useContext } from 'react';
|
||||||
import { CheckIcon } from './Icons';
|
import { CheckIcon } from './Icons';
|
||||||
import styles from './Checkbox.module.css';
|
import styles from './Checkbox.module.css';
|
||||||
import ColorState from './ColorState';
|
import ThemeContext from './ThemeContext';
|
||||||
|
|
||||||
export default ({ className, value, accentSelected, onChange, label }) => (
|
export default ({ className, value, accentSelected, onChange, label }) => {
|
||||||
<ColorState>
|
const { getActiveColorOrFallback } = useContext(ThemeContext);
|
||||||
{ ({ getColor }) => (
|
return (
|
||||||
<label
|
<label
|
||||||
className={ [styles.wrapper, className].join(' ') }
|
className={ [styles.wrapper, className].join(' ') }
|
||||||
style={{
|
style={{
|
||||||
color: value && accentSelected
|
color: value && accentSelected
|
||||||
? getColor('accent3', 'shade7')
|
? getActiveColorOrFallback(['accent3'])
|
||||||
: getColor('shade7'),
|
: getActiveColorOrFallback(['shade7']),
|
||||||
}}
|
}}
|
||||||
tabIndex="0"
|
tabIndex="0"
|
||||||
onKeyDown={ evt => {
|
onKeyDown={ evt => {
|
||||||
if (evt.key === ' ' || evt.key === 'Enter') {
|
if (evt.key === ' ' || evt.key === 'Enter') {
|
||||||
evt.preventDefault();
|
evt.preventDefault();
|
||||||
onChange(!value);
|
onChange(!value);
|
||||||
}
|
}
|
||||||
} }
|
} }
|
||||||
>
|
>
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
className={ styles.input }
|
className={ styles.input }
|
||||||
checked={ value }
|
checked={ value }
|
||||||
onChange={ evt => onChange(evt.target.checked) }
|
onChange={ evt => onChange(evt.target.checked) }
|
||||||
/>
|
/>
|
||||||
<CheckIcon
|
<CheckIcon
|
||||||
backgroundColor={
|
backgroundColor={
|
||||||
value
|
value
|
||||||
? ( accentSelected ? getColor('accent3', 'shade7')
|
? ( accentSelected
|
||||||
: getColor('shade7')) : 'transparent'
|
? getActiveColorOrFallback(['accent3'])
|
||||||
}
|
: getActiveColorOrFallback('shade7')
|
||||||
outlineColor={ value ? 'transparent' : getColor('shade7') }
|
) : 'transparent'
|
||||||
checkColor={ value ? getColor('shade0') : 'transparent' }
|
}
|
||||||
/>
|
outlineColor={ value ? 'transparent' : getActiveColorOrFallback(['shade7']) }
|
||||||
<span className={ styles.label }>{ label }</span>
|
checkColor={ value ? getActiveColorOrFallback(['shade0'], true) : 'transparent' }
|
||||||
</label>
|
/>
|
||||||
) }
|
<span className={ styles.label }>{ label }</span>
|
||||||
</ColorState>
|
</label>
|
||||||
);
|
);
|
||||||
|
};
|
||||||
|
@ -1,88 +1,85 @@
|
|||||||
import React from 'react';
|
import React, { useContext } from 'react';
|
||||||
import ColorState from './ColorState';
|
|
||||||
import styles from './CodePreview.module.css';
|
import styles from './CodePreview.module.css';
|
||||||
import { cursor } from './cursor.module.css';
|
import { cursor } from './cursor.module.css';
|
||||||
|
import ThemeContext from './ThemeContext';
|
||||||
|
|
||||||
export default () => {
|
export default () => {
|
||||||
|
const { activePreparedColorSet } = useContext(ThemeContext);
|
||||||
return (
|
return (
|
||||||
<ColorState>
|
<pre className={ styles.pre }>
|
||||||
{ ({ getColor }) => (
|
<code style={{ color: activePreparedColorSet['shade7'] }}>
|
||||||
<pre className={ styles.pre }>
|
<span style={{ color: activePreparedColorSet['shade1'], backgroundColor: activePreparedColorSet['shade0'] }} className={ styles.lineNumber }> 1 </span>
|
||||||
<code style={{ color: getColor('shade7') }}>
|
<span style={{ color: activePreparedColorSet['accent6'] }}>import</span>
|
||||||
<span style={{ color: getColor('shade1', 'shade7'), backgroundColor: getColor('shade0') }} className={ styles.lineNumber }> 1 </span>
|
{' map '}
|
||||||
<span style={{ color: getColor('accent6', 'shade7') }}>import</span>
|
<span style={{ color: activePreparedColorSet['accent6'] }}>from </span>
|
||||||
{' map '}
|
<span style={{ color: activePreparedColorSet['accent3'] }}>'map.js'</span>
|
||||||
<span style={{ color: getColor('accent6', 'shade7') }}>from </span>
|
;
|
||||||
<span style={{ color: getColor('accent3', 'shade7') }}>'map.js'</span>
|
{'\n'}
|
||||||
;
|
<span style={{ color: activePreparedColorSet['shade1'], backgroundColor: activePreparedColorSet['shade0'] }} className={ styles.lineNumber }> 2 </span>
|
||||||
{'\n'}
|
<span style={{ color: activePreparedColorSet['accent6'] }}>import</span>
|
||||||
<span style={{ color: getColor('shade1', 'shade7'), backgroundColor: getColor('shade0') }} className={ styles.lineNumber }> 2 </span>
|
{' basePickBy '}
|
||||||
<span style={{ color: getColor('accent6', 'shade7') }}>import</span>
|
<span style={{ color: activePreparedColorSet['accent6'] }}>from </span>
|
||||||
{' basePickBy '}
|
<span style={{ color: activePreparedColorSet['accent3'] }}>'./.internal/basePickBy.js'</span>
|
||||||
<span style={{ color: getColor('accent6', 'shade7') }}>from </span>
|
;
|
||||||
<span style={{ color: getColor('accent3', 'shade7') }}>'./.internal/basePickBy.js'</span>
|
{'\n'}
|
||||||
;
|
<span style={{ color: activePreparedColorSet['shade1'], backgroundColor: activePreparedColorSet['shade0'] }} className={ styles.lineNumber }> 3 </span>
|
||||||
{'\n'}
|
<span style={{ color: activePreparedColorSet['accent6'] }}>import</span>
|
||||||
<span style={{ color: getColor('shade1', 'shade7'), backgroundColor: getColor('shade0') }} className={ styles.lineNumber }> 3 </span>
|
{' getAllKeysIn '}
|
||||||
<span style={{ color: getColor('accent6', 'shade7') }}>import</span>
|
<span style={{ color: activePreparedColorSet['accent6'] }}>from </span>
|
||||||
{' getAllKeysIn '}
|
<span style={{ color: activePreparedColorSet['accent3'] }}>'./.internal/getAllKeysIn.js'</span>
|
||||||
<span style={{ color: getColor('accent6', 'shade7') }}>from </span>
|
;
|
||||||
<span style={{ color: getColor('accent3', 'shade7') }}>'./.internal/getAllKeysIn.js'</span>
|
{'\n'}
|
||||||
;
|
<span style={{ color: activePreparedColorSet['shade1'], backgroundColor: activePreparedColorSet['shade0'] }} className={ styles.lineNumber }> 4 </span>
|
||||||
{'\n'}
|
{'\n'}
|
||||||
<span style={{ color: getColor('shade1', 'shade7'), backgroundColor: getColor('shade0') }} className={ styles.lineNumber }> 4 </span>
|
<span style={{ color: activePreparedColorSet['shade1'], backgroundColor: activePreparedColorSet['shade0'] }} className={ styles.lineNumber }> 5 </span>
|
||||||
{'\n'}
|
<span style={{ color: activePreparedColorSet['shade2'] }}>{'/**\n'}</span>
|
||||||
<span style={{ color: getColor('shade1', 'shade7'), backgroundColor: getColor('shade0') }} className={ styles.lineNumber }> 5 </span>
|
<span style={{ color: activePreparedColorSet['shade1'], backgroundColor: activePreparedColorSet['shade0'] }} className={ styles.lineNumber }> 6 </span>
|
||||||
<span style={{ color: getColor('shade2', 'shade7') }}>{'/**\n'}</span>
|
<span style={{ color: activePreparedColorSet['shade2'] }}> * Creates an object composed of the `object` properties `predicate` returns{'\n'}</span>
|
||||||
<span style={{ color: getColor('shade1', 'shade7'), backgroundColor: getColor('shade0') }} className={ styles.lineNumber }> 6 </span>
|
<span style={{ color: activePreparedColorSet['shade1'], backgroundColor: activePreparedColorSet['shade0'] }} className={ styles.lineNumber }> 7 </span>
|
||||||
<span style={{ color: getColor('shade2', 'shade7') }}> * Creates an object composed of the `object` properties `predicate` returns{'\n'}</span>
|
<span style={{ color: activePreparedColorSet['shade2'] }}> * truthy for. The predicate is invoked with two arguments: (value, key).{'\n'}</span>
|
||||||
<span style={{ color: getColor('shade1', 'shade7'), backgroundColor: getColor('shade0') }} className={ styles.lineNumber }> 7 </span>
|
<span style={{ color: activePreparedColorSet['shade1'], backgroundColor: activePreparedColorSet['shade0'] }} className={ styles.lineNumber }> 8 </span>
|
||||||
<span style={{ color: getColor('shade2', 'shade7') }}> * truthy for. The predicate is invoked with two arguments: (value, key).{'\n'}</span>
|
<span style={{ color: activePreparedColorSet['shade2'] }}> */{'\n'}</span>
|
||||||
<span style={{ color: getColor('shade1', 'shade7'), backgroundColor: getColor('shade0') }} className={ styles.lineNumber }> 8 </span>
|
<span style={{ color: activePreparedColorSet['shade1'], backgroundColor: activePreparedColorSet['shade0'] }} className={ styles.lineNumber }> 9 </span>
|
||||||
<span style={{ color: getColor('shade2', 'shade7') }}> */{'\n'}</span>
|
<span style={{ color: activePreparedColorSet['accent7'] }}>function </span>
|
||||||
<span style={{ color: getColor('shade1', 'shade7'), backgroundColor: getColor('shade0') }} className={ styles.lineNumber }> 9 </span>
|
<span style={{ color: activePreparedColorSet['accent2'] }}>pickBy</span>
|
||||||
<span style={{ color: getColor('accent7', 'shade7') }}>function </span>
|
(object, predicate)
|
||||||
<span style={{ color: getColor('accent2', 'shade7') }}>pickBy</span>
|
{' {\n'}
|
||||||
(object, predicate)
|
<span style={{ color: activePreparedColorSet['shade1'], backgroundColor: activePreparedColorSet['shade0'] }} className={ styles.lineNumber }>10 </span>
|
||||||
{' {\n'}
|
<span style={{ color: activePreparedColorSet['accent5'] }}> if </span>
|
||||||
<span style={{ color: getColor('shade1', 'shade7'), backgroundColor: getColor('shade0') }} className={ styles.lineNumber }>10 </span>
|
(object
|
||||||
<span style={{ color: getColor('accent5', 'shade7') }}> if </span>
|
<span style={{ color: activePreparedColorSet['accent5'] }}> == </span>
|
||||||
(object
|
<span style={{ color: activePreparedColorSet['accent7'] }}>null</span>
|
||||||
<span style={{ color: getColor('accent5', 'shade7') }}> == </span>
|
{') {\n'}
|
||||||
<span style={{ color: getColor('accent7', 'shade7') }}>null</span>
|
<span style={{ color: activePreparedColorSet['shade5'], backgroundColor: activePreparedColorSet['shade0'] }} className={ styles.lineNumber }>11 </span>
|
||||||
{') {\n'}
|
<span style={{ color: activePreparedColorSet['accent5'] }}> return </span>
|
||||||
<span style={{ color: getColor('shade5', 'shade7'), backgroundColor: getColor('shade0') }} className={ styles.lineNumber }>11 </span>
|
{'{};'}
|
||||||
<span style={{ color: getColor('accent5', 'shade7') }}> return </span>
|
<span style={{ borderLeftColor: activePreparedColorSet['accent6'] }} className={ [styles.cursor, cursor].join(' ') }></span>
|
||||||
{'{};'}
|
{'\n'}
|
||||||
<span style={{ borderLeftColor: getColor('accent6', 'shade7') }} className={ [styles.cursor, cursor].join(' ') }></span>
|
<span style={{ color: activePreparedColorSet['shade1'], backgroundColor: activePreparedColorSet['shade0'] }} className={ styles.lineNumber }>12 </span>
|
||||||
{'\n'}
|
{' }\n'}
|
||||||
<span style={{ color: getColor('shade1', 'shade7'), backgroundColor: getColor('shade0') }} className={ styles.lineNumber }>12 </span>
|
<span style={{ color: activePreparedColorSet['shade1'], backgroundColor: activePreparedColorSet['shade0'] }} className={ styles.lineNumber }>13 </span>
|
||||||
{' }\n'}
|
<span style={{ color: activePreparedColorSet['accent7'] }}> const </span>
|
||||||
<span style={{ color: getColor('shade1', 'shade7'), backgroundColor: getColor('shade0') }} className={ styles.lineNumber }>13 </span>
|
props
|
||||||
<span style={{ color: getColor('accent7', 'shade7') }}> const </span>
|
<span style={{ color: activePreparedColorSet['accent5'] }}> = </span>
|
||||||
props
|
map(getAllKeysIn(object), prop
|
||||||
<span style={{ color: getColor('accent5', 'shade7') }}> = </span>
|
<span style={{ color: activePreparedColorSet['accent7'] }}> => </span>
|
||||||
map(getAllKeysIn(object), prop
|
{'[prop]);\n'}
|
||||||
<span style={{ color: getColor('accent7', 'shade7') }}> => </span>
|
<span style={{ color: activePreparedColorSet['shade1'], backgroundColor: activePreparedColorSet['shade0'] }} className={ styles.lineNumber }>14 </span>
|
||||||
{'[prop]);\n'}
|
<span style={{ color: activePreparedColorSet['accent5'] }}> return </span>
|
||||||
<span style={{ color: getColor('shade1', 'shade7'), backgroundColor: getColor('shade0') }} className={ styles.lineNumber }>14 </span>
|
basePickBy(object, props, (value, path)
|
||||||
<span style={{ color: getColor('accent5', 'shade7') }}> return </span>
|
<span style={{ color: activePreparedColorSet['accent7'] }}> => </span>
|
||||||
basePickBy(object, props, (value, path)
|
predicate(value, path[
|
||||||
<span style={{ color: getColor('accent7', 'shade7') }}> => </span>
|
<span style={{ color: activePreparedColorSet['accent0'] }}>0</span>
|
||||||
predicate(value, path[
|
{']));\n'}
|
||||||
<span style={{ color: getColor('accent0', 'shade7') }}>0</span>
|
<span style={{ color: activePreparedColorSet['shade1'], backgroundColor: activePreparedColorSet['shade0'] }} className={ styles.lineNumber }>15 </span>
|
||||||
{']));\n'}
|
{'}\n'}
|
||||||
<span style={{ color: getColor('shade1', 'shade7'), backgroundColor: getColor('shade0') }} className={ styles.lineNumber }>15 </span>
|
<span style={{ color: activePreparedColorSet['shade1'], backgroundColor: activePreparedColorSet['shade0'] }} className={ styles.lineNumber }>16 </span>
|
||||||
{'}\n'}
|
{'\n'}
|
||||||
<span style={{ color: getColor('shade1', 'shade7'), backgroundColor: getColor('shade0') }} className={ styles.lineNumber }>16 </span>
|
<span style={{ color: activePreparedColorSet['shade1'], backgroundColor: activePreparedColorSet['shade0'] }} className={ styles.lineNumber }>17 </span>
|
||||||
{'\n'}
|
<span style={{ color: activePreparedColorSet['accent6'] }}>export </span>
|
||||||
<span style={{ color: getColor('shade1', 'shade7'), backgroundColor: getColor('shade0') }} className={ styles.lineNumber }>17 </span>
|
<span style={{ color: activePreparedColorSet['accent7'] }}>default </span>
|
||||||
<span style={{ color: getColor('accent6', 'shade7') }}>export </span>
|
pickBy;
|
||||||
<span style={{ color: getColor('accent7', 'shade7') }}>default </span>
|
</code>
|
||||||
pickBy;
|
</pre>
|
||||||
</code>
|
|
||||||
</pre>
|
|
||||||
) }
|
|
||||||
</ColorState>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -1,62 +1,63 @@
|
|||||||
import React, { useRef } from 'react';
|
import React, { useRef, useContext } from 'react';
|
||||||
import ColorState from './ColorState';
|
|
||||||
import { DropletIcon } 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';
|
||||||
import colorSupport from './colorInputSupport';
|
import colorSupport from './colorInputSupport';
|
||||||
|
import ThemeContext from './ThemeContext';
|
||||||
|
|
||||||
export default ({ className, style, colorKey, help }) => {
|
export default ({ className, style, colorKey, help }) => {
|
||||||
const textInput = useRef(null);
|
const textInput = useRef(null);
|
||||||
|
const {
|
||||||
|
getActiveColorOrFallback,
|
||||||
|
getActiveRawColor,
|
||||||
|
setActiveRawColor,
|
||||||
|
} = useContext(ThemeContext);
|
||||||
return (
|
return (
|
||||||
<ColorState>
|
<div className={ [styles.outerWrapper, className].join(' ') } style={ style }>
|
||||||
{ ({ getColor, getRawColor, setColor }) => (
|
<div className={ styles.inputsWrapper }>
|
||||||
<div className={ [styles.outerWrapper, className].join(' ') } style={ style }>
|
<label className={ styles.textInputWrapper } style={{ color: getActiveColorOrFallback(['shade7']) }}>
|
||||||
<div className={ styles.inputsWrapper }>
|
<span className={ styles.label }>{ colorKey }:</span>
|
||||||
<label className={ styles.textInputWrapper } style={{ color: getColor('shade7') }}>
|
<input
|
||||||
<span className={ styles.label }>{ colorKey }:</span>
|
type="text"
|
||||||
<input
|
className={ styles.textInput }
|
||||||
type="text"
|
style={{
|
||||||
className={ styles.textInput }
|
color: getActiveColorOrFallback(['shade7']),
|
||||||
style={{
|
borderBottomColor: getActiveColorOrFallback([colorKey]),
|
||||||
color: getColor('shade7'),
|
}}
|
||||||
borderBottomColor: getColor(colorKey, 'shade7'),
|
value={ getActiveRawColor(colorKey) }
|
||||||
}}
|
onChange={ evt => setActiveRawColor(colorKey, evt.target.value) }
|
||||||
value={ getRawColor(colorKey) }
|
ref={ textInput }
|
||||||
onChange={ evt => setColor(colorKey, evt.target.value) }
|
/>
|
||||||
ref={ textInput }
|
</label>
|
||||||
/>
|
<label
|
||||||
</label>
|
className={ styles.swatch }
|
||||||
<label
|
style={{
|
||||||
className={ styles.swatch }
|
color: getBestForeground(
|
||||||
style={{
|
getActiveColorOrFallback(['shade7']),
|
||||||
color: getBestForeground(
|
getActiveColorOrFallback(['shade0'], true),
|
||||||
getColor('shade7'),
|
getActiveColorOrFallback([colorKey]),
|
||||||
getColor('shade0'),
|
),
|
||||||
getColor(colorKey, 'shade7'),
|
backgroundColor: getActiveColorOrFallback([colorKey]),
|
||||||
),
|
}}
|
||||||
backgroundColor: getColor(colorKey, 'shade7'),
|
tabIndex="-1"
|
||||||
}}
|
onClick={ evt => {
|
||||||
tabIndex="-1"
|
if(!colorSupport) {
|
||||||
onClick={ evt => {
|
evt.preventDefault();
|
||||||
if(!colorSupport) {
|
textInput.current.focus()
|
||||||
evt.preventDefault();
|
}
|
||||||
textInput.current.focus()
|
} }
|
||||||
}
|
>
|
||||||
} }
|
<DropletIcon />
|
||||||
>
|
<input
|
||||||
<DropletIcon />
|
type="color"
|
||||||
<input
|
className={ styles.colorInput }
|
||||||
type="color"
|
value={ getActiveColorOrFallback([colorKey], colorKey === 'shade0') }
|
||||||
className={ styles.colorInput }
|
onChange={ evt => setActiveRawColor(colorKey, evt.target.value) }
|
||||||
value={ getColor(colorKey) }
|
tabIndex="-1"
|
||||||
onChange={ evt => setColor(colorKey, evt.target.value) }
|
/>
|
||||||
tabIndex="-1"
|
</label>
|
||||||
/>
|
</div>
|
||||||
</label>
|
<div className={ styles.help } style={{ color: getActiveColorOrFallback(['shade4']) }}>{ help }</div>
|
||||||
</div>
|
</div>
|
||||||
<div className={ styles.help } style={{ color: getColor('shade4', 'shade7') }}>{ help }</div>
|
|
||||||
</div>
|
|
||||||
) }
|
|
||||||
</ColorState>
|
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
@ -1,78 +1,68 @@
|
|||||||
import React from 'react';
|
import React, { useContext } from 'react';
|
||||||
import { UrlStateConsumer } from './UrlState';
|
|
||||||
import styles from './ColorSetInputs.module.css';
|
import styles from './ColorSetInputs.module.css';
|
||||||
import ColorState from './ColorState';
|
|
||||||
import ColorInput from './ColorInput';
|
import ColorInput from './ColorInput';
|
||||||
import Checkbox from './Checkbox';
|
import Checkbox from './Checkbox';
|
||||||
import CalculateIntermediaryShadesState from './CalculateIntermediaryShadesState';
|
|
||||||
import Tabs from './Tabs';
|
import Tabs from './Tabs';
|
||||||
|
import ThemeContext from './ThemeContext';
|
||||||
|
|
||||||
export default () => (
|
export default () => {
|
||||||
<UrlStateConsumer>
|
const {
|
||||||
{ ({ getValueOrFallback, mergeState }) => {
|
activeCalculateIntermediaryShades,
|
||||||
const isDark = getValueOrFallback([['activeColorSet']]) === 'dark';
|
setActiveCalculateIntermediaryShades,
|
||||||
return (
|
activeColorSet,
|
||||||
<Tabs>
|
setActiveColorSet,
|
||||||
{ ({ tabClassName, getTabStyle, contentClassName, contentStyle }) => (
|
} = useContext(ThemeContext);
|
||||||
<ColorState>
|
const isDark = activeColorSet === 'dark';
|
||||||
{ () => (
|
return (
|
||||||
<>
|
<Tabs>
|
||||||
<div>
|
{ ({ tabClassName, getTabStyle, contentClassName, contentStyle }) => (
|
||||||
<button
|
<>
|
||||||
className={ tabClassName }
|
<div>
|
||||||
style={ getTabStyle(isDark) }
|
<button
|
||||||
onClick={ () => mergeState({ activeColorSet: 'dark' }) }
|
className={ tabClassName }
|
||||||
>Dark Variant</button>
|
style={ getTabStyle(isDark) }
|
||||||
<button
|
onClick={ () => setActiveColorSet('dark') }
|
||||||
className={ tabClassName }
|
>Dark Variant</button>
|
||||||
style={ getTabStyle(!isDark) }
|
<button
|
||||||
onClick={ () => mergeState({ activeColorSet: 'light' }) }
|
className={ tabClassName }
|
||||||
>Light Variant</button>
|
style={ getTabStyle(!isDark) }
|
||||||
</div>
|
onClick={ () => setActiveColorSet('light') }
|
||||||
<div className={ `${styles.inputContainer} ${contentClassName}` } style={ contentStyle }>
|
>Light Variant</button>
|
||||||
<ColorInput className={ styles.shade0 } colorKey="shade0" help="background color" />
|
</div>
|
||||||
<CalculateIntermediaryShadesState>
|
<div className={ `${styles.inputContainer} ${contentClassName}` } style={ contentStyle }>
|
||||||
{ ({ getValue, setValue }) => (
|
<ColorInput className={ styles.shade0 } colorKey="shade0" help="background color" />
|
||||||
<>
|
{ !activeCalculateIntermediaryShades && (
|
||||||
{ !getValue() && (
|
<>
|
||||||
<>
|
<ColorInput className={ styles.shade1 } colorKey="shade1" help="UI" />
|
||||||
<ColorInput className={ styles.shade1 } colorKey="shade1" help="UI" />
|
<ColorInput className={ styles.shade2 } colorKey="shade2" help="UI, text selection" />
|
||||||
<ColorInput className={ styles.shade2 } colorKey="shade2" help="UI, text selection" />
|
<ColorInput className={ styles.shade3 } colorKey="shade3" help="UI, code comments" />
|
||||||
<ColorInput className={ styles.shade3 } colorKey="shade3" help="UI, code comments" />
|
<ColorInput className={ styles.shade4 } colorKey="shade4" help="UI" />
|
||||||
<ColorInput className={ styles.shade4 } colorKey="shade4" help="UI" />
|
<ColorInput className={ styles.shade5 } colorKey="shade5" help="UI" />
|
||||||
<ColorInput className={ styles.shade5 } colorKey="shade5" help="UI" />
|
<ColorInput className={ styles.shade6 } colorKey="shade6" help="foreground text" />
|
||||||
<ColorInput className={ styles.shade6 } colorKey="shade6" help="foreground text" />
|
</>
|
||||||
</>
|
) }
|
||||||
) }
|
<ColorInput
|
||||||
<ColorInput
|
className={ [styles.shade7, activeCalculateIntermediaryShades ? styles.collapsed : ''].join(' ') }
|
||||||
className={ [styles.shade7, getValue() ? styles.collapsed : ''].join(' ') }
|
colorKey="shade7"
|
||||||
colorKey="shade7"
|
help="foreground text"
|
||||||
help="foreground text"
|
/>
|
||||||
/>
|
<Checkbox
|
||||||
<Checkbox
|
className={ styles.checkbox }
|
||||||
className={ styles.checkbox }
|
label="calculate intermediary shades"
|
||||||
label="calculate intermediary shades"
|
value={ activeCalculateIntermediaryShades }
|
||||||
value={ getValue() }
|
onChange={ setActiveCalculateIntermediaryShades }
|
||||||
onChange={ setValue }
|
/>
|
||||||
/>
|
<ColorInput className={ styles.accent0 } colorKey="accent0" help="error, vcs deletion" />
|
||||||
</>
|
<ColorInput className={ styles.accent1 } colorKey="accent1" help="syntax" />
|
||||||
) }
|
<ColorInput className={ styles.accent2 } colorKey="accent2" help="warning, vcs modification" />
|
||||||
</CalculateIntermediaryShadesState>
|
<ColorInput className={ styles.accent3 } colorKey="accent3" help="success, vcs addition" />
|
||||||
<ColorInput className={ styles.accent0 } colorKey="accent0" help="error, vcs deletion" />
|
<ColorInput className={ styles.accent4 } colorKey="accent4" help="syntax" />
|
||||||
<ColorInput className={ styles.accent1 } colorKey="accent1" help="syntax" />
|
<ColorInput className={ styles.accent5 } colorKey="accent5" help="syntax" />
|
||||||
<ColorInput className={ styles.accent2 } colorKey="accent2" help="warning, vcs modification" />
|
<ColorInput className={ styles.accent6 } colorKey="accent6" help="syntax, caret/cursor" />
|
||||||
<ColorInput className={ styles.accent3 } colorKey="accent3" help="success, vcs addition" />
|
<ColorInput className={ styles.accent7 } colorKey="accent7" help="syntax, special" />
|
||||||
<ColorInput className={ styles.accent4 } colorKey="accent4" help="syntax" />
|
</div>
|
||||||
<ColorInput className={ styles.accent5 } colorKey="accent5" help="syntax" />
|
</>
|
||||||
<ColorInput className={ styles.accent6 } colorKey="accent6" help="syntax, caret/cursor" />
|
) }
|
||||||
<ColorInput className={ styles.accent7 } colorKey="accent7" help="syntax, special" />
|
</Tabs>
|
||||||
</div>
|
);
|
||||||
</>
|
};
|
||||||
) }
|
|
||||||
</ColorState>
|
|
||||||
) }
|
|
||||||
</Tabs>
|
|
||||||
);
|
|
||||||
} }
|
|
||||||
</UrlStateConsumer>
|
|
||||||
);
|
|
||||||
|
@ -1,61 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import { UrlStateConsumer } from './UrlState';
|
|
||||||
import { get } from 'lodash';
|
|
||||||
import colorSteps from 'color-steps';
|
|
||||||
import Color from 'color';
|
|
||||||
import CalculateIntermediaryShadesState from './CalculateIntermediaryShadesState';
|
|
||||||
|
|
||||||
export default ({ children }) => (
|
|
||||||
<CalculateIntermediaryShadesState>
|
|
||||||
{ ({ getValue: shouldCalculateIntermediaryShades }) => (
|
|
||||||
<UrlStateConsumer>
|
|
||||||
{ ({ getValueOrFallback, mergeState, rawState }) => children({
|
|
||||||
getColor: (...args) => {
|
|
||||||
const parse = v => Color(v).hex();
|
|
||||||
const calculatedState = (() => {
|
|
||||||
if (shouldCalculateIntermediaryShades()) {
|
|
||||||
try {
|
|
||||||
const calculatedColors = colorSteps(
|
|
||||||
parse(get(rawState, ['colors', getValueOrFallback([['activeColorSet']]), 'shade0'], '')),
|
|
||||||
parse(get(rawState, ['colors', getValueOrFallback([['activeColorSet']]), 'shade7'], '')),
|
|
||||||
);
|
|
||||||
return {
|
|
||||||
colors: {
|
|
||||||
[getValueOrFallback([['activeColorSet']])]: calculatedColors.reduce(
|
|
||||||
(shades, color, idx) => ({
|
|
||||||
...shades,
|
|
||||||
[`shade${idx+1}`]: color,
|
|
||||||
}),
|
|
||||||
{},
|
|
||||||
)
|
|
||||||
},
|
|
||||||
};
|
|
||||||
} catch {}
|
|
||||||
}
|
|
||||||
return {};
|
|
||||||
})();
|
|
||||||
return getValueOrFallback(
|
|
||||||
args.map(colorKey => [
|
|
||||||
'colors',
|
|
||||||
getValueOrFallback([['activeColorSet']]),
|
|
||||||
colorKey
|
|
||||||
]),
|
|
||||||
parse,
|
|
||||||
calculatedState,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
setColor: (key, value) => {
|
|
||||||
mergeState({
|
|
||||||
colors: {
|
|
||||||
[getValueOrFallback([['activeColorSet']])]: {
|
|
||||||
[key]: value,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
getRawColor: key => get(rawState, ['colors', getValueOrFallback([['activeColorSet']]), key], ''),
|
|
||||||
}) }
|
|
||||||
</UrlStateConsumer>
|
|
||||||
) }
|
|
||||||
</CalculateIntermediaryShadesState>
|
|
||||||
);
|
|
@ -1,11 +1,10 @@
|
|||||||
import React, { useState } from 'react';
|
import React, { useState, useContext } from 'react';
|
||||||
import Checkbox from './Checkbox';
|
import Checkbox from './Checkbox';
|
||||||
import styles from './Download.module.css';
|
import styles from './Download.module.css';
|
||||||
import ColorState from './ColorState';
|
|
||||||
import Button from './Button';
|
import Button from './Button';
|
||||||
import generateZip from './generateZip';
|
import generateZip from './generateZip';
|
||||||
import saveAs from 'file-saver';
|
import saveAs from 'file-saver';
|
||||||
import { UrlStateConsumer } from './UrlState';
|
import ThemeContext from './ThemeContext';
|
||||||
|
|
||||||
export default () => {
|
export default () => {
|
||||||
const [hyper, setHyper] = useState(false);
|
const [hyper, setHyper] = useState(false);
|
||||||
@ -35,243 +34,238 @@ export default () => {
|
|||||||
const [sketchPalettes, setSketchPalettes] = useState(false);
|
const [sketchPalettes, setSketchPalettes] = useState(false);
|
||||||
const [tmux, setTmux] = useState(false);
|
const [tmux, setTmux] = useState(false);
|
||||||
|
|
||||||
|
const { getActiveColorOrFallback, preparedColorSet } = useContext(ThemeContext);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ColorState>
|
<>
|
||||||
{ ({ getColor }) => (
|
<div className={ styles.fieldsetWrapper }>
|
||||||
<>
|
<fieldset style={{ borderColor: getActiveColorOrFallback(['shade2']) }}>
|
||||||
<div className={ styles.fieldsetWrapper }>
|
<legend style={{ color: getActiveColorOrFallback(['shade5']) }}>Terminals</legend>
|
||||||
<fieldset style={{ borderColor: getColor('shade2', 'shade7') }}>
|
<Checkbox
|
||||||
<legend style={{ color: getColor('shade5', 'shade7') }}>Terminals</legend>
|
value={ hyper }
|
||||||
<Checkbox
|
onChange={ () => setHyper(!hyper) }
|
||||||
value={ hyper }
|
label="Hyper"
|
||||||
onChange={ () => setHyper(!hyper) }
|
accentSelected
|
||||||
label="Hyper"
|
/>
|
||||||
accentSelected
|
<Checkbox
|
||||||
/>
|
value={ iterm }
|
||||||
<Checkbox
|
onChange={ () => setIterm(!iterm) }
|
||||||
value={ iterm }
|
label="iTerm"
|
||||||
onChange={ () => setIterm(!iterm) }
|
accentSelected
|
||||||
label="iTerm"
|
/>
|
||||||
accentSelected
|
<Checkbox
|
||||||
/>
|
value={ gnomeTerminal }
|
||||||
<Checkbox
|
onChange={ () => setGnomeTerminal(!gnomeTerminal) }
|
||||||
value={ gnomeTerminal }
|
label="GNOME Terminal"
|
||||||
onChange={ () => setGnomeTerminal(!gnomeTerminal) }
|
accentSelected
|
||||||
label="GNOME Terminal"
|
/>
|
||||||
accentSelected
|
<Checkbox
|
||||||
/>
|
value={ conemu }
|
||||||
<Checkbox
|
onChange={ () => setConemu(!conemu) }
|
||||||
value={ conemu }
|
label="ConEmu"
|
||||||
onChange={ () => setConemu(!conemu) }
|
accentSelected
|
||||||
label="ConEmu"
|
/>
|
||||||
accentSelected
|
<Checkbox
|
||||||
/>
|
value={ cmd }
|
||||||
<Checkbox
|
onChange={ () => setCmd(!cmd) }
|
||||||
value={ cmd }
|
label="CMD.exe"
|
||||||
onChange={ () => setCmd(!cmd) }
|
accentSelected
|
||||||
label="CMD.exe"
|
/>
|
||||||
accentSelected
|
<Checkbox
|
||||||
/>
|
value={ termite }
|
||||||
<Checkbox
|
onChange={ () => setTermite(!termite) }
|
||||||
value={ termite }
|
label="Termite"
|
||||||
onChange={ () => setTermite(!termite) }
|
accentSelected
|
||||||
label="Termite"
|
/>
|
||||||
accentSelected
|
<Checkbox
|
||||||
/>
|
value={ kitty }
|
||||||
<Checkbox
|
onChange={ () => setKitty(!kitty) }
|
||||||
value={ kitty }
|
label="kitty"
|
||||||
onChange={ () => setKitty(!kitty) }
|
accentSelected
|
||||||
label="kitty"
|
/>
|
||||||
accentSelected
|
</fieldset>
|
||||||
/>
|
<fieldset style={{ borderColor: getActiveColorOrFallback(['shade2']) }}>
|
||||||
</fieldset>
|
<legend style={{ color: getActiveColorOrFallback(['shade5']) }}>Editors / IDEs</legend>
|
||||||
<fieldset style={{ borderColor: getColor('shade2', 'shade7') }}>
|
<Checkbox
|
||||||
<legend style={{ color: getColor('shade5', 'shade7') }}>Editors / IDEs</legend>
|
value={ atomSyntax }
|
||||||
<Checkbox
|
onChange={ () => setAtomSyntax(!atomSyntax) }
|
||||||
value={ atomSyntax }
|
label="Atom (syntax)"
|
||||||
onChange={ () => setAtomSyntax(!atomSyntax) }
|
accentSelected
|
||||||
label="Atom (syntax)"
|
/>
|
||||||
accentSelected
|
<Checkbox
|
||||||
/>
|
value={ atomUi }
|
||||||
<Checkbox
|
onChange={ () => setAtomUi(!atomUi) }
|
||||||
value={ atomUi }
|
label="Atom (UI)"
|
||||||
onChange={ () => setAtomUi(!atomUi) }
|
accentSelected
|
||||||
label="Atom (UI)"
|
/>
|
||||||
accentSelected
|
<Checkbox
|
||||||
/>
|
value={ sublimeText }
|
||||||
<Checkbox
|
onChange={ () => setSublimeText(!sublimeText) }
|
||||||
value={ sublimeText }
|
label="Sublime Text"
|
||||||
onChange={ () => setSublimeText(!sublimeText) }
|
accentSelected
|
||||||
label="Sublime Text"
|
/>
|
||||||
accentSelected
|
<Checkbox
|
||||||
/>
|
value={ vim }
|
||||||
<Checkbox
|
onChange={ () => setVim(!vim) }
|
||||||
value={ vim }
|
label="Vim"
|
||||||
onChange={ () => setVim(!vim) }
|
accentSelected
|
||||||
label="Vim"
|
/>
|
||||||
accentSelected
|
<Checkbox
|
||||||
/>
|
value={ vimLightline }
|
||||||
<Checkbox
|
onChange={ () => setVimLightline(!vimLightline) }
|
||||||
value={ vimLightline }
|
label="lightline.vim"
|
||||||
onChange={ () => setVimLightline(!vimLightline) }
|
accentSelected
|
||||||
label="lightline.vim"
|
/>
|
||||||
accentSelected
|
<Checkbox
|
||||||
/>
|
value={ vscode }
|
||||||
<Checkbox
|
onChange={ () => setVscode(!vscode) }
|
||||||
value={ vscode }
|
label="VS Code"
|
||||||
onChange={ () => setVscode(!vscode) }
|
accentSelected
|
||||||
label="VS Code"
|
/>
|
||||||
accentSelected
|
<Checkbox
|
||||||
/>
|
value={ xcode }
|
||||||
<Checkbox
|
onChange={ () => setXcode(!xcode) }
|
||||||
value={ xcode }
|
label="Xcode"
|
||||||
onChange={ () => setXcode(!xcode) }
|
accentSelected
|
||||||
label="Xcode"
|
/>
|
||||||
accentSelected
|
<Checkbox
|
||||||
/>
|
value={ bbedit }
|
||||||
<Checkbox
|
onChange={ () => setBbedit(!bbedit) }
|
||||||
value={ bbedit }
|
label="BBEdit"
|
||||||
onChange={ () => setBbedit(!bbedit) }
|
accentSelected
|
||||||
label="BBEdit"
|
/>
|
||||||
accentSelected
|
<Checkbox
|
||||||
/>
|
value={ jetbrains }
|
||||||
<Checkbox
|
onChange={ () => setJetbrains(!jetbrains) }
|
||||||
value={ jetbrains }
|
label="JetBrains"
|
||||||
onChange={ () => setJetbrains(!jetbrains) }
|
accentSelected
|
||||||
label="JetBrains"
|
/>
|
||||||
accentSelected
|
</fieldset>
|
||||||
/>
|
<fieldset style={{ borderColor: getActiveColorOrFallback(['shade2']) }}>
|
||||||
</fieldset>
|
<legend style={{ color: getActiveColorOrFallback(['shade5']) }}>Wallpapers</legend>
|
||||||
<fieldset style={{ borderColor: getColor('shade2', 'shade7') }}>
|
<Checkbox
|
||||||
<legend style={{ color: getColor('shade5', 'shade7') }}>Wallpapers</legend>
|
value={ wallpaperBlockWave }
|
||||||
<Checkbox
|
onChange={ () => setWallpaperBlockWave(!wallpaperBlockWave) }
|
||||||
value={ wallpaperBlockWave }
|
label="“Block Wave”"
|
||||||
onChange={ () => setWallpaperBlockWave(!wallpaperBlockWave) }
|
accentSelected
|
||||||
label="“Block Wave”"
|
/>
|
||||||
accentSelected
|
<Checkbox
|
||||||
/>
|
value={ wallpaperOctagon }
|
||||||
<Checkbox
|
onChange={ () => setWallpaperOctagon(!wallpaperOctagon) }
|
||||||
value={ wallpaperOctagon }
|
label="“Octagon”"
|
||||||
onChange={ () => setWallpaperOctagon(!wallpaperOctagon) }
|
accentSelected
|
||||||
label="“Octagon”"
|
/>
|
||||||
accentSelected
|
<Checkbox
|
||||||
/>
|
value={ wallpaperTriangles }
|
||||||
<Checkbox
|
onChange={ () => setWallpaperTriangles(!wallpaperTriangles) }
|
||||||
value={ wallpaperTriangles }
|
label="“Triangles”"
|
||||||
onChange={ () => setWallpaperTriangles(!wallpaperTriangles) }
|
accentSelected
|
||||||
label="“Triangles”"
|
/>
|
||||||
accentSelected
|
<Checkbox
|
||||||
/>
|
value={ wallpaperTrianglify }
|
||||||
<Checkbox
|
onChange={ () => setWallpaperTrianglify(!wallpaperTrianglify) }
|
||||||
value={ wallpaperTrianglify }
|
label="“Trianglify”"
|
||||||
onChange={ () => setWallpaperTrianglify(!wallpaperTrianglify) }
|
accentSelected
|
||||||
label="“Trianglify”"
|
/>
|
||||||
accentSelected
|
<Checkbox
|
||||||
/>
|
value={ wallpaperShirts }
|
||||||
<Checkbox
|
onChange={ () => setWallpaperShirts(!wallpaperShirts) }
|
||||||
value={ wallpaperShirts }
|
label="“Shirts”"
|
||||||
onChange={ () => setWallpaperShirts(!wallpaperShirts) }
|
accentSelected
|
||||||
label="“Shirts”"
|
/>
|
||||||
accentSelected
|
<div
|
||||||
/>
|
className={ styles.wallpaperHint }
|
||||||
<div
|
style={{ color: getActiveColorOrFallback(['shade3']) }}
|
||||||
className={ styles.wallpaperHint }
|
>
|
||||||
style={{ color: getColor('shade3', 'shade7') }}
|
Wallpapers will be rendered at the browser viewport's resolution.
|
||||||
>
|
|
||||||
Wallpapers will be rendered at the browser viewport's resolution.
|
|
||||||
</div>
|
|
||||||
{ window.document.fullscreenEnabled ? (
|
|
||||||
<Button
|
|
||||||
className={ styles.fullscreen }
|
|
||||||
small
|
|
||||||
onClick={
|
|
||||||
() => window.document.documentElement.requestFullscreen()
|
|
||||||
}
|
|
||||||
>Go fullscreen</Button>
|
|
||||||
) : null }
|
|
||||||
</fieldset>
|
|
||||||
<fieldset style={{ borderColor: getColor('shade2', 'shade7') }}>
|
|
||||||
<legend style={{ color: getColor('shade5', 'shade7') }}>Other</legend>
|
|
||||||
<Checkbox
|
|
||||||
value={ slack }
|
|
||||||
onChange={ () => setSlack(!slack) }
|
|
||||||
label="Slack sidebar"
|
|
||||||
accentSelected
|
|
||||||
/>
|
|
||||||
<Checkbox
|
|
||||||
value={ alfred }
|
|
||||||
onChange={ () => setAlfred(!alfred) }
|
|
||||||
label="Alfred.app"
|
|
||||||
accentSelected
|
|
||||||
/>
|
|
||||||
<Checkbox
|
|
||||||
value={ chrome }
|
|
||||||
onChange={ () => setChrome(!chrome) }
|
|
||||||
label="Chrome"
|
|
||||||
accentSelected
|
|
||||||
/>
|
|
||||||
<Checkbox
|
|
||||||
value={ sketchPalettes }
|
|
||||||
onChange={ () => setSketchPalettes(!sketchPalettes) }
|
|
||||||
label="Sketch palettes"
|
|
||||||
accentSelected
|
|
||||||
/>
|
|
||||||
<Checkbox
|
|
||||||
value={ tmux }
|
|
||||||
onChange={ () => setTmux(!tmux) }
|
|
||||||
label="tmux"
|
|
||||||
accentSelected
|
|
||||||
/>
|
|
||||||
</fieldset>
|
|
||||||
</div>
|
</div>
|
||||||
<UrlStateConsumer>
|
{ window.document.fullscreenEnabled ? (
|
||||||
{ ({ rawState }) => (
|
<Button
|
||||||
<Button
|
className={ styles.fullscreen }
|
||||||
special
|
small
|
||||||
onClick={ async () => {
|
onClick={
|
||||||
const zip = await generateZip(
|
() => window.document.documentElement.requestFullscreen()
|
||||||
{
|
}
|
||||||
hyper,
|
>Go fullscreen</Button>
|
||||||
iterm,
|
) : null }
|
||||||
gnomeTerminal,
|
</fieldset>
|
||||||
conemu,
|
<fieldset style={{ borderColor: getActiveColorOrFallback(['shade2']) }}>
|
||||||
cmd,
|
<legend style={{ color: getActiveColorOrFallback(['shade5']) }}>Other</legend>
|
||||||
termite,
|
<Checkbox
|
||||||
kitty,
|
value={ slack }
|
||||||
atomSyntax,
|
onChange={ () => setSlack(!slack) }
|
||||||
atomUi,
|
label="Slack sidebar"
|
||||||
sublimeText,
|
accentSelected
|
||||||
vim,
|
/>
|
||||||
vimLightline,
|
<Checkbox
|
||||||
vscode,
|
value={ alfred }
|
||||||
xcode,
|
onChange={ () => setAlfred(!alfred) }
|
||||||
bbedit,
|
label="Alfred.app"
|
||||||
jetbrains,
|
accentSelected
|
||||||
wallpaperBlockWave,
|
/>
|
||||||
wallpaperOctagon,
|
<Checkbox
|
||||||
wallpaperTriangles,
|
value={ chrome }
|
||||||
wallpaperTrianglify,
|
onChange={ () => setChrome(!chrome) }
|
||||||
wallpaperShirts,
|
label="Chrome"
|
||||||
slack,
|
accentSelected
|
||||||
alfred,
|
/>
|
||||||
chrome,
|
<Checkbox
|
||||||
sketchPalettes,
|
value={ sketchPalettes }
|
||||||
tmux,
|
onChange={ () => setSketchPalettes(!sketchPalettes) }
|
||||||
},
|
label="Sketch palettes"
|
||||||
rawState.colors,
|
accentSelected
|
||||||
window.innerWidth * window.devicePixelRatio,
|
/>
|
||||||
window.innerHeight * window.devicePixelRatio,
|
<Checkbox
|
||||||
window.location.href,
|
value={ tmux }
|
||||||
);
|
onChange={ () => setTmux(!tmux) }
|
||||||
zip.generateAsync({ type: 'blob' }).then(contents => {
|
label="tmux"
|
||||||
saveAs(contents, 'themer.zip');
|
accentSelected
|
||||||
});
|
/>
|
||||||
} }
|
</fieldset>
|
||||||
>Download</Button>
|
</div>
|
||||||
) }
|
<Button
|
||||||
</UrlStateConsumer>
|
special
|
||||||
</>
|
disabled={ !preparedColorSet.dark && !preparedColorSet.light }
|
||||||
) }
|
onClick={ async () => {
|
||||||
</ColorState>
|
const zip = await generateZip(
|
||||||
|
{
|
||||||
|
hyper,
|
||||||
|
iterm,
|
||||||
|
gnomeTerminal,
|
||||||
|
conemu,
|
||||||
|
cmd,
|
||||||
|
termite,
|
||||||
|
kitty,
|
||||||
|
atomSyntax,
|
||||||
|
atomUi,
|
||||||
|
sublimeText,
|
||||||
|
vim,
|
||||||
|
vimLightline,
|
||||||
|
vscode,
|
||||||
|
xcode,
|
||||||
|
bbedit,
|
||||||
|
jetbrains,
|
||||||
|
wallpaperBlockWave,
|
||||||
|
wallpaperOctagon,
|
||||||
|
wallpaperTriangles,
|
||||||
|
wallpaperTrianglify,
|
||||||
|
wallpaperShirts,
|
||||||
|
slack,
|
||||||
|
alfred,
|
||||||
|
chrome,
|
||||||
|
sketchPalettes,
|
||||||
|
tmux,
|
||||||
|
},
|
||||||
|
preparedColorSet,
|
||||||
|
window.innerWidth * window.devicePixelRatio,
|
||||||
|
window.innerHeight * window.devicePixelRatio,
|
||||||
|
window.location.href,
|
||||||
|
);
|
||||||
|
zip.generateAsync({ type: 'blob' }).then(contents => {
|
||||||
|
saveAs(contents, 'themer.zip');
|
||||||
|
});
|
||||||
|
} }
|
||||||
|
>Download</Button>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,11 @@
|
|||||||
import React from "react";
|
import React, { useContext } from "react";
|
||||||
import ColorState from "./ColorState";
|
import ThemeContext from "./ThemeContext";
|
||||||
|
|
||||||
export default props => (
|
export default props => {
|
||||||
<ColorState>
|
const { getActiveColorOrFallback } = useContext(ThemeContext);
|
||||||
{({ getColor }) => (
|
return (
|
||||||
<a style={{ color: getColor("accent5", "shade7") }} { ...props }>
|
<a style={{ color: getActiveColorOrFallback(['accent5']) }} { ...props }>
|
||||||
{ props.children }
|
{ props.children }
|
||||||
</a>
|
</a>
|
||||||
)}
|
);
|
||||||
</ColorState>
|
};
|
||||||
);
|
|
||||||
|
103
web/src/Main.js
Normal file
103
web/src/Main.js
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
import React, { useState, useEffect, useContext } from 'react';
|
||||||
|
import styles from './Main.module.css';
|
||||||
|
|
||||||
|
import ColorSetInputs from './ColorSetInputs';
|
||||||
|
import TextPreviews from './TextPreviews';
|
||||||
|
import WallpaperPreview from './WallpaperPreview';
|
||||||
|
import PreBuiltList from './PreBuiltList';
|
||||||
|
import Download from './Download';
|
||||||
|
import Link from './Link';
|
||||||
|
import CopyUrl from './CopyUrl';
|
||||||
|
import StarCount from './StarCount';
|
||||||
|
import ThemeContext from './ThemeContext';
|
||||||
|
|
||||||
|
export default () => {
|
||||||
|
const [keyboarding, setKeyboarding] = useState(false);
|
||||||
|
const onKeyDown = (evt) => {
|
||||||
|
if (evt.key === 'Tab') {
|
||||||
|
setKeyboarding(true);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const onMouseDown = () => {
|
||||||
|
setKeyboarding(false);
|
||||||
|
}
|
||||||
|
useEffect(() => {
|
||||||
|
window.document.addEventListener('keydown', onKeyDown);
|
||||||
|
return () => {
|
||||||
|
window.document.removeEventListener('keydown', onKeyDown);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
useEffect(() => {
|
||||||
|
window.document.addEventListener('mousedown', onMouseDown);
|
||||||
|
return () => {
|
||||||
|
window.document.removeEventListener('mousedown', onMouseDown);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const { getActiveColorOrFallback } = useContext(ThemeContext);
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={ `${styles.app} ${keyboarding ? styles.keyboarding : ''}` }
|
||||||
|
style={{
|
||||||
|
backgroundColor: getActiveColorOrFallback(['shade0'], true),
|
||||||
|
'--selection-foreground-color': getActiveColorOrFallback(['shade0'], true),
|
||||||
|
'--selection-background-color': getActiveColorOrFallback(['accent5']),
|
||||||
|
'--focus-outline-color': getActiveColorOrFallback(['accent6']),
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div className={ styles.container }>
|
||||||
|
<header className={ styles.header }>
|
||||||
|
<h1 className={ styles.h1 } style={{ color: getActiveColorOrFallback(['shade7']) }}>themer</h1>
|
||||||
|
<StarCount />
|
||||||
|
</header>
|
||||||
|
<hr
|
||||||
|
className={ styles.hr }
|
||||||
|
style={{
|
||||||
|
backgroundImage: `
|
||||||
|
linear-gradient(
|
||||||
|
to right,
|
||||||
|
${getActiveColorOrFallback(['accent0', 'shade2'])},
|
||||||
|
${getActiveColorOrFallback(['accent1', 'shade2'])},
|
||||||
|
${getActiveColorOrFallback(['accent2', 'shade2'])},
|
||||||
|
${getActiveColorOrFallback(['accent3', 'shade2'])},
|
||||||
|
${getActiveColorOrFallback(['accent4', 'shade2'])},
|
||||||
|
${getActiveColorOrFallback(['accent4', 'shade2'])},
|
||||||
|
${getActiveColorOrFallback(['accent5', 'shade2'])},
|
||||||
|
${getActiveColorOrFallback(['accent6', 'shade2'])},
|
||||||
|
${getActiveColorOrFallback(['accent7', 'shade2'])}
|
||||||
|
)
|
||||||
|
`,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<p style={{ color: getActiveColorOrFallback(['shade6'])}}>themer takes a set of colors and generates themes for your apps (editors, terminals, wallpapers, and more).</p>
|
||||||
|
<h2 className={ styles.h2 } style={{ color: getActiveColorOrFallback(['shade7']) }}>1. Define colors</h2>
|
||||||
|
<p className={ styles.help } style={{ color: getActiveColorOrFallback(['shade6']) }}>Input your colors using any CSS format (keyword, hsl, rgb, etc.).</p>
|
||||||
|
<ColorSetInputs />
|
||||||
|
<p className={ styles.preBuilt } style={{ color: getActiveColorOrFallback(['shade6']) }}>
|
||||||
|
Or start with a pre-built color set:
|
||||||
|
</p>
|
||||||
|
<PreBuiltList />
|
||||||
|
<h2 className={ styles.h2 } style={{ color: getActiveColorOrFallback(['shade7'])}}>2. Preview</h2>
|
||||||
|
<div className={ styles.previewsContainer }>
|
||||||
|
<TextPreviews />
|
||||||
|
<WallpaperPreview />
|
||||||
|
</div>
|
||||||
|
<h2 className={ styles.h2 } style={{ color: getActiveColorOrFallback(['shade7'])}}>3. Download</h2>
|
||||||
|
<p className={ styles.help } style={{ color: getActiveColorOrFallback(['shade6']) }}>Select which themes you'd like to generate from your color set.</p>
|
||||||
|
<Download />
|
||||||
|
</div>
|
||||||
|
<div className={ styles.shape } style={{ '--shape-color': getActiveColorOrFallback(['shade1'], true) }}>
|
||||||
|
<div className={ styles.container }>
|
||||||
|
<p style={{ color: getActiveColorOrFallback(['shade7']) }}>
|
||||||
|
<span style={{ color: getActiveColorOrFallback(['accent1']) }}>Pro tip:</span>
|
||||||
|
{' '}
|
||||||
|
The current URL uniquely identifies your current theme. Bookmark it, email it, or share it however you like.
|
||||||
|
<CopyUrl className={ styles.copyUrl }/>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<footer className={ styles.footer } style={{ color: getActiveColorOrFallback(['shade3']) }}>
|
||||||
|
themer is free and open source software, made by <Link href="https://mjswensen.com">mjswensen</Link> with <Link href="https://github.com/mjswensen/themer/graphs/contributors">contributors</Link>, and is released under the MIT license
|
||||||
|
</footer>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
@ -1,9 +1,8 @@
|
|||||||
import React from 'react';
|
import React, { useContext } from 'react';
|
||||||
import { UrlStateConsumer, paramsFromState } from './UrlState';
|
|
||||||
import ColorState from './ColorState';
|
|
||||||
import Link from './Link';
|
import Link from './Link';
|
||||||
import { has } from 'lodash';
|
import { has } from 'lodash';
|
||||||
import styles from './PreBuiltList.module.css';
|
import styles from './PreBuiltList.module.css';
|
||||||
|
import ThemeContext, { paramsFromState } from './ThemeContext';
|
||||||
|
|
||||||
import { colors as defaultColors } from 'themer-colors-default';
|
import { colors as defaultColors } from 'themer-colors-default';
|
||||||
import { colors as nightSkyColors } from 'themer-colors-night-sky';
|
import { colors as nightSkyColors } from 'themer-colors-night-sky';
|
||||||
@ -16,51 +15,46 @@ import { colors as solarizedColors } from 'themer-colors-solarized';
|
|||||||
import { colors as githubUniverseColors } from 'themer-colors-github-universe';
|
import { colors as githubUniverseColors } from 'themer-colors-github-universe';
|
||||||
import { colors as novaColors } from 'themer-colors-nova';
|
import { colors as novaColors } from 'themer-colors-nova';
|
||||||
|
|
||||||
const PreBuiltLink = ({ colors, children }) => (
|
const PreBuiltLink = ({ colors, children }) => {
|
||||||
<UrlStateConsumer>
|
const { activeColorSet } = useContext(ThemeContext);
|
||||||
{ ({ getValueOrFallback }) => {
|
const oppositeColorSet = activeColorSet === 'dark' ? 'light' : 'dark';
|
||||||
const activeColorSet = getValueOrFallback([['activeColorSet']]);
|
const preparedState = {
|
||||||
const oppositeColorSet = activeColorSet === 'dark' ? 'light' : 'dark';
|
colors,
|
||||||
const preparedState = {
|
activeColorSet: has(colors, activeColorSet) ? activeColorSet : oppositeColorSet,
|
||||||
colors,
|
calculateIntermediaryShades: {
|
||||||
activeColorSet: has(colors, activeColorSet) ? activeColorSet : oppositeColorSet,
|
dark: !has(colors, 'dark.shade1'),
|
||||||
calculateIntermediaryShades: {
|
light: !has(colors, 'light.shade1'),
|
||||||
dark: !has(colors, 'dark.shade1'),
|
},
|
||||||
light: !has(colors, 'light.shade1'),
|
};
|
||||||
},
|
return (<Link href={ paramsFromState(preparedState) }>{ children }</Link>);
|
||||||
};
|
};
|
||||||
return (<Link href={ paramsFromState(preparedState) }>{ children }</Link>);
|
|
||||||
} }
|
|
||||||
</UrlStateConsumer>
|
|
||||||
);
|
|
||||||
|
|
||||||
export default () => (
|
export default () => {
|
||||||
<ColorState>
|
const { getActiveColorOrFallback } = useContext(ThemeContext);
|
||||||
{ ({ getColor }) => (
|
return (
|
||||||
<ul className={ styles.linksets } style={{ color: getColor('shade5', 'shade7') }}>
|
<ul className={ styles.linksets } style={{ color: getActiveColorOrFallback(['shade5']) }}>
|
||||||
<li>
|
<li>
|
||||||
Original color sets:
|
Original color sets:
|
||||||
{' '}
|
{' '}
|
||||||
<ul className={ styles.links } >
|
<ul className={ styles.links } >
|
||||||
<li><PreBuiltLink colors={ defaultColors }>Default</PreBuiltLink></li>
|
<li><PreBuiltLink colors={ defaultColors }>Default</PreBuiltLink></li>
|
||||||
<li><PreBuiltLink colors={ nightSkyColors }>Night Sky</PreBuiltLink></li>
|
<li><PreBuiltLink colors={ nightSkyColors }>Night Sky</PreBuiltLink></li>
|
||||||
<li><PreBuiltLink colors={ polarIceColors }>Polar Ice</PreBuiltLink></li>
|
<li><PreBuiltLink colors={ polarIceColors }>Polar Ice</PreBuiltLink></li>
|
||||||
<li><PreBuiltLink colors={ fingerPaintColors }>Finger Paint</PreBuiltLink></li>
|
<li><PreBuiltLink colors={ fingerPaintColors }>Finger Paint</PreBuiltLink></li>
|
||||||
<li><PreBuiltLink colors={ monkeyColors }>Monkey</PreBuiltLink></li>
|
<li><PreBuiltLink colors={ monkeyColors }>Monkey</PreBuiltLink></li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
Ports from third party themes:
|
Ports from third party themes:
|
||||||
{' '}
|
{' '}
|
||||||
<ul className={ styles.links }>
|
<ul className={ styles.links }>
|
||||||
<li><PreBuiltLink colors={ oneColors }>One</PreBuiltLink></li>
|
<li><PreBuiltLink colors={ oneColors }>One</PreBuiltLink></li>
|
||||||
<li><PreBuiltLink colors={ lucidColors }>Lucid</PreBuiltLink></li>
|
<li><PreBuiltLink colors={ lucidColors }>Lucid</PreBuiltLink></li>
|
||||||
<li><PreBuiltLink colors={ solarizedColors }>Solarized</PreBuiltLink></li>
|
<li><PreBuiltLink colors={ solarizedColors }>Solarized</PreBuiltLink></li>
|
||||||
<li><PreBuiltLink colors={ githubUniverseColors }>GitHub Universe</PreBuiltLink></li>
|
<li><PreBuiltLink colors={ githubUniverseColors }>GitHub Universe</PreBuiltLink></li>
|
||||||
<li><PreBuiltLink colors={ novaColors }>Nova</PreBuiltLink></li>
|
<li><PreBuiltLink colors={ novaColors }>Nova</PreBuiltLink></li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
) }
|
);
|
||||||
</ColorState>
|
};
|
||||||
);
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect, useContext } from 'react';
|
||||||
import numeral from 'numeral';
|
import numeral from 'numeral';
|
||||||
import styles from './StarCount.module.css';
|
import styles from './StarCount.module.css';
|
||||||
import ColorState from './ColorState';
|
import ThemeContext from './ThemeContext';
|
||||||
|
|
||||||
export default () => {
|
export default () => {
|
||||||
const [count, setCount] = useState('');
|
const [count, setCount] = useState('');
|
||||||
@ -16,34 +16,32 @@ export default () => {
|
|||||||
})();
|
})();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const { getActiveColorOrFallback } = useContext(ThemeContext);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ColorState>
|
<span
|
||||||
{ ({ getColor }) => (
|
style={{
|
||||||
<span
|
'--star-count-resting-background-color': getActiveColorOrFallback(['shade1'], true),
|
||||||
style={{
|
'--star-count-hover-background-color': getActiveColorOrFallback(['shade2'], true),
|
||||||
'--star-count-resting-background-color': getColor('shade1', 'shade0'),
|
'--star-count-active-background-color': getActiveColorOrFallback(['shade0'], true),
|
||||||
'--star-count-hover-background-color': getColor('shade2', 'shade0'),
|
}}
|
||||||
'--star-count-active-background-color': getColor('shade0'),
|
>
|
||||||
}}
|
<a
|
||||||
>
|
className={ styles.star }
|
||||||
<a
|
style={{ color: getActiveColorOrFallback(['shade7']) }}
|
||||||
className={ styles.star }
|
href="https://github.com/mjswensen/themer"
|
||||||
style={{ color: getColor('shade7') }}
|
target="_blank"
|
||||||
href="https://github.com/mjswensen/themer"
|
rel="noopener noreferrer"
|
||||||
target="_blank"
|
>Star on GitHub</a>
|
||||||
rel="noopener noreferrer"
|
{ count ? (
|
||||||
>Star on GitHub</a>
|
<a
|
||||||
{ count ? (
|
className={ styles.stargazers }
|
||||||
<a
|
style={{ color: getActiveColorOrFallback(['shade7']) }}
|
||||||
className={ styles.stargazers }
|
href="https://github.com/mjswensen/themer/stargazers"
|
||||||
style={{ color: getColor('shade7') }}
|
target="_blank"
|
||||||
href="https://github.com/mjswensen/themer/stargazers"
|
rel="noopener noreferrer"
|
||||||
target="_blank"
|
>{ count }</a>
|
||||||
rel="noopener noreferrer"
|
) : null }
|
||||||
>{ count }</a>
|
</span>
|
||||||
) : null }
|
|
||||||
</span>
|
|
||||||
) }
|
|
||||||
</ColorState>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,23 +1,26 @@
|
|||||||
import React from 'react';
|
import { useContext } from 'react';
|
||||||
import ColorState from './ColorState';
|
|
||||||
import styles from './Tabs.module.css';
|
import styles from './Tabs.module.css';
|
||||||
|
import ThemeContext from './ThemeContext';
|
||||||
|
|
||||||
export default ({ children }) => (
|
export default ({ children }) => {
|
||||||
<ColorState>
|
const { getActiveColorOrFallback } = useContext(ThemeContext);
|
||||||
{ ({ getColor }) => children({
|
return children({
|
||||||
tabClassName: styles.tab,
|
tabClassName: styles.tab,
|
||||||
getTabStyle: active => ({
|
getTabStyle: active => ({
|
||||||
backgroundColor: active ? getColor('shade0') : getColor('shade2', 'shade0'),
|
backgroundColor: active ? getActiveColorOrFallback(['shade0'], true) : getActiveColorOrFallback(['shade2'], true),
|
||||||
color: getColor('shade7'),
|
color: getActiveColorOrFallback(['shade7']),
|
||||||
borderColor: getColor('shade7'),
|
borderColor: getActiveColorOrFallback(['shade7']),
|
||||||
'--tab-bottom-overlap-color': active ? getColor('shade0') : getColor('shade2', 'shade0'),
|
'--tab-bottom-overlap-color': active
|
||||||
'--tab-bottom-overlap-size': active ? 'calc(var(--border-size) * 2)' : 'var(--border-size)',
|
? getActiveColorOrFallback(['shade0'], true)
|
||||||
}),
|
: getActiveColorOrFallback(['shade2'], true),
|
||||||
contentClassName: styles.tabContent,
|
'--tab-bottom-overlap-size': active
|
||||||
contentStyle: {
|
? 'calc(var(--border-size) * 2)'
|
||||||
borderColor: getColor('shade7'),
|
: 'var(--border-size)',
|
||||||
backgroundColor: getColor('shade0'),
|
}),
|
||||||
},
|
contentClassName: styles.tabContent,
|
||||||
}) }
|
contentStyle: {
|
||||||
</ColorState>
|
borderColor: getActiveColorOrFallback(['shade7']),
|
||||||
);
|
backgroundColor: getActiveColorOrFallback(['shade0'], true),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
@ -1,73 +1,72 @@
|
|||||||
import React from 'react';
|
import React, { useContext } from 'react';
|
||||||
import ColorState from './ColorState';
|
|
||||||
import styles from './TerminalPreview.module.css';
|
import styles from './TerminalPreview.module.css';
|
||||||
import { cursor } from './cursor.module.css';
|
import { cursor } from './cursor.module.css';
|
||||||
|
import ThemeContext from './ThemeContext';
|
||||||
|
|
||||||
export default () => (
|
export default () => {
|
||||||
<ColorState>
|
const { activePreparedColorSet } = useContext(ThemeContext);
|
||||||
{ ({ getColor }) => (
|
return (
|
||||||
<pre className={ styles.pre }>
|
<pre className={ styles.pre }>
|
||||||
<code>
|
<code>
|
||||||
<span style={{ color: getColor('accent4') }}>~/project</span>
|
<span style={{ color: activePreparedColorSet['accent4'] }}>~/project</span>
|
||||||
<span style={{ color: getColor('accent7') }}>(branch*) </span>
|
<span style={{ color: activePreparedColorSet['accent7'] }}>(branch*) </span>
|
||||||
<span style={{ color: getColor('accent3') }}>|> </span>
|
<span style={{ color: activePreparedColorSet['accent3'] }}>|> </span>
|
||||||
<span style={{ color: getColor('shade5', 'shade7') }}>yarn test</span>
|
<span style={{ color: activePreparedColorSet['shade5'] }}>yarn test</span>
|
||||||
{'\n'}
|
{'\n'}
|
||||||
<span style={{ color: getColor('shade2', 'shade7') }}>$ jest</span>
|
<span style={{ color: activePreparedColorSet['shade2'] }}>$ jest</span>
|
||||||
{'\n'}
|
{'\n'}
|
||||||
<span style={{ color: getColor('shade0'), backgroundColor: getColor('accent3', 'shade7') }}> PASS </span>
|
<span style={{ color: activePreparedColorSet['shade0'], backgroundColor: activePreparedColorSet['accent3'] }}> PASS </span>
|
||||||
<span style={{ color: getColor('shade2', 'shade7') }}> packages/themer/lib/</span>
|
<span style={{ color: activePreparedColorSet['shade2'] }}> packages/themer/lib/</span>
|
||||||
<span style={{ color: getColor('shade7') }}>prepare.spec.js</span>
|
<span style={{ color: activePreparedColorSet['shade7'] }}>prepare.spec.js</span>
|
||||||
{'\n'}
|
{'\n'}
|
||||||
<span style={{ color: getColor('shade0'), backgroundColor: getColor('accent3', 'shade7') }}> PASS </span>
|
<span style={{ color: activePreparedColorSet['shade0'], backgroundColor: activePreparedColorSet['accent3'] }}> PASS </span>
|
||||||
<span style={{ color: getColor('shade2', 'shade7') }}> packages/themer-wallpaper-triangles/lib/</span>
|
<span style={{ color: activePreparedColorSet['shade2'] }}> packages/themer-wallpaper-triangles/lib/</span>
|
||||||
<span style={{ color: getColor('shade7') }}>index.spec.js</span>
|
<span style={{ color: activePreparedColorSet['shade7'] }}>index.spec.js</span>
|
||||||
{'\n'}
|
{'\n'}
|
||||||
<span style={{ color: getColor('shade0'), backgroundColor: getColor('accent3', 'shade7') }}> PASS </span>
|
<span style={{ color: activePreparedColorSet['shade0'], backgroundColor: activePreparedColorSet['accent3'] }}> PASS </span>
|
||||||
<span style={{ color: getColor('shade2', 'shade7') }}> packages/themer-vscode/lib/</span>
|
<span style={{ color: activePreparedColorSet['shade2'] }}> packages/themer-vscode/lib/</span>
|
||||||
<span style={{ color: getColor('shade7') }}>index.spec.js</span>
|
<span style={{ color: activePreparedColorSet['shade7'] }}>index.spec.js</span>
|
||||||
{'\n'}
|
{'\n'}
|
||||||
<span style={{ color: getColor('shade0'), backgroundColor: getColor('accent3', 'shade7') }}> PASS </span>
|
<span style={{ color: activePreparedColorSet['shade0'], backgroundColor: activePreparedColorSet['accent3'] }}> PASS </span>
|
||||||
<span style={{ color: getColor('shade2', 'shade7') }}> packages/themer-utils/lib/</span>
|
<span style={{ color: activePreparedColorSet['shade2'] }}> packages/themer-utils/lib/</span>
|
||||||
<span style={{ color: getColor('shade7') }}>index.spec.js</span>
|
<span style={{ color: activePreparedColorSet['shade7'] }}>index.spec.js</span>
|
||||||
{'\n'}
|
{'\n'}
|
||||||
<span style={{ color: getColor('shade0'), backgroundColor: getColor('accent3', 'shade7') }}> PASS </span>
|
<span style={{ color: activePreparedColorSet['shade0'], backgroundColor: activePreparedColorSet['accent3'] }}> PASS </span>
|
||||||
<span style={{ color: getColor('shade2', 'shade7') }}> packages/themer-wallpaper-octagon/lib/</span>
|
<span style={{ color: activePreparedColorSet['shade2'] }}> packages/themer-wallpaper-octagon/lib/</span>
|
||||||
<span style={{ color: getColor('shade7') }}>index.spec.js</span>
|
<span style={{ color: activePreparedColorSet['shade7'] }}>index.spec.js</span>
|
||||||
{'\n'}
|
{'\n'}
|
||||||
<span style={{ color: getColor('shade0'), backgroundColor: getColor('accent3', 'shade7') }}> PASS </span>
|
<span style={{ color: activePreparedColorSet['shade0'], backgroundColor: activePreparedColorSet['accent3'] }}> PASS </span>
|
||||||
<span style={{ color: getColor('shade2', 'shade7') }}> packages/themer-atom-syntax/lib/</span>
|
<span style={{ color: activePreparedColorSet['shade2'] }}> packages/themer-atom-syntax/lib/</span>
|
||||||
<span style={{ color: getColor('shade7') }}>index.spec.js</span>
|
<span style={{ color: activePreparedColorSet['shade7'] }}>index.spec.js</span>
|
||||||
{'\n'}
|
{'\n'}
|
||||||
<span style={{ color: getColor('shade0'), backgroundColor: getColor('accent3', 'shade7') }}> PASS </span>
|
<span style={{ color: activePreparedColorSet['shade0'], backgroundColor: activePreparedColorSet['accent3'] }}> PASS </span>
|
||||||
<span style={{ color: getColor('shade2', 'shade7') }}> packages/themer-chrome/lib/</span>
|
<span style={{ color: activePreparedColorSet['shade2'] }}> packages/themer-chrome/lib/</span>
|
||||||
<span style={{ color: getColor('shade7') }}>index.spec.js</span>
|
<span style={{ color: activePreparedColorSet['shade7'] }}>index.spec.js</span>
|
||||||
{'\n'}
|
{'\n'}
|
||||||
<span style={{ color: getColor('accent3', 'shade7') }}>...</span>
|
<span style={{ color: activePreparedColorSet['accent3'] }}>...</span>
|
||||||
{'\n\n'}
|
{'\n\n'}
|
||||||
<span style={{ color: getColor('shade7') }}>Test Suites: </span>
|
<span style={{ color: activePreparedColorSet['shade7'] }}>Test Suites: </span>
|
||||||
<span style={{ color: getColor('accent4', 'shade7') }}>42 passed</span>
|
<span style={{ color: activePreparedColorSet['accent4'] }}>42 passed</span>
|
||||||
<span style={{ color: getColor('shade6', 'shade7') }}>, 42 total</span>
|
<span style={{ color: activePreparedColorSet['shade6'] }}>, 42 total</span>
|
||||||
{'\n'}
|
{'\n'}
|
||||||
<span style={{ color: getColor('shade7') }}>Tests: </span>
|
<span style={{ color: activePreparedColorSet['shade7'] }}>Tests: </span>
|
||||||
<span style={{ color: getColor('accent4', 'shade7') }}>145 passed</span>
|
<span style={{ color: activePreparedColorSet['accent4'] }}>145 passed</span>
|
||||||
<span style={{ color: getColor('shade6', 'shade7') }}>, 145 total</span>
|
<span style={{ color: activePreparedColorSet['shade6'] }}>, 145 total</span>
|
||||||
{'\n'}
|
{'\n'}
|
||||||
<span style={{ color: getColor('shade7') }}>Snapshots: </span>
|
<span style={{ color: activePreparedColorSet['shade7'] }}>Snapshots: </span>
|
||||||
<span style={{ color: getColor('accent4', 'shade7') }}>102 passed</span>
|
<span style={{ color: activePreparedColorSet['accent4'] }}>102 passed</span>
|
||||||
<span style={{ color: getColor('shade6', 'shade7') }}>, 102 total</span>
|
<span style={{ color: activePreparedColorSet['shade6'] }}>, 102 total</span>
|
||||||
{'\n'}
|
{'\n'}
|
||||||
<span style={{ color: getColor('shade7') }}>Time: </span>
|
<span style={{ color: activePreparedColorSet['shade7'] }}>Time: </span>
|
||||||
<span style={{ color: getColor('shade6', 'shade7') }}>5.626s</span>
|
<span style={{ color: activePreparedColorSet['shade6'] }}>5.626s</span>
|
||||||
{'\n'}
|
{'\n'}
|
||||||
<span style={{ color: getColor('shade3', 'shade7') }}>Ran all test suites.</span>
|
<span style={{ color: activePreparedColorSet['shade3'] }}>Ran all test suites.</span>
|
||||||
{'\n'}
|
{'\n'}
|
||||||
<span style={{ color: getColor('accent4') }}>~/project</span>
|
<span style={{ color: activePreparedColorSet['accent4'] }}>~/project</span>
|
||||||
<span style={{ color: getColor('accent7') }}>(branch*) </span>
|
<span style={{ color: activePreparedColorSet['accent7'] }}>(branch*) </span>
|
||||||
<span style={{ color: getColor('accent3') }}>|> </span>
|
<span style={{ color: activePreparedColorSet['accent3'] }}>|> </span>
|
||||||
<span style={{ backgroundColor: getColor('shade5', 'shade7') }} className={ cursor }> </span>
|
<span style={{ backgroundColor: activePreparedColorSet['shade5'] }} className={ cursor }> </span>
|
||||||
</code>
|
</code>
|
||||||
</pre>
|
</pre>
|
||||||
) }
|
);
|
||||||
</ColorState>
|
};
|
||||||
);
|
|
||||||
|
275
web/src/ThemeContext.js
Normal file
275
web/src/ThemeContext.js
Normal file
@ -0,0 +1,275 @@
|
|||||||
|
import React, { createContext, useState, useEffect } from "react";
|
||||||
|
import qs from 'qs';
|
||||||
|
import { get, merge } from 'lodash';
|
||||||
|
import Color from 'color';
|
||||||
|
import colorSteps from 'color-steps';
|
||||||
|
|
||||||
|
const stateFromParams = search =>
|
||||||
|
qs.parse(search, { allowDots: true, ignoreQueryPrefix: true });
|
||||||
|
export const paramsFromState = state =>
|
||||||
|
qs.stringify(state, { allowDots: true, addQueryPrefix: true });
|
||||||
|
|
||||||
|
const DEFAULT_STATE = {
|
||||||
|
colors: {
|
||||||
|
dark: {
|
||||||
|
shade0: '#000000',
|
||||||
|
shade7: '#FFFFFF',
|
||||||
|
},
|
||||||
|
light: {
|
||||||
|
shade0: '#FFFFFF',
|
||||||
|
shade7: '#000000',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
activeColorSet: 'dark',
|
||||||
|
calculateIntermediaryShades: {
|
||||||
|
dark: true,
|
||||||
|
light: true,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const stringToBooleanOrDefault = (value, defaultValue) => {
|
||||||
|
switch (value) {
|
||||||
|
case 'true':
|
||||||
|
return true;
|
||||||
|
case 'false':
|
||||||
|
return false;
|
||||||
|
default:
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const ThemeContext = createContext();
|
||||||
|
|
||||||
|
export const ThemeProvider = ({ history, children }) => {
|
||||||
|
const [rawState, setRawState] = useState(stateFromParams(history.location.search));
|
||||||
|
useEffect(() => {
|
||||||
|
return history.listen(location => {
|
||||||
|
setRawState(stateFromParams(location.search));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const mergeState = newState => history.replace(paramsFromState(merge({}, rawState, newState)));
|
||||||
|
|
||||||
|
const activeColorSet = ['dark', 'light'].includes(rawState.activeColorSet)
|
||||||
|
? rawState.activeColorSet
|
||||||
|
: DEFAULT_STATE.activeColorSet;
|
||||||
|
|
||||||
|
const setActiveColorSet = value => mergeState({
|
||||||
|
activeColorSet: value,
|
||||||
|
});
|
||||||
|
|
||||||
|
const calculateIntermediaryDarkShades = stringToBooleanOrDefault(
|
||||||
|
get(rawState, 'calculateIntermediaryShades.dark'),
|
||||||
|
DEFAULT_STATE.calculateIntermediaryShades.dark,
|
||||||
|
)
|
||||||
|
|
||||||
|
const calculateIntermediaryLightShades = stringToBooleanOrDefault(
|
||||||
|
get(rawState, 'calculateIntermediaryShades.light'),
|
||||||
|
DEFAULT_STATE.calculateIntermediaryShades.light,
|
||||||
|
);
|
||||||
|
|
||||||
|
const activeCalculateIntermediaryShades = activeColorSet === 'dark'
|
||||||
|
? calculateIntermediaryDarkShades
|
||||||
|
: calculateIntermediaryLightShades;
|
||||||
|
|
||||||
|
const setActiveCalculateIntermediaryShades = value => mergeState({
|
||||||
|
calculateIntermediaryShades: {
|
||||||
|
[activeColorSet]: value,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const parseSafe = v => {
|
||||||
|
try {
|
||||||
|
if (v === undefined) return;
|
||||||
|
return Color(v).hex();
|
||||||
|
} catch {}
|
||||||
|
};
|
||||||
|
|
||||||
|
const darkShade0 = parseSafe(get(rawState, 'colors.dark.shade0'));
|
||||||
|
const darkShade7 = parseSafe(get(rawState, 'colors.dark.shade7'));
|
||||||
|
const lightShade0 = parseSafe(get(rawState, 'colors.light.shade0'));
|
||||||
|
const lightShade7 = parseSafe(get(rawState, 'colors.light.shade7'));
|
||||||
|
|
||||||
|
const preparedColors = {
|
||||||
|
dark: {
|
||||||
|
shade0: darkShade0,
|
||||||
|
...(calculateIntermediaryDarkShades && darkShade0 && darkShade7
|
||||||
|
? colorSteps(darkShade0, darkShade7).reduce(
|
||||||
|
(shades, color, idx) => ({
|
||||||
|
...shades,
|
||||||
|
[`shade${idx+1}`]: Color(color).hex(),
|
||||||
|
}),
|
||||||
|
{},
|
||||||
|
)
|
||||||
|
: {
|
||||||
|
shade1: parseSafe(get(rawState, 'colors.dark.shade1')),
|
||||||
|
shade2: parseSafe(get(rawState, 'colors.dark.shade2')),
|
||||||
|
shade3: parseSafe(get(rawState, 'colors.dark.shade3')),
|
||||||
|
shade4: parseSafe(get(rawState, 'colors.dark.shade4')),
|
||||||
|
shade5: parseSafe(get(rawState, 'colors.dark.shade5')),
|
||||||
|
shade6: parseSafe(get(rawState, 'colors.dark.shade6')),
|
||||||
|
}
|
||||||
|
),
|
||||||
|
shade7: darkShade7,
|
||||||
|
accent0: parseSafe(get(rawState, 'colors.dark.accent0')),
|
||||||
|
accent1: parseSafe(get(rawState, 'colors.dark.accent1')),
|
||||||
|
accent2: parseSafe(get(rawState, 'colors.dark.accent2')),
|
||||||
|
accent3: parseSafe(get(rawState, 'colors.dark.accent3')),
|
||||||
|
accent4: parseSafe(get(rawState, 'colors.dark.accent4')),
|
||||||
|
accent5: parseSafe(get(rawState, 'colors.dark.accent5')),
|
||||||
|
accent6: parseSafe(get(rawState, 'colors.dark.accent6')),
|
||||||
|
accent7: parseSafe(get(rawState, 'colors.dark.accent7')),
|
||||||
|
},
|
||||||
|
light: {
|
||||||
|
shade0: lightShade0,
|
||||||
|
...(calculateIntermediaryLightShades && lightShade0 && lightShade7
|
||||||
|
? colorSteps(lightShade0, lightShade7).reduce(
|
||||||
|
(shades, color, idx) => ({
|
||||||
|
...shades,
|
||||||
|
[`shade${idx+1}`]: color,
|
||||||
|
}),
|
||||||
|
{},
|
||||||
|
)
|
||||||
|
: {
|
||||||
|
shade1: parseSafe(get(rawState, 'colors.light.shade1')),
|
||||||
|
shade2: parseSafe(get(rawState, 'colors.light.shade2')),
|
||||||
|
shade3: parseSafe(get(rawState, 'colors.light.shade3')),
|
||||||
|
shade4: parseSafe(get(rawState, 'colors.light.shade4')),
|
||||||
|
shade5: parseSafe(get(rawState, 'colors.light.shade5')),
|
||||||
|
shade6: parseSafe(get(rawState, 'colors.light.shade6')),
|
||||||
|
}
|
||||||
|
),
|
||||||
|
shade7: lightShade7,
|
||||||
|
accent0: parseSafe(get(rawState, 'colors.light.accent0')),
|
||||||
|
accent1: parseSafe(get(rawState, 'colors.light.accent1')),
|
||||||
|
accent2: parseSafe(get(rawState, 'colors.light.accent2')),
|
||||||
|
accent3: parseSafe(get(rawState, 'colors.light.accent3')),
|
||||||
|
accent4: parseSafe(get(rawState, 'colors.light.accent4')),
|
||||||
|
accent5: parseSafe(get(rawState, 'colors.light.accent5')),
|
||||||
|
accent6: parseSafe(get(rawState, 'colors.light.accent6')),
|
||||||
|
accent7: parseSafe(get(rawState, 'colors.light.accent7')),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const getPreparedColor = (variant, keys, fallbackKey) => {
|
||||||
|
for (const key of keys) {
|
||||||
|
const preparedColor = get(preparedColors, [variant, key]);
|
||||||
|
if (preparedColor !== undefined) {
|
||||||
|
return preparedColor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const preparedFallback = get(preparedColors, [variant, fallbackKey]);
|
||||||
|
if (preparedFallback !== undefined) {
|
||||||
|
return preparedFallback;
|
||||||
|
} else {
|
||||||
|
return get(DEFAULT_STATE, ['colors', variant, fallbackKey]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const getColorOrFallback = (variant, keys, background = false) =>
|
||||||
|
getPreparedColor(variant, keys, background ? 'shade0' : 'shade7');
|
||||||
|
const getActiveColorOrFallback = (keys, background) =>
|
||||||
|
getColorOrFallback(activeColorSet, keys, background);
|
||||||
|
|
||||||
|
const preparedFullColorSet = {
|
||||||
|
dark: {
|
||||||
|
shade0: getColorOrFallback('dark', ['shade0'], true),
|
||||||
|
shade1: getColorOrFallback('dark', ['shade1']),
|
||||||
|
shade2: getColorOrFallback('dark', ['shade2']),
|
||||||
|
shade3: getColorOrFallback('dark', ['shade3']),
|
||||||
|
shade4: getColorOrFallback('dark', ['shade4']),
|
||||||
|
shade5: getColorOrFallback('dark', ['shade5']),
|
||||||
|
shade6: getColorOrFallback('dark', ['shade6']),
|
||||||
|
shade7: getColorOrFallback('dark', ['shade7']),
|
||||||
|
accent0: getColorOrFallback('dark', ['accent0']),
|
||||||
|
accent1: getColorOrFallback('dark', ['accent1']),
|
||||||
|
accent2: getColorOrFallback('dark', ['accent2']),
|
||||||
|
accent3: getColorOrFallback('dark', ['accent3']),
|
||||||
|
accent4: getColorOrFallback('dark', ['accent4']),
|
||||||
|
accent5: getColorOrFallback('dark', ['accent5']),
|
||||||
|
accent6: getColorOrFallback('dark', ['accent6']),
|
||||||
|
accent7: getColorOrFallback('dark', ['accent7']),
|
||||||
|
},
|
||||||
|
light: {
|
||||||
|
shade0: getColorOrFallback('light', ['shade0'], true),
|
||||||
|
shade1: getColorOrFallback('light', ['shade1']),
|
||||||
|
shade2: getColorOrFallback('light', ['shade2']),
|
||||||
|
shade3: getColorOrFallback('light', ['shade3']),
|
||||||
|
shade4: getColorOrFallback('light', ['shade4']),
|
||||||
|
shade5: getColorOrFallback('light', ['shade5']),
|
||||||
|
shade6: getColorOrFallback('light', ['shade6']),
|
||||||
|
shade7: getColorOrFallback('light', ['shade7']),
|
||||||
|
accent0: getColorOrFallback('light', ['accent0']),
|
||||||
|
accent1: getColorOrFallback('light', ['accent1']),
|
||||||
|
accent2: getColorOrFallback('light', ['accent2']),
|
||||||
|
accent3: getColorOrFallback('light', ['accent3']),
|
||||||
|
accent4: getColorOrFallback('light', ['accent4']),
|
||||||
|
accent5: getColorOrFallback('light', ['accent5']),
|
||||||
|
accent6: getColorOrFallback('light', ['accent6']),
|
||||||
|
accent7: getColorOrFallback('light', ['accent7']),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const activePreparedColorSet = preparedFullColorSet[activeColorSet];
|
||||||
|
|
||||||
|
const colorKeys = [
|
||||||
|
'shade0',
|
||||||
|
'shade1',
|
||||||
|
'shade2',
|
||||||
|
'shade3',
|
||||||
|
'shade4',
|
||||||
|
'shade5',
|
||||||
|
'shade6',
|
||||||
|
'shade7',
|
||||||
|
'accent0',
|
||||||
|
'accent1',
|
||||||
|
'accent2',
|
||||||
|
'accent3',
|
||||||
|
'accent4',
|
||||||
|
'accent5',
|
||||||
|
'accent6',
|
||||||
|
'accent7',
|
||||||
|
];
|
||||||
|
const preparedColorSet = {
|
||||||
|
...(
|
||||||
|
colorKeys.some(key => !!get(rawState, ['colors', 'dark', key]))
|
||||||
|
? { dark: preparedFullColorSet.dark }
|
||||||
|
: null
|
||||||
|
),
|
||||||
|
...(
|
||||||
|
colorKeys.some(key => !!get(rawState, ['colors', 'light', key]))
|
||||||
|
? { light: preparedFullColorSet.light }
|
||||||
|
: null
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
const getActiveRawColor = key => get(rawState, ['colors', activeColorSet, key], '');
|
||||||
|
|
||||||
|
const setActiveRawColor = (key, value) => mergeState({
|
||||||
|
colors: {
|
||||||
|
[activeColorSet]: {
|
||||||
|
[key]: value,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ThemeContext.Provider value={{
|
||||||
|
activeColorSet,
|
||||||
|
setActiveColorSet,
|
||||||
|
|
||||||
|
activeCalculateIntermediaryShades,
|
||||||
|
setActiveCalculateIntermediaryShades,
|
||||||
|
|
||||||
|
getActiveRawColor,
|
||||||
|
getActiveColorOrFallback,
|
||||||
|
preparedColorSet,
|
||||||
|
activePreparedColorSet,
|
||||||
|
setActiveRawColor,
|
||||||
|
}}>
|
||||||
|
{ children }
|
||||||
|
</ThemeContext.Provider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ThemeContext;
|
@ -1,83 +0,0 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
|
||||||
import qs from 'qs';
|
|
||||||
import { merge } from 'lodash';
|
|
||||||
import getValueOrFallback from './getValueOrFallback';
|
|
||||||
|
|
||||||
const UrlStateContext = React.createContext();
|
|
||||||
|
|
||||||
const stateFromParams = search => qs.parse(search, { allowDots: true, ignoreQueryPrefix: true });
|
|
||||||
export const paramsFromState = state => qs.stringify(state, { allowDots: true, addQueryPrefix: true });
|
|
||||||
|
|
||||||
const fallbackState = {
|
|
||||||
colors: {
|
|
||||||
dark: {
|
|
||||||
shade0: '#000000',
|
|
||||||
shade1: '#000000',
|
|
||||||
shade2: '#000000',
|
|
||||||
shade3: '#000000',
|
|
||||||
shade4: '#000000',
|
|
||||||
shade5: '#000000',
|
|
||||||
shade6: '#000000',
|
|
||||||
shade7: '#FFFFFF',
|
|
||||||
accent0: '#FFFFFF',
|
|
||||||
accent1: '#FFFFFF',
|
|
||||||
accent2: '#FFFFFF',
|
|
||||||
accent3: '#FFFFFF',
|
|
||||||
accent4: '#FFFFFF',
|
|
||||||
accent5: '#FFFFFF',
|
|
||||||
accent6: '#FFFFFF',
|
|
||||||
accent7: '#FFFFFF',
|
|
||||||
},
|
|
||||||
light: {
|
|
||||||
shade0: '#FFFFFF',
|
|
||||||
shade1: '#FFFFFF',
|
|
||||||
shade2: '#FFFFFF',
|
|
||||||
shade3: '#FFFFFF',
|
|
||||||
shade4: '#FFFFFF',
|
|
||||||
shade5: '#FFFFFF',
|
|
||||||
shade6: '#FFFFFF',
|
|
||||||
shade7: '#000000',
|
|
||||||
accent0: '#000000',
|
|
||||||
accent1: '#000000',
|
|
||||||
accent2: '#000000',
|
|
||||||
accent3: '#000000',
|
|
||||||
accent4: '#000000',
|
|
||||||
accent5: '#000000',
|
|
||||||
accent6: '#000000',
|
|
||||||
accent7: '#000000',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
activeColorSet: 'dark',
|
|
||||||
calculateIntermediaryShades: {
|
|
||||||
dark: true,
|
|
||||||
light: true,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export const UrlStateProvider = ({ history, children }) => {
|
|
||||||
const [state, setState] = useState(stateFromParams(history.location.search));
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
return history.listen(location => {
|
|
||||||
setState(stateFromParams(location.search));
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
|
||||||
<UrlStateContext.Provider value={{
|
|
||||||
rawState: state,
|
|
||||||
getValueOrFallback: (paths, parse, calculatedState) => getValueOrFallback(
|
|
||||||
state,
|
|
||||||
calculatedState,
|
|
||||||
fallbackState,
|
|
||||||
paths,
|
|
||||||
parse,
|
|
||||||
),
|
|
||||||
mergeState: newState => history.replace(paramsFromState(merge({}, state, newState))),
|
|
||||||
}}>
|
|
||||||
{ children }
|
|
||||||
</UrlStateContext.Provider>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export const UrlStateConsumer = UrlStateContext.Consumer;
|
|
@ -1,5 +1,4 @@
|
|||||||
import React, { useState, useEffect, useRef } from 'react';
|
import React, { useState, useEffect, useRef, useContext } from 'react';
|
||||||
import ColorState from './ColorState';
|
|
||||||
import Button from './Button';
|
import Button from './Button';
|
||||||
import styles from './WallpaperModal.module.css';
|
import styles from './WallpaperModal.module.css';
|
||||||
|
|
||||||
@ -8,6 +7,7 @@ import { render as octagonRender } from 'themer-wallpaper-octagon';
|
|||||||
import { render as shirtsRender } from 'themer-wallpaper-shirts';
|
import { render as shirtsRender } from 'themer-wallpaper-shirts';
|
||||||
import { render as trianglesRender } from 'themer-wallpaper-triangles';
|
import { render as trianglesRender } from 'themer-wallpaper-triangles';
|
||||||
import { render as trianglifyRender } from 'themer-wallpaper-trianglify';
|
import { render as trianglifyRender } from 'themer-wallpaper-trianglify';
|
||||||
|
import ThemeContext from './ThemeContext';
|
||||||
|
|
||||||
const getImagePromises = (pkg, colors, width, height) => {
|
const getImagePromises = (pkg, colors, width, height) => {
|
||||||
const options = { [`${pkg}-size`]: `${width}x${height}` };
|
const options = { [`${pkg}-size`]: `${width}x${height}` };
|
||||||
@ -42,6 +42,8 @@ export default ({ onClose, wallpaper, colors }) => {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const { getActiveColorOrFallback } = useContext(ThemeContext);
|
||||||
|
|
||||||
const node = useRef(null);
|
const node = useRef(null);
|
||||||
const button = useRef(null);
|
const button = useRef(null);
|
||||||
|
|
||||||
@ -72,28 +74,24 @@ export default ({ onClose, wallpaper, colors }) => {
|
|||||||
}, [button]);
|
}, [button]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ColorState>
|
<div
|
||||||
{ ({ getColor }) => (
|
className={ styles.scrim }
|
||||||
|
style={{ backgroundColor: getActiveColorOrFallback(['shade0'], true) }}
|
||||||
|
ref={ node }
|
||||||
|
>
|
||||||
|
{ image ? (
|
||||||
<div
|
<div
|
||||||
className={ styles.scrim }
|
className={ styles.image }
|
||||||
style={{ backgroundColor: getColor('shade0') }}
|
style={{ backgroundImage: image }}
|
||||||
ref={ node }
|
/>
|
||||||
>
|
) : (
|
||||||
{ image ? (
|
<span style={{ color: getActiveColorOrFallback(['shade2']) }}>loading...</span>
|
||||||
<div
|
|
||||||
className={ styles.image }
|
|
||||||
style={{ backgroundImage: image }}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<span style={{ color: getColor('shade2', 'shade7') }}>loading...</span>
|
|
||||||
) }
|
|
||||||
<Button
|
|
||||||
className={ styles.close }
|
|
||||||
onClick={ onClose }
|
|
||||||
ref={ button }
|
|
||||||
>close</Button>
|
|
||||||
</div>
|
|
||||||
) }
|
) }
|
||||||
</ColorState>
|
<Button
|
||||||
|
className={ styles.close }
|
||||||
|
onClick={ onClose }
|
||||||
|
ref={ button }
|
||||||
|
>close</Button>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
@ -1,9 +1,9 @@
|
|||||||
import React, { useState, useRef } from 'react';
|
import React, { useState, useRef, useContext } from 'react';
|
||||||
import Tabs from './Tabs';
|
import Tabs from './Tabs';
|
||||||
import WallpaperModal from './WallpaperModal';
|
import WallpaperModal from './WallpaperModal';
|
||||||
import Button from './Button';
|
import Button from './Button';
|
||||||
import styles from './WallpaperPreview.module.css';
|
import styles from './WallpaperPreview.module.css';
|
||||||
import ColorState from './ColorState';
|
import ThemeContext from './ThemeContext';
|
||||||
|
|
||||||
const wallpaperOptions = [
|
const wallpaperOptions = [
|
||||||
{ value: 'themer-wallpaper-block-wave', label: '"Block Wave"'},
|
{ value: 'themer-wallpaper-block-wave', label: '"Block Wave"'},
|
||||||
@ -26,6 +26,8 @@ export default () => {
|
|||||||
setActivePreview(null);
|
setActivePreview(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const { activePreparedColorSet } = useContext(ThemeContext);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Tabs>
|
<Tabs>
|
||||||
{ ({ tabClassName, getTabStyle, contentClassName, contentStyle }) => (
|
{ ({ tabClassName, getTabStyle, contentClassName, contentStyle }) => (
|
||||||
@ -45,34 +47,13 @@ export default () => {
|
|||||||
)) }
|
)) }
|
||||||
</div>
|
</div>
|
||||||
{ activePreview ? (
|
{ activePreview ? (
|
||||||
<ColorState>
|
<WallpaperModal
|
||||||
{ ({ getColor }) => (
|
wallpaper={ activePreview }
|
||||||
<WallpaperModal
|
colors={{
|
||||||
wallpaper={ activePreview }
|
current: activePreparedColorSet
|
||||||
colors={{
|
}}
|
||||||
current: {
|
onClose={ onModalClose }
|
||||||
shade0: getColor('shade0'),
|
/>
|
||||||
shade1: getColor('shade1'),
|
|
||||||
shade2: getColor('shade2'),
|
|
||||||
shade3: getColor('shade3'),
|
|
||||||
shade4: getColor('shade4'),
|
|
||||||
shade5: getColor('shade5'),
|
|
||||||
shade6: getColor('shade6'),
|
|
||||||
shade7: getColor('shade7'),
|
|
||||||
accent0: getColor('accent0'),
|
|
||||||
accent1: getColor('accent1'),
|
|
||||||
accent2: getColor('accent2'),
|
|
||||||
accent3: getColor('accent3'),
|
|
||||||
accent4: getColor('accent4'),
|
|
||||||
accent5: getColor('accent5'),
|
|
||||||
accent6: getColor('accent6'),
|
|
||||||
accent7: getColor('accent7'),
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
onClose={ onModalClose }
|
|
||||||
/>
|
|
||||||
) }
|
|
||||||
</ColorState>
|
|
||||||
) : null }
|
) : null }
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
Loading…
Reference in New Issue
Block a user