Files
conve-x/src/components/Editor.tsx
T

114 lines
3.8 KiB
TypeScript
Raw Normal View History

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>
);
}