157 lines
5.5 KiB
TypeScript
157 lines
5.5 KiB
TypeScript
import { useState } from 'react'
|
|
import {
|
|
Form,
|
|
useActionData,
|
|
useLoaderData,
|
|
useNavigation
|
|
} from 'react-router-dom'
|
|
import {
|
|
CheckboxFieldUncontrolled,
|
|
InputError,
|
|
InputFieldUncontrolled,
|
|
MenuBar
|
|
} from '../../components/Inputs'
|
|
import { ProfileSection } from '../../components/ProfileSection'
|
|
import { useAppSelector } from '../../hooks'
|
|
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 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'>
|
|
<div className='ContainerMain'>
|
|
<div className='IBMSecMainGroup IBMSecMainGroupAlt'>
|
|
<div className='IBMSMSplitMain'>
|
|
<div className='IBMSMSplitMainBigSide'>
|
|
<div className='IBMSMTitleMain'>
|
|
<h2 className='IBMSMTitleMainHeading'>{title}</h2>
|
|
</div>
|
|
{navigation.state === 'loading' && (
|
|
<LoadingSpinner desc='Loading..' />
|
|
)}
|
|
{navigation.state === 'submitting' && (
|
|
<LoadingSpinner desc='Publishing blog to relays' />
|
|
)}
|
|
<Form className='IBMSMSMBS_Write' method={blog ? 'put' : 'post'}>
|
|
<InputFieldUncontrolled
|
|
label='Title'
|
|
name='title'
|
|
defaultValue={blog?.title}
|
|
error={formErrors?.title}
|
|
/>
|
|
{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
|
|
label='Tags'
|
|
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}
|
|
/>
|
|
{typeof blog?.dTag !== 'undefined' && (
|
|
<input name='dTag' hidden value={blog.dTag} readOnly />
|
|
)}
|
|
{typeof blog?.rTag !== 'undefined' && (
|
|
<input name='rTag' hidden value={blog.rTag} readOnly />
|
|
)}
|
|
{typeof blog?.published_at !== 'undefined' && (
|
|
<input
|
|
name='published_at'
|
|
hidden
|
|
value={blog.published_at}
|
|
readOnly
|
|
/>
|
|
)}
|
|
<div className='IBMSMSMBS_WriteAction'>
|
|
<button
|
|
className='btn btnMain'
|
|
type='submit'
|
|
disabled={
|
|
navigation.state === 'loading' ||
|
|
navigation.state === 'submitting'
|
|
}
|
|
>
|
|
{navigation.state === 'submitting'
|
|
? 'Publishing...'
|
|
: 'Publish'}
|
|
</button>
|
|
</div>
|
|
</Form>
|
|
</div>
|
|
{userState.auth && userState.user?.pubkey && (
|
|
<ProfileSection pubkey={userState.user.pubkey as string} />
|
|
)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|