add ckEditor

This commit is contained in:
HAM!DREZA
2025-01-21 14:47:59 +03:30
parent 12865a12f2
commit 59eeedff1f
6 changed files with 71 additions and 86 deletions
+30 -55
View File
@@ -1,55 +1,30 @@
import { forwardRef, useEffect, useLayoutEffect, useRef } from 'react';
// Editor is an uncontrolled React component
const Editor = forwardRef(
({ readOnly, defaultValue, onTextChange, onSelectionChange }, ref) => {
const containerRef = useRef(null);
const defaultValueRef = useRef(defaultValue);
const onTextChangeRef = useRef(onTextChange);
const onSelectionChangeRef = useRef(onSelectionChange);
useLayoutEffect(() => {
onTextChangeRef.current = onTextChange;
onSelectionChangeRef.current = onSelectionChange;
});
useEffect(() => {
ref.current?.enable(!readOnly);
}, [ref, readOnly]);
useEffect(() => {
const container = containerRef.current;
const editorContainer = container.appendChild(
container.ownerDocument.createElement('div'),
);
const quill = new Quill(editorContainer, {
theme: 'snow',
});
ref.current = quill;
if (defaultValueRef.current) {
quill.setContents(defaultValueRef.current);
}
quill.on(Quill.events.TEXT_CHANGE, (...args) => {
onTextChangeRef.current?.(...args);
});
quill.on(Quill.events.SELECTION_CHANGE, (...args) => {
onSelectionChangeRef.current?.(...args);
});
return () => {
ref.current = null;
container.innerHTML = '';
};
}, [ref]);
return <div ref={containerRef}></div>;
},
);
Editor.displayName = 'Editor';
export default Editor;
import React from 'react';
import ReactDOM from 'react-dom';
import {Editor, EditorState} from 'draft-js';
function MyEditor() {
const [editorState, setEditorState] = React.useState(
EditorState.createEmpty()
);
const editor = React.useRef(null);
function focusEditor() {
editor.current.focus();
}
React.useEffect(() => {
focusEditor()
}, []);
return (
<div onClick={focusEditor}>
<Editor
ref={editor}
editorState={editorState}
onChange={editorState => setEditorState(editorState)}
/>
</div>
);
}
export default MyEditor
+2 -1
View File
@@ -54,7 +54,8 @@ export const Pages = {
},
blog: {
list: "/blog/list",
create: "/blog/create"
create: "/blog/create",
category: "/blog/category"
},
messages: {
list: "/messages/list",
+4
View File
@@ -126,3 +126,7 @@ tbody tr {
.overflowX::-webkit-scrollbar {
display: none;
}
.ql-toolbar:first-child{
display: none !important;
}
+5
View File
@@ -209,6 +209,11 @@
"new_blog": "افزودن بلاگ",
"blog_title": "عنوان بلاگ",
"blog_Summary": "خلاصه بلاگ",
"content": "محتوا",
"blog_status": "وضعیت بلاگ",
"featured_image": "تصویر شاخص",
"tags": "برچسب ها",
"tag_hint": "جدا کردن با کاما یا کلید Enter ",
"shareDate": "تاریخ انتشار",
"enter_your_title": "عنوان بلاگ را وارد کنید",
"add_blog": "افزودن بلاگ",
+29 -29
View File
@@ -9,12 +9,15 @@ import DatePickerComponent from '../../components/DatePicker'
import ImageUploader from './components/ImageUploader'
import "quill/dist/quill.snow.css";
import Quill from 'quill';
const CreateTicket: FC = () => {
const CreateBlog: FC = () => {
const { t } = useTranslation('global')
useEffect(() => {
const quill = new Quill('#editor', {
theme: 'snow',
});
});
const quill2 = new Quill('#editor2', {
theme: 'snow',
});
}, []);
return (
<div className='mt-4'>
@@ -42,37 +45,23 @@ const CreateTicket: FC = () => {
/>
</div>
<div className='mt-6'>
<div id='editor'></div>
</div>
<div className='mt-6 rowTwoInput'>
<DatePickerComponent
label={t('ads.startDate')}
onChange={() => { }}
placeholder=''
defaulValue='1400-01-01'
/>
<DatePickerComponent
label={t('ads.endDate')}
onChange={() => { }}
placeholder=''
defaulValue='1400-01-01'
/>
<p className='mt-6 text-sm'>{t('blog.blog_Summary')}</p>
<div className='mt-1'>
<div className='min-h-[120px]' id='editor'></div>
</div>
<div className='mt-6 relative'>
<Input
label={t('ads.link')}
placeholder={t('ads.enter_your_link')}
/>
<Link2 size={20} color='blue' className='absolute left-4 bottom-[10px]' />
<p className='mt-6 text-sm'>{t('blog.content')}</p>
<div className='mt-1'>
<div className='min-h-[200px]' id='editor2'></div>
</div>
</div>
<div className='min-h-[calc(100vh-201px)] bg-white w-sidebar xl:block hidden py-10 px-5 h-fit rounded-3xl'>
<div className='text-sm flex items-center justify-between'>
<p>
وضعیت تبلیغ
{t('blog.blog_status')}
</p>
<div className='flex gap-1 text-xs items-center text-description'>
<div>
@@ -84,7 +73,7 @@ const CreateTicket: FC = () => {
/>
</div>
</div>
<p className='mt-6 text-sm'>{t('ads.location')}</p>
<p className='mt-6 text-sm'>{t('blog.category')}</p>
<div className='p-2 border border-[##D0D0D0] rounded-lg mt-1'>
<div className='flex items-start gap-2 py-2'>
<div>
@@ -112,6 +101,17 @@ const CreateTicket: FC = () => {
</div>
</div>
<ImageUploader />
<p className='mt-6 text-sm'>{t('blog.tags')}</p>
<div className='mt-6'>
<Input className='-mt-4'/>
<p className='text-description text-xs mt-2'>
{t('blog.tag_hint')}
</p>
</div>
</div>
</div>
@@ -119,4 +119,4 @@ const CreateTicket: FC = () => {
)
}
export default CreateTicket
export default CreateBlog
+1 -1
View File
@@ -16,7 +16,7 @@ const ImageUploader: FC = () => {
return(
<>
<p className='mt-6 text-sm'>{t('ads.upload_picture')}</p>
<p className='mt-6 text-sm'>{t('blog.featured_image')}</p>
<div
{...getRootProps()}
className='py-12 border border-dashed border-[#8C90A3] rounded-lg mt-2 flex items-center justify-center'>