From 9d1bfe45d9a4770b6821f8e3a150dc70b0e49d2c Mon Sep 17 00:00:00 2001 From: Baobhan Sith <80159437+Heavrnl@users.noreply.github.com> Date: Sat, 19 Apr 2025 12:28:30 +0800 Subject: [PATCH] update --- .../src/components/StyleCustomizer.vue | 302 +++++++++--------- packages/frontend/src/locales/en.json | 11 +- packages/frontend/src/locales/zh.json | 11 +- 3 files changed, 164 insertions(+), 160 deletions(-) diff --git a/packages/frontend/src/components/StyleCustomizer.vue b/packages/frontend/src/components/StyleCustomizer.vue index f9cb47f..d342cb9 100644 --- a/packages/frontend/src/components/StyleCustomizer.vue +++ b/packages/frontend/src/components/StyleCustomizer.vue @@ -37,7 +37,6 @@ const themeParseError = ref(null); // 用于显示 JSON 解析错 // 终端主题管理相关状态 const isEditingTheme = ref(false); // 是否正在编辑某个主题 const themeSearchTerm = ref(''); // 主题搜索词 -const themeSortOrder = ref<'nameAsc' | 'nameDesc'>('nameAsc'); // 主题排序方式 // 使用 reactive 确保嵌套对象 themeData 的响应性 // 修正:editingTheme 应该是一个 ref 包含 TerminalTheme 或 null const editingTheme = ref(null); // 正在编辑的主题数据副本 (完整结构) @@ -131,16 +130,13 @@ watch([ const emit = defineEmits(['close']); const closeCustomizer = () => { - // 如果正在编辑主题,提示用户是否放弃更改 + // 如果正在编辑主题,直接关闭并重置状态 if (isEditingTheme.value) { - if (confirm(t('styleCustomizer.confirmCloseEditing'))) { - isEditingTheme.value = false; // 退出编辑状态 - editingTheme.value = null; - emit('close'); - } - } else { - emit('close'); + isEditingTheme.value = false; // 退出编辑状态 + editingTheme.value = null; + saveThemeError.value = null; // 同时清除可能存在的保存错误 } + emit('close'); // 总是触发关闭事件 }; // 当前活动的标签页 @@ -161,15 +157,13 @@ const handleSaveUiTheme = async () => { // 重置 UI 主题 const handleResetUiTheme = async () => { - if (confirm(t('styleCustomizer.confirmResetUi'))) { - try { - await appearanceStore.resetCustomUiTheme(); - // watch 会自动更新 editableUiTheme.value - alert(t('styleCustomizer.uiThemeReset')); - } catch (error: any) { - console.error("重置 UI 主题失败:", error); - alert(t('styleCustomizer.uiThemeResetFailed', { message: error.message })); - } + try { + await appearanceStore.resetCustomUiTheme(); + // watch 会自动更新 editableUiTheme.value + alert(t('styleCustomizer.uiThemeReset')); + } catch (error: any) { + console.error("重置 UI 主题失败:", error); + alert(t('styleCustomizer.uiThemeResetFailed', { message: error.message })); } }; @@ -353,7 +347,7 @@ const handleApplyTheme = async (theme: TerminalTheme) => { try { await appearanceStore.setActiveTerminalTheme(themeIdToApply); // 成功后 activeTerminalThemeId 会自动更新 - alert(t('styleCustomizer.themeAppliedSuccess', { name: theme.name })); // 需要添加翻译 + // alert(`Theme '${theme.name}' applied successfully`); // 移除成功提示 } catch (error: any) { console.error("应用终端主题失败:", error); alert(t('styleCustomizer.setActiveThemeFailed', { message: error.message })); @@ -382,7 +376,7 @@ const handleEditTheme = (theme: TerminalTheme) => { // 基于预设创建副本 const themeCopy = JSON.parse(JSON.stringify(theme)); themeCopy._id = undefined; // 清除 ID,表示是新建 - themeCopy.name = `${theme.name} (${t('styleCustomizer.copySuffix', '副本')})`; // 添加后缀,需要添加翻译 '副本' + themeCopy.name = `${theme.name} (Copy)`; themeCopy.isPreset = false; // 副本不再是预设 editingTheme.value = themeCopy; console.log('创建预设主题副本进行编辑:', editingTheme.value); @@ -438,14 +432,12 @@ const handleCancelEditingTheme = () => { // 删除主题 const handleDeleteTheme = async (theme: TerminalTheme) => { if (theme.isPreset) return; - if (confirm(t('styleCustomizer.confirmDeleteTheme', { name: theme.name }))) { - try { - await appearanceStore.deleteTerminalTheme(theme._id!); - alert(t('styleCustomizer.themeDeletedSuccess')); - } catch (error: any) { - console.error("删除终端主题失败:", error); - alert(t('styleCustomizer.themeDeleteFailed', { message: error.message })); - } + try { + await appearanceStore.deleteTerminalTheme(theme._id!); + alert(t('styleCustomizer.themeDeletedSuccess')); + } catch (error: any) { + console.error("删除终端主题失败:", error); + alert(t('styleCustomizer.themeDeleteFailed', { message: error.message })); } }; @@ -531,26 +523,22 @@ const handleTerminalBgUpload = async (event: Event) => { }; const handleRemovePageBg = async () => { - if (confirm(t('styleCustomizer.confirmRemovePageBg'))) { - try { - await appearanceStore.removePageBackground(); - alert(t('styleCustomizer.pageBgRemoved')); - } catch (error: any) { - console.error("移除页面背景失败:", error); - alert(t('styleCustomizer.removeBgFailed', { message: error.message })); - } + try { + await appearanceStore.removePageBackground(); + alert(t('styleCustomizer.pageBgRemoved')); + } catch (error: any) { + console.error("移除页面背景失败:", error); + alert(t('styleCustomizer.removeBgFailed', { message: error.message })); } }; const handleRemoveTerminalBg = async () => { - if (confirm(t('styleCustomizer.confirmRemoveTerminalBg'))) { - try { - await appearanceStore.removeTerminalBackground(); - alert(t('styleCustomizer.terminalBgRemoved')); - } catch (error: any) { - console.error("移除终端背景失败:", error); - alert(t('styleCustomizer.removeBgFailed', { message: error.message })); - } + try { + await appearanceStore.removeTerminalBackground(); + alert(t('styleCustomizer.terminalBgRemoved')); + } catch (error: any) { + console.error("移除终端背景失败:", error); + alert(t('styleCustomizer.removeBgFailed', { message: error.message })); } }; @@ -579,7 +567,7 @@ const formatXtermLabel = (key: keyof ITheme): string => { const activeThemeName = computed(() => { const theme = availableTerminalThemes.value.find(t => t._id === activeTerminalThemeId.value); // 如果找不到主题 (例如 ID 无效或列表为空),则显示提示 - return theme ? theme.name : t('styleCustomizer.noActiveThemeSelected', '无激活主题'); // 需要添加翻译 + return theme ? theme.name : 'No active theme selected'; }); // 过滤和排序主题列表 @@ -592,25 +580,14 @@ const filteredAndSortedThemes = computed(() => { themes = themes.filter(theme => theme.name.toLowerCase().includes(searchTerm)); } - // 排序 - themes.sort((a, b) => { - const nameA = a.name.toLowerCase(); - const nameB = b.name.toLowerCase(); - if (themeSortOrder.value === 'nameAsc') { - return nameA.localeCompare(nameB); - } else { // nameDesc - return nameB.localeCompare(nameA); - } - // 未来可扩展日期排序,需要后端提供 createdAt/updatedAt - }); + // 排序逻辑已移除 + // 默认按名称升序排序 + themes.sort((a, b) => a.name.localeCompare(b.name)); return themes; }); -// 切换排序顺序 -const handleSortThemes = () => { - themeSortOrder.value = themeSortOrder.value === 'nameAsc' ? 'nameDesc' : 'nameAsc'; -}; +// 排序切换函数已移除 @@ -699,60 +676,59 @@ const handleSortThemes = () => {

