diff --git a/components/Editor.js b/components/Editor.js index 518869b..a7a4c34 100644 --- a/components/Editor.js +++ b/components/Editor.js @@ -45,13 +45,13 @@ class Editor extends React.Component { this.state = { ...DEFAULT_SETTINGS, preset: DEFAULT_PRESET_ID, + highlights: {}, loading: true } this.export = this.export.bind(this) this.upload = this.upload.bind(this) this.updateSetting = this.updateSetting.bind(this) - this.updateTheme = this.updateTheme.bind(this) this.updateLanguage = this.updateLanguage.bind(this) this.updateBackground = this.updateBackground.bind(this) this.resetDefaultSettings = this.resetDefaultSettings.bind(this) @@ -86,7 +86,7 @@ class Editor extends React.Component { newState.language = unescapeHtml(newState.language) } - this.updateState(newState) + this.setState(newState) this.isSafari = window.navigator && @@ -112,7 +112,8 @@ class Editor extends React.Component { // if safari, get image from api const isPNG = format !== 'svg' if (this.context.image && this.isSafari && isPNG) { - const encodedState = serializeState(this.state) + const { highlights, ...state } = this.state + const encodedState = serializeState({ ...state, ...highlights }) return this.context.image(encodedState) } @@ -239,10 +240,6 @@ class Editor extends React.Component { } } - updateTheme(theme) { - this.updateSetting('theme', theme) - } - updateLanguage(language) { this.updateSetting('language', language.mime || language.mode) } @@ -271,6 +268,7 @@ class Editor extends React.Component { render() { const { theme, + highlights, language, backgroundColor, backgroundImage, @@ -284,7 +282,13 @@ class Editor extends React.Component { return (
- + import('./ThemeCreate'), { loading: () => null @@ -40,13 +42,15 @@ const ThemeItem = ({ children, item, isSelected, onClick }) => ( const themeIcon = +const getCustomName = themes => + `Custom Theme ${themes.filter(({ name }) => name.startsWith('Custom Theme')).length + 1}` + class Themes extends React.PureComponent { selectedTheme = DEFAULT_THEME state = { themes: THEMES, preset: this.props.theme, - highlights: {}, name: 'Custom Theme', selected: null } @@ -54,36 +58,67 @@ class Themes extends React.PureComponent { dropdown = React.createRef() componentDidMount() { + const { queryState } = getRouteState(this.props.router) + + const queryHighlights = queryState + ? Object.keys(queryState) + .filter(key => HIGHLIGHT_KEYS.includes(key)) + .reduce((obj, key) => ({ ...obj, [key]: queryState[key] }), {}) + : {} + const storedThemes = getThemes(localStorage) || [] this.setState(({ themes }) => { const newThemes = [...storedThemes, ...themes] - const name = `Custom Theme ${newThemes.filter(({ name }) => name.startsWith('Custom Theme')) - .length + 1}` + const name = getCustomName(newThemes) this.selectedTheme = newThemes.find(({ id }) => id === this.props.theme) || DEFAULT_THEME + const highlights = { + ...this.selectedTheme.highlights, + ...queryHighlights + } + + this.props.onChange('highlights', highlights) + return { themes: newThemes, - highlights: this.selectedTheme.highlights, + highlights, name } }) } - applyPreset = preset => - this.setState(({ themes }) => ({ - preset, - highlights: themes.find(({ id }) => id === preset).highlights - })) + componentDidUpdate(prevProps) { + const { isVisible, theme, onChange } = this.props + const { themes } = this.state + + if (prevProps.isVisible && !isVisible) { + this.setState({ name: getCustomName(themes) }) + onChange('highlights', themes.find(({ id }) => id === theme).highlights) + } + } + + applyPreset = preset => { + this.setState(({ themes }) => { + this.props.onChange('highlights', themes.find(({ id }) => id === preset).highlights) + return { + preset + } + }) + } handleChange = ({ id }) => { + const { theme, toggleVisibility, onChange } = this.props + const { themes } = this.state + if (id === 'create') { - this.props.toggleVisibility() + toggleVisibility() this.dropdown.current.closeMenu() } else { - this.props.updateTheme(id) + onChange('theme', id) + onChange('highlights', themes.find(({ id }) => id === theme).highlights) } } @@ -95,11 +130,9 @@ class Themes extends React.PureComponent { })) updateHighlight = ({ rgb }) => - this.setState({ - highlights: { - ...this.state.highlights, - [this.state.selected]: stringifyRGBA(rgb) - } + this.props.onChange('highlights', { + ...this.props.highlights, + [this.state.selected]: stringifyRGBA(rgb) }) removeTheme = id => event => { @@ -112,14 +145,16 @@ class Themes extends React.PureComponent { saveThemes(localStorage, newThemes.filter(({ custom }) => custom)) if (this.props.theme === id) { - this.props.updateTheme(DEFAULT_THEME.id) + this.props.onChange('theme', DEFAULT_THEME.id) + this.props.onChange('highlights', DEFAULT_THEME.highlights) } else { this.setState({ themes: newThemes }) } } createTheme = () => { - const { themes, name, highlights } = this.state + const { highlights } = this.props + const { themes, name } = this.state const id = `theme:${generateId()}` @@ -134,14 +169,14 @@ class Themes extends React.PureComponent { saveThemes(localStorage, customThemes) - this.props.updateTheme(id) + this.props.onChange('theme', id) } itemWrapper = props => render() { - const { theme, isVisible, toggleVisibility } = this.props - const { name, themes, highlights, selected, preset } = this.state + const { theme, isVisible, toggleVisibility, highlights } = this.props + const { name, themes, selected, preset } = this.state const dropdownValue = isVisible ? { name } : { id: theme, name: this.selectedTheme.name } @@ -255,4 +290,4 @@ class Themes extends React.PureComponent { } } -export default managePopout(Themes) +export default managePopout(withRouter(Themes)) diff --git a/lib/routing.js b/lib/routing.js index f4948f5..5b7022d 100644 --- a/lib/routing.js +++ b/lib/routing.js @@ -35,7 +35,19 @@ const mappings = [ { field: 'wm:watermark', type: 'bool' }, { field: 'copy', type: 'bool' }, { field: 'readonly', type: 'bool' }, - { field: 'id' } + { field: 'id' }, + { field: 'text' }, + { field: 'meta' }, + { field: 'tbg:background' }, + { field: 'var:variable' }, + { field: 'attr:attribute' }, + { field: 'def:definition' }, + { field: 'kw:keyword' }, + { field: 'op:operator' }, + { field: 'prop:property' }, + { field: 'num:number' }, + { field: 'str:string' }, + { field: 'cmt:comment' } ] const reverseMappings = mappings.map(mapping =>