diff --git a/frontend/package.json b/frontend/package.json index 85b63b9b6..d361a8d71 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -22,6 +22,7 @@ "redux-persist": "^6.0.0", "redux-saga": "1.1.3", "slate": "0.78.0", + "slate-history": "^0.93.0", "slate-react": "0.79.0", "socket.io": "^4.5.3", "socket.io-client": "^4.5.3", diff --git a/frontend/src/cse-ui-kit/assets/checklist-button.svg b/frontend/src/cse-ui-kit/assets/checklist-button.svg new file mode 100644 index 000000000..57c8c042d --- /dev/null +++ b/frontend/src/cse-ui-kit/assets/checklist-button.svg @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/frontend/src/cse-ui-kit/small_buttons/ChecklistButton.tsx b/frontend/src/cse-ui-kit/small_buttons/ChecklistButton.tsx new file mode 100644 index 000000000..71152342e --- /dev/null +++ b/frontend/src/cse-ui-kit/small_buttons/ChecklistButton.tsx @@ -0,0 +1,23 @@ +import React, { MouseEventHandler } from 'react'; +import { StyledButton, buttonProps, scaleRate } from './small_buttons-Styled'; +import { ReactComponent as Code } from 'src/cse-ui-kit/assets/checklist-button.svg'; + +type Props = { + onClick?: MouseEventHandler; + onMouseDown?: MouseEventHandler; +} & buttonProps; + +export default function CodeButton({ + onClick, + onMouseDown, + ...styleProps +}: Props) { + return ( + + + + ); +} \ No newline at end of file diff --git a/frontend/src/packages/editor/components/EditorBlock.tsx b/frontend/src/packages/editor/components/EditorBlock.tsx index 83399d542..82ce6d0a8 100644 --- a/frontend/src/packages/editor/components/EditorBlock.tsx +++ b/frontend/src/packages/editor/components/EditorBlock.tsx @@ -1,7 +1,7 @@ import styled from 'styled-components'; -import { createEditor } from 'slate'; import React, { FC, useMemo, useCallback } from 'react'; -import { Slate, Editable, withReact, RenderLeafProps } from 'slate-react'; +import { Slate, Editable, withReact, RenderLeafProps, useReadOnly } from 'slate-react'; +import { createEditor } from 'slate' import { CMSBlockProps } from '../types'; import EditorBoldButton from './buttons/EditorBoldButton'; @@ -12,10 +12,12 @@ import EditorSelectFont from './buttons/EditorSelectFont'; import EditorCenterAlignButton from './buttons/EditorCenterAlignButton'; import EditorLeftAlignButton from './buttons/EditorLeftAlignButton'; import EditorRightAlignButton from './buttons/EditorRightAlignButton'; +import EditorCodeButton from "./buttons/EditorCodeButton"; +import EditorChecklistButton from "./buttons/EditorChecklistButton"; import ContentBlock from "../../../cse-ui-kit/contentblock/contentblock-wrapper"; import { handleKey } from "./buttons/buttonHelpers"; -import EditorCodeButton from "./buttons/EditorCodeButton"; +import { withHistory } from 'slate-history'; const defaultTextSize = 16; @@ -46,6 +48,51 @@ const Text = styled.span<{ background-color: ${(props) => props.code ? "#eee" : "#fff"}; `; + +const CheckListItemElement = ({children, attributes, leaf}: any) => { + const readOnly = useReadOnly() + const [checked, setChecked] = React.useState(false) + return ( +
+
+ + { + // Figure out why ReactEditor.findPath does not work + // const path = ReactEditor.findPath(editor as ReactEditor, leaf); + // const newProperties = { + // checked: event.target.checked, + // } + // Transforms.setNodes(editor, newProperties, { at: path }) + setChecked(event.target.checked); + }} + /> + +
+ + {children} + +
+)} + + const Quote = styled.blockquote` border-left: 3px solid #9e9e9e; margin: 0px; @@ -61,7 +108,7 @@ const EditorBlock: FC = ({ showToolBar, onEditorClick, }) => { - const editor = useMemo(() => withReact(createEditor()), []); + const editor = useMemo(() => withHistory(withReact(createEditor())), []) const renderLeaf: (props: RenderLeafProps) => JSX.Element = useCallback( ({ attributes, children, leaf }) => { @@ -73,9 +120,17 @@ const EditorBlock: FC = ({ code: leaf.code ?? false, align: leaf.align ?? 'left', textSize: leaf.textSize ?? defaultTextSize, + checklist: leaf.checklist ?? false, + checked: leaf.checklist ?? false, ...attributes, }; + + if (leaf.checklist) { + const checklistProps = {attributes, children, leaf} + return + } + return leaf.quote ? ( {children} ) : leaf.align == null ? ( @@ -100,6 +155,7 @@ const EditorBlock: FC = ({ + diff --git a/frontend/src/packages/editor/components/buttons/EditorChecklistButton.tsx b/frontend/src/packages/editor/components/buttons/EditorChecklistButton.tsx new file mode 100644 index 000000000..930b9b4d2 --- /dev/null +++ b/frontend/src/packages/editor/components/buttons/EditorChecklistButton.tsx @@ -0,0 +1,20 @@ +import React, { FC } from "react"; +import { useSlate } from "slate-react"; +import { toggleMark } from "./buttonHelpers"; +import ChecklistButton from "src/cse-ui-kit/small_buttons/ChecklistButton"; +import { Editor } from "slate"; + +const EditorChecklistButton: FC = () => { + const editor = useSlate(); + return ( + { + event.preventDefault(); + toggleMark(editor, "checklist") + }} + /> + ); +}; + +export default EditorChecklistButton; diff --git a/frontend/src/packages/editor/components/buttons/buttonHelpers.ts b/frontend/src/packages/editor/components/buttons/buttonHelpers.ts index 872f2af8a..9d94e6cfd 100644 --- a/frontend/src/packages/editor/components/buttons/buttonHelpers.ts +++ b/frontend/src/packages/editor/components/buttons/buttonHelpers.ts @@ -8,7 +8,7 @@ import { ReactEditor } from 'slate-react'; */ const toggleMark = ( editor: BaseEditor & ReactEditor, - format: 'bold' | 'italic' | 'underline' | 'quote' | 'code' + format: 'bold' | 'italic' | 'underline' | 'quote' | 'code' | 'checklist' ): void => { const isActive = isMarkActive(editor, format); @@ -27,7 +27,7 @@ const toggleMark = ( */ const isMarkActive = ( editor: BaseEditor & ReactEditor, - format: 'bold' | 'italic' | 'underline' | 'quote' | 'code' + format: 'bold' | 'italic' | 'underline' | 'quote' | 'code' | 'checklist' ): boolean => { // https://docs.slatejs.org/concepts/07-editor // Editor object exposes properties of the current editor diff --git a/frontend/src/packages/editor/types.ts b/frontend/src/packages/editor/types.ts index 438c0bb4c..fd7a82e3f 100644 --- a/frontend/src/packages/editor/types.ts +++ b/frontend/src/packages/editor/types.ts @@ -16,6 +16,7 @@ export type CustomText = { type?: string; align?: string; code?: string; + checklist?: boolean; }; export type CustomElement = {