Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 20 additions & 2 deletions ui/src/components/COMPONENT_README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ src/components/
│ │ ├── MdEditor.vue # 支持多语言和自定义页脚的 Markdown 编辑器
│ │ ├── MdEditorMagnify.vue # 支持弹窗放大编辑的 Markdown 编辑器
│ │ ├── MdPreview.vue # 禁用代码折叠的 Markdown 预览器
│ │ ├── sup-popover.scss # Markdown 上标说明悬浮层样式
│ │ ├── md-editor.scss # Markdown 编辑器、预览区和上标说明浮层的共享样式
│ │ └── sup-popover.ts # Markdown 上标说明悬浮层交互
│ ├── mk-complex-search/
│ │ └── index.vue # 字段选择与输入或枚举条件组合搜索框
Expand Down Expand Up @@ -115,7 +115,8 @@ src/components/
│ └── LogoIcon.vue # 不带产品名称的图形 Logo,手动导入
├── codemirror-editor/
│ ├── python.vue # 内置 pylint 诊断和全屏编辑的 Python 编辑器
│ └── Json.vue # 支持格式化、语法诊断和全屏编辑的 JSON 输入框
│ ├── Json.vue # 支持格式化、语法诊断和全屏编辑的 JSON 输入框
│ └── style.scss # Python 与 JSON 编辑器共享的 scoped 样式
└── mk-source-card/
│ ├── index.vue # 来源资源的统一卡片结构,手动导入
│ ├── mk-source-card-action.vue # 卡片悬浮操作容器
Expand Down Expand Up @@ -198,6 +199,18 @@ Element Plus 使用 `ElOnlyChild` 处理浮层触发器。`el-tooltip`、`el-pop
配置为本地实例,避免运行时加载 CDN 资源;`md-editor-v3` v6 的图标已随依赖打包,不再维护或加载
旧版 `markdown-iconfont.js`。

编辑器、预览区和上标说明浮层的共享样式统一放在组件目录的 `md-editor.scss`,由 `config.ts`
引入。`MdEditor` 与 `MdPreview` 在底层组件根节点添加 `mk-markdown-editor`,编辑器内部样式
仅在该范围生效;`MdEditorMagnify` 通过复用 `MdEditor` 继承样式。上标浮层由 `sup-popover.ts`
挂载到 `body`,使用独立的 `markdown-sup-popover` 类名,不依赖编辑器祖先或 Vue scoped 属性。
组件专属样式不放入全局 `src/styles`;第三方基础 CSS 仍由全局 Sass 入口加载。

可编辑的 Markdown 输入框悬浮边框使用 `--el-input-hover-border-color`,编辑区获得焦点时
使用 `--el-input-focus-border-color`,未提供这两个变量时分别回退到 Element Plus 的悬浮边框色
和主题色。只读、禁用和独立预览不触发编辑边框状态。编辑器自带的滚动条统一使用
`el-scrollbar` 的颜色变量、6px 宽度和 0.3/0.5 透明度,内容溢出时由编辑器控制显示,悬浮
滑块时加深颜色;不再额外通过轨道透明度隐藏滚动条,保留原有滚动节点和拖动逻辑。

```vue
<MdEditor v-model="markdownContent">
<template #defFooters>自定义页脚</template>
Expand Down Expand Up @@ -700,6 +713,11 @@ import MkDragUpload from '@/components/mk-drag-upload/index.vue'

### PythonCodeEditor

Python 与 JSON 编辑器通过 `<style lang="scss" scoped src="./style.scss">` 共享组件目录内的
样式,使用 `mk-codemirror` 容器和 `:deep()` 限定 CodeMirror 内部节点的覆盖范围。普通编辑器
与全屏弹窗内容分别提供该容器,默认高度为 `210px`,调用方可通过透传的 `style` 覆盖;全屏
编辑器单独设置高度。不在全局 `app.scss` 中覆盖 `.cm-editor`。

