diff --git a/src/renderer/components/MarkdownComposer.tsx b/src/renderer/components/MarkdownComposer.tsx index 6f77cc7..e0d5ed0 100644 --- a/src/renderer/components/MarkdownComposer.tsx +++ b/src/renderer/components/MarkdownComposer.tsx @@ -20,7 +20,7 @@ import { $convertFromMarkdownString, $convertToMarkdownString, } from '@lexical/markdown'; -import { $isCodeNode, $createCodeNode, CodeNode } from '@lexical/code'; +import { $isCodeNode, $createCodeNode, CodeNode, registerCodeHighlighting } from '@lexical/code'; import { $isListNode, INSERT_ORDERED_LIST_COMMAND, @@ -73,6 +73,38 @@ const editorTheme: EditorThemeClasses = { }, quote: 'mc-blockquote', code: 'mc-code-block', + codeHighlight: { + atrule: 'mc-tok-atrule', + attr: 'mc-tok-attr', + boolean: 'mc-tok-boolean', + builtin: 'mc-tok-builtin', + cdata: 'mc-tok-comment', + char: 'mc-tok-string', + class: 'mc-tok-function', + 'class-name': 'mc-tok-function', + comment: 'mc-tok-comment', + constant: 'mc-tok-constant', + deleted: 'mc-tok-deleted', + doctype: 'mc-tok-comment', + entity: 'mc-tok-symbol', + function: 'mc-tok-function', + important: 'mc-tok-keyword', + inserted: 'mc-tok-inserted', + keyword: 'mc-tok-keyword', + namespace: 'mc-tok-namespace', + number: 'mc-tok-number', + operator: 'mc-tok-operator', + prolog: 'mc-tok-comment', + property: 'mc-tok-property', + punctuation: 'mc-tok-punctuation', + regex: 'mc-tok-regex', + selector: 'mc-tok-selector', + string: 'mc-tok-string', + symbol: 'mc-tok-symbol', + tag: 'mc-tok-tag', + url: 'mc-tok-string', + variable: 'mc-tok-variable', + }, link: 'mc-link', }; @@ -146,6 +178,15 @@ function EditorRefPlugin({ editorRef }: { editorRef: React.MutableRefObject { + return registerCodeHighlighting(editor); + }, [editor]); + return null; +} + /** Syncs the React `disabled` prop to the Lexical editable state. */ function EditablePlugin({ disabled }: { disabled: boolean }) { const [editor] = useLexicalComposerContext(); @@ -556,6 +597,7 @@ export const MarkdownComposer = forwardRef + diff --git a/src/renderer/lib/markdownEditor.ts b/src/renderer/lib/markdownEditor.ts index 9f7e208..6531870 100644 --- a/src/renderer/lib/markdownEditor.ts +++ b/src/renderer/lib/markdownEditor.ts @@ -1,4 +1,4 @@ -import { CodeNode } from '@lexical/code'; +import { CodeHighlightNode, CodeNode } from '@lexical/code'; import { AutoLinkNode, LinkNode } from '@lexical/link'; import { type Transformer, TRANSFORMERS } from '@lexical/markdown'; import { ListItemNode, ListNode } from '@lexical/list'; @@ -38,6 +38,7 @@ export const markdownEditorNodes: ReadonlyArray> = [ LinkNode, AutoLinkNode, CodeNode, + CodeHighlightNode, ]; export const markdownEditorTransformers: ReadonlyArray = TRANSFORMERS; diff --git a/src/renderer/styles.css b/src/renderer/styles.css index c66af0c..4229926 100644 --- a/src/renderer/styles.css +++ b/src/renderer/styles.css @@ -292,6 +292,29 @@ textarea { text-underline-offset: 2px; } +/* Syntax highlighting tokens (dark theme) */ +.mc-tok-comment { color: #6b7280; font-style: italic; } +.mc-tok-keyword { color: #c084fc; } +.mc-tok-string { color: #86efac; } +.mc-tok-number { color: #fbbf24; } +.mc-tok-boolean { color: #fbbf24; } +.mc-tok-constant { color: #fbbf24; } +.mc-tok-function { color: #93c5fd; } +.mc-tok-builtin { color: #67e8f9; } +.mc-tok-operator { color: #f9a8d4; } +.mc-tok-punctuation { color: #a1a1aa; } +.mc-tok-property { color: #7dd3fc; } +.mc-tok-variable { color: #fca5a5; } +.mc-tok-tag { color: #f87171; } +.mc-tok-attr { color: #fdba74; } +.mc-tok-atrule { color: #c084fc; } +.mc-tok-selector { color: #86efac; } +.mc-tok-regex { color: #fcd34d; } +.mc-tok-symbol { color: #fbbf24; } +.mc-tok-namespace { color: #f87171; opacity: 0.8; } +.mc-tok-deleted { color: #fca5a5; text-decoration: line-through; } +.mc-tok-inserted { color: #86efac; } + /* React Flow dark theme overrides */ .react-flow__node { font-family: inherit;