2023-09-09 23:53:20 -05:00
|
|
|
'use client';
|
|
|
|
|
|
2023-09-10 12:14:23 -05:00
|
|
|
import { useCodeMirror } from '@/hooks';
|
2023-09-10 16:02:13 -05:00
|
|
|
import { darkTheme } from '@/lib/codemirror';
|
|
|
|
|
import { indentWithTab } from '@codemirror/commands';
|
2023-09-10 12:14:23 -05:00
|
|
|
import { markdown, markdownLanguage } from '@codemirror/lang-markdown';
|
|
|
|
|
import { languages } from '@codemirror/language-data';
|
2023-09-10 16:02:13 -05:00
|
|
|
import { Compartment, EditorState } from '@codemirror/state';
|
|
|
|
|
import { EditorView, keymap } from '@codemirror/view';
|
2023-09-10 12:14:23 -05:00
|
|
|
import { basicSetup } from 'codemirror';
|
2023-09-10 16:02:13 -05:00
|
|
|
import { useTheme } from 'next-themes';
|
|
|
|
|
import { useEffect, useState } from 'react';
|
|
|
|
|
import ReactMarkdown from 'react-markdown';
|
|
|
|
|
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';
|
|
|
|
|
import { oneDark } from 'react-syntax-highlighter/dist/esm/styles/prism';
|
|
|
|
|
import remarkGfm from 'remark-gfm';
|
2023-09-09 23:53:20 -05:00
|
|
|
|
|
|
|
|
export default function Editor() {
|
2023-09-10 16:02:13 -05:00
|
|
|
const { theme } = useTheme();
|
|
|
|
|
const editorTheme = new Compartment();
|
|
|
|
|
const [currentDoc, setCurrentDoc] = useState('');
|
|
|
|
|
|
2023-09-10 12:14:23 -05:00
|
|
|
const doc = [''];
|
|
|
|
|
const extensions = [
|
|
|
|
|
basicSetup,
|
|
|
|
|
markdown({ base: markdownLanguage, codeLanguages: languages }),
|
|
|
|
|
EditorState.tabSize.of(2),
|
2023-09-10 16:02:13 -05:00
|
|
|
editorTheme.of([]),
|
|
|
|
|
keymap.of([indentWithTab]),
|
|
|
|
|
EditorView.updateListener.of(vu => {
|
|
|
|
|
setCurrentDoc(vu.state.doc.toString());
|
|
|
|
|
}),
|
2023-09-10 12:14:23 -05:00
|
|
|
];
|
|
|
|
|
|
2023-09-09 23:53:20 -05:00
|
|
|
const [mode, setMode] = useState<'write' | 'preview'>('write');
|
2023-09-10 12:14:23 -05:00
|
|
|
const { editorRef, editorView } = useCodeMirror({ doc, extensions });
|
2023-09-09 23:53:20 -05:00
|
|
|
|
2023-09-10 16:02:13 -05:00
|
|
|
useEffect(() => {
|
|
|
|
|
if (editorView === null) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (theme === 'dark') {
|
|
|
|
|
editorView.dispatch({
|
|
|
|
|
effects: editorTheme.reconfigure([darkTheme]),
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
|
|
|
}, [theme, editorView]);
|
|
|
|
|
|
2023-09-09 23:53:20 -05:00
|
|
|
return (
|
|
|
|
|
<form className='flex flex-col shadow-md rounded-md dark:bg-secondary-gray border border-gray-600'>
|
|
|
|
|
<div className='flex items-center justify-between rounded-t-md p-4 pb-0 border-b border-gray-600 dark:bg-primary-gray'>
|
|
|
|
|
<div className='flex items-center'>
|
|
|
|
|
<button
|
|
|
|
|
className='flex items-center justify-center px-3 py-2 rounded-t-md -mb-[1px] disabled:dark:bg-secondary-gray disabled:border disabled:border-gray-600 disabled:border-b-0'
|
|
|
|
|
disabled={mode === 'write'}
|
|
|
|
|
onClick={() => setMode('write')}
|
|
|
|
|
type='button'
|
|
|
|
|
>
|
|
|
|
|
Write
|
|
|
|
|
</button>
|
|
|
|
|
<button
|
|
|
|
|
className='flex items-center justify-center px-3 py-2 rounded-t-md disabled:dark:bg-secondary-gray disabled:border disabled:border-gray-600 disabled:border-b-0'
|
|
|
|
|
disabled={mode === 'preview'}
|
|
|
|
|
onClick={() => setMode('preview')}
|
|
|
|
|
type='button'
|
|
|
|
|
>
|
|
|
|
|
Preview
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
<div></div>
|
|
|
|
|
</div>
|
2023-09-10 12:14:23 -05:00
|
|
|
<div className='p-4'>
|
2023-09-10 16:02:13 -05:00
|
|
|
<div
|
|
|
|
|
className={`${mode === 'write' ? '' : 'hidden'}`}
|
|
|
|
|
ref={editorRef}
|
|
|
|
|
></div>
|
|
|
|
|
<ReactMarkdown
|
|
|
|
|
className={`${mode === 'preview' ? '' : 'hidden'}`}
|
|
|
|
|
remarkPlugins={[remarkGfm]}
|
|
|
|
|
components={{
|
|
|
|
|
code({ node, inline, className, children, ...props }) {
|
|
|
|
|
const match = /language-(\w+)/.exec(className || '');
|
|
|
|
|
return !inline && match ? (
|
|
|
|
|
<SyntaxHighlighter
|
|
|
|
|
{...props}
|
|
|
|
|
style={oneDark}
|
|
|
|
|
language={match[1]}
|
|
|
|
|
PreTag='div'
|
|
|
|
|
>
|
|
|
|
|
{String(children).replace(/\n$/, '')}
|
|
|
|
|
</SyntaxHighlighter>
|
|
|
|
|
) : (
|
|
|
|
|
<code
|
|
|
|
|
{...props}
|
|
|
|
|
className={className}
|
|
|
|
|
>
|
|
|
|
|
{children}
|
|
|
|
|
</code>
|
|
|
|
|
);
|
|
|
|
|
},
|
|
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
{currentDoc}
|
|
|
|
|
</ReactMarkdown>
|
2023-09-10 12:14:23 -05:00
|
|
|
</div>
|
2023-09-09 23:53:20 -05:00
|
|
|
<div className='flex items-center justify-end'>
|
|
|
|
|
<button type='submit'>Post</button>
|
|
|
|
|
</div>
|
|
|
|
|
</form>
|
|
|
|
|
);
|
|
|
|
|
}
|