aboutsummaryrefslogtreecommitdiffstats
path: root/renderer
diff options
context:
space:
mode:
Diffstat (limited to 'renderer')
-rw-r--r--renderer/src/components/DocumentPane.tsx100
-rw-r--r--renderer/src/styles/globals.css14
2 files changed, 108 insertions, 6 deletions
diff --git a/renderer/src/components/DocumentPane.tsx b/renderer/src/components/DocumentPane.tsx
index 95d7d03..cf777b1 100644
--- a/renderer/src/components/DocumentPane.tsx
+++ b/renderer/src/components/DocumentPane.tsx
@@ -1,6 +1,12 @@
1import React, { useState } from "react"; 1import React, { useState, useRef, useEffect } from "react";
2import ReactMarkdown from "react-markdown"; 2import ReactMarkdown from "react-markdown";
3import remarkGfm from "remark-gfm"; 3import remarkGfm from "remark-gfm";
4import { EditorState } from "@codemirror/state";
5import { EditorView, keymap, lineNumbers, highlightActiveLine } from "@codemirror/view";
6import { markdown } from "@codemirror/lang-markdown";
7import { languages } from "@codemirror/language-data";
8import { defaultKeymap, history, historyKeymap } from "@codemirror/commands";
9import { oneDark } from "@codemirror/theme-one-dark";
4import type { Phase } from "../types"; 10import type { Phase } from "../types";
5 11
6interface DocumentPaneProps { 12interface DocumentPaneProps {
@@ -11,6 +17,90 @@ interface DocumentPaneProps {
11 showOnboarding?: boolean; 17 showOnboarding?: boolean;
12} 18}
13 19
20function MarkdownEditor({
21 content,
22 onChange,
23 disabled,
24}: {
25 content: string;
26 onChange: (content: string) => void;
27 disabled: boolean;
28}) {
29 const editorRef = useRef<HTMLDivElement>(null);
30 const viewRef = useRef<EditorView | null>(null);
31
32 useEffect(() => {
33 if (!editorRef.current) return;
34
35 const updateListener = EditorView.updateListener.of((update) => {
36 if (update.docChanged) {
37 onChange(update.state.doc.toString());
38 }
39 });
40
41 const state = EditorState.create({
42 doc: content,
43 extensions: [
44 lineNumbers(),
45 highlightActiveLine(),
46 history(),
47 keymap.of([...defaultKeymap, ...historyKeymap]),
48 markdown({ codeLanguages: languages }),
49 oneDark,
50 updateListener,
51 EditorView.editable.of(!disabled),
52 EditorView.theme({
53 "&": {
54 height: "100%",
55 fontSize: "14px",
56 },
57 ".cm-scroller": {
58 overflow: "auto",
59 fontFamily: '"SF Mono", Monaco, "Cascadia Code", monospace',
60 },
61 ".cm-content": {
62 padding: "16px 0",
63 },
64 ".cm-line": {
65 padding: "0 16px",
66 },
67 }),
68 ],
69 });
70
71 const view = new EditorView({
72 state,
73 parent: editorRef.current,
74 });
75
76 viewRef.current = view;
77
78 return () => {
79 view.destroy();
80 viewRef.current = null;
81 };
82 }, [disabled]);
83
84 // Update content when it changes externally
85 useEffect(() => {
86 const view = viewRef.current;
87 if (!view) return;
88
89 const currentContent = view.state.doc.toString();
90 if (content !== currentContent) {
91 view.dispatch({
92 changes: {
93 from: 0,
94 to: currentContent.length,
95 insert: content,
96 },
97 });
98 }
99 }, [content]);
100
101 return <div ref={editorRef} className="codemirror-editor" />;
102}
103
14export function DocumentPane({ 104export function DocumentPane({
15 content, 105 content,
16 onChange, 106 onChange,
@@ -115,12 +205,10 @@ export function DocumentPane({
115 </div> 205 </div>
116 206
117 {isEditing ? ( 207 {isEditing ? (
118 <textarea 208 <MarkdownEditor
119 className="document-content editing" 209 content={content}
120 value={content} 210 onChange={onChange}
121 onChange={(e) => onChange(e.target.value)}
122 disabled={disabled} 211 disabled={disabled}
123 placeholder={`${filename} will appear here...`}
124 /> 212 />
125 ) : ( 213 ) : (
126 <div 214 <div
diff --git a/renderer/src/styles/globals.css b/renderer/src/styles/globals.css
index 384ebc5..f115734 100644
--- a/renderer/src/styles/globals.css
+++ b/renderer/src/styles/globals.css
@@ -152,6 +152,20 @@ body {
152 color: var(--text-primary); 152 color: var(--text-primary);
153} 153}
154 154
155.codemirror-editor {
156 flex: 1;
157 overflow: hidden;
158}
159
160.codemirror-editor .cm-editor {
161 height: 100%;
162}
163
164.codemirror-editor .cm-gutters {
165 background: var(--bg-secondary);
166 border-right: 1px solid var(--border);
167}
168
155.document-content.rendered { 169.document-content.rendered {
156 line-height: 1.7; 170 line-height: 1.7;
157} 171}