|
@@ -1,60 +1,228 @@
|
|
|
<script setup lang="ts">
|
|
<script setup lang="ts">
|
|
|
|
|
+import { nextTick, onMounted, reactive, ref, watch, onBeforeUnmount, computed } from 'vue'
|
|
|
|
|
+import { useLocalEditorTheme } from "@/utils/useLocalEditorTheme"
|
|
|
import type { editor } from 'monaco-editor'
|
|
import type { editor } from 'monaco-editor'
|
|
|
-
|
|
|
|
|
-import { nextTick, onMounted, ref, watch } from 'vue'
|
|
|
|
|
|
|
+import { ElMessage } from "element-plus"
|
|
|
import * as monaco from 'monaco-editor'
|
|
import * as monaco from 'monaco-editor'
|
|
|
import { IconButton } from '@repo/ui'
|
|
import { IconButton } from '@repo/ui'
|
|
|
|
|
+import { debounce } from "lodash-es"
|
|
|
|
|
+
|
|
|
|
|
+interface CodeEditorType {
|
|
|
|
|
+ // 是否展示工具栏
|
|
|
|
|
+ tools?: boolean
|
|
|
|
|
+ // 是否展示全屏工具
|
|
|
|
|
+ allowFullscreen?: boolean
|
|
|
|
|
+ // 是否展示复制工具
|
|
|
|
|
+ copyCode?: boolean
|
|
|
|
|
+ // 是否自动切换主题
|
|
|
|
|
+ autoToggleTheme?: boolean
|
|
|
|
|
+ // 挂载DOM
|
|
|
|
|
+ appendTo?: string | HTMLElement
|
|
|
|
|
+ // 内容
|
|
|
|
|
+ modelValue?: any
|
|
|
|
|
+ // 语法
|
|
|
|
|
+ language?: string
|
|
|
|
|
+ // 主题
|
|
|
|
|
+ theme?: 'vs-light' | 'vs-dark'
|
|
|
|
|
+ // 是否只读
|
|
|
|
|
+ readOnly?: boolean
|
|
|
|
|
+ // 是否显示行号
|
|
|
|
|
+ lineNumbers?: 'on' | 'off'
|
|
|
|
|
+ // 设置代码模块高度,总高度多40px
|
|
|
|
|
+ height?: number
|
|
|
|
|
+ // 返回结果为string,也可转化为json
|
|
|
|
|
+ formatValue?: 'string' | 'json'
|
|
|
|
|
+ // 插件内部配置
|
|
|
|
|
+ config?: editor.IStandaloneEditorConstructionOptions
|
|
|
|
|
|
|
|
-const props = withDefaults(
|
|
|
|
|
- defineProps<{
|
|
|
|
|
- allowFullscreen?: boolean
|
|
|
|
|
- autoToggleTheme?: boolean
|
|
|
|
|
- bordered?: boolean
|
|
|
|
|
- config?: editor.IStandaloneEditorConstructionOptions
|
|
|
|
|
- language?: string
|
|
|
|
|
- lineNumbers?: 'off' | 'on'
|
|
|
|
|
- modelValue?: any
|
|
|
|
|
- readOnly?: boolean
|
|
|
|
|
- theme?: 'hc-black' | 'vs-dark' | 'vs-light'
|
|
|
|
|
- valueFormat?: string
|
|
|
|
|
- height?: string
|
|
|
|
|
- appendTo?: string | HTMLElement
|
|
|
|
|
- }>(),
|
|
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+const props = withDefaults(defineProps<CodeEditorType>(),
|
|
|
{
|
|
{
|
|
|
|
|
+ //默认配置
|
|
|
|
|
+ tools: true,
|
|
|
|
|
+ copyCode: true,
|
|
|
|
|
+ readOnly: false,
|
|
|
allowFullscreen: true,
|
|
allowFullscreen: true,
|
|
|
- config: () => ({
|
|
|
|
|
- minimap: {
|
|
|
|
|
- enabled: false
|
|
|
|
|
- },
|
|
|
|
|
- selectOnLineNumbers: true
|
|
|
|
|
- }),
|
|
|
|
|
autoToggleTheme: true,
|
|
autoToggleTheme: true,
|
|
|
- language: 'json',
|
|
|
|
|
|
|
+ language: 'javascript',
|
|
|
lineNumbers: 'on',
|
|
lineNumbers: 'on',
|
|
|
- readOnly: false,
|
|
|
|
|
theme: 'vs-light',
|
|
theme: 'vs-light',
|
|
|
- valueFormat: 'string',
|
|
|
|
|
- height: '120px'
|
|
|
|
|
|
|
+ formatValue: 'string',
|
|
|
|
|
+ height: 150,
|
|
|
|
|
+ config: () => ({
|
|
|
|
|
+ minimap: { enabled: false },
|
|
|
|
|
+ selectOnLineNumbers: true
|
|
|
|
|
+ }),
|
|
|
}
|
|
}
|
|
|
)
|
|
)
|
|
|
|
|
|
|
|
-// 动态切换主题
|
|
|
|
|
-const theme = ref('dark')
|
|
|
|
|
|
|
|
|
|
const emit = defineEmits(['update:modelValue', 'update:language'])
|
|
const emit = defineEmits(['update:modelValue', 'update:language'])
|
|
|
|
|
|
|
|
|
|
+let monacoEditor: monaco.editor.IStandaloneCodeEditor | null = null
|
|
|
|
|
+let model: editor.ITextModel | null = null
|
|
|
|
|
+const editContainer = ref<HTMLElement>()
|
|
|
|
|
+
|
|
|
const isFullScreen = ref(false)
|
|
const isFullScreen = ref(false)
|
|
|
|
|
+const {
|
|
|
|
|
+ monacoTheme,
|
|
|
|
|
+ themeClass,
|
|
|
|
|
+ toggleTheme
|
|
|
|
|
+} = useLocalEditorTheme({
|
|
|
|
|
+ defaultTheme: props.theme,
|
|
|
|
|
+ autoToggleTheme: props.autoToggleTheme
|
|
|
|
|
+})
|
|
|
|
|
|
|
|
-const fullScreenStyle = `position: fixed;
|
|
|
|
|
- top: 0;
|
|
|
|
|
- left: 0;
|
|
|
|
|
- right: 0;
|
|
|
|
|
- bottom: 0;
|
|
|
|
|
- z-index: 2999;`
|
|
|
|
|
|
|
+let componentConfig = reactive({
|
|
|
|
|
+ language: props.language
|
|
|
|
|
+})
|
|
|
|
|
|
|
|
-const editContainer = ref<HTMLElement | null>(null)
|
|
|
|
|
|
|
+const languageSource = [
|
|
|
|
|
+ { id: 'javascript', name: 'javascript' },
|
|
|
|
|
+ { id: 'python', name: 'python' },
|
|
|
|
|
+ { id: 'json', name: 'json' }
|
|
|
|
|
+]
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * @description: formatValue为json 格式,需要转换处理
|
|
|
|
|
+ * @return
|
|
|
|
|
+ */
|
|
|
|
|
+const formatValue = (value: any) => {
|
|
|
|
|
+ if (props.formatValue === 'json') {
|
|
|
|
|
+ return JSON.stringify(value ?? {}, null, 2)
|
|
|
|
|
+ }
|
|
|
|
|
+ return value ?? ''
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+onMounted(() => {
|
|
|
|
|
+ // 处理代码转换
|
|
|
|
|
+ model = monaco.editor.createModel(
|
|
|
|
|
+ formatValue(props.modelValue),
|
|
|
|
|
+ componentConfig.language
|
|
|
|
|
+ )
|
|
|
|
|
+
|
|
|
|
|
+ // 接入配置
|
|
|
|
|
+ monacoEditor = monaco.editor.create(editContainer.value!, {
|
|
|
|
|
+ model,
|
|
|
|
|
+ wordWrap: 'on',
|
|
|
|
|
+ automaticLayout: true,
|
|
|
|
|
+ theme: monacoTheme.value,
|
|
|
|
|
+ readOnly: props.readOnly,
|
|
|
|
|
+ lineNumbers: props.lineNumbers,
|
|
|
|
|
+ ...props.config,
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
|
|
+ // 添加空格
|
|
|
|
|
+ monacoEditor.onKeyDown((e) => {
|
|
|
|
|
+ if (e.keyCode === monaco.KeyCode.Space) {
|
|
|
|
|
+ e.preventDefault();
|
|
|
|
|
+ monacoEditor?.trigger('keyboard', 'type', { text: ' ' });
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ // 监听代码输入
|
|
|
|
|
+ monacoEditor.onDidChangeModelContent(updateModelValue)
|
|
|
|
|
+
|
|
|
|
|
+})
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+// 读取传值数据
|
|
|
|
|
+watch(() => props.modelValue, (value) => {
|
|
|
|
|
+ nextTick(() => {
|
|
|
|
|
+ if (!model) return
|
|
|
|
|
+ const next = formatValue(value)
|
|
|
|
|
+ if (model.getValue() !== next) {
|
|
|
|
|
+ model.setValue(next)
|
|
|
|
|
+ }
|
|
|
|
|
+ })
|
|
|
|
|
+}, { immediate: true })
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+// 切换语法,触发回调
|
|
|
|
|
+watch(() => componentConfig.language, (lang) => {
|
|
|
|
|
+ nextTick(() => {
|
|
|
|
|
+ if (!model) return
|
|
|
|
|
+ monaco.editor.setModelLanguage(model, lang)
|
|
|
|
|
+ emit('update:language', lang)
|
|
|
|
|
+ })
|
|
|
|
|
+}, { immediate: true })
|
|
|
|
|
+
|
|
|
|
|
+// 监听全屏, 重新计算layout
|
|
|
|
|
+watch(isFullScreen, () => {
|
|
|
|
|
+ nextTick(() => {
|
|
|
|
|
+ monacoEditor?.layout()
|
|
|
|
|
+ })
|
|
|
|
|
+})
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * @description: 发送回调(formatValue:json,需要转换处理)
|
|
|
|
|
+ * @return {*}
|
|
|
|
|
+ */
|
|
|
|
|
+const updateModelValue = debounce(() => {
|
|
|
|
|
+ if (!model) return
|
|
|
|
|
+ const value = model.getValue()
|
|
|
|
|
+
|
|
|
|
|
+ if (props.formatValue === 'json') {
|
|
|
|
|
+ try {
|
|
|
|
|
+ emit('update:modelValue', JSON.parse(value))
|
|
|
|
|
+ } catch {
|
|
|
|
|
+ return ElMessage.warning('JSON 语法错误')
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ emit('update:modelValue', value)
|
|
|
|
|
+ }
|
|
|
|
|
+}, 1000)
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * @description: 复制代码到粘贴板
|
|
|
|
|
+ * @return {*}
|
|
|
|
|
+ */
|
|
|
|
|
+const copyCode = () => {
|
|
|
|
|
+ const text = model?.getValue()
|
|
|
|
|
+ if (!text) return
|
|
|
|
|
+ try {
|
|
|
|
|
+ navigator.clipboard.writeText(text).then(() => {
|
|
|
|
|
+ ElMessage.success('复制成功!')
|
|
|
|
|
+ })
|
|
|
|
|
+ } catch {
|
|
|
|
|
+ const textarea = document.createElement('textarea')
|
|
|
|
|
+ textarea.value = text
|
|
|
|
|
+ document.body.appendChild(textarea)
|
|
|
|
|
+ textarea.select()
|
|
|
|
|
+ document.execCommand('copy')
|
|
|
|
|
+ textarea.remove()
|
|
|
|
|
+ ElMessage.success('复制成功!')
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * @description: 设置全屏样式
|
|
|
|
|
+ * @return {*}
|
|
|
|
|
+ */
|
|
|
|
|
+const fullScreenStyle = computed(() => {
|
|
|
|
|
+ if (isFullScreen.value) return {}
|
|
|
|
|
+
|
|
|
|
|
+ return {
|
|
|
|
|
+ height: `${props.height + 40}px`
|
|
|
|
|
+ }
|
|
|
|
|
+})
|
|
|
|
|
+/**
|
|
|
|
|
+ * @description: 切换主题, 并设置对应样式
|
|
|
|
|
+ * @return {*}
|
|
|
|
|
+ */
|
|
|
|
|
+const toolTipClass = computed(() => {
|
|
|
|
|
+ return `editor-tooltip editor-tooltip--${themeClass.value}`
|
|
|
|
|
+})
|
|
|
|
|
+const onToggleTheme = () => {
|
|
|
|
|
+ toggleTheme()
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
-let monacoEditor: monaco.editor.IStandaloneCodeEditor | null = null
|
|
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
* 设置文本
|
|
* 设置文本
|
|
@@ -64,6 +232,7 @@ function setValue(text: string) {
|
|
|
monacoEditor?.setValue(text || '')
|
|
monacoEditor?.setValue(text || '')
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+
|
|
|
/**
|
|
/**
|
|
|
* 光标处插入文本
|
|
* 光标处插入文本
|
|
|
* @param text
|
|
* @param text
|
|
@@ -96,60 +265,10 @@ function insertText(text: string) {
|
|
|
monacoEditor?.focus()
|
|
monacoEditor?.focus()
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-onMounted(() => {
|
|
|
|
|
- monacoEditor = monaco.editor.create(editContainer.value as HTMLElement, {
|
|
|
|
|
- value: getValue(),
|
|
|
|
|
- ...props.config,
|
|
|
|
|
- automaticLayout: true,
|
|
|
|
|
- language: props.language,
|
|
|
|
|
- lineNumbers: props.lineNumbers,
|
|
|
|
|
- readOnly: props.readOnly,
|
|
|
|
|
- scrollBeyondLastLine: false,
|
|
|
|
|
- theme: props.theme
|
|
|
|
|
- })
|
|
|
|
|
-
|
|
|
|
|
- function handleToggleTheme() {
|
|
|
|
|
- if (theme.value === 'dark') {
|
|
|
|
|
- monaco.editor.setTheme('vs-dark')
|
|
|
|
|
- } else {
|
|
|
|
|
- monaco.editor.setTheme('vs-light')
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // 自动切换主题
|
|
|
|
|
- if (props.autoToggleTheme) {
|
|
|
|
|
- watch(
|
|
|
|
|
- () => theme,
|
|
|
|
|
- () => {
|
|
|
|
|
- nextTick(() => handleToggleTheme())
|
|
|
|
|
- },
|
|
|
|
|
- {
|
|
|
|
|
- immediate: true
|
|
|
|
|
- }
|
|
|
|
|
- )
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // 获取值
|
|
|
|
|
- function getValue() {
|
|
|
|
|
- // valueFormat 为json 格式,需要转换处理
|
|
|
|
|
- if (props.valueFormat === 'json' && props.modelValue) {
|
|
|
|
|
- return JSON.stringify(props.modelValue, null, 2)
|
|
|
|
|
- }
|
|
|
|
|
- return props.modelValue ?? ''
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // 监听值变化
|
|
|
|
|
- monacoEditor.onDidChangeModelContent(() => {
|
|
|
|
|
- const currenValue = monacoEditor?.getValue()
|
|
|
|
|
-
|
|
|
|
|
- // valueFormat 为json 格式,需要转换处理
|
|
|
|
|
- if (props.valueFormat === 'json' && currenValue) {
|
|
|
|
|
- emit('update:modelValue', JSON.parse(currenValue))
|
|
|
|
|
- return
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- emit('update:modelValue', currenValue ?? '')
|
|
|
|
|
- })
|
|
|
|
|
|
|
+// 销毁model
|
|
|
|
|
+onBeforeUnmount(() => {
|
|
|
|
|
+ monacoEditor?.dispose()
|
|
|
|
|
+ model?.dispose()
|
|
|
})
|
|
})
|
|
|
|
|
|
|
|
defineExpose({
|
|
defineExpose({
|
|
@@ -159,28 +278,187 @@ defineExpose({
|
|
|
</script>
|
|
</script>
|
|
|
<template>
|
|
<template>
|
|
|
<Teleport :disabled="!appendTo" :to="appendTo">
|
|
<Teleport :disabled="!appendTo" :to="appendTo">
|
|
|
- <div ref="editContainer" :class="{ bordered: props.bordered }"
|
|
|
|
|
- :style="isFullScreen ? fullScreenStyle : { height: props.height }"
|
|
|
|
|
- class="code-editor w-full h-full relative">
|
|
|
|
|
- <div class="z-999 text-$epic-text-helper absolute right-4 top-2 cursor-pointer text-xl"
|
|
|
|
|
- @click="isFullScreen = !isFullScreen" v-if="props.allowFullscreen">
|
|
|
|
|
- <IconButton v-if="!isFullScreen" icon="lucide:fullscreen" link />
|
|
|
|
|
- <IconButton v-else icon="material-symbols-light:fullscreen-exit-rounded" link />
|
|
|
|
|
|
|
+ <div class="monacoEditor !m-0" :class="[themeClass, { 'is-fullscreen': isFullScreen }]"
|
|
|
|
|
+ :style="fullScreenStyle">
|
|
|
|
|
+
|
|
|
|
|
+ <div class="tools h-[33px] flex items-center justify-between gap-2" v-if="props.tools">
|
|
|
|
|
+ <!-- 语法切换 -->
|
|
|
|
|
+ <ElTooltip :effect="themeClass" :popper-class="toolTipClass" placement="top" content="切换语法">
|
|
|
|
|
+ <div class="w-1/3">
|
|
|
|
|
+
|
|
|
|
|
+ <ElSelect v-model="componentConfig.language">
|
|
|
|
|
+ <ElOption v-for="value in languageSource" :label="value.name" :value="value.id" />
|
|
|
|
|
+ </ElSelect>
|
|
|
|
|
+
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </ElTooltip>
|
|
|
|
|
+ <div class="flex-1 flex items-center justify-end gap-1">
|
|
|
|
|
+ <!-- 放大/缩小 -->
|
|
|
|
|
+ <ElTooltip :effect="themeClass" placement="top" :popper-class="toolTipClass"
|
|
|
|
|
+ :content="!isFullScreen ? '放大' : '恢复正常'">
|
|
|
|
|
+ <div class="cursor-pointer text-xl text-center px-2" @click="isFullScreen = !isFullScreen"
|
|
|
|
|
+ v-if="props.allowFullscreen">
|
|
|
|
|
+ <IconButton :icon="isFullScreen ? 'lucide:minimize' : 'lucide:fullscreen'" link
|
|
|
|
|
+ class="fullscreen" />
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </ElTooltip>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- copy -->
|
|
|
|
|
+ <ElTooltip :effect="themeClass" :popper-class="toolTipClass" placement="top" content="复制">
|
|
|
|
|
+ <div class="copy text-center px-2" @click="copyCode" v-if="props.copyCode">
|
|
|
|
|
+ <IconButton icon="lucide:copy" link class="copyIcon"></IconButton>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </ElTooltip>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 主题 -->
|
|
|
|
|
+ <ElTooltip :effect="themeClass" :popper-class="toolTipClass" placement="top" content="主题">
|
|
|
|
|
+ <div class="copy text-center px-2" @click="onToggleTheme">
|
|
|
|
|
+ <IconButton :icon="themeClass === 'dark' ? 'lucide:moon' : 'lucide:sun'" link
|
|
|
|
|
+ class="themeIcon">
|
|
|
|
|
+ </IconButton>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </ElTooltip>
|
|
|
|
|
+ </div>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
+ <!-- 编辑器 -->
|
|
|
|
|
+ <div class="editor-wrapper">
|
|
|
|
|
+ <div ref="editContainer" class="code-editor"></div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
</div>
|
|
</div>
|
|
|
</Teleport>
|
|
</Teleport>
|
|
|
</template>
|
|
</template>
|
|
|
|
|
+<style lang="less">
|
|
|
|
|
+.editor-tooltip {
|
|
|
|
|
+ border-radius: 6px;
|
|
|
|
|
+ font-size: 12px;
|
|
|
|
|
+ padding: 6px 10px;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// light
|
|
|
|
|
+.editor-tooltip--light {
|
|
|
|
|
+ background-color: #ffffff !important;
|
|
|
|
|
+ color: #1e1e1e !important;
|
|
|
|
|
+ border: 1px solid #e5e7eb;
|
|
|
|
|
+
|
|
|
|
|
+ .el-popper__arrow::before {
|
|
|
|
|
+ background: #ffffff !important;
|
|
|
|
|
+ border: 1px solid #e5e7eb;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// dark
|
|
|
|
|
+.editor-tooltip--dark {
|
|
|
|
|
+ background-color: #1e1e1e !important;
|
|
|
|
|
+ color: #ffffff !important;
|
|
|
|
|
+
|
|
|
|
|
+ .el-popper__arrow::before {
|
|
|
|
|
+ background: #1e1e1e !important;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+</style>
|
|
|
<style lang="less" scoped>
|
|
<style lang="less" scoped>
|
|
|
-.code-editor {
|
|
|
|
|
- width: 100%;
|
|
|
|
|
- min-height: 150px;
|
|
|
|
|
|
|
+.monacoEditor {
|
|
|
|
|
+ border: 1px solid #eee;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ flex-direction: column;
|
|
|
|
|
+ transition: height 0.25s ease, inset 0.25s ease, background-color 0.2s;
|
|
|
|
|
|
|
|
- :deep(.monaco-editor) {
|
|
|
|
|
|
|
+ &.is-fullscreen {
|
|
|
|
|
+ position: absolute;
|
|
|
|
|
+ inset: 0;
|
|
|
|
|
+ z-index: 1000;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .tools {
|
|
|
|
|
+ border-bottom: 1px solid #eeeeee83;
|
|
|
|
|
+ padding-bottom: 6px;
|
|
|
|
|
+
|
|
|
|
|
+ ::v-deep(.el-select .el-select__wrapper) {
|
|
|
|
|
+ border: none;
|
|
|
|
|
+ box-shadow: none;
|
|
|
|
|
+ background-color: #ffff;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ ::v-deep(.el-select .el-select__placeholder) {
|
|
|
|
|
+ color: #1e1e1e;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .editor-wrapper {
|
|
|
|
|
+ flex: 1;
|
|
|
|
|
+ overflow: hidden;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .code-editor {
|
|
|
|
|
+ width: 100%;
|
|
|
height: 100%;
|
|
height: 100%;
|
|
|
|
|
+
|
|
|
|
|
+ ::v-deep(.monaco-editor) {
|
|
|
|
|
+ height: 100%;
|
|
|
|
|
+ background-color: #ffffff;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ &.bordered {
|
|
|
|
|
+ border: 1px solid var(--epic-border-color);
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- &.bordered {
|
|
|
|
|
- border: 1px solid var(--epic-border-color);
|
|
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.light {
|
|
|
|
|
+ background-color: #ffffff;
|
|
|
|
|
+ color: #1e1e1e;
|
|
|
|
|
+
|
|
|
|
|
+ &:hover {
|
|
|
|
|
+ color: #1e1e1e;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .tools {
|
|
|
|
|
+ ::v-deep(.el-select .el-select__wrapper) {
|
|
|
|
|
+ border: none;
|
|
|
|
|
+ box-shadow: none;
|
|
|
|
|
+ background-color: #ffffff;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ ::v-deep(.el-select .el-select__placeholder) {
|
|
|
|
|
+ color: #1e1e1e;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .fullscreen,
|
|
|
|
|
+ .fullscreen-exit,
|
|
|
|
|
+ .themeIcon,
|
|
|
|
|
+ .copyIcon {
|
|
|
|
|
+ color: #1e1e1e;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.dark {
|
|
|
|
|
+ background-color: #1e1e1e;
|
|
|
|
|
+ color: #ffffff;
|
|
|
|
|
+
|
|
|
|
|
+ &:hover {
|
|
|
|
|
+ color: #ffffff;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .tools {
|
|
|
|
|
+ ::v-deep(.el-select .el-select__wrapper) {
|
|
|
|
|
+ border: none;
|
|
|
|
|
+ box-shadow: none;
|
|
|
|
|
+ background-color: #1e1e1e;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ ::v-deep(.el-select .el-select__placeholder) {
|
|
|
|
|
+ color: #ffffff;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .fullscreen,
|
|
|
|
|
+ .fullscreen-exit,
|
|
|
|
|
+ .themeIcon,
|
|
|
|
|
+ .copyIcon {
|
|
|
|
|
+ color: #ffffff;
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
</style>
|
|
</style>
|