highlight markdown in editor

This commit is contained in:
EGOIST 2022-05-07 22:27:17 +08:00
parent 69355707a7
commit fea7bbf09c
5 changed files with 307 additions and 340 deletions

View File

@ -1,9 +1,26 @@
import { useEffect, useRef, useState } from "react"
import { EditorState } from "@codemirror/state"
import { EditorView, keymap, ViewUpdate } from "@codemirror/view"
import { indentWithTab } from "@codemirror/commands"
import {
EditorView,
keymap,
type ViewUpdate,
dropCursor,
drawSelection,
crosshairCursor,
placeholder as placeholderExtension,
} from "@codemirror/view"
import {
history,
defaultKeymap,
historyKeymap,
indentWithTab,
} from "@codemirror/commands"
import { markdown } from "@codemirror/lang-markdown"
import { history } from "@codemirror/history"
import {
defaultHighlightStyle,
indentOnInput,
syntaxHighlighting,
} from "@codemirror/language"
const theme = EditorView.theme({
".cm-scroller": {
@ -22,7 +39,8 @@ const theme = EditorView.theme({
export const Editor: React.FC<{
value: string
onChange: (value: string) => void
}> = ({ value, onChange }) => {
placeholder?: string
}> = ({ value, onChange, placeholder }) => {
const editorRef = useRef<HTMLDivElement | null>(null)
const [view, setView] = useState<EditorView | null>(null)
@ -37,13 +55,20 @@ export const Editor: React.FC<{
const view = new EditorView({
state: EditorState.create({
doc: value,
doc: "",
extensions: [
keymap.of([indentWithTab]),
markdown(),
keymap.of([indentWithTab, ...defaultKeymap, ...historyKeymap]),
history(),
dropCursor(),
drawSelection(),
indentOnInput(),
crosshairCursor(),
EditorState.allowMultipleSelections.of(true),
updateListener,
EditorView.lineWrapping,
markdown(),
placeholderExtension(placeholder || ""),
syntaxHighlighting(defaultHighlightStyle, { fallback: true }),
theme,
],
}),
@ -56,7 +81,7 @@ export const Editor: React.FC<{
view.destroy()
setView(null)
}
}, [])
}, [onChange, placeholder])
// Update view state when `value` changed
useEffect(() => {

View File

@ -2,7 +2,7 @@ import { Popover } from "@headlessui/react"
import { useFetcher, useLoaderData, useParams } from "@remix-run/react"
import clsx from "clsx"
import dayjs from "dayjs"
import { useEffect, useState } from "react"
import { useCallback, useEffect, useState } from "react"
import { DashboardMain } from "~/components/dashboard/DashboardMain"
import { Button } from "~/components/ui/Button"
import { getPageVisibility } from "~/lib/page-helpers"
@ -14,7 +14,6 @@ import {
type LoaderFunction,
redirect,
} from "@remix-run/node"
import ReactCodeMirror from "@uiw/react-codemirror"
import { siteController } from "~/controllers/site.controller"
import { getAuthUser } from "~/lib/auth.server"
import { getSite } from "~/models/site.model"
@ -22,6 +21,7 @@ import { z } from "zod"
import toast from "react-hot-toast"
import { Input } from "~/components/ui/Input"
import { getSiteLink } from "~/lib/helpers"
import { Editor } from "~/components/ui/Editor"
export const loader: LoaderFunction = async ({ request, params }) => {
const user = await getAuthUser(request)
@ -139,6 +139,11 @@ export default function SubdomainEditor() {
}
}, [fetcher.type])
const handleEditorContentChange = useCallback(
(value) => updateValue("content", value),
[]
)
return (
<DashboardMain fullWidth>
<header className="flex justify-between absolute top-0 left-0 right-0 z-10 px-5 h-14 border-b items-center text-sm">
@ -229,15 +234,16 @@ export default function SubdomainEditor() {
name="title"
value={values.title}
onChange={(e) => updateValue("title", e.target.value)}
className="h-12 ml-1 inline-flex items-center border-none text-2xl font-bold w-full focus:outline-none"
className="h-12 ml-1 inline-flex items-center border-none text-3xl font-bold w-full focus:outline-none"
placeholder="Title goes here.."
/>
</div>
<div className="mt-5">
<div className="">
<ReactCodeMirror
<Editor
value={values.content}
onChange={(value) => updateValue("content", value)}
onChange={handleEditorContentChange}
placeholder="Start writing here.."
/>
</div>
</div>

View File

@ -1,5 +1,9 @@
import { DashboardMain } from "~/components/dashboard/DashboardMain"
export const loader = () => {
return { foo: 1 }
}
export default function SubdomainIndex() {
return <DashboardMain>hi</DashboardMain>
}

View File

@ -19,8 +19,8 @@
"dependencies": {
"@aws-sdk/client-s3": "^3.81.0",
"@codemirror/commands": "^0.20.0",
"@codemirror/history": "^0.19.2",
"@codemirror/lang-markdown": "^0.20.0",
"@codemirror/language": "^0.20.0",
"@codemirror/state": "^0.20.0",
"@codemirror/view": "^0.20.3",
"@headlessui/react": "^1.6.0",
@ -29,7 +29,6 @@
"@remix-run/node": "*",
"@remix-run/react": "*",
"@remix-run/serve": "*",
"@uiw/react-codemirror": "^4.7.0",
"@vercel/node": "^1.14.0",
"clsx": "^1.1.1",
"compression": "^1.7.4",

File diff suppressed because it is too large Load Diff