Skip to content

Commit 9ec7f61

Browse files
committed
refactor: migrate css editor to monaco
1 parent f69c5d6 commit 9ec7f61

File tree

2 files changed

+43
-46
lines changed

2 files changed

+43
-46
lines changed

apps/web/src/components/editor/CssEditor.vue

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -176,10 +176,9 @@ function tabChanged(tabName: string | number) {
176176
</TabsTrigger>
177177
</TabsList>
178178
</Tabs>
179-
<textarea
179+
<div
180180
id="cssEditor"
181-
type="textarea"
182-
placeholder="Your custom css here."
181+
class="flex-1 min-h-0"
183182
/>
184183

185184
<!-- 新增弹窗 -->

apps/web/src/stores/index.ts

Lines changed: 41 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
1+
import type { MonacoEditor } from '@md/shared'
2+
import type CodeMirror from 'codemirror'
13
import { initRenderer } from '@md/core'
4+
import { monaco } from '@md/shared'
25
import {
36
defaultStyleConfig,
47
themeMap,
58
widthOptions,
69
} from '@md/shared/configs'
7-
import CodeMirror from 'codemirror'
810
import { toPng } from 'html-to-image'
911
import { v4 as uuid } from 'uuid'
1012
import DEFAULT_CONTENT from '@/assets/example/markdown.md?raw'
11-
1213
import DEFAULT_CSS_CONTENT from '@/assets/example/theme-css.txt?raw'
13-
import { altKey, shiftKey } from '@/configs/shortcut-key'
1414
import {
1515
addPrefix,
1616
css2json,
@@ -28,6 +28,7 @@ import {
2828
sanitizeTitle,
2929
} from '@/utils'
3030
import { copyPlain } from '@/utils/clipboard'
31+
import 'monaco-editor/esm/vs/basic-languages/css/css.contribution'
3132

3233
/**********************************
3334
* Post 结构接口
@@ -280,10 +281,12 @@ export const useStore = defineStore(`store`, () => {
280281
}
281282
}
282283

283-
// 自义定 CSS 编辑器
284-
const cssEditor = ref<CodeMirror.EditorFromTextArea | null>(null)
284+
// 自义定 CSS 编辑器 (Monaco Editor)
285+
const cssEditor = ref<MonacoEditor.IStandaloneCodeEditor | null>(null)
285286
const setCssEditorValue = (content: string) => {
286-
cssEditor.value!.setValue(content)
287+
if (cssEditor.value) {
288+
toRaw(cssEditor.value).setValue(content)
289+
}
287290
}
288291
/**
289292
* 自定义 CSS 内容
@@ -381,7 +384,7 @@ export const useStore = defineStore(`store`, () => {
381384
isShowLineNumber: isShowLineNumber.value,
382385
})
383386

384-
const raw = editor.value!.getValue()
387+
const raw = toRaw(editor.value!).getValue()
385388
const { html: baseHtml, readingTime: readingTimeResult } = renderMarkdown(raw, renderer)
386389
readingTime.chars = raw.length
387390
readingTime.words = readingTimeResult.words
@@ -409,7 +412,7 @@ export const useStore = defineStore(`store`, () => {
409412

410413
// 更新 CSS
411414
const updateCss = () => {
412-
const json = css2json(cssEditor.value!.getValue())
415+
const json = css2json(toRaw(cssEditor.value!).getValue())
413416
const newTheme = customCssWithTemplate(
414417
json,
415418
primaryColor.value,
@@ -429,47 +432,40 @@ export const useStore = defineStore(`store`, () => {
429432
const cssEditorDom = document.querySelector<HTMLTextAreaElement>(
430433
`#cssEditor`,
431434
)!
432-
cssEditorDom.value = getCurrentTab().content
433-
const theme = isDark.value ? `darcula` : `xq-light`
434-
cssEditor.value = markRaw(
435-
CodeMirror.fromTextArea(cssEditorDom, {
436-
mode: `css`,
437-
theme,
438-
lineNumbers: false,
439-
lineWrapping: true,
440-
styleActiveLine: true,
441-
matchBrackets: true,
442-
autofocus: true,
443-
extraKeys: {
444-
[`${shiftKey}-${altKey}-F`]: function autoFormat(
445-
editor: CodeMirror.Editor,
446-
) {
447-
formatDoc(editor.getValue(), `css`).then((doc) => {
448-
getCurrentTab().content = doc
449-
editor.setValue(doc)
450-
})
451-
},
452-
},
453-
} as never),
454-
)
455435

456-
// 自动提示
457-
cssEditor.value.on(`keyup`, (cm, e) => {
458-
if ((e.keyCode >= 65 && e.keyCode <= 90) || e.keyCode === 189) {
459-
(cm as any).showHint(e)
460-
}
436+
cssEditor.value = monaco.editor.create(cssEditorDom, {
437+
value: getCurrentTab().content,
438+
language: `css`,
439+
theme: isDark.value ? `vs-dark` : `vs`,
440+
lineNumbers: `off`,
441+
automaticLayout: true,
442+
fontSize: 14,
443+
lineHeight: 22,
444+
tabSize: 2,
445+
minimap: { enabled: false },
461446
})
462447

463-
// 实时保存
464-
cssEditor.value.on(`update`, () => {
465-
updateCss()
466-
getCurrentTab().content = cssEditor.value!.getValue()
448+
// 格式化
449+
cssEditor.value.addCommand(monaco.KeyMod.Alt | monaco.KeyMod.Shift | monaco.KeyCode.KeyF, () => {
450+
formatDoc(toRaw(cssEditor.value!).getValue(), `css`).then((doc) => {
451+
toRaw(cssEditor.value!).setValue(doc)
452+
})
453+
})
454+
455+
// 监听内容变化
456+
cssEditor.value.onDidChangeModelContent(() => {
457+
if (cssEditor.value) {
458+
const content = toRaw(cssEditor.value).getValue()
459+
getCurrentTab().content = content
460+
updateCss()
461+
}
467462
})
468463
})
469464

470465
watch(isDark, () => {
471-
const theme = isDark.value ? `darcula` : `xq-light`
472-
toRaw(cssEditor.value)?.setOption?.(`theme`, theme)
466+
if (cssEditor.value) {
467+
cssEditor.value.updateOptions({ theme: isDark.value ? `vs-dark` : `vs` })
468+
}
473469
})
474470

475471
// 重置样式
@@ -498,7 +494,9 @@ export const useStore = defineStore(`store`, () => {
498494
],
499495
}
500496

501-
cssEditor.value!.setValue(DEFAULT_CSS_CONTENT)
497+
if (cssEditor.value) {
498+
toRaw(cssEditor.value).setValue(DEFAULT_CSS_CONTENT)
499+
}
502500

503501
updateCss()
504502
editorRefresh()

0 commit comments

Comments
 (0)