{{ t('styleCustomizer.terminalThemeSelection') }}

-
- {{ t('styleCustomizer.activeTheme') }}: - {{ activeThemeName }} - -
+
+ {{ t('styleCustomizer.activeTheme') }}: + {{ activeThemeName }} + +
- -
- - - + +
+ + + +

{{ importError }}

-
+
- -
- - -
- - + + - + + + + - -
+ +

{{ editingTheme._id ? t('styleCustomizer.editThemeTitle') : t('styleCustomizer.newThemeTitle') }}

{{ saveThemeError }}

@@ -1165,6 +1141,7 @@ hr { display: flex; gap: var(--base-margin); flex-wrap: wrap; + align-items: center; /* 垂直居中按钮和错误消息 */ padding-bottom: var(--base-padding); border-bottom: 1px dashed var(--border-color); } @@ -1188,14 +1165,19 @@ hr { opacity: 0.6; cursor: not-allowed; } +.theme-management-buttons .error-message { + margin: 0; /* 移除错误消息的默认外边距 */ + flex-grow: 1; /* 让错误消息填充剩余空间 */ + text-align: left; /* 错误消息左对齐 */ +} .theme-list { list-style: none; padding: 0; - margin-top: 0; - max-height: 280px; - overflow-y: auto; + margin-top: var(--base-padding); /* 列表与上方元素间距 */ + max-height: 280px; /* 限制高度 */ + overflow-y: auto; /* 允许滚动 */ border: 1px solid var(--border-color); border-radius: 4px; background-color: var(--app-bg-color); @@ -1203,8 +1185,8 @@ hr { .theme-list li { display: grid; /* 使用 Grid 布局列表项 */ - /* 新增列: 应用按钮 | 名称 | 操作按钮 */ - grid-template-columns: auto 1fr auto; + /* 列: 名称 | 操作按钮组 */ + grid-template-columns: 1fr auto; /* 名称占据剩余空间,按钮组自适应 */ align-items: center; padding: 0.6rem 0.8rem; /* 调整内边距 */ border-bottom: 1px solid var(--border-color); @@ -1223,14 +1205,26 @@ hr { font-weight: bold; color: var(--button-text-color); /* 确保激活项文本颜色正确 */ } -.theme-list li.active .button-apply { - /* 可以选择隐藏或禁用已激活项的应用按钮 */ - opacity: 0.5; - cursor: default; - background-color: transparent; /* 激活项的应用按钮背景透明 */ - border-color: transparent; +/* 激活项内按钮样式调整 */ +.theme-list li.active .theme-actions button { color: var(--button-text-color); /* 继承激活项文本颜色 */ + border-color: rgba(255, 255, 255, 0.3); /* 边框稍微可见 */ + background-color: rgba(255, 255, 255, 0.1); /* 轻微背景 */ } +.theme-list li.active .theme-actions button:hover:not(:disabled) { + background-color: rgba(255, 255, 255, 0.2); + border-color: rgba(255, 255, 255, 0.5); +} +/* 激活项的应用按钮禁用样式 - 注意: :disabled 选择器优先级可能需要调整 */ +.theme-list li.active .theme-actions button:disabled { + opacity: 0.5 !important; /* 增加优先级确保生效 */ + cursor: default !important; + background-color: transparent !important; + border-color: transparent !important; + color: var(--button-text-color) !important; /* 确保禁用时颜色也正确 */ +} + + .theme-list li:last-child { border-bottom: none; } @@ -1243,44 +1237,24 @@ hr { font-style: italic; } -.button-apply { /* 应用按钮样式 */ - grid-column: 1 / 2; - padding: 0.3rem 0.6rem; - font-size: 0.85rem; - border: 1px solid var(--border-color); - border-radius: 4px; - background-color: var(--header-bg-color); - color: var(--text-color); - cursor: pointer; - transition: background-color 0.2s ease, border-color 0.2s ease; - white-space: nowrap; - margin-right: var(--base-margin); /* 与名称间距 */ -} +/* 移除独立的 .button-apply 样式 */ -.button-apply:hover:not(:disabled) { - background-color: var(--border-color); - border-color: var(--text-color-secondary); -} -.button-apply:disabled { - opacity: 0.5; - cursor: not-allowed; -} .theme-name { /* 主题名称样式 */ - grid-column: 2 / 3; + grid-column: 1 / 2; /* 名称在第一列 */ overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--text-color); /* 确保非激活项文本颜色 */ } .theme-list li.preset-theme .theme-name { - /* font-style: italic; */ /* 移除斜体,通过按钮区分 */ - /* color: var(--text-color-secondary); */ + /* 可以添加特定样式 */ } .theme-actions { - grid-column: 3 / 4; /* 按钮组在第三列 */ + grid-column: 2 / 3; /* 按钮组在第二列 */ flex-shrink: 0; display: flex; - gap: 0.5rem; + gap: 0.5rem; /* 按钮间距 */ + justify-content: flex-end; /* 按钮靠右对齐 */ } /* 统一操作按钮样式 */ .theme-actions button { @@ -1401,30 +1375,42 @@ hr { cursor: not-allowed; } -/* 搜索和排序区域 */ -.theme-filter-sort { - display: flex; - gap: var(--base-margin); - margin-bottom: var(--base-padding); - align-items: center; +/* 搜索框样式 */ +.theme-search-bar { + margin-bottom: var(--base-padding); /* 与下方列表的间距 */ } -.theme-filter-sort input.text-input { - flex-grow: 1; /* 让搜索框占据更多空间 */ - grid-column: auto; /* 重置 grid 影响 */ +.theme-search-bar input.text-input { + /* flex-grow: 1; /* 不再需要 flex */ + /* 移除 grid-column 相关的样式,因为它不再是 grid item */ + /* grid-column: auto; */ + /* 确保输入框样式正确 */ + border: 1px solid var(--border-color); + padding: 0.5rem 0.7rem; + border-radius: 4px; + font-size: 0.9rem; + background-color: var(--app-bg-color); + color: var(--text-color); + /* width: auto; /* 覆盖 form-group 的 width: 100% */ + width: 100%; /* 让搜索框占满宽度 */ + box-sizing: border-box; + transition: border-color 0.2s ease, box-shadow 0.2s ease; } -.theme-filter-sort button { - flex-shrink: 0; /* 防止按钮被压缩 */ +.theme-search-bar input.text-input:focus { + border-color: var(--link-active-color); + outline: 0; + box-shadow: 0 0 0 3px rgba(0, 123, 255, 0.15); } +/* 排序按钮样式已移除 */ /* 当前激活主题显示 */ .active-theme-display { - margin-bottom: var(--base-padding); + margin-bottom: var(--base-padding); /* 与下方搜索框的间距 */ padding: 0.6rem 0; font-size: 0.95rem; display: flex; align-items: center; gap: 0.8rem; - border-bottom: 1px solid var(--border-color); + /* border-bottom: 1px solid var(--border-color); */ /* 移除底部边框 */ } .active-theme-display span { color: var(--text-color-secondary); diff --git a/packages/frontend/src/locales/en.json b/packages/frontend/src/locales/en.json index 684b2b1..15e7130 100644 --- a/packages/frontend/src/locales/en.json +++ b/packages/frontend/src/locales/en.json @@ -88,7 +88,16 @@ "errorInvalidJsonObject": "Invalid input. Please provide a valid JSON object.", "errorInvalidJsonConfig": "Invalid JSON configuration", "editAsCopy": "Edit as Copy", - "copySuffix": "Copy" + "copySuffix": "Copy", + "cannotDeletePreset": "Cannot delete preset theme", + "applyThemeTooltip": "Apply this theme", + "applyButton": "Apply", + "searchThemePlaceholder": "Search theme name...", + "sortBy": "Sort by:", + "sortAsc": "Name Asc", + "sortDesc": "Name Desc", + "exportActiveThemeTooltip": "Export the currently active theme as a JSON file", + "exportActiveTheme": "Export Active Theme" }, "login": { "title": "User Login", diff --git a/packages/frontend/src/locales/zh.json b/packages/frontend/src/locales/zh.json index 257180a..97b5378 100644 --- a/packages/frontend/src/locales/zh.json +++ b/packages/frontend/src/locales/zh.json @@ -88,7 +88,16 @@ "errorInvalidJsonObject": "输入无效。请输入一个有效的 JSON 对象。", "errorInvalidJsonConfig": "无效的 JSON 配置", "editAsCopy": "编辑副本", - "copySuffix": "副本" + "copySuffix": "副本", + "cannotDeletePreset": "无法删除预设主题", + "applyThemeTooltip": "应用此主题", + "applyButton": "应用", + "searchThemePlaceholder": "搜索主题名称...", + "sortBy": "排序:", + "sortAsc": "名称升序", + "sortDesc": "名称降序", + "exportActiveThemeTooltip": "将当前激活的主题导出为 JSON 文件", + "exportActiveTheme": "导出当前主题" }, "login": { "title": "用户登录",