Compare commits

...

4 Commits

Author SHA1 Message Date
e729ac1af2
fix: 过滤 dev overlay 中误报的 ResizeObserver loop 错误
ResizeObserver loop completed with undelivered notifications 是浏览器
规范允许的良性通知,Element Plus 下拉框展开时会触发,不影响实际功能。
webpack-dev-server 错误地将其当成运行时错误弹出 overlay,通过
client.overlay.runtimeErrors 回调将其过滤掉。

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-11 01:32:55 +08:00
d4ec727437
feat: 美化文章 Markdown 预览样式,支持亮/暗双色模式
- Drawer 宽度调整为 50%,标题栏加背景/底部边框
- 为预览内容 div 添加 markdown-body 类
- 新增完整 markdown-body 样式:
  - h1-h6 标题层级(h1/h2 带下划线)
  - 段落、强调、链接(带 hover 过渡)
  - 内联代码:使用 Element Plus 填充色 + danger 颜色
  - 代码块:亮色模式 #f6f8fa 浅灰背景,暗色模式 #161b22 深背景
  - 引用块:主题色左边框 + 浅色背景
  - 有序/无序列表(支持嵌套)
  - 表格:条纹行 + hover 高亮
  - 图片:居中、圆角、阴影
  - 水平线
- 暗色模式通过 html.dark 选择器单独覆盖代码块和图片阴影

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-11 01:27:39 +08:00
18224299aa
fix: 修复 dev 模式下 extract-css 插件不存在导致的报错
dev 模式不加载 mini-css-extract-plugin,需先判断插件是否存在再调用 tap()

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-11 01:19:40 +08:00
d5d82d3488
fix: 修复 npm 依赖安全漏洞并消除 CSS 顺序警告
- 执行 npm audit fix 自动修复 41 个漏洞中的大部分(babel、webpack、axios 等)
- 在 package.json 中添加 overrides 强制升级无法自动修复的间接依赖:
  - postcss >= 8.4.31(修复 CVE in @vue/component-compiler-utils)
  - serialize-javascript >= 7.0.5(修复 XSS/RCE in copy-webpack-plugin)
  - webpack-dev-server >= 5.2.1(修复源码泄露漏洞)
- 漏洞数从 41 降至 0
- vue.config.js 中为 mini-css-extract-plugin 添加 ignoreOrder: true,
  消除 Element Plus 按需导入时不同路由 chunk CSS 顺序冲突的警告

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-11 01:10:58 +08:00
6 changed files with 5173 additions and 3629 deletions

