feat: blogs #118
@ -167,7 +167,7 @@ type MenuBarProps = {
|
||||
editor: Editor
|
||||
}
|
||||
|
||||
const MenuBar = ({ editor }: MenuBarProps) => {
|
||||
export const MenuBar = ({ editor }: MenuBarProps) => {
|
||||
const setLink = () => {
|
||||
// Prompt the user to enter a URL
|
||||
let url = prompt('URL')
|
||||
|
@ -1,28 +1,57 @@
|
||||
import { useState } from 'react'
|
||||
import { Form, useActionData, useNavigation } from 'react-router-dom'
|
||||
import {
|
||||
Form,
|
||||
useActionData,
|
||||
useLoaderData,
|
||||
useNavigation
|
||||
} from 'react-router-dom'
|
||||
import {
|
||||
CheckboxFieldUncontrolled,
|
||||
InputField,
|
||||
InputFieldUncontrolled
|
||||
InputError,
|
||||
InputFieldUncontrolled,
|
||||
MenuBar
|
||||
} from '../../components/Inputs'
|
||||
import { ProfileSection } from '../../components/ProfileSection'
|
||||
import { useAppSelector } from '../../hooks'
|
||||
import { BlogFormErrors } from 'types'
|
||||
import { BlogFormErrors, BlogPageLoaderResult } from 'types'
|
||||
import '../../styles/innerPage.css'
|
||||
import '../../styles/styles.css'
|
||||
import '../../styles/write.css'
|
||||
import { LoadingSpinner } from 'components/LoadingSpinner'
|
||||
import { marked } from 'marked'
|
||||
import DOMPurify from 'dompurify'
|
||||
import { EditorContent, useEditor } from '@tiptap/react'
|
||||
import StarterKit from '@tiptap/starter-kit'
|
||||
import Link from '@tiptap/extension-link'
|
||||
import Image from '@tiptap/extension-image'
|
||||
|
||||
export const WritePage = () => {
|
||||
const userState = useAppSelector((state) => state.user)
|
||||
const data = useLoaderData() as BlogPageLoaderResult
|
||||
const formErrors = useActionData() as BlogFormErrors
|
||||
const navigation = useNavigation()
|
||||
const title = 'Submit a blog post'
|
||||
|
||||
const [content, setContent] = useState<string>('')
|
||||
const handleContentChange = (_: string, value: string) => {
|
||||
setContent(value)
|
||||
const blog = data?.blog
|
||||
const title = data?.blog ? 'Edit blog post' : 'Submit a blog post'
|
||||
const html = marked.parse(blog?.content || '', { async: false })
|
||||
const sanitized = DOMPurify.sanitize(html)
|
||||
const [content, setContent] = useState<string>(sanitized)
|
||||
const editor = useEditor({
|
||||
content: content,
|
||||
extensions: [
|
||||
StarterKit,
|
||||
Link,
|
||||
Image.configure({
|
||||
inline: true,
|
||||
HTMLAttributes: {
|
||||
class: 'IBMSMSMBSSPostImg'
|
||||
}
|
||||
})
|
||||
],
|
||||
onUpdate: ({ editor }) => {
|
||||
setContent(editor.getHTML())
|
||||
}
|
||||
})
|
||||
|
||||
return (
|
||||
<div className='InnerBodyMain'>
|
||||
@ -43,28 +72,34 @@ export const WritePage = () => {
|
||||
<InputFieldUncontrolled
|
||||
label='Title'
|
||||
name='title'
|
||||
defaultValue={blog?.title}
|
||||
error={formErrors?.title}
|
||||
/>
|
||||
<InputField
|
||||
label='Content'
|
||||
name={'content'}
|
||||
type='richtext'
|
||||
placeholder='Blog content'
|
||||
value={content}
|
||||
error={formErrors?.content}
|
||||
onChange={handleContentChange}
|
||||
/>
|
||||
{editor && (
|
||||
<div className='inputLabelWrapperMain'>
|
||||
<label className='form-label labelMain'>Content</label>
|
||||
<div className='inputMain'>
|
||||
<MenuBar editor={editor} />
|
||||
<EditorContent editor={editor} />
|
||||
</div>
|
||||
{typeof formErrors?.content !== 'undefined' && (
|
||||
<InputError message={formErrors?.content} />
|
||||
)}
|
||||
<input name='content' hidden value={content} readOnly />
|
||||
</div>
|
||||
)}
|
||||
<InputFieldUncontrolled
|
||||
label='Featured Image URL'
|
||||
name='image'
|
||||
inputMode='url'
|
||||
defaultValue={blog?.image}
|
||||
error={formErrors?.image}
|
||||
/>
|
||||
<InputFieldUncontrolled
|
||||
label='Summary'
|
||||
name='summary'
|
||||
type='textarea'
|
||||
defaultValue={blog?.summary}
|
||||
error={formErrors?.summary}
|
||||
/>
|
||||
<InputFieldUncontrolled
|
||||
@ -72,11 +107,13 @@ export const WritePage = () => {
|
||||
description='Separate each tag with a comma. (Example: tag1, tag2, tag3)'
|
||||
placeholder='Tags'
|
||||
name='tags'
|
||||
defaultValue={blog?.tTags?.join(', ')}
|
||||
error={formErrors?.tags}
|
||||
/>
|
||||
<CheckboxFieldUncontrolled
|
||||
label='This post is not safe for work (NSFW)'
|
||||
name='nsfw'
|
||||
defaultChecked={blog?.nsfw}
|
||||
/>
|
||||
<div className='IBMSMSMBS_WriteAction'>
|
||||
<button
|
||||
|
Loading…
Reference in New Issue
Block a user