simplify theme state logic

main
Mike Fix 6 years ago committed by Michael Fix
parent 132c0f6d5a
commit 0db4a89e72

@ -76,7 +76,7 @@ class Carbon extends React.PureComponent {
const options = { const options = {
lineNumbers: config.lineNumbers, lineNumbers: config.lineNumbers,
mode: languageMode || 'plaintext', mode: languageMode || 'plaintext',
theme: config.theme.id, theme: config.theme,
scrollBarStyle: null, scrollBarStyle: null,
viewportMargin: Infinity, viewportMargin: Infinity,
lineWrapping: true, lineWrapping: true,

@ -46,7 +46,6 @@ class Editor extends React.Component {
super(props) super(props)
this.state = { this.state = {
...DEFAULT_SETTINGS, ...DEFAULT_SETTINGS,
themes: THEMES,
preset: DEFAULT_PRESET_ID, preset: DEFAULT_PRESET_ID,
loading: true loading: true
} }
@ -83,27 +82,12 @@ class Editor extends React.Component {
loading: false loading: false
} }
const storedThemes = getThemes(localStorage) || []
newState.themes = [...storedThemes, ...this.state.themes]
if (newState.theme) {
newState.theme = newState.themes.find(t => t.id === newState.theme) || DEFAULT_THEME
}
if (newState.highlights) {
newState.theme = {
...newState.theme,
highlights: newState.highlights
}
}
// Makes sure the slash in 'application/X' is decoded // Makes sure the slash in 'application/X' is decoded
if (newState.language) { if (newState.language) {
newState.language = unescapeHtml(newState.language) newState.language = unescapeHtml(newState.language)
} }
this.updateState(omit(newState, ['highlights'])) this.updateState(newState)
this.isSafari = this.isSafari =
window.navigator && window.navigator &&
@ -116,10 +100,7 @@ class Editor extends React.Component {
updateState = updates => { updateState = updates => {
this.setState(updates, () => { this.setState(updates, () => {
if (!this.gist) { if (!this.gist) {
this.props.onUpdate({ this.props.onUpdate(this.state)
...this.state,
theme: this.state.theme.id
})
} }
}) })
} }
@ -137,14 +118,7 @@ class Editor extends React.Component {
// if safari, get image from api // if safari, get image from api
const isPNG = format !== 'svg' const isPNG = format !== 'svg'
if (this.context.image && this.isSafari && isPNG) { if (this.context.image && this.isSafari && isPNG) {
const state = { const encodedState = serializeState(this.state)
...this.state,
theme: this.state.theme.id,
highlights: this.state.theme.highlights
}
const encodedState = serializeState(omit(state, ['themes']))
return this.context.image(encodedState) return this.context.image(encodedState)
} }
@ -289,33 +263,18 @@ class Editor extends React.Component {
updateTheme = theme => this.updateState({ theme }) updateTheme = theme => this.updateState({ theme })
createTheme = theme => createTheme = theme => {
this.setState(({ themes }) => { this.props.updateThemes(themes => [theme, ...themes])
const newThemes = [theme, ...themes] this.updateTheme(theme.id)
saveThemes(localStorage, newThemes.filter(({ custom }) => custom))
return {
theme,
themes: newThemes
} }
})
removeTheme = id => removeTheme = id => {
this.setState(({ themes, theme }) => { this.props.updateThemes(themes => themes.filter(t => t.id !== id))
const newState = { if (this.state.theme.id === id) {
themes: themes.filter(t => t.id !== id) this.updateTheme(DEFAULT_THEME.id)
} }
saveThemes(localStorage, newState.themes.filter(({ custom }) => custom))
if (theme.id === id) {
newState.theme = DEFAULT_THEME
} }
return newState
})
format = () => format = () =>
formatCode(this.state.code) formatCode(this.state.code)
.then(this.updateCode) .then(this.updateCode)
@ -326,7 +285,6 @@ class Editor extends React.Component {
render() { render() {
const { const {
theme, theme,
themes,
language, language,
backgroundColor, backgroundColor,
backgroundImage, backgroundImage,
@ -345,7 +303,8 @@ class Editor extends React.Component {
remove={this.removeTheme} remove={this.removeTheme}
create={this.createTheme} create={this.createTheme}
theme={theme} theme={theme}
themes={themes} themes={this.props.themes}
router={this.props.router}
/> />
<Dropdown <Dropdown
icon={languageIcon} icon={languageIcon}
@ -432,4 +391,21 @@ Editor.defaultProps = {
onReset: () => {} onReset: () => {}
} }
export default Editor function ThemesContainer(props) {
const [themes, updateThemes] = React.useState(THEMES)
React.useEffect(() => {
const storedThemes = getThemes(localStorage) || []
if (storedThemes) {
updateThemes(currentThemes => [...storedThemes, ...currentThemes])
}
}, [])
React.useEffect(() => {
saveThemes(localStorage, themes.filter(({ custom }) => custom))
}, [themes])
return <Editor {...props} themes={themes} updateThemes={updateThemes} />
}
export default ThemesContainer

@ -53,6 +53,8 @@ const getCustomName = themes =>
const ThemeCreate = ({ theme, themes, highlights, create, updateHighlights }) => { const ThemeCreate = ({ theme, themes, highlights, create, updateHighlights }) => {
const [preset, updatePreset] = React.useState(theme.id) const [preset, updatePreset] = React.useState(theme.id)
const [highlight, selectHighlight] = React.useState() const [highlight, selectHighlight] = React.useState()
// TODO consider using an uncontrolled input
const [name, updateName] = React.useState(getCustomName(themes)) const [name, updateName] = React.useState(getCustomName(themes))
return ( return (

@ -5,7 +5,8 @@ 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 { COLORS } from '../../lib/constants' import { COLORS, DEFAULT_THEME } from '../../lib/constants'
import { getRouteState } from '../../lib/routing'
const ThemeCreate = dynamic(() => import('./ThemeCreate'), { const ThemeCreate = dynamic(() => import('./ThemeCreate'), {
loading: () => null loading: () => null
@ -52,12 +53,24 @@ class Themes extends React.PureComponent {
highlights: {} highlights: {}
} }
componentDidMount() {
// TODO consider just using withRouter directly
const { queryState } = getRouteState(this.props.router)
if (queryState.highlights) {
this.updateHighlights(queryState.highlights)
}
}
dropdown = React.createRef() dropdown = React.createRef()
static getDerivedStateFromProps(props) { static getDerivedStateFromProps(props) {
if (!props.isVisible) { if (!props.isVisible) {
// TODO use shared function for this next line
const themeConfig =
(props.themes && props.themes.find(t => t.id === props.theme)) || DEFAULT_THEME
return { return {
highlights: {} highlights: themeConfig.highlights
} }
} }
return null return null
@ -69,7 +82,7 @@ class Themes extends React.PureComponent {
toggleVisibility() toggleVisibility()
this.dropdown.current.closeMenu() this.dropdown.current.closeMenu()
} else { } else {
update(theme) update(theme.id)
} }
} }
@ -90,10 +103,11 @@ class Themes extends React.PureComponent {
render() { render() {
const { themes, theme, isVisible, toggleVisibility } = this.props const { themes, theme, isVisible, toggleVisibility } = this.props
const { highlights } = this.state
const highlights = { ...theme.highlights, ...this.state.highlights } const themeConfig = themes.find(t => t.id === theme) || DEFAULT_THEME
const dropdownValue = isVisible ? { name: '' } : { id: theme.id, name: theme.name } const dropdownValue = isVisible ? { name: '' } : { id: themeConfig.id, name: themeConfig.name }
const dropdownList = [ const dropdownList = [
{ {
@ -118,7 +132,7 @@ class Themes extends React.PureComponent {
/> />
{isVisible && ( {isVisible && (
<ThemeCreate <ThemeCreate
theme={theme} theme={themeConfig}
themes={themes} themes={themes}
highlights={highlights} highlights={highlights}
create={this.create} create={this.create}

@ -26,7 +26,7 @@ class Index extends React.Component {
updateRouteState(this.props.router, state) updateRouteState(this.props.router, state)
saveSettings( saveSettings(
localStorage, localStorage,
omit(state, ['code', 'backgroundImage', 'backgroundImageSelection', 'themes']) omit(state, ['code', 'backgroundImage', 'backgroundImageSelection', 'themes', 'highlights'])
) )
}, },
750, 750,

Loading…
Cancel
Save