feat: work on previewing post

This commit is contained in:
Stevan Freeborn
2023-09-10 16:02:13 -05:00
parent 71dd48763f
commit 90f95e50a5
5 changed files with 1614 additions and 6 deletions
+9 -1
View File
@@ -1,4 +1,12 @@
{
"css.lint.unknownAtRules": "ignore",
"cSpell.words": ["codemirror", "conve", "Keymap", "nextjs", "signup", "svix"]
"cSpell.words": [
"codemirror",
"conve",
"Keymap",
"nextjs",
"rehype",
"signup",
"svix"
]
}
+1453
View File
File diff suppressed because it is too large Load Diff
+8 -2
View File
@@ -10,11 +10,13 @@
},
"dependencies": {
"@clerk/nextjs": "^4.23.5",
"@codemirror/commands": "^6.2.5",
"@codemirror/lang-markdown": "^6.2.0",
"@codemirror/language": "^6.9.0",
"@codemirror/language-data": "^6.3.1",
"@codemirror/state": "^6.2.1",
"@codemirror/view": "^6.18.0",
"@lezer/highlight": "^1.1.6",
"@types/node": "20.6.0",
"@types/react": "18.2.21",
"@types/react-dom": "18.2.7",
@@ -29,8 +31,12 @@
"react": "18.2.0",
"react-dom": "18.2.0",
"react-icons": "^4.11.0",
"react-markdown": "^8.0.7",
"react-syntax-highlighter": "^15.5.0",
"remark-gfm": "^3.0.1",
"svix": "^1.11.0",
"tailwindcss": "3.3.3",
"typescript": "5.2.2"
"typescript": "5.2.2",
"@types/react-syntax-highlighter": "^15.5.7"
}
}
}
+64 -3
View File
@@ -1,23 +1,53 @@
'use client';
import { useCodeMirror } from '@/hooks';
import { darkTheme } from '@/lib/codemirror';
import { indentWithTab } from '@codemirror/commands';
import { markdown, markdownLanguage } from '@codemirror/lang-markdown';
import { languages } from '@codemirror/language-data';
import { EditorState } from '@codemirror/state';
import { Compartment, EditorState } from '@codemirror/state';
import { EditorView, keymap } from '@codemirror/view';
import { basicSetup } from 'codemirror';
import { useState } from 'react';
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';
export default function Editor() {
const { theme } = useTheme();
const editorTheme = new Compartment();
const [currentDoc, setCurrentDoc] = useState('');
const doc = [''];
const extensions = [
basicSetup,
markdown({ base: markdownLanguage, codeLanguages: languages }),
EditorState.tabSize.of(2),
editorTheme.of([]),
keymap.of([indentWithTab]),
EditorView.updateListener.of(vu => {
setCurrentDoc(vu.state.doc.toString());
}),
];
const [mode, setMode] = useState<'write' | 'preview'>('write');
const { editorRef, editorView } = useCodeMirror({ doc, extensions });
useEffect(() => {
if (editorView === null) {
return;
}
if (theme === 'dark') {
editorView.dispatch({
effects: editorTheme.reconfigure([darkTheme]),
});
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [theme, editorView]);
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'>
@@ -42,7 +72,38 @@ export default function Editor() {
<div></div>
</div>
<div className='p-4'>
<div ref={editorRef}></div>
<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>
</div>
<div className='flex items-center justify-end'>
<button type='submit'>Post</button>
+80
View File
@@ -0,0 +1,80 @@
import { HighlightStyle } from '@codemirror/language';
import { EditorView } from '@codemirror/view';
import { tags as t } from '@lezer/highlight';
export const darkTheme = EditorView.theme(
{
'&': {
backgroundColor: '#24272d',
color: '#d0d9e4',
height: '100%',
},
'.cm-content': {
caretColor: '#f8f8f0',
},
'.cm-content, .cm-gutter': { height: '100%' },
'.cm-scroller': { overflow: 'auto' },
'.cm-cursor, .cm-dropCursor': {
borderLeftColor: '#f8f8f0',
},
'&.cm-focused': {
outline: 'none',
},
'&.cm-focused .cm-selectionBackground .cm-selectionBackground, .cm-content ::selection':
{
backgroundColor: '#2f333a',
},
'.cm-activeLine': {
backgroundColor: 'transparent',
},
'.cm-gutters': {
border: 'none',
backgroundColor: '#24272d',
color: 'd0d9e4',
},
'.cm-activeLineGutter': {
backgroundColor: 'transparent',
},
},
{ dark: true }
);
export const highlightStyle = HighlightStyle.define([
{
tag: t.comment,
color: '#6272a4',
},
{
tag: [t.string, t.special(t.brace)],
color: '#f1fa8c',
},
{
tag: [t.number, t.self, t.bool, t.null],
color: '#bd93f9',
},
{
tag: [t.keyword, t.operator],
color: '#ff79c6',
},
{
tag: [t.definitionKeyword, t.typeName],
color: '#8be9fd',
},
{
tag: t.definition(t.typeName),
color: '#f8f8f2',
},
{
tag: [
t.className,
t.definition(t.propertyName),
t.function(t.variableName),
t.attributeName,
],
color: '#50fa7b',
},
{
tag: [t.heading],
color: '#50fa7b',
},
]);