@@ -8,14 +8,34 @@ import Typography from "@tiptap/extension-typography";
88import Link from "@tiptap/extension-link" ;
99import Placeholder from "@tiptap/extension-placeholder" ;
1010import HorizontalRule from "@tiptap/extension-horizontal-rule" ;
11+ import CodeBlockLowlight from "@tiptap/extension-code-block-lowlight" ;
12+ import { createLowlight } from "lowlight" ;
13+ import js from "highlight.js/lib/languages/javascript" ;
14+ import ts from "highlight.js/lib/languages/typescript" ;
15+ import css from "highlight.js/lib/languages/css" ;
16+ import html from "highlight.js/lib/languages/xml" ;
17+ import python from "highlight.js/lib/languages/python" ;
1118import { useState , useCallback , useMemo , useEffect } from "react" ;
1219import { markdownToHtml , htmlToMarkdown } from "./utils" ;
20+ import "highlight.js/styles/github-dark.css" ;
1321
1422import { Button } from "@/components/ui/Button" ;
1523import { Card , CardContent , CardHeader , CardTitle } from "@/components/ui/Card" ;
1624import { Toolbar } from "@/components/common/TextEditor" ;
1725import Loader from "../Loader" ;
1826
27+ const lowlight = createLowlight ( ) ;
28+
29+ lowlight . register ( "js" , js ) ;
30+ lowlight . register ( "javascript" , js ) ;
31+ lowlight . register ( "ts" , ts ) ;
32+ lowlight . register ( "typescript" , ts ) ;
33+ lowlight . register ( "css" , css ) ;
34+ lowlight . register ( "html" , html ) ;
35+ lowlight . register ( "xml" , html ) ;
36+ lowlight . register ( "python" , python ) ;
37+ lowlight . register ( "py" , python ) ;
38+
1939interface TextEditorProps {
2040 markdownOutput ?: boolean ;
2141 value ?: string ;
@@ -29,7 +49,12 @@ const TextEditor = ({ markdownOutput = false, value, onChange }: TextEditorProps
2949
3050 const editor = useEditor ( {
3151 extensions : [
32- StarterKit ,
52+ StarterKit . configure ( {
53+ codeBlock : false ,
54+ } ) ,
55+ CodeBlockLowlight . configure ( {
56+ lowlight,
57+ } ) ,
3358 Underline ,
3459 Typography ,
3560 HorizontalRule ,
@@ -57,14 +82,12 @@ const TextEditor = ({ markdownOutput = false, value, onChange }: TextEditorProps
5782 const html = editor . getHTML ( ) ;
5883 const markdown = htmlToMarkdown ( html ) ;
5984 setMarkdownContent ( markdown ) ;
60- onChange ?.( html ) ;
61- console . log ( "markdown: " , markdown ) ;
62- console . log ( "html: " , html ) ;
85+ onChange ?.( htmlToMarkdown ( html ) ) ;
6386 } ,
6487 editorProps : {
6588 attributes : {
6689 class :
67- "prose prose-md dark:prose-invert max-w-none mx-auto focus:outline-none max-h-[300px] p-3 prose-blockquote:border-primary prose-blockquote:bg-muted/50 prose-blockquote:pl-4 prose-blockquote:py-1 prose-blockquote:before:content-none prose-blockquote:not-italic prose-code:bg-muted prose-code: rounded prose-code:before:content-none prose-code:after:content-none prose-pre:bg-muted prose-pre: border prose-pre:text-foreground prose-pre:p-3 prose-p:my-1 prose-h1:my-2 prose-h2:my-2 prose-h3:my-1 prose-ul:my-1 prose-ol:my-1 prose-li:my-0 prose-hr:my-3" ,
90+ "prose prose-md dark:prose-invert max-w-none mx-auto focus:outline-none max-h-[300px] p-3 prose-blockquote:border-primary prose-blockquote:bg-muted/50 prose-blockquote:pl-4 prose-blockquote:py-1 prose-blockquote:before:content-none prose-blockquote:not-italic prose-code:rounded prose-code:before:content-none prose-code:after:content-none prose-pre:border prose-pre:p-3 prose-p:my-1 prose-h1:my-2 prose-h2:my-2 prose-h3:my-1 prose-ul:my-1 prose-ol:my-1 prose-li:my-0 prose-hr:my-3" ,
6891 } ,
6992 } ,
7093 } ) ;
@@ -98,18 +121,6 @@ const TextEditor = ({ markdownOutput = false, value, onChange }: TextEditorProps
98121 input . click ( ) ;
99122 } , [ editor ] ) ;
100123
101- const downloadMarkdown = useCallback ( ( ) => {
102- const blob = new Blob ( [ markdownContent ] , { type : "text/markdown" } ) ;
103- const url = URL . createObjectURL ( blob ) ;
104- const a = document . createElement ( "a" ) ;
105- a . href = url ;
106- a . download = "document.md" ;
107- document . body . appendChild ( a ) ;
108- a . click ( ) ;
109- document . body . removeChild ( a ) ;
110- URL . revokeObjectURL ( url ) ;
111- } , [ markdownContent ] ) ;
112-
113124 const addLink = useCallback ( ( ) => {
114125 if ( ! editor ) return ;
115126
@@ -129,8 +140,13 @@ const TextEditor = ({ markdownOutput = false, value, onChange }: TextEditorProps
129140 } , [ editor ] ) ;
130141
131142 useEffect ( ( ) => {
132- if ( editor && htmlContent !== undefined && editor . getHTML ( ) !== htmlContent ) {
133- editor . commands . setContent ( htmlContent ) ;
143+ if ( editor && htmlContent !== undefined ) {
144+ const currentMarkdown = htmlToMarkdown ( editor . getHTML ( ) ) ;
145+ const incomingMarkdown = htmlToMarkdown ( htmlContent ) ;
146+
147+ if ( currentMarkdown !== incomingMarkdown && ! editor . isFocused ) {
148+ editor . commands . setContent ( htmlContent ) ;
149+ }
134150 }
135151 } , [ editor , htmlContent ] ) ;
136152
@@ -147,7 +163,7 @@ const TextEditor = ({ markdownOutput = false, value, onChange }: TextEditorProps
147163 onAddImage = { addImage }
148164 onAddImageFromFile = { addImageFromFile }
149165 onAddLink = { addLink }
150- onDownloadMarkdown = { downloadMarkdown }
166+ // onDownloadMarkdown={downloadMarkdown}
151167 isDownloadDisabled = { ! markdownContent }
152168 />
153169 </ CardHeader >
0 commit comments