diff --git a/src/ace-config.ts b/src/ace-config.ts index accb26e1..39650f00 100644 --- a/src/ace-config.ts +++ b/src/ace-config.ts @@ -14,6 +14,10 @@ import modeIniUrl from 'ace-builds/src-noconflict/mode-ini?url' import themeGithubUrl from 'ace-builds/src-noconflict/theme-github?url' +import themeGithubDarkUrl from 'ace-builds/src-noconflict/theme-github_dark?url' + +import themeGithubLightDefaultUrl from 'ace-builds/src-noconflict/theme-github_light_default?url' + import themeChromeUrl from 'ace-builds/src-noconflict/theme-chrome?url' import themeMonokaiUrl from 'ace-builds/src-noconflict/theme-monokai?url' @@ -533,6 +537,8 @@ ace.config.setModuleUrl('ace/mode/yaml', modeYamlUrl) ace.config.setModuleUrl('ace/mode/css', modeCssUrl) ace.config.setModuleUrl('ace/mode/ini', modeIniUrl) ace.config.setModuleUrl('ace/theme/github', themeGithubUrl) +ace.config.setModuleUrl('ace/theme/github_dark', themeGithubDarkUrl) +ace.config.setModuleUrl('ace/theme/github_light_default', themeGithubLightDefaultUrl) ace.config.setModuleUrl('ace/theme/chrome', themeChromeUrl) ace.config.setModuleUrl('ace/theme/monokai', themeMonokaiUrl) ace.config.setModuleUrl('ace/mode/base', workerBaseUrl) diff --git a/src/components/dialog/CustomCssDialog.vue b/src/components/dialog/CustomCssDialog.vue index 2c1c6acd..46e8171b 100644 --- a/src/components/dialog/CustomCssDialog.vue +++ b/src/components/dialog/CustomCssDialog.vue @@ -40,6 +40,14 @@ const visible = computed({ // 正在编辑的 CSS 内容 const editableCSS = ref(props.css) +const editorOptions = { + displayIndentGuides: true, + fontSize: 14, + highlightActiveLine: true, + scrollPastEnd: 0.2, + showPrintMargin: false, + tabSize: 2, +} watch( () => props.css, @@ -56,25 +64,66 @@ function submitCustomCSS() { + + diff --git a/src/components/dialog/NotificationTemplateEditorDialog.vue b/src/components/dialog/NotificationTemplateEditorDialog.vue index 0eff6026..730e5967 100644 --- a/src/components/dialog/NotificationTemplateEditorDialog.vue +++ b/src/components/dialog/NotificationTemplateEditorDialog.vue @@ -38,6 +38,14 @@ const visible = computed({ }) const editableContent = ref(props.content) +const editorOptions = { + displayIndentGuides: true, + fontSize: 14, + highlightActiveLine: true, + scrollPastEnd: 0.2, + showPrintMargin: false, + tabSize: 2, +} watch( () => props.content, @@ -58,10 +66,12 @@ function submitTemplate() { + + diff --git a/src/layouts/components/UserProfile.vue b/src/layouts/components/UserProfile.vue index 5bec4ec2..8bb32409 100644 --- a/src/layouts/components/UserProfile.vue +++ b/src/layouts/components/UserProfile.vue @@ -293,8 +293,8 @@ const themes: ThemeSwitcherTheme[] = [ }, ] -// 编辑器主题 -const editorTheme = computed(() => (currentThemeName.value === 'light' ? 'github' : 'monokai')) +// Ace 跟随 Vuetify 当前生效主题,避免 auto 模式或弹窗打开后切主题时颜色不同步。 +const editorTheme = computed(() => (globalTheme.current.value.dark ? 'github_dark' : 'github_light_default')) // 更新主题 async function updateTheme() { @@ -369,6 +369,11 @@ function showCustomCssDialog() { ) } +// 共享弹窗打开后也要同步主题变化,否则 Ace 会停留在打开时的配色。 +watch(editorTheme, theme => { + customCssDialogController?.updateProps({ editorTheme: theme }) +}) + /** 打开透明主题设置共享弹窗。 */ function showTransparencySettingsDialog() { openSharedDialog(TransparencySettingsDialog, {}, {}, { closeOn: ['close', 'update:modelValue'] }) diff --git a/src/views/setting/AccountSettingDirectory.vue b/src/views/setting/AccountSettingDirectory.vue index 64739be7..a5098c60 100644 --- a/src/views/setting/AccountSettingDirectory.vue +++ b/src/views/setting/AccountSettingDirectory.vue @@ -64,7 +64,8 @@ const SystemSettings = ref({ }) // 编辑器主题 -const editorTheme = computed(() => (globalTheme.name.value === 'light' ? 'github' : 'monokai')) +// Ace 跟随 Vuetify 当前生效主题,auto 模式下也按实际明暗色渲染。 +const editorTheme = computed(() => (globalTheme.current.value.dark ? 'github_dark' : 'github_light_default')) const renameEditorOptions = { fontSize: 14, diff --git a/src/views/setting/AccountSettingNotification.vue b/src/views/setting/AccountSettingNotification.vue index 68556130..783f6be4 100644 --- a/src/views/setting/AccountSettingNotification.vue +++ b/src/views/setting/AccountSettingNotification.vue @@ -25,39 +25,51 @@ const NotificationTemplateEditorDialog = defineAsyncComponent( () => import('@/components/dialog/NotificationTemplateEditorDialog.vue'), ) -// 初始化模板配置字典 -const templateConfigs = ref>({ - organizeSuccess: '{}', - downloadAdded: '{}', - subscribeAdded: '{}', - subscribeComplete: '{}', -}) - -// 模板类型配置 -const templateTypes = ref([ +// 通知模板入口的图标和强调色统一维护,避免模板中散落长判断。 +const templateTypeDefaults = [ { type: 'organizeSuccess', - label: t('setting.notification.organizeSuccess'), + icon: 'mdi-folder-check', + color: 'primary', }, { type: 'downloadAdded', - label: t('setting.notification.downloadAdded'), + icon: 'mdi-download-box', + color: 'info', }, { type: 'subscribeAdded', - label: t('setting.notification.subscribeAdded'), + icon: 'mdi-rss-box', + color: 'warning', }, { type: 'subscribeComplete', - label: t('setting.notification.subscribeComplete'), + icon: 'mdi-check-circle', + color: 'success', }, -]) +] as const -// 编辑器主题 -const { name: themeName, global: globalTheme } = useTheme() -const savedTheme = ref(localStorage.getItem('theme') ?? 'auto') -const currentThemeName = ref(savedTheme.value) -const editorTheme = computed(() => (currentThemeName.value === 'light' ? 'github' : 'monokai')) +type NotificationTemplateType = (typeof templateTypeDefaults)[number]['type'] + +// 初始化模板配置字典 +const templateConfigs = ref>( + templateTypeDefaults.reduce>((configs, item) => { + configs[item.type] = '{}' + return configs + }, {}), +) + +// 模板类型配置 +const templateTypes = computed(() => + templateTypeDefaults.map(item => ({ + ...item, + label: t(`setting.notification.${item.type}`), + })), +) + +// Ace 直接跟随 Vuetify 当前生效主题,auto 模式下也能按实际明暗色切换。 +const { global: globalTheme } = useTheme() +const editorTheme = computed(() => (globalTheme.current.value.dark ? 'github_dark' : 'github_light_default')) // 所有消息渠道 const notifications = ref([]) @@ -66,7 +78,7 @@ const notifications = ref([]) const $toast = useToast() const editorDialogOpen = ref(false) -const currentTemplate = ref('') +const currentTemplate = ref('') const editorContent = ref('') // 消息类型开关 @@ -127,7 +139,7 @@ function closeTemplateEditorDialog() { } // 打开通知模板共享弹窗,保持内容通过事件回写到设置页。 -function openTemplateEditorDialog(type: string) { +function openTemplateEditorDialog(type: NotificationTemplateType) { closeTemplateEditorDialog() editorDialogOpen.value = true editorDialogController = openSharedDialog( @@ -158,6 +170,13 @@ function openTemplateEditorDialog(type: string) { ) } +// 共享弹窗的 props 是打开时写入的,主题切换时主动推送给已打开的编辑器。 +watch(editorTheme, theme => { + if (!editorDialogOpen.value) return + + editorDialogController?.updateProps({ editorTheme: theme }) +}) + // 添加通知渠道 function addNotification(notification: string) { let name = `${t('setting.notification.channel')}${notifications.value.length + 1}` @@ -229,7 +248,7 @@ async function loadNotificationSetting() { } } -async function openEditor(type: string) { +async function openEditor(type: NotificationTemplateType) { try { currentTemplate.value = type const result: { [key: string]: any } = await api.get('system/setting/NotificationTemplates') @@ -460,34 +479,25 @@ useSilentSettingRefresh(loadPageData, { {{ t('setting.notification.templateConfigDesc') }} - - - - - - {{ item.label }} - - - - - +
+ +
@@ -575,20 +585,126 @@ useSilentSettingRefresh(loadPageData, {