✨ Added preset theme
This commit is contained in:
@@ -1191,9 +1191,20 @@ export class Theme {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ThemeColorConfig 主题颜色配置
|
* ThemeColorConfig 主题颜色配置(与前端 ThemeColors 接口保持一致)
|
||||||
*/
|
*/
|
||||||
export class ThemeColorConfig {
|
export class ThemeColorConfig {
|
||||||
|
/**
|
||||||
|
* 主题基本信息
|
||||||
|
* 主题名称
|
||||||
|
*/
|
||||||
|
"name": string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否为深色主题
|
||||||
|
*/
|
||||||
|
"dark": boolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 基础色调
|
* 基础色调
|
||||||
* 主背景色
|
* 主背景色
|
||||||
@@ -1201,7 +1212,7 @@ export class ThemeColorConfig {
|
|||||||
"background": string;
|
"background": string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 次要背景色
|
* 次要背景色(用于代码块交替背景)
|
||||||
*/
|
*/
|
||||||
"backgroundSecondary": string;
|
"backgroundSecondary": string;
|
||||||
|
|
||||||
@@ -1211,6 +1222,17 @@ export class ThemeColorConfig {
|
|||||||
"surface": string;
|
"surface": string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* 下拉菜单背景
|
||||||
|
*/
|
||||||
|
"dropdownBackground": string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 下拉菜单边框
|
||||||
|
*/
|
||||||
|
"dropdownBorder": string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文本颜色
|
||||||
* 主文本色
|
* 主文本色
|
||||||
*/
|
*/
|
||||||
"foreground": string;
|
"foreground": string;
|
||||||
@@ -1221,12 +1243,12 @@ export class ThemeColorConfig {
|
|||||||
"foregroundSecondary": string;
|
"foregroundSecondary": string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 语法高亮
|
|
||||||
* 注释色
|
* 注释色
|
||||||
*/
|
*/
|
||||||
"comment": string;
|
"comment": string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* 语法高亮色 - 核心
|
||||||
* 关键字
|
* 关键字
|
||||||
*/
|
*/
|
||||||
"keyword": string;
|
"keyword": string;
|
||||||
@@ -1261,6 +1283,42 @@ export class ThemeColorConfig {
|
|||||||
*/
|
*/
|
||||||
"type": string;
|
"type": string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 语法高亮色 - 扩展
|
||||||
|
* 常量
|
||||||
|
*/
|
||||||
|
"constant": string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 存储类型(如 static, const)
|
||||||
|
*/
|
||||||
|
"storage": string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 参数
|
||||||
|
*/
|
||||||
|
"parameter": string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 类名
|
||||||
|
*/
|
||||||
|
"class": string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 标题(Markdown等)
|
||||||
|
*/
|
||||||
|
"heading": string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 无效内容/错误
|
||||||
|
*/
|
||||||
|
"invalid": string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 正则表达式
|
||||||
|
*/
|
||||||
|
"regexp": string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 界面元素
|
* 界面元素
|
||||||
* 光标
|
* 光标
|
||||||
@@ -1288,12 +1346,12 @@ export class ThemeColorConfig {
|
|||||||
"lineNumber": string;
|
"lineNumber": string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 活动行号
|
* 活动行号颜色
|
||||||
*/
|
*/
|
||||||
"activeLineNumber": string;
|
"activeLineNumber": string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 边框分割线
|
* 边框和分割线
|
||||||
* 边框色
|
* 边框色
|
||||||
*/
|
*/
|
||||||
"borderColor": string;
|
"borderColor": string;
|
||||||
@@ -1304,7 +1362,7 @@ export class ThemeColorConfig {
|
|||||||
"borderLight": string;
|
"borderLight": string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 搜索匹配
|
* 搜索和匹配
|
||||||
* 搜索匹配
|
* 搜索匹配
|
||||||
*/
|
*/
|
||||||
"searchMatch": string;
|
"searchMatch": string;
|
||||||
@@ -1316,6 +1374,12 @@ export class ThemeColorConfig {
|
|||||||
|
|
||||||
/** Creates a new ThemeColorConfig instance. */
|
/** Creates a new ThemeColorConfig instance. */
|
||||||
constructor($$source: Partial<ThemeColorConfig> = {}) {
|
constructor($$source: Partial<ThemeColorConfig> = {}) {
|
||||||
|
if (!("name" in $$source)) {
|
||||||
|
this["name"] = "";
|
||||||
|
}
|
||||||
|
if (!("dark" in $$source)) {
|
||||||
|
this["dark"] = false;
|
||||||
|
}
|
||||||
if (!("background" in $$source)) {
|
if (!("background" in $$source)) {
|
||||||
this["background"] = "";
|
this["background"] = "";
|
||||||
}
|
}
|
||||||
@@ -1325,6 +1389,12 @@ export class ThemeColorConfig {
|
|||||||
if (!("surface" in $$source)) {
|
if (!("surface" in $$source)) {
|
||||||
this["surface"] = "";
|
this["surface"] = "";
|
||||||
}
|
}
|
||||||
|
if (!("dropdownBackground" in $$source)) {
|
||||||
|
this["dropdownBackground"] = "";
|
||||||
|
}
|
||||||
|
if (!("dropdownBorder" in $$source)) {
|
||||||
|
this["dropdownBorder"] = "";
|
||||||
|
}
|
||||||
if (!("foreground" in $$source)) {
|
if (!("foreground" in $$source)) {
|
||||||
this["foreground"] = "";
|
this["foreground"] = "";
|
||||||
}
|
}
|
||||||
@@ -1355,6 +1425,27 @@ export class ThemeColorConfig {
|
|||||||
if (!("type" in $$source)) {
|
if (!("type" in $$source)) {
|
||||||
this["type"] = "";
|
this["type"] = "";
|
||||||
}
|
}
|
||||||
|
if (!("constant" in $$source)) {
|
||||||
|
this["constant"] = "";
|
||||||
|
}
|
||||||
|
if (!("storage" in $$source)) {
|
||||||
|
this["storage"] = "";
|
||||||
|
}
|
||||||
|
if (!("parameter" in $$source)) {
|
||||||
|
this["parameter"] = "";
|
||||||
|
}
|
||||||
|
if (!("class" in $$source)) {
|
||||||
|
this["class"] = "";
|
||||||
|
}
|
||||||
|
if (!("heading" in $$source)) {
|
||||||
|
this["heading"] = "";
|
||||||
|
}
|
||||||
|
if (!("invalid" in $$source)) {
|
||||||
|
this["invalid"] = "";
|
||||||
|
}
|
||||||
|
if (!("regexp" in $$source)) {
|
||||||
|
this["regexp"] = "";
|
||||||
|
}
|
||||||
if (!("cursor" in $$source)) {
|
if (!("cursor" in $$source)) {
|
||||||
this["cursor"] = "";
|
this["cursor"] = "";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,12 +42,12 @@ export function GetAllThemes(): Promise<(models$0.Theme | null)[]> & { cancel():
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GetDefaultThemes 获取默认主题
|
* GetThemeByID 根据ID获取主题
|
||||||
*/
|
*/
|
||||||
export function GetDefaultThemes(): Promise<{ [_: string]: models$0.Theme | null }> & { cancel(): void } {
|
export function GetThemeByID(id: number): Promise<models$0.Theme | null> & { cancel(): void } {
|
||||||
let $resultPromise = $Call.ByID(3801788118) as any;
|
let $resultPromise = $Call.ByID(3053137052, id) as any;
|
||||||
let $typingPromise = $resultPromise.then(($result: any) => {
|
let $typingPromise = $resultPromise.then(($result: any) => {
|
||||||
return $$createType3($result);
|
return $$createType1($result);
|
||||||
}) as any;
|
}) as any;
|
||||||
$typingPromise.cancel = $resultPromise.cancel.bind($resultPromise);
|
$typingPromise.cancel = $resultPromise.cancel.bind($resultPromise);
|
||||||
return $typingPromise;
|
return $typingPromise;
|
||||||
@@ -66,10 +66,22 @@ export function GetThemeByType(themeType: models$0.ThemeType): Promise<models$0.
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ResetThemeColors 重置主题颜色为默认值
|
* GetThemesByType 根据类型获取所有主题
|
||||||
*/
|
*/
|
||||||
export function ResetThemeColors(themeType: models$0.ThemeType): Promise<void> & { cancel(): void } {
|
export function GetThemesByType(themeType: models$0.ThemeType): Promise<(models$0.Theme | null)[]> & { cancel(): void } {
|
||||||
let $resultPromise = $Call.ByID(342461245, themeType) as any;
|
let $resultPromise = $Call.ByID(1478417492, themeType) as any;
|
||||||
|
let $typingPromise = $resultPromise.then(($result: any) => {
|
||||||
|
return $$createType2($result);
|
||||||
|
}) as any;
|
||||||
|
$typingPromise.cancel = $resultPromise.cancel.bind($resultPromise);
|
||||||
|
return $typingPromise;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ResetTheme 重置主题为预设配置
|
||||||
|
*/
|
||||||
|
export function ResetTheme(id: number): Promise<void> & { cancel(): void } {
|
||||||
|
let $resultPromise = $Call.ByID(1806334457, id) as any;
|
||||||
return $resultPromise;
|
return $resultPromise;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,10 +102,10 @@ export function ServiceStartup(options: application$0.ServiceOptions): Promise<v
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* UpdateThemeColors 更新主题颜色
|
* UpdateTheme 更新主题
|
||||||
*/
|
*/
|
||||||
export function UpdateThemeColors(themeType: models$0.ThemeType, colors: models$0.ThemeColorConfig): Promise<void> & { cancel(): void } {
|
export function UpdateTheme(id: number, colors: models$0.ThemeColorConfig): Promise<void> & { cancel(): void } {
|
||||||
let $resultPromise = $Call.ByID(2750902529, themeType, colors) as any;
|
let $resultPromise = $Call.ByID(70189749, id, colors) as any;
|
||||||
return $resultPromise;
|
return $resultPromise;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,4 +113,3 @@ export function UpdateThemeColors(themeType: models$0.ThemeType, colors: models$
|
|||||||
const $$createType0 = models$0.Theme.createFrom;
|
const $$createType0 = models$0.Theme.createFrom;
|
||||||
const $$createType1 = $Create.Nullable($$createType0);
|
const $$createType1 = $Create.Nullable($$createType0);
|
||||||
const $$createType2 = $Create.Array($$createType1);
|
const $$createType2 = $Create.Array($$createType1);
|
||||||
const $$createType3 = $Create.Map($Create.Any, $$createType1);
|
|
||||||
|
|||||||
225
frontend/package-lock.json
generated
225
frontend/package-lock.json
generated
@@ -36,9 +36,9 @@
|
|||||||
"@codemirror/lint": "^6.9.0",
|
"@codemirror/lint": "^6.9.0",
|
||||||
"@codemirror/search": "^6.5.11",
|
"@codemirror/search": "^6.5.11",
|
||||||
"@codemirror/state": "^6.5.2",
|
"@codemirror/state": "^6.5.2",
|
||||||
"@codemirror/view": "^6.38.5",
|
"@codemirror/view": "^6.38.6",
|
||||||
"@cospaia/prettier-plugin-clojure": "^0.0.2",
|
"@cospaia/prettier-plugin-clojure": "^0.0.2",
|
||||||
"@lezer/highlight": "^1.2.1",
|
"@lezer/highlight": "^1.2.2",
|
||||||
"@lezer/lr": "^1.4.2",
|
"@lezer/lr": "^1.4.2",
|
||||||
"@prettier/plugin-xml": "^3.4.2",
|
"@prettier/plugin-xml": "^3.4.2",
|
||||||
"@replit/codemirror-lang-svelte": "^6.0.0",
|
"@replit/codemirror-lang-svelte": "^6.0.0",
|
||||||
@@ -62,23 +62,23 @@
|
|||||||
"vue": "^3.5.22",
|
"vue": "^3.5.22",
|
||||||
"vue-i18n": "^11.1.12",
|
"vue-i18n": "^11.1.12",
|
||||||
"vue-pick-colors": "^1.8.0",
|
"vue-pick-colors": "^1.8.0",
|
||||||
"vue-router": "^4.5.1"
|
"vue-router": "^4.6.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/js": "^9.37.0",
|
"@eslint/js": "^9.38.0",
|
||||||
"@lezer/generator": "^1.8.0",
|
"@lezer/generator": "^1.8.0",
|
||||||
"@types/node": "^24.7.1",
|
"@types/node": "^24.8.1",
|
||||||
"@types/remarkable": "^2.0.8",
|
"@types/remarkable": "^2.0.8",
|
||||||
"@vitejs/plugin-vue": "^6.0.1",
|
"@vitejs/plugin-vue": "^6.0.1",
|
||||||
"@wailsio/runtime": "latest",
|
"@wailsio/runtime": "latest",
|
||||||
"cross-env": "^10.1.0",
|
"cross-env": "^10.1.0",
|
||||||
"eslint": "^9.37.0",
|
"eslint": "^9.38.0",
|
||||||
"eslint-plugin-vue": "^10.5.0",
|
"eslint-plugin-vue": "^10.5.1",
|
||||||
"globals": "^16.4.0",
|
"globals": "^16.4.0",
|
||||||
"typescript": "^5.9.3",
|
"typescript": "^5.9.3",
|
||||||
"typescript-eslint": "^8.46.0",
|
"typescript-eslint": "^8.46.1",
|
||||||
"unplugin-vue-components": "^29.1.0",
|
"unplugin-vue-components": "^29.1.0",
|
||||||
"vite": "^7.1.9",
|
"vite": "^7.1.10",
|
||||||
"vite-plugin-node-polyfills": "^0.24.0",
|
"vite-plugin-node-polyfills": "^0.24.0",
|
||||||
"vue-eslint-parser": "^10.2.0",
|
"vue-eslint-parser": "^10.2.0",
|
||||||
"vue-tsc": "^3.1.1"
|
"vue-tsc": "^3.1.1"
|
||||||
@@ -554,9 +554,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@codemirror/view": {
|
"node_modules/@codemirror/view": {
|
||||||
"version": "6.38.5",
|
"version": "6.38.6",
|
||||||
"resolved": "https://registry.npmmirror.com/@codemirror/view/-/view-6.38.5.tgz",
|
"resolved": "https://registry.npmmirror.com/@codemirror/view/-/view-6.38.6.tgz",
|
||||||
"integrity": "sha512-SFVsNAgsAoou+BjRewMqN+m9jaztB9wCWN9RSRgePqUbq8UVlvJfku5zB2KVhLPgH/h0RLk38tvd4tGeAhygnw==",
|
"integrity": "sha512-qiS0z1bKs5WOvHIAC0Cybmv4AJSkAXgX5aD6Mqd2epSLlVJsQl8NG23jCVouIgkh4All/mrbdsf2UOLFnJw0tw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/state": "^6.5.0",
|
"@codemirror/state": "^6.5.0",
|
||||||
@@ -1046,13 +1046,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@eslint/config-array": {
|
"node_modules/@eslint/config-array": {
|
||||||
"version": "0.21.0",
|
"version": "0.21.1",
|
||||||
"resolved": "https://registry.npmmirror.com/@eslint/config-array/-/config-array-0.21.0.tgz",
|
"resolved": "https://registry.npmmirror.com/@eslint/config-array/-/config-array-0.21.1.tgz",
|
||||||
"integrity": "sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ==",
|
"integrity": "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint/object-schema": "^2.1.6",
|
"@eslint/object-schema": "^2.1.7",
|
||||||
"debug": "^4.3.1",
|
"debug": "^4.3.1",
|
||||||
"minimatch": "^3.1.2"
|
"minimatch": "^3.1.2"
|
||||||
},
|
},
|
||||||
@@ -1061,9 +1061,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@eslint/config-helpers": {
|
"node_modules/@eslint/config-helpers": {
|
||||||
"version": "0.4.0",
|
"version": "0.4.1",
|
||||||
"resolved": "https://registry.npmmirror.com/@eslint/config-helpers/-/config-helpers-0.4.0.tgz",
|
"resolved": "https://registry.npmmirror.com/@eslint/config-helpers/-/config-helpers-0.4.1.tgz",
|
||||||
"integrity": "sha512-WUFvV4WoIwW8Bv0KeKCIIEgdSiFOsulyN0xrMu+7z43q/hkOLXjvb5u7UC9jDxvRzcrbEmuZBX5yJZz1741jog==",
|
"integrity": "sha512-csZAzkNhsgwb0I/UAV6/RGFTbiakPCf0ZrGmrIxQpYvGZ00PhTkSnyKNolphgIvmnJeGw6rcGVEXfTzUnFuEvw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -1124,9 +1124,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@eslint/js": {
|
"node_modules/@eslint/js": {
|
||||||
"version": "9.37.0",
|
"version": "9.38.0",
|
||||||
"resolved": "https://registry.npmmirror.com/@eslint/js/-/js-9.37.0.tgz",
|
"resolved": "https://registry.npmmirror.com/@eslint/js/-/js-9.38.0.tgz",
|
||||||
"integrity": "sha512-jaS+NJ+hximswBG6pjNX0uEJZkrT0zwpVi3BA3vX22aFGjJjmgSTSmPpZCRKmoBL5VY/M6p0xsSJx7rk7sy5gg==",
|
"integrity": "sha512-UZ1VpFvXf9J06YG9xQBdnzU+kthors6KjhMAl6f4gH4usHyh31rUf2DLGInT8RFYIReYXNSydgPY0V2LuWgl7A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -1137,9 +1137,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@eslint/object-schema": {
|
"node_modules/@eslint/object-schema": {
|
||||||
"version": "2.1.6",
|
"version": "2.1.7",
|
||||||
"resolved": "https://registry.npmmirror.com/@eslint/object-schema/-/object-schema-2.1.6.tgz",
|
"resolved": "https://registry.npmmirror.com/@eslint/object-schema/-/object-schema-2.1.7.tgz",
|
||||||
"integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==",
|
"integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -1320,9 +1320,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@lezer/common": {
|
"node_modules/@lezer/common": {
|
||||||
"version": "1.2.3",
|
"version": "1.3.0",
|
||||||
"resolved": "https://registry.npmmirror.com/@lezer/common/-/common-1.2.3.tgz",
|
"resolved": "https://registry.npmmirror.com/@lezer/common/-/common-1.3.0.tgz",
|
||||||
"integrity": "sha512-w7ojc8ejBqr2REPsWxJjrMFsA/ysDCFICn8zEOR9mrqzOu2amhITYuLD8ag6XZf0CFXDrhKqw7+tW8cX66NaDA==",
|
"integrity": "sha512-L9X8uHCYU310o99L3/MpJKYxPzXPOS7S0NmBaM7UO/x2Kb2WbmMLSkfvdr1KxRIFYOpbY0Jhn7CfLSUDzL8arQ==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@lezer/cpp": {
|
"node_modules/@lezer/cpp": {
|
||||||
@@ -1373,12 +1373,12 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@lezer/highlight": {
|
"node_modules/@lezer/highlight": {
|
||||||
"version": "1.2.1",
|
"version": "1.2.2",
|
||||||
"resolved": "https://registry.npmmirror.com/@lezer/highlight/-/highlight-1.2.1.tgz",
|
"resolved": "https://registry.npmmirror.com/@lezer/highlight/-/highlight-1.2.2.tgz",
|
||||||
"integrity": "sha512-Z5duk4RN/3zuVO7Jq0pGLJ3qynpxUVsh7IbUbGj88+uV2ApSAn6kWg2au3iJb+0Zi7kKtqffIESgNcRXWZWmSA==",
|
"integrity": "sha512-z8TQwaBXXQIvG6i2g3e9cgMwUUXu9Ib7jo2qRRggdhwKpM56Dw3PM3wmexn+EGaaOZ7az0K7sjc3/gcGW7sz7A==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@lezer/common": "^1.0.0"
|
"@lezer/common": "^1.3.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@lezer/html": {
|
"node_modules/@lezer/html": {
|
||||||
@@ -2327,9 +2327,9 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@types/node": {
|
"node_modules/@types/node": {
|
||||||
"version": "24.7.1",
|
"version": "24.8.1",
|
||||||
"resolved": "https://registry.npmmirror.com/@types/node/-/node-24.7.1.tgz",
|
"resolved": "https://registry.npmmirror.com/@types/node/-/node-24.8.1.tgz",
|
||||||
"integrity": "sha512-CmyhGZanP88uuC5GpWU9q+fI61j2SkhO3UGMUdfYRE6Bcy0ccyzn1Rqj9YAB/ZY4kOXmNf0ocah5GtphmLMP6Q==",
|
"integrity": "sha512-alv65KGRadQVfVcG69MuB4IzdYVpRwMG/mq8KWOaoOdyY617P5ivaDiMCGOFDWD2sAn5Q0mR3mRtUOgm99hL9Q==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -2344,17 +2344,17 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/eslint-plugin": {
|
"node_modules/@typescript-eslint/eslint-plugin": {
|
||||||
"version": "8.46.0",
|
"version": "8.46.1",
|
||||||
"resolved": "https://registry.npmmirror.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.46.0.tgz",
|
"resolved": "https://registry.npmmirror.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.46.1.tgz",
|
||||||
"integrity": "sha512-hA8gxBq4ukonVXPy0OKhiaUh/68D0E88GSmtC1iAEnGaieuDi38LhS7jdCHRLi6ErJBNDGCzvh5EnzdPwUc0DA==",
|
"integrity": "sha512-rUsLh8PXmBjdiPY+Emjz9NX2yHvhS11v0SR6xNJkm5GM1MO9ea/1GoDKlHHZGrOJclL/cZ2i/vRUYVtjRhrHVQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint-community/regexpp": "^4.10.0",
|
"@eslint-community/regexpp": "^4.10.0",
|
||||||
"@typescript-eslint/scope-manager": "8.46.0",
|
"@typescript-eslint/scope-manager": "8.46.1",
|
||||||
"@typescript-eslint/type-utils": "8.46.0",
|
"@typescript-eslint/type-utils": "8.46.1",
|
||||||
"@typescript-eslint/utils": "8.46.0",
|
"@typescript-eslint/utils": "8.46.1",
|
||||||
"@typescript-eslint/visitor-keys": "8.46.0",
|
"@typescript-eslint/visitor-keys": "8.46.1",
|
||||||
"graphemer": "^1.4.0",
|
"graphemer": "^1.4.0",
|
||||||
"ignore": "^7.0.0",
|
"ignore": "^7.0.0",
|
||||||
"natural-compare": "^1.4.0",
|
"natural-compare": "^1.4.0",
|
||||||
@@ -2368,7 +2368,7 @@
|
|||||||
"url": "https://opencollective.com/typescript-eslint"
|
"url": "https://opencollective.com/typescript-eslint"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@typescript-eslint/parser": "^8.46.0",
|
"@typescript-eslint/parser": "^8.46.1",
|
||||||
"eslint": "^8.57.0 || ^9.0.0",
|
"eslint": "^8.57.0 || ^9.0.0",
|
||||||
"typescript": ">=4.8.4 <6.0.0"
|
"typescript": ">=4.8.4 <6.0.0"
|
||||||
}
|
}
|
||||||
@@ -2384,16 +2384,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/parser": {
|
"node_modules/@typescript-eslint/parser": {
|
||||||
"version": "8.46.0",
|
"version": "8.46.1",
|
||||||
"resolved": "https://registry.npmmirror.com/@typescript-eslint/parser/-/parser-8.46.0.tgz",
|
"resolved": "https://registry.npmmirror.com/@typescript-eslint/parser/-/parser-8.46.1.tgz",
|
||||||
"integrity": "sha512-n1H6IcDhmmUEG7TNVSspGmiHHutt7iVKtZwRppD7e04wha5MrkV1h3pti9xQLcCMt6YWsncpoT0HMjkH1FNwWQ==",
|
"integrity": "sha512-6JSSaBZmsKvEkbRUkf7Zj7dru/8ZCrJxAqArcLaVMee5907JdtEbKGsZ7zNiIm/UAkpGUkaSMZEXShnN2D1HZA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/scope-manager": "8.46.0",
|
"@typescript-eslint/scope-manager": "8.46.1",
|
||||||
"@typescript-eslint/types": "8.46.0",
|
"@typescript-eslint/types": "8.46.1",
|
||||||
"@typescript-eslint/typescript-estree": "8.46.0",
|
"@typescript-eslint/typescript-estree": "8.46.1",
|
||||||
"@typescript-eslint/visitor-keys": "8.46.0",
|
"@typescript-eslint/visitor-keys": "8.46.1",
|
||||||
"debug": "^4.3.4"
|
"debug": "^4.3.4"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -2409,14 +2409,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/project-service": {
|
"node_modules/@typescript-eslint/project-service": {
|
||||||
"version": "8.46.0",
|
"version": "8.46.1",
|
||||||
"resolved": "https://registry.npmmirror.com/@typescript-eslint/project-service/-/project-service-8.46.0.tgz",
|
"resolved": "https://registry.npmmirror.com/@typescript-eslint/project-service/-/project-service-8.46.1.tgz",
|
||||||
"integrity": "sha512-OEhec0mH+U5Je2NZOeK1AbVCdm0ChyapAyTeXVIYTPXDJ3F07+cu87PPXcGoYqZ7M9YJVvFnfpGg1UmCIqM+QQ==",
|
"integrity": "sha512-FOIaFVMHzRskXr5J4Jp8lFVV0gz5ngv3RHmn+E4HYxSJ3DgDzU7fVI1/M7Ijh1zf6S7HIoaIOtln1H5y8V+9Zg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/tsconfig-utils": "^8.46.0",
|
"@typescript-eslint/tsconfig-utils": "^8.46.1",
|
||||||
"@typescript-eslint/types": "^8.46.0",
|
"@typescript-eslint/types": "^8.46.1",
|
||||||
"debug": "^4.3.4"
|
"debug": "^4.3.4"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -2431,14 +2431,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/scope-manager": {
|
"node_modules/@typescript-eslint/scope-manager": {
|
||||||
"version": "8.46.0",
|
"version": "8.46.1",
|
||||||
"resolved": "https://registry.npmmirror.com/@typescript-eslint/scope-manager/-/scope-manager-8.46.0.tgz",
|
"resolved": "https://registry.npmmirror.com/@typescript-eslint/scope-manager/-/scope-manager-8.46.1.tgz",
|
||||||
"integrity": "sha512-lWETPa9XGcBes4jqAMYD9fW0j4n6hrPtTJwWDmtqgFO/4HF4jmdH/Q6wggTw5qIT5TXjKzbt7GsZUBnWoO3dqw==",
|
"integrity": "sha512-weL9Gg3/5F0pVQKiF8eOXFZp8emqWzZsOJuWRUNtHT+UNV2xSJegmpCNQHy37aEQIbToTq7RHKhWvOsmbM680A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/types": "8.46.0",
|
"@typescript-eslint/types": "8.46.1",
|
||||||
"@typescript-eslint/visitor-keys": "8.46.0"
|
"@typescript-eslint/visitor-keys": "8.46.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
@@ -2449,9 +2449,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/tsconfig-utils": {
|
"node_modules/@typescript-eslint/tsconfig-utils": {
|
||||||
"version": "8.46.0",
|
"version": "8.46.1",
|
||||||
"resolved": "https://registry.npmmirror.com/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.46.0.tgz",
|
"resolved": "https://registry.npmmirror.com/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.46.1.tgz",
|
||||||
"integrity": "sha512-WrYXKGAHY836/N7zoK/kzi6p8tXFhasHh8ocFL9VZSAkvH956gfeRfcnhs3xzRy8qQ/dq3q44v1jvQieMFg2cw==",
|
"integrity": "sha512-X88+J/CwFvlJB+mK09VFqx5FE4H5cXD+H/Bdza2aEWkSb8hnWIQorNcscRl4IEo1Cz9VI/+/r/jnGWkbWPx54g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -2466,15 +2466,15 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/type-utils": {
|
"node_modules/@typescript-eslint/type-utils": {
|
||||||
"version": "8.46.0",
|
"version": "8.46.1",
|
||||||
"resolved": "https://registry.npmmirror.com/@typescript-eslint/type-utils/-/type-utils-8.46.0.tgz",
|
"resolved": "https://registry.npmmirror.com/@typescript-eslint/type-utils/-/type-utils-8.46.1.tgz",
|
||||||
"integrity": "sha512-hy+lvYV1lZpVs2jRaEYvgCblZxUoJiPyCemwbQZ+NGulWkQRy0HRPYAoef/CNSzaLt+MLvMptZsHXHlkEilaeg==",
|
"integrity": "sha512-+BlmiHIiqufBxkVnOtFwjah/vrkF4MtKKvpXrKSPLCkCtAp8H01/VV43sfqA98Od7nJpDcFnkwgyfQbOG0AMvw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/types": "8.46.0",
|
"@typescript-eslint/types": "8.46.1",
|
||||||
"@typescript-eslint/typescript-estree": "8.46.0",
|
"@typescript-eslint/typescript-estree": "8.46.1",
|
||||||
"@typescript-eslint/utils": "8.46.0",
|
"@typescript-eslint/utils": "8.46.1",
|
||||||
"debug": "^4.3.4",
|
"debug": "^4.3.4",
|
||||||
"ts-api-utils": "^2.1.0"
|
"ts-api-utils": "^2.1.0"
|
||||||
},
|
},
|
||||||
@@ -2491,9 +2491,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/types": {
|
"node_modules/@typescript-eslint/types": {
|
||||||
"version": "8.46.0",
|
"version": "8.46.1",
|
||||||
"resolved": "https://registry.npmmirror.com/@typescript-eslint/types/-/types-8.46.0.tgz",
|
"resolved": "https://registry.npmmirror.com/@typescript-eslint/types/-/types-8.46.1.tgz",
|
||||||
"integrity": "sha512-bHGGJyVjSE4dJJIO5yyEWt/cHyNwga/zXGJbJJ8TiO01aVREK6gCTu3L+5wrkb1FbDkQ+TKjMNe9R/QQQP9+rA==",
|
"integrity": "sha512-C+soprGBHwWBdkDpbaRC4paGBrkIXxVlNohadL5o0kfhsXqOC6GYH2S/Obmig+I0HTDl8wMaRySwrfrXVP8/pQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -2505,16 +2505,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/typescript-estree": {
|
"node_modules/@typescript-eslint/typescript-estree": {
|
||||||
"version": "8.46.0",
|
"version": "8.46.1",
|
||||||
"resolved": "https://registry.npmmirror.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.46.0.tgz",
|
"resolved": "https://registry.npmmirror.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.46.1.tgz",
|
||||||
"integrity": "sha512-ekDCUfVpAKWJbRfm8T1YRrCot1KFxZn21oV76v5Fj4tr7ELyk84OS+ouvYdcDAwZL89WpEkEj2DKQ+qg//+ucg==",
|
"integrity": "sha512-uIifjT4s8cQKFQ8ZBXXyoUODtRoAd7F7+G8MKmtzj17+1UbdzFl52AzRyZRyKqPHhgzvXunnSckVu36flGy8cg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/project-service": "8.46.0",
|
"@typescript-eslint/project-service": "8.46.1",
|
||||||
"@typescript-eslint/tsconfig-utils": "8.46.0",
|
"@typescript-eslint/tsconfig-utils": "8.46.1",
|
||||||
"@typescript-eslint/types": "8.46.0",
|
"@typescript-eslint/types": "8.46.1",
|
||||||
"@typescript-eslint/visitor-keys": "8.46.0",
|
"@typescript-eslint/visitor-keys": "8.46.1",
|
||||||
"debug": "^4.3.4",
|
"debug": "^4.3.4",
|
||||||
"fast-glob": "^3.3.2",
|
"fast-glob": "^3.3.2",
|
||||||
"is-glob": "^4.0.3",
|
"is-glob": "^4.0.3",
|
||||||
@@ -2560,16 +2560,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/utils": {
|
"node_modules/@typescript-eslint/utils": {
|
||||||
"version": "8.46.0",
|
"version": "8.46.1",
|
||||||
"resolved": "https://registry.npmmirror.com/@typescript-eslint/utils/-/utils-8.46.0.tgz",
|
"resolved": "https://registry.npmmirror.com/@typescript-eslint/utils/-/utils-8.46.1.tgz",
|
||||||
"integrity": "sha512-nD6yGWPj1xiOm4Gk0k6hLSZz2XkNXhuYmyIrOWcHoPuAhjT9i5bAG+xbWPgFeNR8HPHHtpNKdYUXJl/D3x7f5g==",
|
"integrity": "sha512-vkYUy6LdZS7q1v/Gxb2Zs7zziuXN0wxqsetJdeZdRe/f5dwJFglmuvZBfTUivCtjH725C1jWCDfpadadD95EDQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint-community/eslint-utils": "^4.7.0",
|
"@eslint-community/eslint-utils": "^4.7.0",
|
||||||
"@typescript-eslint/scope-manager": "8.46.0",
|
"@typescript-eslint/scope-manager": "8.46.1",
|
||||||
"@typescript-eslint/types": "8.46.0",
|
"@typescript-eslint/types": "8.46.1",
|
||||||
"@typescript-eslint/typescript-estree": "8.46.0"
|
"@typescript-eslint/typescript-estree": "8.46.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
@@ -2584,13 +2584,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/visitor-keys": {
|
"node_modules/@typescript-eslint/visitor-keys": {
|
||||||
"version": "8.46.0",
|
"version": "8.46.1",
|
||||||
"resolved": "https://registry.npmmirror.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.46.0.tgz",
|
"resolved": "https://registry.npmmirror.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.46.1.tgz",
|
||||||
"integrity": "sha512-FrvMpAK+hTbFy7vH5j1+tMYHMSKLE6RzluFJlkFNKD0p9YsUT75JlBSmr5so3QRzvMwU5/bIEdeNrxm8du8l3Q==",
|
"integrity": "sha512-ptkmIf2iDkNUjdeu2bQqhFPV1m6qTnFFjg7PPDjxKWaMaP0Z6I9l30Jr3g5QqbZGdw8YdYvLp+XnqnWWZOg/NA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/types": "8.46.0",
|
"@typescript-eslint/types": "8.46.1",
|
||||||
"eslint-visitor-keys": "^4.2.1"
|
"eslint-visitor-keys": "^4.2.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -3997,25 +3997,24 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/eslint": {
|
"node_modules/eslint": {
|
||||||
"version": "9.37.0",
|
"version": "9.38.0",
|
||||||
"resolved": "https://registry.npmmirror.com/eslint/-/eslint-9.37.0.tgz",
|
"resolved": "https://registry.npmmirror.com/eslint/-/eslint-9.38.0.tgz",
|
||||||
"integrity": "sha512-XyLmROnACWqSxiGYArdef1fItQd47weqB7iwtfr9JHwRrqIXZdcFMvvEcL9xHCmL0SNsOvF0c42lWyM1U5dgig==",
|
"integrity": "sha512-t5aPOpmtJcZcz5UJyY2GbvpDlsK5E8JqRqoKtfiKE3cNh437KIqfJr3A3AKf5k64NPx6d0G3dno6XDY05PqPtw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint-community/eslint-utils": "^4.8.0",
|
"@eslint-community/eslint-utils": "^4.8.0",
|
||||||
"@eslint-community/regexpp": "^4.12.1",
|
"@eslint-community/regexpp": "^4.12.1",
|
||||||
"@eslint/config-array": "^0.21.0",
|
"@eslint/config-array": "^0.21.1",
|
||||||
"@eslint/config-helpers": "^0.4.0",
|
"@eslint/config-helpers": "^0.4.1",
|
||||||
"@eslint/core": "^0.16.0",
|
"@eslint/core": "^0.16.0",
|
||||||
"@eslint/eslintrc": "^3.3.1",
|
"@eslint/eslintrc": "^3.3.1",
|
||||||
"@eslint/js": "9.37.0",
|
"@eslint/js": "9.38.0",
|
||||||
"@eslint/plugin-kit": "^0.4.0",
|
"@eslint/plugin-kit": "^0.4.0",
|
||||||
"@humanfs/node": "^0.16.6",
|
"@humanfs/node": "^0.16.6",
|
||||||
"@humanwhocodes/module-importer": "^1.0.1",
|
"@humanwhocodes/module-importer": "^1.0.1",
|
||||||
"@humanwhocodes/retry": "^0.4.2",
|
"@humanwhocodes/retry": "^0.4.2",
|
||||||
"@types/estree": "^1.0.6",
|
"@types/estree": "^1.0.6",
|
||||||
"@types/json-schema": "^7.0.15",
|
|
||||||
"ajv": "^6.12.4",
|
"ajv": "^6.12.4",
|
||||||
"chalk": "^4.0.0",
|
"chalk": "^4.0.0",
|
||||||
"cross-spawn": "^7.0.6",
|
"cross-spawn": "^7.0.6",
|
||||||
@@ -4058,9 +4057,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/eslint-plugin-vue": {
|
"node_modules/eslint-plugin-vue": {
|
||||||
"version": "10.5.0",
|
"version": "10.5.1",
|
||||||
"resolved": "https://registry.npmmirror.com/eslint-plugin-vue/-/eslint-plugin-vue-10.5.0.tgz",
|
"resolved": "https://registry.npmmirror.com/eslint-plugin-vue/-/eslint-plugin-vue-10.5.1.tgz",
|
||||||
"integrity": "sha512-7BZHsG3kC2vei8F2W8hnfDi9RK+cv5eKPMvzBdrl8Vuc0hR5odGQRli8VVzUkrmUHkxFEm4Iio1r5HOKslO0Aw==",
|
"integrity": "sha512-SbR9ZBUFKgvWAbq3RrdCtWaW0IKm6wwUiApxf3BVTNfqUIo4IQQmreMg2iHFJJ6C/0wss3LXURBJ1OwS/MhFcQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -6652,16 +6651,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/typescript-eslint": {
|
"node_modules/typescript-eslint": {
|
||||||
"version": "8.46.0",
|
"version": "8.46.1",
|
||||||
"resolved": "https://registry.npmmirror.com/typescript-eslint/-/typescript-eslint-8.46.0.tgz",
|
"resolved": "https://registry.npmmirror.com/typescript-eslint/-/typescript-eslint-8.46.1.tgz",
|
||||||
"integrity": "sha512-6+ZrB6y2bT2DX3K+Qd9vn7OFOJR+xSLDj+Aw/N3zBwUt27uTw2sw2TE2+UcY1RiyBZkaGbTkVg9SSdPNUG6aUw==",
|
"integrity": "sha512-VHgijW803JafdSsDO8I761r3SHrgk4T00IdyQ+/UsthtgPRsBWQLqoSxOolxTpxRKi1kGXK0bSz4CoAc9ObqJA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/eslint-plugin": "8.46.0",
|
"@typescript-eslint/eslint-plugin": "8.46.1",
|
||||||
"@typescript-eslint/parser": "8.46.0",
|
"@typescript-eslint/parser": "8.46.1",
|
||||||
"@typescript-eslint/typescript-estree": "8.46.0",
|
"@typescript-eslint/typescript-estree": "8.46.1",
|
||||||
"@typescript-eslint/utils": "8.46.0"
|
"@typescript-eslint/utils": "8.46.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
@@ -7029,9 +7028,9 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/vite": {
|
"node_modules/vite": {
|
||||||
"version": "7.1.9",
|
"version": "7.1.10",
|
||||||
"resolved": "https://registry.npmmirror.com/vite/-/vite-7.1.9.tgz",
|
"resolved": "https://registry.npmmirror.com/vite/-/vite-7.1.10.tgz",
|
||||||
"integrity": "sha512-4nVGliEpxmhCL8DslSAUdxlB6+SMrhB0a1v5ijlh1xB1nEPuy1mxaHxysVucLHuWryAxLWg6a5ei+U4TLn/rFg==",
|
"integrity": "sha512-CmuvUBzVJ/e3HGxhg6cYk88NGgTnBoOo7ogtfJJ0fefUWAxN/WDSUa50o+oVBxuIhO8FoEZW0j2eW7sfjs5EtA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -7250,9 +7249,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/vue-router": {
|
"node_modules/vue-router": {
|
||||||
"version": "4.5.1",
|
"version": "4.6.3",
|
||||||
"resolved": "https://registry.npmmirror.com/vue-router/-/vue-router-4.5.1.tgz",
|
"resolved": "https://registry.npmmirror.com/vue-router/-/vue-router-4.6.3.tgz",
|
||||||
"integrity": "sha512-ogAF3P97NPm8fJsE4by9dwSYtDwXIY1nFY9T6DyQnGHd1E2Da94w9JIolpe42LJGIl0DwOHBi8TcRPlPGwbTtw==",
|
"integrity": "sha512-ARBedLm9YlbvQomnmq91Os7ck6efydTSpRP3nuOKCvgJOHNrhRoJDSKtee8kcL1Vf7nz6U+PMBL+hTvR3bTVQg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vue/devtools-api": "^6.6.4"
|
"@vue/devtools-api": "^6.6.4"
|
||||||
@@ -7261,7 +7260,7 @@
|
|||||||
"url": "https://github.com/sponsors/posva"
|
"url": "https://github.com/sponsors/posva"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"vue": "^3.2.0"
|
"vue": "^3.5.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/vue-router/node_modules/@vue/devtools-api": {
|
"node_modules/vue-router/node_modules/@vue/devtools-api": {
|
||||||
|
|||||||
@@ -41,9 +41,9 @@
|
|||||||
"@codemirror/lint": "^6.9.0",
|
"@codemirror/lint": "^6.9.0",
|
||||||
"@codemirror/search": "^6.5.11",
|
"@codemirror/search": "^6.5.11",
|
||||||
"@codemirror/state": "^6.5.2",
|
"@codemirror/state": "^6.5.2",
|
||||||
"@codemirror/view": "^6.38.5",
|
"@codemirror/view": "^6.38.6",
|
||||||
"@cospaia/prettier-plugin-clojure": "^0.0.2",
|
"@cospaia/prettier-plugin-clojure": "^0.0.2",
|
||||||
"@lezer/highlight": "^1.2.1",
|
"@lezer/highlight": "^1.2.2",
|
||||||
"@lezer/lr": "^1.4.2",
|
"@lezer/lr": "^1.4.2",
|
||||||
"@prettier/plugin-xml": "^3.4.2",
|
"@prettier/plugin-xml": "^3.4.2",
|
||||||
"@replit/codemirror-lang-svelte": "^6.0.0",
|
"@replit/codemirror-lang-svelte": "^6.0.0",
|
||||||
@@ -67,23 +67,23 @@
|
|||||||
"vue": "^3.5.22",
|
"vue": "^3.5.22",
|
||||||
"vue-i18n": "^11.1.12",
|
"vue-i18n": "^11.1.12",
|
||||||
"vue-pick-colors": "^1.8.0",
|
"vue-pick-colors": "^1.8.0",
|
||||||
"vue-router": "^4.5.1"
|
"vue-router": "^4.6.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/js": "^9.37.0",
|
"@eslint/js": "^9.38.0",
|
||||||
"@lezer/generator": "^1.8.0",
|
"@lezer/generator": "^1.8.0",
|
||||||
"@types/node": "^24.7.1",
|
"@types/node": "^24.8.1",
|
||||||
"@types/remarkable": "^2.0.8",
|
"@types/remarkable": "^2.0.8",
|
||||||
"@vitejs/plugin-vue": "^6.0.1",
|
"@vitejs/plugin-vue": "^6.0.1",
|
||||||
"@wailsio/runtime": "latest",
|
"@wailsio/runtime": "latest",
|
||||||
"cross-env": "^10.1.0",
|
"cross-env": "^10.1.0",
|
||||||
"eslint": "^9.37.0",
|
"eslint": "^9.38.0",
|
||||||
"eslint-plugin-vue": "^10.5.0",
|
"eslint-plugin-vue": "^10.5.1",
|
||||||
"globals": "^16.4.0",
|
"globals": "^16.4.0",
|
||||||
"typescript": "^5.9.3",
|
"typescript": "^5.9.3",
|
||||||
"typescript-eslint": "^8.46.0",
|
"typescript-eslint": "^8.46.1",
|
||||||
"unplugin-vue-components": "^29.1.0",
|
"unplugin-vue-components": "^29.1.0",
|
||||||
"vite": "^7.1.9",
|
"vite": "^7.1.10",
|
||||||
"vite-plugin-node-polyfills": "^0.24.0",
|
"vite-plugin-node-polyfills": "^0.24.0",
|
||||||
"vue-eslint-parser": "^10.2.0",
|
"vue-eslint-parser": "^10.2.0",
|
||||||
"vue-tsc": "^3.1.1"
|
"vue-tsc": "^3.1.1"
|
||||||
|
|||||||
@@ -166,12 +166,17 @@ export default {
|
|||||||
interface: 'Interface Elements',
|
interface: 'Interface Elements',
|
||||||
border: 'Borders & Dividers',
|
border: 'Borders & Dividers',
|
||||||
search: 'Search & Matching',
|
search: 'Search & Matching',
|
||||||
|
// Base Colors
|
||||||
background: 'Main Background',
|
background: 'Main Background',
|
||||||
backgroundSecondary: 'Secondary Background',
|
backgroundSecondary: 'Secondary Background',
|
||||||
surface: 'Panel Background',
|
surface: 'Panel Background',
|
||||||
|
dropdownBackground: 'Dropdown Background',
|
||||||
|
dropdownBorder: 'Dropdown Border',
|
||||||
|
// Text Colors
|
||||||
foreground: 'Primary Text',
|
foreground: 'Primary Text',
|
||||||
foregroundSecondary: 'Secondary Text',
|
foregroundSecondary: 'Secondary Text',
|
||||||
comment: 'Comments',
|
comment: 'Comments',
|
||||||
|
// Syntax Highlighting - Core
|
||||||
keyword: 'Keywords',
|
keyword: 'Keywords',
|
||||||
string: 'Strings',
|
string: 'Strings',
|
||||||
function: 'Functions',
|
function: 'Functions',
|
||||||
@@ -179,14 +184,25 @@ export default {
|
|||||||
operator: 'Operators',
|
operator: 'Operators',
|
||||||
variable: 'Variables',
|
variable: 'Variables',
|
||||||
type: 'Types',
|
type: 'Types',
|
||||||
|
// Syntax Highlighting - Extended
|
||||||
|
constant: 'Constants',
|
||||||
|
storage: 'Storage Type',
|
||||||
|
parameter: 'Parameters',
|
||||||
|
class: 'Class Names',
|
||||||
|
heading: 'Headings',
|
||||||
|
invalid: 'Invalid/Error',
|
||||||
|
regexp: 'Regular Expressions',
|
||||||
|
// Interface Elements
|
||||||
cursor: 'Cursor',
|
cursor: 'Cursor',
|
||||||
selection: 'Selection Background',
|
selection: 'Selection Background',
|
||||||
selectionBlur: 'Unfocused Selection',
|
selectionBlur: 'Unfocused Selection',
|
||||||
activeLine: 'Active Line Highlight',
|
activeLine: 'Active Line Highlight',
|
||||||
lineNumber: 'Line Numbers',
|
lineNumber: 'Line Numbers',
|
||||||
activeLineNumber: 'Active Line Number',
|
activeLineNumber: 'Active Line Number',
|
||||||
|
// Borders & Dividers
|
||||||
borderColor: 'Border Color',
|
borderColor: 'Border Color',
|
||||||
borderLight: 'Light Border',
|
borderLight: 'Light Border',
|
||||||
|
// Search & Matching
|
||||||
searchMatch: 'Search Match',
|
searchMatch: 'Search Match',
|
||||||
matchingBracket: 'Matching Bracket'
|
matchingBracket: 'Matching Bracket'
|
||||||
},
|
},
|
||||||
@@ -199,6 +215,7 @@ export default {
|
|||||||
enableTabIndent: 'Enable Tab Indent',
|
enableTabIndent: 'Enable Tab Indent',
|
||||||
language: 'Interface Language',
|
language: 'Interface Language',
|
||||||
systemTheme: 'System Theme',
|
systemTheme: 'System Theme',
|
||||||
|
presetTheme: 'Preset Theme',
|
||||||
saveOptions: 'Save Options',
|
saveOptions: 'Save Options',
|
||||||
autoSaveDelay: 'Auto Save Delay (ms)',
|
autoSaveDelay: 'Auto Save Delay (ms)',
|
||||||
updateSettings: 'Update Settings',
|
updateSettings: 'Update Settings',
|
||||||
|
|||||||
@@ -166,6 +166,7 @@ export default {
|
|||||||
enableTabIndent: '启用 Tab 缩进',
|
enableTabIndent: '启用 Tab 缩进',
|
||||||
language: '界面语言',
|
language: '界面语言',
|
||||||
systemTheme: '系统主题',
|
systemTheme: '系统主题',
|
||||||
|
presetTheme: '预设主题',
|
||||||
saveOptions: '保存选项',
|
saveOptions: '保存选项',
|
||||||
autoSaveDelay: '自动保存延迟(毫秒)',
|
autoSaveDelay: '自动保存延迟(毫秒)',
|
||||||
updateSettings: '更新设置',
|
updateSettings: '更新设置',
|
||||||
@@ -206,12 +207,17 @@ export default {
|
|||||||
interface: '界面元素',
|
interface: '界面元素',
|
||||||
border: '边框分割线',
|
border: '边框分割线',
|
||||||
search: '搜索匹配',
|
search: '搜索匹配',
|
||||||
|
// 基础色调
|
||||||
background: '主背景色',
|
background: '主背景色',
|
||||||
backgroundSecondary: '次要背景色',
|
backgroundSecondary: '次要背景色',
|
||||||
surface: '面板背景',
|
surface: '面板背景',
|
||||||
|
dropdownBackground: '下拉菜单背景',
|
||||||
|
dropdownBorder: '下拉菜单边框',
|
||||||
|
// 文本颜色
|
||||||
foreground: '主文本色',
|
foreground: '主文本色',
|
||||||
foregroundSecondary: '次要文本色',
|
foregroundSecondary: '次要文本色',
|
||||||
comment: '注释色',
|
comment: '注释色',
|
||||||
|
// 语法高亮 - 核心
|
||||||
keyword: '关键字',
|
keyword: '关键字',
|
||||||
string: '字符串',
|
string: '字符串',
|
||||||
function: '函数名',
|
function: '函数名',
|
||||||
@@ -219,14 +225,25 @@ export default {
|
|||||||
operator: '操作符',
|
operator: '操作符',
|
||||||
variable: '变量',
|
variable: '变量',
|
||||||
type: '类型',
|
type: '类型',
|
||||||
|
// 语法高亮 - 扩展
|
||||||
|
constant: '常量',
|
||||||
|
storage: '存储类型',
|
||||||
|
parameter: '参数',
|
||||||
|
class: '类名',
|
||||||
|
heading: '标题',
|
||||||
|
invalid: '无效内容',
|
||||||
|
regexp: '正则表达式',
|
||||||
|
// 界面元素
|
||||||
cursor: '光标',
|
cursor: '光标',
|
||||||
selection: '选中背景',
|
selection: '选中背景',
|
||||||
selectionBlur: '失焦选中背景',
|
selectionBlur: '失焦选中背景',
|
||||||
activeLine: '当前行高亮',
|
activeLine: '当前行高亮',
|
||||||
lineNumber: '行号',
|
lineNumber: '行号',
|
||||||
activeLineNumber: '活动行号',
|
activeLineNumber: '活动行号',
|
||||||
|
// 边框和分割线
|
||||||
borderColor: '边框色',
|
borderColor: '边框色',
|
||||||
borderLight: '浅色边框',
|
borderLight: '浅色边框',
|
||||||
|
// 搜索和匹配
|
||||||
searchMatch: '搜索匹配',
|
searchMatch: '搜索匹配',
|
||||||
matchingBracket: '匹配括号'
|
matchingBracket: '匹配括号'
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,33 +1,59 @@
|
|||||||
import { defineStore } from 'pinia';
|
import { defineStore } from 'pinia';
|
||||||
import { computed, reactive } from 'vue';
|
import { computed, reactive, ref } from 'vue';
|
||||||
import { SystemThemeType, ThemeType, ThemeColorConfig } from '@/../bindings/voidraft/internal/models/models';
|
import {SystemThemeType, ThemeType, Theme, ThemeColorConfig} from '@/../bindings/voidraft/internal/models/models';
|
||||||
import { ThemeService } from '@/../bindings/voidraft/internal/services';
|
import { ThemeService } from '@/../bindings/voidraft/internal/services';
|
||||||
import { useConfigStore } from './configStore';
|
import { useConfigStore } from './configStore';
|
||||||
import { useEditorStore } from './editorStore';
|
import { useEditorStore } from './editorStore';
|
||||||
import { defaultDarkColors } from '@/views/editor/theme/dark';
|
import type { ThemeColors } from '@/views/editor/theme/types';
|
||||||
import { defaultLightColors } from '@/views/editor/theme/light';
|
import { getThemeConfig } from '@/views/editor/theme/registry';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 主题管理 Store
|
* 主题管理 Store
|
||||||
* 职责:管理主题状态和颜色配置
|
* 职责:管理主题状态、颜色配置和预设主题列表
|
||||||
*/
|
*/
|
||||||
export const useThemeStore = defineStore('theme', () => {
|
export const useThemeStore = defineStore('theme', () => {
|
||||||
const configStore = useConfigStore();
|
const configStore = useConfigStore();
|
||||||
|
|
||||||
// 响应式状态
|
// 所有主题列表(从数据库加载)
|
||||||
const themeColors = reactive({
|
const allThemes = ref<Theme[]>([]);
|
||||||
darkTheme: { ...defaultDarkColors },
|
|
||||||
lightTheme: { ...defaultLightColors }
|
// 当前选中的主题 ID
|
||||||
|
const currentThemeIds = reactive({
|
||||||
|
dark: 0, // 当前深色主题ID
|
||||||
|
light: 0, // 当前浅色主题ID
|
||||||
});
|
});
|
||||||
|
|
||||||
// 计算属性
|
// 当前主题的颜色配置(用于编辑器渲染)
|
||||||
|
const currentColors = reactive<{
|
||||||
|
dark: ThemeColors | null;
|
||||||
|
light: ThemeColors | null;
|
||||||
|
}>({
|
||||||
|
dark: null,
|
||||||
|
light: null,
|
||||||
|
});
|
||||||
|
|
||||||
|
// 计算属性:当前系统主题模式
|
||||||
const currentTheme = computed(() =>
|
const currentTheme = computed(() =>
|
||||||
configStore.config?.appearance?.systemTheme || SystemThemeType.SystemThemeAuto
|
configStore.config?.appearance?.systemTheme || SystemThemeType.SystemThemeAuto
|
||||||
);
|
);
|
||||||
|
|
||||||
// 获取默认主题颜色
|
// 计算属性:根据类型获取主题列表
|
||||||
const getDefaultColors = (themeType: ThemeType) =>
|
const darkThemes = computed(() =>
|
||||||
themeType === ThemeType.ThemeTypeDark ? defaultDarkColors : defaultLightColors;
|
allThemes.value.filter(t => t.type === ThemeType.ThemeTypeDark)
|
||||||
|
);
|
||||||
|
|
||||||
|
const lightThemes = computed(() =>
|
||||||
|
allThemes.value.filter(t => t.type === ThemeType.ThemeTypeLight)
|
||||||
|
);
|
||||||
|
|
||||||
|
// 计算属性:获取当前激活的主题对象
|
||||||
|
const activeTheme = computed(() => {
|
||||||
|
const isDark = currentTheme.value === SystemThemeType.SystemThemeDark ||
|
||||||
|
(currentTheme.value === SystemThemeType.SystemThemeAuto &&
|
||||||
|
window.matchMedia('(prefers-color-scheme: dark)').matches);
|
||||||
|
|
||||||
|
return isDark ? currentColors.dark : currentColors.light;
|
||||||
|
});
|
||||||
|
|
||||||
// 应用主题到 DOM
|
// 应用主题到 DOM
|
||||||
const applyThemeToDOM = (theme: SystemThemeType) => {
|
const applyThemeToDOM = (theme: SystemThemeType) => {
|
||||||
@@ -39,30 +65,77 @@ export const useThemeStore = defineStore('theme', () => {
|
|||||||
document.documentElement.setAttribute('data-theme', themeMap[theme]);
|
document.documentElement.setAttribute('data-theme', themeMap[theme]);
|
||||||
};
|
};
|
||||||
|
|
||||||
// 初始化主题颜色
|
// 从数据库加载所有主题
|
||||||
|
const loadAllThemes = async () => {
|
||||||
|
try {
|
||||||
|
const themes = await ThemeService.GetAllThemes();
|
||||||
|
allThemes.value = (themes || []).filter((t): t is Theme => t !== null);
|
||||||
|
return allThemes.value;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to load themes from database:', error);
|
||||||
|
allThemes.value = [];
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 根据主题对象加载颜色配置
|
||||||
|
const loadThemeColors = (theme: Theme): ThemeColors => {
|
||||||
|
// 优先使用数据库中的颜色配置
|
||||||
|
const dbColors = theme.colors as unknown as ThemeColors;
|
||||||
|
|
||||||
|
// 如果数据库颜色不完整,尝试从预设主题获取
|
||||||
|
if (!dbColors || Object.keys(dbColors).length < 10) {
|
||||||
|
const presetConfig = getThemeConfig(theme.name);
|
||||||
|
if (presetConfig) {
|
||||||
|
return presetConfig;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return dbColors;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 初始化主题颜色(加载默认主题)
|
||||||
const initializeThemeColors = async () => {
|
const initializeThemeColors = async () => {
|
||||||
try {
|
try {
|
||||||
const themes = await ThemeService.GetDefaultThemes();
|
// 加载所有主题
|
||||||
|
await loadAllThemes();
|
||||||
|
|
||||||
// 如果没有获取到主题数据,使用默认值
|
// 查找默认主题
|
||||||
if (!themes) {
|
const defaultDark = allThemes.value.find(
|
||||||
Object.assign(themeColors.darkTheme, defaultDarkColors);
|
t => t.type === ThemeType.ThemeTypeDark && t.isDefault
|
||||||
Object.assign(themeColors.lightTheme, defaultLightColors);
|
);
|
||||||
return;
|
const defaultLight = allThemes.value.find(
|
||||||
|
t => t.type === ThemeType.ThemeTypeLight && t.isDefault
|
||||||
|
);
|
||||||
|
|
||||||
|
// 设置默认主题
|
||||||
|
if (defaultDark) {
|
||||||
|
currentThemeIds.dark = defaultDark.id;
|
||||||
|
currentColors.dark = loadThemeColors(defaultDark);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 更新主题颜色
|
if (defaultLight) {
|
||||||
if (themes[ThemeType.ThemeTypeDark]) {
|
currentThemeIds.light = defaultLight.id;
|
||||||
Object.assign(themeColors.darkTheme, themes[ThemeType.ThemeTypeDark].colors);
|
currentColors.light = loadThemeColors(defaultLight);
|
||||||
}
|
}
|
||||||
if (themes[ThemeType.ThemeTypeLight]) {
|
|
||||||
Object.assign(themeColors.lightTheme, themes[ThemeType.ThemeTypeLight].colors);
|
// 如果没有找到默认主题,使用第一个可用主题
|
||||||
|
if (!currentColors.dark && darkThemes.value.length > 0) {
|
||||||
|
const fallback = darkThemes.value[0];
|
||||||
|
currentThemeIds.dark = fallback.id;
|
||||||
|
currentColors.dark = loadThemeColors(fallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!currentColors.light && lightThemes.value.length > 0) {
|
||||||
|
const fallback = lightThemes.value[0];
|
||||||
|
currentThemeIds.light = fallback.id;
|
||||||
|
currentColors.light = loadThemeColors(fallback);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.warn('Failed to load themes from database, using defaults:', error);
|
console.error('Failed to initialize theme colors:', error);
|
||||||
// 如果数据库加载失败,使用默认主题
|
// 使用预设主题作为后备
|
||||||
Object.assign(themeColors.darkTheme, defaultDarkColors);
|
currentColors.dark = getThemeConfig('default-dark');
|
||||||
Object.assign(themeColors.lightTheme, defaultLightColors);
|
currentColors.light = getThemeConfig('default-light');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -73,77 +146,109 @@ export const useThemeStore = defineStore('theme', () => {
|
|||||||
await initializeThemeColors();
|
await initializeThemeColors();
|
||||||
};
|
};
|
||||||
|
|
||||||
// 设置主题
|
// 设置系统主题模式(深色/浅色/自动)
|
||||||
const setTheme = async (theme: SystemThemeType) => {
|
const setTheme = async (theme: SystemThemeType) => {
|
||||||
await configStore.setSystemTheme(theme);
|
await configStore.setSystemTheme(theme);
|
||||||
applyThemeToDOM(theme);
|
applyThemeToDOM(theme);
|
||||||
refreshEditorTheme();
|
refreshEditorTheme();
|
||||||
};
|
};
|
||||||
|
|
||||||
// 更新主题颜色 - 合并逻辑,减少重复代码
|
// 切换到指定的预设主题(通过主题ID)
|
||||||
const updateThemeColors = (darkColors?: any, lightColors?: any): boolean => {
|
const switchToTheme = async (themeId: number) => {
|
||||||
let hasChanges = false;
|
try {
|
||||||
|
const theme = allThemes.value.find(t => t.id === themeId);
|
||||||
|
if (!theme) {
|
||||||
|
console.error('Theme not found:', themeId);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
const updateColors = (target: any, source: any) => {
|
// 加载主题颜色
|
||||||
if (!source) return false;
|
const colors = loadThemeColors(theme);
|
||||||
|
|
||||||
let changed = false;
|
// 根据主题类型更新对应的颜色配置
|
||||||
Object.entries(source).forEach(([key, value]) => {
|
if (theme.type === ThemeType.ThemeTypeDark) {
|
||||||
if (value !== undefined && target[key] !== value) {
|
currentThemeIds.dark = themeId;
|
||||||
target[key] = value;
|
currentColors.dark = colors;
|
||||||
changed = true;
|
} else {
|
||||||
}
|
currentThemeIds.light = themeId;
|
||||||
});
|
currentColors.light = colors;
|
||||||
return changed;
|
}
|
||||||
};
|
|
||||||
|
|
||||||
hasChanges = updateColors(themeColors.darkTheme, darkColors) || hasChanges;
|
// 刷新编辑器主题
|
||||||
hasChanges = updateColors(themeColors.lightTheme, lightColors) || hasChanges;
|
refreshEditorTheme();
|
||||||
|
return true;
|
||||||
return hasChanges;
|
} catch (error) {
|
||||||
|
console.error('Failed to switch theme:', error);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 保存主题颜色到数据库
|
// 更新当前主题的颜色配置
|
||||||
const saveThemeColors = async () => {
|
const updateCurrentColors = (colors: Partial<ThemeColors>, isDark: boolean) => {
|
||||||
try {
|
const target = isDark ? currentColors.dark : currentColors.light;
|
||||||
const darkColors = ThemeColorConfig.createFrom(themeColors.darkTheme);
|
if (!target) return;
|
||||||
const lightColors = ThemeColorConfig.createFrom(themeColors.lightTheme);
|
|
||||||
|
|
||||||
await Promise.all([
|
Object.assign(target, colors);
|
||||||
ThemeService.UpdateThemeColors(ThemeType.ThemeTypeDark, darkColors),
|
};
|
||||||
ThemeService.UpdateThemeColors(ThemeType.ThemeTypeLight, lightColors)
|
|
||||||
]);
|
// 保存当前主题颜色到数据库
|
||||||
|
const saveCurrentTheme = async (isDark: boolean) => {
|
||||||
|
try {
|
||||||
|
const themeId = isDark ? currentThemeIds.dark : currentThemeIds.light;
|
||||||
|
const colors = isDark ? currentColors.dark : currentColors.light;
|
||||||
|
|
||||||
|
if (!themeId || !colors) {
|
||||||
|
throw new Error('No theme selected');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 转换为数据库格式并保存
|
||||||
|
const dbColors = colors as ThemeColorConfig; // ThemeColorConfig from bindings
|
||||||
|
await ThemeService.UpdateTheme(themeId, dbColors);
|
||||||
|
|
||||||
|
return true;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to save theme colors:', error);
|
console.error('Failed to save theme:', error);
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 重置主题颜色
|
// 重置当前主题为预设配置
|
||||||
const resetThemeColors = async (themeType: 'darkTheme' | 'lightTheme') => {
|
const resetCurrentTheme = async (isDark: boolean) => {
|
||||||
try {
|
try {
|
||||||
const dbThemeType = themeType === 'darkTheme' ? ThemeType.ThemeTypeDark : ThemeType.ThemeTypeLight;
|
const themeId = isDark ? currentThemeIds.dark : currentThemeIds.light;
|
||||||
|
|
||||||
// 1. 调用后端重置服务
|
if (!themeId) {
|
||||||
await ThemeService.ResetThemeColors(dbThemeType);
|
throw new Error('No theme selected');
|
||||||
|
}
|
||||||
|
|
||||||
// 2. 更新内存中的颜色状态
|
// 调用后端重置服务
|
||||||
const defaultColors = getDefaultColors(dbThemeType);
|
await ThemeService.ResetTheme(themeId);
|
||||||
Object.assign(themeColors[themeType], defaultColors);
|
|
||||||
|
|
||||||
// 3. 刷新编辑器主题
|
// 重新加载主题
|
||||||
|
await loadAllThemes();
|
||||||
|
const theme = allThemes.value.find(t => t.id === themeId);
|
||||||
|
|
||||||
|
if (theme) {
|
||||||
|
const colors = loadThemeColors(theme);
|
||||||
|
if (isDark) {
|
||||||
|
currentColors.dark = colors;
|
||||||
|
} else {
|
||||||
|
currentColors.light = colors;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 刷新编辑器主题
|
||||||
refreshEditorTheme();
|
refreshEditorTheme();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to reset theme colors:', error);
|
console.error('Failed to reset theme:', error);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 刷新编辑器主题
|
// 刷新编辑器主题
|
||||||
const refreshEditorTheme = () => {
|
const refreshEditorTheme = () => {
|
||||||
// 使用当前主题重新应用DOM主题
|
|
||||||
applyThemeToDOM(currentTheme.value);
|
applyThemeToDOM(currentTheme.value);
|
||||||
|
|
||||||
const editorStore = useEditorStore();
|
const editorStore = useEditorStore();
|
||||||
@@ -151,14 +256,24 @@ export const useThemeStore = defineStore('theme', () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
// 状态
|
||||||
|
allThemes,
|
||||||
|
darkThemes,
|
||||||
|
lightThemes,
|
||||||
currentTheme,
|
currentTheme,
|
||||||
themeColors,
|
currentThemeIds,
|
||||||
|
currentColors,
|
||||||
|
activeTheme,
|
||||||
|
|
||||||
|
// 方法
|
||||||
setTheme,
|
setTheme,
|
||||||
|
switchToTheme,
|
||||||
initializeTheme,
|
initializeTheme,
|
||||||
|
loadAllThemes,
|
||||||
|
updateCurrentColors,
|
||||||
|
saveCurrentTheme,
|
||||||
|
resetCurrentTheme,
|
||||||
|
refreshEditorTheme,
|
||||||
applyThemeToDOM,
|
applyThemeToDOM,
|
||||||
updateThemeColors,
|
|
||||||
saveThemeColors,
|
|
||||||
resetThemeColors,
|
|
||||||
refreshEditorTheme
|
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
@@ -1,8 +1,7 @@
|
|||||||
import { Extension, Compartment } from '@codemirror/state';
|
import { Extension, Compartment } from '@codemirror/state';
|
||||||
import { EditorView } from '@codemirror/view';
|
import { EditorView } from '@codemirror/view';
|
||||||
import { SystemThemeType } from '@/../bindings/voidraft/internal/models/models';
|
import { SystemThemeType } from '@/../bindings/voidraft/internal/models/models';
|
||||||
import { createDarkTheme } from '@/views/editor/theme/dark';
|
import { createThemeByColors } from '@/views/editor/theme/registry';
|
||||||
import { createLightTheme } from '@/views/editor/theme/light';
|
|
||||||
import { useThemeStore } from '@/stores/themeStore';
|
import { useThemeStore } from '@/stores/themeStore';
|
||||||
|
|
||||||
// 主题区间 - 用于动态切换主题
|
// 主题区间 - 用于动态切换主题
|
||||||
@@ -11,23 +10,25 @@ export const themeCompartment = new Compartment();
|
|||||||
/**
|
/**
|
||||||
* 根据主题类型获取主题扩展
|
* 根据主题类型获取主题扩展
|
||||||
*/
|
*/
|
||||||
const getThemeExtension = (themeType: SystemThemeType): Extension => {
|
const getThemeExtension = (themeType: SystemThemeType): Extension | null => {
|
||||||
const themeStore = useThemeStore();
|
const themeStore = useThemeStore();
|
||||||
|
|
||||||
// 处理 auto 主题类型
|
// 处理 auto 主题类型
|
||||||
let actualTheme: SystemThemeType = themeType;
|
let isDark = themeType === SystemThemeType.SystemThemeDark;
|
||||||
if (themeType === SystemThemeType.SystemThemeAuto) {
|
if (themeType === SystemThemeType.SystemThemeAuto) {
|
||||||
actualTheme = window.matchMedia('(prefers-color-scheme: dark)').matches
|
isDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
|
||||||
? SystemThemeType.SystemThemeDark
|
|
||||||
: SystemThemeType.SystemThemeLight;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 根据主题类型创建主题
|
// 根据主题类型获取对应的颜色配置
|
||||||
if (actualTheme === SystemThemeType.SystemThemeLight) {
|
const colors = isDark ? themeStore.currentColors.dark : themeStore.currentColors.light;
|
||||||
return createLightTheme(themeStore.themeColors.lightTheme);
|
|
||||||
} else {
|
if (!colors) {
|
||||||
return createDarkTheme(themeStore.themeColors.darkTheme);
|
console.warn('Theme colors not loaded yet');
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 使用颜色配置创建主题
|
||||||
|
return createThemeByColors(colors);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -35,6 +36,12 @@ const getThemeExtension = (themeType: SystemThemeType): Extension => {
|
|||||||
*/
|
*/
|
||||||
export const createThemeExtension = (themeType: SystemThemeType = SystemThemeType.SystemThemeDark): Extension => {
|
export const createThemeExtension = (themeType: SystemThemeType = SystemThemeType.SystemThemeDark): Extension => {
|
||||||
const extension = getThemeExtension(themeType);
|
const extension = getThemeExtension(themeType);
|
||||||
|
|
||||||
|
// 如果主题未加载,返回空扩展
|
||||||
|
if (!extension) {
|
||||||
|
return themeCompartment.of([]);
|
||||||
|
}
|
||||||
|
|
||||||
return themeCompartment.of(extension);
|
return themeCompartment.of(extension);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -48,6 +55,13 @@ export const updateEditorTheme = (view: EditorView, themeType: SystemThemeType):
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const extension = getThemeExtension(themeType);
|
const extension = getThemeExtension(themeType);
|
||||||
|
|
||||||
|
// 如果主题未加载,不更新
|
||||||
|
if (!extension) {
|
||||||
|
console.warn('Cannot update theme: theme not loaded');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
view.dispatch({
|
view.dispatch({
|
||||||
effects: themeCompartment.reconfigure(extension)
|
effects: themeCompartment.reconfigure(extension)
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,48 +1,17 @@
|
|||||||
import {EditorView} from '@codemirror/view';
|
import {EditorView} from '@codemirror/view';
|
||||||
import {HighlightStyle, syntaxHighlighting} from '@codemirror/language';
|
import {HighlightStyle, syntaxHighlighting} from '@codemirror/language';
|
||||||
import {tags} from '@lezer/highlight';
|
import {tags} from '@lezer/highlight';
|
||||||
|
import {Extension} from '@codemirror/state';
|
||||||
|
import type {ThemeColors} from './types';
|
||||||
|
|
||||||
// 默认深色主题颜色
|
/**
|
||||||
export const defaultDarkColors = {
|
* 创建通用主题
|
||||||
// 基础色调
|
* @param colors 主题颜色配置
|
||||||
background: '#252B37', // 主背景色
|
* @returns CodeMirror Extension数组
|
||||||
backgroundSecondary: '#213644', // 次要背景色
|
*/
|
||||||
surface: '#474747', // 面板背景
|
export function createBaseTheme(colors: ThemeColors): Extension {
|
||||||
|
// 编辑器主题样式
|
||||||
// 文本颜色
|
const theme = EditorView.theme({
|
||||||
foreground: '#9BB586', // 主文本色
|
|
||||||
foregroundSecondary: '#9c9c9c', // 次要文本色
|
|
||||||
comment: '#6272a4', // 注释色
|
|
||||||
|
|
||||||
// 语法高亮色
|
|
||||||
keyword: '#ff79c6', // 关键字
|
|
||||||
string: '#f1fa8c', // 字符串
|
|
||||||
function: '#50fa7b', // 函数名
|
|
||||||
number: '#bd93f9', // 数字
|
|
||||||
operator: '#ff79c6', // 操作符
|
|
||||||
variable: '#8fbcbb', // 变量
|
|
||||||
type: '#8be9fd', // 类型
|
|
||||||
|
|
||||||
// 界面元素
|
|
||||||
cursor: '#ffffff', // 光标
|
|
||||||
selection: '#0865a9', // 选中背景
|
|
||||||
selectionBlur: '#225377', // 失焦选中背景
|
|
||||||
activeLine: '#ffffff0a', // 当前行高亮
|
|
||||||
lineNumber: '#ffffff26', // 行号
|
|
||||||
activeLineNumber: '#ffffff99', // 活动行号
|
|
||||||
|
|
||||||
// 边框和分割线
|
|
||||||
borderColor: '#1e222a', // 边框色
|
|
||||||
borderLight: '#ffffff19', // 浅色边框
|
|
||||||
|
|
||||||
// 搜索和匹配
|
|
||||||
searchMatch: '#8fbcbb', // 搜索匹配
|
|
||||||
matchingBracket: '#ffffff19', // 匹配括号
|
|
||||||
};
|
|
||||||
|
|
||||||
// 创建深色主题
|
|
||||||
export function createDarkTheme(colors = defaultDarkColors) {
|
|
||||||
const darkTheme = EditorView.theme({
|
|
||||||
'&': {
|
'&': {
|
||||||
color: colors.foreground,
|
color: colors.foreground,
|
||||||
backgroundColor: colors.background,
|
backgroundColor: colors.background,
|
||||||
@@ -79,6 +48,9 @@ export function createDarkTheme(colors = defaultDarkColors) {
|
|||||||
'&.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground': {
|
'&.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground': {
|
||||||
backgroundColor: colors.selection,
|
backgroundColor: colors.selection,
|
||||||
},
|
},
|
||||||
|
'.cm-content ::selection': {
|
||||||
|
backgroundColor: colors.selection,
|
||||||
|
},
|
||||||
'.cm-activeLine.code-empty-block-selected': {
|
'.cm-activeLine.code-empty-block-selected': {
|
||||||
backgroundColor: colors.selection,
|
backgroundColor: colors.selection,
|
||||||
},
|
},
|
||||||
@@ -90,9 +62,10 @@ export function createDarkTheme(colors = defaultDarkColors) {
|
|||||||
|
|
||||||
// 行号区域
|
// 行号区域
|
||||||
'.cm-gutters': {
|
'.cm-gutters': {
|
||||||
backgroundColor: 'rgba(0,0,0, 0.1)',
|
backgroundColor: colors.dark ? 'rgba(0,0,0, 0.1)' : 'rgba(0,0,0, 0.04)',
|
||||||
color: colors.lineNumber,
|
color: colors.lineNumber,
|
||||||
border: 'none',
|
border: 'none',
|
||||||
|
borderRight: colors.dark ? 'none' : `1px solid ${colors.borderLight}`,
|
||||||
padding: '0 2px 0 4px',
|
padding: '0 2px 0 4px',
|
||||||
userSelect: 'none',
|
userSelect: 'none',
|
||||||
},
|
},
|
||||||
@@ -115,9 +88,20 @@ export function createDarkTheme(colors = defaultDarkColors) {
|
|||||||
'.cm-foldPlaceholder': {
|
'.cm-foldPlaceholder': {
|
||||||
backgroundColor: 'transparent',
|
backgroundColor: 'transparent',
|
||||||
border: 'none',
|
border: 'none',
|
||||||
color: '#ddd',
|
color: colors.comment,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// 面板
|
||||||
|
'.cm-panels': {
|
||||||
|
backgroundColor: colors.dropdownBackground,
|
||||||
|
color: colors.foreground
|
||||||
|
},
|
||||||
|
'.cm-panels.cm-panels-top': {
|
||||||
|
borderBottom: '2px solid black'
|
||||||
|
},
|
||||||
|
'.cm-panels.cm-panels-bottom': {
|
||||||
|
borderTop: '2px solid black'
|
||||||
|
},
|
||||||
|
|
||||||
// 搜索匹配
|
// 搜索匹配
|
||||||
'.cm-searchMatch': {
|
'.cm-searchMatch': {
|
||||||
@@ -125,11 +109,11 @@ export function createDarkTheme(colors = defaultDarkColors) {
|
|||||||
outline: `1px solid ${colors.searchMatch}`,
|
outline: `1px solid ${colors.searchMatch}`,
|
||||||
},
|
},
|
||||||
'.cm-searchMatch.cm-searchMatch-selected': {
|
'.cm-searchMatch.cm-searchMatch-selected': {
|
||||||
backgroundColor: colors.foreground,
|
backgroundColor: colors.searchMatch,
|
||||||
color: colors.background,
|
color: colors.background,
|
||||||
},
|
},
|
||||||
'.cm-selectionMatch': {
|
'.cm-selectionMatch': {
|
||||||
backgroundColor: '#50606D',
|
backgroundColor: colors.dark ? '#50606D' : '#e6f3ff',
|
||||||
},
|
},
|
||||||
|
|
||||||
// 括号匹配
|
// 括号匹配
|
||||||
@@ -141,7 +125,7 @@ export function createDarkTheme(colors = defaultDarkColors) {
|
|||||||
color: 'inherit',
|
color: 'inherit',
|
||||||
},
|
},
|
||||||
'&.cm-focused .cm-nonmatchingBracket': {
|
'&.cm-focused .cm-nonmatchingBracket': {
|
||||||
outline: '0.5px solid #bc8f8f',
|
outline: colors.dark ? '0.5px solid #bc8f8f' : '0.5px solid #d73a49',
|
||||||
},
|
},
|
||||||
|
|
||||||
// 编辑器焦点
|
// 编辑器焦点
|
||||||
@@ -151,8 +135,10 @@ export function createDarkTheme(colors = defaultDarkColors) {
|
|||||||
|
|
||||||
// 工具提示
|
// 工具提示
|
||||||
'.cm-tooltip': {
|
'.cm-tooltip': {
|
||||||
border: 'none',
|
border: colors.dark ? 'none' : `1px solid ${colors.dropdownBorder}`,
|
||||||
backgroundColor: colors.surface,
|
backgroundColor: colors.surface,
|
||||||
|
color: colors.foreground,
|
||||||
|
boxShadow: colors.dark ? 'none' : '0 2px 8px rgba(0,0,0,0.1)',
|
||||||
},
|
},
|
||||||
'.cm-tooltip .cm-tooltip-arrow:before': {
|
'.cm-tooltip .cm-tooltip-arrow:before': {
|
||||||
borderTopColor: 'transparent',
|
borderTopColor: 'transparent',
|
||||||
@@ -169,7 +155,7 @@ export function createDarkTheme(colors = defaultDarkColors) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
// 代码块层
|
// 代码块层(自定义)
|
||||||
'.code-blocks-layer': {
|
'.code-blocks-layer': {
|
||||||
width: '100%',
|
width: '100%',
|
||||||
},
|
},
|
||||||
@@ -188,34 +174,36 @@ export function createDarkTheme(colors = defaultDarkColors) {
|
|||||||
background: colors.backgroundSecondary,
|
background: colors.backgroundSecondary,
|
||||||
borderTop: `1px solid ${colors.borderColor}`,
|
borderTop: `1px solid ${colors.borderColor}`,
|
||||||
},
|
},
|
||||||
'.code-blocks-math-result': {
|
|
||||||
paddingLeft: "12px",
|
|
||||||
position: "relative",
|
|
||||||
},
|
|
||||||
".code-blocks-math-result .inner": {
|
|
||||||
background: "#0e1217",
|
|
||||||
color: "#a0e7c7",
|
|
||||||
padding: '0px 4px',
|
|
||||||
borderRadius: '2px',
|
|
||||||
boxShadow: '0 0 3px rgba(0,0,0, 0.3)',
|
|
||||||
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: "rgba(220,240,230, 1.0)",
|
|
||||||
},
|
|
||||||
'.code-blocks-math-result-copied.fade-out': {
|
|
||||||
opacity: 0,
|
|
||||||
},
|
|
||||||
|
|
||||||
// 代码块开始标记
|
// 数学计算结果(自定义)
|
||||||
|
'.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,
|
||||||
|
},
|
||||||
|
|
||||||
|
// 代码块开始标记(自定义)
|
||||||
'.code-block-start': {
|
'.code-block-start': {
|
||||||
height: '12px',
|
height: '12px',
|
||||||
position: 'relative',
|
position: 'relative',
|
||||||
@@ -223,47 +211,79 @@ export function createDarkTheme(colors = defaultDarkColors) {
|
|||||||
'.code-block-start.first': {
|
'.code-block-start.first': {
|
||||||
height: '0px',
|
height: '0px',
|
||||||
},
|
},
|
||||||
}, {dark: true});
|
}, {dark: colors.dark});
|
||||||
|
|
||||||
// 语法高亮样式
|
// 语法高亮样式
|
||||||
const darkHighlightStyle = HighlightStyle.define([
|
const highlightStyle = HighlightStyle.define([
|
||||||
|
// 关键字
|
||||||
{tag: tags.keyword, color: colors.keyword},
|
{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.operator, tags.operatorKeyword], color: colors.operator},
|
||||||
{tag: [tags.tagName], color: colors.number},
|
|
||||||
{tag: [tags.squareBracket], color: '#bf616a'},
|
// 名称、变量
|
||||||
{tag: [tags.angleBracket], color: '#d08770'},
|
{tag: [tags.name, tags.deleted, tags.character, tags.macroName], color: colors.variable},
|
||||||
{tag: [tags.attributeName], color: colors.variable},
|
{tag: [tags.variableName], color: colors.variable},
|
||||||
{tag: [tags.regexp], color: colors.string},
|
{tag: [tags.labelName], color: colors.operator},
|
||||||
|
{tag: [tags.atom, tags.bool, tags.special(tags.variableName)], color: colors.variable},
|
||||||
|
|
||||||
|
// 函数
|
||||||
|
{tag: [tags.function(tags.variableName)], color: colors.function},
|
||||||
|
{tag: [tags.propertyName], color: colors.function},
|
||||||
|
|
||||||
|
// 类型、类
|
||||||
|
{tag: [tags.typeName], color: colors.type},
|
||||||
|
{tag: [tags.className], color: colors.class},
|
||||||
|
|
||||||
|
// 常量
|
||||||
|
{tag: [tags.color, tags.constant(tags.name), tags.standard(tags.name)], color: colors.constant},
|
||||||
|
|
||||||
|
// 字符串
|
||||||
|
{tag: [tags.processingInstruction, tags.string, tags.inserted], color: colors.string},
|
||||||
|
{tag: [tags.special(tags.string)], color: colors.string},
|
||||||
{tag: [tags.quote], color: colors.comment},
|
{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.number, tags.changed, tags.annotation, tags.modifier, tags.self, tags.namespace], color: colors.number},
|
||||||
{tag: [tags.meta], color: colors.comment},
|
|
||||||
{tag: [tags.comment], color: colors.comment, fontStyle: 'italic'},
|
// 正则表达式
|
||||||
|
{tag: [tags.url, tags.escape, tags.regexp, tags.link], color: colors.regexp},
|
||||||
|
|
||||||
|
// 注释
|
||||||
|
{tag: [tags.meta, tags.comment], color: colors.comment, fontStyle: 'italic'},
|
||||||
|
|
||||||
|
// 分隔符、括号
|
||||||
|
{tag: [tags.definition(tags.name), tags.separator], color: colors.variable},
|
||||||
|
{tag: [tags.brace], color: colors.variable},
|
||||||
|
{tag: [tags.squareBracket], color: colors.dark ? '#bf616a' : colors.keyword},
|
||||||
|
{tag: [tags.angleBracket], color: colors.dark ? '#d08770' : colors.operator},
|
||||||
|
{tag: [tags.attributeName], color: colors.variable},
|
||||||
|
|
||||||
|
// 标签
|
||||||
|
{tag: [tags.tagName], color: colors.number},
|
||||||
|
|
||||||
|
// 注解
|
||||||
|
{tag: [tags.annotation], color: colors.invalid},
|
||||||
|
|
||||||
|
// 特殊样式
|
||||||
{tag: tags.strong, fontWeight: 'bold'},
|
{tag: tags.strong, fontWeight: 'bold'},
|
||||||
{tag: tags.emphasis, fontStyle: 'italic'},
|
{tag: tags.emphasis, fontStyle: 'italic'},
|
||||||
{tag: tags.strikethrough, textDecoration: 'line-through'},
|
{tag: tags.strikethrough, textDecoration: 'line-through'},
|
||||||
{tag: tags.heading, fontWeight: 'bold', color: colors.keyword},
|
{tag: tags.link, color: colors.variable, textDecoration: 'underline'},
|
||||||
|
|
||||||
|
// 标题
|
||||||
|
{tag: tags.heading, fontWeight: 'bold', color: colors.heading},
|
||||||
{tag: [tags.heading1, tags.heading2], fontSize: '1.4em'},
|
{tag: [tags.heading1, tags.heading2], fontSize: '1.4em'},
|
||||||
{tag: [tags.heading3, tags.heading4], fontSize: '1.2em'},
|
{tag: [tags.heading3, tags.heading4], fontSize: '1.2em'},
|
||||||
{tag: [tags.heading5, tags.heading6], fontSize: '1.1em'},
|
{tag: [tags.heading5, tags.heading6], fontSize: '1.1em'},
|
||||||
|
|
||||||
|
// 无效内容
|
||||||
|
{tag: tags.invalid, color: colors.invalid},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return [
|
return [
|
||||||
darkTheme,
|
theme,
|
||||||
syntaxHighlighting(darkHighlightStyle),
|
syntaxHighlighting(highlightStyle),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
// 默认深色主题
|
|
||||||
export const dark = createDarkTheme(defaultDarkColors);
|
|
||||||
@@ -1,128 +1,57 @@
|
|||||||
import {EditorView} from '@codemirror/view'
|
|
||||||
import {Extension} from '@codemirror/state'
|
import {Extension} from '@codemirror/state'
|
||||||
import {HighlightStyle, syntaxHighlighting} from '@codemirror/language'
|
import {createBaseTheme} from '../base'
|
||||||
import {tags as t} from '@lezer/highlight'
|
import type {ThemeColors} from '../types'
|
||||||
|
|
||||||
export const config = {
|
export const config: ThemeColors = {
|
||||||
name: 'aura',
|
name: 'aura',
|
||||||
dark: true,
|
dark: true,
|
||||||
|
|
||||||
|
// 基础色调
|
||||||
background: '#21202e',
|
background: '#21202e',
|
||||||
foreground: '#edecee',
|
backgroundSecondary: '#21202e',
|
||||||
selection: '#3d375e7f',
|
surface: '#21202e',
|
||||||
cursor: '#a277ff',
|
|
||||||
dropdownBackground: '#21202e',
|
dropdownBackground: '#21202e',
|
||||||
dropdownBorder: '#3b334b',
|
dropdownBorder: '#3b334b',
|
||||||
activeLine: '#4d4b6622',
|
|
||||||
lineNumber: '#a394f033',
|
// 文本颜色
|
||||||
activeLineNumber: '#cdccce',
|
foreground: '#edecee',
|
||||||
matchingBracket: '#a394f033',
|
foregroundSecondary: '#edecee',
|
||||||
keyword: '#a277ff',
|
|
||||||
storage: '#a277ff',
|
|
||||||
variable: '#edecee',
|
|
||||||
parameter: '#edecee',
|
|
||||||
function: '#ffca85',
|
|
||||||
string: '#61ffca',
|
|
||||||
constant: '#61ffca',
|
|
||||||
type: '#82e2ff',
|
|
||||||
class: '#82e2ff',
|
|
||||||
number: '#61ffca',
|
|
||||||
comment: '#6d6d6d',
|
comment: '#6d6d6d',
|
||||||
|
|
||||||
|
// 语法高亮色 - 核心
|
||||||
|
keyword: '#a277ff',
|
||||||
|
string: '#61ffca',
|
||||||
|
function: '#ffca85',
|
||||||
|
number: '#61ffca',
|
||||||
|
operator: '#a277ff',
|
||||||
|
variable: '#edecee',
|
||||||
|
type: '#82e2ff',
|
||||||
|
|
||||||
|
// 语法高亮色 - 扩展
|
||||||
|
constant: '#61ffca',
|
||||||
|
storage: '#a277ff',
|
||||||
|
parameter: '#edecee',
|
||||||
|
class: '#82e2ff',
|
||||||
heading: '#a277ff',
|
heading: '#a277ff',
|
||||||
invalid: '#ff6767',
|
invalid: '#ff6767',
|
||||||
regexp: '#61ffca',
|
regexp: '#61ffca',
|
||||||
|
|
||||||
|
// 界面元素
|
||||||
|
cursor: '#a277ff',
|
||||||
|
selection: '#3d375e7f',
|
||||||
|
selectionBlur: '#3d375e7f',
|
||||||
|
activeLine: '#4d4b6622',
|
||||||
|
lineNumber: '#a394f033',
|
||||||
|
activeLineNumber: '#cdccce',
|
||||||
|
|
||||||
|
// 边框和分割线
|
||||||
|
borderColor: '#3b334b',
|
||||||
|
borderLight: '#edecee19',
|
||||||
|
|
||||||
|
// 搜索和匹配
|
||||||
|
searchMatch: '#61ffca',
|
||||||
|
matchingBracket: '#a394f033',
|
||||||
}
|
}
|
||||||
|
|
||||||
export const auraTheme = EditorView.theme({
|
// 使用通用主题工厂函数创建 Aura 主题
|
||||||
'&': {
|
export const aura: Extension = createBaseTheme(config)
|
||||||
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.activeLineNumber},
|
|
||||||
|
|
||||||
'.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),
|
|
||||||
]
|
|
||||||
|
|||||||
63
frontend/src/views/editor/theme/dark/default-dark.ts
Normal file
63
frontend/src/views/editor/theme/dark/default-dark.ts
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
import {createBaseTheme} from '../base';
|
||||||
|
import type {ThemeColors} from '../types';
|
||||||
|
|
||||||
|
// 默认深色主题颜色
|
||||||
|
export const defaultDarkColors: ThemeColors = {
|
||||||
|
// 主题信息
|
||||||
|
name: 'default-dark',
|
||||||
|
dark: true,
|
||||||
|
|
||||||
|
// 基础色调
|
||||||
|
background: '#252B37', // 主背景色
|
||||||
|
backgroundSecondary: '#213644', // 次要背景色
|
||||||
|
surface: '#474747', // 面板背景
|
||||||
|
dropdownBackground: '#252B37', // 下拉菜单背景
|
||||||
|
dropdownBorder: '#ffffff19', // 下拉菜单边框
|
||||||
|
|
||||||
|
// 文本颜色
|
||||||
|
foreground: '#9BB586', // 主文本色
|
||||||
|
foregroundSecondary: '#9c9c9c', // 次要文本色
|
||||||
|
comment: '#6272a4', // 注释色
|
||||||
|
|
||||||
|
// 语法高亮色 - 核心
|
||||||
|
keyword: '#ff79c6', // 关键字
|
||||||
|
string: '#f1fa8c', // 字符串
|
||||||
|
function: '#50fa7b', // 函数名
|
||||||
|
number: '#bd93f9', // 数字
|
||||||
|
operator: '#ff79c6', // 操作符
|
||||||
|
variable: '#8fbcbb', // 变量
|
||||||
|
type: '#8be9fd', // 类型
|
||||||
|
|
||||||
|
// 语法高亮色 - 扩展
|
||||||
|
constant: '#bd93f9', // 常量
|
||||||
|
storage: '#ff79c6', // 存储类型
|
||||||
|
parameter: '#8fbcbb', // 参数
|
||||||
|
class: '#8be9fd', // 类名
|
||||||
|
heading: '#ff79c6', // 标题
|
||||||
|
invalid: '#d30102', // 无效内容
|
||||||
|
regexp: '#f1fa8c', // 正则表达式
|
||||||
|
|
||||||
|
// 界面元素
|
||||||
|
cursor: '#ffffff', // 光标
|
||||||
|
selection: '#0865a9', // 选中背景
|
||||||
|
selectionBlur: '#225377', // 失焦选中背景
|
||||||
|
activeLine: '#ffffff0a', // 当前行高亮
|
||||||
|
lineNumber: '#ffffff26', // 行号
|
||||||
|
activeLineNumber: '#ffffff99', // 活动行号
|
||||||
|
|
||||||
|
// 边框和分割线
|
||||||
|
borderColor: '#1e222a', // 边框色
|
||||||
|
borderLight: '#ffffff19', // 浅色边框
|
||||||
|
|
||||||
|
// 搜索和匹配
|
||||||
|
searchMatch: '#8fbcbb', // 搜索匹配
|
||||||
|
matchingBracket: '#ffffff19', // 匹配括号
|
||||||
|
};
|
||||||
|
|
||||||
|
// 创建深色主题
|
||||||
|
export function createDarkTheme(colors: ThemeColors = defaultDarkColors) {
|
||||||
|
return createBaseTheme({...colors, dark: true});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 默认深色主题
|
||||||
|
export const defaultDark = createDarkTheme(defaultDarkColors);
|
||||||
@@ -1,128 +1,57 @@
|
|||||||
import {EditorView} from '@codemirror/view'
|
|
||||||
import {Extension} from '@codemirror/state'
|
import {Extension} from '@codemirror/state'
|
||||||
import {HighlightStyle, syntaxHighlighting} from '@codemirror/language'
|
import {createBaseTheme} from '../base'
|
||||||
import {tags as t} from '@lezer/highlight'
|
import type {ThemeColors} from '../types'
|
||||||
|
|
||||||
export const config = {
|
export const config: ThemeColors = {
|
||||||
name: 'dracula',
|
name: 'dracula',
|
||||||
dark: true,
|
dark: true,
|
||||||
|
|
||||||
|
// 基础色调
|
||||||
background: '#282A36',
|
background: '#282A36',
|
||||||
foreground: '#F8F8F2',
|
backgroundSecondary: '#282A36',
|
||||||
selection: '#44475A',
|
surface: '#282A36',
|
||||||
cursor: '#F8F8F2',
|
|
||||||
dropdownBackground: '#282A36',
|
dropdownBackground: '#282A36',
|
||||||
dropdownBorder: '#191A21',
|
dropdownBorder: '#191A21',
|
||||||
activeLine: '#53576c22',
|
|
||||||
lineNumber: '#6272A4',
|
// 文本颜色
|
||||||
activeLineNumber: '#F8F8F2',
|
foreground: '#F8F8F2',
|
||||||
matchingBracket: '#44475A',
|
foregroundSecondary: '#F8F8F2',
|
||||||
keyword: '#FF79C6',
|
|
||||||
storage: '#FF79C6',
|
|
||||||
variable: '#F8F8F2',
|
|
||||||
parameter: '#F8F8F2',
|
|
||||||
function: '#50FA7B',
|
|
||||||
string: '#F1FA8C',
|
|
||||||
constant: '#BD93F9',
|
|
||||||
type: '#8BE9FD',
|
|
||||||
class: '#8BE9FD',
|
|
||||||
number: '#BD93F9',
|
|
||||||
comment: '#6272A4',
|
comment: '#6272A4',
|
||||||
|
|
||||||
|
// 语法高亮色 - 核心
|
||||||
|
keyword: '#FF79C6',
|
||||||
|
string: '#F1FA8C',
|
||||||
|
function: '#50FA7B',
|
||||||
|
number: '#BD93F9',
|
||||||
|
operator: '#FF79C6',
|
||||||
|
variable: '#F8F8F2',
|
||||||
|
type: '#8BE9FD',
|
||||||
|
|
||||||
|
// 语法高亮色 - 扩展
|
||||||
|
constant: '#BD93F9',
|
||||||
|
storage: '#FF79C6',
|
||||||
|
parameter: '#F8F8F2',
|
||||||
|
class: '#8BE9FD',
|
||||||
heading: '#BD93F9',
|
heading: '#BD93F9',
|
||||||
invalid: '#FF5555',
|
invalid: '#FF5555',
|
||||||
regexp: '#F1FA8C',
|
regexp: '#F1FA8C',
|
||||||
|
|
||||||
|
// 界面元素
|
||||||
|
cursor: '#F8F8F2',
|
||||||
|
selection: '#44475A',
|
||||||
|
selectionBlur: '#44475A',
|
||||||
|
activeLine: '#53576c22',
|
||||||
|
lineNumber: '#6272A4',
|
||||||
|
activeLineNumber: '#F8F8F2',
|
||||||
|
|
||||||
|
// 边框和分割线
|
||||||
|
borderColor: '#191A21',
|
||||||
|
borderLight: '#F8F8F219',
|
||||||
|
|
||||||
|
// 搜索和匹配
|
||||||
|
searchMatch: '#50FA7B',
|
||||||
|
matchingBracket: '#44475A',
|
||||||
}
|
}
|
||||||
|
|
||||||
export const draculaTheme = EditorView.theme({
|
// 使用通用主题工厂函数创建 Dracula 主题
|
||||||
'&': {
|
export const dracula: Extension = createBaseTheme(config)
|
||||||
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.activeLineNumber},
|
|
||||||
|
|
||||||
'.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),
|
|
||||||
]
|
|
||||||
|
|||||||
@@ -1,128 +1,57 @@
|
|||||||
import {EditorView, lineNumbers} from '@codemirror/view'
|
|
||||||
import {Extension} from '@codemirror/state'
|
import {Extension} from '@codemirror/state'
|
||||||
import {HighlightStyle, syntaxHighlighting} from '@codemirror/language'
|
import {createBaseTheme} from '../base'
|
||||||
import {tags as t} from '@lezer/highlight'
|
import type {ThemeColors} from '../types'
|
||||||
|
|
||||||
export const config = {
|
export const config: ThemeColors = {
|
||||||
name: 'githubDark',
|
name: 'github-dark',
|
||||||
dark: true,
|
dark: true,
|
||||||
|
|
||||||
|
// 基础色调
|
||||||
background: '#24292e',
|
background: '#24292e',
|
||||||
foreground: '#d1d5da',
|
backgroundSecondary: '#24292e',
|
||||||
selection: '#3392FF44',
|
surface: '#24292e',
|
||||||
cursor: '#c8e1ff',
|
|
||||||
dropdownBackground: '#24292e',
|
dropdownBackground: '#24292e',
|
||||||
dropdownBorder: '#1b1f23',
|
dropdownBorder: '#1b1f23',
|
||||||
activeLine: '#4d566022',
|
|
||||||
lineNumber: '#444d56',
|
// 文本颜色
|
||||||
activeLineNumber: '#e1e4e8',
|
foreground: '#d1d5da',
|
||||||
matchingBracket: '#17E5E650',
|
foregroundSecondary: '#d1d5da',
|
||||||
keyword: '#f97583',
|
|
||||||
storage: '#f97583',
|
|
||||||
variable: '#ffab70',
|
|
||||||
parameter: '#e1e4e8',
|
|
||||||
function: '#79b8ff',
|
|
||||||
string: '#9ecbff',
|
|
||||||
constant: '#79b8ff',
|
|
||||||
type: '#79b8ff',
|
|
||||||
class: '#b392f0',
|
|
||||||
number: '#79b8ff',
|
|
||||||
comment: '#6a737d',
|
comment: '#6a737d',
|
||||||
|
|
||||||
|
// 语法高亮色 - 核心
|
||||||
|
keyword: '#f97583',
|
||||||
|
string: '#9ecbff',
|
||||||
|
function: '#79b8ff',
|
||||||
|
number: '#79b8ff',
|
||||||
|
operator: '#f97583',
|
||||||
|
variable: '#ffab70',
|
||||||
|
type: '#79b8ff',
|
||||||
|
|
||||||
|
// 语法高亮色 - 扩展
|
||||||
|
constant: '#79b8ff',
|
||||||
|
storage: '#f97583',
|
||||||
|
parameter: '#e1e4e8',
|
||||||
|
class: '#b392f0',
|
||||||
heading: '#79b8ff',
|
heading: '#79b8ff',
|
||||||
invalid: '#f97583',
|
invalid: '#f97583',
|
||||||
regexp: '#9ecbff',
|
regexp: '#9ecbff',
|
||||||
|
|
||||||
|
// 界面元素
|
||||||
|
cursor: '#c8e1ff',
|
||||||
|
selection: '#3392FF44',
|
||||||
|
selectionBlur: '#3392FF44',
|
||||||
|
activeLine: '#4d566022',
|
||||||
|
lineNumber: '#444d56',
|
||||||
|
activeLineNumber: '#e1e4e8',
|
||||||
|
|
||||||
|
// 边框和分割线
|
||||||
|
borderColor: '#1b1f23',
|
||||||
|
borderLight: '#d1d5da19',
|
||||||
|
|
||||||
|
// 搜索和匹配
|
||||||
|
searchMatch: '#79b8ff',
|
||||||
|
matchingBracket: '#17E5E650',
|
||||||
}
|
}
|
||||||
|
|
||||||
export const githubDarkTheme = EditorView.theme({
|
// 使用通用主题工厂函数创建 GitHub Dark 主题
|
||||||
'&': {
|
export const githubDark: Extension = createBaseTheme(config)
|
||||||
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.activeLineNumber},
|
|
||||||
|
|
||||||
'.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),
|
|
||||||
]
|
|
||||||
|
|||||||
@@ -1,128 +1,57 @@
|
|||||||
import {EditorView} from '@codemirror/view'
|
|
||||||
import {Extension} from '@codemirror/state'
|
import {Extension} from '@codemirror/state'
|
||||||
import {HighlightStyle, syntaxHighlighting} from '@codemirror/language'
|
import {createBaseTheme} from '../base'
|
||||||
import {tags as t} from '@lezer/highlight'
|
import type {ThemeColors} from '../types'
|
||||||
|
|
||||||
export const config = {
|
export const config: ThemeColors = {
|
||||||
name: 'materialDark',
|
name: 'material-dark',
|
||||||
dark: true,
|
dark: true,
|
||||||
|
|
||||||
|
// 基础色调
|
||||||
background: '#263238',
|
background: '#263238',
|
||||||
foreground: '#EEFFFF',
|
backgroundSecondary: '#263238',
|
||||||
selection: '#80CBC420',
|
surface: '#263238',
|
||||||
cursor: '#FFCC00',
|
|
||||||
dropdownBackground: '#263238',
|
dropdownBackground: '#263238',
|
||||||
dropdownBorder: '#FFFFFF10',
|
dropdownBorder: '#FFFFFF10',
|
||||||
activeLine: '#4c616c22',
|
|
||||||
lineNumber: '#37474F',
|
// 文本颜色
|
||||||
activeLineNumber: '#607a86',
|
foreground: '#EEFFFF',
|
||||||
matchingBracket: '#263238',
|
foregroundSecondary: '#EEFFFF',
|
||||||
keyword: '#C792EA',
|
|
||||||
storage: '#C792EA',
|
|
||||||
variable: '#EEFFFF',
|
|
||||||
parameter: '#EEFFFF',
|
|
||||||
function: '#82AAFF',
|
|
||||||
string: '#C3E88D',
|
|
||||||
constant: '#F78C6C',
|
|
||||||
type: '#B2CCD6',
|
|
||||||
class: '#FFCB6B',
|
|
||||||
number: '#F78C6C',
|
|
||||||
comment: '#546E7A',
|
comment: '#546E7A',
|
||||||
|
|
||||||
|
// 语法高亮色 - 核心
|
||||||
|
keyword: '#C792EA',
|
||||||
|
string: '#C3E88D',
|
||||||
|
function: '#82AAFF',
|
||||||
|
number: '#F78C6C',
|
||||||
|
operator: '#C792EA',
|
||||||
|
variable: '#EEFFFF',
|
||||||
|
type: '#B2CCD6',
|
||||||
|
|
||||||
|
// 语法高亮色 - 扩展
|
||||||
|
constant: '#F78C6C',
|
||||||
|
storage: '#C792EA',
|
||||||
|
parameter: '#EEFFFF',
|
||||||
|
class: '#FFCB6B',
|
||||||
heading: '#C3E88D',
|
heading: '#C3E88D',
|
||||||
invalid: '#FF5370',
|
invalid: '#FF5370',
|
||||||
regexp: '#89DDFF',
|
regexp: '#89DDFF',
|
||||||
|
|
||||||
|
// 界面元素
|
||||||
|
cursor: '#FFCC00',
|
||||||
|
selection: '#80CBC420',
|
||||||
|
selectionBlur: '#80CBC420',
|
||||||
|
activeLine: '#4c616c22',
|
||||||
|
lineNumber: '#37474F',
|
||||||
|
activeLineNumber: '#607a86',
|
||||||
|
|
||||||
|
// 边框和分割线
|
||||||
|
borderColor: '#FFFFFF10',
|
||||||
|
borderLight: '#EEFFFF19',
|
||||||
|
|
||||||
|
// 搜索和匹配
|
||||||
|
searchMatch: '#82AAFF',
|
||||||
|
matchingBracket: '#263238',
|
||||||
}
|
}
|
||||||
|
|
||||||
export const materialDarkTheme = EditorView.theme({
|
// 使用通用主题工厂函数创建 Material Dark 主题
|
||||||
'&': {
|
export const materialDark: Extension = createBaseTheme(config)
|
||||||
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.activeLineNumber},
|
|
||||||
|
|
||||||
'.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),
|
|
||||||
]
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import {EditorView} from "@codemirror/view"
|
|
||||||
import {Extension} from "@codemirror/state"
|
import {Extension} from "@codemirror/state"
|
||||||
import {HighlightStyle, syntaxHighlighting} from "@codemirror/language"
|
import {createBaseTheme} from '../base'
|
||||||
import {tags as t} from "@lezer/highlight"
|
import type {ThemeColors} from '../types'
|
||||||
|
|
||||||
// Using https://github.com/one-dark/vscode-one-dark-theme/ as reference for the colors
|
// Using https://github.com/one-dark/vscode-one-dark-theme/ as reference for the colors
|
||||||
|
|
||||||
@@ -22,133 +21,56 @@ const chalky = "#e5c07b",
|
|||||||
selection = "#3E4451",
|
selection = "#3E4451",
|
||||||
cursor = "#528bff"
|
cursor = "#528bff"
|
||||||
|
|
||||||
/// The colors used in the theme, as CSS color strings.
|
export const config: ThemeColors = {
|
||||||
export const color = {
|
name: 'one-dark',
|
||||||
chalky,
|
dark: true,
|
||||||
coral,
|
|
||||||
cyan,
|
// 基础色调
|
||||||
invalid,
|
background: background,
|
||||||
ivory,
|
backgroundSecondary: highlightBackground,
|
||||||
stone,
|
surface: tooltipBackground,
|
||||||
malibu,
|
dropdownBackground: darkBackground,
|
||||||
sage,
|
dropdownBorder: stone,
|
||||||
whiskey,
|
|
||||||
violet,
|
// 文本颜色
|
||||||
darkBackground,
|
foreground: ivory,
|
||||||
highlightBackground,
|
foregroundSecondary: stone,
|
||||||
background,
|
comment: stone,
|
||||||
tooltipBackground,
|
|
||||||
selection,
|
// 语法高亮色 - 核心
|
||||||
cursor
|
keyword: violet,
|
||||||
|
string: sage,
|
||||||
|
function: malibu,
|
||||||
|
number: chalky,
|
||||||
|
operator: cyan,
|
||||||
|
variable: coral,
|
||||||
|
type: chalky,
|
||||||
|
|
||||||
|
// 语法高亮色 - 扩展
|
||||||
|
constant: whiskey,
|
||||||
|
storage: violet,
|
||||||
|
parameter: coral,
|
||||||
|
class: chalky,
|
||||||
|
heading: coral,
|
||||||
|
invalid: invalid,
|
||||||
|
regexp: cyan,
|
||||||
|
|
||||||
|
// 界面元素
|
||||||
|
cursor: cursor,
|
||||||
|
selection: selection,
|
||||||
|
selectionBlur: selection,
|
||||||
|
activeLine: '#6699ff0b',
|
||||||
|
lineNumber: stone,
|
||||||
|
activeLineNumber: ivory,
|
||||||
|
|
||||||
|
// 边框和分割线
|
||||||
|
borderColor: darkBackground,
|
||||||
|
borderLight: ivory + '19',
|
||||||
|
|
||||||
|
// 搜索和匹配
|
||||||
|
searchMatch: malibu,
|
||||||
|
matchingBracket: '#bad0f847',
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The editor theme styles for One Dark.
|
// 使用通用主题工厂函数创建 One Dark 主题
|
||||||
export const oneDarkTheme = EditorView.theme({
|
export const oneDark: Extension = createBaseTheme(config)
|
||||||
"&": {
|
|
||||||
color: ivory,
|
|
||||||
backgroundColor: background
|
|
||||||
},
|
|
||||||
|
|
||||||
".cm-content": {
|
|
||||||
caretColor: cursor
|
|
||||||
},
|
|
||||||
|
|
||||||
".cm-cursor, .cm-dropCursor": {borderLeftColor: cursor},
|
|
||||||
"&.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground, .cm-selectionBackground, .cm-content ::selection": {backgroundColor: selection},
|
|
||||||
|
|
||||||
".cm-panels": {backgroundColor: darkBackground, color: ivory},
|
|
||||||
".cm-panels.cm-panels-top": {borderBottom: "2px solid black"},
|
|
||||||
".cm-panels.cm-panels-bottom": {borderTop: "2px solid black"},
|
|
||||||
|
|
||||||
".cm-searchMatch": {
|
|
||||||
backgroundColor: "#72a1ff59",
|
|
||||||
outline: "1px solid #457dff"
|
|
||||||
},
|
|
||||||
".cm-searchMatch.cm-searchMatch-selected": {
|
|
||||||
backgroundColor: "#6199ff2f"
|
|
||||||
},
|
|
||||||
|
|
||||||
".cm-activeLine": {backgroundColor: "#6699ff0b"},
|
|
||||||
".cm-selectionMatch": {backgroundColor: "#aafe661a"},
|
|
||||||
|
|
||||||
"&.cm-focused .cm-matchingBracket, &.cm-focused .cm-nonmatchingBracket": {
|
|
||||||
backgroundColor: "#bad0f847"
|
|
||||||
},
|
|
||||||
|
|
||||||
".cm-gutters": {
|
|
||||||
backgroundColor: background,
|
|
||||||
color: stone,
|
|
||||||
border: "none"
|
|
||||||
},
|
|
||||||
|
|
||||||
".cm-activeLineGutter": {
|
|
||||||
backgroundColor: highlightBackground
|
|
||||||
},
|
|
||||||
|
|
||||||
".cm-foldPlaceholder": {
|
|
||||||
backgroundColor: "transparent",
|
|
||||||
border: "none",
|
|
||||||
color: "#ddd"
|
|
||||||
},
|
|
||||||
|
|
||||||
".cm-tooltip": {
|
|
||||||
border: "none",
|
|
||||||
backgroundColor: tooltipBackground
|
|
||||||
},
|
|
||||||
".cm-tooltip .cm-tooltip-arrow:before": {
|
|
||||||
borderTopColor: "transparent",
|
|
||||||
borderBottomColor: "transparent"
|
|
||||||
},
|
|
||||||
".cm-tooltip .cm-tooltip-arrow:after": {
|
|
||||||
borderTopColor: tooltipBackground,
|
|
||||||
borderBottomColor: tooltipBackground
|
|
||||||
},
|
|
||||||
".cm-tooltip-autocomplete": {
|
|
||||||
"& > ul > li[aria-selected]": {
|
|
||||||
backgroundColor: highlightBackground,
|
|
||||||
color: ivory
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, {dark: true})
|
|
||||||
|
|
||||||
/// The highlighting style for code in the One Dark theme.
|
|
||||||
export const oneDarkHighlightStyle = HighlightStyle.define([
|
|
||||||
{tag: t.keyword,
|
|
||||||
color: violet},
|
|
||||||
{tag: [t.name, t.deleted, t.character, t.propertyName, t.macroName],
|
|
||||||
color: coral},
|
|
||||||
{tag: [t.function(t.variableName), t.labelName],
|
|
||||||
color: malibu},
|
|
||||||
{tag: [t.color, t.constant(t.name), t.standard(t.name)],
|
|
||||||
color: whiskey},
|
|
||||||
{tag: [t.definition(t.name), t.separator],
|
|
||||||
color: ivory},
|
|
||||||
{tag: [t.typeName, t.className, t.number, t.changed, t.annotation, t.modifier, t.self, t.namespace],
|
|
||||||
color: chalky},
|
|
||||||
{tag: [t.operator, t.operatorKeyword, t.url, t.escape, t.regexp, t.link, t.special(t.string)],
|
|
||||||
color: cyan},
|
|
||||||
{tag: [t.meta, t.comment],
|
|
||||||
color: stone},
|
|
||||||
{tag: t.strong,
|
|
||||||
fontWeight: "bold"},
|
|
||||||
{tag: t.emphasis,
|
|
||||||
fontStyle: "italic"},
|
|
||||||
{tag: t.strikethrough,
|
|
||||||
textDecoration: "line-through"},
|
|
||||||
{tag: t.link,
|
|
||||||
color: stone,
|
|
||||||
textDecoration: "underline"},
|
|
||||||
{tag: t.heading,
|
|
||||||
fontWeight: "bold",
|
|
||||||
color: coral},
|
|
||||||
{tag: [t.atom, t.bool, t.special(t.variableName)],
|
|
||||||
color: whiskey },
|
|
||||||
{tag: [t.processingInstruction, t.string, t.inserted],
|
|
||||||
color: sage},
|
|
||||||
{tag: t.invalid,
|
|
||||||
color: invalid},
|
|
||||||
])
|
|
||||||
|
|
||||||
/// Extension to enable the One Dark theme (both the editor theme and
|
|
||||||
/// the highlight style).
|
|
||||||
export const oneDark: Extension = [oneDarkTheme, syntaxHighlighting(oneDarkHighlightStyle)]
|
|
||||||
@@ -1,128 +1,57 @@
|
|||||||
import {EditorView} from '@codemirror/view'
|
|
||||||
import {Extension} from '@codemirror/state'
|
import {Extension} from '@codemirror/state'
|
||||||
import {HighlightStyle, syntaxHighlighting} from '@codemirror/language'
|
import {createBaseTheme} from '../base'
|
||||||
import {tags as t} from '@lezer/highlight'
|
import type {ThemeColors} from '../types'
|
||||||
|
|
||||||
export const config = {
|
export const config: ThemeColors = {
|
||||||
name: 'solarizedDark',
|
name: 'solarized-dark',
|
||||||
dark: true,
|
dark: true,
|
||||||
|
|
||||||
|
// 基础色调
|
||||||
background: '#002B36',
|
background: '#002B36',
|
||||||
foreground: '#93A1A1',
|
backgroundSecondary: '#002B36',
|
||||||
selection: '#274642',
|
surface: '#002B36',
|
||||||
cursor: '#D30102',
|
|
||||||
dropdownBackground: '#002B36',
|
dropdownBackground: '#002B36',
|
||||||
dropdownBorder: '#2AA19899',
|
dropdownBorder: '#2AA19899',
|
||||||
activeLine: '#005b7022',
|
|
||||||
lineNumber: '#93A1A1',
|
// 文本颜色
|
||||||
activeLineNumber: '#949494',
|
foreground: '#93A1A1',
|
||||||
matchingBracket: '#073642',
|
foregroundSecondary: '#93A1A1',
|
||||||
keyword: '#859900',
|
|
||||||
storage: '#93A1A1',
|
|
||||||
variable: '#268BD2',
|
|
||||||
parameter: '#268BD2',
|
|
||||||
function: '#268BD2',
|
|
||||||
string: '#2AA198',
|
|
||||||
constant: '#CB4B16',
|
|
||||||
type: '#CB4B16',
|
|
||||||
class: '#CB4B16',
|
|
||||||
number: '#D33682',
|
|
||||||
comment: '#586E75',
|
comment: '#586E75',
|
||||||
|
|
||||||
|
// 语法高亮色 - 核心
|
||||||
|
keyword: '#859900',
|
||||||
|
string: '#2AA198',
|
||||||
|
function: '#268BD2',
|
||||||
|
number: '#D33682',
|
||||||
|
operator: '#859900',
|
||||||
|
variable: '#268BD2',
|
||||||
|
type: '#CB4B16',
|
||||||
|
|
||||||
|
// 语法高亮色 - 扩展
|
||||||
|
constant: '#CB4B16',
|
||||||
|
storage: '#93A1A1',
|
||||||
|
parameter: '#268BD2',
|
||||||
|
class: '#CB4B16',
|
||||||
heading: '#268BD2',
|
heading: '#268BD2',
|
||||||
invalid: '#DC322F',
|
invalid: '#DC322F',
|
||||||
regexp: '#DC322F',
|
regexp: '#DC322F',
|
||||||
|
|
||||||
|
// 界面元素
|
||||||
|
cursor: '#D30102',
|
||||||
|
selection: '#274642',
|
||||||
|
selectionBlur: '#274642',
|
||||||
|
activeLine: '#005b7022',
|
||||||
|
lineNumber: '#93A1A1',
|
||||||
|
activeLineNumber: '#949494',
|
||||||
|
|
||||||
|
// 边框和分割线
|
||||||
|
borderColor: '#073642',
|
||||||
|
borderLight: '#93A1A119',
|
||||||
|
|
||||||
|
// 搜索和匹配
|
||||||
|
searchMatch: '#2AA198',
|
||||||
|
matchingBracket: '#073642',
|
||||||
}
|
}
|
||||||
|
|
||||||
export const solarizedDarkTheme = EditorView.theme({
|
// 使用通用主题工厂函数创建 Solarized Dark 主题
|
||||||
'&': {
|
export const solarizedDark: Extension = createBaseTheme(config)
|
||||||
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.activeLineNumber},
|
|
||||||
|
|
||||||
'.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),
|
|
||||||
]
|
|
||||||
|
|||||||
@@ -1,128 +1,57 @@
|
|||||||
import {EditorView} from '@codemirror/view'
|
|
||||||
import {Extension} from '@codemirror/state'
|
import {Extension} from '@codemirror/state'
|
||||||
import {HighlightStyle, syntaxHighlighting} from '@codemirror/language'
|
import {createBaseTheme} from '../base'
|
||||||
import {tags as t} from '@lezer/highlight'
|
import type {ThemeColors} from '../types'
|
||||||
|
|
||||||
export const config = {
|
export const config: ThemeColors = {
|
||||||
name: 'tokyoNightStorm',
|
name: 'tokyo-night-storm',
|
||||||
dark: true,
|
dark: true,
|
||||||
|
|
||||||
|
// 基础色调
|
||||||
background: '#24283b',
|
background: '#24283b',
|
||||||
foreground: '#7982a9',
|
backgroundSecondary: '#24283b',
|
||||||
selection: '#6f7bb630',
|
surface: '#24283b',
|
||||||
cursor: '#c0caf5',
|
|
||||||
dropdownBackground: '#24283b',
|
dropdownBackground: '#24283b',
|
||||||
dropdownBorder: '#7982a9',
|
dropdownBorder: '#7982a9',
|
||||||
activeLine: '#4d547722',
|
|
||||||
lineNumber: '#3b4261',
|
// 文本颜色
|
||||||
activeLineNumber: '#737aa2',
|
foreground: '#7982a9',
|
||||||
matchingBracket: '#1f2335',
|
foregroundSecondary: '#7982a9',
|
||||||
keyword: '#bb9af7',
|
|
||||||
storage: '#bb9af7',
|
|
||||||
variable: '#c0caf5',
|
|
||||||
parameter: '#c0caf5',
|
|
||||||
function: '#7aa2f7',
|
|
||||||
string: '#9ece6a',
|
|
||||||
constant: '#bb9af7',
|
|
||||||
type: '#2ac3de',
|
|
||||||
class: '#c0caf5',
|
|
||||||
number: '#ff9e64',
|
|
||||||
comment: '#565f89',
|
comment: '#565f89',
|
||||||
|
|
||||||
|
// 语法高亮色 - 核心
|
||||||
|
keyword: '#bb9af7',
|
||||||
|
string: '#9ece6a',
|
||||||
|
function: '#7aa2f7',
|
||||||
|
number: '#ff9e64',
|
||||||
|
operator: '#bb9af7',
|
||||||
|
variable: '#c0caf5',
|
||||||
|
type: '#2ac3de',
|
||||||
|
|
||||||
|
// 语法高亮色 - 扩展
|
||||||
|
constant: '#bb9af7',
|
||||||
|
storage: '#bb9af7',
|
||||||
|
parameter: '#c0caf5',
|
||||||
|
class: '#c0caf5',
|
||||||
heading: '#89ddff',
|
heading: '#89ddff',
|
||||||
invalid: '#ff5370',
|
invalid: '#ff5370',
|
||||||
regexp: '#b4f9f8',
|
regexp: '#b4f9f8',
|
||||||
|
|
||||||
|
// 界面元素
|
||||||
|
cursor: '#c0caf5',
|
||||||
|
selection: '#6f7bb630',
|
||||||
|
selectionBlur: '#6f7bb630',
|
||||||
|
activeLine: '#4d547722',
|
||||||
|
lineNumber: '#3b4261',
|
||||||
|
activeLineNumber: '#737aa2',
|
||||||
|
|
||||||
|
// 边框和分割线
|
||||||
|
borderColor: '#1f2335',
|
||||||
|
borderLight: '#7982a919',
|
||||||
|
|
||||||
|
// 搜索和匹配
|
||||||
|
searchMatch: '#7aa2f7',
|
||||||
|
matchingBracket: '#1f2335',
|
||||||
}
|
}
|
||||||
|
|
||||||
export const tokyoNightStormTheme = EditorView.theme({
|
// 使用通用主题工厂函数创建 Tokyo Night Storm 主题
|
||||||
'&': {
|
export const tokyoNightStorm: Extension = createBaseTheme(config)
|
||||||
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.activeLineNumber},
|
|
||||||
|
|
||||||
'.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),
|
|
||||||
]
|
|
||||||
|
|||||||
@@ -1,128 +1,57 @@
|
|||||||
import {EditorView} from '@codemirror/view'
|
|
||||||
import {Extension} from '@codemirror/state'
|
import {Extension} from '@codemirror/state'
|
||||||
import {HighlightStyle, syntaxHighlighting} from '@codemirror/language'
|
import {createBaseTheme} from '../base'
|
||||||
import {tags as t} from '@lezer/highlight'
|
import type {ThemeColors} from '../types'
|
||||||
|
|
||||||
export const config = {
|
export const config: ThemeColors = {
|
||||||
name: 'tokyoNight',
|
name: 'tokyo-night',
|
||||||
dark: true,
|
dark: true,
|
||||||
|
|
||||||
|
// 基础色调
|
||||||
background: '#1a1b26',
|
background: '#1a1b26',
|
||||||
foreground: '#787c99',
|
backgroundSecondary: '#1a1b26',
|
||||||
selection: '#515c7e40',
|
surface: '#1a1b26',
|
||||||
cursor: '#c0caf5',
|
|
||||||
dropdownBackground: '#1a1b26',
|
dropdownBackground: '#1a1b26',
|
||||||
dropdownBorder: '#787c99',
|
dropdownBorder: '#787c99',
|
||||||
activeLine: '#43455c22',
|
|
||||||
lineNumber: '#363b54',
|
// 文本颜色
|
||||||
activeLineNumber: '#737aa2',
|
foreground: '#787c99',
|
||||||
matchingBracket: '#16161e',
|
foregroundSecondary: '#787c99',
|
||||||
keyword: '#bb9af7',
|
|
||||||
storage: '#bb9af7',
|
|
||||||
variable: '#c0caf5',
|
|
||||||
parameter: '#c0caf5',
|
|
||||||
function: '#7aa2f7',
|
|
||||||
string: '#9ece6a',
|
|
||||||
constant: '#bb9af7',
|
|
||||||
type: '#0db9d7',
|
|
||||||
class: '#c0caf5',
|
|
||||||
number: '#ff9e64',
|
|
||||||
comment: '#444b6a',
|
comment: '#444b6a',
|
||||||
|
|
||||||
|
// 语法高亮色 - 核心
|
||||||
|
keyword: '#bb9af7',
|
||||||
|
string: '#9ece6a',
|
||||||
|
function: '#7aa2f7',
|
||||||
|
number: '#ff9e64',
|
||||||
|
operator: '#bb9af7',
|
||||||
|
variable: '#c0caf5',
|
||||||
|
type: '#0db9d7',
|
||||||
|
|
||||||
|
// 语法高亮色 - 扩展
|
||||||
|
constant: '#bb9af7',
|
||||||
|
storage: '#bb9af7',
|
||||||
|
parameter: '#c0caf5',
|
||||||
|
class: '#c0caf5',
|
||||||
heading: '#89ddff',
|
heading: '#89ddff',
|
||||||
invalid: '#ff5370',
|
invalid: '#ff5370',
|
||||||
regexp: '#b4f9f8',
|
regexp: '#b4f9f8',
|
||||||
|
|
||||||
|
// 界面元素
|
||||||
|
cursor: '#c0caf5',
|
||||||
|
selection: '#515c7e40',
|
||||||
|
selectionBlur: '#515c7e40',
|
||||||
|
activeLine: '#43455c22',
|
||||||
|
lineNumber: '#363b54',
|
||||||
|
activeLineNumber: '#737aa2',
|
||||||
|
|
||||||
|
// 边框和分割线
|
||||||
|
borderColor: '#16161e',
|
||||||
|
borderLight: '#787c9919',
|
||||||
|
|
||||||
|
// 搜索和匹配
|
||||||
|
searchMatch: '#7aa2f7',
|
||||||
|
matchingBracket: '#16161e',
|
||||||
}
|
}
|
||||||
|
|
||||||
export const tokyoNightTheme = EditorView.theme({
|
// 使用通用主题工厂函数创建 Tokyo Night 主题
|
||||||
'&': {
|
export const tokyoNight: Extension = createBaseTheme(config)
|
||||||
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.activeLineNumber},
|
|
||||||
|
|
||||||
'.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),
|
|
||||||
]
|
|
||||||
|
|||||||
@@ -1,273 +0,0 @@
|
|||||||
import {EditorView} from '@codemirror/view';
|
|
||||||
import {HighlightStyle, syntaxHighlighting} from '@codemirror/language';
|
|
||||||
import {tags} from '@lezer/highlight';
|
|
||||||
|
|
||||||
// 默认浅色主题颜色
|
|
||||||
export const defaultLightColors = {
|
|
||||||
// 基础色调
|
|
||||||
background: '#ffffff', // 主背景色
|
|
||||||
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: '#000000', // 光标
|
|
||||||
selection: '#77baff', // 选中背景
|
|
||||||
selectionBlur: '#b2c2ca', // 失焦选中背景
|
|
||||||
activeLine: '#0000000a', // 当前行高亮
|
|
||||||
lineNumber: '#00000040', // 行号
|
|
||||||
activeLineNumber: '#000000aa', // 活动行号
|
|
||||||
|
|
||||||
// 边框和分割线
|
|
||||||
borderColor: '#dfdfdf', // 边框色
|
|
||||||
borderLight: '#0000000c', // 浅色边框
|
|
||||||
|
|
||||||
// 搜索和匹配
|
|
||||||
searchMatch: '#005cc5', // 搜索匹配
|
|
||||||
matchingBracket: '#00000019', // 匹配括号
|
|
||||||
};
|
|
||||||
|
|
||||||
// 创建浅色主题
|
|
||||||
export function createLightTheme(colors = defaultLightColors) {
|
|
||||||
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.borderColor}`,
|
|
||||||
},
|
|
||||||
'.code-blocks-layer .block-even:first-child': {
|
|
||||||
borderTop: 'none',
|
|
||||||
},
|
|
||||||
'.code-blocks-layer .block-odd': {
|
|
||||||
background: colors.backgroundSecondary,
|
|
||||||
borderTop: `1px solid ${colors.borderColor}`,
|
|
||||||
},
|
|
||||||
'.code-blocks-math-result': {
|
|
||||||
paddingLeft: "12px",
|
|
||||||
position: "relative",
|
|
||||||
},
|
|
||||||
'.code-blocks-math-result .inner': {
|
|
||||||
background: '#48b57e',
|
|
||||||
color: '#fff',
|
|
||||||
padding: '0px 4px',
|
|
||||||
borderRadius: '2px',
|
|
||||||
boxShadow: '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: "rgba(0,0,0, 0.8)",
|
|
||||||
},
|
|
||||||
'.code-blocks-math-result-copied.fade-out': {
|
|
||||||
opacity: 0,
|
|
||||||
},
|
|
||||||
|
|
||||||
// 代码块开始标记
|
|
||||||
'.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'},
|
|
||||||
]);
|
|
||||||
|
|
||||||
return [
|
|
||||||
lightTheme,
|
|
||||||
syntaxHighlighting(lightHighlightStyle),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
// 默认浅色主题
|
|
||||||
export const light = createLightTheme(defaultLightColors);
|
|
||||||
63
frontend/src/views/editor/theme/light/default-light.ts
Normal file
63
frontend/src/views/editor/theme/light/default-light.ts
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
import {createBaseTheme} from '../base';
|
||||||
|
import type {ThemeColors} from '../types';
|
||||||
|
|
||||||
|
// 默认浅色主题颜色
|
||||||
|
export const defaultLightColors: ThemeColors = {
|
||||||
|
// 主题信息
|
||||||
|
name: 'default-light',
|
||||||
|
dark: false,
|
||||||
|
|
||||||
|
// 基础色调
|
||||||
|
background: '#ffffff', // 主背景色
|
||||||
|
backgroundSecondary: '#f1faf1', // 次要背景色
|
||||||
|
surface: '#f5f5f5', // 面板背景
|
||||||
|
dropdownBackground: '#ffffff', // 下拉菜单背景
|
||||||
|
dropdownBorder: '#e1e4e8', // 下拉菜单边框
|
||||||
|
|
||||||
|
// 文本颜色
|
||||||
|
foreground: '#444d56', // 主文本色
|
||||||
|
foregroundSecondary: '#6a737d', // 次要文本色
|
||||||
|
comment: '#6a737d', // 注释色
|
||||||
|
|
||||||
|
// 语法高亮色 - 核心
|
||||||
|
keyword: '#d73a49', // 关键字
|
||||||
|
string: '#032f62', // 字符串
|
||||||
|
function: '#005cc5', // 函数名
|
||||||
|
number: '#005cc5', // 数字
|
||||||
|
operator: '#d73a49', // 操作符
|
||||||
|
variable: '#24292e', // 变量
|
||||||
|
type: '#6f42c1', // 类型
|
||||||
|
|
||||||
|
// 语法高亮色 - 扩展
|
||||||
|
constant: '#005cc5', // 常量
|
||||||
|
storage: '#d73a49', // 存储类型
|
||||||
|
parameter: '#24292e', // 参数
|
||||||
|
class: '#6f42c1', // 类名
|
||||||
|
heading: '#d73a49', // 标题
|
||||||
|
invalid: '#cb2431', // 无效内容
|
||||||
|
regexp: '#032f62', // 正则表达式
|
||||||
|
|
||||||
|
// 界面元素
|
||||||
|
cursor: '#000000', // 光标
|
||||||
|
selection: '#77baff', // 选中背景
|
||||||
|
selectionBlur: '#b2c2ca', // 失焦选中背景
|
||||||
|
activeLine: '#0000000a', // 当前行高亮
|
||||||
|
lineNumber: '#00000040', // 行号
|
||||||
|
activeLineNumber: '#000000aa', // 活动行号
|
||||||
|
|
||||||
|
// 边框和分割线
|
||||||
|
borderColor: '#dfdfdf', // 边框色
|
||||||
|
borderLight: '#0000000c', // 浅色边框
|
||||||
|
|
||||||
|
// 搜索和匹配
|
||||||
|
searchMatch: '#005cc5', // 搜索匹配
|
||||||
|
matchingBracket: '#00000019', // 匹配括号
|
||||||
|
};
|
||||||
|
|
||||||
|
// 创建浅色主题
|
||||||
|
export function createLightTheme(colors: ThemeColors = defaultLightColors) {
|
||||||
|
return createBaseTheme({...colors, dark: false});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 默认浅色主题
|
||||||
|
export const defaultLight = createLightTheme(defaultLightColors);
|
||||||
@@ -1,128 +1,57 @@
|
|||||||
import {EditorView} from '@codemirror/view'
|
|
||||||
import {Extension} from '@codemirror/state'
|
import {Extension} from '@codemirror/state'
|
||||||
import {HighlightStyle, syntaxHighlighting} from '@codemirror/language'
|
import {createBaseTheme} from '../base'
|
||||||
import {tags as t} from '@lezer/highlight'
|
import type {ThemeColors} from '../types'
|
||||||
|
|
||||||
export const config = {
|
export const config: ThemeColors = {
|
||||||
name: 'githubLight',
|
name: 'github-light',
|
||||||
dark: false,
|
dark: false,
|
||||||
|
|
||||||
|
// 基础色调
|
||||||
background: '#fff',
|
background: '#fff',
|
||||||
foreground: '#444d56',
|
backgroundSecondary: '#fff',
|
||||||
selection: '#0366d625',
|
surface: '#fff',
|
||||||
cursor: '#044289',
|
|
||||||
dropdownBackground: '#fff',
|
dropdownBackground: '#fff',
|
||||||
dropdownBorder: '#e1e4e8',
|
dropdownBorder: '#e1e4e8',
|
||||||
activeLine: '#c6c6c622',
|
|
||||||
lineNumber: '#1b1f234d',
|
// 文本颜色
|
||||||
activeLineNumber: '#24292e',
|
foreground: '#444d56',
|
||||||
matchingBracket: '#34d05840',
|
foregroundSecondary: '#444d56',
|
||||||
keyword: '#d73a49',
|
|
||||||
storage: '#d73a49',
|
|
||||||
variable: '#e36209',
|
|
||||||
parameter: '#24292e',
|
|
||||||
function: '#005cc5',
|
|
||||||
string: '#032f62',
|
|
||||||
constant: '#005cc5',
|
|
||||||
type: '#005cc5',
|
|
||||||
class: '#6f42c1',
|
|
||||||
number: '#005cc5',
|
|
||||||
comment: '#6a737d',
|
comment: '#6a737d',
|
||||||
|
|
||||||
|
// 语法高亮色 - 核心
|
||||||
|
keyword: '#d73a49',
|
||||||
|
string: '#032f62',
|
||||||
|
function: '#005cc5',
|
||||||
|
number: '#005cc5',
|
||||||
|
operator: '#d73a49',
|
||||||
|
variable: '#e36209',
|
||||||
|
type: '#005cc5',
|
||||||
|
|
||||||
|
// 语法高亮色 - 扩展
|
||||||
|
constant: '#005cc5',
|
||||||
|
storage: '#d73a49',
|
||||||
|
parameter: '#24292e',
|
||||||
|
class: '#6f42c1',
|
||||||
heading: '#005cc5',
|
heading: '#005cc5',
|
||||||
invalid: '#cb2431',
|
invalid: '#cb2431',
|
||||||
regexp: '#032f62',
|
regexp: '#032f62',
|
||||||
|
|
||||||
|
// 界面元素
|
||||||
|
cursor: '#044289',
|
||||||
|
selection: '#0366d625',
|
||||||
|
selectionBlur: '#0366d625',
|
||||||
|
activeLine: '#c6c6c622',
|
||||||
|
lineNumber: '#1b1f234d',
|
||||||
|
activeLineNumber: '#24292e',
|
||||||
|
|
||||||
|
// 边框和分割线
|
||||||
|
borderColor: '#e1e4e8',
|
||||||
|
borderLight: '#444d5619',
|
||||||
|
|
||||||
|
// 搜索和匹配
|
||||||
|
searchMatch: '#005cc5',
|
||||||
|
matchingBracket: '#34d05840',
|
||||||
}
|
}
|
||||||
|
|
||||||
export const githubLightTheme = EditorView.theme({
|
// 使用通用主题工厂函数创建 GitHub Light 主题
|
||||||
'&': {
|
export const githubLight: Extension = createBaseTheme(config)
|
||||||
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.activeLineNumber},
|
|
||||||
|
|
||||||
'.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),
|
|
||||||
]
|
|
||||||
|
|||||||
@@ -1,128 +1,57 @@
|
|||||||
import {EditorView} from '@codemirror/view'
|
|
||||||
import {Extension} from '@codemirror/state'
|
import {Extension} from '@codemirror/state'
|
||||||
import {HighlightStyle, syntaxHighlighting} from '@codemirror/language'
|
import {createBaseTheme} from '../base'
|
||||||
import {tags as t} from '@lezer/highlight'
|
import type {ThemeColors} from '../types'
|
||||||
|
|
||||||
export const config = {
|
export const config: ThemeColors = {
|
||||||
name: 'materialLight',
|
name: 'material-light',
|
||||||
dark: false,
|
dark: false,
|
||||||
|
|
||||||
|
// 基础色调
|
||||||
background: '#FAFAFA',
|
background: '#FAFAFA',
|
||||||
foreground: '#90A4AE',
|
backgroundSecondary: '#FAFAFA',
|
||||||
selection: '#80CBC440',
|
surface: '#FAFAFA',
|
||||||
cursor: '#272727',
|
|
||||||
dropdownBackground: '#FAFAFA',
|
dropdownBackground: '#FAFAFA',
|
||||||
dropdownBorder: '#00000010',
|
dropdownBorder: '#00000010',
|
||||||
activeLine: '#c2c2c222',
|
|
||||||
lineNumber: '#CFD8DC',
|
// 文本颜色
|
||||||
activeLineNumber: '#7E939E',
|
foreground: '#90A4AE',
|
||||||
matchingBracket: '#FAFAFA',
|
foregroundSecondary: '#90A4AE',
|
||||||
keyword: '#7C4DFF',
|
|
||||||
storage: '#7C4DFF',
|
|
||||||
variable: '#90A4AE',
|
|
||||||
parameter: '#90A4AE',
|
|
||||||
function: '#6182B8',
|
|
||||||
string: '#91B859',
|
|
||||||
constant: '#F76D47',
|
|
||||||
type: '#8796B0',
|
|
||||||
class: '#FFB62C',
|
|
||||||
number: '#F76D47',
|
|
||||||
comment: '#90A4AE',
|
comment: '#90A4AE',
|
||||||
|
|
||||||
|
// 语法高亮色 - 核心
|
||||||
|
keyword: '#7C4DFF',
|
||||||
|
string: '#91B859',
|
||||||
|
function: '#6182B8',
|
||||||
|
number: '#F76D47',
|
||||||
|
operator: '#7C4DFF',
|
||||||
|
variable: '#90A4AE',
|
||||||
|
type: '#8796B0',
|
||||||
|
|
||||||
|
// 语法高亮色 - 扩展
|
||||||
|
constant: '#F76D47',
|
||||||
|
storage: '#7C4DFF',
|
||||||
|
parameter: '#90A4AE',
|
||||||
|
class: '#FFB62C',
|
||||||
heading: '#91B859',
|
heading: '#91B859',
|
||||||
invalid: '#E53935',
|
invalid: '#E53935',
|
||||||
regexp: '#39ADB5',
|
regexp: '#39ADB5',
|
||||||
|
|
||||||
|
// 界面元素
|
||||||
|
cursor: '#272727',
|
||||||
|
selection: '#80CBC440',
|
||||||
|
selectionBlur: '#80CBC440',
|
||||||
|
activeLine: '#c2c2c222',
|
||||||
|
lineNumber: '#CFD8DC',
|
||||||
|
activeLineNumber: '#7E939E',
|
||||||
|
|
||||||
|
// 边框和分割线
|
||||||
|
borderColor: '#00000010',
|
||||||
|
borderLight: '#90A4AE19',
|
||||||
|
|
||||||
|
// 搜索和匹配
|
||||||
|
searchMatch: '#6182B8',
|
||||||
|
matchingBracket: '#FAFAFA',
|
||||||
}
|
}
|
||||||
|
|
||||||
export const materialLightTheme = EditorView.theme({
|
// 使用通用主题工厂函数创建 Material Light 主题
|
||||||
'&': {
|
export const materialLight: Extension = createBaseTheme(config)
|
||||||
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.activeLineNumber},
|
|
||||||
|
|
||||||
'.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),
|
|
||||||
]
|
|
||||||
|
|||||||
@@ -1,128 +1,57 @@
|
|||||||
import {EditorView} from '@codemirror/view'
|
|
||||||
import {Extension} from '@codemirror/state'
|
import {Extension} from '@codemirror/state'
|
||||||
import {HighlightStyle, syntaxHighlighting} from '@codemirror/language'
|
import {createBaseTheme} from '../base'
|
||||||
import {tags as t} from '@lezer/highlight'
|
import type {ThemeColors} from '../types'
|
||||||
|
|
||||||
export const config = {
|
export const config: ThemeColors = {
|
||||||
name: 'solarizedLight',
|
name: 'solarized-light',
|
||||||
dark: false,
|
dark: false,
|
||||||
|
|
||||||
|
// 基础色调
|
||||||
background: '#FDF6E3',
|
background: '#FDF6E3',
|
||||||
foreground: '#586E75',
|
backgroundSecondary: '#FDF6E3',
|
||||||
selection: '#EEE8D5',
|
surface: '#FDF6E3',
|
||||||
cursor: '#657B83',
|
|
||||||
dropdownBackground: '#FDF6E3',
|
dropdownBackground: '#FDF6E3',
|
||||||
dropdownBorder: '#D3AF86',
|
dropdownBorder: '#D3AF86',
|
||||||
activeLine: '#d5bd5c22',
|
|
||||||
lineNumber: '#586E75',
|
// 文本颜色
|
||||||
activeLineNumber: '#567983',
|
foreground: '#586E75',
|
||||||
matchingBracket: '#EEE8D5',
|
foregroundSecondary: '#586E75',
|
||||||
keyword: '#859900',
|
|
||||||
storage: '#586E75',
|
|
||||||
variable: '#268BD2',
|
|
||||||
parameter: '#268BD2',
|
|
||||||
function: '#268BD2',
|
|
||||||
string: '#2AA198',
|
|
||||||
constant: '#CB4B16',
|
|
||||||
type: '#CB4B16',
|
|
||||||
class: '#CB4B16',
|
|
||||||
number: '#D33682',
|
|
||||||
comment: '#93A1A1',
|
comment: '#93A1A1',
|
||||||
|
|
||||||
|
// 语法高亮色 - 核心
|
||||||
|
keyword: '#859900',
|
||||||
|
string: '#2AA198',
|
||||||
|
function: '#268BD2',
|
||||||
|
number: '#D33682',
|
||||||
|
operator: '#859900',
|
||||||
|
variable: '#268BD2',
|
||||||
|
type: '#CB4B16',
|
||||||
|
|
||||||
|
// 语法高亮色 - 扩展
|
||||||
|
constant: '#CB4B16',
|
||||||
|
storage: '#586E75',
|
||||||
|
parameter: '#268BD2',
|
||||||
|
class: '#CB4B16',
|
||||||
heading: '#268BD2',
|
heading: '#268BD2',
|
||||||
invalid: '#DC322F',
|
invalid: '#DC322F',
|
||||||
regexp: '#DC322F',
|
regexp: '#DC322F',
|
||||||
|
|
||||||
|
// 界面元素
|
||||||
|
cursor: '#657B83',
|
||||||
|
selection: '#EEE8D5',
|
||||||
|
selectionBlur: '#EEE8D5',
|
||||||
|
activeLine: '#d5bd5c22',
|
||||||
|
lineNumber: '#586E75',
|
||||||
|
activeLineNumber: '#567983',
|
||||||
|
|
||||||
|
// 边框和分割线
|
||||||
|
borderColor: '#EEE8D5',
|
||||||
|
borderLight: '#586E7519',
|
||||||
|
|
||||||
|
// 搜索和匹配
|
||||||
|
searchMatch: '#268BD2',
|
||||||
|
matchingBracket: '#EEE8D5',
|
||||||
}
|
}
|
||||||
|
|
||||||
export const solarizedLightTheme = EditorView.theme({
|
// 使用通用主题工厂函数创建 Solarized Light 主题
|
||||||
'&': {
|
export const solarizedLight: Extension = createBaseTheme(config)
|
||||||
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.activeLineNumber},
|
|
||||||
|
|
||||||
'.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),
|
|
||||||
]
|
|
||||||
|
|||||||
@@ -1,128 +1,57 @@
|
|||||||
import {EditorView} from '@codemirror/view'
|
|
||||||
import {Extension} from '@codemirror/state'
|
import {Extension} from '@codemirror/state'
|
||||||
import {HighlightStyle, syntaxHighlighting} from '@codemirror/language'
|
import {createBaseTheme} from '../base'
|
||||||
import {tags as t} from '@lezer/highlight'
|
import type {ThemeColors} from '../types'
|
||||||
|
|
||||||
export const config = {
|
export const config: ThemeColors = {
|
||||||
name: 'tokyoNightDay',
|
name: 'tokyo-night-day',
|
||||||
dark: false,
|
dark: false,
|
||||||
|
|
||||||
|
// 基础色调
|
||||||
background: '#e1e2e7',
|
background: '#e1e2e7',
|
||||||
foreground: '#6a6f8e',
|
backgroundSecondary: '#e1e2e7',
|
||||||
selection: '#8591b840',
|
surface: '#e1e2e7',
|
||||||
cursor: '#3760bf',
|
|
||||||
dropdownBackground: '#e1e2e7',
|
dropdownBackground: '#e1e2e7',
|
||||||
dropdownBorder: '#6a6f8e',
|
dropdownBorder: '#6a6f8e',
|
||||||
activeLine: '#a7aaba22',
|
|
||||||
lineNumber: '#b3b6cd',
|
// 文本颜色
|
||||||
activeLineNumber: '#68709a',
|
foreground: '#6a6f8e',
|
||||||
matchingBracket: '#e9e9ec',
|
foregroundSecondary: '#6a6f8e',
|
||||||
keyword: '#9854f1',
|
|
||||||
storage: '#9854f1',
|
|
||||||
variable: '#3760bf',
|
|
||||||
parameter: '#3760bf',
|
|
||||||
function: '#2e7de9',
|
|
||||||
string: '#587539',
|
|
||||||
constant: '#9854f1',
|
|
||||||
type: '#07879d',
|
|
||||||
class: '#3760bf',
|
|
||||||
number: '#b15c00',
|
|
||||||
comment: '#9da3c2',
|
comment: '#9da3c2',
|
||||||
|
|
||||||
|
// 语法高亮色 - 核心
|
||||||
|
keyword: '#9854f1',
|
||||||
|
string: '#587539',
|
||||||
|
function: '#2e7de9',
|
||||||
|
number: '#b15c00',
|
||||||
|
operator: '#9854f1',
|
||||||
|
variable: '#3760bf',
|
||||||
|
type: '#07879d',
|
||||||
|
|
||||||
|
// 语法高亮色 - 扩展
|
||||||
|
constant: '#9854f1',
|
||||||
|
storage: '#9854f1',
|
||||||
|
parameter: '#3760bf',
|
||||||
|
class: '#3760bf',
|
||||||
heading: '#006a83',
|
heading: '#006a83',
|
||||||
invalid: '#ff3e64',
|
invalid: '#ff3e64',
|
||||||
regexp: '#2e5857',
|
regexp: '#2e5857',
|
||||||
|
|
||||||
|
// 界面元素
|
||||||
|
cursor: '#3760bf',
|
||||||
|
selection: '#8591b840',
|
||||||
|
selectionBlur: '#8591b840',
|
||||||
|
activeLine: '#a7aaba22',
|
||||||
|
lineNumber: '#b3b6cd',
|
||||||
|
activeLineNumber: '#68709a',
|
||||||
|
|
||||||
|
// 边框和分割线
|
||||||
|
borderColor: '#e9e9ec',
|
||||||
|
borderLight: '#6a6f8e19',
|
||||||
|
|
||||||
|
// 搜索和匹配
|
||||||
|
searchMatch: '#2e7de9',
|
||||||
|
matchingBracket: '#e9e9ec',
|
||||||
}
|
}
|
||||||
|
|
||||||
export const tokyoNightDayTheme = EditorView.theme({
|
// 使用通用主题工厂函数创建 Tokyo Night Day 主题
|
||||||
'&': {
|
export const tokyoNightDay: Extension = createBaseTheme(config)
|
||||||
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.activeLineNumber},
|
|
||||||
|
|
||||||
'.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),
|
|
||||||
]
|
|
||||||
|
|||||||
59
frontend/src/views/editor/theme/registry.ts
Normal file
59
frontend/src/views/editor/theme/registry.ts
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
import { Extension } from '@codemirror/state';
|
||||||
|
import type { ThemeColors } from './types';
|
||||||
|
import { createBaseTheme } from './base';
|
||||||
|
|
||||||
|
// 深色主题导入
|
||||||
|
import { config as draculaConfig } from './dark/dracula';
|
||||||
|
import { config as auraConfig } from './dark/aura';
|
||||||
|
import { config as githubDarkConfig } from './dark/github-dark';
|
||||||
|
import { config as materialDarkConfig } from './dark/material-dark';
|
||||||
|
import { config as oneDarkConfig } from './dark/one-dark';
|
||||||
|
import { config as solarizedDarkConfig } from './dark/solarized-dark';
|
||||||
|
import { config as tokyoNightConfig } from './dark/tokyo-night';
|
||||||
|
import { config as tokyoNightStormConfig } from './dark/tokyo-night-storm';
|
||||||
|
|
||||||
|
// 浅色主题导入
|
||||||
|
import { config as githubLightConfig } from './light/github-light';
|
||||||
|
import { config as materialLightConfig } from './light/material-light';
|
||||||
|
import { config as solarizedLightConfig } from './light/solarized-light';
|
||||||
|
import { config as tokyoNightDayConfig } from './light/tokyo-night-day';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 主题配置映射表
|
||||||
|
* key: 主题名称(与数据库中的 name 字段一致)
|
||||||
|
* value: 主题颜色配置
|
||||||
|
*/
|
||||||
|
const themeConfigMap: Record<string, ThemeColors> = {
|
||||||
|
// 深色主题
|
||||||
|
'dracula': draculaConfig,
|
||||||
|
'aura': auraConfig,
|
||||||
|
'github-dark': githubDarkConfig,
|
||||||
|
'material-dark': materialDarkConfig,
|
||||||
|
'one-dark': oneDarkConfig,
|
||||||
|
'solarized-dark': solarizedDarkConfig,
|
||||||
|
'tokyo-night': tokyoNightConfig,
|
||||||
|
'tokyo-night-storm': tokyoNightStormConfig,
|
||||||
|
|
||||||
|
// 浅色主题
|
||||||
|
'github-light': githubLightConfig,
|
||||||
|
'material-light': materialLightConfig,
|
||||||
|
'solarized-light': solarizedLightConfig,
|
||||||
|
'tokyo-night-day': tokyoNightDayConfig,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据主题名称获取主题配置
|
||||||
|
*/
|
||||||
|
export function getThemeConfig(themeName: string): ThemeColors | null {
|
||||||
|
return themeConfigMap[themeName] || null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据自定义颜色配置创建主题
|
||||||
|
*/
|
||||||
|
export function createThemeByColors(colors: ThemeColors): Extension {
|
||||||
|
return createBaseTheme(colors);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1,50 +1,52 @@
|
|||||||
export interface ThemeColors {
|
export interface ThemeColors {
|
||||||
// 主题基本信息
|
// 主题基本信息
|
||||||
name?: string; // 主题名称
|
name: string; // 主题名称
|
||||||
dark?: boolean; // 是否为深色主题标识
|
dark: boolean; // 是否为深色主题标识
|
||||||
|
|
||||||
// 基础色调
|
// 基础色调
|
||||||
background: string; // 主背景色
|
background: string; // 主背景色
|
||||||
backgroundSecondary?: string; // 次要背景色
|
backgroundSecondary: string; // 次要背景色(用于代码块交替背景)
|
||||||
surface?: string; // 面板背景
|
surface: string; // 面板背景
|
||||||
dropdownBackground?: string; // 下拉菜单背景
|
dropdownBackground: string; // 下拉菜单背景
|
||||||
dropdownBorder?: string; // 下拉菜单边框
|
dropdownBorder: string; // 下拉菜单边框
|
||||||
|
|
||||||
// 文本颜色
|
// 文本颜色
|
||||||
foreground: string; // 主文本色
|
foreground: string; // 主文本色
|
||||||
foregroundSecondary?: string; // 次要文本色
|
foregroundSecondary: string; // 次要文本色
|
||||||
comment: string; // 注释色
|
comment: string; // 注释色
|
||||||
|
|
||||||
// 语法高亮色
|
// 语法高亮色 - 核心
|
||||||
keyword: string; // 关键字
|
keyword: string; // 关键字
|
||||||
string: string; // 字符串
|
string: string; // 字符串
|
||||||
function: string; // 函数名
|
function: string; // 函数名
|
||||||
number: string; // 数字
|
number: string; // 数字
|
||||||
operator?: string; // 操作符
|
operator: string; // 操作符
|
||||||
variable: string; // 变量
|
variable: string; // 变量
|
||||||
type: string; // 类型
|
type: string; // 类型
|
||||||
|
|
||||||
|
// 语法高亮色 - 扩展
|
||||||
constant: string; // 常量
|
constant: string; // 常量
|
||||||
storage?: string; // 存储类型
|
storage: string; // 存储类型(如 static, const)
|
||||||
parameter?: string; // 参数
|
parameter: string; // 参数
|
||||||
class?: string; // 类名
|
class: string; // 类名
|
||||||
heading?: string; // 标题
|
heading: string; // 标题(Markdown等)
|
||||||
invalid?: string; // 无效内容
|
invalid: string; // 无效内容/错误
|
||||||
regexp?: string; // 正则表达式
|
regexp: string; // 正则表达式
|
||||||
|
|
||||||
// 界面元素
|
// 界面元素
|
||||||
cursor: string; // 光标
|
cursor: string; // 光标
|
||||||
selection: string; // 选中背景
|
selection: string; // 选中背景
|
||||||
selectionBlur?: string; // 失焦选中背景
|
selectionBlur: string; // 失焦选中背景
|
||||||
activeLine: string; // 当前行高亮
|
activeLine: string; // 当前行高亮
|
||||||
lineNumber: string; // 行号
|
lineNumber: string; // 行号
|
||||||
activeLineNumber: string; // 活动行号颜色
|
activeLineNumber: string; // 活动行号颜色
|
||||||
|
|
||||||
// 边框和分割线
|
// 边框和分割线
|
||||||
borderColor?: string; // 边框色
|
borderColor: string; // 边框色
|
||||||
borderLight?: string; // 浅色边框
|
borderLight: string; // 浅色边框
|
||||||
|
|
||||||
// 搜索和匹配
|
// 搜索和匹配
|
||||||
searchMatch?: string; // 搜索匹配
|
searchMatch: string; // 搜索匹配
|
||||||
matchingBracket?: string; // 匹配括号
|
matchingBracket: string; // 匹配括号
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,11 +6,10 @@ import { computed, watch, onMounted, ref } from 'vue';
|
|||||||
import SettingSection from '../components/SettingSection.vue';
|
import SettingSection from '../components/SettingSection.vue';
|
||||||
import SettingItem from '../components/SettingItem.vue';
|
import SettingItem from '../components/SettingItem.vue';
|
||||||
import { SystemThemeType, LanguageType } from '@/../bindings/voidraft/internal/models/models';
|
import { SystemThemeType, LanguageType } from '@/../bindings/voidraft/internal/models/models';
|
||||||
import { defaultDarkColors } from '@/views/editor/theme/dark';
|
|
||||||
import { defaultLightColors } from '@/views/editor/theme/light';
|
|
||||||
import { createDebounce } from '@/common/utils/debounce';
|
import { createDebounce } from '@/common/utils/debounce';
|
||||||
import { createTimerManager } from '@/common/utils/timerUtils';
|
import { createTimerManager } from '@/common/utils/timerUtils';
|
||||||
import PickColors from 'vue-pick-colors';
|
import PickColors from 'vue-pick-colors';
|
||||||
|
import type { ThemeColors } from '@/views/editor/theme/types';
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const configStore = useConfigStore();
|
const configStore = useConfigStore();
|
||||||
@@ -24,14 +23,12 @@ const { debouncedFn: debouncedUpdateColor } = createDebounce(
|
|||||||
|
|
||||||
const { debouncedFn: debouncedResetTheme } = createDebounce(
|
const { debouncedFn: debouncedResetTheme } = createDebounce(
|
||||||
async () => {
|
async () => {
|
||||||
const themeType = activeThemeType.value;
|
const isDark = isDarkMode.value;
|
||||||
const success = await themeStore.resetThemeColors(themeType);
|
const success = await themeStore.resetCurrentTheme(isDark);
|
||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
tempColors.value = {
|
// 重新加载临时颜色
|
||||||
darkTheme: { ...themeStore.themeColors.darkTheme },
|
syncTempColors();
|
||||||
lightTheme: { ...themeStore.themeColors.lightTheme }
|
|
||||||
};
|
|
||||||
hasUnsavedChanges.value = false;
|
hasUnsavedChanges.value = false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -41,11 +38,8 @@ const { debouncedFn: debouncedResetTheme } = createDebounce(
|
|||||||
// 创建定时器管理器
|
// 创建定时器管理器
|
||||||
const resetTimer = createTimerManager();
|
const resetTimer = createTimerManager();
|
||||||
|
|
||||||
// 添加临时颜色状态
|
// 临时颜色状态(用于编辑)
|
||||||
const tempColors = ref({
|
const tempColors = ref<ThemeColors | null>(null);
|
||||||
darkTheme: { ...defaultDarkColors },
|
|
||||||
lightTheme: { ...defaultLightColors }
|
|
||||||
});
|
|
||||||
|
|
||||||
// 标记是否有未保存的更改
|
// 标记是否有未保存的更改
|
||||||
const hasUnsavedChanges = ref(false);
|
const hasUnsavedChanges = ref(false);
|
||||||
@@ -55,81 +49,72 @@ const resetButtonState = ref({
|
|||||||
confirming: false
|
confirming: false
|
||||||
});
|
});
|
||||||
|
|
||||||
// 当前激活的主题类型
|
// 当前激活的主题类型(深色/浅色)
|
||||||
const isDarkMode = computed(() =>
|
const isDarkMode = computed(() =>
|
||||||
themeStore.currentTheme === SystemThemeType.SystemThemeDark ||
|
themeStore.currentTheme === SystemThemeType.SystemThemeDark ||
|
||||||
(themeStore.currentTheme === SystemThemeType.SystemThemeAuto &&
|
(themeStore.currentTheme === SystemThemeType.SystemThemeAuto &&
|
||||||
window.matchMedia('(prefers-color-scheme: dark)').matches)
|
window.matchMedia('(prefers-color-scheme: dark)').matches)
|
||||||
);
|
);
|
||||||
|
|
||||||
const activeThemeType = computed(() => isDarkMode.value ? 'darkTheme' : 'lightTheme');
|
// 当前可用的预设主题列表
|
||||||
|
const availableThemes = computed(() =>
|
||||||
|
isDarkMode.value ? themeStore.darkThemes : themeStore.lightThemes
|
||||||
|
);
|
||||||
|
|
||||||
// 当前主题的颜色配置
|
// 当前选中的主题ID
|
||||||
const currentColors = computed(() => {
|
const currentThemeId = computed({
|
||||||
const themeType = activeThemeType.value;
|
get: () => isDarkMode.value ? themeStore.currentThemeIds.dark : themeStore.currentThemeIds.light,
|
||||||
return tempColors.value[themeType] ||
|
set: async (themeId: number) => {
|
||||||
(themeType === 'darkTheme' ? defaultDarkColors : defaultLightColors);
|
await themeStore.switchToTheme(themeId);
|
||||||
|
syncTempColors();
|
||||||
|
hasUnsavedChanges.value = false;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// 获取当前主题模式
|
// 当前主题的颜色配置
|
||||||
|
const currentColors = computed(() => tempColors.value || ({} as ThemeColors));
|
||||||
|
|
||||||
|
// 获取当前主题模式(用于颜色选择器)
|
||||||
const currentThemeMode = computed(() => isDarkMode.value ? 'dark' : 'light');
|
const currentThemeMode = computed(() => isDarkMode.value ? 'dark' : 'light');
|
||||||
|
|
||||||
// 监听主题颜色变更,
|
// 同步临时颜色从 store
|
||||||
|
const syncTempColors = () => {
|
||||||
|
const colors = isDarkMode.value ? themeStore.currentColors.dark : themeStore.currentColors.light;
|
||||||
|
if (colors) {
|
||||||
|
tempColors.value = { ...colors };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 监听主题切换,同步临时颜色
|
||||||
watch(
|
watch(
|
||||||
() => themeStore.themeColors,
|
[() => themeStore.currentColors.dark, () => themeStore.currentColors.light, isDarkMode],
|
||||||
(newValue) => {
|
() => {
|
||||||
if (!hasUnsavedChanges.value) {
|
if (!hasUnsavedChanges.value) {
|
||||||
tempColors.value.darkTheme = { ...newValue.darkTheme };
|
syncTempColors();
|
||||||
tempColors.value.lightTheme = { ...newValue.lightTheme };
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{ deep: true, immediate: true }
|
{ deep: true }
|
||||||
);
|
);
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
tempColors.value = {
|
syncTempColors();
|
||||||
darkTheme: { ...themeStore.themeColors.darkTheme },
|
|
||||||
lightTheme: { ...themeStore.themeColors.lightTheme }
|
|
||||||
};
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// 颜色配置
|
// 从 ThemeColors 接口自动提取所有颜色字段
|
||||||
const colorConfig = [
|
const colorKeys = computed(() => {
|
||||||
{
|
if (!tempColors.value) return [];
|
||||||
key: 'basic',
|
|
||||||
colors: ['background', 'backgroundSecondary', 'surface']
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'text',
|
|
||||||
colors: ['foreground', 'foregroundSecondary', 'comment']
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'syntax',
|
|
||||||
colors: ['keyword', 'string', 'function', 'number', 'operator', 'variable', 'type']
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'interface',
|
|
||||||
colors: ['cursor', 'selection', 'selectionBlur', 'activeLine', 'lineNumber', 'activeLineNumber']
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'border',
|
|
||||||
colors: ['borderColor', 'borderLight']
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'search',
|
|
||||||
colors: ['searchMatch', 'matchingBracket']
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
// 颜色配置分组
|
// 获取所有字段,排除 name 和 dark(这两个是元数据)
|
||||||
const colorGroups = computed(() =>
|
return Object.keys(tempColors.value).filter(key =>
|
||||||
colorConfig.map(group => ({
|
key !== 'name' && key !== 'dark'
|
||||||
key: group.key,
|
);
|
||||||
title: t(`settings.themeColors.${group.key}`),
|
});
|
||||||
colors: group.colors.map(colorKey => ({
|
|
||||||
key: colorKey,
|
// 颜色配置列表
|
||||||
label: t(`settings.themeColors.${colorKey}`)
|
const colorList = computed(() =>
|
||||||
}))
|
colorKeys.value.map(colorKey => ({
|
||||||
|
key: colorKey,
|
||||||
|
label: t(`settings.themeColors.${colorKey}`)
|
||||||
}))
|
}))
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -152,15 +137,12 @@ const handleResetClick = () => {
|
|||||||
|
|
||||||
// 更新本地颜色配置
|
// 更新本地颜色配置
|
||||||
const updateLocalColor = (colorKey: string, value: string) => {
|
const updateLocalColor = (colorKey: string, value: string) => {
|
||||||
const themeType = activeThemeType.value;
|
if (!tempColors.value) return;
|
||||||
|
|
||||||
// 更新临时颜色
|
// 更新临时颜色
|
||||||
tempColors.value = {
|
tempColors.value = {
|
||||||
...tempColors.value,
|
...tempColors.value,
|
||||||
[themeType]: {
|
[colorKey]: value
|
||||||
...tempColors.value[themeType],
|
|
||||||
[colorKey]: value
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
hasUnsavedChanges.value = true;
|
hasUnsavedChanges.value = true;
|
||||||
@@ -169,17 +151,15 @@ const updateLocalColor = (colorKey: string, value: string) => {
|
|||||||
// 应用颜色更改到系统
|
// 应用颜色更改到系统
|
||||||
const applyChanges = async () => {
|
const applyChanges = async () => {
|
||||||
try {
|
try {
|
||||||
// 获取当前主题的自定义颜色
|
if (!tempColors.value) return;
|
||||||
const customTheme = {
|
|
||||||
darkTheme: tempColors.value.darkTheme,
|
|
||||||
lightTheme: tempColors.value.lightTheme
|
|
||||||
};
|
|
||||||
|
|
||||||
// 更新themeStore中的颜色
|
const isDark = isDarkMode.value;
|
||||||
themeStore.updateThemeColors(customTheme.darkTheme, customTheme.lightTheme);
|
|
||||||
|
|
||||||
// 保存到配置
|
// 更新 store 中的颜色
|
||||||
await themeStore.saveThemeColors();
|
themeStore.updateCurrentColors(tempColors.value, isDark);
|
||||||
|
|
||||||
|
// 保存到数据库
|
||||||
|
await themeStore.saveCurrentTheme(isDark);
|
||||||
|
|
||||||
// 刷新编辑器主题
|
// 刷新编辑器主题
|
||||||
themeStore.refreshEditorTheme();
|
themeStore.refreshEditorTheme();
|
||||||
@@ -193,11 +173,8 @@ const applyChanges = async () => {
|
|||||||
|
|
||||||
// 取消颜色更改
|
// 取消颜色更改
|
||||||
const cancelChanges = () => {
|
const cancelChanges = () => {
|
||||||
// 恢复到themeStore中的颜色
|
// 恢复到 store 中的颜色
|
||||||
tempColors.value = {
|
syncTempColors();
|
||||||
darkTheme: { ...themeStore.themeColors.darkTheme },
|
|
||||||
lightTheme: { ...themeStore.themeColors.lightTheme }
|
|
||||||
};
|
|
||||||
|
|
||||||
// 清除未保存标记
|
// 清除未保存标记
|
||||||
hasUnsavedChanges.value = false;
|
hasUnsavedChanges.value = false;
|
||||||
@@ -266,6 +243,15 @@ const handlePickerClose = () => {
|
|||||||
</option>
|
</option>
|
||||||
</select>
|
</select>
|
||||||
</SettingItem>
|
</SettingItem>
|
||||||
|
|
||||||
|
<!-- 预设主题选择 -->
|
||||||
|
<SettingItem :title="t('settings.presetTheme')">
|
||||||
|
<select class="select-input" v-model="currentThemeId" :disabled="hasUnsavedChanges">
|
||||||
|
<option v-for="theme in availableThemes" :key="theme.id" :value="theme.id">
|
||||||
|
{{ theme.name }}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
</SettingItem>
|
||||||
</SettingSection>
|
</SettingSection>
|
||||||
|
|
||||||
<!-- 自定义主题颜色配置 -->
|
<!-- 自定义主题颜色配置 -->
|
||||||
@@ -290,45 +276,41 @@ const handlePickerClose = () => {
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<div class="color-groups">
|
<!-- 颜色列表 -->
|
||||||
<div v-for="group in colorGroups" :key="group.key" class="color-group">
|
<div class="color-list">
|
||||||
<h4 class="group-title">{{ group.title }}</h4>
|
<SettingItem
|
||||||
<div class="color-items">
|
v-for="color in colorList"
|
||||||
<SettingItem
|
:key="color.key"
|
||||||
v-for="color in group.colors"
|
:title="color.label"
|
||||||
:key="color.key"
|
class="color-setting-item"
|
||||||
:title="color.label"
|
>
|
||||||
class="color-setting-item"
|
<div class="color-input-wrapper">
|
||||||
>
|
<div class="color-picker-wrapper">
|
||||||
<div class="color-input-wrapper">
|
<PickColors
|
||||||
<div class="color-picker-wrapper">
|
v-model:value="currentColors[color.key]"
|
||||||
<PickColors
|
v-model:show-picker="showPickerMap[color.key]"
|
||||||
v-model:value="currentColors[color.key]"
|
:size="28"
|
||||||
v-model:show-picker="showPickerMap[color.key]"
|
show-alpha
|
||||||
:size="28"
|
:theme="currentThemeMode"
|
||||||
show-alpha
|
:colors="[]"
|
||||||
:theme="currentThemeMode"
|
format="hex"
|
||||||
:colors="[]"
|
:format-options="['rgb', 'hex', 'hsl', 'hsv']"
|
||||||
format="hex"
|
placement="bottom"
|
||||||
:format-options="['rgb', 'hex', 'hsl', 'hsv']"
|
position="absolute"
|
||||||
placement="bottom"
|
:z-index="1000"
|
||||||
position="absolute"
|
@change="(val) => handleColorChange(color.key, val)"
|
||||||
:z-index="1000"
|
@close-picker="handlePickerClose"
|
||||||
@change="(val) => handleColorChange(color.key, val)"
|
/>
|
||||||
@close-picker="handlePickerClose"
|
</div>
|
||||||
/>
|
<input
|
||||||
</div>
|
type="text"
|
||||||
<input
|
:value="currentColors[color.key] || ''"
|
||||||
type="text"
|
@input="debouncedUpdateColor(color.key, ($event.target as HTMLInputElement).value)"
|
||||||
:value="currentColors[color.key] || ''"
|
class="color-text-input"
|
||||||
@input="debouncedUpdateColor(color.key, ($event.target as HTMLInputElement).value)"
|
:placeholder="t('settings.colorValue')"
|
||||||
class="color-text-input"
|
/>
|
||||||
:placeholder="t('settings.colorValue')"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</SettingItem>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</SettingItem>
|
||||||
</div>
|
</div>
|
||||||
</SettingSection>
|
</SettingSection>
|
||||||
</div>
|
</div>
|
||||||
@@ -430,27 +412,11 @@ const handlePickerClose = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.color-groups {
|
.color-list {
|
||||||
display: flex;
|
display: grid;
|
||||||
flex-direction: column;
|
grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
|
||||||
gap: 24px;
|
gap: 12px;
|
||||||
}
|
margin-top: 12px;
|
||||||
|
|
||||||
.color-group {
|
|
||||||
.group-title {
|
|
||||||
font-size: 14px;
|
|
||||||
font-weight: 600;
|
|
||||||
color: var(--settings-text);
|
|
||||||
margin: 0 0 12px 0;
|
|
||||||
padding-bottom: 6px;
|
|
||||||
border-bottom: 1px solid var(--settings-input-border);
|
|
||||||
}
|
|
||||||
|
|
||||||
.color-items {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
|
||||||
gap: 8px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.color-setting-item {
|
.color-setting-item {
|
||||||
|
|||||||
6
go.mod
6
go.mod
@@ -10,11 +10,11 @@ require (
|
|||||||
github.com/knadh/koanf/providers/structs v1.0.0
|
github.com/knadh/koanf/providers/structs v1.0.0
|
||||||
github.com/knadh/koanf/v2 v2.3.0
|
github.com/knadh/koanf/v2 v2.3.0
|
||||||
github.com/stretchr/testify v1.11.1
|
github.com/stretchr/testify v1.11.1
|
||||||
github.com/wailsapp/wails/v3 v3.0.0-alpha.34
|
github.com/wailsapp/wails/v3 v3.0.0-alpha.36
|
||||||
golang.org/x/net v0.46.0
|
golang.org/x/net v0.46.0
|
||||||
golang.org/x/sys v0.37.0
|
golang.org/x/sys v0.37.0
|
||||||
golang.org/x/text v0.30.0
|
golang.org/x/text v0.30.0
|
||||||
modernc.org/sqlite v1.39.0
|
modernc.org/sqlite v1.39.1
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
@@ -72,7 +72,7 @@ require (
|
|||||||
github.com/sergi/go-diff v1.4.0 // indirect
|
github.com/sergi/go-diff v1.4.0 // indirect
|
||||||
github.com/skeema/knownhosts v1.3.2 // indirect
|
github.com/skeema/knownhosts v1.3.2 // indirect
|
||||||
github.com/ulikunitz/xz v0.5.15 // indirect
|
github.com/ulikunitz/xz v0.5.15 // indirect
|
||||||
github.com/wailsapp/go-webview2 v1.0.21 // indirect
|
github.com/wailsapp/go-webview2 v1.0.22 // indirect
|
||||||
github.com/wailsapp/mimetype v1.4.1 // indirect
|
github.com/wailsapp/mimetype v1.4.1 // indirect
|
||||||
github.com/xanzy/go-gitlab v0.115.0 // indirect
|
github.com/xanzy/go-gitlab v0.115.0 // indirect
|
||||||
github.com/xanzy/ssh-agent v0.3.3 // indirect
|
github.com/xanzy/ssh-agent v0.3.3 // indirect
|
||||||
|
|||||||
12
go.sum
12
go.sum
@@ -162,12 +162,12 @@ github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu
|
|||||||
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||||
github.com/ulikunitz/xz v0.5.15 h1:9DNdB5s+SgV3bQ2ApL10xRc35ck0DuIX/isZvIk+ubY=
|
github.com/ulikunitz/xz v0.5.15 h1:9DNdB5s+SgV3bQ2ApL10xRc35ck0DuIX/isZvIk+ubY=
|
||||||
github.com/ulikunitz/xz v0.5.15/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
|
github.com/ulikunitz/xz v0.5.15/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
|
||||||
github.com/wailsapp/go-webview2 v1.0.21 h1:k3dtoZU4KCoN/AEIbWiPln3P2661GtA2oEgA2Pb+maA=
|
github.com/wailsapp/go-webview2 v1.0.22 h1:YT61F5lj+GGaat5OB96Aa3b4QA+mybD0Ggq6NZijQ58=
|
||||||
github.com/wailsapp/go-webview2 v1.0.21/go.mod h1:qJmWAmAmaniuKGZPWwne+uor3AHMB5PFhqiK0Bbj8kc=
|
github.com/wailsapp/go-webview2 v1.0.22/go.mod h1:qJmWAmAmaniuKGZPWwne+uor3AHMB5PFhqiK0Bbj8kc=
|
||||||
github.com/wailsapp/mimetype v1.4.1 h1:pQN9ycO7uo4vsUUuPeHEYoUkLVkaRntMnHJxVwYhwHs=
|
github.com/wailsapp/mimetype v1.4.1 h1:pQN9ycO7uo4vsUUuPeHEYoUkLVkaRntMnHJxVwYhwHs=
|
||||||
github.com/wailsapp/mimetype v1.4.1/go.mod h1:9aV5k31bBOv5z6u+QP8TltzvNGJPmNJD4XlAL3U+j3o=
|
github.com/wailsapp/mimetype v1.4.1/go.mod h1:9aV5k31bBOv5z6u+QP8TltzvNGJPmNJD4XlAL3U+j3o=
|
||||||
github.com/wailsapp/wails/v3 v3.0.0-alpha.34 h1:t6NwHOLJzXuESb3YSXarSd1C/U1h2CpXF+BLr0ekj2g=
|
github.com/wailsapp/wails/v3 v3.0.0-alpha.36 h1:GQ8vSrFgafITwMd/p4k+WBjG9K/anma9Pk2eJ/5CLsI=
|
||||||
github.com/wailsapp/wails/v3 v3.0.0-alpha.34/go.mod h1:UZpnhYuju4saspCJrIHAvC0H5XjtKnqd26FRxJLrQ0M=
|
github.com/wailsapp/wails/v3 v3.0.0-alpha.36/go.mod h1:7i8tSuA74q97zZ5qEJlcVZdnO+IR7LT2KU8UpzYMPsw=
|
||||||
github.com/xanzy/go-gitlab v0.115.0 h1:6DmtItNcVe+At/liXSgfE/DZNZrGfalQmBRmOcJjOn8=
|
github.com/xanzy/go-gitlab v0.115.0 h1:6DmtItNcVe+At/liXSgfE/DZNZrGfalQmBRmOcJjOn8=
|
||||||
github.com/xanzy/go-gitlab v0.115.0/go.mod h1:5XCDtM7AM6WMKmfDdOiEpyRWUqui2iS9ILfvCZ2gJ5M=
|
github.com/xanzy/go-gitlab v0.115.0/go.mod h1:5XCDtM7AM6WMKmfDdOiEpyRWUqui2iS9ILfvCZ2gJ5M=
|
||||||
github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM=
|
github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM=
|
||||||
@@ -256,8 +256,8 @@ modernc.org/opt v0.1.4 h1:2kNGMRiUjrp4LcaPuLY2PzUfqM/w9N23quVwhKt5Qm8=
|
|||||||
modernc.org/opt v0.1.4/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns=
|
modernc.org/opt v0.1.4/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns=
|
||||||
modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w=
|
modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w=
|
||||||
modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE=
|
modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE=
|
||||||
modernc.org/sqlite v1.39.0 h1:6bwu9Ooim0yVYA7IZn9demiQk/Ejp0BtTjBWFLymSeY=
|
modernc.org/sqlite v1.39.1 h1:H+/wGFzuSCIEVCvXYVHX5RQglwhMOvtHSv+VtidL2r4=
|
||||||
modernc.org/sqlite v1.39.0/go.mod h1:cPTJYSlgg3Sfg046yBShXENNtPrWrDX8bsbAQBzgQ5E=
|
modernc.org/sqlite v1.39.1/go.mod h1:9fjQZ0mB1LLP0GYrp39oOJXx/I2sxEnZtzCmEQIKvGE=
|
||||||
modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0=
|
modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0=
|
||||||
modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A=
|
modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A=
|
||||||
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
|
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
|
||||||
|
|||||||
@@ -14,17 +14,25 @@ const (
|
|||||||
ThemeTypeLight ThemeType = "light"
|
ThemeTypeLight ThemeType = "light"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ThemeColorConfig 主题颜色配置
|
// ThemeColorConfig 主题颜色配置(与前端 ThemeColors 接口保持一致)
|
||||||
type ThemeColorConfig struct {
|
type ThemeColorConfig struct {
|
||||||
|
// 主题基本信息
|
||||||
|
Name string `json:"name"` // 主题名称
|
||||||
|
Dark bool `json:"dark"` // 是否为深色主题
|
||||||
|
|
||||||
// 基础色调
|
// 基础色调
|
||||||
Background string `json:"background"` // 主背景色
|
Background string `json:"background"` // 主背景色
|
||||||
BackgroundSecondary string `json:"backgroundSecondary"` // 次要背景色
|
BackgroundSecondary string `json:"backgroundSecondary"` // 次要背景色(用于代码块交替背景)
|
||||||
Surface string `json:"surface"` // 面板背景
|
Surface string `json:"surface"` // 面板背景
|
||||||
|
DropdownBackground string `json:"dropdownBackground"` // 下拉菜单背景
|
||||||
|
DropdownBorder string `json:"dropdownBorder"` // 下拉菜单边框
|
||||||
|
|
||||||
|
// 文本颜色
|
||||||
Foreground string `json:"foreground"` // 主文本色
|
Foreground string `json:"foreground"` // 主文本色
|
||||||
ForegroundSecondary string `json:"foregroundSecondary"` // 次要文本色
|
ForegroundSecondary string `json:"foregroundSecondary"` // 次要文本色
|
||||||
|
Comment string `json:"comment"` // 注释色
|
||||||
|
|
||||||
// 语法高亮
|
// 语法高亮色 - 核心
|
||||||
Comment string `json:"comment"` // 注释色
|
|
||||||
Keyword string `json:"keyword"` // 关键字
|
Keyword string `json:"keyword"` // 关键字
|
||||||
String string `json:"string"` // 字符串
|
String string `json:"string"` // 字符串
|
||||||
Function string `json:"function"` // 函数名
|
Function string `json:"function"` // 函数名
|
||||||
@@ -33,34 +41,32 @@ type ThemeColorConfig struct {
|
|||||||
Variable string `json:"variable"` // 变量
|
Variable string `json:"variable"` // 变量
|
||||||
Type string `json:"type"` // 类型
|
Type string `json:"type"` // 类型
|
||||||
|
|
||||||
|
// 语法高亮色 - 扩展
|
||||||
|
Constant string `json:"constant"` // 常量
|
||||||
|
Storage string `json:"storage"` // 存储类型(如 static, const)
|
||||||
|
Parameter string `json:"parameter"` // 参数
|
||||||
|
Class string `json:"class"` // 类名
|
||||||
|
Heading string `json:"heading"` // 标题(Markdown等)
|
||||||
|
Invalid string `json:"invalid"` // 无效内容/错误
|
||||||
|
Regexp string `json:"regexp"` // 正则表达式
|
||||||
|
|
||||||
// 界面元素
|
// 界面元素
|
||||||
Cursor string `json:"cursor"` // 光标
|
Cursor string `json:"cursor"` // 光标
|
||||||
Selection string `json:"selection"` // 选中背景
|
Selection string `json:"selection"` // 选中背景
|
||||||
SelectionBlur string `json:"selectionBlur"` // 失焦选中背景
|
SelectionBlur string `json:"selectionBlur"` // 失焦选中背景
|
||||||
ActiveLine string `json:"activeLine"` // 当前行高亮
|
ActiveLine string `json:"activeLine"` // 当前行高亮
|
||||||
LineNumber string `json:"lineNumber"` // 行号
|
LineNumber string `json:"lineNumber"` // 行号
|
||||||
ActiveLineNumber string `json:"activeLineNumber"` // 活动行号
|
ActiveLineNumber string `json:"activeLineNumber"` // 活动行号颜色
|
||||||
|
|
||||||
// 边框分割线
|
// 边框和分割线
|
||||||
BorderColor string `json:"borderColor"` // 边框色
|
BorderColor string `json:"borderColor"` // 边框色
|
||||||
BorderLight string `json:"borderLight"` // 浅色边框
|
BorderLight string `json:"borderLight"` // 浅色边框
|
||||||
|
|
||||||
// 搜索匹配
|
// 搜索和匹配
|
||||||
SearchMatch string `json:"searchMatch"` // 搜索匹配
|
SearchMatch string `json:"searchMatch"` // 搜索匹配
|
||||||
MatchingBracket string `json:"matchingBracket"` // 匹配括号
|
MatchingBracket string `json:"matchingBracket"` // 匹配括号
|
||||||
}
|
}
|
||||||
|
|
||||||
// Theme 主题数据库模型
|
|
||||||
type Theme struct {
|
|
||||||
ID int `db:"id" json:"id"`
|
|
||||||
Name string `db:"name" json:"name"`
|
|
||||||
Type ThemeType `db:"type" json:"type"`
|
|
||||||
Colors ThemeColorConfig `db:"colors" json:"colors"`
|
|
||||||
IsDefault bool `db:"is_default" json:"isDefault"`
|
|
||||||
CreatedAt string `db:"created_at" json:"createdAt"`
|
|
||||||
UpdatedAt string `db:"updated_at" json:"updatedAt"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Value 实现 driver.Valuer 接口,用于将 ThemeColorConfig 存储到数据库
|
// Value 实现 driver.Valuer 接口,用于将 ThemeColorConfig 存储到数据库
|
||||||
func (tc ThemeColorConfig) Value() (driver.Value, error) {
|
func (tc ThemeColorConfig) Value() (driver.Value, error) {
|
||||||
return json.Marshal(tc)
|
return json.Marshal(tc)
|
||||||
@@ -85,18 +91,37 @@ func (tc *ThemeColorConfig) Scan(value interface{}) error {
|
|||||||
return json.Unmarshal(bytes, tc)
|
return json.Unmarshal(bytes, tc)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewDefaultDarkTheme 创建默认深色主题配置
|
// Theme 主题数据库模型
|
||||||
|
type Theme struct {
|
||||||
|
ID int `db:"id" json:"id"`
|
||||||
|
Name string `db:"name" json:"name"`
|
||||||
|
Type ThemeType `db:"type" json:"type"`
|
||||||
|
Colors ThemeColorConfig `db:"colors" json:"colors"`
|
||||||
|
IsDefault bool `db:"is_default" json:"isDefault"`
|
||||||
|
CreatedAt string `db:"created_at" json:"createdAt"`
|
||||||
|
UpdatedAt string `db:"updated_at" json:"updatedAt"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewDefaultDarkTheme 创建默认深色主题配置(与前端 defaultDarkColors 完全一致)
|
||||||
func NewDefaultDarkTheme() *ThemeColorConfig {
|
func NewDefaultDarkTheme() *ThemeColorConfig {
|
||||||
return &ThemeColorConfig{
|
return &ThemeColorConfig{
|
||||||
|
// 主题信息
|
||||||
|
Name: "default-dark",
|
||||||
|
Dark: true,
|
||||||
|
|
||||||
// 基础色调
|
// 基础色调
|
||||||
Background: "#252B37",
|
Background: "#252B37",
|
||||||
BackgroundSecondary: "#213644",
|
BackgroundSecondary: "#213644",
|
||||||
Surface: "#474747",
|
Surface: "#474747",
|
||||||
|
DropdownBackground: "#252B37",
|
||||||
|
DropdownBorder: "#ffffff19",
|
||||||
|
|
||||||
|
// 文本颜色
|
||||||
Foreground: "#9BB586",
|
Foreground: "#9BB586",
|
||||||
ForegroundSecondary: "#9c9c9c",
|
ForegroundSecondary: "#9c9c9c",
|
||||||
|
Comment: "#6272a4",
|
||||||
|
|
||||||
// 语法高亮
|
// 语法高亮色 - 核心
|
||||||
Comment: "#6272a4",
|
|
||||||
Keyword: "#ff79c6",
|
Keyword: "#ff79c6",
|
||||||
String: "#f1fa8c",
|
String: "#f1fa8c",
|
||||||
Function: "#50fa7b",
|
Function: "#50fa7b",
|
||||||
@@ -105,6 +130,15 @@ func NewDefaultDarkTheme() *ThemeColorConfig {
|
|||||||
Variable: "#8fbcbb",
|
Variable: "#8fbcbb",
|
||||||
Type: "#8be9fd",
|
Type: "#8be9fd",
|
||||||
|
|
||||||
|
// 语法高亮色 - 扩展
|
||||||
|
Constant: "#bd93f9",
|
||||||
|
Storage: "#ff79c6",
|
||||||
|
Parameter: "#8fbcbb",
|
||||||
|
Class: "#8be9fd",
|
||||||
|
Heading: "#ff79c6",
|
||||||
|
Invalid: "#d30102",
|
||||||
|
Regexp: "#f1fa8c",
|
||||||
|
|
||||||
// 界面元素
|
// 界面元素
|
||||||
Cursor: "#ffffff",
|
Cursor: "#ffffff",
|
||||||
Selection: "#0865a9",
|
Selection: "#0865a9",
|
||||||
@@ -113,28 +147,36 @@ func NewDefaultDarkTheme() *ThemeColorConfig {
|
|||||||
LineNumber: "#ffffff26",
|
LineNumber: "#ffffff26",
|
||||||
ActiveLineNumber: "#ffffff99",
|
ActiveLineNumber: "#ffffff99",
|
||||||
|
|
||||||
// 边框分割线
|
// 边框和分割线
|
||||||
BorderColor: "#1e222a",
|
BorderColor: "#1e222a",
|
||||||
BorderLight: "#ffffff1a",
|
BorderLight: "#ffffff19",
|
||||||
|
|
||||||
// 搜索匹配
|
// 搜索和匹配
|
||||||
SearchMatch: "#8fbcbb",
|
SearchMatch: "#8fbcbb",
|
||||||
MatchingBracket: "#ffffff1a",
|
MatchingBracket: "#ffffff19",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewDefaultLightTheme 创建默认浅色主题配置
|
// NewDefaultLightTheme 创建默认浅色主题配置(与前端 defaultLightColors 完全一致)
|
||||||
func NewDefaultLightTheme() *ThemeColorConfig {
|
func NewDefaultLightTheme() *ThemeColorConfig {
|
||||||
return &ThemeColorConfig{
|
return &ThemeColorConfig{
|
||||||
|
// 主题信息
|
||||||
|
Name: "default-light",
|
||||||
|
Dark: false,
|
||||||
|
|
||||||
// 基础色调
|
// 基础色调
|
||||||
Background: "#ffffff",
|
Background: "#ffffff",
|
||||||
BackgroundSecondary: "#f1faf1",
|
BackgroundSecondary: "#f1faf1",
|
||||||
Surface: "#f5f5f5",
|
Surface: "#f5f5f5",
|
||||||
|
DropdownBackground: "#ffffff",
|
||||||
|
DropdownBorder: "#e1e4e8",
|
||||||
|
|
||||||
|
// 文本颜色
|
||||||
Foreground: "#444d56",
|
Foreground: "#444d56",
|
||||||
ForegroundSecondary: "#6a737d",
|
ForegroundSecondary: "#6a737d",
|
||||||
|
Comment: "#6a737d",
|
||||||
|
|
||||||
// 语法高亮
|
// 语法高亮色 - 核心
|
||||||
Comment: "#6a737d",
|
|
||||||
Keyword: "#d73a49",
|
Keyword: "#d73a49",
|
||||||
String: "#032f62",
|
String: "#032f62",
|
||||||
Function: "#005cc5",
|
Function: "#005cc5",
|
||||||
@@ -143,6 +185,15 @@ func NewDefaultLightTheme() *ThemeColorConfig {
|
|||||||
Variable: "#24292e",
|
Variable: "#24292e",
|
||||||
Type: "#6f42c1",
|
Type: "#6f42c1",
|
||||||
|
|
||||||
|
// 语法高亮色 - 扩展
|
||||||
|
Constant: "#005cc5",
|
||||||
|
Storage: "#d73a49",
|
||||||
|
Parameter: "#24292e",
|
||||||
|
Class: "#6f42c1",
|
||||||
|
Heading: "#d73a49",
|
||||||
|
Invalid: "#cb2431",
|
||||||
|
Regexp: "#032f62",
|
||||||
|
|
||||||
// 界面元素
|
// 界面元素
|
||||||
Cursor: "#000000",
|
Cursor: "#000000",
|
||||||
Selection: "#77baff",
|
Selection: "#77baff",
|
||||||
@@ -151,12 +202,578 @@ func NewDefaultLightTheme() *ThemeColorConfig {
|
|||||||
LineNumber: "#00000040",
|
LineNumber: "#00000040",
|
||||||
ActiveLineNumber: "#000000aa",
|
ActiveLineNumber: "#000000aa",
|
||||||
|
|
||||||
// 边框分割线
|
// 边框和分割线
|
||||||
BorderColor: "#dfdfdf",
|
BorderColor: "#dfdfdf",
|
||||||
BorderLight: "#0000000c",
|
BorderLight: "#0000000c",
|
||||||
|
|
||||||
// 搜索匹配
|
// 搜索和匹配
|
||||||
SearchMatch: "#005cc5",
|
SearchMatch: "#005cc5",
|
||||||
MatchingBracket: "#00000019",
|
MatchingBracket: "#00000019",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewDraculaTheme 创建 Dracula 深色主题配置
|
||||||
|
func NewDraculaTheme() *ThemeColorConfig {
|
||||||
|
return &ThemeColorConfig{
|
||||||
|
Name: "dracula",
|
||||||
|
Dark: true,
|
||||||
|
|
||||||
|
Background: "#282A36",
|
||||||
|
BackgroundSecondary: "#282A36",
|
||||||
|
Surface: "#282A36",
|
||||||
|
DropdownBackground: "#282A36",
|
||||||
|
DropdownBorder: "#191A21",
|
||||||
|
|
||||||
|
Foreground: "#F8F8F2",
|
||||||
|
ForegroundSecondary: "#F8F8F2",
|
||||||
|
Comment: "#6272A4",
|
||||||
|
|
||||||
|
Keyword: "#FF79C6",
|
||||||
|
String: "#F1FA8C",
|
||||||
|
Function: "#50FA7B",
|
||||||
|
Number: "#BD93F9",
|
||||||
|
Operator: "#FF79C6",
|
||||||
|
Variable: "#F8F8F2",
|
||||||
|
Type: "#8BE9FD",
|
||||||
|
|
||||||
|
Constant: "#BD93F9",
|
||||||
|
Storage: "#FF79C6",
|
||||||
|
Parameter: "#F8F8F2",
|
||||||
|
Class: "#8BE9FD",
|
||||||
|
Heading: "#BD93F9",
|
||||||
|
Invalid: "#FF5555",
|
||||||
|
Regexp: "#F1FA8C",
|
||||||
|
|
||||||
|
Cursor: "#F8F8F2",
|
||||||
|
Selection: "#44475A",
|
||||||
|
SelectionBlur: "#44475A",
|
||||||
|
ActiveLine: "#53576c22",
|
||||||
|
LineNumber: "#6272A4",
|
||||||
|
ActiveLineNumber: "#F8F8F2",
|
||||||
|
|
||||||
|
BorderColor: "#191A21",
|
||||||
|
BorderLight: "#F8F8F219",
|
||||||
|
|
||||||
|
SearchMatch: "#50FA7B",
|
||||||
|
MatchingBracket: "#44475A",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewAuraTheme 创建 Aura 深色主题配置
|
||||||
|
func NewAuraTheme() *ThemeColorConfig {
|
||||||
|
return &ThemeColorConfig{
|
||||||
|
Name: "aura",
|
||||||
|
Dark: true,
|
||||||
|
|
||||||
|
Background: "#21202e",
|
||||||
|
BackgroundSecondary: "#21202e",
|
||||||
|
Surface: "#21202e",
|
||||||
|
DropdownBackground: "#21202e",
|
||||||
|
DropdownBorder: "#3b334b",
|
||||||
|
|
||||||
|
Foreground: "#edecee",
|
||||||
|
ForegroundSecondary: "#edecee",
|
||||||
|
Comment: "#6d6d6d",
|
||||||
|
|
||||||
|
Keyword: "#a277ff",
|
||||||
|
String: "#61ffca",
|
||||||
|
Function: "#ffca85",
|
||||||
|
Number: "#61ffca",
|
||||||
|
Operator: "#a277ff",
|
||||||
|
Variable: "#edecee",
|
||||||
|
Type: "#82e2ff",
|
||||||
|
|
||||||
|
Constant: "#61ffca",
|
||||||
|
Storage: "#a277ff",
|
||||||
|
Parameter: "#edecee",
|
||||||
|
Class: "#82e2ff",
|
||||||
|
Heading: "#a277ff",
|
||||||
|
Invalid: "#ff6767",
|
||||||
|
Regexp: "#61ffca",
|
||||||
|
|
||||||
|
Cursor: "#a277ff",
|
||||||
|
Selection: "#3d375e7f",
|
||||||
|
SelectionBlur: "#3d375e7f",
|
||||||
|
ActiveLine: "#4d4b6622",
|
||||||
|
LineNumber: "#a394f033",
|
||||||
|
ActiveLineNumber: "#cdccce",
|
||||||
|
|
||||||
|
BorderColor: "#3b334b",
|
||||||
|
BorderLight: "#edecee19",
|
||||||
|
|
||||||
|
SearchMatch: "#61ffca",
|
||||||
|
MatchingBracket: "#a394f033",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewGitHubDarkTheme 创建 GitHub Dark 主题配置
|
||||||
|
func NewGitHubDarkTheme() *ThemeColorConfig {
|
||||||
|
return &ThemeColorConfig{
|
||||||
|
Name: "github-dark",
|
||||||
|
Dark: true,
|
||||||
|
|
||||||
|
Background: "#24292e",
|
||||||
|
BackgroundSecondary: "#24292e",
|
||||||
|
Surface: "#24292e",
|
||||||
|
DropdownBackground: "#24292e",
|
||||||
|
DropdownBorder: "#1b1f23",
|
||||||
|
|
||||||
|
Foreground: "#d1d5da",
|
||||||
|
ForegroundSecondary: "#d1d5da",
|
||||||
|
Comment: "#6a737d",
|
||||||
|
|
||||||
|
Keyword: "#f97583",
|
||||||
|
String: "#9ecbff",
|
||||||
|
Function: "#79b8ff",
|
||||||
|
Number: "#79b8ff",
|
||||||
|
Operator: "#f97583",
|
||||||
|
Variable: "#ffab70",
|
||||||
|
Type: "#79b8ff",
|
||||||
|
|
||||||
|
Constant: "#79b8ff",
|
||||||
|
Storage: "#f97583",
|
||||||
|
Parameter: "#e1e4e8",
|
||||||
|
Class: "#b392f0",
|
||||||
|
Heading: "#79b8ff",
|
||||||
|
Invalid: "#f97583",
|
||||||
|
Regexp: "#9ecbff",
|
||||||
|
|
||||||
|
Cursor: "#c8e1ff",
|
||||||
|
Selection: "#3392FF44",
|
||||||
|
SelectionBlur: "#3392FF44",
|
||||||
|
ActiveLine: "#4d566022",
|
||||||
|
LineNumber: "#444d56",
|
||||||
|
ActiveLineNumber: "#e1e4e8",
|
||||||
|
|
||||||
|
BorderColor: "#1b1f23",
|
||||||
|
BorderLight: "#d1d5da19",
|
||||||
|
|
||||||
|
SearchMatch: "#79b8ff",
|
||||||
|
MatchingBracket: "#17E5E650",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewMaterialDarkTheme 创建 Material Dark 主题配置
|
||||||
|
func NewMaterialDarkTheme() *ThemeColorConfig {
|
||||||
|
return &ThemeColorConfig{
|
||||||
|
Name: "material-dark",
|
||||||
|
Dark: true,
|
||||||
|
|
||||||
|
Background: "#263238",
|
||||||
|
BackgroundSecondary: "#263238",
|
||||||
|
Surface: "#263238",
|
||||||
|
DropdownBackground: "#263238",
|
||||||
|
DropdownBorder: "#FFFFFF10",
|
||||||
|
|
||||||
|
Foreground: "#EEFFFF",
|
||||||
|
ForegroundSecondary: "#EEFFFF",
|
||||||
|
Comment: "#546E7A",
|
||||||
|
|
||||||
|
Keyword: "#C792EA",
|
||||||
|
String: "#C3E88D",
|
||||||
|
Function: "#82AAFF",
|
||||||
|
Number: "#F78C6C",
|
||||||
|
Operator: "#C792EA",
|
||||||
|
Variable: "#EEFFFF",
|
||||||
|
Type: "#B2CCD6",
|
||||||
|
|
||||||
|
Constant: "#F78C6C",
|
||||||
|
Storage: "#C792EA",
|
||||||
|
Parameter: "#EEFFFF",
|
||||||
|
Class: "#FFCB6B",
|
||||||
|
Heading: "#C3E88D",
|
||||||
|
Invalid: "#FF5370",
|
||||||
|
Regexp: "#89DDFF",
|
||||||
|
|
||||||
|
Cursor: "#FFCC00",
|
||||||
|
Selection: "#80CBC420",
|
||||||
|
SelectionBlur: "#80CBC420",
|
||||||
|
ActiveLine: "#4c616c22",
|
||||||
|
LineNumber: "#37474F",
|
||||||
|
ActiveLineNumber: "#607a86",
|
||||||
|
|
||||||
|
BorderColor: "#FFFFFF10",
|
||||||
|
BorderLight: "#EEFFFF19",
|
||||||
|
|
||||||
|
SearchMatch: "#82AAFF",
|
||||||
|
MatchingBracket: "#263238",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewOneDarkTheme 创建 One Dark 主题配置
|
||||||
|
func NewOneDarkTheme() *ThemeColorConfig {
|
||||||
|
return &ThemeColorConfig{
|
||||||
|
Name: "one-dark",
|
||||||
|
Dark: true,
|
||||||
|
|
||||||
|
Background: "#282c34",
|
||||||
|
BackgroundSecondary: "#2c313a",
|
||||||
|
Surface: "#353a42",
|
||||||
|
DropdownBackground: "#21252b",
|
||||||
|
DropdownBorder: "#7d8799",
|
||||||
|
|
||||||
|
Foreground: "#abb2bf",
|
||||||
|
ForegroundSecondary: "#7d8799",
|
||||||
|
Comment: "#7d8799",
|
||||||
|
|
||||||
|
Keyword: "#c678dd",
|
||||||
|
String: "#98c379",
|
||||||
|
Function: "#61afef",
|
||||||
|
Number: "#e5c07b",
|
||||||
|
Operator: "#56b6c2",
|
||||||
|
Variable: "#e06c75",
|
||||||
|
Type: "#e5c07b",
|
||||||
|
|
||||||
|
Constant: "#d19a66",
|
||||||
|
Storage: "#c678dd",
|
||||||
|
Parameter: "#e06c75",
|
||||||
|
Class: "#e5c07b",
|
||||||
|
Heading: "#e06c75",
|
||||||
|
Invalid: "#ffffff",
|
||||||
|
Regexp: "#56b6c2",
|
||||||
|
|
||||||
|
Cursor: "#528bff",
|
||||||
|
Selection: "#3E4451",
|
||||||
|
SelectionBlur: "#3E4451",
|
||||||
|
ActiveLine: "#6699ff0b",
|
||||||
|
LineNumber: "#7d8799",
|
||||||
|
ActiveLineNumber: "#abb2bf",
|
||||||
|
|
||||||
|
BorderColor: "#21252b",
|
||||||
|
BorderLight: "#abb2bf19",
|
||||||
|
|
||||||
|
SearchMatch: "#61afef",
|
||||||
|
MatchingBracket: "#bad0f847",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewSolarizedDarkTheme 创建 Solarized Dark 主题配置
|
||||||
|
func NewSolarizedDarkTheme() *ThemeColorConfig {
|
||||||
|
return &ThemeColorConfig{
|
||||||
|
Name: "solarized-dark",
|
||||||
|
Dark: true,
|
||||||
|
|
||||||
|
Background: "#002B36",
|
||||||
|
BackgroundSecondary: "#002B36",
|
||||||
|
Surface: "#002B36",
|
||||||
|
DropdownBackground: "#002B36",
|
||||||
|
DropdownBorder: "#2AA19899",
|
||||||
|
|
||||||
|
Foreground: "#93A1A1",
|
||||||
|
ForegroundSecondary: "#93A1A1",
|
||||||
|
Comment: "#586E75",
|
||||||
|
|
||||||
|
Keyword: "#859900",
|
||||||
|
String: "#2AA198",
|
||||||
|
Function: "#268BD2",
|
||||||
|
Number: "#D33682",
|
||||||
|
Operator: "#859900",
|
||||||
|
Variable: "#268BD2",
|
||||||
|
Type: "#CB4B16",
|
||||||
|
|
||||||
|
Constant: "#CB4B16",
|
||||||
|
Storage: "#93A1A1",
|
||||||
|
Parameter: "#268BD2",
|
||||||
|
Class: "#CB4B16",
|
||||||
|
Heading: "#268BD2",
|
||||||
|
Invalid: "#DC322F",
|
||||||
|
Regexp: "#DC322F",
|
||||||
|
|
||||||
|
Cursor: "#D30102",
|
||||||
|
Selection: "#274642",
|
||||||
|
SelectionBlur: "#274642",
|
||||||
|
ActiveLine: "#005b7022",
|
||||||
|
LineNumber: "#93A1A1",
|
||||||
|
ActiveLineNumber: "#949494",
|
||||||
|
|
||||||
|
BorderColor: "#073642",
|
||||||
|
BorderLight: "#93A1A119",
|
||||||
|
|
||||||
|
SearchMatch: "#2AA198",
|
||||||
|
MatchingBracket: "#073642",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewTokyoNightTheme 创建 Tokyo Night 主题配置
|
||||||
|
func NewTokyoNightTheme() *ThemeColorConfig {
|
||||||
|
return &ThemeColorConfig{
|
||||||
|
Name: "tokyo-night",
|
||||||
|
Dark: true,
|
||||||
|
|
||||||
|
Background: "#1a1b26",
|
||||||
|
BackgroundSecondary: "#1a1b26",
|
||||||
|
Surface: "#1a1b26",
|
||||||
|
DropdownBackground: "#1a1b26",
|
||||||
|
DropdownBorder: "#787c99",
|
||||||
|
|
||||||
|
Foreground: "#787c99",
|
||||||
|
ForegroundSecondary: "#787c99",
|
||||||
|
Comment: "#444b6a",
|
||||||
|
|
||||||
|
Keyword: "#bb9af7",
|
||||||
|
String: "#9ece6a",
|
||||||
|
Function: "#7aa2f7",
|
||||||
|
Number: "#ff9e64",
|
||||||
|
Operator: "#bb9af7",
|
||||||
|
Variable: "#c0caf5",
|
||||||
|
Type: "#0db9d7",
|
||||||
|
|
||||||
|
Constant: "#bb9af7",
|
||||||
|
Storage: "#bb9af7",
|
||||||
|
Parameter: "#c0caf5",
|
||||||
|
Class: "#c0caf5",
|
||||||
|
Heading: "#89ddff",
|
||||||
|
Invalid: "#ff5370",
|
||||||
|
Regexp: "#b4f9f8",
|
||||||
|
|
||||||
|
Cursor: "#c0caf5",
|
||||||
|
Selection: "#515c7e40",
|
||||||
|
SelectionBlur: "#515c7e40",
|
||||||
|
ActiveLine: "#43455c22",
|
||||||
|
LineNumber: "#363b54",
|
||||||
|
ActiveLineNumber: "#737aa2",
|
||||||
|
|
||||||
|
BorderColor: "#16161e",
|
||||||
|
BorderLight: "#787c9919",
|
||||||
|
|
||||||
|
SearchMatch: "#7aa2f7",
|
||||||
|
MatchingBracket: "#16161e",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewTokyoNightStormTheme 创建 Tokyo Night Storm 主题配置
|
||||||
|
func NewTokyoNightStormTheme() *ThemeColorConfig {
|
||||||
|
return &ThemeColorConfig{
|
||||||
|
Name: "tokyo-night-storm",
|
||||||
|
Dark: true,
|
||||||
|
|
||||||
|
Background: "#24283b",
|
||||||
|
BackgroundSecondary: "#24283b",
|
||||||
|
Surface: "#24283b",
|
||||||
|
DropdownBackground: "#24283b",
|
||||||
|
DropdownBorder: "#7982a9",
|
||||||
|
|
||||||
|
Foreground: "#7982a9",
|
||||||
|
ForegroundSecondary: "#7982a9",
|
||||||
|
Comment: "#565f89",
|
||||||
|
|
||||||
|
Keyword: "#bb9af7",
|
||||||
|
String: "#9ece6a",
|
||||||
|
Function: "#7aa2f7",
|
||||||
|
Number: "#ff9e64",
|
||||||
|
Operator: "#bb9af7",
|
||||||
|
Variable: "#c0caf5",
|
||||||
|
Type: "#2ac3de",
|
||||||
|
|
||||||
|
Constant: "#bb9af7",
|
||||||
|
Storage: "#bb9af7",
|
||||||
|
Parameter: "#c0caf5",
|
||||||
|
Class: "#c0caf5",
|
||||||
|
Heading: "#89ddff",
|
||||||
|
Invalid: "#ff5370",
|
||||||
|
Regexp: "#b4f9f8",
|
||||||
|
|
||||||
|
Cursor: "#c0caf5",
|
||||||
|
Selection: "#6f7bb630",
|
||||||
|
SelectionBlur: "#6f7bb630",
|
||||||
|
ActiveLine: "#4d547722",
|
||||||
|
LineNumber: "#3b4261",
|
||||||
|
ActiveLineNumber: "#737aa2",
|
||||||
|
|
||||||
|
BorderColor: "#1f2335",
|
||||||
|
BorderLight: "#7982a919",
|
||||||
|
|
||||||
|
SearchMatch: "#7aa2f7",
|
||||||
|
MatchingBracket: "#1f2335",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 浅色主题预设配置
|
||||||
|
|
||||||
|
// NewGitHubLightTheme 创建 GitHub Light 主题配置
|
||||||
|
func NewGitHubLightTheme() *ThemeColorConfig {
|
||||||
|
return &ThemeColorConfig{
|
||||||
|
Name: "github-light",
|
||||||
|
Dark: false,
|
||||||
|
|
||||||
|
Background: "#fff",
|
||||||
|
BackgroundSecondary: "#fff",
|
||||||
|
Surface: "#fff",
|
||||||
|
DropdownBackground: "#fff",
|
||||||
|
DropdownBorder: "#e1e4e8",
|
||||||
|
|
||||||
|
Foreground: "#444d56",
|
||||||
|
ForegroundSecondary: "#444d56",
|
||||||
|
Comment: "#6a737d",
|
||||||
|
|
||||||
|
Keyword: "#d73a49",
|
||||||
|
String: "#032f62",
|
||||||
|
Function: "#005cc5",
|
||||||
|
Number: "#005cc5",
|
||||||
|
Operator: "#d73a49",
|
||||||
|
Variable: "#e36209",
|
||||||
|
Type: "#005cc5",
|
||||||
|
|
||||||
|
Constant: "#005cc5",
|
||||||
|
Storage: "#d73a49",
|
||||||
|
Parameter: "#24292e",
|
||||||
|
Class: "#6f42c1",
|
||||||
|
Heading: "#005cc5",
|
||||||
|
Invalid: "#cb2431",
|
||||||
|
Regexp: "#032f62",
|
||||||
|
|
||||||
|
Cursor: "#044289",
|
||||||
|
Selection: "#0366d625",
|
||||||
|
SelectionBlur: "#0366d625",
|
||||||
|
ActiveLine: "#c6c6c622",
|
||||||
|
LineNumber: "#1b1f234d",
|
||||||
|
ActiveLineNumber: "#24292e",
|
||||||
|
|
||||||
|
BorderColor: "#e1e4e8",
|
||||||
|
BorderLight: "#444d5619",
|
||||||
|
|
||||||
|
SearchMatch: "#005cc5",
|
||||||
|
MatchingBracket: "#34d05840",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewMaterialLightTheme 创建 Material Light 主题配置
|
||||||
|
func NewMaterialLightTheme() *ThemeColorConfig {
|
||||||
|
return &ThemeColorConfig{
|
||||||
|
Name: "material-light",
|
||||||
|
Dark: false,
|
||||||
|
|
||||||
|
Background: "#FAFAFA",
|
||||||
|
BackgroundSecondary: "#FAFAFA",
|
||||||
|
Surface: "#FAFAFA",
|
||||||
|
DropdownBackground: "#FAFAFA",
|
||||||
|
DropdownBorder: "#00000010",
|
||||||
|
|
||||||
|
Foreground: "#90A4AE",
|
||||||
|
ForegroundSecondary: "#90A4AE",
|
||||||
|
Comment: "#90A4AE",
|
||||||
|
|
||||||
|
Keyword: "#7C4DFF",
|
||||||
|
String: "#91B859",
|
||||||
|
Function: "#6182B8",
|
||||||
|
Number: "#F76D47",
|
||||||
|
Operator: "#7C4DFF",
|
||||||
|
Variable: "#90A4AE",
|
||||||
|
Type: "#8796B0",
|
||||||
|
|
||||||
|
Constant: "#F76D47",
|
||||||
|
Storage: "#7C4DFF",
|
||||||
|
Parameter: "#90A4AE",
|
||||||
|
Class: "#FFB62C",
|
||||||
|
Heading: "#91B859",
|
||||||
|
Invalid: "#E53935",
|
||||||
|
Regexp: "#39ADB5",
|
||||||
|
|
||||||
|
Cursor: "#272727",
|
||||||
|
Selection: "#80CBC440",
|
||||||
|
SelectionBlur: "#80CBC440",
|
||||||
|
ActiveLine: "#c2c2c222",
|
||||||
|
LineNumber: "#CFD8DC",
|
||||||
|
ActiveLineNumber: "#7E939E",
|
||||||
|
|
||||||
|
BorderColor: "#00000010",
|
||||||
|
BorderLight: "#90A4AE19",
|
||||||
|
|
||||||
|
SearchMatch: "#6182B8",
|
||||||
|
MatchingBracket: "#FAFAFA",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewSolarizedLightTheme 创建 Solarized Light 主题配置
|
||||||
|
func NewSolarizedLightTheme() *ThemeColorConfig {
|
||||||
|
return &ThemeColorConfig{
|
||||||
|
Name: "solarized-light",
|
||||||
|
Dark: false,
|
||||||
|
|
||||||
|
Background: "#FDF6E3",
|
||||||
|
BackgroundSecondary: "#FDF6E3",
|
||||||
|
Surface: "#FDF6E3",
|
||||||
|
DropdownBackground: "#FDF6E3",
|
||||||
|
DropdownBorder: "#D3AF86",
|
||||||
|
|
||||||
|
Foreground: "#586E75",
|
||||||
|
ForegroundSecondary: "#586E75",
|
||||||
|
Comment: "#93A1A1",
|
||||||
|
|
||||||
|
Keyword: "#859900",
|
||||||
|
String: "#2AA198",
|
||||||
|
Function: "#268BD2",
|
||||||
|
Number: "#D33682",
|
||||||
|
Operator: "#859900",
|
||||||
|
Variable: "#268BD2",
|
||||||
|
Type: "#CB4B16",
|
||||||
|
|
||||||
|
Constant: "#CB4B16",
|
||||||
|
Storage: "#586E75",
|
||||||
|
Parameter: "#268BD2",
|
||||||
|
Class: "#CB4B16",
|
||||||
|
Heading: "#268BD2",
|
||||||
|
Invalid: "#DC322F",
|
||||||
|
Regexp: "#DC322F",
|
||||||
|
|
||||||
|
Cursor: "#657B83",
|
||||||
|
Selection: "#EEE8D5",
|
||||||
|
SelectionBlur: "#EEE8D5",
|
||||||
|
ActiveLine: "#d5bd5c22",
|
||||||
|
LineNumber: "#586E75",
|
||||||
|
ActiveLineNumber: "#567983",
|
||||||
|
|
||||||
|
BorderColor: "#EEE8D5",
|
||||||
|
BorderLight: "#586E7519",
|
||||||
|
|
||||||
|
SearchMatch: "#268BD2",
|
||||||
|
MatchingBracket: "#EEE8D5",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewTokyoNightDayTheme 创建 Tokyo Night Day 主题配置
|
||||||
|
func NewTokyoNightDayTheme() *ThemeColorConfig {
|
||||||
|
return &ThemeColorConfig{
|
||||||
|
Name: "tokyo-night-day",
|
||||||
|
Dark: false,
|
||||||
|
|
||||||
|
Background: "#e1e2e7",
|
||||||
|
BackgroundSecondary: "#e1e2e7",
|
||||||
|
Surface: "#e1e2e7",
|
||||||
|
DropdownBackground: "#e1e2e7",
|
||||||
|
DropdownBorder: "#6a6f8e",
|
||||||
|
|
||||||
|
Foreground: "#6a6f8e",
|
||||||
|
ForegroundSecondary: "#6a6f8e",
|
||||||
|
Comment: "#9da3c2",
|
||||||
|
|
||||||
|
Keyword: "#9854f1",
|
||||||
|
String: "#587539",
|
||||||
|
Function: "#2e7de9",
|
||||||
|
Number: "#b15c00",
|
||||||
|
Operator: "#9854f1",
|
||||||
|
Variable: "#3760bf",
|
||||||
|
Type: "#07879d",
|
||||||
|
|
||||||
|
Constant: "#9854f1",
|
||||||
|
Storage: "#9854f1",
|
||||||
|
Parameter: "#3760bf",
|
||||||
|
Class: "#3760bf",
|
||||||
|
Heading: "#006a83",
|
||||||
|
Invalid: "#ff3e64",
|
||||||
|
Regexp: "#2e5857",
|
||||||
|
|
||||||
|
Cursor: "#3760bf",
|
||||||
|
Selection: "#8591b840",
|
||||||
|
SelectionBlur: "#8591b840",
|
||||||
|
ActiveLine: "#a7aaba22",
|
||||||
|
LineNumber: "#b3b6cd",
|
||||||
|
ActiveLineNumber: "#68709a",
|
||||||
|
|
||||||
|
BorderColor: "#e9e9ec",
|
||||||
|
BorderLight: "#6a6f8e19",
|
||||||
|
|
||||||
|
SearchMatch: "#2e7de9",
|
||||||
|
MatchingBracket: "#e9e9ec",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -67,13 +67,12 @@ CREATE TABLE IF NOT EXISTS key_bindings (
|
|||||||
sqlCreateThemesTable = `
|
sqlCreateThemesTable = `
|
||||||
CREATE TABLE IF NOT EXISTS themes (
|
CREATE TABLE IF NOT EXISTS themes (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
name TEXT NOT NULL,
|
name TEXT NOT NULL UNIQUE,
|
||||||
type TEXT NOT NULL,
|
type TEXT NOT NULL,
|
||||||
colors TEXT NOT NULL,
|
colors TEXT NOT NULL,
|
||||||
is_default INTEGER NOT NULL DEFAULT 0,
|
is_default INTEGER NOT NULL DEFAULT 0,
|
||||||
created_at TEXT NOT NULL,
|
created_at TEXT NOT NULL,
|
||||||
updated_at TEXT NOT NULL,
|
updated_at TEXT NOT NULL
|
||||||
UNIQUE(type, is_default)
|
|
||||||
)`
|
)`
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -222,6 +221,8 @@ func (ds *DatabaseService) createIndexes() error {
|
|||||||
// Themes indexes
|
// Themes indexes
|
||||||
`CREATE INDEX IF NOT EXISTS idx_themes_type ON themes(type)`,
|
`CREATE INDEX IF NOT EXISTS idx_themes_type ON themes(type)`,
|
||||||
`CREATE INDEX IF NOT EXISTS idx_themes_is_default ON themes(is_default)`,
|
`CREATE INDEX IF NOT EXISTS idx_themes_is_default ON themes(is_default)`,
|
||||||
|
// 条件唯一索引:确保每种类型只能有一个默认主题
|
||||||
|
`CREATE UNIQUE INDEX IF NOT EXISTS idx_themes_type_default ON themes(type) WHERE is_default = 1`,
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, index := range indexes {
|
for _, index := range indexes {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package services
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
"voidraft/internal/models"
|
"voidraft/internal/models"
|
||||||
@@ -43,96 +44,141 @@ func (ts *ThemeService) getDB() *sql.DB {
|
|||||||
return ts.databaseService.db
|
return ts.databaseService.db
|
||||||
}
|
}
|
||||||
|
|
||||||
// initializeDefaultThemes 初始化默认主题
|
// initializeDefaultThemes 初始化所有预设主题
|
||||||
func (ts *ThemeService) initializeDefaultThemes() error {
|
func (ts *ThemeService) initializeDefaultThemes() error {
|
||||||
db := ts.getDB()
|
db := ts.getDB()
|
||||||
if db == nil {
|
if db == nil {
|
||||||
return fmt.Errorf("database not available")
|
return fmt.Errorf("database not available")
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查是否已存在默认主题
|
// 获取所有已存在的主题名称
|
||||||
var count int
|
existingThemes := make(map[string]bool)
|
||||||
err := db.QueryRow("SELECT COUNT(*) FROM themes WHERE is_default = 1").Scan(&count)
|
rows, err := db.Query("SELECT name FROM themes")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to check existing themes: %w", err)
|
return fmt.Errorf("failed to query existing themes: %w", err)
|
||||||
}
|
|
||||||
|
|
||||||
if count > 0 {
|
|
||||||
return nil // 默认主题已存在
|
|
||||||
}
|
|
||||||
|
|
||||||
// 创建默认深色主题
|
|
||||||
now := time.Now().Format("2006-01-02 15:04:05")
|
|
||||||
darkTheme := &models.Theme{
|
|
||||||
Name: "Default Dark",
|
|
||||||
Type: models.ThemeTypeDark,
|
|
||||||
Colors: *models.NewDefaultDarkTheme(),
|
|
||||||
IsDefault: true,
|
|
||||||
CreatedAt: now,
|
|
||||||
UpdatedAt: now,
|
|
||||||
}
|
|
||||||
|
|
||||||
// 创建默认浅色主题
|
|
||||||
lightTheme := &models.Theme{
|
|
||||||
Name: "Default Light",
|
|
||||||
Type: models.ThemeTypeLight,
|
|
||||||
Colors: *models.NewDefaultLightTheme(),
|
|
||||||
IsDefault: true,
|
|
||||||
CreatedAt: now,
|
|
||||||
UpdatedAt: now,
|
|
||||||
}
|
|
||||||
|
|
||||||
// 插入默认主题
|
|
||||||
if _, err := ts.CreateTheme(darkTheme); err != nil {
|
|
||||||
return fmt.Errorf("failed to create default dark theme: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := ts.CreateTheme(lightTheme); err != nil {
|
|
||||||
return fmt.Errorf("failed to create default light theme: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetDefaultThemes 获取默认主题
|
|
||||||
func (ts *ThemeService) GetDefaultThemes() (map[string]*models.Theme, error) {
|
|
||||||
query := `
|
|
||||||
SELECT id, name, type, colors, is_default, created_at, updated_at
|
|
||||||
FROM themes
|
|
||||||
WHERE is_default = 1
|
|
||||||
ORDER BY type
|
|
||||||
`
|
|
||||||
|
|
||||||
db := ts.getDB()
|
|
||||||
rows, err := db.Query(query)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to query default themes: %w", err)
|
|
||||||
}
|
}
|
||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
|
|
||||||
themes := make(map[string]*models.Theme)
|
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
theme := &models.Theme{}
|
var name string
|
||||||
err := rows.Scan(
|
if err := rows.Scan(&name); err != nil {
|
||||||
&theme.ID,
|
return fmt.Errorf("failed to scan theme name: %w", err)
|
||||||
&theme.Name,
|
}
|
||||||
&theme.Type,
|
existingThemes[name] = true
|
||||||
&theme.Colors,
|
}
|
||||||
&theme.IsDefault,
|
|
||||||
&theme.CreatedAt,
|
// 定义所有预设主题配置
|
||||||
&theme.UpdatedAt,
|
now := time.Now().Format("2006-01-02 15:04:05")
|
||||||
|
presetThemes := []struct {
|
||||||
|
config *models.ThemeColorConfig
|
||||||
|
themeType models.ThemeType
|
||||||
|
isDefault bool
|
||||||
|
}{
|
||||||
|
// 默认主题
|
||||||
|
{models.NewDefaultDarkTheme(), models.ThemeTypeDark, true},
|
||||||
|
{models.NewDefaultLightTheme(), models.ThemeTypeLight, true},
|
||||||
|
|
||||||
|
// 深色主题预设
|
||||||
|
{models.NewDraculaTheme(), models.ThemeTypeDark, false},
|
||||||
|
{models.NewAuraTheme(), models.ThemeTypeDark, false},
|
||||||
|
{models.NewGitHubDarkTheme(), models.ThemeTypeDark, false},
|
||||||
|
{models.NewMaterialDarkTheme(), models.ThemeTypeDark, false},
|
||||||
|
{models.NewOneDarkTheme(), models.ThemeTypeDark, false},
|
||||||
|
{models.NewSolarizedDarkTheme(), models.ThemeTypeDark, false},
|
||||||
|
{models.NewTokyoNightTheme(), models.ThemeTypeDark, false},
|
||||||
|
{models.NewTokyoNightStormTheme(), models.ThemeTypeDark, false},
|
||||||
|
|
||||||
|
// 浅色主题预设
|
||||||
|
{models.NewGitHubLightTheme(), models.ThemeTypeLight, false},
|
||||||
|
{models.NewMaterialLightTheme(), models.ThemeTypeLight, false},
|
||||||
|
{models.NewSolarizedLightTheme(), models.ThemeTypeLight, false},
|
||||||
|
{models.NewTokyoNightDayTheme(), models.ThemeTypeLight, false},
|
||||||
|
}
|
||||||
|
|
||||||
|
// 筛选出需要创建的主题
|
||||||
|
var themesToCreate []*models.Theme
|
||||||
|
for _, preset := range presetThemes {
|
||||||
|
if !existingThemes[preset.config.Name] {
|
||||||
|
themesToCreate = append(themesToCreate, &models.Theme{
|
||||||
|
Name: preset.config.Name,
|
||||||
|
Type: preset.themeType,
|
||||||
|
Colors: *preset.config,
|
||||||
|
IsDefault: preset.isDefault,
|
||||||
|
CreatedAt: now,
|
||||||
|
UpdatedAt: now,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(themesToCreate) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 批量插入主题
|
||||||
|
tx, err := db.Begin()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to begin transaction: %w", err)
|
||||||
|
}
|
||||||
|
defer tx.Rollback()
|
||||||
|
|
||||||
|
stmt, err := tx.Prepare(`
|
||||||
|
INSERT INTO themes (name, type, colors, is_default, created_at, updated_at)
|
||||||
|
VALUES (?, ?, ?, ?, ?, ?)
|
||||||
|
`)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to prepare statement: %w", err)
|
||||||
|
}
|
||||||
|
defer stmt.Close()
|
||||||
|
|
||||||
|
for _, theme := range themesToCreate {
|
||||||
|
_, err := stmt.Exec(
|
||||||
|
theme.Name,
|
||||||
|
theme.Type,
|
||||||
|
theme.Colors,
|
||||||
|
theme.IsDefault,
|
||||||
|
theme.CreatedAt,
|
||||||
|
theme.UpdatedAt,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to scan theme: %w", err)
|
return fmt.Errorf("failed to insert theme %s: %w", theme.Name, err)
|
||||||
}
|
}
|
||||||
themes[string(theme.Type)] = theme
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := rows.Err(); err != nil {
|
if err := tx.Commit(); err != nil {
|
||||||
return nil, fmt.Errorf("failed to iterate themes: %w", err)
|
return fmt.Errorf("failed to commit transaction: %w", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetThemeByID 根据ID获取主题
|
||||||
|
func (ts *ThemeService) GetThemeByID(id int) (*models.Theme, error) {
|
||||||
|
query := `
|
||||||
|
SELECT id, name, type, colors, is_default, created_at, updated_at
|
||||||
|
FROM themes
|
||||||
|
WHERE id = ?
|
||||||
|
LIMIT 1
|
||||||
|
`
|
||||||
|
|
||||||
|
theme := &models.Theme{}
|
||||||
|
db := ts.getDB()
|
||||||
|
err := db.QueryRow(query, id).Scan(
|
||||||
|
&theme.ID,
|
||||||
|
&theme.Name,
|
||||||
|
&theme.Type,
|
||||||
|
&theme.Colors,
|
||||||
|
&theme.IsDefault,
|
||||||
|
&theme.CreatedAt,
|
||||||
|
&theme.UpdatedAt,
|
||||||
|
)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, sql.ErrNoRows) {
|
||||||
|
return nil, fmt.Errorf("theme not found with id: %d", id)
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("failed to get theme by id: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return themes, nil
|
return theme, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetThemeByType 根据类型获取默认主题
|
// GetThemeByType 根据类型获取默认主题
|
||||||
@@ -166,37 +212,123 @@ func (ts *ThemeService) GetThemeByType(themeType models.ThemeType) (*models.Them
|
|||||||
return theme, nil
|
return theme, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateThemeColors 更新主题颜色
|
// GetThemesByType 根据类型获取所有主题
|
||||||
func (ts *ThemeService) UpdateThemeColors(themeType models.ThemeType, colors models.ThemeColorConfig) error {
|
func (ts *ThemeService) GetThemesByType(themeType models.ThemeType) ([]*models.Theme, error) {
|
||||||
query := `
|
query := `
|
||||||
UPDATE themes
|
SELECT id, name, type, colors, is_default, created_at, updated_at
|
||||||
SET colors = ?, updated_at = ?
|
FROM themes
|
||||||
WHERE type = ? AND is_default = 1
|
WHERE type = ?
|
||||||
|
ORDER BY is_default DESC, name ASC
|
||||||
`
|
`
|
||||||
|
|
||||||
db := ts.getDB()
|
db := ts.getDB()
|
||||||
_, err := db.Exec(query, colors, time.Now().Format("2006-01-02 15:04:05"), themeType)
|
rows, err := db.Query(query, themeType)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to update theme colors: %w", err)
|
return nil, fmt.Errorf("failed to query themes by type: %w", err)
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
var themes []*models.Theme
|
||||||
|
for rows.Next() {
|
||||||
|
theme := &models.Theme{}
|
||||||
|
err := rows.Scan(
|
||||||
|
&theme.ID,
|
||||||
|
&theme.Name,
|
||||||
|
&theme.Type,
|
||||||
|
&theme.Colors,
|
||||||
|
&theme.IsDefault,
|
||||||
|
&theme.CreatedAt,
|
||||||
|
&theme.UpdatedAt,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to scan theme: %w", err)
|
||||||
|
}
|
||||||
|
themes = append(themes, theme)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := rows.Err(); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to iterate themes: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return themes, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateTheme 更新主题
|
||||||
|
func (ts *ThemeService) UpdateTheme(id int, colors models.ThemeColorConfig) error {
|
||||||
|
query := `
|
||||||
|
UPDATE themes
|
||||||
|
SET colors = ?, updated_at = ?
|
||||||
|
WHERE id = ?
|
||||||
|
`
|
||||||
|
|
||||||
|
db := ts.getDB()
|
||||||
|
result, err := db.Exec(query, colors, time.Now().Format("2006-01-02 15:04:05"), id)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to update theme: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
rowsAffected, err := result.RowsAffected()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to get rows affected: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if rowsAffected == 0 {
|
||||||
|
return fmt.Errorf("theme not found with id: %d", id)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ResetThemeColors 重置主题颜色为默认值
|
// ResetTheme 重置主题为预设配置
|
||||||
func (ts *ThemeService) ResetThemeColors(themeType models.ThemeType) error {
|
func (ts *ThemeService) ResetTheme(id int) error {
|
||||||
var defaultColors models.ThemeColorConfig
|
// 先获取主题信息
|
||||||
|
theme, err := ts.GetThemeByID(id)
|
||||||
switch themeType {
|
if err != nil {
|
||||||
case models.ThemeTypeDark:
|
return err
|
||||||
defaultColors = *models.NewDefaultDarkTheme()
|
|
||||||
case models.ThemeTypeLight:
|
|
||||||
defaultColors = *models.NewDefaultLightTheme()
|
|
||||||
default:
|
|
||||||
return fmt.Errorf("unknown theme type: %s", themeType)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ts.UpdateThemeColors(themeType, defaultColors)
|
// 根据主题名称获取预设配置
|
||||||
|
var presetConfig *models.ThemeColorConfig
|
||||||
|
switch theme.Name {
|
||||||
|
// 默认主题
|
||||||
|
case "default-dark":
|
||||||
|
presetConfig = models.NewDefaultDarkTheme()
|
||||||
|
case "default-light":
|
||||||
|
presetConfig = models.NewDefaultLightTheme()
|
||||||
|
|
||||||
|
// 深色主题预设
|
||||||
|
case "dracula":
|
||||||
|
presetConfig = models.NewDraculaTheme()
|
||||||
|
case "aura":
|
||||||
|
presetConfig = models.NewAuraTheme()
|
||||||
|
case "github-dark":
|
||||||
|
presetConfig = models.NewGitHubDarkTheme()
|
||||||
|
case "material-dark":
|
||||||
|
presetConfig = models.NewMaterialDarkTheme()
|
||||||
|
case "one-dark":
|
||||||
|
presetConfig = models.NewOneDarkTheme()
|
||||||
|
case "solarized-dark":
|
||||||
|
presetConfig = models.NewSolarizedDarkTheme()
|
||||||
|
case "tokyo-night":
|
||||||
|
presetConfig = models.NewTokyoNightTheme()
|
||||||
|
case "tokyo-night-storm":
|
||||||
|
presetConfig = models.NewTokyoNightStormTheme()
|
||||||
|
|
||||||
|
// 浅色主题预设
|
||||||
|
case "github-light":
|
||||||
|
presetConfig = models.NewGitHubLightTheme()
|
||||||
|
case "material-light":
|
||||||
|
presetConfig = models.NewMaterialLightTheme()
|
||||||
|
case "solarized-light":
|
||||||
|
presetConfig = models.NewSolarizedLightTheme()
|
||||||
|
case "tokyo-night-day":
|
||||||
|
presetConfig = models.NewTokyoNightDayTheme()
|
||||||
|
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("no preset configuration found for theme: %s", theme.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ts.UpdateTheme(id, *presetConfig)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateTheme 创建新主题
|
// CreateTheme 创建新主题
|
||||||
@@ -235,7 +367,7 @@ func (ts *ThemeService) GetAllThemes() ([]*models.Theme, error) {
|
|||||||
query := `
|
query := `
|
||||||
SELECT id, name, type, colors, is_default, created_at, updated_at
|
SELECT id, name, type, colors, is_default, created_at, updated_at
|
||||||
FROM themes
|
FROM themes
|
||||||
ORDER BY is_default DESC, created_at ASC
|
ORDER BY is_default DESC, type DESC, name ASC
|
||||||
`
|
`
|
||||||
|
|
||||||
db := ts.getDB()
|
db := ts.getDB()
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
VERSION=1.5.0
|
VERSION=1.5.1
|
||||||
|
|||||||
Reference in New Issue
Block a user