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'; import React from 'react';
import ReactDOM from 'react-dom';
// Editor is an uncontrolled React component import {Editor, EditorState} from 'draft-js';
const Editor = forwardRef(
({ readOnly, defaultValue, onTextChange, onSelectionChange }, ref) => { function MyEditor() {
const containerRef = useRef(null); const [editorState, setEditorState] = React.useState(
const defaultValueRef = useRef(defaultValue); EditorState.createEmpty()
const onTextChangeRef = useRef(onTextChange); );
const onSelectionChangeRef = useRef(onSelectionChange);
const editor = React.useRef(null);
useLayoutEffect(() => {
onTextChangeRef.current = onTextChange; function focusEditor() {
onSelectionChangeRef.current = onSelectionChange; editor.current.focus();
}); }
useEffect(() => { React.useEffect(() => {
ref.current?.enable(!readOnly); focusEditor()
}, [ref, readOnly]); }, []);
useEffect(() => { return (
const container = containerRef.current; <div onClick={focusEditor}>
const editorContainer = container.appendChild( <Editor
container.ownerDocument.createElement('div'), ref={editor}
); editorState={editorState}
const quill = new Quill(editorContainer, { onChange={editorState => setEditorState(editorState)}
theme: 'snow', />
}); </div>
);
ref.current = quill; }
export default MyEditor
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;
+2 -1
View File
@@ -54,7 +54,8 @@ export const Pages = {
}, },
blog: { blog: {
list: "/blog/list", list: "/blog/list",
create: "/blog/create" create: "/blog/create",
category: "/blog/category"
}, },
messages: { messages: {
list: "/messages/list", list: "/messages/list",
+4
View File
@@ -126,3 +126,7 @@ tbody tr {
.overflowX::-webkit-scrollbar { .overflowX::-webkit-scrollbar {
display: none; display: none;
} }
.ql-toolbar:first-child{
display: none !important;
}
+5
View File
@@ -209,6 +209,11 @@
"new_blog": "افزودن بلاگ", "new_blog": "افزودن بلاگ",
"blog_title": "عنوان بلاگ", "blog_title": "عنوان بلاگ",
"blog_Summary": "خلاصه بلاگ", "blog_Summary": "خلاصه بلاگ",
"content": "محتوا",
"blog_status": "وضعیت بلاگ",
"featured_image": "تصویر شاخص",
"tags": "برچسب ها",
"tag_hint": "جدا کردن با کاما یا کلید Enter ",
"shareDate": "تاریخ انتشار", "shareDate": "تاریخ انتشار",
"enter_your_title": "عنوان بلاگ را وارد کنید", "enter_your_title": "عنوان بلاگ را وارد کنید",
"add_blog": "افزودن بلاگ", "add_blog": "افزودن بلاگ",
+29 -29
View File
@@ -9,12 +9,15 @@ import DatePickerComponent from '../../components/DatePicker'
import ImageUploader from './components/ImageUploader' import ImageUploader from './components/ImageUploader'
import "quill/dist/quill.snow.css"; import "quill/dist/quill.snow.css";
import Quill from 'quill'; import Quill from 'quill';
const CreateTicket: FC = () => { const CreateBlog: FC = () => {
const { t } = useTranslation('global') const { t } = useTranslation('global')
useEffect(() => { useEffect(() => {
const quill = new Quill('#editor', { const quill = new Quill('#editor', {
theme: 'snow', theme: 'snow',
}); });
const quill2 = new Quill('#editor2', {
theme: 'snow',
});
}, []); }, []);
return ( return (
<div className='mt-4'> <div className='mt-4'>
@@ -42,37 +45,23 @@ const CreateTicket: FC = () => {
/> />
</div> </div>
<div className='mt-6'> <p className='mt-6 text-sm'>{t('blog.blog_Summary')}</p>
<div id='editor'></div> <div className='mt-1'>
</div> <div className='min-h-[120px]' id='editor'></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'
/>
</div> </div>
<div className='mt-6 relative'>
<Input <p className='mt-6 text-sm'>{t('blog.content')}</p>
label={t('ads.link')} <div className='mt-1'>
placeholder={t('ads.enter_your_link')} <div className='min-h-[200px]' id='editor2'></div>
/>
<Link2 size={20} color='blue' className='absolute left-4 bottom-[10px]' />
</div> </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='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'> <div className='text-sm flex items-center justify-between'>
<p> <p>
وضعیت تبلیغ {t('blog.blog_status')}
</p> </p>
<div className='flex gap-1 text-xs items-center text-description'> <div className='flex gap-1 text-xs items-center text-description'>
<div> <div>
@@ -84,7 +73,7 @@ const CreateTicket: FC = () => {
/> />
</div> </div>
</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='p-2 border border-[##D0D0D0] rounded-lg mt-1'>
<div className='flex items-start gap-2 py-2'> <div className='flex items-start gap-2 py-2'>
<div> <div>
@@ -112,6 +101,17 @@ const CreateTicket: FC = () => {
</div> </div>
</div> </div>
<ImageUploader /> <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>
</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( return(
<> <>
<p className='mt-6 text-sm'>{t('ads.upload_picture')}</p> <p className='mt-6 text-sm'>{t('blog.featured_image')}</p>
<div <div
{...getRootProps()} {...getRootProps()}
className='py-12 border border-dashed border-[#8C90A3] rounded-lg mt-2 flex items-center justify-center'> className='py-12 border border-dashed border-[#8C90A3] rounded-lg mt-2 flex items-center justify-center'>