feat: 升级 CodeMirror 编辑器并新增 Markdown 工具栏
This commit is contained in:
+40
-14
@@ -9,6 +9,7 @@ import {
|
||||
useRef,
|
||||
useState
|
||||
} from "react";
|
||||
import type { EditorView } from "@codemirror/view";
|
||||
import {
|
||||
createPagedDocumentPayload,
|
||||
getPaperDimensionsMm,
|
||||
@@ -71,6 +72,11 @@ import {
|
||||
applyThemeDefaults,
|
||||
selectTheme
|
||||
} from "./theme-margins";
|
||||
import {
|
||||
MarkdownEditor,
|
||||
type MarkdownEditorHandle
|
||||
} from "./MarkdownEditor";
|
||||
import { MarkdownToolbar } from "./MarkdownToolbar";
|
||||
|
||||
const PrecisePdfPreview = lazy(async () => {
|
||||
const module = await import("./PrecisePdfPreview");
|
||||
@@ -107,6 +113,11 @@ const initialDocumentKind: DocumentKind = startsWithBlankMarkdown
|
||||
|
||||
export function App() {
|
||||
const [markdown, setMarkdown] = useState(initialMarkdown);
|
||||
const [editorDocumentVersion, setEditorDocumentVersion] =
|
||||
useState(0);
|
||||
const [editorView, setEditorView] = useState<EditorView | null>(
|
||||
null
|
||||
);
|
||||
const [fileName, setFileName] = useState(initialFileName);
|
||||
const [documentKind, setDocumentKind] =
|
||||
useState<DocumentKind>(initialDocumentKind);
|
||||
@@ -141,7 +152,7 @@ export function App() {
|
||||
current: 0,
|
||||
total: 0
|
||||
});
|
||||
const editorRef = useRef<HTMLTextAreaElement>(null);
|
||||
const editorRef = useRef<MarkdownEditorHandle>(null);
|
||||
const markdownFileInputRef = useRef<HTMLInputElement>(null);
|
||||
const moreMenuRef = useRef<HTMLDivElement>(null);
|
||||
const previewScrollRef = useRef<HTMLDivElement>(null);
|
||||
@@ -158,6 +169,11 @@ export function App() {
|
||||
const themeRefreshTargetRef = useRef<number | undefined>(undefined);
|
||||
documentDirtyRef.current = documentDirty;
|
||||
|
||||
function replaceMarkdownDocument(content: string) {
|
||||
setMarkdown(content);
|
||||
setEditorDocumentVersion((version) => version + 1);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
const bridge = window.mdToPdfDesktop;
|
||||
if (!bridge) {
|
||||
@@ -191,7 +207,7 @@ export function App() {
|
||||
return;
|
||||
}
|
||||
setAppError("");
|
||||
setMarkdown(opened.markdown);
|
||||
replaceMarkdownDocument(opened.markdown);
|
||||
setFileName(opened.fileName);
|
||||
setDocumentKind("file");
|
||||
setSavedMarkdown(opened.markdown);
|
||||
@@ -658,9 +674,13 @@ export function App() {
|
||||
|
||||
function synchronizeScroll(origin: "editor" | "preview") {
|
||||
const source =
|
||||
origin === "editor" ? editorRef.current : getPreviewScroller();
|
||||
origin === "editor"
|
||||
? editorRef.current?.getScrollElement()
|
||||
: getPreviewScroller();
|
||||
const target =
|
||||
origin === "editor" ? getPreviewScroller() : editorRef.current;
|
||||
origin === "editor"
|
||||
? getPreviewScroller()
|
||||
: editorRef.current?.getScrollElement();
|
||||
if (!source || !target) {
|
||||
return;
|
||||
}
|
||||
@@ -866,7 +886,7 @@ export function App() {
|
||||
try {
|
||||
setAppError("");
|
||||
const content = await file.text();
|
||||
setMarkdown(content);
|
||||
replaceMarkdownDocument(content);
|
||||
setFileName(file.name);
|
||||
setDocumentKind("file");
|
||||
setSavedMarkdown(content);
|
||||
@@ -885,7 +905,7 @@ export function App() {
|
||||
if (!opened) {
|
||||
return;
|
||||
}
|
||||
setMarkdown(opened.markdown);
|
||||
replaceMarkdownDocument(opened.markdown);
|
||||
setFileName(opened.fileName);
|
||||
setDocumentKind("file");
|
||||
setSavedMarkdown(opened.markdown);
|
||||
@@ -923,7 +943,7 @@ export function App() {
|
||||
try {
|
||||
setAppError("");
|
||||
await window.mdToPdfDesktop?.startNewMarkdown();
|
||||
setMarkdown("");
|
||||
replaceMarkdownDocument("");
|
||||
setFileName("");
|
||||
setDocumentKind("new");
|
||||
setSavedMarkdown("");
|
||||
@@ -1034,7 +1054,7 @@ export function App() {
|
||||
try {
|
||||
setAppError("");
|
||||
await window.mdToPdfDesktop?.startNewMarkdown();
|
||||
setMarkdown(sample.markdown);
|
||||
replaceMarkdownDocument(sample.markdown);
|
||||
setFileName(sample.fileName);
|
||||
setDocumentKind("sample");
|
||||
setSavedMarkdown(sample.markdown);
|
||||
@@ -1078,7 +1098,7 @@ export function App() {
|
||||
try {
|
||||
setAppError("");
|
||||
await window.mdToPdfDesktop?.startNewMarkdown();
|
||||
setMarkdown(tutorial.markdown);
|
||||
replaceMarkdownDocument(tutorial.markdown);
|
||||
setFileName(tutorial.fileName);
|
||||
setDocumentKind("sample");
|
||||
setSavedMarkdown(tutorial.markdown);
|
||||
@@ -1522,12 +1542,13 @@ export function App() {
|
||||
收起
|
||||
</button>
|
||||
</div>
|
||||
<textarea
|
||||
<MarkdownToolbar editorView={editorView} />
|
||||
<MarkdownEditor
|
||||
ref={editorRef}
|
||||
aria-label="Markdown 内容"
|
||||
value={markdown}
|
||||
spellCheck={false}
|
||||
onChange={(event) => setMarkdown(event.target.value)}
|
||||
documentVersion={editorDocumentVersion}
|
||||
onChange={setMarkdown}
|
||||
onEditorReady={setEditorView}
|
||||
onScroll={() => synchronizeScroll("editor")}
|
||||
/>
|
||||
</div>
|
||||
@@ -1537,7 +1558,12 @@ export function App() {
|
||||
className="source-panel-restore"
|
||||
aria-controls="markdown-source-content"
|
||||
aria-expanded="false"
|
||||
onClick={() => setSourcePanelCollapsed(false)}
|
||||
onClick={() => {
|
||||
setSourcePanelCollapsed(false);
|
||||
window.requestAnimationFrame(() =>
|
||||
editorRef.current?.focus()
|
||||
);
|
||||
}}
|
||||
>
|
||||
展开源文本
|
||||
</button>
|
||||
|
||||
Reference in New Issue
Block a user