From 0db4a89e72c0c5423b9e7dd22470ee19667daba1 Mon Sep 17 00:00:00 2001 From: Mike Fix Date: Sun, 14 Apr 2019 14:36:50 -0700 Subject: [PATCH] simplify theme state logic --- components/Carbon.js | 2 +- components/Editor.js | 90 ++++++++++++-------------------- components/Themes/ThemeCreate.js | 2 + components/Themes/index.js | 26 ++++++--- pages/index.js | 2 +- 5 files changed, 57 insertions(+), 65 deletions(-) diff --git a/components/Carbon.js b/components/Carbon.js index 5ca8ea7..3f5f489 100644 --- a/components/Carbon.js +++ b/components/Carbon.js @@ -76,7 +76,7 @@ class Carbon extends React.PureComponent { const options = { lineNumbers: config.lineNumbers, mode: languageMode || 'plaintext', - theme: config.theme.id, + theme: config.theme, scrollBarStyle: null, viewportMargin: Infinity, lineWrapping: true, diff --git a/components/Editor.js b/components/Editor.js index d0705cb..4720661 100644 --- a/components/Editor.js +++ b/components/Editor.js @@ -46,7 +46,6 @@ class Editor extends React.Component { super(props) this.state = { ...DEFAULT_SETTINGS, - themes: THEMES, preset: DEFAULT_PRESET_ID, loading: true } @@ -83,27 +82,12 @@ class Editor extends React.Component { 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 if (newState.language) { newState.language = unescapeHtml(newState.language) } - this.updateState(omit(newState, ['highlights'])) + this.updateState(newState) this.isSafari = window.navigator && @@ -116,10 +100,7 @@ class Editor extends React.Component { updateState = updates => { this.setState(updates, () => { if (!this.gist) { - this.props.onUpdate({ - ...this.state, - theme: this.state.theme.id - }) + this.props.onUpdate(this.state) } }) } @@ -137,14 +118,7 @@ class Editor extends React.Component { // if safari, get image from api const isPNG = format !== 'svg' if (this.context.image && this.isSafari && isPNG) { - const state = { - ...this.state, - theme: this.state.theme.id, - highlights: this.state.theme.highlights - } - - const encodedState = serializeState(omit(state, ['themes'])) - + const encodedState = serializeState(this.state) return this.context.image(encodedState) } @@ -289,32 +263,17 @@ class Editor extends React.Component { updateTheme = theme => this.updateState({ theme }) - createTheme = theme => - this.setState(({ themes }) => { - const newThemes = [theme, ...themes] - - saveThemes(localStorage, newThemes.filter(({ custom }) => custom)) - - return { - theme, - themes: newThemes - } - }) - - removeTheme = id => - this.setState(({ themes, theme }) => { - const newState = { - themes: themes.filter(t => t.id !== id) - } - - saveThemes(localStorage, newState.themes.filter(({ custom }) => custom)) - - if (theme.id === id) { - newState.theme = DEFAULT_THEME - } + createTheme = theme => { + this.props.updateThemes(themes => [theme, ...themes]) + this.updateTheme(theme.id) + } - return newState - }) + removeTheme = id => { + this.props.updateThemes(themes => themes.filter(t => t.id !== id)) + if (this.state.theme.id === id) { + this.updateTheme(DEFAULT_THEME.id) + } + } format = () => formatCode(this.state.code) @@ -326,7 +285,6 @@ class Editor extends React.Component { render() { const { theme, - themes, language, backgroundColor, backgroundImage, @@ -345,7 +303,8 @@ class Editor extends React.Component { remove={this.removeTheme} create={this.createTheme} theme={theme} - themes={themes} + themes={this.props.themes} + router={this.props.router} /> {} } -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 +} + +export default ThemesContainer diff --git a/components/Themes/ThemeCreate.js b/components/Themes/ThemeCreate.js index 89cce96..ff8a2df 100644 --- a/components/Themes/ThemeCreate.js +++ b/components/Themes/ThemeCreate.js @@ -53,6 +53,8 @@ const getCustomName = themes => const ThemeCreate = ({ theme, themes, highlights, create, updateHighlights }) => { const [preset, updatePreset] = React.useState(theme.id) const [highlight, selectHighlight] = React.useState() + + // TODO consider using an uncontrolled input const [name, updateName] = React.useState(getCustomName(themes)) return ( diff --git a/components/Themes/index.js b/components/Themes/index.js index 7952f15..87d590c 100644 --- a/components/Themes/index.js +++ b/components/Themes/index.js @@ -5,7 +5,8 @@ import Dropdown from '../Dropdown' import { managePopout } from '../Popout' import ThemeIcon from '../svg/Theme' 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'), { loading: () => null @@ -52,12 +53,24 @@ class Themes extends React.PureComponent { highlights: {} } + componentDidMount() { + // TODO consider just using withRouter directly + const { queryState } = getRouteState(this.props.router) + + if (queryState.highlights) { + this.updateHighlights(queryState.highlights) + } + } + dropdown = React.createRef() static getDerivedStateFromProps(props) { 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 { - highlights: {} + highlights: themeConfig.highlights } } return null @@ -69,7 +82,7 @@ class Themes extends React.PureComponent { toggleVisibility() this.dropdown.current.closeMenu() } else { - update(theme) + update(theme.id) } } @@ -90,10 +103,11 @@ class Themes extends React.PureComponent { render() { 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 = [ { @@ -118,7 +132,7 @@ class Themes extends React.PureComponent { /> {isVisible && (