Skip to content

Commit

Permalink
styling fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
victorzheng02 committed Oct 10, 2023
1 parent c766d67 commit 4a99a92
Show file tree
Hide file tree
Showing 2 changed files with 235 additions and 214 deletions.
273 changes: 60 additions & 213 deletions frontend/src/components/CommentSection.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,25 @@ import {
Editor,
Transforms,
createEditor,
Descendant,
Element as SlateElement,
} from 'slate'
import { withHistory } from 'slate-history'

import { Button, Icon, Toolbar } from './SlateComponents'
import {
BlockButton,
Button,
Element,
Icon,
Leaf,
MarkButton,
TEXT_ALIGN_TYPES,
Toolbar,
isBlockActive,
isMarkActive,
toggleBlock,
toggleMark,
} from './SlateComponents'
import { Box, Heading } from '@chakra-ui/react'

const HOTKEYS = {
'mod+b': 'bold',
Expand All @@ -20,225 +33,59 @@ const HOTKEYS = {
'mod+`': 'code',
}

const LIST_TYPES = ['numbered-list', 'bulleted-list']
const TEXT_ALIGN_TYPES = ['left', 'center', 'right', 'justify']

const RichTextExample = () => {
const CommentSection = () => {
const renderElement = useCallback((props) => <Element {...props} />, [])
const renderLeaf = useCallback((props) => <Leaf {...props} />, [])
const editor = useMemo(() => withHistory(withReact(createEditor())), [])

return (
<Slate editor={editor} initialValue={initialValue}>
<Toolbar>
<MarkButton format="bold" icon="format_bold" />
<MarkButton format="italic" icon="format_italic" />
<MarkButton format="underline" icon="format_underlined" />
<MarkButton format="code" icon="code" />
<BlockButton format="heading-one" icon="looks_one" />
<BlockButton format="heading-two" icon="looks_two" />
<BlockButton format="block-quote" icon="format_quote" />
<BlockButton
format="numbered-list"
icon="format_list_numbered"
/>
<BlockButton
format="bulleted-list"
icon="format_list_bulleted"
/>
<BlockButton format="left" icon="format_align_left" />
<BlockButton format="center" icon="format_align_center" />
<BlockButton format="right" icon="format_align_right" />
<BlockButton format="justify" icon="format_align_justify" />
</Toolbar>
<Editable
renderElement={renderElement}
renderLeaf={renderLeaf}
placeholder="Enter some rich text…"
spellCheck
autoFocus
onKeyDown={(event) => {
for (const hotkey in HOTKEYS) {
if (isHotkey(hotkey, event)) {
event.preventDefault()
const mark = HOTKEYS[hotkey]
toggleMark(editor, mark)
<Box mt="20px">
<Heading textAlign="center">Comment Section </Heading>
<Slate editor={editor} initialValue={initialValue}>
<Toolbar>
<MarkButton format="bold" icon="format_bold" />
<MarkButton format="italic" icon="format_italic" />
<MarkButton format="underline" icon="format_underlined" />
<MarkButton format="code" icon="code" />
<BlockButton format="heading-one" icon="looks_one" />
<BlockButton format="heading-two" icon="looks_two" />
<BlockButton format="block-quote" icon="format_quote" />
<BlockButton
format="numbered-list"
icon="format_list_numbered"
/>
<BlockButton
format="bulleted-list"
icon="format_list_bulleted"
/>
<BlockButton format="left" icon="format_align_left" />
<BlockButton format="center" icon="format_align_center" />
<BlockButton format="right" icon="format_align_right" />
<BlockButton format="justify" icon="format_align_justify" />
</Toolbar>
<Editable
renderElement={renderElement}
renderLeaf={renderLeaf}
placeholder="Enter some rich text…"
spellCheck
autoFocus
onKeyDown={(event) => {
for (const hotkey in HOTKEYS) {
if (isHotkey(hotkey, event)) {
event.preventDefault()
const mark = HOTKEYS[hotkey]
toggleMark(editor, mark)
}
}
}
}}
/>
</Slate>
)
}

const toggleBlock = (editor, format) => {
const isActive = isBlockActive(
editor,
format,
TEXT_ALIGN_TYPES.includes(format) ? 'align' : 'type'
)
const isList = LIST_TYPES.includes(format)

Transforms.unwrapNodes(editor, {
match: (n) =>
!Editor.isEditor(n) &&
SlateElement.isElement(n) &&
LIST_TYPES.includes(n.type) &&
!TEXT_ALIGN_TYPES.includes(format),
split: true,
})
let newProperties
if (TEXT_ALIGN_TYPES.includes(format)) {
newProperties = {
align: isActive ? undefined : format,
}
} else {
newProperties = {
type: isActive ? 'paragraph' : isList ? 'list-item' : format,
}
}
Transforms.setNodes(editor, newProperties)

if (!isActive && isList) {
const block = { type: format, children: [] }
Transforms.wrapNodes(editor, block)
}
}

const toggleMark = (editor, format) => {
const isActive = isMarkActive(editor, format)

if (isActive) {
Editor.removeMark(editor, format)
} else {
Editor.addMark(editor, format, true)
}
}

const isBlockActive = (editor, format, blockType = 'type') => {
const { selection } = editor
if (!selection) return false

const [match] = Array.from(
Editor.nodes(editor, {
at: Editor.unhangRange(editor, selection),
match: (n) =>
!Editor.isEditor(n) &&
SlateElement.isElement(n) &&
n[blockType] === format,
})
)

return !!match
}

const isMarkActive = (editor, format) => {
const marks = Editor.marks(editor)
return marks ? marks[format] === true : false
}

const Element = ({ attributes, children, element }) => {
const style = { textAlign: element.align }
switch (element.type) {
case 'block-quote':
return (
<blockquote style={style} {...attributes}>
{children}
</blockquote>
)
case 'bulleted-list':
return (
<ul style={style} {...attributes}>
{children}
</ul>
)
case 'heading-one':
return (
<h1 style={style} {...attributes}>
{children}
</h1>
)
case 'heading-two':
return (
<h2 style={style} {...attributes}>
{children}
</h2>
)
case 'list-item':
return (
<li style={style} {...attributes}>
{children}
</li>
)
case 'numbered-list':
return (
<ol style={style} {...attributes}>
{children}
</ol>
)
default:
return (
<p style={style} {...attributes}>
{children}
</p>
)
}
}

const Leaf = ({ attributes, children, leaf }) => {
if (leaf.bold) {
children = <strong>{children}</strong>
}

if (leaf.code) {
children = <code>{children}</code>
}

if (leaf.italic) {
children = <em>{children}</em>
}

if (leaf.underline) {
children = <u>{children}</u>
}

return <span {...attributes}>{children}</span>
}

const BlockButton = ({ format, icon }) => {
const editor = useSlate()
return (
<Button
active={isBlockActive(
editor,
format,
TEXT_ALIGN_TYPES.includes(format) ? 'align' : 'type'
)}
onMouseDown={(event) => {
event.preventDefault()
toggleBlock(editor, format)
}}
>
<Icon>{icon}</Icon>
</Button>
)
}

const MarkButton = ({ format, icon }) => {
const editor = useSlate()
return (
<Button
active={isMarkActive(editor, format)}
onMouseDown={(event) => {
event.preventDefault()
toggleMark(editor, format)
}}
>
<Icon>{icon}</Icon>
</Button>
}}
/>
</Slate>
</Box>
)
}

// example taken from https://github.com/ianstormtaylor/slate/blob/main/site/components.tsx
// remove once dynamically fetched from backend
const initialValue = [
{
type: 'paragraph',
Expand Down Expand Up @@ -275,4 +122,4 @@ const initialValue = [
},
]

export default RichTextExample
export default CommentSection
Loading

0 comments on commit 4a99a92

Please sign in to comment.