|
|
@ -5,18 +5,25 @@ import Dropdown from '../Dropdown'
|
|
|
|
import { managePopout } from '../Popout'
|
|
|
|
import { managePopout } from '../Popout'
|
|
|
|
import ThemeIcon from '../svg/Theme'
|
|
|
|
import ThemeIcon from '../svg/Theme'
|
|
|
|
import RemoveIcon from '../svg/Remove'
|
|
|
|
import RemoveIcon from '../svg/Remove'
|
|
|
|
import { THEMES, COLORS, DEFAULT_THEME } from '../../lib/constants'
|
|
|
|
import { COLORS } from '../../lib/constants'
|
|
|
|
import { getThemes, saveThemes, stringifyRGBA, generateId } from '../../lib/util'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const ThemeCreate = dynamic(() => import('./ThemeCreate'), {
|
|
|
|
const ThemeCreate = dynamic(() => import('./ThemeCreate'), {
|
|
|
|
loading: () => null
|
|
|
|
loading: () => null
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
const ThemeItem = ({ children, item, isSelected, onClick }) => (
|
|
|
|
const ThemeItem = ({ children, item, isSelected, remove }) => (
|
|
|
|
<div className="theme-item">
|
|
|
|
<div className="theme-item">
|
|
|
|
{children}
|
|
|
|
{children}
|
|
|
|
{item.custom && !isSelected && (
|
|
|
|
{item.custom && !isSelected && (
|
|
|
|
<div role="button" tabIndex={0} className="icon" onClick={onClick(item.id)}>
|
|
|
|
<div
|
|
|
|
|
|
|
|
role="button"
|
|
|
|
|
|
|
|
tabIndex={0}
|
|
|
|
|
|
|
|
className="icon"
|
|
|
|
|
|
|
|
onClick={e => {
|
|
|
|
|
|
|
|
e.stopPropagation()
|
|
|
|
|
|
|
|
remove(item.id)
|
|
|
|
|
|
|
|
}}
|
|
|
|
|
|
|
|
>
|
|
|
|
<RemoveIcon color={COLORS.SECONDARY} />
|
|
|
|
<RemoveIcon color={COLORS.SECONDARY} />
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
)}
|
|
|
|
)}
|
|
|
@ -40,131 +47,58 @@ const ThemeItem = ({ children, item, isSelected, onClick }) => (
|
|
|
|
|
|
|
|
|
|
|
|
const themeIcon = <ThemeIcon />
|
|
|
|
const themeIcon = <ThemeIcon />
|
|
|
|
|
|
|
|
|
|
|
|
const getCustomName = themes =>
|
|
|
|
|
|
|
|
`Custom Theme ${themes.filter(({ name }) => name.startsWith('Custom Theme')).length + 1}`
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Themes extends React.PureComponent {
|
|
|
|
class Themes extends React.PureComponent {
|
|
|
|
selectedTheme = DEFAULT_THEME
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
state = {
|
|
|
|
state = {
|
|
|
|
themes: THEMES,
|
|
|
|
highlights: {}
|
|
|
|
preset: this.props.theme,
|
|
|
|
|
|
|
|
input: 'Custom Theme',
|
|
|
|
|
|
|
|
selected: null
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
dropdown = React.createRef()
|
|
|
|
dropdown = React.createRef()
|
|
|
|
|
|
|
|
|
|
|
|
componentDidMount() {
|
|
|
|
|
|
|
|
const { update, theme, highlights } = this.props
|
|
|
|
|
|
|
|
const storedThemes = getThemes(localStorage) || []
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
this.setState(({ themes }) => {
|
|
|
|
|
|
|
|
const newThemes = [...storedThemes, ...themes]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
this.selectedTheme = newThemes.find(({ id }) => id === theme) || DEFAULT_THEME
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (Object.keys(highlights).length === 0) {
|
|
|
|
|
|
|
|
update({ highlights: this.selectedTheme.highlights })
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
|
|
|
themes: newThemes,
|
|
|
|
|
|
|
|
input: getCustomName(newThemes)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
componentDidUpdate(prevProps) {
|
|
|
|
componentDidUpdate(prevProps) {
|
|
|
|
const { isVisible, theme, update } = this.props
|
|
|
|
if (prevProps.isVisible && !this.props.isVisible) {
|
|
|
|
const { themes } = this.state
|
|
|
|
this.setState({
|
|
|
|
|
|
|
|
highlights: {}
|
|
|
|
if (prevProps.isVisible && !isVisible) {
|
|
|
|
|
|
|
|
this.setState({ input: getCustomName(themes) })
|
|
|
|
|
|
|
|
update({ highlights: themes.find(({ id }) => id === theme).highlights })
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
applyPreset = preset => {
|
|
|
|
|
|
|
|
this.setState(({ themes }) => {
|
|
|
|
|
|
|
|
this.props.update({ highlights: themes.find(({ id }) => id === preset).highlights })
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
|
|
|
preset
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
handleChange = ({ id }) => {
|
|
|
|
handleThemeSelected = theme => {
|
|
|
|
const { toggleVisibility, update } = this.props
|
|
|
|
const { toggleVisibility, update } = this.props
|
|
|
|
const { themes } = this.state
|
|
|
|
if (theme.id === 'create') {
|
|
|
|
|
|
|
|
|
|
|
|
if (id === 'create') {
|
|
|
|
|
|
|
|
toggleVisibility()
|
|
|
|
toggleVisibility()
|
|
|
|
this.dropdown.current.closeMenu()
|
|
|
|
this.dropdown.current.closeMenu()
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
update({ theme: id, highlights: themes.find(theme => theme.id === id).highlights })
|
|
|
|
update(theme)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
updateInput = ({ target: { value: input } }) => this.setState({ input })
|
|
|
|
selectHighlight = key => () =>
|
|
|
|
|
|
|
|
this.setState(({ selectedHighlight }) => ({
|
|
|
|
selectHighlight = highlight => () =>
|
|
|
|
selectedHighlight: selectedHighlight === key ? null : key
|
|
|
|
this.setState(({ selected }) => ({
|
|
|
|
|
|
|
|
selected: selected === highlight ? null : highlight
|
|
|
|
|
|
|
|
}))
|
|
|
|
}))
|
|
|
|
|
|
|
|
|
|
|
|
updateHighlight = ({ rgb }) =>
|
|
|
|
updateHighlights = updates =>
|
|
|
|
this.props.update({
|
|
|
|
this.setState(({ highlights }) => ({
|
|
|
|
highlights: {
|
|
|
|
highlights: {
|
|
|
|
...this.props.highlights,
|
|
|
|
...highlights,
|
|
|
|
[this.state.selected]: stringifyRGBA(rgb)
|
|
|
|
...updates
|
|
|
|
}
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
removeTheme = id => event => {
|
|
|
|
|
|
|
|
const { themes } = this.state
|
|
|
|
|
|
|
|
const { theme, update } = this.props
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
event.stopPropagation()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const newThemes = themes.filter(t => t.id !== id)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
saveThemes(localStorage, newThemes.filter(({ custom }) => custom))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (theme === id) {
|
|
|
|
|
|
|
|
update({ theme: DEFAULT_THEME.id, highlights: DEFAULT_THEME.highlights })
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
this.setState({ themes: newThemes })
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}))
|
|
|
|
|
|
|
|
|
|
|
|
createTheme = () => {
|
|
|
|
|
|
|
|
const { highlights, update } = this.props
|
|
|
|
|
|
|
|
const { themes, input: name } = this.state
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const id = `theme:${generateId()}`
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const newTheme = {
|
|
|
|
|
|
|
|
id,
|
|
|
|
|
|
|
|
name,
|
|
|
|
|
|
|
|
highlights,
|
|
|
|
|
|
|
|
custom: true
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const customThemes = [newTheme, ...themes.filter(({ custom }) => custom)]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
saveThemes(localStorage, customThemes)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
update({ theme: id })
|
|
|
|
create = theme => {
|
|
|
|
|
|
|
|
this.props.toggleVisibility()
|
|
|
|
|
|
|
|
this.props.create(theme)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
itemWrapper = props => <ThemeItem {...props} onClick={this.removeTheme} />
|
|
|
|
itemWrapper = props => <ThemeItem {...props} remove={this.props.remove} />
|
|
|
|
|
|
|
|
|
|
|
|
render() {
|
|
|
|
render() {
|
|
|
|
const { theme, isVisible, toggleVisibility, highlights } = this.props
|
|
|
|
const { themes, theme, isVisible, toggleVisibility } = this.props
|
|
|
|
const { input, themes, selected, preset } = this.state
|
|
|
|
const { input } = this.state
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const highlights = { ...theme.highlights, ...this.state.highlights }
|
|
|
|
|
|
|
|
|
|
|
|
const dropdownValue = isVisible ? { name: input } : { id: theme, name: this.selectedTheme.name }
|
|
|
|
const dropdownValue = isVisible ? { name: input } : { id: theme.id, name: theme.name }
|
|
|
|
|
|
|
|
|
|
|
|
const dropdownList = [
|
|
|
|
const dropdownList = [
|
|
|
|
{
|
|
|
|
{
|
|
|
@ -184,23 +118,16 @@ class Themes extends React.PureComponent {
|
|
|
|
selected={dropdownValue}
|
|
|
|
selected={dropdownValue}
|
|
|
|
list={dropdownList}
|
|
|
|
list={dropdownList}
|
|
|
|
itemWrapper={this.itemWrapper}
|
|
|
|
itemWrapper={this.itemWrapper}
|
|
|
|
onChange={this.handleChange}
|
|
|
|
onChange={this.handleThemeSelected}
|
|
|
|
onOpen={isVisible && toggleVisibility}
|
|
|
|
onOpen={isVisible && toggleVisibility}
|
|
|
|
/>
|
|
|
|
/>
|
|
|
|
{isVisible && (
|
|
|
|
{isVisible && (
|
|
|
|
<ThemeCreate
|
|
|
|
<ThemeCreate
|
|
|
|
key={theme}
|
|
|
|
|
|
|
|
preset={preset}
|
|
|
|
|
|
|
|
name={input}
|
|
|
|
|
|
|
|
theme={theme}
|
|
|
|
theme={theme}
|
|
|
|
themes={themes}
|
|
|
|
themes={themes}
|
|
|
|
highlights={highlights}
|
|
|
|
highlights={highlights}
|
|
|
|
selected={selected}
|
|
|
|
create={this.create}
|
|
|
|
applyPreset={this.applyPreset}
|
|
|
|
updateHighlights={this.updateHighlights}
|
|
|
|
createTheme={this.createTheme}
|
|
|
|
|
|
|
|
updateName={this.updateInput}
|
|
|
|
|
|
|
|
selectHighlight={this.selectHighlight}
|
|
|
|
|
|
|
|
updateHighlight={this.updateHighlight}
|
|
|
|
|
|
|
|
/>
|
|
|
|
/>
|
|
|
|
)}
|
|
|
|
)}
|
|
|
|
<style jsx>
|
|
|
|
<style jsx>
|
|
|
|