From e717e56245789bbd42d6ce796a12c58c29eec553 Mon Sep 17 00:00:00 2001 From: maigamo <13341529504@163.com> Date: Mon, 23 Jun 2025 11:21:11 +0800 Subject: [PATCH] The interface was optimized and some bugs were fixed --- src/i18n/i18n.ts | 30 +++++++ src/models/settings.ts | 14 ++++ src/settings/settings.ts | 168 +++++++++++++++++++++++++++++++++++++-- src/taskGenerator.ts | 122 +++++++++++++++++++++++++++- src/utils/domUtils.ts | 27 ++++--- src/utils/fileUtils.ts | 108 +++++++++++++++++++++++++ styles.css | 24 ++++-- 7 files changed, 465 insertions(+), 28 deletions(-) diff --git a/src/i18n/i18n.ts b/src/i18n/i18n.ts index d4bbe01..c0e2384 100644 --- a/src/i18n/i18n.ts +++ b/src/i18n/i18n.ts @@ -16,6 +16,16 @@ export type TranslationKey = | 'settings.mode.none' | 'settings.mode.daily' | 'settings.mode.workday' + + // 文件生成模式相关 + | 'settings.fileGenerationMode' + | 'settings.fileGenerationMode.desc' + | 'settings.mode.monthly' + | 'settings.mode.dailyFile' + | 'settings.dailyFilePrefix' + | 'settings.dailyFilePrefix.desc' + | 'notification.dailyFileExists' + | 'settings.language' | 'settings.language.desc' | 'settings.language.auto' @@ -145,6 +155,16 @@ const translationsZH: Record = { 'settings.mode.none': '❌ 关闭', 'settings.mode.daily': '📆 每天', 'settings.mode.workday': '💼 仅工作日', + + // 文件生成模式相关 + 'settings.fileGenerationMode': '📄 文件生成模式', + 'settings.fileGenerationMode.desc': '选择任务文件的生成方式', + 'settings.mode.monthly': '📅 月度文件', + 'settings.mode.dailyFile': '📆 日度文件', + 'settings.dailyFilePrefix': '🏷️ 文件名前缀', + 'settings.dailyFilePrefix.desc': '日度文件模式下的文件名前缀(可选)', + 'notification.dailyFileExists': '今日任务文件已存在', + 'settings.language': '🔤 界面语言', 'settings.language.desc': '选择插件界面显示的语言', 'settings.language.auto': '🔍 自动检测', @@ -221,6 +241,16 @@ const translationsEN: Record = { 'settings.mode.none': '❌ Off', 'settings.mode.daily': '📆 Daily', 'settings.mode.workday': '💼 Workdays only', + + // 文件生成模式相关 + 'settings.fileGenerationMode': '📄 File Generation Mode', + 'settings.fileGenerationMode.desc': 'Choose how task files are generated', + 'settings.mode.monthly': '📅 Monthly Files', + 'settings.mode.dailyFile': '📆 Daily Files', + 'settings.dailyFilePrefix': '🏷️ File Name Prefix', + 'settings.dailyFilePrefix.desc': 'Optional prefix for daily file names', + 'notification.dailyFileExists': 'Today\'s task file already exists', + 'settings.language': '🔤 Interface language', 'settings.language.desc': 'Select the language for the plugin interface', 'settings.language.auto': '🔍 Auto detect', diff --git a/src/models/settings.ts b/src/models/settings.ts index 5994d8b..e3e404f 100644 --- a/src/models/settings.ts +++ b/src/models/settings.ts @@ -7,6 +7,14 @@ export enum AutoGenerateMode { WORKDAY = 'workday' // 仅工作日自动生成 } +/** + * 文件生成模式枚举 + */ +export enum FileGenerationMode { + MONTHLY = 'monthly', // 月度文件模式(默认) + DAILY = 'daily' // 日度文件模式 +} + /** * 设置界面语言 */ @@ -25,6 +33,10 @@ export interface DailyTaskSettings { autoGenerateMode: AutoGenerateMode; // 自动生成模式 language: string; // 界面语言 + // 文件生成模式配置 + fileGenerationMode: FileGenerationMode; // 文件生成模式 + dailyFilePrefix: string; // 日度文件前缀(仅日度模式使用) + // 模板配置 templateZh: string; // 中文任务模板 templateEn: string; // 英文任务模板 @@ -87,6 +99,8 @@ export const DEFAULT_SETTINGS: DailyTaskSettings = { rootDir: 'DailyTasks', autoGenerateMode: AutoGenerateMode.WORKDAY, language: Language.AUTO, + fileGenerationMode: FileGenerationMode.MONTHLY, // 默认为月度文件模式 + dailyFilePrefix: '', // 默认无前缀 templateZh: DEFAULT_TEMPLATE_ZH, templateEn: DEFAULT_TEMPLATE_EN, customTemplate: '', // 默认为空,表示使用语言相关的默认模板 diff --git a/src/settings/settings.ts b/src/settings/settings.ts index d9dd19e..1ca305e 100644 --- a/src/settings/settings.ts +++ b/src/settings/settings.ts @@ -1,5 +1,5 @@ import { App, ButtonComponent, DropdownComponent, Notice, Plugin, PluginSettingTab, Setting, TextAreaComponent, TextComponent, ToggleComponent } from 'obsidian'; -import { AutoGenerateMode, DEFAULT_SETTINGS, DEFAULT_TEMPLATE_EN, DEFAULT_TEMPLATE_ZH, DailyTaskSettings, Language } from '../models/settings'; +import { AutoGenerateMode, DEFAULT_SETTINGS, DEFAULT_TEMPLATE_EN, DEFAULT_TEMPLATE_ZH, DailyTaskSettings, Language, FileGenerationMode } from '../models/settings'; import { getTranslation, setCurrentLanguage } from '../i18n/i18n'; import { renderTemplate } from '../utils/templateEngine'; import { TaskGenerator } from '../taskGenerator'; @@ -45,12 +45,19 @@ export class DailyTaskSettingTab extends PluginSettingTab { // 目录输入框 rootDirInput: TextComponent | null = null; + // 日度文件前缀输入框 + dailyFilePrefixInput: TextComponent | null = null; + dailyFilePrefixSetting: HTMLElement | null = null; + // 标记设置是否已修改但未保存 dirtySettings: boolean = false; // 自动保存目录的方法 autoSaveRootDir: (value: string) => Promise; + // 自动保存日度文件前缀的方法 + autoSaveDailyFilePrefix: (value: string) => Promise; + constructor(app: App, plugin: Plugin) { super(app, plugin); this.plugin = plugin; @@ -210,6 +217,141 @@ export class DailyTaskSettingTab extends PluginSettingTab { toggleContainer.appendChild(option); }); + // 文件生成模式设置 + const fileGenSetting = new Setting(containerEl) + .setName(getTranslation('settings.fileGenerationMode')) + .setDesc(getTranslation('settings.fileGenerationMode.desc')); + + // 创建文件生成模式选择器(二选滑块) + const fileGenToggleContainer = document.createElement('div'); + fileGenToggleContainer.classList.add('mode-toggle-container'); + fileGenSetting.controlEl.appendChild(fileGenToggleContainer); + + const fileGenModes = [ + { value: FileGenerationMode.MONTHLY, label: getTranslation('settings.mode.monthly') }, + { value: FileGenerationMode.DAILY, label: getTranslation('settings.mode.dailyFile') } + ]; + + // 文件生成模式滑块指示器 + const fileGenSlider = document.createElement('div'); + fileGenSlider.classList.add('mode-toggle-slider'); + fileGenToggleContainer.appendChild(fileGenSlider); + + // 更新文件生成模式滑块位置 + const updateFileGenSlider = (index: number) => { + // 移除之前的位置类(二选滑块) + fileGenSlider.classList.remove('slider-position-0', 'slider-position-1'); + // 添加新的位置类 + fileGenSlider.classList.add(`slider-position-${index}`); + }; + + // 设置当前文件生成模式 + let currentFileGenModeIndex = fileGenModes.findIndex(mode => mode.value === settings.fileGenerationMode); + if (currentFileGenModeIndex === -1) { + // 如果没有找到有效的模式,设置为月度模式(默认) + currentFileGenModeIndex = 0; + this.settingsManager.updateSettings({ fileGenerationMode: FileGenerationMode.MONTHLY }); + } + updateFileGenSlider(currentFileGenModeIndex); + + // 创建文件生成模式选项 + fileGenModes.forEach((mode, index) => { + const option = document.createElement('div'); + option.classList.add('mode-toggle-option'); + option.textContent = mode.label; + + if (mode.value === settings.fileGenerationMode) { + option.classList.add('active'); + } + + option.addEventListener('click', async () => { + // 更新视觉状态 + fileGenToggleContainer.querySelectorAll('.mode-toggle-option').forEach(el => { + el.classList.remove('active'); + }); + option.classList.add('active'); + + // 更新滑块位置 + updateFileGenSlider(index); + + // 保存设置 + await this.settingsManager.updateSettings({ fileGenerationMode: mode.value }); + + // 更新日度文件前缀设置的显示状态 + this.updateDailyFilePrefixVisibility(mode.value); + }); + + fileGenToggleContainer.appendChild(option); + }); + + // 日度文件前缀设置 + const dailyFilePrefixSetting = new Setting(containerEl) + .setName(getTranslation('settings.dailyFilePrefix')) + .setDesc(getTranslation('settings.dailyFilePrefix.desc')); + + this.dailyFilePrefixSetting = dailyFilePrefixSetting.controlEl.parentElement; + + // 创建前缀输入框容器 + const prefixInputContainer = document.createElement('div'); + prefixInputContainer.classList.add(InputContainerCSS); + dailyFilePrefixSetting.controlEl.appendChild(prefixInputContainer); + + this.dailyFilePrefixInput = new TextComponent(prefixInputContainer) + .setValue(settings.dailyFilePrefix || '') + .onChange(async (value) => { + // 设置已更改,准备自动保存 + this.dirtySettings = true; + + // 启动自动保存定时器 + this.autoSaveDailyFilePrefix(value); + }); + + // 给input元素设置类和placeholder属性 + if (this.dailyFilePrefixInput && this.dailyFilePrefixInput.inputEl) { + this.dailyFilePrefixInput.inputEl.classList.add(InputCSS); + this.dailyFilePrefixInput.inputEl.placeholder = getTranslation('settings.dailyFilePrefix.desc'); + } + + // 添加前缀自动保存指示器 + const prefixSaveIndicator = document.createElement('div'); + prefixSaveIndicator.classList.add(SaveIndicatorCSS); + prefixInputContainer.appendChild(prefixSaveIndicator); + + // 创建前缀保存成功图标 + const prefixSaveSuccessIcon = document.createElement('span'); + prefixSaveSuccessIcon.classList.add('svg-icon', 'lucide-check', SuccessIconCSS); + prefixSaveIndicator.appendChild(prefixSaveSuccessIcon); + + // 记录前缀自动保存定时器 + let prefixAutoSaveTimer: number | null = null; + + // 前缀自动保存方法 + this.autoSaveDailyFilePrefix = async (value: string) => { + // 清除之前的定时器 + if (prefixAutoSaveTimer !== null) { + window.clearTimeout(prefixAutoSaveTimer); + } + + // 设置新的定时器,延迟800ms保存(在用户停止输入后) + prefixAutoSaveTimer = window.setTimeout(async () => { + // 实际保存设置 + await this.settingsManager.updateSettings({ dailyFilePrefix: value }); + this.dirtySettings = false; + + // 显示保存成功的视觉反馈 + prefixSaveIndicator.classList.add('save-indicator-visible'); + prefixSaveIndicator.classList.remove('save-indicator-hidden'); + window.setTimeout(() => { + prefixSaveIndicator.classList.remove('save-indicator-visible'); + prefixSaveIndicator.classList.add('save-indicator-hidden'); + }, 1500); + + }, 800); + }; + + // 初始化日度文件前缀设置的可见性 + this.updateDailyFilePrefixVisibility(settings.fileGenerationMode); + // 语言设置 // TODO: 应该使用Obsidian API的app.i18n.locale获取系统语言设置 // 需要在manifest.json中设置minAppVersion: "1.8.0"或更高 @@ -398,9 +540,9 @@ export class DailyTaskSettingTab extends PluginSettingTab { resetBtn.buttonEl.addClass('daily-task-button-common'); resetBtn.buttonEl.addClass('daily-task-button-lg'); - // 添加重置图标 + // 添加重置图标 - 使用撤销图标更直观 const resetIcon = document.createElement('span'); - resetIcon.classList.add('svg-icon', 'lucide-refresh-cw'); + resetIcon.classList.add('svg-icon', 'lucide-undo2'); resetBtn.buttonEl.prepend(resetIcon); // 添加重置事件 @@ -447,9 +589,9 @@ export class DailyTaskSettingTab extends PluginSettingTab { resetDefaultBtn.buttonEl.addClass('daily-task-button-common'); resetDefaultBtn.buttonEl.addClass('daily-task-button-lg'); - // 添加重置图标 + // 添加重置图标 - 使用返回主页图标表示恢复到默认状态 const resetIcon2 = document.createElement('span'); - resetIcon2.classList.add('svg-icon', 'lucide-refresh-cw'); + resetIcon2.classList.add('svg-icon', 'lucide-home'); resetDefaultBtn.buttonEl.prepend(resetIcon2); // 为全局重置按钮添加事件处理 @@ -506,6 +648,20 @@ export class DailyTaskSettingTab extends PluginSettingTab { this.addTaskButton.buttonEl.prepend(calendarIcon); } + /** + * 更新日度文件前缀设置的可见性 + * @param mode 文件生成模式 + */ + private updateDailyFilePrefixVisibility(mode: FileGenerationMode): void { + if (!this.dailyFilePrefixSetting) return; + + if (mode === FileGenerationMode.DAILY) { + this.dailyFilePrefixSetting.style.display = 'block'; + } else { + this.dailyFilePrefixSetting.style.display = 'none'; + } + } + /** * 更新模板预览 */ @@ -725,4 +881,4 @@ export class SettingsManager { hasCustomTemplate(): boolean { return !!this.settings.customTemplate; } -} \ No newline at end of file +} \ No newline at end of file diff --git a/src/taskGenerator.ts b/src/taskGenerator.ts index 771439e..fe913c5 100644 --- a/src/taskGenerator.ts +++ b/src/taskGenerator.ts @@ -1,9 +1,10 @@ import { App, Notice, TAbstractFile, TFile, Vault } from "obsidian"; import { getTranslation } from "./i18n/i18n"; import { SettingsManager } from "./settings/settings"; -import { appendToFile, ensureFileExists, ensureFolderExists, getTaskFilePath, todayTaskExists, fileContains, getYesterdayDate, getYesterdayTaskFilePath, extractTasksForDate, analyzeTaskCompletion, yesterdayStatisticsExists, generateStatisticsContent } from "./utils/fileUtils"; +import { appendToFile, ensureFileExists, ensureFolderExists, getTaskFilePath, todayTaskExists, fileContains, getYesterdayDate, getYesterdayTaskFilePath, extractTasksForDate, analyzeTaskCompletion, yesterdayStatisticsExists, generateStatisticsContent, getTaskFilePathByMode, getDailyTaskFilePath, getDailyTaskFolderPaths, dailyTaskFileExists, createDailyTaskFile } from "./utils/fileUtils"; import { renderTemplate } from "./utils/templateEngine"; import { getCurrentDate } from "./utils/dateUtils"; +import { FileGenerationMode } from "./models/settings"; /** * 任务生成器 @@ -21,12 +22,28 @@ export class TaskGenerator { } /** - * 生成每日任务 + * 生成每日任务(主入口方法) * @param openFile 是否打开文件 * @param quietMode 静默模式,减少日志输出 * @returns 成功或失败 */ async generateDailyTask(openFile: boolean = true, quietMode: boolean = false): Promise { + const settings = this.settingsManager.getSettings(); + + if (settings.fileGenerationMode === FileGenerationMode.MONTHLY) { + return await this.generateMonthlyTask(openFile, quietMode); + } else { + return await this.generateDailyTaskFile(openFile, quietMode); + } + } + + /** + * 生成月度任务文件(原有逻辑) + * @param openFile 是否打开文件 + * @param quietMode 静默模式,减少日志输出 + * @returns 成功或失败 + */ + private async generateMonthlyTask(openFile: boolean = true, quietMode: boolean = false): Promise { try { const settings = this.settingsManager.getSettings(); const rootDir = settings.rootDir.trim() || 'DailyTasks'; // 使用默认目录 @@ -145,6 +162,107 @@ export class TaskGenerator { return false; } } + + /** + * 生成日度任务文件(新增逻辑) + * @param openFile 是否打开文件 + * @param quietMode 静默模式,减少日志输出 + * @returns 成功或失败 + */ + private async generateDailyTaskFile(openFile: boolean = true, quietMode: boolean = false): Promise { + try { + const settings = this.settingsManager.getSettings(); + const rootDir = settings.rootDir.trim() || 'DailyTasks'; + const prefix = settings.dailyFilePrefix || ''; + + // 获取日度任务文件路径 + const filePath = getDailyTaskFilePath(rootDir, prefix); + + // 检查文件是否已存在 + const fileExists = await dailyTaskFileExists(this.vault, rootDir, prefix); + + if (fileExists) { + // 如果需要打开文件 + if (openFile) { + // 显示提示并打开文件 + this.showWarningNotice(`📌 ${getTranslation('notification.dailyFileExists')}`); + const file = this.vault.getAbstractFileByPath(filePath); + if (file && file instanceof TFile) { + const leaf = this.app.workspace.getLeaf(); + await leaf.openFile(file); + } + } + + return true; // 文件已存在,视为成功 + } + + // 获取年份和月份文件夹路径 + const { yearPath, monthPath } = getDailyTaskFolderPaths(rootDir); + + // 确保根目录存在 + const rootCreated = await ensureFolderExists(this.vault, rootDir); + if (!rootCreated) { + throw new Error(`无法访问根目录: ${rootDir},可能是存在同名文件或权限问题`); + } + + // 确保年份目录存在 + const yearCreated = await ensureFolderExists(this.vault, yearPath); + if (!yearCreated) { + throw new Error(`无法访问年份目录: ${yearPath},可能是存在同名文件或权限问题`); + } + + // 确保月份目录存在 + const monthCreated = await ensureFolderExists(this.vault, monthPath); + if (!monthCreated) { + throw new Error(`无法访问月份目录: ${monthPath},可能是存在同名文件或权限问题`); + } + + // 获取任务模板内容 + let template = ''; + if (this.settingsManager.hasCustomTemplate()) { + // 使用用户自定义模板 + template = this.settingsManager.getSettings().customTemplate; + } else { + // 使用语言相关的默认模板 + template = this.settingsManager.getTemplateByLanguage(); + } + + // 渲染模板 + const renderedContent = renderTemplate(template); + + // 创建日度任务文件(不追加,直接创建完整文件) + const success = await createDailyTaskFile(this.vault, filePath, renderedContent); + + if (success) { + // 如果需要打开文件 + if (openFile) { + // 打开创建的文件 + const file = this.vault.getAbstractFileByPath(filePath); + if (file && file instanceof TFile) { + const leaf = this.app.workspace.getLeaf(); + await leaf.openFile(file); + + // 延迟一下再显示通知,确保文件已经打开 + setTimeout(() => { + this.showSuccessNotice(`✨ ${getTranslation('notification.taskAdded')}`); + }, 300); + } else { + throw new Error(`文件创建成功但无法打开: ${filePath}`); + } + } + } else { + throw new Error(`无法创建日度任务文件: ${filePath}`); + } + + return success; + } catch (error) { + // 显示错误通知 + const errorMsg = error instanceof Error ? error.message : String(error); + this.showErrorNotice(`${getTranslation('notification.error')} ${errorMsg}`); + + return false; + } + } /** * 生成昨日任务统计信息 diff --git a/src/utils/domUtils.ts b/src/utils/domUtils.ts index 4796463..1cfe6bb 100644 --- a/src/utils/domUtils.ts +++ b/src/utils/domUtils.ts @@ -36,20 +36,21 @@ export function setTextContentByLines(targetEl: HTMLElement, textContent: string targetEl.removeChild(targetEl.firstChild); } - // 将内容按行分割 - const lines = textContent.split('\n'); + // 创建预格式化的div来保持原始格式 + const preEl = document.createElement('div'); + preEl.style.whiteSpace = 'pre-wrap'; + preEl.style.wordWrap = 'break-word'; + preEl.style.textAlign = 'left'; + preEl.style.margin = '0'; + preEl.style.padding = '0'; + preEl.style.fontFamily = 'inherit'; + preEl.style.lineHeight = 'inherit'; - // 为每行创建一个div - lines.forEach((line, index) => { - const lineEl = document.createElement('div'); - lineEl.textContent = line; - targetEl.appendChild(lineEl); - - // 如果不是最后一行,添加换行符 - if (index < lines.length - 1) { - targetEl.appendChild(document.createElement('br')); - } - }); + // 直接设置文本内容,保持原始格式 + preEl.textContent = textContent; + + // 添加到目标元素 + targetEl.appendChild(preEl); } /** diff --git a/src/utils/fileUtils.ts b/src/utils/fileUtils.ts index cd72b6f..7bc665c 100644 --- a/src/utils/fileUtils.ts +++ b/src/utils/fileUtils.ts @@ -3,6 +3,7 @@ import { getCurrentDate, getCurrentMonth, getCurrentYear, getLocalizedMonthName, import { getTranslation, TranslationKey } from '../i18n/i18n'; import { Notice } from 'obsidian'; import { DEFAULT_SETTINGS } from '../settings/index'; +import { FileGenerationMode } from '../models/settings'; /** * 文件操作工具函数 @@ -175,6 +176,113 @@ export function getTaskFilePath(rootDir: string): string { return normalizePath(`${rootDir}/${yearDir}/${monthFile}`); } +/** + * 根据文件生成模式和配置生成任务文件路径 + * @param rootDir 根目录 + * @param mode 文件生成模式 + * @param prefix 日度文件前缀(仅日度模式使用) + * @returns 任务文件路径 + */ +export function getTaskFilePathByMode(rootDir: string, mode: FileGenerationMode, prefix: string = ''): string { + if (mode === FileGenerationMode.MONTHLY) { + return getTaskFilePath(rootDir); + } else { + return getDailyTaskFilePath(rootDir, prefix); + } +} + +/** + * 根据当前日期生成日度任务文件路径 + * @param rootDir 根目录 + * @param prefix 文件名前缀 + * @returns 日度任务文件路径,格式为:rootDir/year/monthFolder/prefix+date.md + */ +export function getDailyTaskFilePath(rootDir: string, prefix: string = ''): string { + const now = new Date(); + const year = now.getFullYear(); + const month = now.getMonth() + 1; // 1-12 + const day = now.getDate(); + + const yearDir = year.toString(); + // 使用数字格式的月份文件夹,保持两位数格式 + const monthFolder = month.toString().padStart(2, '0'); + + // 生成日期字符串 YYYY-MM-DD + const dateStr = `${year}-${month.toString().padStart(2, '0')}-${day.toString().padStart(2, '0')}`; + + // 构建文件名:前缀 + 日期 + .md + const fileName = prefix.trim() ? `${prefix.trim()}${dateStr}.md` : `${dateStr}.md`; + + return normalizePath(`${rootDir}/${yearDir}/${monthFolder}/${fileName}`); +} + +/** + * 获取日度任务文件的年份和月份文件夹路径 + * @param rootDir 根目录 + * @returns 包含年份路径和月份路径的对象 + */ +export function getDailyTaskFolderPaths(rootDir: string): { yearPath: string; monthPath: string } { + const now = new Date(); + const year = now.getFullYear(); + const month = now.getMonth() + 1; // 1-12 + + const yearDir = year.toString(); + const monthFolder = month.toString().padStart(2, '0'); + + const yearPath = normalizePath(`${rootDir}/${yearDir}`); + const monthPath = normalizePath(`${rootDir}/${yearDir}/${monthFolder}`); + + return { yearPath, monthPath }; +} + +/** + * 检查日度任务文件是否已存在 + * @param vault Obsidian文件系统 + * @param rootDir 根目录 + * @param prefix 文件名前缀 + * @returns 是否已存在 + */ +export async function dailyTaskFileExists(vault: Vault, rootDir: string, prefix: string = ''): Promise { + const filePath = getDailyTaskFilePath(rootDir, prefix); + const file = vault.getAbstractFileByPath(filePath); + return file !== null && file instanceof TFile; +} + +/** + * 创建完整的日度任务文件(不追加内容) + * @param vault Obsidian文件系统 + * @param filePath 文件路径 + * @param content 文件内容 + * @returns 是否成功创建 + */ +export async function createDailyTaskFile(vault: Vault, filePath: string, content: string): Promise { + try { + const normalizedPath = normalizePath(filePath); + + // 确保文件夹结构存在 + const folderPath = normalizedPath.substring(0, normalizedPath.lastIndexOf('/')); + if (folderPath) { + const folderExists = await ensureFolderExists(vault, folderPath); + if (!folderExists) { + return false; + } + } + + // 检查文件是否已存在 + const existingFile = vault.getAbstractFileByPath(normalizedPath); + if (existingFile) { + return false; // 文件已存在,不重复创建 + } + + // 创建新文件 + await vault.create(normalizedPath, content); + + return true; + } catch (error) { + return false; + } +} + /** * 检查今日任务是否已存在 * @param vault Obsidian文件系统 diff --git a/styles.css b/styles.css index 4e7a726..39d4e6f 100644 --- a/styles.css +++ b/styles.css @@ -256,15 +256,20 @@ button { /* 模板预览容器 */ .template-preview { - background-color: var(--background-primary); - border: 1px solid var(--background-modifier-border); - border-radius: 5px; + margin-top: 15px; padding: 15px; - margin-top: 10px; - max-height: 200px; - overflow-y: auto; - box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); + border: 1px dashed var(--background-modifier-border); + border-radius: 8px; + background-color: var(--background-secondary); display: none; + max-height: 200px; + overflow: auto; + box-shadow: inset 0 0 5px rgba(0,0,0,0.1); + text-align: left; + line-height: 1.6; + font-family: var(--font-text); + white-space: pre-wrap; + word-wrap: break-word; } .template-preview.visible { @@ -672,6 +677,11 @@ button { max-height: 200px; overflow: auto; box-shadow: inset 0 0 5px rgba(0,0,0,0.1); + text-align: left; + line-height: 1.6; + font-family: var(--font-text); + white-space: pre-wrap; + word-wrap: break-word; } .template-preview.visible {