xfy 5b9e65bf72 fix(editor): 修复文章页折叠行被撑高 & 折叠图标垂直不居中
文章页 CodeRunner 嵌在 .md-content 内,CodeMirror 折叠后插入的
<img class="cm-widgetBuffer">(width:0、height:1em 的占位符,用于对齐折叠
widget 基线)被 .md-content img 的 margin:1rem 0 命中,上下各 16px margin
把折叠那行 .cm-line 撑到 47.5px(试运行页不在 .md-content 内,正常 19.6px)。
对比两页 .cm-line 的 children 锁定:文章页含 cm-widgetBuffer,试运行页没有。

input.css:.md-content img 选择器加 :where(:not(.cm-widgetBuffer)) 排除占位 img,
用 :where() 压低特异性避免影响其它规则。

themes.ts:core 对折叠列 .cm-foldGutter .cm-gutterElement 完全没设样式,格子
高度 ≈ font-size(14px) 比正文行(line-height ≈19.6px)矮,图标偏离中央。给格子
flex 居中 + line-height:1.4(复刻 CM 的字号×1.4 行高算法),图标落在正文行中央。
2026-07-08 14:03:14 +08:00

64 lines
3.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// @catppuccin/codemirror 提供现成的 Catppuccin 主题 Extension
// 与项目 themes/ 下的 Catppuccin Latte/Mocha .tmTheme 视觉一致。
import { catppuccinLatte, catppuccinMocha } from '@catppuccin/codemirror';
import type { Extension } from '@codemirror/state';
import { EditorView } from '@codemirror/view';
export type ThemeName = 'light' | 'dark';
/**
* 覆盖 CodeMirror core 内置 base theme 的两处问题:
*
* 1. `.cm-gutters` 默认背景core 的 `&light .cm-gutters``#f5f5f5`/ `&dark`
* `#333338`)特异性高于 catppuccin 的 `.cm-gutters`catppuccin 的 base 背景被
* 压制,行号列与代码区背景不一致。用 `!important` 强制透明,继承 editor base 色。
*
* 2. `.cm-editor` 默认不撑满父容器core 的 `&` 没设 height/flex编辑器只占内容
* 高度。`height: 100%` 在父容器只有 min-height 时会塌缩CSS百分比高度需要
* 父元素有明确 height。改用 `flex: 1`,配合父容器 `display: flex`,编辑器才能
* 真正填满,避免「有内容的上半部分」与「空白下半部分」背景割裂。
*/
const gutterBackgroundOverride: Extension = EditorView.theme({
'&': {
flex: '1 1 0',
minHeight: '0',
},
'.cm-gutters': {
backgroundColor: 'transparent !important',
},
});
/**
* 修复 CodeMirror 折叠图标fold gutter 的 ⌄ / ›)垂直不居中。
*
* core 的 baseTheme 对 `.cm-gutterElement` 只设了 `box-sizing`,对折叠列
* `.cm-foldGutter .cm-gutterElement` 完全没设样式。`.cm-gutter` 是
* `display:flex; flex-direction:column`,格子高度由内容决定——折叠列格子高度
* ≈ font-size14px比正文行line-height ≈19.6px)矮一截,图标被挤在矮格子
* 顶部/底部,视觉上偏离每行中央。
*
* 把折叠列每个格子变成 flex 容器并居中,图标稳稳落在格子中央;同时格子必须和正文
* 行等高,图标才会落在正文行的视觉中央。正文 .cm-line 的 line-height 由 CodeMirror
* 按「字号 × 1.4」算出(实测 14px → 19.6px),这里用同样倍数复刻,避免硬编码像素
* 值随字号漂移。
*
* 注意:折叠后正文行被撑高的根因(文章页 47.5px vs 试运行页 19.6px)不在
* placeholder——而在 `<img class="cm-widgetBuffer">` 被 `.md-content img` 的
* `margin: 1rem 0` 命中(上下各 16px = 32px。修复见 input.css 的
* `.md-content img:where(:not(.cm-widgetBuffer))`。
*/
const foldGutterCenterOverride: Extension = EditorView.theme({
'.cm-foldGutter .cm-gutterElement': {
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
lineHeight: '1.4',
},
});
/** 根据主题名返回对应的 CodeMirror 主题 Extension。 */
export function themeExtension(name: ThemeName): Extension {
const catppuccin = name === 'light' ? catppuccinLatte : catppuccinMocha;
return [catppuccin, gutterBackgroundOverride, foldGutterCenterOverride];
}