✨ Added preset theme
This commit is contained in:
@@ -14,17 +14,25 @@ const (
|
||||
ThemeTypeLight ThemeType = "light"
|
||||
)
|
||||
|
||||
// ThemeColorConfig 主题颜色配置
|
||||
// ThemeColorConfig 主题颜色配置(与前端 ThemeColors 接口保持一致)
|
||||
type ThemeColorConfig struct {
|
||||
// 主题基本信息
|
||||
Name string `json:"name"` // 主题名称
|
||||
Dark bool `json:"dark"` // 是否为深色主题
|
||||
|
||||
// 基础色调
|
||||
Background string `json:"background"` // 主背景色
|
||||
BackgroundSecondary string `json:"backgroundSecondary"` // 次要背景色
|
||||
BackgroundSecondary string `json:"backgroundSecondary"` // 次要背景色(用于代码块交替背景)
|
||||
Surface string `json:"surface"` // 面板背景
|
||||
DropdownBackground string `json:"dropdownBackground"` // 下拉菜单背景
|
||||
DropdownBorder string `json:"dropdownBorder"` // 下拉菜单边框
|
||||
|
||||
// 文本颜色
|
||||
Foreground string `json:"foreground"` // 主文本色
|
||||
ForegroundSecondary string `json:"foregroundSecondary"` // 次要文本色
|
||||
Comment string `json:"comment"` // 注释色
|
||||
|
||||
// 语法高亮
|
||||
Comment string `json:"comment"` // 注释色
|
||||
// 语法高亮色 - 核心
|
||||
Keyword string `json:"keyword"` // 关键字
|
||||
String string `json:"string"` // 字符串
|
||||
Function string `json:"function"` // 函数名
|
||||
@@ -33,34 +41,32 @@ type ThemeColorConfig struct {
|
||||
Variable string `json:"variable"` // 变量
|
||||
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"` // 光标
|
||||
Selection string `json:"selection"` // 选中背景
|
||||
SelectionBlur string `json:"selectionBlur"` // 失焦选中背景
|
||||
ActiveLine string `json:"activeLine"` // 当前行高亮
|
||||
LineNumber string `json:"lineNumber"` // 行号
|
||||
ActiveLineNumber string `json:"activeLineNumber"` // 活动行号
|
||||
ActiveLineNumber string `json:"activeLineNumber"` // 活动行号颜色
|
||||
|
||||
// 边框分割线
|
||||
// 边框和分割线
|
||||
BorderColor string `json:"borderColor"` // 边框色
|
||||
BorderLight string `json:"borderLight"` // 浅色边框
|
||||
|
||||
// 搜索匹配
|
||||
// 搜索和匹配
|
||||
SearchMatch string `json:"searchMatch"` // 搜索匹配
|
||||
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 存储到数据库
|
||||
func (tc ThemeColorConfig) Value() (driver.Value, error) {
|
||||
return json.Marshal(tc)
|
||||
@@ -85,18 +91,37 @@ func (tc *ThemeColorConfig) Scan(value interface{}) error {
|
||||
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 {
|
||||
return &ThemeColorConfig{
|
||||
// 主题信息
|
||||
Name: "default-dark",
|
||||
Dark: true,
|
||||
|
||||
// 基础色调
|
||||
Background: "#252B37",
|
||||
BackgroundSecondary: "#213644",
|
||||
Surface: "#474747",
|
||||
DropdownBackground: "#252B37",
|
||||
DropdownBorder: "#ffffff19",
|
||||
|
||||
// 文本颜色
|
||||
Foreground: "#9BB586",
|
||||
ForegroundSecondary: "#9c9c9c",
|
||||
Comment: "#6272a4",
|
||||
|
||||
// 语法高亮
|
||||
Comment: "#6272a4",
|
||||
// 语法高亮色 - 核心
|
||||
Keyword: "#ff79c6",
|
||||
String: "#f1fa8c",
|
||||
Function: "#50fa7b",
|
||||
@@ -105,6 +130,15 @@ func NewDefaultDarkTheme() *ThemeColorConfig {
|
||||
Variable: "#8fbcbb",
|
||||
Type: "#8be9fd",
|
||||
|
||||
// 语法高亮色 - 扩展
|
||||
Constant: "#bd93f9",
|
||||
Storage: "#ff79c6",
|
||||
Parameter: "#8fbcbb",
|
||||
Class: "#8be9fd",
|
||||
Heading: "#ff79c6",
|
||||
Invalid: "#d30102",
|
||||
Regexp: "#f1fa8c",
|
||||
|
||||
// 界面元素
|
||||
Cursor: "#ffffff",
|
||||
Selection: "#0865a9",
|
||||
@@ -113,28 +147,36 @@ func NewDefaultDarkTheme() *ThemeColorConfig {
|
||||
LineNumber: "#ffffff26",
|
||||
ActiveLineNumber: "#ffffff99",
|
||||
|
||||
// 边框分割线
|
||||
// 边框和分割线
|
||||
BorderColor: "#1e222a",
|
||||
BorderLight: "#ffffff1a",
|
||||
BorderLight: "#ffffff19",
|
||||
|
||||
// 搜索匹配
|
||||
// 搜索和匹配
|
||||
SearchMatch: "#8fbcbb",
|
||||
MatchingBracket: "#ffffff1a",
|
||||
MatchingBracket: "#ffffff19",
|
||||
}
|
||||
}
|
||||
|
||||
// NewDefaultLightTheme 创建默认浅色主题配置
|
||||
// NewDefaultLightTheme 创建默认浅色主题配置(与前端 defaultLightColors 完全一致)
|
||||
func NewDefaultLightTheme() *ThemeColorConfig {
|
||||
return &ThemeColorConfig{
|
||||
// 主题信息
|
||||
Name: "default-light",
|
||||
Dark: false,
|
||||
|
||||
// 基础色调
|
||||
Background: "#ffffff",
|
||||
BackgroundSecondary: "#f1faf1",
|
||||
Surface: "#f5f5f5",
|
||||
DropdownBackground: "#ffffff",
|
||||
DropdownBorder: "#e1e4e8",
|
||||
|
||||
// 文本颜色
|
||||
Foreground: "#444d56",
|
||||
ForegroundSecondary: "#6a737d",
|
||||
Comment: "#6a737d",
|
||||
|
||||
// 语法高亮
|
||||
Comment: "#6a737d",
|
||||
// 语法高亮色 - 核心
|
||||
Keyword: "#d73a49",
|
||||
String: "#032f62",
|
||||
Function: "#005cc5",
|
||||
@@ -143,6 +185,15 @@ func NewDefaultLightTheme() *ThemeColorConfig {
|
||||
Variable: "#24292e",
|
||||
Type: "#6f42c1",
|
||||
|
||||
// 语法高亮色 - 扩展
|
||||
Constant: "#005cc5",
|
||||
Storage: "#d73a49",
|
||||
Parameter: "#24292e",
|
||||
Class: "#6f42c1",
|
||||
Heading: "#d73a49",
|
||||
Invalid: "#cb2431",
|
||||
Regexp: "#032f62",
|
||||
|
||||
// 界面元素
|
||||
Cursor: "#000000",
|
||||
Selection: "#77baff",
|
||||
@@ -151,12 +202,578 @@ func NewDefaultLightTheme() *ThemeColorConfig {
|
||||
LineNumber: "#00000040",
|
||||
ActiveLineNumber: "#000000aa",
|
||||
|
||||
// 边框分割线
|
||||
// 边框和分割线
|
||||
BorderColor: "#dfdfdf",
|
||||
BorderLight: "#0000000c",
|
||||
|
||||
// 搜索匹配
|
||||
// 搜索和匹配
|
||||
SearchMatch: "#005cc5",
|
||||
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 = `
|
||||
CREATE TABLE IF NOT EXISTS themes (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT NOT NULL,
|
||||
name TEXT NOT NULL UNIQUE,
|
||||
type TEXT NOT NULL,
|
||||
colors TEXT NOT NULL,
|
||||
is_default INTEGER NOT NULL DEFAULT 0,
|
||||
created_at TEXT NOT NULL,
|
||||
updated_at TEXT NOT NULL,
|
||||
UNIQUE(type, is_default)
|
||||
updated_at TEXT NOT NULL
|
||||
)`
|
||||
)
|
||||
|
||||
@@ -222,6 +221,8 @@ func (ds *DatabaseService) createIndexes() error {
|
||||
// Themes indexes
|
||||
`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 UNIQUE INDEX IF NOT EXISTS idx_themes_type_default ON themes(type) WHERE is_default = 1`,
|
||||
}
|
||||
|
||||
for _, index := range indexes {
|
||||
|
||||
@@ -3,6 +3,7 @@ package services
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
"voidraft/internal/models"
|
||||
@@ -43,96 +44,141 @@ func (ts *ThemeService) getDB() *sql.DB {
|
||||
return ts.databaseService.db
|
||||
}
|
||||
|
||||
// initializeDefaultThemes 初始化默认主题
|
||||
// initializeDefaultThemes 初始化所有预设主题
|
||||
func (ts *ThemeService) initializeDefaultThemes() error {
|
||||
db := ts.getDB()
|
||||
if db == nil {
|
||||
return fmt.Errorf("database not available")
|
||||
}
|
||||
|
||||
// 检查是否已存在默认主题
|
||||
var count int
|
||||
err := db.QueryRow("SELECT COUNT(*) FROM themes WHERE is_default = 1").Scan(&count)
|
||||
// 获取所有已存在的主题名称
|
||||
existingThemes := make(map[string]bool)
|
||||
rows, err := db.Query("SELECT name FROM themes")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to check 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)
|
||||
return fmt.Errorf("failed to query existing themes: %w", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
themes := make(map[string]*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,
|
||||
var name string
|
||||
if err := rows.Scan(&name); err != nil {
|
||||
return fmt.Errorf("failed to scan theme name: %w", err)
|
||||
}
|
||||
existingThemes[name] = true
|
||||
}
|
||||
|
||||
// 定义所有预设主题配置
|
||||
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 {
|
||||
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 {
|
||||
return nil, fmt.Errorf("failed to iterate themes: %w", err)
|
||||
if err := tx.Commit(); err != nil {
|
||||
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 根据类型获取默认主题
|
||||
@@ -166,37 +212,123 @@ func (ts *ThemeService) GetThemeByType(themeType models.ThemeType) (*models.Them
|
||||
return theme, nil
|
||||
}
|
||||
|
||||
// UpdateThemeColors 更新主题颜色
|
||||
func (ts *ThemeService) UpdateThemeColors(themeType models.ThemeType, colors models.ThemeColorConfig) error {
|
||||
// GetThemesByType 根据类型获取所有主题
|
||||
func (ts *ThemeService) GetThemesByType(themeType models.ThemeType) ([]*models.Theme, error) {
|
||||
query := `
|
||||
UPDATE themes
|
||||
SET colors = ?, updated_at = ?
|
||||
WHERE type = ? AND is_default = 1
|
||||
SELECT id, name, type, colors, is_default, created_at, updated_at
|
||||
FROM themes
|
||||
WHERE type = ?
|
||||
ORDER BY is_default DESC, name ASC
|
||||
`
|
||||
|
||||
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 {
|
||||
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
|
||||
}
|
||||
|
||||
// ResetThemeColors 重置主题颜色为默认值
|
||||
func (ts *ThemeService) ResetThemeColors(themeType models.ThemeType) error {
|
||||
var defaultColors models.ThemeColorConfig
|
||||
|
||||
switch themeType {
|
||||
case models.ThemeTypeDark:
|
||||
defaultColors = *models.NewDefaultDarkTheme()
|
||||
case models.ThemeTypeLight:
|
||||
defaultColors = *models.NewDefaultLightTheme()
|
||||
default:
|
||||
return fmt.Errorf("unknown theme type: %s", themeType)
|
||||
// ResetTheme 重置主题为预设配置
|
||||
func (ts *ThemeService) ResetTheme(id int) error {
|
||||
// 先获取主题信息
|
||||
theme, err := ts.GetThemeByID(id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
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 创建新主题
|
||||
@@ -235,7 +367,7 @@ func (ts *ThemeService) GetAllThemes() ([]*models.Theme, error) {
|
||||
query := `
|
||||
SELECT id, name, type, colors, is_default, created_at, updated_at
|
||||
FROM themes
|
||||
ORDER BY is_default DESC, created_at ASC
|
||||
ORDER BY is_default DESC, type DESC, name ASC
|
||||
`
|
||||
|
||||
db := ts.getDB()
|
||||
|
||||
Reference in New Issue
Block a user