基于 CodeMirror 6 的 Python 代码编辑器,通过 `v-model` 管理代码,并在组件内部调用工具 pylint
接口生成诊断。组件最多展示 50 条诊断,并在代码停止输入 500ms 后检查。编辑器提供内置全屏
入口;全屏确认时更新 `v-model` 并触发 `submit-dialog`,`header-extra` 插槽用于添加全屏标题栏操作。
Expand Down
12 changes: 9 additions & 3 deletions ui/src/components/codemirror-editor/Json.vue
Original file line number Diff line number Diff line change
Expand Up @@ -91,13 +91,13 @@ defineExpose({ format, validateRules })
</script>

<template>
<div class="relative w-full">
<div class="mk-codemirror relative w-full">
<Codemirror
:model-value="editorContent"
:extensions="extensions"
:tab-size="4"
autofocus
style="height: 210px; width: 100%"
:style="{ height: '210px' }"
v-bind="$attrs"
@update:model-value="handleContentChange"
/>
Expand All @@ -110,11 +110,17 @@ defineExpose({ format, validateRules })
</div>

<MkDialog v-model="dialogVisible" :title="props.title" append-to-body fullscreen>
<Codemirror v-model="dialogContent" :extensions="extensions" :tab-size="4" autofocus style="height: calc(100vh - 160px)" />
<div class="mk-codemirror">
<Codemirror v-model="dialogContent" :extensions="extensions" :tab-size="4" autofocus :style="{ height: 'calc(100dvh - 160px)' }" />
</div>

<template #footer>
<el-button @click="closeEditorDialog">取消</el-button>
<el-button type="primary" @click="submitEditorDialog">确定</el-button>
</template>
</MkDialog>
</template>

