Files
voidraft/frontend/src/views/editor/theme/base.ts
2025-11-21 00:03:03 +08:00

236 lines
9.8 KiB
TypeScript

import {EditorView} from '@codemirror/view';
import {HighlightStyle, syntaxHighlighting} from '@codemirror/language';
import {tags} from '@lezer/highlight';
import {Extension} from '@codemirror/state';
import type {ThemeColors} from './types';
const MONO_FONT_FALLBACK = 'var(--voidraft-font-mono, SFMono-Regular, Consolas, "Liberation Mono", Menlo, monospace)';
/**
* 创建通用主题
* @param colors 主题颜色配置
* @returns CodeMirror Extension数组
*/
export function createBaseTheme(colors: ThemeColors): Extension {
// 编辑器主题样式
const theme = EditorView.theme({
'&': {
backgroundColor: colors.background,
},
'.cm-editor': {
backgroundColor: colors.background,
},
// 光标
'.cm-cursor, .cm-dropCursor': {
borderLeftColor: colors.cursor,
borderLeftWidth: '2px',
paddingTop: '4px',
marginTop: '-2px',
},
// 选择背景
'&.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground': {
backgroundColor: colors.selection,
},
// 当前行高亮
'.cm-activeLine': {
backgroundColor: colors.activeLine
},
// 行号区域
'.cm-gutters': {
backgroundColor: colors.dark ? 'rgba(0,0,0, 0.1)' : 'rgba(0,0,0, 0.04)',
color: colors.lineNumber,
border: 'none',
padding: '0 2px 0 4px',
userSelect: 'none',
},
'.cm-activeLineGutter': {
backgroundColor: 'transparent',
color: colors.activeLineNumber,
},
// 括号匹配
'&.cm-focused .cm-matchingBracket, &.cm-focused .cm-nonmatchingBracket': {
outline: `0.5px solid ${colors.matchingBracket}`,
},
// 代码块层(自定义)
'.code-blocks-layer': {
width: '100%',
},
'.code-blocks-layer .block-even, .code-blocks-layer .block-odd': {
width: '100%',
boxSizing: 'content-box',
},
'.code-blocks-layer .block-even': {
background: colors.background,
borderTop: `1px solid ${colors.borderColor}`,
},
'.code-blocks-layer .block-even:first-child': {
borderTop: 'none',
},
'.code-blocks-layer .block-odd': {
background: colors.backgroundSecondary,
borderTop: `1px solid ${colors.borderColor}`,
},
'.code-block-empty-selected': {
backgroundColor: colors.selection,
},
// 代码块开始标记
'.code-block-start': {
height: '12px',
position: 'relative',
},
'.code-block-start.first': {
height: '0px',
},
// 数学计算结果
'.code-blocks-math-result': {
paddingLeft: "12px",
position: "relative",
},
".code-blocks-math-result .inner": {
background: colors.dark ? '#0e1217' : '#48b57e',
color: colors.dark ? '#a0e7c7' : '#fff',
padding: '0px 4px',
borderRadius: '2px',
boxShadow: colors.dark ? '0 0 3px rgba(0,0,0, 0.3)' : '0 0 3px rgba(0,0,0, 0.1)',
cursor: 'pointer',
whiteSpace: "nowrap",
},
'.code-blocks-math-result-copied': {
position: "absolute",
top: "0px",
left: "0px",
marginLeft: "calc(100% + 10px)",
width: "60px",
transition: "opacity 500ms",
transitionDelay: "1000ms",
color: colors.dark ? 'rgba(220,240,230, 1.0)' : 'rgba(0,0,0, 0.8)',
},
'.code-blocks-math-result-copied.fade-out': {
opacity: 0,
},
}, {dark: colors.dark});
const highlightStyle = HighlightStyle.define([
{tag: tags.comment, color: colors.comment, fontStyle: 'italic'},
{tag: tags.lineComment, color: colors.lineComment, fontStyle: 'italic'},
{tag: tags.blockComment, color: colors.blockComment, fontStyle: 'italic'},
{tag: tags.docComment, color: colors.docComment, fontStyle: 'italic'},
{tag: tags.name, color: colors.name},
{tag: tags.variableName, color: colors.variableName},
{tag: tags.typeName, color: colors.typeName},
{tag: tags.tagName, color: colors.tagName},
{tag: tags.propertyName, color: colors.propertyName},
{tag: tags.attributeName, color: colors.attributeName},
{tag: tags.className, color: colors.className},
{tag: tags.labelName, color: colors.labelName},
{tag: tags.namespace, color: colors.namespace},
{tag: tags.macroName, color: colors.macroName},
{tag: tags.literal, color: colors.literal},
{tag: tags.string, color: colors.string},
{tag: tags.docString, color: colors.docString},
{tag: tags.character, color: colors.character},
{tag: tags.attributeValue, color: colors.attributeValue},
{tag: tags.number, color: colors.number},
{tag: tags.integer, color: colors.integer},
{tag: tags.float, color: colors.float},
{tag: tags.bool, color: colors.bool},
{tag: tags.regexp, color: colors.regexp},
{tag: tags.escape, color: colors.escape},
{tag: tags.color, color: colors.color},
{tag: tags.url, color: colors.url},
{tag: tags.keyword, color: colors.keyword},
{tag: tags.self, color: colors.self},
{tag: tags.null, color: colors.null},
{tag: tags.atom, color: colors.atom},
{tag: tags.unit, color: colors.unit},
{tag: tags.modifier, color: colors.modifier},
{tag: tags.operatorKeyword, color: colors.operatorKeyword},
{tag: tags.controlKeyword, color: colors.controlKeyword},
{tag: tags.definitionKeyword, color: colors.definitionKeyword},
{tag: tags.moduleKeyword, color: colors.moduleKeyword},
{tag: tags.operator, color: colors.operator},
{tag: tags.derefOperator, color: colors.derefOperator},
{tag: tags.arithmeticOperator, color: colors.arithmeticOperator},
{tag: tags.logicOperator, color: colors.logicOperator},
{tag: tags.bitwiseOperator, color: colors.bitwiseOperator},
{tag: tags.compareOperator, color: colors.compareOperator},
{tag: tags.updateOperator, color: colors.updateOperator},
{tag: tags.definitionOperator, color: colors.definitionOperator},
{tag: tags.typeOperator, color: colors.typeOperator},
{tag: tags.controlOperator, color: colors.controlOperator},
{tag: tags.punctuation, color: colors.punctuation},
{tag: tags.separator, color: colors.separator},
{tag: tags.bracket, color: colors.bracket},
{tag: tags.angleBracket, color: colors.angleBracket},
{tag: tags.squareBracket, color: colors.squareBracket},
{tag: tags.paren, color: colors.paren},
{tag: tags.brace, color: colors.brace},
{tag: tags.content, color: colors.content},
{tag: tags.heading, color: colors.heading, fontWeight: 'bold'},
{tag: tags.heading1, color: colors.heading1, fontWeight: 'bold', fontSize: '1.4em'},
{tag: tags.heading2, color: colors.heading2, fontWeight: 'bold', fontSize: '1.3em'},
{tag: tags.heading3, color: colors.heading3, fontWeight: 'bold', fontSize: '1.2em'},
{tag: tags.heading4, color: colors.heading4, fontWeight: 'bold', fontSize: '1.1em'},
{tag: tags.heading5, color: colors.heading5, fontWeight: 'bold'},
{tag: tags.heading6, color: colors.heading6, fontWeight: 'bold'},
{tag: tags.contentSeparator, color: colors.contentSeparator},
{tag: tags.list, color: colors.list},
{tag: tags.quote, color: colors.quote, fontStyle: 'italic'},
{tag: tags.emphasis, color: colors.emphasis, fontStyle: 'italic'},
{tag: tags.strong, color: colors.strong, fontWeight: 'bold'},
{tag: tags.link, color: colors.link, textDecoration: 'underline'},
{tag: tags.monospace, color: colors.monospace, fontFamily: MONO_FONT_FALLBACK},
{tag: tags.strikethrough, color: colors.strikethrough, textDecoration: 'line-through'},
{tag: tags.inserted, color: colors.inserted},
{tag: tags.deleted, color: colors.deleted},
{tag: tags.changed, color: colors.changed},
{tag: tags.meta, color: colors.meta, fontStyle: 'italic'},
{tag: tags.documentMeta, color: colors.documentMeta},
{tag: tags.annotation, color: colors.annotation},
{tag: tags.processingInstruction, color: colors.processingInstruction},
{tag: tags.definition(tags.variableName), color: colors.definition},
{tag: tags.definition(tags.propertyName), color: colors.definition},
{tag: tags.definition(tags.name), color: colors.definition},
{tag: tags.constant(tags.variableName), color: colors.constant},
{tag: tags.constant(tags.propertyName), color: colors.constant},
{tag: tags.constant(tags.name), color: colors.constant},
{tag: tags.function(tags.variableName), color: colors.function},
{tag: tags.function(tags.propertyName), color: colors.function},
{tag: tags.function(tags.name), color: colors.function},
{tag: tags.standard(tags.variableName), color: colors.standard},
{tag: tags.standard(tags.name), color: colors.standard},
{tag: tags.local(tags.variableName), color: colors.local},
{tag: tags.local(tags.name), color: colors.local},
{tag: tags.special(tags.variableName), color: colors.special},
{tag: tags.special(tags.name), color: colors.special},
{tag: tags.special(tags.string), color: colors.special},
{tag: tags.invalid, color: colors.invalid},
]);
return [
theme,
syntaxHighlighting(highlightStyle),
];
}