diff --git a/components/Carbon.js b/components/Carbon.js
index b899a50..5d0fd80 100644
--- a/components/Carbon.js
+++ b/components/Carbon.js
@@ -12,7 +12,6 @@ import {
LANGUAGE_MODE_HASH,
LANGUAGE_NAME_HASH,
LANGUAGE_MIME_HASH,
- THEMES_HASH,
DEFAULT_SETTINGS
} from '../lib/constants'
@@ -77,7 +76,7 @@ class Carbon extends React.PureComponent {
const options = {
lineNumbers: config.lineNumbers,
mode: languageMode || 'plaintext',
- theme: config.theme,
+ theme: config.theme.id,
scrollBarStyle: null,
viewportMargin: Infinity,
lineWrapping: true,
@@ -108,7 +107,7 @@ class Carbon extends React.PureComponent {
value={this.props.children}
options={options}
/>
- {config.watermark && }
+ {config.watermark && }
diff --git a/components/Editor.js b/components/Editor.js
index cbec0f8..c0b396e 100644
--- a/components/Editor.js
+++ b/components/Editor.js
@@ -25,10 +25,12 @@ import {
DEFAULT_CODE,
DEFAULT_SETTINGS,
DEFAULT_LANGUAGE,
- DEFAULT_PRESET_ID
+ DEFAULT_PRESET_ID,
+ DEFAULT_THEME,
+ THEMES
} from '../lib/constants'
import { serializeState, getRouteState } from '../lib/routing'
-import { getSettings, unescapeHtml, formatCode, omit } from '../lib/util'
+import { getThemes, saveThemes, getSettings, unescapeHtml, formatCode, omit } from '../lib/util'
import LanguageIcon from './svg/Language'
const languageIcon =
@@ -44,8 +46,8 @@ class Editor extends React.Component {
super(props)
this.state = {
...DEFAULT_SETTINGS,
+ themes: THEMES,
preset: DEFAULT_PRESET_ID,
- highlights: {},
loading: true
}
@@ -81,6 +83,25 @@ class Editor extends React.Component {
loading: false
}
+ const storedThemes = getThemes(localStorage)
+
+ newState.themes = storedThemes
+ ? [...storedThemes, ...this.state.themes]
+ : [...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
+ }
+
+ delete newState.highlights
+ }
+
// Makes sure the slash in 'application/X' is decoded
if (newState.language) {
newState.language = unescapeHtml(newState.language)
@@ -99,7 +120,10 @@ class Editor extends React.Component {
updateState = updates => {
this.setState(updates, () => {
if (!this.gist) {
- this.props.onUpdate(this.state)
+ this.props.onUpdate({
+ ...this.state,
+ theme: this.state.theme.id
+ })
}
})
}
@@ -117,7 +141,16 @@ 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 state = {
+ ...this.state,
+ theme: this.state.theme.id,
+ highlights: this.state.theme.highlights
+ }
+
+ delete state.themes
+
+ const encodedState = serializeState(state)
+
return this.context.image(encodedState)
}
@@ -260,6 +293,35 @@ 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
+ }
+
+ return newState
+ })
+
format = () =>
formatCode(this.state.code)
.then(this.updateCode)
@@ -267,12 +329,10 @@ class Editor extends React.Component {
// create toast here in the future
})
- applyPreset = ({ id: preset, ...settings }) => this.updateState({ preset, ...settings })
-
render() {
const {
theme,
- highlights,
+ themes,
language,
backgroundColor,
backgroundImage,
@@ -286,7 +346,13 @@ class Editor extends React.Component {
return (
-
+
(
)
-const ThemeCreate = ({
- theme,
- themes,
- highlights,
- name,
- preset,
- selected,
- createTheme,
- applyPreset,
- updateName,
- selectHighlight,
- updateHighlight
-}) => (
-
-
-
- Name
-
-
-
-
+ `Custom Theme ${themes.filter(({ name }) => name.startsWith('Custom Theme')).length + 1}`
+
+const ThemeCreate = ({ theme, themes, highlights, create, updateHighlights }) => {
+ const [preset, updatePreset] = React.useState(theme.id)
+ const [highlight, selectHighlight] = React.useState()
+ const [name, updateName] = React.useState(getCustomName(themes))
+
+ return (
+
+
+
+ Name
+ updateName(value)}
+ maxLength="32"
+ />
+
+
+ selectHighlight(null)}
+ onChange={id => {
+ updatePreset(id)
+ updateHighlights(themes.find(t => t.id === id).highlights)
+ }}
+ >
+ {({ name }) => {name}}
+
+
+
+ {HIGHLIGHT_KEYS.map(key => (
+
+
+
+ ))}
+
+
-
- {HIGHLIGHT_KEYS.map(key => (
-
-
-
- ))}
+ Create +
+
-
-
- {selected && (
-
- )}
-
-
-)
+ {highlight && (
+
updateHighlights({ [highlight]: stringifyRGBA(rgb) })}
+ />
+ )}
+
+
+ )
+}
export default ThemeCreate
diff --git a/components/Themes/index.js b/components/Themes/index.js
index 9e4348b..b77edf6 100644
--- a/components/Themes/index.js
+++ b/components/Themes/index.js
@@ -5,18 +5,25 @@ import Dropdown from '../Dropdown'
import { managePopout } from '../Popout'
import ThemeIcon from '../svg/Theme'
import RemoveIcon from '../svg/Remove'
-import { THEMES, COLORS, DEFAULT_THEME } from '../../lib/constants'
-import { getThemes, saveThemes, stringifyRGBA, generateId } from '../../lib/util'
+import { COLORS } from '../../lib/constants'
const ThemeCreate = dynamic(() => import('./ThemeCreate'), {
loading: () => null
})
-const ThemeItem = ({ children, item, isSelected, onClick }) => (
+const ThemeItem = ({ children, item, isSelected, remove }) => (
{children}
{item.custom && !isSelected && (
-
+
{
+ e.stopPropagation()
+ remove(item.id)
+ }}
+ >
)}
@@ -40,131 +47,58 @@ 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,
- input: 'Custom Theme',
- selected: null
+ highlights: {}
}
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) {
- const { isVisible, theme, update } = this.props
- const { themes } = this.state
-
- if (prevProps.isVisible && !isVisible) {
- this.setState({ input: getCustomName(themes) })
- update({ highlights: themes.find(({ id }) => id === theme).highlights })
+ if (prevProps.isVisible && !this.props.isVisible) {
+ this.setState({
+ 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 { themes } = this.state
-
- if (id === 'create') {
+ if (theme.id === 'create') {
toggleVisibility()
this.dropdown.current.closeMenu()
} else {
- update({ theme: id, highlights: themes.find(theme => theme.id === id).highlights })
+ update(theme)
}
}
- updateInput = ({ target: { value: input } }) => this.setState({ input })
-
- selectHighlight = highlight => () =>
- this.setState(({ selected }) => ({
- selected: selected === highlight ? null : highlight
+ selectHighlight = key => () =>
+ this.setState(({ selectedHighlight }) => ({
+ selectedHighlight: selectedHighlight === key ? null : key
}))
- updateHighlight = ({ rgb }) =>
- this.props.update({
+ updateHighlights = updates =>
+ this.setState(({ highlights }) => ({
highlights: {
- ...this.props.highlights,
- [this.state.selected]: stringifyRGBA(rgb)
+ ...highlights,
+ ...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 =>
+ itemWrapper = props =>
render() {
- const { theme, isVisible, toggleVisibility, highlights } = this.props
- const { input, themes, selected, preset } = this.state
+ const { themes, theme, isVisible, toggleVisibility } = this.props
+ 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 = [
{
@@ -184,23 +118,16 @@ class Themes extends React.PureComponent {
selected={dropdownValue}
list={dropdownList}
itemWrapper={this.itemWrapper}
- onChange={this.handleChange}
+ onChange={this.handleThemeSelected}
onOpen={isVisible && toggleVisibility}
/>
{isVisible && (
)}