diff --git a/app/components/textEditor/editor.js b/app/components/textEditor/editor.js
new file mode 100644
index 00000000..f5e9fe81
--- /dev/null
+++ b/app/components/textEditor/editor.js
@@ -0,0 +1,127 @@
+import defaultTheme from "./theme/defaultTheme";
+import { LexicalComposer } from "@lexical/react/LexicalComposer";
+import { RichTextPlugin } from "@lexical/react/LexicalRichTextPlugin";
+import { ContentEditable } from "@lexical/react/LexicalContentEditable";
+import { HistoryPlugin } from "@lexical/react/LexicalHistoryPlugin";
+import { AutoFocusPlugin } from "@lexical/react/LexicalAutoFocusPlugin";
+import LexicalErrorBoundary from "@lexical/react/LexicalErrorBoundary";
+import ToolbarPlugin from "./plugins/ToolbarPlugin";
+import { HeadingNode, QuoteNode } from "@lexical/rich-text";
+import { TableCellNode, TableNode, TableRowNode } from "@lexical/table";
+import { ListItemNode, ListNode } from "@lexical/list";
+import { CodeHighlightNode, CodeNode } from "@lexical/code";
+import { AutoLinkNode, LinkNode } from "@lexical/link";
+import { LinkPlugin } from "@lexical/react/LexicalLinkPlugin";
+import { ListPlugin } from "@lexical/react/LexicalListPlugin";
+import { MarkdownShortcutPlugin } from "@lexical/react/LexicalMarkdownShortcutPlugin";
+import { TRANSFORMERS } from "@lexical/markdown";
+import ListMaxIndentLevelPlugin from "./plugins/ListMaxIndentLevelPlugin";
+import { OnChangePlugin } from "@lexical/react/LexicalOnChangePlugin";
+import CodeHighlightPlugin from "./plugins/CodeHighlightPlugin";
+import AutoLinkPlugin from "./plugins/AutoLinkPlugin";
+import styles from "../../styles/Editor.module.css"
+import { $generateHtmlFromNodes } from '@lexical/html';
+import {$generateNodesFromDOM} from '@lexical/html';
+import { useEffect, } from "react";
+import {useLexicalComposerContext} from '@lexical/react/LexicalComposerContext';
+import {$insertNodes} from 'lexical'
+import PropTypes from 'prop-types'
+
+function Placeholder() {
+ return
Enter some rich text...
;
+}
+
+
+
+
+const editorConfig = {
+ // The editor theme
+ theme: defaultTheme,
+ // Handling of errors during update
+ onError(error) {
+ throw error;
+ },
+ // Any custom nodes go here
+ nodes: [
+ HeadingNode,
+ ListNode,
+ ListItemNode,
+ QuoteNode,
+ CodeNode,
+ CodeHighlightNode,
+ TableNode,
+ TableCellNode,
+ TableRowNode,
+ AutoLinkNode,
+ LinkNode
+ ],
+
+
+};
+
+
+function SetInitValue(props) {
+ const [editor] = useLexicalComposerContext();
+
+ useEffect(() => {
+ editor.update(() => {
+ if(!props.value) return;
+ const parser = new DOMParser();
+ const doc = parser.parseFromString(props.value, "text/html");
+ const nodes = $generateNodesFromDOM(editor , doc);
+ $insertNodes(nodes);
+ });
+ }, [props.value]);
+
+ return null;
+}
+
+export default function Editor({ name, value, onChange, placeholder }) {
+
+ const on_Change = (editorState, editor) => {
+ editor.update(() => {
+ const htmlString = $generateHtmlFromNodes(editor, null);
+ const customFormData = {
+ target: {
+ name: name,
+ value: htmlString
+ }}
+ onChange(customFormData);
+ });
+ }
+
+ return (
+
+
+
+
+
}
+ placeholder={
+ placeholder ? placeholder :
}
+ ErrorBoundary={LexicalErrorBoundary}
+ />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
+
+Editor.propTypes = {
+ name: PropTypes.string.isRequired,
+ onChange: PropTypes.func.isRequired,
+ value: PropTypes.string,
+ placeholder: PropTypes.string
+};
diff --git a/app/components/textEditor/plugins/AutoLinkPlugin.js b/app/components/textEditor/plugins/AutoLinkPlugin.js
new file mode 100644
index 00000000..3475c917
--- /dev/null
+++ b/app/components/textEditor/plugins/AutoLinkPlugin.js
@@ -0,0 +1,34 @@
+import { AutoLinkPlugin } from "@lexical/react/LexicalAutoLinkPlugin";
+
+const URL_MATCHER = /((https?:\/\/(www\.)?)|(www\.))[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_+.~#?&//=]*)/;
+
+const EMAIL_MATCHER = /(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))/;
+
+const MATCHERS = [
+ (text) => {
+ const match = URL_MATCHER.exec(text);
+ return (
+ match && {
+ index: match.index,
+ length: match[0].length,
+ text: match[0],
+ url: match[0]
+ }
+ );
+ },
+ (text) => {
+ const match = EMAIL_MATCHER.exec(text);
+ return (
+ match && {
+ index: match.index,
+ length: match[0].length,
+ text: match[0],
+ url: `mailto:${match[0]}`
+ }
+ );
+ }
+];
+
+export default function PlaygroundAutoLinkPlugin() {
+ return ;
+}
diff --git a/app/components/textEditor/plugins/CodeHighlightPlugin.js b/app/components/textEditor/plugins/CodeHighlightPlugin.js
new file mode 100644
index 00000000..f9318052
--- /dev/null
+++ b/app/components/textEditor/plugins/CodeHighlightPlugin.js
@@ -0,0 +1,11 @@
+import { registerCodeHighlighting } from "@lexical/code";
+import { useLexicalComposerContext } from "@lexical/react/LexicalComposerContext";
+import { useEffect } from "react";
+
+export default function CodeHighlightPlugin() {
+ const [editor] = useLexicalComposerContext();
+ useEffect(() => {
+ return registerCodeHighlighting(editor);
+ }, [editor]);
+ return null;
+}
diff --git a/app/components/textEditor/plugins/ListMaxIndentLevelPlugin.js b/app/components/textEditor/plugins/ListMaxIndentLevelPlugin.js
new file mode 100644
index 00000000..657535e7
--- /dev/null
+++ b/app/components/textEditor/plugins/ListMaxIndentLevelPlugin.js
@@ -0,0 +1,68 @@
+import { $getListDepth, $isListItemNode, $isListNode } from "@lexical/list";
+import { useLexicalComposerContext } from "@lexical/react/LexicalComposerContext";
+import {
+ $getSelection,
+ $isElementNode,
+ $isRangeSelection,
+ INDENT_CONTENT_COMMAND,
+ COMMAND_PRIORITY_HIGH
+} from "lexical";
+import { useEffect } from "react";
+
+function getElementNodesInSelection(selection) {
+ const nodesInSelection = selection.getNodes();
+
+ if (nodesInSelection.length === 0) {
+ return new Set([
+ selection.anchor.getNode().getParentOrThrow(),
+ selection.focus.getNode().getParentOrThrow()
+ ]);
+ }
+
+ return new Set(
+ nodesInSelection.map((n) => ($isElementNode(n) ? n : n.getParentOrThrow()))
+ );
+}
+
+function isIndentPermitted(maxDepth) {
+ const selection = $getSelection();
+
+ if (!$isRangeSelection(selection)) {
+ return false;
+ }
+
+ const elementNodesInSelection = getElementNodesInSelection(selection);
+
+ let totalDepth = 0;
+
+ for (const elementNode of elementNodesInSelection) {
+ if ($isListNode(elementNode)) {
+ totalDepth = Math.max($getListDepth(elementNode) + 1, totalDepth);
+ } else if ($isListItemNode(elementNode)) {
+ const parent = elementNode.getParent();
+ if (!$isListNode(parent)) {
+ throw new Error(
+ "ListMaxIndentLevelPlugin: A ListItemNode must have a ListNode for a parent."
+ );
+ }
+
+ totalDepth = Math.max($getListDepth(parent) + 1, totalDepth);
+ }
+ }
+
+ return totalDepth <= maxDepth;
+}
+
+export default function ListMaxIndentLevelPlugin({ maxDepth }) {
+ const [editor] = useLexicalComposerContext();
+
+ useEffect(() => {
+ return editor.registerCommand(
+ INDENT_CONTENT_COMMAND,
+ () => !isIndentPermitted(maxDepth ?? 7),
+ COMMAND_PRIORITY_HIGH
+ );
+ }, [editor, maxDepth]);
+
+ return null;
+}
diff --git a/app/components/textEditor/plugins/ToolbarPlugin.js b/app/components/textEditor/plugins/ToolbarPlugin.js
new file mode 100644
index 00000000..2c327e18
--- /dev/null
+++ b/app/components/textEditor/plugins/ToolbarPlugin.js
@@ -0,0 +1,438 @@
+import {
+ $isCodeNode, getDefaultCodeLanguage
+} from "@lexical/code";
+import { $isLinkNode, TOGGLE_LINK_COMMAND } from "@lexical/link";
+import {
+ $isListNode, INSERT_ORDERED_LIST_COMMAND,
+ INSERT_UNORDERED_LIST_COMMAND, ListNode, REMOVE_LIST_COMMAND
+} from "@lexical/list";
+import { useLexicalComposerContext } from "@lexical/react/LexicalComposerContext";
+import {
+ $isHeadingNode
+} from "@lexical/rich-text";
+import {
+ $isAtNodeEnd, $isParentElementRTL
+} from "@lexical/selection";
+import { $getNearestNodeOfType, mergeRegister } from "@lexical/utils";
+import {
+ $getSelection,
+ $isRangeSelection, CAN_REDO_COMMAND,
+ CAN_UNDO_COMMAND, FORMAT_ELEMENT_COMMAND, FORMAT_TEXT_COMMAND, REDO_COMMAND, SELECTION_CHANGE_COMMAND, UNDO_COMMAND
+} from "lexical";
+import { useCallback, useEffect, useRef, useState } from "react";
+import { createPortal } from "react-dom";
+
+import styles from "../../../styles/Editor.module.css";
+
+import {
+ BsArrowClockwise, BsArrowCounterclockwise, BsCode, BsLink, BsListOl, BsListUl, BsPen, BsTextCenter, BsTextLeft, BsTextRight, BsTypeBold, BsTypeItalic, BsTypeStrikethrough, BsTypeUnderline
+} from "react-icons/bs";
+import DOMPurify from "dompurify";
+
+const LowPriority = 1;
+
+function Divider() {
+ return ;
+}
+
+function positionEditorElement(editor, rect) {
+ if (rect === null) {
+ editor.style.opacity = "0";
+ editor.style.top = "-1000px";
+ editor.style.left = "-1000px";
+ } else {
+ editor.style.opacity = "1";
+ editor.style.top = `${rect.top + rect.height + window.pageYOffset + 10}px`;
+ editor.style.left = `${rect.left + window.pageXOffset - editor.offsetWidth / 2 + rect.width / 2
+ }px`;
+ }
+}
+
+function FloatingLinkEditor({ editor }) {
+ const editorRef = useRef(null);
+ const inputRef = useRef(null);
+ const mouseDownRef = useRef(false);
+ const [linkUrl, setLinkUrl] = useState("");
+ const [isEditMode, setEditMode] = useState(false);
+ const [lastSelection, setLastSelection] = useState(null);
+
+ const updateLinkEditor = useCallback(() => {
+ const selection = $getSelection();
+ if ($isRangeSelection(selection)) {
+ const node = getSelectedNode(selection);
+ const parent = node.getParent();
+ if ($isLinkNode(parent)) {
+ setLinkUrl(parent.getURL());
+ } else if ($isLinkNode(node)) {
+ setLinkUrl(node.getURL());
+ } else {
+ setLinkUrl("");
+ }
+ }
+ const editorElem = editorRef.current;
+ const nativeSelection = window.getSelection();
+ const activeElement = document.activeElement;
+
+ if (editorElem === null) {
+ return;
+ }
+
+ const rootElement = editor.getRootElement();
+ if (
+ selection !== null &&
+ !nativeSelection.isCollapsed &&
+ rootElement !== null &&
+ rootElement.contains(nativeSelection.anchorNode)
+ ) {
+ const domRange = nativeSelection.getRangeAt(0);
+ let rect;
+ if (nativeSelection.anchorNode === rootElement) {
+ let inner = rootElement;
+ while (inner.firstElementChild != null) {
+ inner = inner.firstElementChild;
+ }
+ rect = inner.getBoundingClientRect();
+ } else {
+ rect = domRange.getBoundingClientRect();
+ }
+
+ if (!mouseDownRef.current) {
+ positionEditorElement(editorElem, rect);
+ }
+ setLastSelection(selection);
+ } else if (!activeElement || activeElement.className !== styles.link_input) {
+ positionEditorElement(editorElem, null);
+ setLastSelection(null);
+ setEditMode(false);
+ setLinkUrl("");
+ }
+
+ return true;
+ }, [editor]);
+
+ useEffect(() => {
+ return mergeRegister(
+ editor.registerUpdateListener(({ editorState }) => {
+ editorState.read(() => {
+ updateLinkEditor();
+ });
+ }),
+
+ editor.registerCommand(
+ SELECTION_CHANGE_COMMAND,
+ () => {
+ updateLinkEditor();
+ return true;
+ },
+ LowPriority
+ )
+ );
+ }, [editor, updateLinkEditor]);
+
+ useEffect(() => {
+ editor.getEditorState().read(() => {
+ updateLinkEditor();
+ });
+
+ }, [editor, updateLinkEditor]);
+
+ useEffect(() => {
+ if (isEditMode && inputRef.current) {
+ inputRef.current.focus();
+ }
+ }, [isEditMode]);
+
+ return (
+
+ {isEditMode ? (
+
{
+ setLinkUrl(event.target.value);
+ }}
+ onKeyDown={(event) => {
+ if (event.key === "Enter") {
+ event.preventDefault();
+ if (lastSelection !== null) {
+ if (linkUrl !== "") {
+ editor.dispatchCommand(TOGGLE_LINK_COMMAND, linkUrl);
+ }
+ setEditMode(false);
+ }
+ } else if (event.key === "Escape") {
+ event.preventDefault();
+ setEditMode(false);
+ }
+ }}
+ />
+ ) : (
+ <>
+
+ >
+ )}
+
+ );
+}
+
+function getSelectedNode(selection) {
+ const anchor = selection.anchor;
+ const focus = selection.focus;
+ const anchorNode = selection.anchor.getNode();
+ const focusNode = selection.focus.getNode();
+ if (anchorNode === focusNode) {
+ return anchorNode;
+ }
+ const isBackward = selection.isBackward();
+ if (isBackward) {
+ return $isAtNodeEnd(focus) ? anchorNode : focusNode;
+ } else {
+ return $isAtNodeEnd(anchor) ? focusNode : anchorNode;
+ }
+}
+
+export default function ToolbarPlugin() {
+ const [editor] = useLexicalComposerContext();
+ const toolbarRef = useRef(null);
+ const [canUndo, setCanUndo] = useState(false);
+ const [canRedo, setCanRedo] = useState(false);
+ const [blockType, setBlockType] = useState("paragraph");
+ const [selectedElementKey, setSelectedElementKey] = useState(null);
+ const [isRTL, setIsRTL] = useState(false);
+ const [isLink, setIsLink] = useState(false);
+ const [isBold, setIsBold] = useState(false);
+ const [isItalic, setIsItalic] = useState(false);
+ const [isUnderline, setIsUnderline] = useState(false);
+ const [isStrikethrough, setIsStrikethrough] = useState(false);
+ const [isCode, setIsCode] = useState(false);
+
+ const updateToolbar = useCallback(() => {
+ const selection = $getSelection();
+ if ($isRangeSelection(selection)) {
+ const anchorNode = selection.anchor.getNode();
+ const element =
+ anchorNode.getKey() === "root"
+ ? anchorNode
+ : anchorNode.getTopLevelElementOrThrow();
+ const elementKey = element.getKey();
+ const elementDOM = editor.getElementByKey(elementKey);
+ if (elementDOM !== null) {
+ setSelectedElementKey(elementKey);
+ if ($isListNode(element)) {
+ const parentList = $getNearestNodeOfType(anchorNode, ListNode);
+ const type = parentList ? parentList.getTag() : element.getTag();
+ setBlockType(type);
+ } else {
+ const type = $isHeadingNode(element)
+ ? element.getTag()
+ : element.getType();
+ setBlockType(type);
+ if ($isCodeNode(element)) {
+ setCodeLanguage(element.getLanguage() || getDefaultCodeLanguage());
+ }
+ }
+ }
+ // Update text format
+ setIsBold(selection.hasFormat("bold"));
+ setIsItalic(selection.hasFormat("italic"));
+ setIsUnderline(selection.hasFormat("underline"));
+ setIsStrikethrough(selection.hasFormat("strikethrough"));
+ setIsCode(selection.hasFormat("code"));
+ setIsRTL($isParentElementRTL(selection));
+
+ // Update links
+ const node = getSelectedNode(selection);
+ const parent = node.getParent();
+ if ($isLinkNode(parent) || $isLinkNode(node)) {
+ setIsLink(true);
+ } else {
+ setIsLink(false);
+ }
+ }
+ }, [editor]);
+
+ useEffect(() => {
+ return mergeRegister(
+ editor.registerUpdateListener(({ editorState }) => {
+ editorState.read(() => {
+ updateToolbar();
+ });
+ }),
+ editor.registerCommand(
+ SELECTION_CHANGE_COMMAND,
+ (_payload, newEditor) => {
+ updateToolbar();
+ return false;
+ },
+ LowPriority
+ ),
+ editor.registerCommand(
+ CAN_UNDO_COMMAND,
+ (payload) => {
+ setCanUndo(payload);
+ return false;
+ },
+ LowPriority
+ ),
+ editor.registerCommand(
+ CAN_REDO_COMMAND,
+ (payload) => {
+ setCanRedo(payload);
+ return false;
+ },
+ LowPriority
+ )
+ );
+ }, [editor, updateToolbar]);
+
+ const insertLink = useCallback(() => {
+ if (!isLink) {
+ editor.dispatchCommand(TOGGLE_LINK_COMMAND, "https://");
+ } else {
+ editor.dispatchCommand(TOGGLE_LINK_COMMAND, null);
+ }
+ }, [editor, isLink]);
+
+ return (
+
+
{
+ editor.dispatchCommand(UNDO_COMMAND);
+ }}
+ className={"" + styles.toolbar_tools}
+ aria-label="Undo"
+ >
+
+
+
{
+ editor.dispatchCommand(REDO_COMMAND);
+ }}
+ className={"" + styles.toolbar_tools}
+ aria-label="Redo"
+ >
+
+
+
+ <>
+
{
+ editor.dispatchCommand(FORMAT_TEXT_COMMAND, "bold");
+ }}
+ className={styles.toolbar_tools + " " + (isBold ? styles.active : "")}
+ aria-label="Format Bold"
+ >
+
+
+
{
+ editor.dispatchCommand(FORMAT_TEXT_COMMAND, "italic");
+ }}
+ className={styles.toolbar_tools + " " + (isItalic ? styles.active : "")}
+ aria-label="Format Italics"
+ >
+
+
+
{
+ editor.dispatchCommand(FORMAT_TEXT_COMMAND, "underline");
+ }}
+ className={styles.toolbar_tools + " " + (isUnderline ? styles.active : "")}
+ aria-label="Format Underline"
+ >
+
+
+
{
+ editor.dispatchCommand(FORMAT_TEXT_COMMAND, "strikethrough");
+ }}
+ className={
+ styles.toolbar_tools + " " + (isStrikethrough ? styles.active : "")
+ }
+ aria-label="Format Strikethrough"
+ >
+
+
+
{
+ editor.dispatchCommand(FORMAT_TEXT_COMMAND, "code");
+ }}
+ className={styles.toolbar_tools + " " + (isCode ? styles.active : "")}
+ aria-label="Insert Code"
+ >
+
+
+
+
+
+ {isLink &&
+ createPortal(
, document.body)}
+
+
{
+ editor.dispatchCommand(FORMAT_ELEMENT_COMMAND, "left");
+ }}
+ className={styles.toolbar_tools}
+ aria-label="Left Align"
+ >
+
+
+
{
+ editor.dispatchCommand(FORMAT_ELEMENT_COMMAND, "center");
+ }}
+ className={styles.toolbar_tools}
+ aria-label="Center Align"
+ >
+
+
+
{
+ editor.dispatchCommand(FORMAT_ELEMENT_COMMAND, "right");
+ }}
+ className={"" + styles.toolbar_tools}
+ aria-label="Right Align"
+ >
+
+
+
{
+ (blockType === "ul") ? editor.dispatchCommand(REMOVE_LIST_COMMAND) : editor.dispatchCommand(INSERT_UNORDERED_LIST_COMMAND)
+ }
+ } >
+
+
+
{
+ (blockType === "ol") ? editor.dispatchCommand(REMOVE_LIST_COMMAND) : editor.dispatchCommand(INSERT_ORDERED_LIST_COMMAND)
+ }
+ } >
+
+
+ >
+
+ );
+}
diff --git a/app/components/textEditor/theme/defaultTheme.js b/app/components/textEditor/theme/defaultTheme.js
new file mode 100644
index 00000000..dacc3e9a
--- /dev/null
+++ b/app/components/textEditor/theme/defaultTheme.js
@@ -0,0 +1,10 @@
+const defaultTheme = {
+ ltr: 'text-left',
+ rtl: 'text-right',
+ text:{
+ underline : 'text-decoration-underline',
+ }
+ };
+
+export default defaultTheme;
+
\ No newline at end of file
diff --git a/app/package.json b/app/package.json
index 702c977c..5f3e7748 100644
--- a/app/package.json
+++ b/app/package.json
@@ -14,6 +14,7 @@
"@apollo/client": "^3.5.9",
"@jitsi/react-sdk": "^1.0.0",
"@jitsi/web-sdk": "^0.2.0",
+ "@lexical/react": "^0.8.0",
"@rocket.chat/fuselage": "^0.31.3",
"@rocket.chat/fuselage-hooks": "^0.31.3",
"@rocket.chat/fuselage-polyfills": "^0.31.3",
@@ -29,6 +30,7 @@
"gapi-cjs": "^1.0.3",
"graphql": "^16.3.0",
"js-cookie": "^3.0.1",
+ "lexical": "^0.8.0",
"lodash": "^4.17.21",
"marked": "^4.0.12",
"next": "^12.2.5",
diff --git a/app/styles/Editor.module.css b/app/styles/Editor.module.css
new file mode 100644
index 00000000..0a7fc825
--- /dev/null
+++ b/app/styles/Editor.module.css
@@ -0,0 +1,344 @@
+.other h2 {
+ font-size: 18px;
+ color: #444;
+ margin-bottom: 7px;
+}
+
+.other a {
+ color: #777;
+ text-decoration: underline;
+ font-size: 14px;
+}
+
+.other ul {
+ padding: 0;
+ margin: 0;
+ list-style-type: none;
+}
+
+.editor_container {
+ margin: 20px auto 20px auto;
+ border-radius: 2px;
+ color: #000;
+ position: relative;
+ line-height: 20px;
+ font-weight: 400;
+ text-align: left;
+ border-right : 1px solid black;
+ border-left : 1px solid black;
+ border-bottom: 1px solid black;
+}
+
+.editor_inner {
+ background: #fff;
+ position: relative;
+}
+
+.editor_input {
+ min-height: 150px;
+ resize: none;
+ font-size: 15px;
+ caret-color: rgb(5, 5, 5);
+ position: relative;
+ tab-size: 1;
+ outline: 0;
+ padding: 15px 10px;
+ caret-color: #444;
+}
+
+.editor_placeholder {
+ color: #999;
+ overflow: hidden;
+ position: absolute;
+ text-overflow: ellipsis;
+ top: 15px;
+ left: 10px;
+ font-size: 15px;
+ user-select: none;
+ display: inline-block;
+ pointer-events: none;
+}
+
+.editor_text_bold {
+ font-weight: bold;
+}
+
+.editor_text_italic {
+ font-style: italic;
+}
+
+.editor_text_underline {
+ text-decoration: underline;
+}
+
+.editor_text_strikethrough {
+ text-decoration: line-through;
+}
+
+.editor_text_underlineStrikethrough {
+ text-decoration: underline line-through;
+}
+
+.editor_text_code {
+ background-color: rgb(240, 242, 245);
+ padding: 1px 0.25rem;
+ font-family: Menlo, Consolas, Monaco, monospace;
+ font-size: 94%;
+}
+
+.editor_link {
+ color: rgb(33, 111, 219);
+ text-decoration: none;
+}
+
+.editor_code {
+ background-color: rgb(240, 242, 245);
+ font-family: Menlo, Consolas, Monaco, monospace;
+ display: block;
+ padding: 8px 8px 8px 52px;
+ line-height: 1.53;
+ font-size: 13px;
+ margin: 0;
+ margin-top: 8px;
+ margin-bottom: 8px;
+ tab-size: 2;
+ /* white-space: pre; */
+ overflow-x: auto;
+ position: relative;
+}
+
+.editor_code:before {
+ content: attr(data-gutter);
+ position: absolute;
+ background-color: #eee;
+ left: 0;
+ top: 0;
+ border-right: 1px solid #ccc;
+ padding: 8px;
+ color: #777;
+ white-space: pre-wrap;
+ text-align: right;
+ min-width: 25px;
+}
+.editor_code:after {
+ content: attr(data-highlight-language);
+ top: 0;
+ right: 3px;
+ padding: 3px;
+ font-size: 10px;
+ text-transform: uppercase;
+ position: absolute;
+ color: rgba(0, 0, 0, 0.5);
+}
+
+.editor_tokenComment {
+ color: slategray;
+}
+
+.editor_tokenPunctuation {
+ color: #999;
+}
+
+.editor_tokenProperty {
+ color: #905;
+}
+
+.editor_tokenSelector {
+ color: #690;
+}
+
+.editor_tokenOperator {
+ color: #9a6e3a;
+}
+
+.editor_tokenAttr {
+ color: #07a;
+}
+
+.editor_tokenVariable {
+ color: #e90;
+}
+
+.editor_tokenFunction {
+ color: #dd4a68;
+}
+
+.editor_paragraph {
+ margin: 0;
+ margin-bottom: 8px;
+ position: relative;
+}
+
+.editor_paragraph:last-child {
+ margin-bottom: 0;
+}
+
+.editor_heading_h1 {
+ font-size: 24px;
+ color: rgb(5, 5, 5);
+ font-weight: 400;
+ margin: 0;
+ margin-bottom: 12px;
+ padding: 0;
+}
+
+.editor_heading_h2 {
+ font-size: 15px;
+ color: rgb(101, 103, 107);
+ font-weight: 700;
+ margin: 0;
+ margin-top: 10px;
+ padding: 0;
+ text-transform: uppercase;
+}
+
+.editor_quote {
+ margin: 0;
+ margin-left: 20px;
+ font-size: 15px;
+ color: rgb(101, 103, 107);
+ border-left-color: rgb(206, 208, 212);
+ border-left-width: 4px;
+ border-left-style: solid;
+ padding-left: 16px;
+}
+
+.editor_list_ol {
+ padding: 0;
+ margin: 0;
+ margin-left: 16px;
+}
+
+.editor_list_ul {
+ padding: 0;
+ margin: 0;
+ margin-left: 16px;
+}
+
+.editor_listitem {
+ margin: 8px 32px 8px 32px;
+}
+
+.editor_nested_listitem {
+ list-style-type: none;
+}
+
+.toolbar {
+ display: flex;
+ margin-bottom: 1px;
+ background: #ffffff;
+ border-top: 1px solid black;
+ border-bottom: 1px solid black;
+ border-radius: 2px;
+ vertical-align: middle;
+ flex-wrap: wrap;
+}
+
+.toolbar_tools {
+ border: 0;
+ display: flex;
+ background: none;
+ padding: 8px;
+ cursor: pointer;
+ vertical-align: middle;
+ align-self: center;
+ background: white;
+ border-radius: 4px;
+ margin:2px;
+ margin-right : 2px;
+}
+
+.toolbar_tools:hover {
+ background-color: #d7d2d2;
+}
+.active {
+ background: #9e9e9e;
+}
+
+
+.link_editor {
+ position: absolute;
+ z-index: 100;
+ top: -10000px;
+ left: -10000px;
+ margin-top: -6px;
+ max-width: 300px;
+ width: 100%;
+ opacity: 0;
+ background-color: #fff;
+ box-shadow: 0px 5px 10px rgba(0, 0, 0, 0.3);
+ border-radius: 8px;
+ transition: opacity 0.5s;
+}
+
+.link_editor .link_input {
+ display: block;
+ width: calc(100% - 24px);
+ box-sizing: border-box;
+ margin: 8px 12px;
+ padding: 8px 12px;
+ border-radius: 15px;
+ background-color: #eee;
+ font-size: 15px;
+ color: rgb(5, 5, 5);
+ border: 0;
+ outline: 0;
+ position: relative;
+ font-family: inherit;
+}
+
+.link_editor span.link_edit {
+ display: flex;
+ align-items: center;
+ align-self: center;
+ background-size: 16px;
+ background-position: center;
+ background-repeat: no-repeat;
+ width: 35px;
+ vertical-align: -0.25em;
+ position: absolute;
+ right: 0;
+ top: 0;
+ bottom: 0;
+ cursor: pointer;
+}
+
+.link_editor .link_input a {
+ color: rgb(33, 111, 219);
+ text-decoration: none;
+ display: block;
+ white-space: nowrap;
+ overflow: hidden;
+ margin-right: 30px;
+ text-overflow: ellipsis;
+}
+
+.link_editor .link_input a:hover {
+ text-decoration: underline;
+}
+
+.link_editor .button {
+ width: 20px;
+ height: 20px;
+ display: inline-block;
+ padding: 6px;
+ border-radius: 8px;
+ cursor: pointer;
+ margin: 0 2px;
+}
+
+.link_editor .button.hovered {
+ width: 20px;
+ height: 20px;
+ display: inline-block;
+ background-color: #eee;
+}
+
+.link_editor .button i,
+.actions i {
+ background-size: contain;
+ display: inline-block;
+ height: 20px;
+ width: 20px;
+ vertical-align: -0.25em;
+}
\ No newline at end of file