react

'use client';

2024년 2월 12일 09:32
'use client';


import { useEffect, useMemo, useRef } from 'react';


import { supabase } from '@/libs/supabase';
import { ImageActions } from '@xeger/quill-image-actions';
import { ImageFormats } from '@xeger/quill-image-formats';
import hljs from 'highlight.js';
import c from "highlight.js/lib/languages/c";
import javascript from "highlight.js/lib/languages/javascript";
import python from "highlight.js/lib/languages/python";
import typescript from "highlight.js/lib/languages/typescript";
import 'highlight.js/styles/github.css';
import ReactQuill, { Quill } from 'react-quill';
import 'react-quill/dist/quill.snow.css';
import { v4 as uuidv4 } from 'uuid';


Quill.register('modules/imageActions', ImageActions);
Quill.register('modules/imageFormats', ImageFormats);
interface QuillEditorProps {
  content: string;
  setContent: (char: string) => void;
}


hljs.registerLanguage("javascript", javascript);
hljs.registerLanguage("python", python);
hljs.registerLanguage("typescript", typescript);
hljs.registerLanguage("c", c);
const formats = [
  'font',
  'size',
  'header',
  'color',
  'background',
  'bold',
  'italic',
  'align',
  'underline',
  'strike',
  'blockquote',
  'list',
  'bullet',
  'indent',
  'link',
  'image',
  'video',
  'formula',
  'float',
  'height',
  'width',
  'code-block'
];


const Size = Quill.import('formats/size');
Size.whitelist = ['small', 'medium', 'large', 'huge'];
Quill.register(Size, true);


const QuillEditor: React.FC<QuillEditorProps> = ({ content, setContent }) => {
  const quillRef = useRef<ReactQuill>(null);
  
  const imageHandler = async () => {
    const input = document.createElement('input');
    input.setAttribute('type', 'file');
    input.setAttribute('accept', 'image/*');
    input.click();


    input.onchange = async () => {
      const file = input.files?.[0];
      if (!file) return;


      const uniqueFileName = uuidv4();
      const filePath = `uploads/images/${uniqueFileName}`; // 파일을 저장할 경로와 파일 이름
      const contentType = file.type; // 파일의 MIME 타입


      try {
        const { error: uploadError, data } = await supabase.storage
          .from('images') // 스토리지 버킷 이름
          .upload(filePath, file, {
            contentType,
            upsert: false,
          });


        if (uploadError) throw uploadError;


        const publicUrl = `https://rgvzlonuavmjvodmalpd.supabase.co/storage/v1/object/public/images/${data?.path}`;
        console.log('publicUrl:', publicUrl);
        // 에디터에 이미지 URL을 삽입합니다.
        const editor = quillRef.current;
        if (editor) {
          const range = editor.getEditor().getSelection(true);
          if (range) {
            // insertEmbed의 첫 번째 인자는 커서 위치(index)입니다.
            editor.getEditor().insertEmbed(range.index, 'image', publicUrl);
            editor.getEditor().setSelection(range.index + 1, 0);
          }
        }
      } catch (error: any) {
        console.error('Error uploading image: ', error.message);
      }
    };
  };


  const modules = useMemo(() => {
    return {
      imageActions: {},
      imageFormats: {},
      syntax: {
        highlight: (text: any) => hljs.highlightAuto(text).value,
      },
      toolbar: {
        container: [
          [{ font: [] }],
          [{ header: '1' }, { header: '2' }],
          [{ size: ['small', false, 'large', 'huge'] }],
          ['bold', 'italic', 'underline', 'strike', 'blockquote'],
          [
            { align: '' },
            { align: 'center' },
            { align: 'right' },
            { align: 'justify' },
          ],
          [
            { list: 'ordered' },
            { list: 'bullet' },
            { indent: '-1' },
            { indent: '+1' },
          ],
          ['code-block'],
          [{ color: [] }, { background: [] }],
          ['link', 'image', 'video', 'formula'],
          ['clean'],
        ],
        handlers: {
          image: imageHandler,
        },
      },
      clipboard: {
        matchVisual: false,
      },
    };
  }, []);



  useEffect(() => {
    document.querySelectorAll('pre code').forEach((block) => {
      if (block instanceof HTMLElement) {
        hljs.highlightBlock(block);
      }
    });
  }, [content]);


  return (
    <div>
      <ReactQuill
        ref={quillRef}
        style={{
          width: '100%',
          backgroundColor: '#FFF',
        }}
        theme="snow"
        placeholder={'내용을 입력해주세요.'}
        defaultValue={content}
        value={content}
        onChange={(content, delta, source, editor) =>
          setContent(editor.getHTML())
        }
        // onChange={(value) => setContent(value)}
        modules={modules}
        formats={formats}
      />
    </div>
  );
};


export default QuillEditor;


Copyright © 2024 White Mouse Dev