♻️ Refactor code

This commit is contained in:
2025-06-19 01:05:08 +08:00
parent 9204315c7b
commit 3c880199ae
41 changed files with 932 additions and 2889 deletions

View File

@@ -72,9 +72,7 @@ export function createAutoSavePlugin(options: AutoSaveOptions = {}) {
// 静默发送最终内容,忽略错误
const content = this.view.state.doc.toString();
DocumentService.UpdateActiveDocumentContent(content).catch(() => {
// 静默忽略销毁时的错误
});
DocumentService.UpdateActiveDocumentContent(content).then();
}
}
);

View File

@@ -143,16 +143,14 @@ const blockLayer = layer({
return;
}
// 对最后一个块进行特殊处理
// 对最后一个块进行特殊处理,让它直接延伸到底部
if (idx === blocks.length - 1) {
// 计算需要为最后一个块添加多少额外高度,但要更保守
const editorHeight = view.dom.clientHeight;
const contentBottom = toCoordsBottom - view.documentTop + view.documentPadding.top;
// 只有当内容不足以填满视口时,才添加额外高度
// 让最后一个块直接延伸到编辑器底部
if (contentBottom < editorHeight) {
let extraHeight = editorHeight - contentBottom - view.defaultLineHeight - 16; // 保留合理的底部边距
extraHeight = Math.max(0, extraHeight); // 确保不为负数
const extraHeight = editorHeight - contentBottom-10;
toCoordsBottom += extraHeight;
}
}

View File

@@ -28,7 +28,6 @@ import {getCodeBlockLanguageExtension} from './lang-parser';
import {createLanguageDetection} from './language-detection';
import {EditorOptions, SupportedLanguage} from './types';
import {lineNumbers} from '@codemirror/view';
import './styles.css'
/**
* 代码块扩展配置选项
@@ -47,14 +46,6 @@ export interface CodeBlockOptions {
defaultAutoDetect?: boolean;
}
/**
* 默认编辑器选项
*/
const defaultEditorOptions: EditorOptions = {
defaultBlockToken: 'text',
defaultBlockAutoDetect: false,
};
/**
* 获取块内行号信息
*/

View File

@@ -48,14 +48,12 @@ export function getBlocksFromSyntaxTree(state: EditorState): Block[] | null {
// 解析整个分隔符文本来获取语言和自动检测标记
const delimiterText = doc.sliceString(child.from, child.to);
console.log('🔍 [解析器] 分隔符文本:', delimiterText);
// 使用正则表达式解析分隔符
const match = delimiterText.match(/∞∞∞([a-zA-Z0-9_-]+)(-a)?\n/);
if (match) {
language = match[1] || 'text';
auto = match[2] === '-a';
console.log(`🔍 [解析器] 解析结果: 语言=${language}, 自动=${auto}`);
} else {
// 回退到逐个解析子节点
child.node.firstChild?.cursor().iterate(langChild => {

View File

@@ -1,224 +0,0 @@
/* 块层样式 */
.code-blocks-layer {
width: 100%;
z-index: -1;
}
.code-blocks-layer .block-even,
.code-blocks-layer .block-odd {
width: 100%;
box-sizing: content-box;
left: 0;
margin-left: 0;
}
.code-blocks-layer .block-even:first-child {
border-top: none;
}
/* 块开始装饰 */
.code-block-start {
height: 12px;
position: relative;
z-index: 0;
}
.code-block-start.first {
height: 0px;
}
/* 默认块样式*/
.code-blocks-layer .block-even {
background: #252B37 !important;
border-top: 1px solid #1e222a;
}
.code-blocks-layer .block-odd {
background: #213644 !important;
border-top: 1px solid #1e222a;
}
/* 浅色主题块样式 */
:root[data-theme="light"] .code-blocks-layer .block-even {
background: #ffffff !important;
border-top: 1px solid #dfdfdf;
}
:root[data-theme="light"] .code-blocks-layer .block-odd {
background: #f4f8f4 !important;
border-top: 1px solid #dfdfdf;
}
/* 确保深色主题样式 */
:root[data-theme="dark"] .code-blocks-layer .block-even {
background: #252B37 !important;
border-top: 1px solid #1e222a;
}
:root[data-theme="dark"] .code-blocks-layer .block-odd {
background: #213644 !important;
border-top: 1px solid #1e222a;
}
/* 空块选择样式 */
.code-block-empty-selected {
background-color: #0865a9aa !important;
border-radius: 3px;
}
:root[data-theme="light"] .code-block-empty-selected {
background-color: #77baff8c !important;
}
/* 选择样式 */
.cm-activeLine.code-empty-block-selected {
background-color: #0865a9aa;
}
:root[data-theme="light"] .cm-activeLine.code-empty-block-selected {
background-color: #77baff8c;
}
/* 光标样式 */
.cm-cursor, .cm-dropCursor {
border-left-width: 2px;
padding-top: 4px;
margin-top: -2px;
}
/* 内容区域样式 */
.cm-content {
padding-top: 4px;
}
/* 装订线样式 */
.cm-gutters {
padding: 0 2px 0 4px;
user-select: none;
background-color: transparent;
color: rgba(255, 255, 255, 0.15);
border: none;
}
.cm-activeLineGutter {
background-color: transparent;
color: rgba(255, 255, 255, 0.6);
}
/* 浅色主题装订线 */
:root[data-theme="light"] .cm-gutters {
background-color: transparent;
color: rgba(0, 0, 0, 0.25);
border: none;
border-right: 1px solid rgba(0, 0, 0, 0.05);
}
:root[data-theme="light"] .cm-activeLineGutter {
background-color: transparent;
color: rgba(0, 0, 0, 0.6);
}
/* 活动行样式 */
.cm-activeLine {
background-color: rgba(255, 255, 255, 0.04);
}
:root[data-theme="light"] .cm-activeLine {
background-color: rgba(0, 0, 0, 0.04);
}
/* 选择背景 */
.cm-selectionBackground {
background-color: #225377aa;
}
.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground {
background-color: #0865a9aa;
}
:root[data-theme="light"] .cm-selectionBackground {
background: #b2c2ca85;
}
:root[data-theme="light"] .cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground {
background: #77baff8c;
}
/* 编辑器焦点样式 */
.cm-editor.cm-focused {
outline: none;
}
/* 折叠装订线样式 */
.cm-foldGutter {
margin-left: 0px;
}
.cm-foldGutter .cm-gutterElement {
opacity: 0;
transition: opacity 400ms;
}
.cm-gutters:hover .cm-gutterElement {
opacity: 1;
}
/* 匹配括号样式 */
.cm-focused .cm-matchingBracket,
.cm-focused .cm-nonmatchingBracket {
outline: 0.5px solid #8fbcbb;
}
.cm-focused .cm-matchingBracket {
background-color: rgba(255, 255, 255, 0.1);
color: inherit;
}
.cm-focused .cm-nonmatchingBracket {
outline: 0.5px solid #bc8f8f;
}
/* 搜索匹配样式 */
.cm-searchMatch {
background-color: transparent;
outline: 1px solid #8fbcbb;
}
.cm-searchMatch.cm-searchMatch-selected {
background-color: #d8dee9;
color: #2e3440;
}
/* 选择匹配样式 */
.cm-selectionMatch {
background-color: #50606D;
}
/* 折叠占位符样式 */
.cm-foldPlaceholder {
background-color: transparent;
border: none;
color: #ddd;
}
/* 工具提示样式 */
.cm-tooltip {
border: none;
background-color: #3b4252;
}
.cm-tooltip .cm-tooltip-arrow:before {
border-top-color: transparent;
border-bottom-color: transparent;
}
.cm-tooltip .cm-tooltip-arrow:after {
border-top-color: #3b4252;
border-bottom-color: #3b4252;
}
/* 自动完成工具提示 */
.cm-tooltip-autocomplete > ul > li[aria-selected] {
background-color: rgba(255, 255, 255, 0.04);
color: #4c566a;
}

View File

@@ -4,5 +4,6 @@ export * from './wheelZoomExtension';
export * from './statsExtension';
export * from './autoSaveExtension';
export * from './fontExtension';
export * from './themeExtension';
export * from './codeblast';
export * from './codeblock';

View File

@@ -1,7 +1,6 @@
import {Extension} from '@codemirror/state';
import {EditorView} from '@codemirror/view';
import {DocumentStats} from '@/types/editor';
import {DocumentStats} from '@/stores/editorStore';
// 更新编辑器文档统计信息
export const updateStats = (
view: EditorView,

View File

@@ -0,0 +1,53 @@
import { Extension, Compartment } from '@codemirror/state';
import { EditorView } from '@codemirror/view';
import { SystemThemeType } from '@/../bindings/voidraft/internal/models/models';
import { dark } from '@/views/editor/theme/dark';
import { light } from '@/views/editor/theme/light';
// 主题区间 - 用于动态切换主题
export const themeCompartment = new Compartment();
/**
* 根据主题类型获取主题扩展
*/
const getThemeExtension = (themeType: SystemThemeType): Extension => {
// 处理 auto 主题类型
let actualTheme: SystemThemeType = themeType;
if (themeType === SystemThemeType.SystemThemeAuto) {
actualTheme = window.matchMedia('(prefers-color-scheme: dark)').matches
? SystemThemeType.SystemThemeDark
: SystemThemeType.SystemThemeLight;
}
// 直接返回对应的主题扩展
switch (actualTheme) {
case SystemThemeType.SystemThemeLight:
return light;
case SystemThemeType.SystemThemeDark:
default:
return dark;
}
};
/**
* 创建主题扩展(用于编辑器初始化)
*/
export const createThemeExtension = (themeType: SystemThemeType = SystemThemeType.SystemThemeDark): Extension => {
const extension = getThemeExtension(themeType);
return themeCompartment.of(extension);
};
/**
* 更新编辑器主题
*/
export const updateEditorTheme = (view: EditorView, themeType: SystemThemeType): void => {
if (!view?.dispatch) {
return;
}
const extension = getThemeExtension(themeType);
view.dispatch({
effects: themeCompartment.reconfigure(extension)
});
};

View File

@@ -1,128 +0,0 @@
import {EditorView} from '@codemirror/view'
import {Extension} from '@codemirror/state'
import {HighlightStyle, syntaxHighlighting} from '@codemirror/language'
import {tags as t} from '@lezer/highlight'
export const config = {
name: 'aura',
dark: true,
background: '#21202e',
foreground: '#edecee',
selection: '#A198EC7F',
cursor: '#a277ff',
dropdownBackground: '#21202e',
dropdownBorder: '#3b334b',
activeLine: '#4d4b6622',
lineNumber: '#a394f033',
lineNumberActive: '#cdccce',
matchingBracket: '#a394f033',
keyword: '#a277ff',
storage: '#a277ff',
variable: '#edecee',
parameter: '#edecee',
function: '#ffca85',
string: '#61ffca',
constant: '#61ffca',
type: '#82e2ff',
class: '#82e2ff',
number: '#61ffca',
comment: '#6d6d6d',
heading: '#a277ff',
invalid: '#ff6767',
regexp: '#61ffca',
}
export const auraTheme = EditorView.theme({
'&': {
color: config.foreground,
backgroundColor: config.background,
},
'.cm-content': {caretColor: config.cursor},
'.cm-cursor, .cm-dropCursor': {borderLeftColor: config.cursor},
'&.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground, .cm-selectionBackground, .cm-content ::selection': {backgroundColor: config.selection},
'.cm-panels': {backgroundColor: config.dropdownBackground, color: config.foreground},
'.cm-panels.cm-panels-top': {borderBottom: '2px solid black'},
'.cm-panels.cm-panels-bottom': {borderTop: '2px solid black'},
'.cm-searchMatch': {
backgroundColor: config.dropdownBackground,
outline: `1px solid ${config.dropdownBorder}`
},
'.cm-searchMatch.cm-searchMatch-selected': {
backgroundColor: config.selection
},
'.cm-activeLine': {backgroundColor: config.activeLine},
'.cm-selectionMatch': {backgroundColor: config.selection},
'&.cm-focused .cm-matchingBracket, &.cm-focused .cm-nonmatchingBracket': {
backgroundColor: config.matchingBracket,
outline: 'none'
},
'.cm-gutters': {
backgroundColor: config.background,
color: config.foreground,
border: 'none'
},
'.cm-activeLineGutter': {backgroundColor: config.background},
'.cm-lineNumbers .cm-gutterElement': {color: config.lineNumber},
'.cm-lineNumbers .cm-activeLineGutter': {color: config.lineNumberActive},
'.cm-foldPlaceholder': {
backgroundColor: 'transparent',
border: 'none',
color: config.foreground
},
'.cm-tooltip': {
border: `1px solid ${config.dropdownBorder}`,
backgroundColor: config.dropdownBackground,
color: config.foreground,
},
'.cm-tooltip .cm-tooltip-arrow:before': {
borderTopColor: 'transparent',
borderBottomColor: 'transparent'
},
'.cm-tooltip .cm-tooltip-arrow:after': {
borderTopColor: config.foreground,
borderBottomColor: config.foreground,
},
'.cm-tooltip-autocomplete': {
'& > ul > li[aria-selected]': {
background: config.selection,
color: config.foreground,
}
}
}, {dark: config.dark})
export const auraHighlightStyle = HighlightStyle.define([
{tag: t.keyword, color: config.keyword},
{tag: [t.name, t.deleted, t.character, t.macroName], color: config.variable},
{tag: [t.propertyName], color: config.function},
{tag: [t.processingInstruction, t.string, t.inserted, t.special(t.string)], color: config.string},
{tag: [t.function(t.variableName), t.labelName], color: config.function},
{tag: [t.color, t.constant(t.name), t.standard(t.name)], color: config.constant},
{tag: [t.definition(t.name), t.separator], color: config.variable},
{tag: [t.className], color: config.class},
{tag: [t.number, t.changed, t.annotation, t.modifier, t.self, t.namespace], color: config.number},
{tag: [t.typeName], color: config.type, fontStyle: config.type},
{tag: [t.operator, t.operatorKeyword], color: config.keyword},
{tag: [t.url, t.escape, t.regexp, t.link], color: config.regexp},
{tag: [t.meta, t.comment], color: config.comment},
{tag: t.strong, fontWeight: 'bold'},
{tag: t.emphasis, fontStyle: 'italic'},
{tag: t.link, textDecoration: 'underline'},
{tag: t.heading, fontWeight: 'bold', color: config.heading},
{tag: [t.atom, t.bool, t.special(t.variableName)], color: config.variable},
{tag: t.invalid, color: config.invalid},
{tag: t.strikethrough, textDecoration: 'line-through'},
])
export const aura: Extension = [
auraTheme,
syntaxHighlighting(auraHighlightStyle),
]

View File

@@ -0,0 +1,237 @@
import {EditorView} from '@codemirror/view';
import {HighlightStyle, syntaxHighlighting} from '@codemirror/language';
import {tags} from '@lezer/highlight';
const colors = {
// 基础色调
background: '#252B37', // 主背景色
// backgroundAlt: '#252B37', // 交替背景色
backgroundSecondary: '#213644', // 次要背景色
surface: '#474747', // 面板背景
// 文本颜色
foreground: '#9BB586', // 主文本色
foregroundSecondary: '#9c9c9c', // 次要文本色
comment: '#6272a4', // 注释色
// 语法高亮色
keyword: '#ff79c6', // 关键字
string: '#f1fa8c', // 字符串
function: '#50fa7b', // 函数名
number: '#bd93f9', // 数字
operator: '#ff79c6', // 操作符
variable: '#8fbcbb', // 变量
type: '#8be9fd', // 类型
// 界面元素
cursor: '#fff', // 光标
selection: '#0865a9aa', // 选中背景
selectionBlur: '#225377aa', // 失焦选中背景
activeLine: 'rgba(255,255,255,0.04)', // 当前行高亮
lineNumber: 'rgba(255,255,255, 0.15)', // 行号
activeLineNumber: 'rgba(255,255,255, 0.6)', // 活动行号
// 边框和分割线
border: '#1e222a', // 边框色
borderLight: 'rgba(255,255,255, 0.1)', // 浅色边框
// 搜索和匹配
searchMatch: '#8fbcbb', // 搜索匹配
matchingBracket: 'rgba(255,255,255,0.1)', // 匹配括号
};
const darkTheme = EditorView.theme({
'&': {
color: colors.foreground,
backgroundColor: colors.background,
},
// 确保编辑器容器背景一致
'.cm-editor': {
backgroundColor: colors.background,
},
// 确保滚动区域背景一致
'.cm-scroller': {
backgroundColor: colors.background,
},
// 编辑器内容
'.cm-content': {
caretColor: colors.cursor,
paddingTop: '4px',
},
// 光标
'.cm-cursor, .cm-dropCursor': {
borderLeftColor: colors.cursor,
borderLeftWidth: '2px',
paddingTop: '4px',
marginTop: '-2px',
},
// 选择
'.cm-selectionBackground': {
backgroundColor: colors.selectionBlur,
},
'&.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground': {
backgroundColor: colors.selection,
},
'.cm-activeLine.code-empty-block-selected': {
backgroundColor: colors.selection,
},
// 当前行高亮
'.cm-activeLine': {
backgroundColor: colors.activeLine
},
// 行号区域
'.cm-gutters': {
backgroundColor: 'rgba(0,0,0, 0.1)',
color: colors.lineNumber,
border: 'none',
padding: '0 2px 0 4px',
userSelect: 'none',
},
'.cm-activeLineGutter': {
backgroundColor: 'transparent',
color: colors.activeLineNumber,
},
// 折叠功能
'.cm-foldGutter': {
marginLeft: '0px',
},
'.cm-foldGutter .cm-gutterElement': {
opacity: 0,
transition: 'opacity 400ms',
},
'.cm-gutters:hover .cm-gutterElement': {
opacity: 1,
},
'.cm-foldPlaceholder': {
backgroundColor: 'transparent',
border: 'none',
color: '#ddd',
},
// 搜索匹配
'.cm-searchMatch': {
backgroundColor: 'transparent',
outline: `1px solid ${colors.searchMatch}`,
},
'.cm-searchMatch.cm-searchMatch-selected': {
backgroundColor: colors.foreground,
color: colors.background,
},
'.cm-selectionMatch': {
backgroundColor: '#50606D',
},
// 括号匹配
'&.cm-focused .cm-matchingBracket, &.cm-focused .cm-nonmatchingBracket': {
outline: `0.5px solid ${colors.searchMatch}`,
},
'&.cm-focused .cm-matchingBracket': {
backgroundColor: colors.matchingBracket,
color: 'inherit',
},
'&.cm-focused .cm-nonmatchingBracket': {
outline: '0.5px solid #bc8f8f',
},
// 编辑器焦点
'&.cm-editor.cm-focused': {
outline: 'none',
},
// 工具提示
'.cm-tooltip': {
border: 'none',
backgroundColor: colors.surface,
},
'.cm-tooltip .cm-tooltip-arrow:before': {
borderTopColor: 'transparent',
borderBottomColor: 'transparent',
},
'.cm-tooltip .cm-tooltip-arrow:after': {
borderTopColor: colors.surface,
borderBottomColor: colors.surface,
},
'.cm-tooltip-autocomplete': {
'& > ul > li[aria-selected]': {
backgroundColor: colors.activeLine,
color: colors.foreground,
},
},
// 代码块层
'.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.border}`,
},
'.code-blocks-layer .block-even:first-child': {
borderTop: 'none',
},
'.code-blocks-layer .block-odd': {
background: colors.backgroundSecondary,
borderTop: `1px solid ${colors.border}`,
},
// 代码块开始标记
'.code-block-start': {
height: '12px',
position: 'relative',
},
'.code-block-start.first': {
height: '0px',
},
}, {dark: true});
// 语法高亮样式
const darkHighlightStyle = HighlightStyle.define([
{tag: tags.keyword, color: colors.keyword},
{tag: [tags.name, tags.deleted, tags.character, tags.propertyName, tags.macroName], color: colors.variable},
{tag: [tags.variableName], color: colors.variable},
{tag: [tags.function(tags.variableName)], color: colors.function},
{tag: [tags.labelName], color: colors.operator},
{tag: [tags.color, tags.constant(tags.name), tags.standard(tags.name)], color: colors.keyword},
{tag: [tags.definition(tags.name), tags.separator], color: colors.function},
{tag: [tags.brace], color: colors.variable},
{tag: [tags.annotation], color: '#d30102'},
{tag: [tags.number, tags.changed, tags.annotation, tags.modifier, tags.self, tags.namespace], color: colors.number},
{tag: [tags.typeName, tags.className], color: colors.type},
{tag: [tags.operator, tags.operatorKeyword], color: colors.operator},
{tag: [tags.tagName], color: colors.number},
{tag: [tags.squareBracket], color: '#bf616a'},
{tag: [tags.angleBracket], color: '#d08770'},
{tag: [tags.attributeName], color: colors.variable},
{tag: [tags.regexp], color: colors.string},
{tag: [tags.quote], color: colors.comment},
{tag: [tags.string], color: colors.string},
{tag: tags.link, color: colors.variable, textDecoration: 'underline'},
{tag: [tags.url, tags.escape, tags.special(tags.string)], color: colors.string},
{tag: [tags.meta], color: colors.comment},
{tag: [tags.comment], color: colors.comment, fontStyle: 'italic'},
{tag: tags.strong, fontWeight: 'bold'},
{tag: tags.emphasis, fontStyle: 'italic'},
{tag: tags.strikethrough, textDecoration: 'line-through'},
{tag: tags.heading, fontWeight: 'bold', color: colors.keyword},
{tag: [tags.heading1, tags.heading2], fontSize: '1.4em'},
{tag: [tags.heading3, tags.heading4], fontSize: '1.2em'},
{tag: [tags.heading5, tags.heading6], fontSize: '1.1em'},
]);
export const dark = [
darkTheme,
syntaxHighlighting(darkHighlightStyle),
];

View File

@@ -1,149 +0,0 @@
import {EditorView} from '@codemirror/view'
import {Extension} from '@codemirror/state'
import {HighlightStyle, syntaxHighlighting} from '@codemirror/language'
import {tags as t} from '@lezer/highlight'
export const config = {
name: 'base-dark',
dark: true,
background: '#252B37',
foreground: '#9BB586',
selection: '#3381c1',
selectionMatch: '#1A58887F',
cursor: '#F8F8F2',
dropdownBackground: '#282A36',
dropdownBorder: '#191A21',
activeLine: '#2E333F99',
lineNumber: '#676d7c',
lineNumberActive: '#F8F8F2',
lineNumberBackground: '#212731',
matchingBracket: '#44475A',
keyword: '#FF79C6',
storage: '#FF79C6',
variable: '#F8F8F2',
parameter: '#F8F8F2',
function: '#50FA7B',
string: '#F1FA8C',
constant: '#BD93F9',
type: '#8BE9FD',
class: '#8BE9FD',
number: '#BD93F9',
comment: '#6272A4',
heading: '#BD93F9',
invalid: '#FF5555',
regexp: '#F1FA8C',
}
export const draculaTheme = EditorView.theme({
'&': {
color: config.foreground,
backgroundColor: config.background,
},
'.cm-content': {caretColor: config.cursor},
'.cm-cursor, .cm-dropCursor': {borderLeftColor: config.cursor},
'&.cm-focused .cm-selectionBackground, .cm-selectionBackground, .cm-content ::selection': {
backgroundColor: `${config.selection} !important`
},
'.cm-panels': {backgroundColor: config.dropdownBackground, color: config.foreground},
'.cm-panels.cm-panels-top': {borderBottom: '2px solid black'},
'.cm-panels.cm-panels-bottom': {borderTop: '2px solid black'},
'.cm-searchMatch': {
backgroundColor: config.dropdownBackground,
outline: `1px solid ${config.dropdownBorder}`
},
'.cm-searchMatch.cm-searchMatch-selected': {
backgroundColor: config.selection
},
'.cm-activeLine': {backgroundColor: config.activeLine},
'.cm-selectionMatch': {
backgroundColor: `${config.selectionMatch} !important`,
borderRadius: '2px'
},
'&.cm-focused .cm-matchingBracket, &.cm-focused .cm-nonmatchingBracket': {
backgroundColor: config.matchingBracket,
outline: 'none'
},
'.cm-gutters': {
backgroundColor: 'rgba(0,0,0, 0.1)',
color: config.foreground,
border: 'none',
padding: '0 2px 0 4px',
userSelect: 'none',
},
'.cm-activeLineGutter': {
// backgroundColor: config.background
backgroundColor: "transparent",
color: 'rgba(255,255,255, 0.6)'
},
'.cm-lineNumbers .cm-gutterElement': {color: config.lineNumber},
'.cm-lineNumbers .cm-activeLineGutter': {color: config.lineNumberActive},
'.cm-foldPlaceholder': {
backgroundColor: 'transparent',
border: 'none',
color: config.foreground
},
'.cm-tooltip': {
border: `1px solid ${config.dropdownBorder}`,
backgroundColor: config.dropdownBackground,
color: config.foreground,
},
'.cm-tooltip .cm-tooltip-arrow:before': {
borderTopColor: 'transparent',
borderBottomColor: 'transparent'
},
'.cm-tooltip .cm-tooltip-arrow:after': {
borderTopColor: config.foreground,
borderBottomColor: config.foreground,
},
'.cm-tooltip-autocomplete': {
'& > ul > li[aria-selected]': {
background: config.selection,
color: config.foreground,
}
}
}, {dark: config.dark})
export const draculaHighlightStyle = HighlightStyle.define([
{tag: t.keyword, color: config.keyword},
{tag: [t.name, t.deleted, t.character, t.macroName], color: config.variable},
{tag: [t.propertyName], color: config.function},
{tag: [t.processingInstruction, t.string, t.inserted, t.special(t.string)], color: config.string},
{tag: [t.function(t.variableName), t.labelName], color: config.function},
{tag: [t.color, t.constant(t.name), t.standard(t.name)], color: config.constant},
{tag: [t.definition(t.name), t.separator], color: config.variable},
{tag: [t.className], color: config.class},
{tag: [t.number, t.changed, t.annotation, t.modifier, t.self, t.namespace], color: config.number},
{tag: [t.typeName], color: config.type, fontStyle: config.type},
{tag: [t.operator, t.operatorKeyword], color: config.keyword},
{tag: [t.url, t.escape, t.regexp, t.link], color: config.regexp},
{tag: [t.meta, t.comment], color: config.comment},
{tag: t.strong, fontWeight: 'bold'},
{tag: t.emphasis, fontStyle: 'italic'},
{tag: t.link, textDecoration: 'underline'},
{tag: t.heading, fontWeight: 'bold', color: config.heading},
{tag: [t.atom, t.bool, t.special(t.variableName)], color: config.variable},
{tag: t.invalid, color: config.invalid},
{tag: t.strikethrough, textDecoration: 'line-through'},
])
export const customHighlightActiveLine = EditorView.theme({
'.cm-activeLine': {
backgroundColor: config.activeLine,
}
})
export const defaultDark: Extension = [
draculaTheme,
syntaxHighlighting(draculaHighlightStyle),
]

View File

@@ -1,128 +0,0 @@
import {EditorView} from '@codemirror/view'
import {Extension} from '@codemirror/state'
import {HighlightStyle, syntaxHighlighting} from '@codemirror/language'
import {tags as t} from '@lezer/highlight'
export const config = {
name: 'dracula',
dark: true,
background: '#282A36',
foreground: '#F8F8F2',
selection: '#44475A',
cursor: '#F8F8F2',
dropdownBackground: '#282A36',
dropdownBorder: '#191A21',
activeLine: '#53576c22',
lineNumber: '#6272A4',
lineNumberActive: '#F8F8F2',
matchingBracket: '#44475A',
keyword: '#FF79C6',
storage: '#FF79C6',
variable: '#F8F8F2',
parameter: '#F8F8F2',
function: '#50FA7B',
string: '#F1FA8C',
constant: '#BD93F9',
type: '#8BE9FD',
class: '#8BE9FD',
number: '#BD93F9',
comment: '#6272A4',
heading: '#BD93F9',
invalid: '#FF5555',
regexp: '#F1FA8C',
}
export const draculaTheme = EditorView.theme({
'&': {
color: config.foreground,
backgroundColor: config.background,
},
'.cm-content': {caretColor: config.cursor},
'.cm-cursor, .cm-dropCursor': {borderLeftColor: config.cursor},
'&.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground, .cm-selectionBackground, .cm-content ::selection': {backgroundColor: config.selection},
'.cm-panels': {backgroundColor: config.dropdownBackground, color: config.foreground},
'.cm-panels.cm-panels-top': {borderBottom: '2px solid black'},
'.cm-panels.cm-panels-bottom': {borderTop: '2px solid black'},
'.cm-searchMatch': {
backgroundColor: config.dropdownBackground,
outline: `1px solid ${config.dropdownBorder}`
},
'.cm-searchMatch.cm-searchMatch-selected': {
backgroundColor: config.selection
},
'.cm-activeLine': {backgroundColor: config.activeLine},
'.cm-selectionMatch': {backgroundColor: config.selection},
'&.cm-focused .cm-matchingBracket, &.cm-focused .cm-nonmatchingBracket': {
backgroundColor: config.matchingBracket,
outline: 'none'
},
'.cm-gutters': {
backgroundColor: config.background,
color: config.foreground,
border: 'none'
},
'.cm-activeLineGutter': {backgroundColor: config.background},
'.cm-lineNumbers .cm-gutterElement': {color: config.lineNumber},
'.cm-lineNumbers .cm-activeLineGutter': {color: config.lineNumberActive},
'.cm-foldPlaceholder': {
backgroundColor: 'transparent',
border: 'none',
color: config.foreground
},
'.cm-tooltip': {
border: `1px solid ${config.dropdownBorder}`,
backgroundColor: config.dropdownBackground,
color: config.foreground,
},
'.cm-tooltip .cm-tooltip-arrow:before': {
borderTopColor: 'transparent',
borderBottomColor: 'transparent'
},
'.cm-tooltip .cm-tooltip-arrow:after': {
borderTopColor: config.foreground,
borderBottomColor: config.foreground,
},
'.cm-tooltip-autocomplete': {
'& > ul > li[aria-selected]': {
background: config.selection,
color: config.foreground,
}
}
}, {dark: config.dark})
export const draculaHighlightStyle = HighlightStyle.define([
{tag: t.keyword, color: config.keyword},
{tag: [t.name, t.deleted, t.character, t.macroName], color: config.variable},
{tag: [t.propertyName], color: config.function},
{tag: [t.processingInstruction, t.string, t.inserted, t.special(t.string)], color: config.string},
{tag: [t.function(t.variableName), t.labelName], color: config.function},
{tag: [t.color, t.constant(t.name), t.standard(t.name)], color: config.constant},
{tag: [t.definition(t.name), t.separator], color: config.variable},
{tag: [t.className], color: config.class},
{tag: [t.number, t.changed, t.annotation, t.modifier, t.self, t.namespace], color: config.number},
{tag: [t.typeName], color: config.type, fontStyle: config.type},
{tag: [t.operator, t.operatorKeyword], color: config.keyword},
{tag: [t.url, t.escape, t.regexp, t.link], color: config.regexp},
{tag: [t.meta, t.comment], color: config.comment},
{tag: t.strong, fontWeight: 'bold'},
{tag: t.emphasis, fontStyle: 'italic'},
{tag: t.link, textDecoration: 'underline'},
{tag: t.heading, fontWeight: 'bold', color: config.heading},
{tag: [t.atom, t.bool, t.special(t.variableName)], color: config.variable},
{tag: t.invalid, color: config.invalid},
{tag: t.strikethrough, textDecoration: 'line-through'},
])
export const dracula: Extension = [
draculaTheme,
syntaxHighlighting(draculaHighlightStyle),
]

View File

@@ -1,128 +0,0 @@
import {EditorView} from '@codemirror/view'
import {Extension} from '@codemirror/state'
import {HighlightStyle, syntaxHighlighting} from '@codemirror/language'
import {tags as t} from '@lezer/highlight'
export const config = {
name: 'githubDark',
dark: true,
background: '#24292e',
foreground: '#d1d5da',
selection: '#3392FF44',
cursor: '#c8e1ff',
dropdownBackground: '#24292e',
dropdownBorder: '#1b1f23',
activeLine: '#4d566022',
lineNumber: '#444d56',
lineNumberActive: '#e1e4e8',
matchingBracket: '#17E5E650',
keyword: '#f97583',
storage: '#f97583',
variable: '#ffab70',
parameter: '#e1e4e8',
function: '#79b8ff',
string: '#9ecbff',
constant: '#79b8ff',
type: '#79b8ff',
class: '#b392f0',
number: '#79b8ff',
comment: '#6a737d',
heading: '#79b8ff',
invalid: '#f97583',
regexp: '#9ecbff',
}
export const githubDarkTheme = EditorView.theme({
'&': {
color: config.foreground,
backgroundColor: config.background,
},
'.cm-content': {caretColor: config.cursor},
'.cm-cursor, .cm-dropCursor': {borderLeftColor: config.cursor},
'&.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground, .cm-selectionBackground, .cm-content ::selection': {backgroundColor: config.selection},
'.cm-panels': {backgroundColor: config.dropdownBackground, color: config.foreground},
'.cm-panels.cm-panels-top': {borderBottom: '2px solid black'},
'.cm-panels.cm-panels-bottom': {borderTop: '2px solid black'},
'.cm-searchMatch': {
backgroundColor: config.dropdownBackground,
outline: `1px solid ${config.dropdownBorder}`
},
'.cm-searchMatch.cm-searchMatch-selected': {
backgroundColor: config.selection
},
'.cm-activeLine': {backgroundColor: config.activeLine},
'.cm-selectionMatch': {backgroundColor: config.selection},
'&.cm-focused .cm-matchingBracket, &.cm-focused .cm-nonmatchingBracket': {
backgroundColor: config.matchingBracket,
outline: 'none'
},
'.cm-gutters': {
backgroundColor: config.background,
color: config.foreground,
border: 'none'
},
'.cm-activeLineGutter': {backgroundColor: config.background},
'.cm-lineNumbers .cm-gutterElement': {color: config.lineNumber},
'.cm-lineNumbers .cm-activeLineGutter': {color: config.lineNumberActive},
'.cm-foldPlaceholder': {
backgroundColor: 'transparent',
border: 'none',
color: config.foreground
},
'.cm-tooltip': {
border: `1px solid ${config.dropdownBorder}`,
backgroundColor: config.dropdownBackground,
color: config.foreground,
},
'.cm-tooltip .cm-tooltip-arrow:before': {
borderTopColor: 'transparent',
borderBottomColor: 'transparent'
},
'.cm-tooltip .cm-tooltip-arrow:after': {
borderTopColor: config.foreground,
borderBottomColor: config.foreground,
},
'.cm-tooltip-autocomplete': {
'& > ul > li[aria-selected]': {
background: config.selection,
color: config.foreground,
}
}
}, {dark: config.dark})
export const githubDarkHighlightStyle = HighlightStyle.define([
{tag: t.keyword, color: config.keyword},
{tag: [t.name, t.deleted, t.character, t.macroName], color: config.variable},
{tag: [t.propertyName], color: config.function},
{tag: [t.processingInstruction, t.string, t.inserted, t.special(t.string)], color: config.string},
{tag: [t.function(t.variableName), t.labelName], color: config.function},
{tag: [t.color, t.constant(t.name), t.standard(t.name)], color: config.constant},
{tag: [t.definition(t.name), t.separator], color: config.variable},
{tag: [t.className], color: config.class},
{tag: [t.number, t.changed, t.annotation, t.modifier, t.self, t.namespace], color: config.number},
{tag: [t.typeName], color: config.type, fontStyle: config.type},
{tag: [t.operator, t.operatorKeyword], color: config.keyword},
{tag: [t.url, t.escape, t.regexp, t.link], color: config.regexp},
{tag: [t.meta, t.comment], color: config.comment},
{tag: t.strong, fontWeight: 'bold'},
{tag: t.emphasis, fontStyle: 'italic'},
{tag: t.link, textDecoration: 'underline'},
{tag: t.heading, fontWeight: 'bold', color: config.heading},
{tag: [t.atom, t.bool, t.special(t.variableName)], color: config.variable},
{tag: t.invalid, color: config.invalid},
{tag: t.strikethrough, textDecoration: 'line-through'},
])
export const githubDark: Extension = [
githubDarkTheme,
syntaxHighlighting(githubDarkHighlightStyle),
]

View File

@@ -1,128 +0,0 @@
import {EditorView} from '@codemirror/view'
import {Extension} from '@codemirror/state'
import {HighlightStyle, syntaxHighlighting} from '@codemirror/language'
import {tags as t} from '@lezer/highlight'
export const config = {
name: 'githubLight',
dark: false,
background: '#fff',
foreground: '#444d56',
selection: '#0366d625',
cursor: '#044289',
dropdownBackground: '#fff',
dropdownBorder: '#e1e4e8',
activeLine: '#c6c6c622',
lineNumber: '#1b1f234d',
lineNumberActive: '#24292e',
matchingBracket: '#34d05840',
keyword: '#d73a49',
storage: '#d73a49',
variable: '#e36209',
parameter: '#24292e',
function: '#005cc5',
string: '#032f62',
constant: '#005cc5',
type: '#005cc5',
class: '#6f42c1',
number: '#005cc5',
comment: '#6a737d',
heading: '#005cc5',
invalid: '#cb2431',
regexp: '#032f62',
}
export const githubLightTheme = EditorView.theme({
'&': {
color: config.foreground,
backgroundColor: config.background,
},
'.cm-content': {caretColor: config.cursor},
'.cm-cursor, .cm-dropCursor': {borderLeftColor: config.cursor},
'&.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground, .cm-selectionBackground, .cm-content ::selection': {backgroundColor: config.selection},
'.cm-panels': {backgroundColor: config.dropdownBackground, color: config.foreground},
'.cm-panels.cm-panels-top': {borderBottom: '2px solid black'},
'.cm-panels.cm-panels-bottom': {borderTop: '2px solid black'},
'.cm-searchMatch': {
backgroundColor: config.dropdownBackground,
outline: `1px solid ${config.dropdownBorder}`
},
'.cm-searchMatch.cm-searchMatch-selected': {
backgroundColor: config.selection
},
'.cm-activeLine': {backgroundColor: config.activeLine},
'.cm-selectionMatch': {backgroundColor: config.selection},
'&.cm-focused .cm-matchingBracket, &.cm-focused .cm-nonmatchingBracket': {
backgroundColor: config.matchingBracket,
outline: 'none'
},
'.cm-gutters': {
backgroundColor: config.background,
color: config.foreground,
border: 'none'
},
'.cm-activeLineGutter': {backgroundColor: config.background},
'.cm-lineNumbers .cm-gutterElement': {color: config.lineNumber},
'.cm-lineNumbers .cm-activeLineGutter': {color: config.lineNumberActive},
'.cm-foldPlaceholder': {
backgroundColor: 'transparent',
border: 'none',
color: config.foreground
},
'.cm-tooltip': {
border: `1px solid ${config.dropdownBorder}`,
backgroundColor: config.dropdownBackground,
color: config.foreground,
},
'.cm-tooltip .cm-tooltip-arrow:before': {
borderTopColor: 'transparent',
borderBottomColor: 'transparent'
},
'.cm-tooltip .cm-tooltip-arrow:after': {
borderTopColor: config.foreground,
borderBottomColor: config.foreground,
},
'.cm-tooltip-autocomplete': {
'& > ul > li[aria-selected]': {
background: config.selection,
color: config.foreground,
}
}
}, {dark: config.dark})
export const githubLightHighlightStyle = HighlightStyle.define([
{tag: t.keyword, color: config.keyword},
{tag: [t.name, t.deleted, t.character, t.macroName], color: config.variable},
{tag: [t.propertyName], color: config.function},
{tag: [t.processingInstruction, t.string, t.inserted, t.special(t.string)], color: config.string},
{tag: [t.function(t.variableName), t.labelName], color: config.function},
{tag: [t.color, t.constant(t.name), t.standard(t.name)], color: config.constant},
{tag: [t.definition(t.name), t.separator], color: config.variable},
{tag: [t.className], color: config.class},
{tag: [t.number, t.changed, t.annotation, t.modifier, t.self, t.namespace], color: config.number},
{tag: [t.typeName], color: config.type, fontStyle: config.type},
{tag: [t.operator, t.operatorKeyword], color: config.keyword},
{tag: [t.url, t.escape, t.regexp, t.link], color: config.regexp},
{tag: [t.meta, t.comment], color: config.comment},
{tag: t.strong, fontWeight: 'bold'},
{tag: t.emphasis, fontStyle: 'italic'},
{tag: t.link, textDecoration: 'underline'},
{tag: t.heading, fontWeight: 'bold', color: config.heading},
{tag: [t.atom, t.bool, t.special(t.variableName)], color: config.variable},
{tag: t.invalid, color: config.invalid},
{tag: t.strikethrough, textDecoration: 'line-through'},
])
export const githubLight: Extension = [
githubLightTheme,
syntaxHighlighting(githubLightHighlightStyle),
]

View File

@@ -0,0 +1,239 @@
import { EditorView } from '@codemirror/view';
import { HighlightStyle, syntaxHighlighting } from '@codemirror/language';
import { tags } from '@lezer/highlight';
const colors = {
// 基础色调
background: '#ffffff', // 主背景色
// backgroundAlt: '#f4f8f4', // 交替背景色
backgroundSecondary: '#f1faf1', // 次要背景色
surface: '#f5f5f5', // 面板背景
// 文本颜色
foreground: '#444d56', // 主文本色
foregroundSecondary: '#6a737d', // 次要文本色
comment: '#6a737d', // 注释色
// 语法高亮色
keyword: '#d73a49', // 关键字
string: '#032f62', // 字符串
function: '#005cc5', // 函数名
number: '#005cc5', // 数字
operator: '#d73a49', // 操作符
variable: '#24292e', // 变量
type: '#6f42c1', // 类型
// 界面元素
cursor: '#000', // 光标
selection: '#77baff8c', // 选中背景
selectionBlur: '#b2c2ca85', // 失焦选中背景
activeLine: 'rgba(0,0,0, 0.04)', // 当前行高亮
lineNumber: 'rgba(0,0,0, 0.25)', // 行号
activeLineNumber: 'rgba(0,0,0, 0.6)', // 活动行号
// 边框和分割线
border: '#dfdfdf', // 边框色
borderLight: 'rgba(0,0,0, 0.05)', // 浅色边框
// 搜索和匹配
searchMatch: '#005cc5', // 搜索匹配
matchingBracket: 'rgba(0,0,0,0.1)', // 匹配括号
};
const lightTheme = EditorView.theme({
'&': {
color: colors.foreground,
backgroundColor: colors.background,
},
// 确保编辑器容器背景一致
'.cm-editor': {
backgroundColor: colors.background,
},
// 确保滚动区域背景一致
'.cm-scroller': {
backgroundColor: colors.background,
},
// 编辑器内容
'.cm-content': {
caretColor: colors.cursor,
paddingTop: '4px',
},
// 光标
'.cm-cursor, .cm-dropCursor': {
borderLeftColor: colors.cursor,
borderLeftWidth: '2px',
paddingTop: '4px',
marginTop: '-2px',
},
// 选择
'.cm-selectionBackground': {
backgroundColor: colors.selectionBlur,
},
'&.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground': {
backgroundColor: colors.selection,
},
'.cm-activeLine.code-empty-block-selected': {
backgroundColor: colors.selection,
},
// 当前行高亮
'.cm-activeLine': {
backgroundColor: colors.activeLine
},
// 行号区域
'.cm-gutters': {
backgroundColor: 'rgba(0,0,0, 0.04)',
color: colors.lineNumber,
border: 'none',
borderRight: `1px solid ${colors.borderLight}`,
padding: '0 2px 0 4px',
userSelect: 'none',
},
'.cm-activeLineGutter': {
backgroundColor: 'transparent',
color: colors.activeLineNumber,
},
// 折叠功能
'.cm-foldGutter': {
marginLeft: '0px',
},
'.cm-foldGutter .cm-gutterElement': {
opacity: 0,
transition: 'opacity 400ms',
},
'.cm-gutters:hover .cm-gutterElement': {
opacity: 1,
},
'.cm-foldPlaceholder': {
backgroundColor: 'transparent',
border: 'none',
color: colors.comment,
},
// 搜索匹配
'.cm-searchMatch': {
backgroundColor: 'transparent',
outline: `1px solid ${colors.searchMatch}`,
},
'.cm-searchMatch.cm-searchMatch-selected': {
backgroundColor: colors.searchMatch,
color: colors.background,
},
'.cm-selectionMatch': {
backgroundColor: '#e6f3ff',
},
// 括号匹配
'&.cm-focused .cm-matchingBracket, &.cm-focused .cm-nonmatchingBracket': {
outline: `0.5px solid ${colors.searchMatch}`,
},
'&.cm-focused .cm-matchingBracket': {
backgroundColor: colors.matchingBracket,
color: 'inherit',
},
'&.cm-focused .cm-nonmatchingBracket': {
outline: '0.5px solid #d73a49',
},
// 编辑器焦点
'&.cm-editor.cm-focused': {
outline: 'none',
},
// 工具提示
'.cm-tooltip': {
border: 'none',
backgroundColor: colors.surface,
boxShadow: '0 2px 8px rgba(0,0,0,0.1)',
},
'.cm-tooltip .cm-tooltip-arrow:before': {
borderTopColor: 'transparent',
borderBottomColor: 'transparent',
},
'.cm-tooltip .cm-tooltip-arrow:after': {
borderTopColor: colors.surface,
borderBottomColor: colors.surface,
},
'.cm-tooltip-autocomplete': {
'& > ul > li[aria-selected]': {
backgroundColor: colors.activeLine,
color: colors.foreground,
},
},
// 代码块层
'.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.border}`,
},
'.code-blocks-layer .block-even:first-child': {
borderTop: 'none',
},
'.code-blocks-layer .block-odd': {
background: colors.backgroundSecondary,
borderTop: `1px solid ${colors.border}`,
},
// 代码块开始标记
'.code-block-start': {
height: '12px',
},
'.code-block-start.first': {
height: '0px',
},
}, { dark: false });
// 语法高亮样式
const lightHighlightStyle = HighlightStyle.define([
{ tag: tags.keyword, color: colors.keyword },
{ tag: [tags.name, tags.deleted, tags.character, tags.propertyName, tags.macroName], color: colors.variable },
{ tag: [tags.variableName], color: colors.variable },
{ tag: [tags.function(tags.variableName)], color: colors.function },
{ tag: [tags.labelName], color: colors.operator },
{ tag: [tags.color, tags.constant(tags.name), tags.standard(tags.name)], color: colors.keyword },
{ tag: [tags.definition(tags.name), tags.separator], color: colors.function },
{ tag: [tags.brace], color: colors.variable },
{ tag: [tags.annotation], color: '#d73a49' },
{ tag: [tags.number, tags.changed, tags.annotation, tags.modifier, tags.self, tags.namespace], color: colors.number },
{ tag: [tags.typeName, tags.className], color: colors.type },
{ tag: [tags.operator, tags.operatorKeyword], color: colors.operator },
{ tag: [tags.tagName], color: colors.type },
{ tag: [tags.squareBracket], color: colors.keyword },
{ tag: [tags.angleBracket], color: colors.operator },
{ tag: [tags.attributeName], color: colors.variable },
{ tag: [tags.regexp], color: colors.string },
{ tag: [tags.quote], color: colors.comment },
{ tag: [tags.string], color: colors.string },
{ tag: tags.link, color: colors.function, textDecoration: 'underline' },
{ tag: [tags.url, tags.escape, tags.special(tags.string)], color: colors.string },
{ tag: [tags.meta], color: colors.comment },
{ tag: [tags.comment], color: colors.comment, fontStyle: 'italic' },
{ tag: tags.strong, fontWeight: 'bold' },
{ tag: tags.emphasis, fontStyle: 'italic' },
{ tag: tags.strikethrough, textDecoration: 'line-through' },
{ tag: tags.heading, fontWeight: 'bold', color: colors.keyword },
{ tag: [tags.heading1, tags.heading2], fontSize: '1.4em' },
{ tag: [tags.heading3, tags.heading4], fontSize: '1.2em' },
{ tag: [tags.heading5, tags.heading6], fontSize: '1.1em' },
]);
export const light = [
lightTheme,
syntaxHighlighting(lightHighlightStyle),
];

View File

@@ -1,128 +0,0 @@
import {EditorView} from '@codemirror/view'
import {Extension} from '@codemirror/state'
import {HighlightStyle, syntaxHighlighting} from '@codemirror/language'
import {tags as t} from '@lezer/highlight'
export const config = {
name: 'materialDark',
dark: true,
background: '#263238',
foreground: '#EEFFFF',
selection: '#80CBC420',
cursor: '#FFCC00',
dropdownBackground: '#263238',
dropdownBorder: '#FFFFFF10',
activeLine: '#4c616c22',
lineNumber: '#37474F',
lineNumberActive: '#607a86',
matchingBracket: '#263238',
keyword: '#C792EA',
storage: '#C792EA',
variable: '#EEFFFF',
parameter: '#EEFFFF',
function: '#82AAFF',
string: '#C3E88D',
constant: '#F78C6C',
type: '#B2CCD6',
class: '#FFCB6B',
number: '#F78C6C',
comment: '#546E7A',
heading: '#C3E88D',
invalid: '#FF5370',
regexp: '#89DDFF',
}
export const materialDarkTheme = EditorView.theme({
'&': {
color: config.foreground,
backgroundColor: config.background,
},
'.cm-content': {caretColor: config.cursor},
'.cm-cursor, .cm-dropCursor': {borderLeftColor: config.cursor},
'&.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground, .cm-selectionBackground, .cm-content ::selection': {backgroundColor: config.selection},
'.cm-panels': {backgroundColor: config.dropdownBackground, color: config.foreground},
'.cm-panels.cm-panels-top': {borderBottom: '2px solid black'},
'.cm-panels.cm-panels-bottom': {borderTop: '2px solid black'},
'.cm-searchMatch': {
backgroundColor: config.dropdownBackground,
outline: `1px solid ${config.dropdownBorder}`
},
'.cm-searchMatch.cm-searchMatch-selected': {
backgroundColor: config.selection
},
'.cm-activeLine': {backgroundColor: config.activeLine},
'.cm-selectionMatch': {backgroundColor: config.selection},
'&.cm-focused .cm-matchingBracket, &.cm-focused .cm-nonmatchingBracket': {
backgroundColor: config.matchingBracket,
outline: 'none'
},
'.cm-gutters': {
backgroundColor: config.background,
color: config.foreground,
border: 'none'
},
'.cm-activeLineGutter': {backgroundColor: config.background},
'.cm-lineNumbers .cm-gutterElement': {color: config.lineNumber},
'.cm-lineNumbers .cm-activeLineGutter': {color: config.lineNumberActive},
'.cm-foldPlaceholder': {
backgroundColor: 'transparent',
border: 'none',
color: config.foreground
},
'.cm-tooltip': {
border: `1px solid ${config.dropdownBorder}`,
backgroundColor: config.dropdownBackground,
color: config.foreground,
},
'.cm-tooltip .cm-tooltip-arrow:before': {
borderTopColor: 'transparent',
borderBottomColor: 'transparent'
},
'.cm-tooltip .cm-tooltip-arrow:after': {
borderTopColor: config.foreground,
borderBottomColor: config.foreground,
},
'.cm-tooltip-autocomplete': {
'& > ul > li[aria-selected]': {
background: config.selection,
color: config.foreground,
}
}
}, {dark: config.dark})
export const materialDarkHighlightStyle = HighlightStyle.define([
{tag: t.keyword, color: config.keyword},
{tag: [t.name, t.deleted, t.character, t.macroName], color: config.variable},
{tag: [t.propertyName], color: config.function},
{tag: [t.processingInstruction, t.string, t.inserted, t.special(t.string)], color: config.string},
{tag: [t.function(t.variableName), t.labelName], color: config.function},
{tag: [t.color, t.constant(t.name), t.standard(t.name)], color: config.constant},
{tag: [t.definition(t.name), t.separator], color: config.variable},
{tag: [t.className], color: config.class},
{tag: [t.number, t.changed, t.annotation, t.modifier, t.self, t.namespace], color: config.number},
{tag: [t.typeName], color: config.type, fontStyle: config.type},
{tag: [t.operator, t.operatorKeyword], color: config.keyword},
{tag: [t.url, t.escape, t.regexp, t.link], color: config.regexp},
{tag: [t.meta, t.comment], color: config.comment},
{tag: t.strong, fontWeight: 'bold'},
{tag: t.emphasis, fontStyle: 'italic'},
{tag: t.link, textDecoration: 'underline'},
{tag: t.heading, fontWeight: 'bold', color: config.heading},
{tag: [t.atom, t.bool, t.special(t.variableName)], color: config.variable},
{tag: t.invalid, color: config.invalid},
{tag: t.strikethrough, textDecoration: 'line-through'},
])
export const materialDark: Extension = [
materialDarkTheme,
syntaxHighlighting(materialDarkHighlightStyle),
]

View File

@@ -1,128 +0,0 @@
import {EditorView} from '@codemirror/view'
import {Extension} from '@codemirror/state'
import {HighlightStyle, syntaxHighlighting} from '@codemirror/language'
import {tags as t} from '@lezer/highlight'
export const config = {
name: 'materialLight',
dark: false,
background: '#FAFAFA',
foreground: '#90A4AE',
selection: '#80CBC440',
cursor: '#272727',
dropdownBackground: '#FAFAFA',
dropdownBorder: '#00000010',
activeLine: '#c2c2c222',
lineNumber: '#CFD8DC',
lineNumberActive: '#7E939E',
matchingBracket: '#FAFAFA',
keyword: '#7C4DFF',
storage: '#7C4DFF',
variable: '#90A4AE',
parameter: '#90A4AE',
function: '#6182B8',
string: '#91B859',
constant: '#F76D47',
type: '#8796B0',
class: '#FFB62C',
number: '#F76D47',
comment: '#90A4AE',
heading: '#91B859',
invalid: '#E53935',
regexp: '#39ADB5',
}
export const materialLightTheme = EditorView.theme({
'&': {
color: config.foreground,
backgroundColor: config.background,
},
'.cm-content': {caretColor: config.cursor},
'.cm-cursor, .cm-dropCursor': {borderLeftColor: config.cursor},
'&.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground, .cm-selectionBackground, .cm-content ::selection': {backgroundColor: config.selection},
'.cm-panels': {backgroundColor: config.dropdownBackground, color: config.foreground},
'.cm-panels.cm-panels-top': {borderBottom: '2px solid black'},
'.cm-panels.cm-panels-bottom': {borderTop: '2px solid black'},
'.cm-searchMatch': {
backgroundColor: config.dropdownBackground,
outline: `1px solid ${config.dropdownBorder}`
},
'.cm-searchMatch.cm-searchMatch-selected': {
backgroundColor: config.selection
},
'.cm-activeLine': {backgroundColor: config.activeLine},
'.cm-selectionMatch': {backgroundColor: config.selection},
'&.cm-focused .cm-matchingBracket, &.cm-focused .cm-nonmatchingBracket': {
backgroundColor: config.matchingBracket,
outline: 'none'
},
'.cm-gutters': {
backgroundColor: config.background,
color: config.foreground,
border: 'none'
},
'.cm-activeLineGutter': {backgroundColor: config.background},
'.cm-lineNumbers .cm-gutterElement': {color: config.lineNumber},
'.cm-lineNumbers .cm-activeLineGutter': {color: config.lineNumberActive},
'.cm-foldPlaceholder': {
backgroundColor: 'transparent',
border: 'none',
color: config.foreground
},
'.cm-tooltip': {
border: `1px solid ${config.dropdownBorder}`,
backgroundColor: config.dropdownBackground,
color: config.foreground,
},
'.cm-tooltip .cm-tooltip-arrow:before': {
borderTopColor: 'transparent',
borderBottomColor: 'transparent'
},
'.cm-tooltip .cm-tooltip-arrow:after': {
borderTopColor: config.foreground,
borderBottomColor: config.foreground,
},
'.cm-tooltip-autocomplete': {
'& > ul > li[aria-selected]': {
background: config.selection,
color: config.foreground,
}
}
}, {dark: config.dark})
export const materialLightHighlightStyle = HighlightStyle.define([
{tag: t.keyword, color: config.keyword},
{tag: [t.name, t.deleted, t.character, t.macroName], color: config.variable},
{tag: [t.propertyName], color: config.function},
{tag: [t.processingInstruction, t.string, t.inserted, t.special(t.string)], color: config.string},
{tag: [t.function(t.variableName), t.labelName], color: config.function},
{tag: [t.color, t.constant(t.name), t.standard(t.name)], color: config.constant},
{tag: [t.definition(t.name), t.separator], color: config.variable},
{tag: [t.className], color: config.class},
{tag: [t.number, t.changed, t.annotation, t.modifier, t.self, t.namespace], color: config.number},
{tag: [t.typeName], color: config.type, fontStyle: config.type},
{tag: [t.operator, t.operatorKeyword], color: config.keyword},
{tag: [t.url, t.escape, t.regexp, t.link], color: config.regexp},
{tag: [t.meta, t.comment], color: config.comment},
{tag: t.strong, fontWeight: 'bold'},
{tag: t.emphasis, fontStyle: 'italic'},
{tag: t.link, textDecoration: 'underline'},
{tag: t.heading, fontWeight: 'bold', color: config.heading},
{tag: [t.atom, t.bool, t.special(t.variableName)], color: config.variable},
{tag: t.invalid, color: config.invalid},
{tag: t.strikethrough, textDecoration: 'line-through'},
])
export const materialLight: Extension = [
materialLightTheme,
syntaxHighlighting(materialLightHighlightStyle),
]

View File

@@ -1,128 +0,0 @@
import {EditorView} from '@codemirror/view'
import {Extension} from '@codemirror/state'
import {HighlightStyle, syntaxHighlighting} from '@codemirror/language'
import {tags as t} from '@lezer/highlight'
export const config = {
name: 'solarizedDark',
dark: true,
background: '#002B36',
foreground: '#93A1A1',
selection: '#274642',
cursor: '#D30102',
dropdownBackground: '#002B36',
dropdownBorder: '#2AA19899',
activeLine: '#005b7022',
lineNumber: '#93A1A1',
lineNumberActive: '#949494',
matchingBracket: '#073642',
keyword: '#859900',
storage: '#93A1A1',
variable: '#268BD2',
parameter: '#268BD2',
function: '#268BD2',
string: '#2AA198',
constant: '#CB4B16',
type: '#CB4B16',
class: '#CB4B16',
number: '#D33682',
comment: '#586E75',
heading: '#268BD2',
invalid: '#DC322F',
regexp: '#DC322F',
}
export const solarizedDarkTheme = EditorView.theme({
'&': {
color: config.foreground,
backgroundColor: config.background,
},
'.cm-content': {caretColor: config.cursor},
'.cm-cursor, .cm-dropCursor': {borderLeftColor: config.cursor},
'&.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground, .cm-selectionBackground, .cm-content ::selection': {backgroundColor: config.selection},
'.cm-panels': {backgroundColor: config.dropdownBackground, color: config.foreground},
'.cm-panels.cm-panels-top': {borderBottom: '2px solid black'},
'.cm-panels.cm-panels-bottom': {borderTop: '2px solid black'},
'.cm-searchMatch': {
backgroundColor: config.dropdownBackground,
outline: `1px solid ${config.dropdownBorder}`
},
'.cm-searchMatch.cm-searchMatch-selected': {
backgroundColor: config.selection
},
'.cm-activeLine': {backgroundColor: config.activeLine},
'.cm-selectionMatch': {backgroundColor: config.selection},
'&.cm-focused .cm-matchingBracket, &.cm-focused .cm-nonmatchingBracket': {
backgroundColor: config.matchingBracket,
outline: 'none'
},
'.cm-gutters': {
backgroundColor: config.background,
color: config.foreground,
border: 'none'
},
'.cm-activeLineGutter': {backgroundColor: config.background},
'.cm-lineNumbers .cm-gutterElement': {color: config.lineNumber},
'.cm-lineNumbers .cm-activeLineGutter': {color: config.lineNumberActive},
'.cm-foldPlaceholder': {
backgroundColor: 'transparent',
border: 'none',
color: config.foreground
},
'.cm-tooltip': {
border: `1px solid ${config.dropdownBorder}`,
backgroundColor: config.dropdownBackground,
color: config.foreground,
},
'.cm-tooltip .cm-tooltip-arrow:before': {
borderTopColor: 'transparent',
borderBottomColor: 'transparent'
},
'.cm-tooltip .cm-tooltip-arrow:after': {
borderTopColor: config.foreground,
borderBottomColor: config.foreground,
},
'.cm-tooltip-autocomplete': {
'& > ul > li[aria-selected]': {
background: config.selection,
color: config.foreground,
}
}
}, {dark: config.dark})
export const solarizedDarkHighlightStyle = HighlightStyle.define([
{tag: t.keyword, color: config.keyword},
{tag: [t.name, t.deleted, t.character, t.macroName], color: config.variable},
{tag: [t.propertyName], color: config.function},
{tag: [t.processingInstruction, t.string, t.inserted, t.special(t.string)], color: config.string},
{tag: [t.function(t.variableName), t.labelName], color: config.function},
{tag: [t.color, t.constant(t.name), t.standard(t.name)], color: config.constant},
{tag: [t.definition(t.name), t.separator], color: config.variable},
{tag: [t.className], color: config.class},
{tag: [t.number, t.changed, t.annotation, t.modifier, t.self, t.namespace], color: config.number},
{tag: [t.typeName], color: config.type, fontStyle: config.type},
{tag: [t.operator, t.operatorKeyword], color: config.keyword},
{tag: [t.url, t.escape, t.regexp, t.link], color: config.regexp},
{tag: [t.meta, t.comment], color: config.comment},
{tag: t.strong, fontWeight: 'bold'},
{tag: t.emphasis, fontStyle: 'italic'},
{tag: t.link, textDecoration: 'underline'},
{tag: t.heading, fontWeight: 'bold', color: config.heading},
{tag: [t.atom, t.bool, t.special(t.variableName)], color: config.variable},
{tag: t.invalid, color: config.invalid},
{tag: t.strikethrough, textDecoration: 'line-through'},
])
export const solarizedDark: Extension = [
solarizedDarkTheme,
syntaxHighlighting(solarizedDarkHighlightStyle),
]

View File

@@ -1,128 +0,0 @@
import {EditorView} from '@codemirror/view'
import {Extension} from '@codemirror/state'
import {HighlightStyle, syntaxHighlighting} from '@codemirror/language'
import {tags as t} from '@lezer/highlight'
export const config = {
name: 'solarizedLight',
dark: false,
background: '#FDF6E3',
foreground: '#586E75',
selection: '#EEE8D5',
cursor: '#657B83',
dropdownBackground: '#FDF6E3',
dropdownBorder: '#D3AF86',
activeLine: '#d5bd5c22',
lineNumber: '#586E75',
lineNumberActive: '#567983',
matchingBracket: '#EEE8D5',
keyword: '#859900',
storage: '#586E75',
variable: '#268BD2',
parameter: '#268BD2',
function: '#268BD2',
string: '#2AA198',
constant: '#CB4B16',
type: '#CB4B16',
class: '#CB4B16',
number: '#D33682',
comment: '#93A1A1',
heading: '#268BD2',
invalid: '#DC322F',
regexp: '#DC322F',
}
export const solarizedLightTheme = EditorView.theme({
'&': {
color: config.foreground,
backgroundColor: config.background,
},
'.cm-content': {caretColor: config.cursor},
'.cm-cursor, .cm-dropCursor': {borderLeftColor: config.cursor},
'&.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground, .cm-selectionBackground, .cm-content ::selection': {backgroundColor: config.selection},
'.cm-panels': {backgroundColor: config.dropdownBackground, color: config.foreground},
'.cm-panels.cm-panels-top': {borderBottom: '2px solid black'},
'.cm-panels.cm-panels-bottom': {borderTop: '2px solid black'},
'.cm-searchMatch': {
backgroundColor: config.dropdownBackground,
outline: `1px solid ${config.dropdownBorder}`
},
'.cm-searchMatch.cm-searchMatch-selected': {
backgroundColor: config.selection
},
'.cm-activeLine': {backgroundColor: config.activeLine},
'.cm-selectionMatch': {backgroundColor: config.selection},
'&.cm-focused .cm-matchingBracket, &.cm-focused .cm-nonmatchingBracket': {
backgroundColor: config.matchingBracket,
outline: 'none'
},
'.cm-gutters': {
backgroundColor: config.background,
color: config.foreground,
border: 'none'
},
'.cm-activeLineGutter': {backgroundColor: config.background},
'.cm-lineNumbers .cm-gutterElement': {color: config.lineNumber},
'.cm-lineNumbers .cm-activeLineGutter': {color: config.lineNumberActive},
'.cm-foldPlaceholder': {
backgroundColor: 'transparent',
border: 'none',
color: config.foreground
},
'.cm-tooltip': {
border: `1px solid ${config.dropdownBorder}`,
backgroundColor: config.dropdownBackground,
color: config.foreground,
},
'.cm-tooltip .cm-tooltip-arrow:before': {
borderTopColor: 'transparent',
borderBottomColor: 'transparent'
},
'.cm-tooltip .cm-tooltip-arrow:after': {
borderTopColor: config.foreground,
borderBottomColor: config.foreground,
},
'.cm-tooltip-autocomplete': {
'& > ul > li[aria-selected]': {
background: config.selection,
color: config.foreground,
}
}
}, {dark: config.dark})
export const solarizedLightHighlightStyle = HighlightStyle.define([
{tag: t.keyword, color: config.keyword},
{tag: [t.name, t.deleted, t.character, t.macroName], color: config.variable},
{tag: [t.propertyName], color: config.function},
{tag: [t.processingInstruction, t.string, t.inserted, t.special(t.string)], color: config.string},
{tag: [t.function(t.variableName), t.labelName], color: config.function},
{tag: [t.color, t.constant(t.name), t.standard(t.name)], color: config.constant},
{tag: [t.definition(t.name), t.separator], color: config.variable},
{tag: [t.className], color: config.class},
{tag: [t.number, t.changed, t.annotation, t.modifier, t.self, t.namespace], color: config.number},
{tag: [t.typeName], color: config.type, fontStyle: config.type},
{tag: [t.operator, t.operatorKeyword], color: config.keyword},
{tag: [t.url, t.escape, t.regexp, t.link], color: config.regexp},
{tag: [t.meta, t.comment], color: config.comment},
{tag: t.strong, fontWeight: 'bold'},
{tag: t.emphasis, fontStyle: 'italic'},
{tag: t.link, textDecoration: 'underline'},
{tag: t.heading, fontWeight: 'bold', color: config.heading},
{tag: [t.atom, t.bool, t.special(t.variableName)], color: config.variable},
{tag: t.invalid, color: config.invalid},
{tag: t.strikethrough, textDecoration: 'line-through'},
])
export const solarizedLight: Extension = [
solarizedLightTheme,
syntaxHighlighting(solarizedLightHighlightStyle),
]

View File

@@ -1,128 +0,0 @@
import {EditorView} from '@codemirror/view'
import {Extension} from '@codemirror/state'
import {HighlightStyle, syntaxHighlighting} from '@codemirror/language'
import {tags as t} from '@lezer/highlight'
export const config = {
name: 'tokyoNightDay',
dark: false,
background: '#e1e2e7',
foreground: '#6a6f8e',
selection: '#8591b840',
cursor: '#3760bf',
dropdownBackground: '#e1e2e7',
dropdownBorder: '#6a6f8e',
activeLine: '#a7aaba22',
lineNumber: '#b3b6cd',
lineNumberActive: '#68709a',
matchingBracket: '#e9e9ec',
keyword: '#9854f1',
storage: '#9854f1',
variable: '#3760bf',
parameter: '#3760bf',
function: '#2e7de9',
string: '#587539',
constant: '#9854f1',
type: '#07879d',
class: '#3760bf',
number: '#b15c00',
comment: '#9da3c2',
heading: '#006a83',
invalid: '#ff3e64',
regexp: '#2e5857',
}
export const tokyoNightDayTheme = EditorView.theme({
'&': {
color: config.foreground,
backgroundColor: config.background,
},
'.cm-content': {caretColor: config.cursor},
'.cm-cursor, .cm-dropCursor': {borderLeftColor: config.cursor},
'&.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground, .cm-selectionBackground, .cm-content ::selection': {backgroundColor: config.selection},
'.cm-panels': {backgroundColor: config.dropdownBackground, color: config.foreground},
'.cm-panels.cm-panels-top': {borderBottom: '2px solid black'},
'.cm-panels.cm-panels-bottom': {borderTop: '2px solid black'},
'.cm-searchMatch': {
backgroundColor: config.dropdownBackground,
outline: `1px solid ${config.dropdownBorder}`
},
'.cm-searchMatch.cm-searchMatch-selected': {
backgroundColor: config.selection
},
'.cm-activeLine': {backgroundColor: config.activeLine},
'.cm-selectionMatch': {backgroundColor: config.selection},
'&.cm-focused .cm-matchingBracket, &.cm-focused .cm-nonmatchingBracket': {
backgroundColor: config.matchingBracket,
outline: 'none'
},
'.cm-gutters': {
backgroundColor: config.background,
color: config.foreground,
border: 'none'
},
'.cm-activeLineGutter': {backgroundColor: config.background},
'.cm-lineNumbers .cm-gutterElement': {color: config.lineNumber},
'.cm-lineNumbers .cm-activeLineGutter': {color: config.lineNumberActive},
'.cm-foldPlaceholder': {
backgroundColor: 'transparent',
border: 'none',
color: config.foreground
},
'.cm-tooltip': {
border: `1px solid ${config.dropdownBorder}`,
backgroundColor: config.dropdownBackground,
color: config.foreground,
},
'.cm-tooltip .cm-tooltip-arrow:before': {
borderTopColor: 'transparent',
borderBottomColor: 'transparent'
},
'.cm-tooltip .cm-tooltip-arrow:after': {
borderTopColor: config.foreground,
borderBottomColor: config.foreground,
},
'.cm-tooltip-autocomplete': {
'& > ul > li[aria-selected]': {
background: config.selection,
color: config.foreground,
}
}
}, {dark: config.dark})
export const tokyoNightDayHighlightStyle = HighlightStyle.define([
{tag: t.keyword, color: config.keyword},
{tag: [t.name, t.deleted, t.character, t.macroName], color: config.variable},
{tag: [t.propertyName], color: config.function},
{tag: [t.processingInstruction, t.string, t.inserted, t.special(t.string)], color: config.string},
{tag: [t.function(t.variableName), t.labelName], color: config.function},
{tag: [t.color, t.constant(t.name), t.standard(t.name)], color: config.constant},
{tag: [t.definition(t.name), t.separator], color: config.variable},
{tag: [t.className], color: config.class},
{tag: [t.number, t.changed, t.annotation, t.modifier, t.self, t.namespace], color: config.number},
{tag: [t.typeName], color: config.type, fontStyle: config.type},
{tag: [t.operator, t.operatorKeyword], color: config.keyword},
{tag: [t.url, t.escape, t.regexp, t.link], color: config.regexp},
{tag: [t.meta, t.comment], color: config.comment},
{tag: t.strong, fontWeight: 'bold'},
{tag: t.emphasis, fontStyle: 'italic'},
{tag: t.link, textDecoration: 'underline'},
{tag: t.heading, fontWeight: 'bold', color: config.heading},
{tag: [t.atom, t.bool, t.special(t.variableName)], color: config.variable},
{tag: t.invalid, color: config.invalid},
{tag: t.strikethrough, textDecoration: 'line-through'},
])
export const tokyoNightDay: Extension = [
tokyoNightDayTheme,
syntaxHighlighting(tokyoNightDayHighlightStyle),
]

View File

@@ -1,128 +0,0 @@
import {EditorView} from '@codemirror/view'
import {Extension} from '@codemirror/state'
import {HighlightStyle, syntaxHighlighting} from '@codemirror/language'
import {tags as t} from '@lezer/highlight'
export const config = {
name: 'tokyoNightStorm',
dark: true,
background: '#24283b',
foreground: '#7982a9',
selection: '#6f7bb630',
cursor: '#c0caf5',
dropdownBackground: '#24283b',
dropdownBorder: '#7982a9',
activeLine: '#4d547722',
lineNumber: '#3b4261',
lineNumberActive: '#737aa2',
matchingBracket: '#1f2335',
keyword: '#bb9af7',
storage: '#bb9af7',
variable: '#c0caf5',
parameter: '#c0caf5',
function: '#7aa2f7',
string: '#9ece6a',
constant: '#bb9af7',
type: '#2ac3de',
class: '#c0caf5',
number: '#ff9e64',
comment: '#565f89',
heading: '#89ddff',
invalid: '#ff5370',
regexp: '#b4f9f8',
}
export const tokyoNightStormTheme = EditorView.theme({
'&': {
color: config.foreground,
backgroundColor: config.background,
},
'.cm-content': {caretColor: config.cursor},
'.cm-cursor, .cm-dropCursor': {borderLeftColor: config.cursor},
'&.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground, .cm-selectionBackground, .cm-content ::selection': {backgroundColor: config.selection},
'.cm-panels': {backgroundColor: config.dropdownBackground, color: config.foreground},
'.cm-panels.cm-panels-top': {borderBottom: '2px solid black'},
'.cm-panels.cm-panels-bottom': {borderTop: '2px solid black'},
'.cm-searchMatch': {
backgroundColor: config.dropdownBackground,
outline: `1px solid ${config.dropdownBorder}`
},
'.cm-searchMatch.cm-searchMatch-selected': {
backgroundColor: config.selection
},
'.cm-activeLine': {backgroundColor: config.activeLine},
'.cm-selectionMatch': {backgroundColor: config.selection},
'&.cm-focused .cm-matchingBracket, &.cm-focused .cm-nonmatchingBracket': {
backgroundColor: config.matchingBracket,
outline: 'none'
},
'.cm-gutters': {
backgroundColor: config.background,
color: config.foreground,
border: 'none'
},
'.cm-activeLineGutter': {backgroundColor: config.background},
'.cm-lineNumbers .cm-gutterElement': {color: config.lineNumber},
'.cm-lineNumbers .cm-activeLineGutter': {color: config.lineNumberActive},
'.cm-foldPlaceholder': {
backgroundColor: 'transparent',
border: 'none',
color: config.foreground
},
'.cm-tooltip': {
border: `1px solid ${config.dropdownBorder}`,
backgroundColor: config.dropdownBackground,
color: config.foreground,
},
'.cm-tooltip .cm-tooltip-arrow:before': {
borderTopColor: 'transparent',
borderBottomColor: 'transparent'
},
'.cm-tooltip .cm-tooltip-arrow:after': {
borderTopColor: config.foreground,
borderBottomColor: config.foreground,
},
'.cm-tooltip-autocomplete': {
'& > ul > li[aria-selected]': {
background: config.selection,
color: config.foreground,
}
}
}, {dark: config.dark})
export const tokyoNightStormHighlightStyle = HighlightStyle.define([
{tag: t.keyword, color: config.keyword},
{tag: [t.name, t.deleted, t.character, t.macroName], color: config.variable},
{tag: [t.propertyName], color: config.function},
{tag: [t.processingInstruction, t.string, t.inserted, t.special(t.string)], color: config.string},
{tag: [t.function(t.variableName), t.labelName], color: config.function},
{tag: [t.color, t.constant(t.name), t.standard(t.name)], color: config.constant},
{tag: [t.definition(t.name), t.separator], color: config.variable},
{tag: [t.className], color: config.class},
{tag: [t.number, t.changed, t.annotation, t.modifier, t.self, t.namespace], color: config.number},
{tag: [t.typeName], color: config.type, fontStyle: config.type},
{tag: [t.operator, t.operatorKeyword], color: config.keyword},
{tag: [t.url, t.escape, t.regexp, t.link], color: config.regexp},
{tag: [t.meta, t.comment], color: config.comment},
{tag: t.strong, fontWeight: 'bold'},
{tag: t.emphasis, fontStyle: 'italic'},
{tag: t.link, textDecoration: 'underline'},
{tag: t.heading, fontWeight: 'bold', color: config.heading},
{tag: [t.atom, t.bool, t.special(t.variableName)], color: config.variable},
{tag: t.invalid, color: config.invalid},
{tag: t.strikethrough, textDecoration: 'line-through'},
])
export const tokyoNightStorm: Extension = [
tokyoNightStormTheme,
syntaxHighlighting(tokyoNightStormHighlightStyle),
]

View File

@@ -1,128 +0,0 @@
import {EditorView} from '@codemirror/view'
import {Extension} from '@codemirror/state'
import {HighlightStyle, syntaxHighlighting} from '@codemirror/language'
import {tags as t} from '@lezer/highlight'
export const config = {
name: 'tokyoNight',
dark: true,
background: '#1a1b26',
foreground: '#787c99',
selection: '#515c7e40',
cursor: '#c0caf5',
dropdownBackground: '#1a1b26',
dropdownBorder: '#787c99',
activeLine: '#43455c22',
lineNumber: '#363b54',
lineNumberActive: '#737aa2',
matchingBracket: '#16161e',
keyword: '#bb9af7',
storage: '#bb9af7',
variable: '#c0caf5',
parameter: '#c0caf5',
function: '#7aa2f7',
string: '#9ece6a',
constant: '#bb9af7',
type: '#0db9d7',
class: '#c0caf5',
number: '#ff9e64',
comment: '#444b6a',
heading: '#89ddff',
invalid: '#ff5370',
regexp: '#b4f9f8',
}
export const tokyoNightTheme = EditorView.theme({
'&': {
color: config.foreground,
backgroundColor: config.background,
},
'.cm-content': {caretColor: config.cursor},
'.cm-cursor, .cm-dropCursor': {borderLeftColor: config.cursor},
'&.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground, .cm-selectionBackground, .cm-content ::selection': {backgroundColor: config.selection},
'.cm-panels': {backgroundColor: config.dropdownBackground, color: config.foreground},
'.cm-panels.cm-panels-top': {borderBottom: '2px solid black'},
'.cm-panels.cm-panels-bottom': {borderTop: '2px solid black'},
'.cm-searchMatch': {
backgroundColor: config.dropdownBackground,
outline: `1px solid ${config.dropdownBorder}`
},
'.cm-searchMatch.cm-searchMatch-selected': {
backgroundColor: config.selection
},
'.cm-activeLine': {backgroundColor: config.activeLine},
'.cm-selectionMatch': {backgroundColor: config.selection},
'&.cm-focused .cm-matchingBracket, &.cm-focused .cm-nonmatchingBracket': {
backgroundColor: config.matchingBracket,
outline: 'none'
},
'.cm-gutters': {
backgroundColor: config.background,
color: config.foreground,
border: 'none'
},
'.cm-activeLineGutter': {backgroundColor: config.background},
'.cm-lineNumbers .cm-gutterElement': {color: config.lineNumber},
'.cm-lineNumbers .cm-activeLineGutter': {color: config.lineNumberActive},
'.cm-foldPlaceholder': {
backgroundColor: 'transparent',
border: 'none',
color: config.foreground
},
'.cm-tooltip': {
border: `1px solid ${config.dropdownBorder}`,
backgroundColor: config.dropdownBackground,
color: config.foreground,
},
'.cm-tooltip .cm-tooltip-arrow:before': {
borderTopColor: 'transparent',
borderBottomColor: 'transparent'
},
'.cm-tooltip .cm-tooltip-arrow:after': {
borderTopColor: config.foreground,
borderBottomColor: config.foreground,
},
'.cm-tooltip-autocomplete': {
'& > ul > li[aria-selected]': {
background: config.selection,
color: config.foreground,
}
}
}, {dark: config.dark})
export const tokyoNightHighlightStyle = HighlightStyle.define([
{tag: t.keyword, color: config.keyword},
{tag: [t.name, t.deleted, t.character, t.macroName], color: config.variable},
{tag: [t.propertyName], color: config.function},
{tag: [t.processingInstruction, t.string, t.inserted, t.special(t.string)], color: config.string},
{tag: [t.function(t.variableName), t.labelName], color: config.function},
{tag: [t.color, t.constant(t.name), t.standard(t.name)], color: config.constant},
{tag: [t.definition(t.name), t.separator], color: config.variable},
{tag: [t.className], color: config.class},
{tag: [t.number, t.changed, t.annotation, t.modifier, t.self, t.namespace], color: config.number},
{tag: [t.typeName], color: config.type, fontStyle: config.type},
{tag: [t.operator, t.operatorKeyword], color: config.keyword},
{tag: [t.url, t.escape, t.regexp, t.link], color: config.regexp},
{tag: [t.meta, t.comment], color: config.comment},
{tag: t.strong, fontWeight: 'bold'},
{tag: t.emphasis, fontStyle: 'italic'},
{tag: t.link, textDecoration: 'underline'},
{tag: t.heading, fontWeight: 'bold', color: config.heading},
{tag: [t.atom, t.bool, t.special(t.variableName)], color: config.variable},
{tag: t.invalid, color: config.invalid},
{tag: t.strikethrough, textDecoration: 'line-through'},
])
export const tokyoNight: Extension = [
tokyoNightTheme,
syntaxHighlighting(tokyoNightHighlightStyle),
]

View File

@@ -1,19 +1,16 @@
<script setup lang="ts">
import { useConfigStore } from '@/stores/configStore';
import { useThemeStore } from '@/stores/themeStore';
import { useErrorHandler } from '@/utils/errorHandler';
import { useI18n } from 'vue-i18n';
import { ref, computed, watch } from 'vue';
import SettingSection from '../components/SettingSection.vue';
import SettingItem from '../components/SettingItem.vue';
import type { ThemeType, SystemThemeType } from '@/types';
import { LanguageType } from '@/../bindings/voidraft/internal/models';
import { AVAILABLE_THEMES } from '@/types/theme';
import { useTheme } from '@/composables/useTheme';
import { SystemThemeType, LanguageType } from '@/../bindings/voidraft/internal/models/models';
const { t } = useI18n();
const configStore = useConfigStore();
const themeStore = useThemeStore();
const { safeCall } = useErrorHandler();
const { setTheme: setThemeComposable } = useTheme();
// 语言选项
const languageOptions = [
@@ -23,9 +20,9 @@ const languageOptions = [
// 系统主题选项
const systemThemeOptions = [
{ value: 'dark' as SystemThemeType, label: t('systemTheme.dark') },
{ value: 'light' as SystemThemeType, label: t('systemTheme.light') },
{ value: 'auto' as SystemThemeType, label: t('systemTheme.auto') },
{ value: SystemThemeType.SystemThemeDark, label: t('systemTheme.dark') },
{ value: SystemThemeType.SystemThemeLight, label: t('systemTheme.light') },
{ value: SystemThemeType.SystemThemeAuto, label: t('systemTheme.auto') },
];
// 更新语言设置
@@ -45,42 +42,10 @@ const updateSystemTheme = async (event: Event) => {
const selectedSystemTheme = select.value as SystemThemeType;
await safeCall(
() => configStore.setSystemTheme(selectedSystemTheme),
() => themeStore.setTheme(selectedSystemTheme),
'config.systemThemeChangeFailed'
);
};
// 主题选择
const themeOptions = computed(() => AVAILABLE_THEMES);
const selectedTheme = ref<ThemeType>(configStore.config.appearance.theme || 'default-dark' as ThemeType);
// 当前主题预览信息
const currentPreviewTheme = computed(() => {
const theme = themeOptions.value.find(t => t.id === selectedTheme.value);
return theme || themeOptions.value[0];
});
// 选择主题
const selectTheme = async (themeId: ThemeType) => {
selectedTheme.value = themeId;
// 更新配置(这会自动触发编辑器主题更新)
await safeCall(
() => configStore.setTheme(themeId),
'config.themeChangeFailed'
);
// 同步更新预览(用于设置页面的预览区域)
await setThemeComposable(themeId);
};
// 监听配置变化,同步主题选择
watch(() => configStore.config.appearance.theme, (newTheme) => {
if (newTheme && newTheme !== selectedTheme.value) {
selectedTheme.value = newTheme;
setThemeComposable(newTheme);
}
}, { immediate: true });
</script>
<template>
@@ -104,64 +69,6 @@ watch(() => configStore.config.appearance.theme, (newTheme) => {
</select>
</SettingItem>
</SettingSection>
<SettingSection :title="t('settings.appearance')">
<div class="appearance-content">
<div class="theme-selection-area">
<div class="theme-selector">
<div class="selector-label">{{ t('settings.theme') }}</div>
<div class="theme-options">
<div
v-for="theme in themeOptions"
:key="theme.id"
class="theme-option"
:class="{ active: selectedTheme === theme.id }"
@click="selectTheme(theme.id)"
>
<div class="color-preview" :style="{ backgroundColor: theme.previewColors.background }"></div>
<div class="theme-name">{{ theme.displayName }}</div>
</div>
</div>
</div>
</div>
<div class="preview-area">
<div class="editor-preview" :style="{ backgroundColor: currentPreviewTheme.previewColors.background }">
<div class="preview-header" :style="{ backgroundColor: currentPreviewTheme.previewColors.background, borderBottomColor: currentPreviewTheme.previewColors.foreground + '33' }">
<div class="preview-title" :style="{ color: currentPreviewTheme.previewColors.foreground }">{{ currentPreviewTheme.displayName }} 预览</div>
</div>
<div class="preview-content" :style="{ color: currentPreviewTheme.previewColors.foreground }">
<div class="preview-line">
<span class="line-number" :style="{ color: currentPreviewTheme.previewColors.comment }">1</span>
<span class="keyword" :style="{ color: currentPreviewTheme.previewColors.keyword }">function</span>
<span>&nbsp;</span>
<span class="function" :style="{ color: currentPreviewTheme.previewColors.function }">exampleFunc</span>() {
</div>
<div class="preview-line">
<span class="line-number" :style="{ color: currentPreviewTheme.previewColors.comment }">2</span>
<span>&nbsp;&nbsp;</span>
<span class="keyword" :style="{ color: currentPreviewTheme.previewColors.keyword }">const</span>
<span> hello = </span>
<span class="string" :style="{ color: currentPreviewTheme.previewColors.string }">"你好,世界!"</span>;
</div>
<div class="preview-line">
<span class="line-number" :style="{ color: currentPreviewTheme.previewColors.comment }">3</span>
<span>&nbsp;&nbsp;</span>
<span class="function" :style="{ color: currentPreviewTheme.previewColors.function }">console.log</span>(hello);
</div>
<div class="preview-line">
<span class="line-number" :style="{ color: currentPreviewTheme.previewColors.comment }">4</span>
<span>&nbsp;&nbsp;</span>
<span class="comment" :style="{ color: currentPreviewTheme.previewColors.comment }">// 这是中文注释</span>
</div>
<div class="preview-line">
<span class="line-number" :style="{ color: currentPreviewTheme.previewColors.comment }">5</span>}
</div>
</div>
</div>
</div>
</div>
</SettingSection>
</div>
</template>
@@ -171,30 +78,6 @@ watch(() => configStore.config.appearance.theme, (newTheme) => {
padding-bottom: 48px;
}
.appearance-content {
display: flex;
flex-direction: column;
gap: 24px;
@media (min-width: 768px) {
flex-direction: row;
gap: 32px;
}
}
.theme-selection-area {
flex: 1;
min-width: 0;
}
.preview-area {
flex: 0 0 400px;
@media (max-width: 767px) {
flex: none;
}
}
.select-input {
min-width: 150px;
padding: 8px 12px;
@@ -221,158 +104,4 @@ watch(() => configStore.config.appearance.theme, (newTheme) => {
color: var(--settings-text);
}
}
.theme-selector {
padding: 0;
.selector-label {
font-size: 14px;
font-weight: 500;
margin-bottom: 15px;
color: #e0e0e0;
}
.theme-options {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
gap: 16px;
justify-content: start;
.theme-option {
cursor: pointer;
transition: all 0.2s ease;
.color-preview {
height: 70px;
border-radius: 6px;
border: 2px solid transparent;
transition: all 0.2s ease;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.3);
position: relative;
&::before {
content: '';
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 16px;
height: 16px;
border-radius: 50%;
background: rgba(255, 255, 255, 0.1);
opacity: 0;
transition: opacity 0.2s ease;
}
}
.theme-name {
margin-top: 8px;
font-size: 13px;
text-align: center;
color: #c0c0c0;
font-weight: 500;
}
&:hover {
transform: translateY(-2px);
.color-preview {
border-color: rgba(255, 255, 255, 0.4);
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.4);
&::before {
opacity: 1;
}
}
}
&.active {
.color-preview {
border-color: #4a9eff;
box-shadow: 0 4px 20px rgba(74, 158, 255, 0.3);
&::after {
content: '✓';
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
color: #4a9eff;
font-size: 18px;
font-weight: bold;
text-shadow: 0 0 4px rgba(74, 158, 255, 0.8);
}
}
.theme-name {
color: #4a9eff;
font-weight: 600;
}
}
}
}
}
.editor-preview {
border-radius: 8px;
overflow: hidden;
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.3);
border: 1px solid rgba(255, 255, 255, 0.1);
width: 100%;
max-width: 400px;
.preview-header {
padding: 12px 16px;
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
.preview-title {
font-size: 14px;
font-weight: 600;
display: flex;
align-items: center;
gap: 8px;
&::before {
content: '🎨';
font-size: 16px;
}
}
}
.preview-content {
padding: 16px 0;
font-family: 'JetBrains Mono', 'Fira Code', 'Consolas', 'Courier New', monospace;
font-size: 13px;
line-height: 1.6;
.preview-line {
padding: 2px 16px;
transition: background-color 0.2s ease;
&:hover {
background-color: rgba(255, 255, 255, 0.05);
}
.line-number {
display: inline-block;
width: 24px;
margin-right: 12px;
text-align: right;
user-select: none;
font-size: 12px;
opacity: 0.7;
}
}
}
}
.coming-soon-placeholder {
padding: 20px;
background-color: #333333;
border-radius: 6px;
color: #a0a0a0;
text-align: center;
font-style: italic;
font-size: 14px;
}
</style>