diff --git a/app/components/elements/ReplyEditor.jsx b/app/components/elements/ReplyEditor.jsx
index 88c74bdfd776a7e003cce344d8466446e320b41b..4aa5308e73cd9ead5350199f31ae3f5659b10606 100644
--- a/app/components/elements/ReplyEditor.jsx
+++ b/app/components/elements/ReplyEditor.jsx
@@ -117,8 +117,9 @@ class ReplyEditor extends React.Component {
             const {onCancel, resetForm} = this.props
             resetForm()
             this.setAutoVote()
-            this.setState({rte_value: stateFromHtml()})
-            this.refs.rte.reset()
+            //this.setState({rte_value: stateFromHtml()})
+            //this.refs.rte.reset()
+            this.refs.rte.setState({state: stateFromHtml()})
             if(onCancel) onCancel(e)
         }
         this.onChange = this.onChange.bind(this);
@@ -215,6 +216,7 @@ class ReplyEditor extends React.Component {
     // As rte_editor is updated, keep the (invisible) 'body' field in sync.
     onChange(rte_value) {
         //this.setState({rte_value})
+        this.refs.rte.setState({state: rte_value})
         const html = stateToHtml(rte_value)
         const body = this.props.fields.body
         if(body.value !== html) body.onChange(html);
diff --git a/app/components/elements/SlateEditor.jsx b/app/components/elements/SlateEditor.jsx
index 0666a0441fbe1e0c425bdc609d32aa2490dc05cf..b2a968459a4a53b1f5a0f2835fbe6d31506745f6 100644
--- a/app/components/elements/SlateEditor.jsx
+++ b/app/components/elements/SlateEditor.jsx
@@ -26,7 +26,7 @@ if(process.env.BROWSER) {
 
     plugins.push(
         InsertImages({
-            extensions: ['jpeg'],
+            extensions: ['jpeg', 'png', 'gif'],
             applyTransform: (transform, file) => {
                 return transform.insertInline({
                     type: 'image',
@@ -56,22 +56,29 @@ export default class SlateEditor extends React.Component {
 
     componentDidMount = () => {
         this.updateMenu()
+        this.updateSidebar()
     }
 
     componentDidUpdate = () => {
         this.updateMenu()
+        this.updateSidebar()
     }
 
     onChange = (state) => {
-        this.setState({ state })
+        //this.setState({ state })
         this.props.onChange(state)
     }
 
     // When the portal opens, cache the menu element.
-    onOpen = (portal) => {
+    onMenuOpen = (portal) => {
         this.setState({ menu: portal.firstChild })
     }
 
+    // When the portal opens, cache the menu element.
+    onSidebarOpen = (portal) => {
+        this.setState({ sidebar: portal.firstChild })
+    }
+
 
     // Check if the current selection has a mark with `type` in it.
     hasMark = (type) => {
@@ -295,7 +302,7 @@ console.log(JSON.stringify(Raw.serialize(state, {terse: false}), null, 2))
         const { startBlock, startOffset, endOffset } = state
 
         // Allow soft returns for certain block types
-        if (startBlock.type == 'code-block' || startBlock.type == 'block-quote') {
+        if (startBlock.type == 'paragraph' || startBlock.type == 'code-block' || startBlock.type == 'block-quote') {
             let transform = state.transform()
             if (state.isExpanded) transform = transform.delete()
             transform = transform.insertText('\n')
@@ -344,25 +351,82 @@ console.log(JSON.stringify(Raw.serialize(state, {terse: false}), null, 2))
         return (
             <div>
                 {this.renderMenu()}
+                {this.renderSidebar()}
                 {this.renderEditor()}
             </div>
         )
     }
 
+    renderSidebar = () => {
+        const { state } = this.state
+        const isOpen = state.isExpanded && state.isFocused
+        return (
+            <Portal isOpened onOpen={this.onSidebarOpen}>
+                <div className="SlateEditor__sidebar">
+                    {this.renderAddBlockButton({type: 'image', label: <Icon name="photo" />, handler: this.onClickInsertImage})}
+                    {this.renderAddBlockButton({type: 'hrule', label: <Icon name="line" />, handler: this.onClickInsertHr})}
+                </div>
+            </Portal>
+        )
+    }
+
+    onClickInsertImage = (e) => {
+        e.preventDefault()
+        let { state } = this.state
+
+        const src = window.prompt('Enter the URL of the image:', 'https://lh3.googleusercontent.com/-uY1D2XxBC5I/VbZbodsihNI/AAAAAAAAICw/glsw_avviBY/w592-h330/xkcdinternet.png')
+        if(!src) return;
+
+        state = state
+            .transform()
+            //.insertBlock({type: 'paragraph', isVoid: false})
+            .insertInline({type: 'image', isVoid: true, data: {src}})
+            .collapseToStartOfNextBlock()
+            .apply()
+
+        this.setState({ state })
+    }
+
+    onClickInsertHr = (e, type) => {
+        e.preventDefault()
+        let { state } = this.state
+
+        state = state
+            .transform()
+            .insertBlock({type: 'hr', isVoid: true})
+            .insertBlock({type: 'paragraph', isVoid: false})
+            .apply()
+
+        this.setState({ state })
+    }
+
+
+
+    renderAddBlockButton = (props) => {
+        const { type, label, handler } = props
+        const onMouseDown = e => handler(e)
+
+        return (
+            <span key={type} className="SlateEditor__sidebar-button" onMouseDown={onMouseDown}>
+                {label}
+            </span>
+        )
+    }
+
     renderMenu = () => {
         const { state } = this.state
         const isOpen = state.isExpanded && state.isFocused
 
         return (
-            <Portal isOpened onOpen={this.onOpen}>
+            <Portal isOpened onOpen={this.onMenuOpen}>
                 <div className="SlateEditor__menu SlateEditor__menu">
                     {schema.toolbarMarks.map(this.renderMarkButton)}
                     {this.renderInlineButton({type: 'link', label: <Icon name="link" />})}
                     {this.renderBlockButton({type: 'block-quote', label: <span>&ldquo;</span>})}
                     {this.renderBlockButton({type: 'heading-one', label: 'H1'})}
                     {this.renderBlockButton({type: 'heading-two', label: 'H2'})}
-                    {this.renderBlockButton({type: 'bulleted-list', label: 'ul'})}
-                    {this.renderBlockButton({type: 'numbered-list', label: 'ol'})}
+                    {/*this.renderBlockButton({type: 'bulleted-list', label: 'ul'})*/}
+                    {/*this.renderBlockButton({type: 'numbered-list', label: 'ol'})*/}
                     {this.renderBlockButton({type: 'code-block', label: '<>'})}
                 </div>
             </Portal>
@@ -420,6 +484,42 @@ console.log(JSON.stringify(Raw.serialize(state, {terse: false}), null, 2))
         )
     }
 
+    findParentTag = (el, tag, depth = 0) => {
+        if (!el) return null;
+        if (el.tagName == tag) return el;
+        return this.findParentTag(el.parentNode, tag, depth + 1);
+    }
+
+    getCollapsedClientRect = () => {
+        const selection = document.getSelection();
+        if (selection.rangeCount === 0 || !selection.getRangeAt || !selection.getRangeAt(0) || !selection.getRangeAt(0).startContainer || !selection.getRangeAt(0).startContainer.getBoundingClientRect) {
+            return null;
+        }
+
+        const node = selection.getRangeAt(0).startContainer;
+        if(! this.findParentTag(node, 'P')) return; // only show sidebar at the beginning of an empty <p>
+
+        const rect = node.getBoundingClientRect();
+        return rect;
+    }
+
+    updateSidebar = () => {
+        const { sidebar, state } = this.state
+        if (!sidebar) return
+
+        const rect = this.getCollapsedClientRect() //position()
+
+        if (state.isBlurred || state.isExpanded || !rect) {
+          sidebar.removeAttribute('style')
+          return
+        }
+
+        //sidebar.style.opacity = 1
+        sidebar.style.top = `${rect.top + window.scrollY}px`
+        //sidebar.style.top = `${rect.top + window.scrollY - sidebar.offsetHeight / 2 + rect.height / 2}px`
+        sidebar.style.left = `${rect.left + window.scrollX - sidebar.offsetWidth}px`
+    }
+
     updateMenu = () => {
         const { menu, state } = this.state
         if (!menu) return
@@ -430,7 +530,7 @@ console.log(JSON.stringify(Raw.serialize(state, {terse: false}), null, 2))
         }
 
         const rect = position()
-        menu.style.opacity = 1
+        //menu.style.opacity = 1
         menu.style.top = `${rect.top + window.scrollY - menu.offsetHeight}px`
         menu.style.left = `${rect.left + window.scrollX - menu.offsetWidth / 2 + rect.width / 2}px`
     }
diff --git a/app/components/elements/SlateEditor.scss b/app/components/elements/SlateEditor.scss
index 9f616277d4d42a448bb50bb55f6a8d128fdfa787..e8ffdd07e77ddfb0136dee8181c80844200f71bc 100644
--- a/app/components/elements/SlateEditor.scss
+++ b/app/components/elements/SlateEditor.scss
@@ -1,45 +1,99 @@
-.SlateEditor {
-  //padding: 1rem;
-  //border: 1px solid $medium-gray;
-  //border-radius: 8px;
-}
-
 .SlateEditor.Markdown {
   a {
     border-bottom: 1px dotted #00f;
     position: relative;
     img {border: 1px dotted #00f}
   }
-  .active {
-    box-shadow: 0 0 0 2px blue;
-  }
+  .active {box-shadow: 0 0 0 2px blue;}
+  hr.active {box-shadow: 0 0 0 1px blue;}
 
   a:hover:after{
-      border: 1px solid #ccc;
-      padding: 1px 3px;
-      background: #eee;
-      content: attr(href);
-      display: block;
-      position: absolute;
-      left: 0;
-      top: 110%;
-      line-height: 1;
-      white-space: nowrap;
-      font-size: 70%;
-      z-index: 99999;
+    border: 1px solid #ccc;
+    padding: 1px 3px;
+    background: #eee;
+    content: attr(href);
+    display: block;
+    position: absolute;
+    left: 0;
+    top: 110%;
+    line-height: 1;
+    white-space: nowrap;
+    font-size: 70%;
+    z-index: 99999;
   }
 }
 
-.SlateEditor > * > * + * {
-  margin-top: 1em;
+
+.SlateEditor__sidebar {
+  opacity: 0.25;
+  font-size: 110%;
+  padding: 1px;
+  position: absolute;
+  z-index: 1;
+  top: -10000px;
+  left: -10000px;
+  margin-left: -10px;
+  background-color: #222;
+  border-radius: 4px;
+  transition: opacity .75s;
+  background-image: linear-gradient(180deg,#464646,#151515);
+
+  &:hover {opacity: 1;}
+  &:after {
+    top: 0.6rem;
+    left: 100%;
+    border: transparent solid;
+    content: " ";
+    height: 0;
+    width: 0;
+    position: absolute;
+    pointer-events: none;
+    border-left-color: #464646;
+    border-width: 5px;
+    margin-left: 0px;
+  }
 }
 
-.SlateEditor__menu > * {
-  display: inline-block;
+.SlateEditor__sidebar-button {
+  display: block;
+  color: white;
+  padding: 1px 2px;
+  min-width: 1.75rem;
+  text-align: center;
+  svg {fill: white}
+  &:hover {svg {fill: #32cd32;}}
 }
 
-.SlateEditor__menu > * + * {
-  margin: 0;
+
+.SlateEditor__menu {
+  font-size: 110%;
+  padding: 1px;
+  position: absolute;
+  z-index: 1;
+  top: -10000px;
+  left: -10000px;
+  margin-top: -6px;
+  opacity: 0.9;
+  background-color: #222;
+  border-radius: 4px;
+  transition: opacity .75s;
+  background-image: linear-gradient(180deg,#464646,#151515);
+
+  &:hover {opacity: 1}
+  &:after {
+    top: 100%;
+    left: 50%;
+    border: solid transparent;
+    content: " ";
+    height: 0;
+    width: 0;
+    position: absolute;
+    pointer-events: none;
+    border-top-color: #151515;
+    border-width: 5px;
+    margin-left: -5px;
+  }
+  > * {display: inline-block;}
 }
 
 .SlateEditor__menu-button {
@@ -53,14 +107,6 @@
   background: rgba(0,0,0,0.1);
   border-radius: 2px;
   > span {
-    code {
-      border: none;
-      background: transparent;
-      color: inherit;
-      padding: 0;
-      font-size: 90%;
-      vertical-align: top;
-    }
     path {fill: white}
   }
 }
@@ -74,50 +120,30 @@
   }
 }
 
-.SlateEditor__menu-button-sup span,
-.SlateEditor__menu-button-sub span {
-  font-family: Arial;
+.SlateEditor__menu-button-code > span > code {
+  border: none;
+  background: transparent;
+  color: inherit;
+  padding: 0;
   font-size: 90%;
-  vertical-align: 4%;
+  vertical-align: top;
 }
 
-.SlateEditor__menu-button-link {
-  .Icon > svg, .Icon {width: 1rem; height: 1rem;}
+.SlateEditor__menu-button-sup > span > span ,
+.SlateEditor__menu-button-sub > span > span {
+  font-family: Arial;
+  font-size: 80%;
+  vertical-align: 4%;
 }
 
-.SlateEditor__menu-button-block-quote {
-  span {
-    font-size: 140%;
-    vertical-align: -25%;
-    line-height: 1;
-  }
+.SlateEditor__menu-button-link {
+  .Icon,
+  .Icon > svg {width: 1rem; height: 1rem;}
 }
 
-.SlateEditor__menu {
-  font-size: 110%;
-  padding: 1px;
-  position: absolute;
-  z-index: 1;
-  top: -10000px;
-  left: -10000px;
-  margin-top: -6px;
-  opacity: 0;
-  background-color: #222;
-  border-radius: 4px;
-  transition: opacity .75s;
-  background-image: linear-gradient(180deg,#464646,#151515);
+.SlateEditor__menu-button-block-quote > span > span {
+  font-size: 220%;
+  vertical-align: -45%;
+  line-height: 1;
 }
 
-.SlateEditor__menu:after {
-    top: 100%;
-    left: 50%;
-    border: solid transparent;
-    content: " ";
-    height: 0;
-    width: 0;
-    position: absolute;
-    pointer-events: none;
-    border-top-color: #151515;
-    border-width: 5px;
-    margin-left: -5px;
-}