diff --git a/resources/js/editor/markdown-serializer.js b/resources/js/editor/markdown-serializer.js index c194ceaf7..5e1dfb33b 100644 --- a/resources/js/editor/markdown-serializer.js +++ b/resources/js/editor/markdown-serializer.js @@ -30,6 +30,20 @@ marks.subscript = { close: '', }; +marks.text_color = { + open(state, mark, parent, index) { + return `` + }, + close: '', +}; + +marks.background_color = { + open(state, mark, parent, index) { + return `` + }, + close: '', +}; + function writeNodeAsHtml(state, node) { const html = docToHtml({ content: [node] }); @@ -43,11 +57,11 @@ function writeNodeAsHtml(state, node) { // or element that cannot be represented in commonmark without losing // formatting or content. for (const [nodeType, serializerFunction] of Object.entries(nodes)) { - nodes[nodeType] = function(state, node) { + nodes[nodeType] = function(state, node, parent, index) { if (node.attrs.align) { writeNodeAsHtml(state, node); } else { - serializerFunction(state, node); + serializerFunction(state, node, parent, index); } } } diff --git a/resources/js/editor/menu/ColorPickerGrid.js b/resources/js/editor/menu/ColorPickerGrid.js new file mode 100644 index 000000000..91ea73317 --- /dev/null +++ b/resources/js/editor/menu/ColorPickerGrid.js @@ -0,0 +1,40 @@ +import crel from "crelt" +const prefix = "ProseMirror-menu" +import {toggleMark} from "prosemirror-commands"; + +class ColorPickerGrid { + + constructor(markType, attrName, colors) { + this.markType = markType; + this.colors = colors + this.attrName = attrName; + } + + // :: (EditorView) → {dom: dom.Node, update: (EditorState) → bool} + // Renders the submenu. + render(view) { + + const colorElems = []; + for (const color of this.colors) { + const elem = crel("div", {class: prefix + "-color-grid-item", style: `background-color: ${color};`}); + colorElems.push(elem); + } + + const wrap = crel("div", {class: prefix + "-color-grid-container"}, colorElems); + wrap.addEventListener('click', event => { + if (event.target.classList.contains(prefix + "-color-grid-item")) { + const color = event.target.style.backgroundColor; + const attrs = {[this.attrName]: color}; + toggleMark(this.markType, attrs)(view.state, view.dispatch, view, event); + } + }); + + function update(state) { + return true; + } + + return {dom: wrap, update} + } +} + +export default ColorPickerGrid; \ No newline at end of file diff --git a/resources/js/editor/menu/index.js b/resources/js/editor/menu/index.js index ed6a1c25b..72d034b2a 100644 --- a/resources/js/editor/menu/index.js +++ b/resources/js/editor/menu/index.js @@ -2,6 +2,7 @@ import { MenuItem, Dropdown, DropdownSubmenu, renderGrouped, icons, joinUpItem, liftItem, selectParentNodeItem, undoItem, redoItem, wrapItem, blockTypeItem, setAttrItem, } from "./menu" +import ColorPickerGrid from "./ColorPickerGrid"; import {toggleMark} from "prosemirror-commands"; import {menuBar} from "./menubar" @@ -117,9 +118,15 @@ const alignments = [ }), ]; +const colorOptions = ["#000000","#993300","#333300","#003300","#003366","#000080","#333399","#333333","#800000","#FF6600","#808000","#008000","#008080","#0000FF","#666699","#808080","#FF0000","#FF9900","#99CC00","#339966","#33CCCC","#3366FF","#800080","#999999","#FF00FF","#FFCC00","#FFFF00","#00FF00","#00FFFF","#00CCFF","#993366","#FFFFFF","#FF99CC","#FFCC99","#FFFF99","#CCFFCC","#CCFFFF","#99CCFF","#CC99FF"]; + const colors = [ - markItem(schema.marks.text_color, {title: "Green", label: "Green", attrs: {color: '#00FF00'}}), - markItem(schema.marks.text_color, {title: "Blue", label: "Blue", attrs: {color: '#0000FF'}}), + new DropdownSubmenu([ + new ColorPickerGrid(schema.marks.text_color, 'color', colorOptions), + ], {label: 'Text Color'}), + new DropdownSubmenu([ + new ColorPickerGrid(schema.marks.background_color, 'color', colorOptions), + ], {label: 'Background Color'}), ]; const menu = menuBar({ @@ -127,8 +134,8 @@ const menu = menuBar({ content: [ [undoItem, redoItem], [new DropdownSubmenu(formats, { label: 'Formats' })], - colors, inlineStyles, + colors, alignments, ], }); diff --git a/resources/js/editor/menu/menu.js b/resources/js/editor/menu/menu.js index 8386de5dc..a922f4540 100644 --- a/resources/js/editor/menu/menu.js +++ b/resources/js/editor/menu/menu.js @@ -6,7 +6,7 @@ */ import crel from "crelt" -import {lift, joinUp, selectParentNode, wrapIn, setBlockType} from "prosemirror-commands" +import {lift, joinUp, selectParentNode, wrapIn, setBlockType, toggleMark} from "prosemirror-commands" import {undo, redo} from "prosemirror-history" import {setBlockAttr} from "../commands"; @@ -321,6 +321,8 @@ function separator() { return crel("span", {class: prefix + "separator"}) } + + // :: Object // A set of basic editor-related icons. Contains the properties // `join`, `lift`, `selectParentNode`, `undo`, `redo`, `strong`, `em`, diff --git a/resources/js/editor/schema-marks.js b/resources/js/editor/schema-marks.js index 175d8bda8..52335fac6 100644 --- a/resources/js/editor/schema-marks.js +++ b/resources/js/editor/schema-marks.js @@ -45,12 +45,28 @@ const text_color = { } }; +const background_color = { + attrs: { + color: {}, + }, + parseDOM: [{ + style: 'background-color', + getAttrs(color) { + return {color} + } + }], + toDOM(node) { + return ['span', {style: `background-color: ${node.attrs.color};`}, 0]; + } +}; + const marks = baseMarks.append({ underline, strike, superscript, subscript, text_color, + background_color, }); export default marks; \ No newline at end of file diff --git a/resources/sass/_editor.scss b/resources/sass/_editor.scss index d24dfaec5..1a3ee165d 100644 --- a/resources/sass/_editor.scss +++ b/resources/sass/_editor.scss @@ -365,4 +365,16 @@ img.ProseMirror-separator { outline: none; } -.ProseMirror p { margin-bottom: 1em } \ No newline at end of file +.ProseMirror p { margin-bottom: 1em } + +.ProseMirror-menu-color-grid-container { + display: grid; + grid-template-columns: repeat(8, 1fr); +} + +.ProseMirror-menu-color-grid-item { + width: 20px; + height: 20px; + border: 2px solid #FFF; + display: block; +} \ No newline at end of file