4865
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -30,6 +30,11 @@
"unplugin-auto-import": "^0.12.1",
"unplugin-vue-components": "^0.22.12"
},
"overrides": {
"postcss": ">=8.4.31",
"serialize-javascript": ">=7.0.5",
"webpack-dev-server": ">=5.2.1"
},
"browserslist": [
"> 1%",
"last 2 versions",

View File

@ -215,6 +215,191 @@ body .el-dialog {
overflow: auto;
}
}
/* ===== Markdown 预览 ===== */
.article-preview-drawer {
> .el-drawer__header {
border-bottom: 1px solid var(--el-border-color-lighter);
padding: 14px 20px;
margin-bottom: 0;
background: var(--el-fill-color-light);
.el-drawer__title {
font-size: var(--el-font-size-base);
font-weight: var(--el-font-weight-primary);
color: var(--el-text-color-primary);
}
}
> .el-drawer__body {
padding: 24px 32px;
}
}
.markdown-body {
font-size: 15px;
line-height: 1.8;
color: var(--el-text-color-primary);
word-break: break-word;
// 首个元素去掉顶部外边距
> :first-child { margin-top: 0 !important; }
// ── 标题 ───────────────────────────────────
h1, h2, h3, h4, h5, h6 {
font-weight: 600;
line-height: 1.35;
margin: 1.4em 0 0.6em;
color: var(--el-text-color-primary);
}
h1 {
font-size: 1.8em;
padding-bottom: 0.4em;
border-bottom: 2px solid var(--el-border-color);
}
h2 {
font-size: 1.45em;
padding-bottom: 0.3em;
border-bottom: 1px solid var(--el-border-color-lighter);
}
h3 { font-size: 1.2em; }
h4 { font-size: 1.05em; }
h5 { font-size: 0.95em; }
h6 {
font-size: 0.9em;
color: var(--el-text-color-secondary);
}
// ── 段落 ───────────────────────────────────
p { margin: 0.85em 0; }
// ── 链接 ───────────────────────────────────
a {
color: var(--el-color-primary);
text-decoration: none;
border-bottom: 1px solid transparent;
transition: border-color 0.2s, color 0.2s;
&:hover {
color: var(--el-color-primary-light-3);
border-bottom-color: var(--el-color-primary-light-3);
}
}
// ── 强调 ───────────────────────────────────
strong { font-weight: 600; }
em { font-style: italic; }
del { color: var(--el-text-color-secondary); text-decoration: line-through; }
// ── 内联代码 ───────────────────────────────
:not(pre) > code {
font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
font-size: 0.85em;
padding: 0.18em 0.45em;
border-radius: 4px;
background: var(--el-fill-color-dark);
color: var(--el-color-danger);
border: 1px solid var(--el-border-color-lighter);
}
// ── 代码块(亮色:浅灰背景;暗色:深背景) ───
pre {
background: #f6f8fa;
border: 1px solid var(--el-border-color-lighter);
border-radius: 8px;
padding: 1em 1.2em;
overflow-x: auto;
margin: 1em 0;
code {
font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;
font-size: 0.875em;
background: none;
border: none;
padding: 0;
color: #24292f;
line-height: 1.65;
}
}
// ── 引用块 ─────────────────────────────────
blockquote {
margin: 1em 0;
padding: 0.6em 1.1em;
border-left: 4px solid var(--el-color-primary-light-5);
background: var(--el-color-primary-light-9);
border-radius: 0 6px 6px 0;
color: var(--el-text-color-secondary);
> :first-child { margin-top: 0; }
> :last-child { margin-bottom: 0; }
}
// ── 列表 ───────────────────────────────────
ul, ol {
margin: 0.7em 0;
padding-left: 1.8em;
}
li {
margin: 0.3em 0;
line-height: 1.75;
> ul, > ol { margin: 0.2em 0; }
}
ul > li { list-style-type: disc; }
ul > li > ul > li { list-style-type: circle; }
ol > li { list-style-type: decimal; }
// ── 水平线 ─────────────────────────────────
hr {
border: none;
border-top: 1px solid var(--el-border-color);
margin: 1.6em 0;
}
// ── 图片 ───────────────────────────────────
img {
max-width: 100%;
height: auto;
border-radius: 6px;
display: block;
margin: 1em auto;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
// ── 表格 ───────────────────────────────────
table {
border-collapse: collapse;
width: 100%;
margin: 1em 0;
font-size: 0.9em;
border: 1px solid var(--el-border-color);
border-radius: 6px;
overflow: hidden;
th, td {
padding: 0.6em 1em;
border: 1px solid var(--el-border-color-lighter);
text-align: left;
vertical-align: top;
}
th {
background: var(--el-fill-color-light);
font-weight: 600;
color: var(--el-text-color-regular);
}
tr:nth-child(even) td { background: var(--el-fill-color-lighter); }
tr:hover td { background: var(--el-color-primary-light-9); }
}
}
// 暗色模式:代码块使用深色背景
html.dark .markdown-body {
pre {
background: #161b22;
border-color: rgba(255, 255, 255, 0.08);
code { color: #e6edf3; }
}
img { box-shadow: 0 2px 12px rgba(0, 0, 0, 0.4); }
}
/* ========================================== */
.el-tabs--card.nav-tabs {
> .el-tabs__header {
margin-bottom: 0;

View File

@ -99,8 +99,9 @@
v-model="markdownPreview.show"
:title="markdownPreview.title"
direction="rtl"
class="custom-drawer">
<div v-html="markdownPreview.content"></div>
size="50%"
class="custom-drawer article-preview-drawer">
<div class="markdown-body" v-html="markdownPreview.content"></div>
</el-drawer>
</div>
</template>

View File

@ -32,9 +32,25 @@ module.exports = defineConfig({
// fork-ts-checker-webpack-plugin v6 与 TypeScript 5 不兼容(无法覆写只读的 performance.mark
// 类型检查改由 tsc --noEmit 承担
config.plugins.delete('fork-ts-checker')
// Element Plus 按需导入时,不同路由 chunk 的 CSS 导入顺序不一致,
// 但这不影响最终样式specificity 规则优先),忽略该警告
// extract-css 仅在生产构建时存在dev 模式下跳过
if (config.plugins.has('extract-css')) {
config.plugin('extract-css').tap(args => {
args[0].ignoreOrder = true
return args
})
}
},
devServer: {
port: 8080,
client: {
overlay: {
// ResizeObserver loop 是浏览器规范允许的良性通知,不是真实错误,过滤掉避免干扰开发
runtimeErrors: (err) => err?.message !== 'ResizeObserver loop completed with undelivered notifications.'
}
},
proxy: {
'^/api': {
target: process.env.VUE_APP_PROXY_TARGET,

3726
yarn.lock

File diff suppressed because it is too large Load Diff