2
0
mirror of https://github.com/acepanel/panel.git synced 2026-02-05 14:53:19 +08:00
Files
panel/web/src/components/common/DiffEditor.vue

165 lines
3.6 KiB
Vue

<script setup lang="ts">
import { useThemeStore } from '@/store'
import { getMonaco } from '@/utils/monaco'
import type * as Monaco from 'monaco-editor'
import { useThemeVars } from 'naive-ui'
const props = defineProps({
original: {
type: String,
required: true
},
lang: {
type: String,
required: false,
default: 'yaml'
},
height: {
type: String,
required: false,
default: '60vh'
},
readOnly: {
type: Boolean,
required: false,
default: false
}
})
const modified = defineModel<string>('modified', { type: String, required: true })
const containerRef = ref<HTMLDivElement>()
const editorRef = shallowRef<Monaco.editor.IStandaloneDiffEditor>()
const monacoRef = shallowRef<typeof Monaco>()
const loading = ref(true)
const themeStore = useThemeStore()
const themeVars = useThemeVars()
async function initEditor() {
if (!containerRef.value) return
const monaco = await getMonaco(themeStore.locale)
monacoRef.value = monaco
const originalModel = monaco.editor.createModel(props.original, props.lang)
const modifiedModel = monaco.editor.createModel(modified.value, props.lang)
editorRef.value = monaco.editor.createDiffEditor(containerRef.value, {
theme: 'vs' + (themeStore.darkMode ? '-dark' : ''),
automaticLayout: true,
smoothScrolling: true,
readOnly: props.readOnly,
renderSideBySide: true,
enableSplitViewResizing: true,
originalEditable: false
})
editorRef.value.setModel({
original: originalModel,
modified: modifiedModel
})
// 监听修改后的内容变化
modifiedModel.onDidChangeContent(() => {
const newValue = modifiedModel.getValue()
if (newValue !== modified.value) {
modified.value = newValue
}
})
loading.value = false
}
watch(
() => props.original,
(newOriginal) => {
if (editorRef.value && monacoRef.value) {
const model = editorRef.value.getModel()
if (model?.original) {
model.original.setValue(newOriginal)
}
}
}
)
watch(modified, (newModified) => {
if (editorRef.value) {
const model = editorRef.value.getModel()
if (model?.modified && model.modified.getValue() !== newModified) {
model.modified.setValue(newModified)
}
}
})
watch(
() => props.lang,
(newLang) => {
if (editorRef.value && monacoRef.value) {
const model = editorRef.value.getModel()
if (model?.original) {
monacoRef.value.editor.setModelLanguage(model.original, newLang)
}
if (model?.modified) {
monacoRef.value.editor.setModelLanguage(model.modified, newLang)
}
}
}
)
watch(
() => props.readOnly,
(newReadOnly) => {
if (editorRef.value) {
editorRef.value.updateOptions({ readOnly: newReadOnly })
}
}
)
onMounted(() => {
initEditor()
})
onBeforeUnmount(() => {
const model = editorRef.value?.getModel()
model?.original?.dispose()
model?.modified?.dispose()
editorRef.value?.dispose()
})
</script>
<template>
<div class="diff-editor" :style="{ height: props.height, borderColor: themeVars.borderColor }">
<div v-if="loading" class="editor-loading">
<n-spin size="medium" />
</div>
<div ref="containerRef" class="editor-container" :style="{ height: props.height }" />
</div>
</template>
<style scoped lang="scss">
.diff-editor {
position: relative;
width: 100%;
border: 1px solid;
border-radius: 3px;
overflow: hidden;
}
.editor-loading {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
display: flex;
align-items: center;
justify-content: center;
z-index: 1;
}
.editor-container {
width: 100%;
}
</style>