<style lang="scss" scoped>
@use './style.scss';
</style>
12 changes: 8 additions & 4 deletions ui/src/components/codemirror-editor/python.vue
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,8 @@ function submitEditorDialog() {
</script>

<template>
<div class="codemirror-editor w-full relative">
<Codemirror v-model="code" :extensions="extensions" :tab-size="4" autofocus v-bind="$attrs" />
<div class="mk-codemirror w-full relative">
<Codemirror v-model="code" :extensions="extensions" :tab-size="4" autofocus v-bind="$attrs" :style="{ height: '210px' }" />
<el-button class="absolute right-2 bottom-2" text type="info" @click="openEditorDialog">
<MkIcon name="icon_magnify_outlined" />
</el-button>
Expand All @@ -83,12 +83,16 @@ function submitEditorDialog() {
</div>
</template>

<Codemirror v-model="dialogCode" autofocus :extensions="extensions" style="height: calc(100vh - 160px) !important" :tab-size="4" />
<div class="mk-codemirror">
<Codemirror v-model="dialogCode" autofocus :extensions="extensions" :tab-size="4" :style="{ height: 'calc(100dvh - 160px)' }" />
</div>

<template #footer>
<el-button type="primary" @click="submitEditorDialog">确定</el-button>
</template>
</MkDialog>
</template>

<style lang="scss" scoped></style>
<style lang="scss" scoped>
@use './style.scss';
</style>
53 changes: 53 additions & 0 deletions ui/src/components/codemirror-editor/style.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/* CodeMirror 编辑器 */
.mk-codemirror {
:deep(.cm-editor) {
--el-scrollbar-bg-color: var(--el-text-color-secondary);
--el-scrollbar-hover-bg-color: var(--el-text-color-secondary);
--el-scrollbar-hover-opacity: 0.5;
--el-scrollbar-opacity: 0.3;
border: var(--el-border);
border-radius: var(--el-border-radius-base);
overflow: hidden;
scrollbar-color: transparent transparent;
scrollbar-width: thin;
}

:deep(.cm-editor .cm-gutters.cm-gutters-before) {
border: none;
}

:deep(.cm-editor.cm-focused) {
outline: none !important;
}

:deep(.cm-editor::-webkit-scrollbar) {
background-color: transparent;
height: 6px;
width: 6px;
}

:deep(.cm-editor::-webkit-scrollbar-corner) {
background-color: transparent;
}

:deep(.cm-editor::-webkit-scrollbar-thumb) {
background-color: transparent;
border-radius: var(--el-border-radius-base);
transition: background-color var(--el-transition-duration);
}

:deep(.cm-editor:hover) {
scrollbar-color: color-mix(in srgb, var(--el-scrollbar-bg-color) calc(var(--el-scrollbar-opacity) * 100%), transparent) transparent;
}

:deep(.cm-editor:hover::-webkit-scrollbar-thumb) {
background-color: var(--el-scrollbar-bg-color);
opacity: var(--el-scrollbar-opacity);
}

// 滑块悬浮状态覆盖编辑器悬浮状态。
:deep(.cm-editor::-webkit-scrollbar-thumb:hover) {
background-color: var(--el-scrollbar-hover-bg-color);
opacity: var(--el-scrollbar-hover-opacity);
}
}
2 changes: 1 addition & 1 deletion ui/src/components/global/markdown-editor/MdEditor.vue
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ const language = computed(() => {
</script>

<template>
<MdEditorV3 :language="language" no-prettier v-bind="$attrs">
<MdEditorV3 class="mk-markdown-editor" :language="language" no-prettier v-bind="$attrs">
<template #defFooters>
<slot name="defFooters" />
</template>
Expand Down
13 changes: 2 additions & 11 deletions ui/src/components/global/markdown-editor/MdEditorMagnify.vue
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ function submitEditorDialog() {
<template>
<MdEditor v-model="modelValue" :preview="false" :toolbars="[]" :footers="footers" class="magnify-md-editor" v-bind="$attrs">
<template #defFooters>
<el-button text @click="openEditorDialog">
<el-button text @click="openEditorDialog" class="mr-1 mb-1">
<MkIcon name="icon_magnify_outlined" />
</el-button>
</template>
Expand All @@ -42,18 +42,9 @@ function submitEditorDialog() {
<MdEditor v-model="dialogContent" :preview="false" :toolbars="[]" :footers="[]" class="magnify-dialog-editor" />

<template #footer>
<el-button @click="closeEditorDialog">取消</el-button>
<el-button type="primary" @click="submitEditorDialog">确定</el-button>
</template>
</MkDialog>
</template>

<style scoped>
.magnify-md-editor :deep(.md-editor-footer) {
border: 0;
}

.magnify-dialog-editor {
height: min(60vh, 600px);
}
</style>
<style scoped></style>
2 changes: 1 addition & 1 deletion ui/src/components/global/markdown-editor/MdPreview.vue
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const language = computed(() => {
</script>

<template>
<MdPreviewV3 :language="language" :code-foldable="false" v-bind="$attrs" />
<MdPreviewV3 class="mk-markdown-editor" :language="language" :code-foldable="false" v-bind="$attrs" />
</template>

<style scoped>
Expand Down
2 changes: 1 addition & 1 deletion ui/src/components/global/markdown-editor/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { supPopover } from './sup-popover'
import 'cropperjs/dist/cropper.css'
import 'highlight.js/styles/atom-one-dark.css'
import 'katex/dist/katex.min.css'
import './sup-popover.scss'
import './md-editor.scss'

let configured = false

Expand Down
168 changes: 168 additions & 0 deletions ui/src/components/global/markdown-editor/md-editor.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
/* Markdown 编辑器 */
.mk-markdown-editor.md-editor {
--md-color: var(--mk-N900);
--md-scrollbar-bg-color: transparent;
--md-scrollbar-thumb-active-color: var(--el-scrollbar-hover-bg-color, var(--el-text-color-secondary));
--md-scrollbar-thumb-color: var(--el-scrollbar-bg-color, var(--el-text-color-secondary));
--md-scrollbar-thumb-hover-color: var(--el-scrollbar-hover-bg-color, var(--el-text-color-secondary));
border-radius: var(--el-border-radius-base);
font-weight: 400;
line-height: 22px;
font-family: var(--mk-font-family) !important;

.cm-content {
color: var(--mk-N900);
font-weight: 400;
margin-block: 0 !important;
margin-inline: 11px !important;
padding: 5px 0 !important;
}
.cm-line {
padding: 0 !important;
}

.cm-placeholder {
color: var(--mk-N500);
font-size: var(--mk-font-size-base);
font-weight: 400;
}

.md-editor-footer {
height: auto !important;
border: none !important;
}
/* Markdown 输入框边框 */
&:not(.md-editor-previewOnly) {
border-color: var(--el-input-border-color, var(--el-border-color));
transition: border-color var(--el-transition-duration);

&:not(.md-editor-disabled):has(.cm-content[contenteditable='true']:not([aria-readonly='true'])) {
&:hover {
border-color: var(--el-input-hover-border-color, var(--el-border-color-hover));
}

// 编辑焦点优先于鼠标悬浮状态。
&:has(.cm-focused) {
border-color: var(--el-input-focus-border-color, var(--el-color-primary));
}
}
}
}

/* Markdown 自带滚动条沿用 el-scrollbar 的颜色、尺寸和悬浮透明度。 */
.mk-markdown-editor {
.md-editor-custom-scrollbar__thumb {
border-radius: inherit;
opacity: var(--el-scrollbar-opacity, 0.3);
transition: background-color var(--el-transition-duration);
width: 100%;

&:active,
&:hover {
opacity: var(--el-scrollbar-hover-opacity, 0.5);
}
}

.md-editor-custom-scrollbar__track {
border-radius: 4px;
inset-inline-end: 2px;
width: 6px;
z-index: 1;
}
}

/* Markdown 预览 */
.mk-markdown-editor {
.md-editor-preview {
font-size: inherit;
margin: 0;
padding: 0;
word-break: break-word;

.md-editor-admonition {
margin: 0;
padding: 0;
}

.md-editor-code .md-editor-code-head {
z-index: inherit !important;
}

img {
border: 0 !important;
max-width: calc(var(--spacing) * 90) !important;
}

p {
padding: 0 !important;
}

sup[data-title] {
align-items: center;
background-color: var(--el-color-primary-light-9);
border: 1px solid var(--el-color-primary-light-7);
border-radius: 4px;
color: var(--mk-primary);
cursor: pointer;
display: inline-flex;
font-size: 10px;
font-weight: 500;
letter-spacing: 0.02em;
line-height: 1;
padding: 2px var(--spacing);
transition:
background-color 0.15s,
color 0.15s;
vertical-align: super;
white-space: nowrap;
}

table {
display: block;
}

ul {
list-style: circle;
}

video {
max-width: calc(var(--spacing) * 90) !important;
width: 100%;
}
}

.md-editor-preview-wrapper {
padding: 0;
}
}

@media only screen and (max-width: 768px) {
.mk-markdown-editor .md-editor-preview img {
max-width: 100% !important;
}
}

/* 上标说明浮层由 sup-popover.ts 挂载到 body,使用独立类名限定范围。 */
.markdown-sup-popover {
background: var(--el-bg-color-overlay);
border-radius: 4px;
box-shadow: var(--el-box-shadow-light);
color: var(--mk-N900);
display: none;
font-size: 13px;
line-height: 1.5;
padding: 10px calc(var(--spacing) * 3);
position: absolute;
width: calc(var(--spacing) * 60);
word-break: break-word;
z-index: 20001;
}

.markdown-sup-popover__arrow {
background: var(--el-bg-color-overlay);
box-shadow: 1px 1px 4px rgb(0 0 0 / 8%);
height: calc(var(--spacing) * 2);
position: absolute;
transform: rotate(45deg);
width: calc(var(--spacing) * 2);
}
Loading
Loading