maigamo_Daily-Task-Auto-Gen.../main.js
2025-04-21 11:07:55 +08:00

1466 lines
58 KiB
JavaScript

/*
THIS IS A GENERATED/BUNDLED FILE BY ESBUILD
if you want to view the source, please visit the github repository of this plugin
*/
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/main.ts
var main_exports = {};
__export(main_exports, {
default: () => DailyTaskPlugin
});
module.exports = __toCommonJS(main_exports);
var import_obsidian4 = require("obsidian");
// src/models/settings.ts
var DEFAULT_TEMPLATE_ZH = `## {{dateWithIcon}}\uFF08{{weekday}}\uFF09
### \u{1F9D8} \u4ECA\u65E5\u8BA1\u5212
---
- [ ] \u51A5\u60F3 10 \u5206\u949F
- [ ] \u590D\u76D8\u524D\u4E00\u65E5\u8BA1\u5212
- [ ] \u9605\u8BFB 20 \u9875\u4E66
### \u{1F4DD} \u5DE5\u4F5C\u4EFB\u52A1
---
- [ ] \u6574\u7406\u4ECA\u65E5\u5DE5\u4F5C\u8BA1\u5212
- [ ] \u5B8C\u6210\u91CD\u8981\u9879\u76EE\u8FDB\u5EA6
`;
var DEFAULT_TEMPLATE_EN = `## {{dateWithIcon}} ({{weekday}})
### \u{1F9D8} Today's Plan
---
- [ ] Meditate for 10 minutes
- [ ] Review yesterday's plan
- [ ] Read 20 pages
### \u{1F4DD} Work Tasks
---
- [ ] Organize today's work schedule
- [ ] Progress on important projects
`;
var DEFAULT_SETTINGS = {
rootDir: "DailyTasks",
autoGenerateMode: "workday" /* WORKDAY */,
language: "auto" /* AUTO */,
templateZh: DEFAULT_TEMPLATE_ZH,
templateEn: DEFAULT_TEMPLATE_EN,
customTemplate: "",
// 默认为空,表示使用语言相关的默认模板
hasCustomTemplate: false,
// 默认不使用自定义模板
taskStatistics: false,
// 默认关闭任务统计功能
successNotificationDuration: 3e3
};
// src/settings/settings.ts
var import_obsidian3 = require("obsidian");
// src/i18n/i18n.ts
var translationsZH = {
// 设置页面
"settings.title": "\u6BCF\u65E5\u4EFB\u52A1\u81EA\u52A8\u751F\u6210\u5668\u8BBE\u7F6E",
"settings.rootDir": "\u{1F4C1} \u4EFB\u52A1\u6587\u4EF6\u5B58\u653E\u76EE\u5F55",
"settings.rootDir.desc": '\u6307\u5B9A\u4FDD\u5B58\u4EFB\u52A1\u6587\u4EF6\u7684\u6839\u76EE\u5F55\uFF0C\u4EFB\u52A1\u5C06\u6309"\u5E74\u4EFD/\u6708\u4EFD.md"\u683C\u5F0F\u5B58\u50A8',
"settings.rootDir.saved": "\u2713 \u76EE\u5F55\u5DF2\u4FDD\u5B58",
"settings.save": "\u{1F4BE} \u4FDD\u5B58",
"settings.autoGenerate": "\u{1F504} \u81EA\u52A8\u751F\u6210\u6A21\u5F0F",
"settings.autoGenerate.desc": "\u9009\u62E9\u4F55\u65F6\u81EA\u52A8\u751F\u6210\u6BCF\u65E5\u4EFB\u52A1",
"settings.mode.none": "\u274C \u5173\u95ED",
"settings.mode.daily": "\u{1F4C6} \u6BCF\u5929",
"settings.mode.workday": "\u{1F4BC} \u4EC5\u5DE5\u4F5C\u65E5",
"settings.language": "\u{1F524} \u754C\u9762\u8BED\u8A00",
"settings.language.desc": "\u9009\u62E9\u63D2\u4EF6\u754C\u9762\u663E\u793A\u7684\u8BED\u8A00",
"settings.language.auto": "\u{1F50D} \u81EA\u52A8\u68C0\u6D4B",
"settings.language.zh": "\u{1F1E8}\u{1F1F3} \u4E2D\u6587",
"settings.language.en": "\u{1F1EC}\u{1F1E7} \u82F1\u6587",
"settings.animations": "\u2728 \u52A8\u753B\u6548\u679C",
"settings.animations.desc": "\u542F\u7528\u754C\u9762\u52A8\u753B\u6548\u679C",
"settings.template": "\u{1F4DD} \u4EFB\u52A1\u6A21\u677F",
"settings.template.zh": "\u{1F1E8}\u{1F1F3} \u4E2D\u6587\u6A21\u677F",
"settings.template.en": "\u{1F1EC}\u{1F1E7} \u82F1\u6587\u6A21\u677F",
"settings.template.preview": "\u{1F441}\uFE0F \u663E\u793A\u9884\u89C8",
"settings.template.hide": "\u{1F441}\uFE0F\u200D\u{1F5E8}\uFE0F \u9690\u85CF\u9884\u89C8",
"settings.resetToDefault": "\u{1F504} \u6062\u590D\u9ED8\u8BA4\u8BBE\u7F6E",
"settings.addTaskButton": "\u2795 \u624B\u52A8\u6DFB\u52A0\u4ECA\u65E5\u4EFB\u52A1",
"settings.notificationDuration": "\u23F1\uFE0F \u901A\u77E5\u663E\u793A\u65F6\u95F4",
"settings.notificationDuration.desc": "\u6210\u529F/\u5931\u8D25\u63D0\u793A\u663E\u793A\u65F6\u95F4\uFF08\u6BEB\u79D2\uFF09",
"settings.preview": "\u9884\u89C8\u6A21\u677F\u6548\u679C",
"settings.resetDefault": "\u6062\u590D\u9ED8\u8BA4\u8BBE\u7F6E",
"template.dateWithIcon": "\u5E26\u56FE\u6807\u7684\u5F53\u524D\u65E5\u671F",
"settings.basicSettings": "\u57FA\u672C\u8BBE\u7F6E",
"settings.templateSettings": "\u6A21\u677F\u8BBE\u7F6E",
// 通知
"notification.taskAdded": "\u4ECA\u65E5\u4EFB\u52A1\u5DF2\u6DFB\u52A0",
"notification.taskExists": "\u4ECA\u65E5\u4EFB\u52A1\u5DF2\u5B58\u5728",
"notification.error": "\u9519\u8BEF\uFF1A",
// 星期
"weekday.mon": "\u661F\u671F\u4E00",
"weekday.tue": "\u661F\u671F\u4E8C",
"weekday.wed": "\u661F\u671F\u4E09",
"weekday.thu": "\u661F\u671F\u56DB",
"weekday.fri": "\u661F\u671F\u4E94",
"weekday.sat": "\u661F\u671F\u516D",
"weekday.sun": "\u661F\u671F\u65E5",
// 插件名称和描述
"plugin.name": "\u6BCF\u65E5\u4EFB\u52A1\u81EA\u52A8\u751F\u6210\u5668",
"plugin.description": "\u4E00\u4E2A\u5F3A\u5927\u7684\u4EFB\u52A1\u81EA\u52A8\u751F\u6210\u5668\uFF0C\u5E2E\u52A9\u4F60\u9AD8\u6548\u5730\u7BA1\u7406\u65E5\u5E38\u4EFB\u52A1",
// 一般按钮和消息
"button.addTask": "\u6DFB\u52A0\u4EFB\u52A1",
"button.save": "\u4FDD\u5B58",
"button.cancel": "\u53D6\u6D88",
"button.done": "\u5B8C\u6210",
// 添加任务统计相关翻译
"settings.taskStatistics": "\u{1F4CA} \u4EFB\u52A1\u5B8C\u6210\u7EDF\u8BA1",
"settings.taskStatistics.desc": "\u5F00\u542F\u540E\uFF0C\u6BCF\u65E5\u751F\u6210\u4EFB\u52A1\u524D\u4F1A\u81EA\u52A8\u7EDF\u8BA1\u524D\u4E00\u5929\u7684\u4EFB\u52A1\u5B8C\u6210\u60C5\u51B5",
"statistics.title": "\u{1F4CA} \u6628\u65E5\u4EFB\u52A1\u7EDF\u8BA1",
"statistics.totalTasks": "\u4EFB\u52A1\u603B\u6570",
"statistics.completedTasks": "\u5DF2\u5B8C\u6210\u4EFB\u52A1",
"statistics.completionRate": "\u5B8C\u6210\u7387",
"statistics.unfinishedTasks": "\u672A\u5B8C\u6210\u7684\u4EFB\u52A1",
"statistics.suggestions": "\u5EFA\u8BAE\u4ECA\u65E5\u8003\u8651\u5B8C\u6210\u4EE5\u4E0B\u4EFB\u52A1",
"statistics.moreTasks.singular": "\u8FD8\u67091\u4E2A\u672A\u5B8C\u6210\u4EFB\u52A1",
"statistics.moreTasks.plural": "\u8FD8\u6709\u66F4\u591A\u672A\u5B8C\u6210\u4EFB\u52A1"
};
var translationsEN = {
// 设置页面
"settings.title": "Daily Task Auto Generator Settings",
"settings.rootDir": "\u{1F4C1} Task Directory",
"settings.rootDir.desc": 'Specify the root directory for storing task files, tasks will be stored in "Year/Month.md" format',
"settings.rootDir.saved": "\u2713 Directory saved",
"settings.save": "\u{1F4BE} Save",
"settings.autoGenerate": "\u{1F504} Auto Generate Mode",
"settings.autoGenerate.desc": "Choose when to automatically generate daily tasks",
"settings.mode.none": "\u274C Off",
"settings.mode.daily": "\u{1F4C6} Daily",
"settings.mode.workday": "\u{1F4BC} Workdays Only",
"settings.language": "\u{1F524} Interface Language",
"settings.language.desc": "Select the language for the plugin interface",
"settings.language.auto": "\u{1F50D} Auto Detect",
"settings.language.zh": "\u{1F1E8}\u{1F1F3} Chinese",
"settings.language.en": "\u{1F1EC}\u{1F1E7} English",
"settings.animations": "\u2728 Animation Effects",
"settings.animations.desc": "Enable interface animation effects",
"settings.template": "\u{1F4DD} Task Template",
"settings.template.zh": "\u{1F1E8}\u{1F1F3} Chinese Template",
"settings.template.en": "\u{1F1EC}\u{1F1E7} English Template",
"settings.template.preview": "\u{1F441}\uFE0F Show Preview",
"settings.template.hide": "\u{1F441}\uFE0F\u200D\u{1F5E8}\uFE0F Hide Preview",
"settings.resetToDefault": "\u{1F504} Reset to Default",
"settings.addTaskButton": "\u2795 Add Today's Task Manually",
"settings.notificationDuration": "\u23F1\uFE0F Notification Duration",
"settings.notificationDuration.desc": "Duration to show success/failure notifications (milliseconds)",
"settings.preview": "Preview Template",
"settings.resetDefault": "Reset to Default",
"template.dateWithIcon": "Current date with icon",
"settings.basicSettings": "Basic Settings",
"settings.templateSettings": "Template Settings",
// 通知
"notification.taskAdded": "Today's task has been added",
"notification.taskExists": "Today's task already exists",
"notification.error": "Error: ",
// 星期
"weekday.mon": "Monday",
"weekday.tue": "Tuesday",
"weekday.wed": "Wednesday",
"weekday.thu": "Thursday",
"weekday.fri": "Friday",
"weekday.sat": "Saturday",
"weekday.sun": "Sunday",
// 插件名称和描述
"plugin.name": "Daily Task Auto Generator",
"plugin.description": "A powerful task auto generator to help you efficiently manage daily tasks",
// 一般按钮和消息
"button.addTask": "Add Task",
"button.save": "Save",
"button.cancel": "Cancel",
"button.done": "Done",
// 添加任务统计相关翻译
"settings.taskStatistics": "\u{1F4CA} Task Completion Statistics",
"settings.taskStatistics.desc": "When enabled, automatically analyze yesterday's task completion before generating today's tasks",
"statistics.title": "\u{1F4CA} Yesterday's Task Summary",
"statistics.totalTasks": "Total Tasks",
"statistics.completedTasks": "Completed Tasks",
"statistics.completionRate": "Completion Rate",
"statistics.unfinishedTasks": "Unfinished Tasks",
"statistics.suggestions": "Consider completing the following tasks today",
"statistics.moreTasks.singular": "more task",
"statistics.moreTasks.plural": "more tasks"
};
var translations = {
"zh": translationsZH,
"en": translationsEN
};
var currentLanguage = "en";
function setCurrentLanguage(language) {
currentLanguage = language;
}
function getTranslation(key, fallbackLanguage) {
var _a;
const language = fallbackLanguage || currentLanguage;
const translation = (_a = translations[language]) == null ? void 0 : _a[key];
if (!translation) {
return translations["en"][key] || key;
}
return translation;
}
function getLocalizedWeekday(dayOfWeek) {
const weekdayKeys = [
"weekday.sun",
"weekday.mon",
"weekday.tue",
"weekday.wed",
"weekday.thu",
"weekday.fri",
"weekday.sat"
];
const normalizedDayOfWeek = (dayOfWeek % 7 + 7) % 7;
return getTranslation(weekdayKeys[normalizedDayOfWeek]);
}
// src/utils/dateUtils.ts
function getCurrentYear() {
return new Date().getFullYear().toString();
}
function getCurrentMonth() {
const month = (new Date().getMonth() + 1).toString();
return month.padStart(2, "0");
}
function getLocalizedMonthName(isEnglish = false) {
const monthIndex = new Date().getMonth();
const chineseMonths = [
"1\u6708",
"2\u6708",
"3\u6708",
"4\u6708",
"5\u6708",
"6\u6708",
"7\u6708",
"8\u6708",
"9\u6708",
"10\u6708",
"11\u6708",
"12\u6708"
];
const englishMonths = [
"January",
"February",
"March",
"April",
"May",
"June",
"July",
"August",
"September",
"October",
"November",
"December"
];
return isEnglish ? englishMonths[monthIndex] : chineseMonths[monthIndex];
}
function getDayIcon() {
const day = new Date().getDate();
const dayIcons = [
"\u{1F311}",
// 1日
"\u{1F312}",
// 2日
"\u{1F313}",
// 3日
"\u{1F314}",
// 4日
"\u{1F315}",
// 5日
"\u{1F316}",
// 6日
"\u{1F317}",
// 7日
"\u{1F318}",
// 8日
"\u{1F31F}",
// 9日
"\u2B50",
// 10日
"\u{1F308}",
// 11日
"\u{1F31E}",
// 12日
"\u{1F324}\uFE0F",
// 13日
"\u26C5",
// 14日
"\u{1F326}\uFE0F",
// 15日
"\u{1F327}\uFE0F",
// 16日
"\u26C8\uFE0F",
// 17日
"\u{1F329}\uFE0F",
// 18日
"\u{1F32A}\uFE0F",
// 19日
"\u{1F32B}\uFE0F",
// 20日
"\u{1F32C}\uFE0F",
// 21日
"\u{1F340}",
// 22日
"\u{1F331}",
// 23日
"\u{1F332}",
// 24日
"\u{1F333}",
// 25日
"\u{1F334}",
// 26日
"\u{1F335}",
// 27日
"\u{1F33A}",
// 28日
"\u{1F33B}",
// 29日
"\u{1F33C}",
// 30日
"\u{1F338}"
// 31日
];
return dayIcons[day - 1] || "\u{1F4C5}";
}
function isEnglishEnvironment() {
const mondayText = getTranslation("weekday.mon");
return mondayText === "Monday";
}
function getCurrentDay() {
const day = new Date().getDate().toString();
return day.padStart(2, "0");
}
function getCurrentDate() {
return `${getCurrentYear()}-${getCurrentMonth()}-${getCurrentDay()}`;
}
function getCurrentDateWithIcon() {
const icon = getDayIcon();
return `${icon} ${getCurrentDate()}`;
}
function isWorkday() {
const day = new Date().getDay();
return day >= 1 && day <= 5;
}
function getCurrentWeekdayName() {
const day = new Date().getDay();
return getLocalizedWeekday(day);
}
function getYearProgress() {
const now = new Date();
const start = new Date(now.getFullYear(), 0, 1);
const end = new Date(now.getFullYear() + 1, 0, 1);
const totalDays = (end.getTime() - start.getTime()) / (1e3 * 60 * 60 * 24);
const passedDays = (now.getTime() - start.getTime()) / (1e3 * 60 * 60 * 24);
return Math.round(passedDays / totalDays * 100);
}
function getMonthProgress() {
const now = new Date();
const start = new Date(now.getFullYear(), now.getMonth(), 1);
const end = new Date(now.getFullYear(), now.getMonth() + 1, 1);
const totalDays = (end.getTime() - start.getTime()) / (1e3 * 60 * 60 * 24);
const passedDays = (now.getTime() - start.getTime()) / (1e3 * 60 * 60 * 24);
return Math.round(passedDays / totalDays * 100);
}
// src/utils/templateEngine.ts
function getCurrentTime() {
const now = new Date();
const hours = now.getHours().toString().padStart(2, "0");
const minutes = now.getMinutes().toString().padStart(2, "0");
return `${hours}:${minutes}`;
}
function renderTemplate(template) {
const variableMap = {
"date": getCurrentDate(),
"dateWithIcon": getCurrentDateWithIcon(),
"weekday": getCurrentWeekdayName(),
"yearProgress": getYearProgress(),
"monthProgress": getMonthProgress(),
"time": getCurrentTime()
};
let renderedContent = template;
for (const [variable, value] of Object.entries(variableMap)) {
renderedContent = renderedContent.replace(
new RegExp(`{{${variable}}}`, "g"),
value.toString()
);
}
return renderedContent;
}
// src/taskGenerator.ts
var import_obsidian2 = require("obsidian");
// src/utils/fileUtils.ts
var import_obsidian = require("obsidian");
async function ensureFolderExists(vault, path) {
try {
path = path.endsWith("/") ? path : path + "/";
const folders = path.split("/").filter((p) => p.length > 0);
let currentPath = "";
for (const folder of folders) {
if (currentPath) {
currentPath += "/" + folder;
} else {
currentPath = folder;
}
console.log(`\u68C0\u67E5\u76EE\u5F55: ${currentPath}`);
const existingItem = vault.getAbstractFileByPath(currentPath);
if (!existingItem) {
console.log(`\u76EE\u5F55\u4E0D\u5B58\u5728\uFF0C\u6B63\u5728\u521B\u5EFA: ${currentPath}`);
try {
await vault.createFolder(currentPath);
console.log(`\u76EE\u5F55\u521B\u5EFA\u6210\u529F: ${currentPath}`);
} catch (e) {
console.log(`\u521B\u5EFA\u76EE\u5F55\u65F6\u51FA\u73B0\u5F02\u5E38\uFF0C\u53EF\u80FD\u5DF2\u88AB\u5176\u4ED6\u8FDB\u7A0B\u521B\u5EFA: ${e}`);
const folderAfterError = vault.getAbstractFileByPath(currentPath);
if (!folderAfterError || !(folderAfterError instanceof import_obsidian.TFolder)) {
console.error(`\u76EE\u5F55\u521B\u5EFA\u5931\u8D25\uFF0C\u4E14\u65E0\u6CD5\u786E\u8BA4\u76EE\u5F55\u5DF2\u5B58\u5728: ${currentPath}`);
return false;
}
}
} else if (!(existingItem instanceof import_obsidian.TFolder)) {
console.error(`\u8DEF\u5F84 ${currentPath} \u5DF2\u5B58\u5728\u4F46\u4E0D\u662F\u6587\u4EF6\u5939\uFF0C\u800C\u662F: ${existingItem.constructor.name}`);
return false;
} else {
console.log(`\u76EE\u5F55\u5DF2\u5B58\u5728\uFF0C\u65E0\u9700\u521B\u5EFA: ${currentPath}`);
}
}
return true;
} catch (error) {
console.error(`\u521B\u5EFA\u76EE\u5F55\u65F6\u51FA\u73B0\u672A\u9884\u671F\u9519\u8BEF(${path}):`, error);
return false;
}
}
async function ensureFileExists(vault, path, content = "") {
try {
const existingItem = vault.getAbstractFileByPath(path);
if (existingItem) {
if (existingItem instanceof import_obsidian.TFile) {
console.log(`\u6587\u4EF6\u5DF2\u5B58\u5728\uFF0C\u65E0\u9700\u521B\u5EFA: ${path}`);
return true;
} else {
console.error(`\u8DEF\u5F84 ${path} \u5B58\u5728\u4F46\u4E0D\u662F\u6587\u4EF6\uFF0C\u65E0\u6CD5\u521B\u5EFA\u6587\u4EF6\uFF0C\u53EF\u80FD\u662F\u540C\u540D\u76EE\u5F55`);
return false;
}
}
const lastSlashIndex = path.lastIndexOf("/");
if (lastSlashIndex > 0) {
const parentPath = path.substring(0, lastSlashIndex);
console.log(`\u68C0\u67E5\u6587\u4EF6\u7236\u76EE\u5F55: ${parentPath}`);
const parentExists = await ensureFolderExists(vault, parentPath);
if (!parentExists) {
console.error(`\u65E0\u6CD5\u786E\u4FDD\u7236\u76EE\u5F55\u5B58\u5728: ${parentPath}`);
return false;
}
}
try {
console.log(`\u5F00\u59CB\u521B\u5EFA\u6587\u4EF6: ${path}`);
await vault.create(path, content);
console.log(`\u6587\u4EF6\u521B\u5EFA\u6210\u529F: ${path}`);
return true;
} catch (e) {
console.log(`\u521B\u5EFA\u6587\u4EF6\u65F6\u51FA\u73B0\u5F02\u5E38: ${e}`);
const fileAfterError = vault.getAbstractFileByPath(path);
if (fileAfterError && fileAfterError instanceof import_obsidian.TFile) {
console.log(`\u5C3D\u7BA1\u51FA\u73B0\u5F02\u5E38\uFF0C\u4F46\u6587\u4EF6\u5DF2\u5B58\u5728\uFF0C\u53EF\u80FD\u88AB\u5176\u4ED6\u8FDB\u7A0B\u521B\u5EFA: ${path}`);
return true;
}
console.error(`\u6587\u4EF6\u521B\u5EFA\u6700\u7EC8\u5931\u8D25: ${path}`);
return false;
}
} catch (error) {
console.error(`\u521B\u5EFA\u6587\u4EF6\u65F6\u51FA\u73B0\u672A\u9884\u671F\u9519\u8BEF(${path}):`, error);
return false;
}
}
async function appendToFile(vault, path, content) {
try {
const file = vault.getAbstractFileByPath(path);
if (file && file instanceof import_obsidian.TFile) {
try {
const currentContent = await vault.read(file);
await vault.modify(file, currentContent + "\n\n" + content);
return true;
} catch (e) {
console.error(`\u8BFB\u53D6\u6216\u4FEE\u6539\u6587\u4EF6\u65F6\u51FA\u9519: ${e}`);
return false;
}
} else {
console.log(`\u6587\u4EF6\u4E0D\u5B58\u5728\uFF0C\u5C1D\u8BD5\u521B\u5EFA: ${path}`);
return await ensureFileExists(vault, path, content);
}
} catch (error) {
console.error(`Error appending to file at ${path}:`, error);
return false;
}
}
function getTaskFilePath(rootDir) {
const year = getCurrentYear();
const isEnglish = isEnglishEnvironment();
const monthName = getLocalizedMonthName(isEnglish);
return (0, import_obsidian.normalizePath)(`${rootDir}/${year}/${monthName}.md`);
}
async function todayTaskExists(vault, rootDir) {
const taskFilePath = getTaskFilePath(rootDir);
const date = getCurrentDate();
try {
console.log(`\u68C0\u67E5\u4ECA\u65E5\u4EFB\u52A1\u662F\u5426\u5B58\u5728\u4E8E: ${taskFilePath}`);
const file = vault.getAbstractFileByPath(taskFilePath);
if (file && file instanceof import_obsidian.TFile) {
const content = await vault.read(file);
const dateRegex = new RegExp(`## [^\\n]*${date}[^\\n]*\\n`);
return dateRegex.test(content);
}
return false;
} catch (error) {
console.error(`\u68C0\u67E5\u4ECA\u65E5\u4EFB\u52A1\u65F6\u51FA\u9519:`, error);
return false;
}
}
function getYesterdayDate() {
const today = new Date();
const yesterday = new Date(today);
yesterday.setDate(today.getDate() - 1);
const year = yesterday.getFullYear();
const month = (yesterday.getMonth() + 1).toString().padStart(2, "0");
const day = yesterday.getDate().toString().padStart(2, "0");
return `${year}-${month}-${day}`;
}
function getYesterdayTaskFilePath(rootDir) {
const yesterday = new Date();
yesterday.setDate(yesterday.getDate() - 1);
const year = yesterday.getFullYear().toString();
const isEnglish = isEnglishEnvironment();
const month = new Date().getMonth();
const yesterdayMonth = yesterday.getMonth();
const tempDate = new Date();
tempDate.setMonth(yesterdayMonth);
const monthName = isEnglish ? getMonthNameEN(yesterdayMonth) : getMonthNameZH(yesterdayMonth);
return (0, import_obsidian.normalizePath)(`${rootDir}/${year}/${monthName}.md`);
}
function getMonthNameZH(monthIndex) {
const months = [
"1\u6708",
"2\u6708",
"3\u6708",
"4\u6708",
"5\u6708",
"6\u6708",
"7\u6708",
"8\u6708",
"9\u6708",
"10\u6708",
"11\u6708",
"12\u6708"
];
return months[monthIndex];
}
function getMonthNameEN(monthIndex) {
const months = [
"January",
"February",
"March",
"April",
"May",
"June",
"July",
"August",
"September",
"October",
"November",
"December"
];
return months[monthIndex];
}
async function extractTasksForDate(vault, filePath, date) {
try {
const file = vault.getAbstractFileByPath(filePath);
if (!file || !(file instanceof import_obsidian.TFile)) {
console.log(`\u627E\u4E0D\u5230\u6587\u4EF6: ${filePath}`);
return null;
}
const content = await vault.read(file);
const dateHeaderRegex = new RegExp(`## [^\\n]*${date}[^\\n]*\\n(.*?)(?=\\n## |$)`, "s");
const match = content.match(dateHeaderRegex);
if (match && match[1]) {
return match[1].trim();
}
console.log(`\u627E\u4E0D\u5230\u65E5\u671F ${date} \u7684\u4EFB\u52A1\u5185\u5BB9`);
return null;
} catch (error) {
console.error(`\u63D0\u53D6\u4EFB\u52A1\u5185\u5BB9\u65F6\u51FA\u9519: ${error}`);
return null;
}
}
function analyzeTaskCompletion(taskContent) {
const result = {
totalTasks: 0,
completedTasks: 0,
unfinishedTasksList: []
};
if (!taskContent) {
return result;
}
const allTasksRegex = /- \[([ x])\] (.+)$/gm;
const completedTasksRegex = /- \[x\] (.+)$/gm;
const unfinishedTasksRegex = /- \[ \] (.+)$/gm;
const allTasksMatches = [...taskContent.matchAll(allTasksRegex)];
result.totalTasks = allTasksMatches.length;
const completedTasksMatches = [...taskContent.matchAll(completedTasksRegex)];
result.completedTasks = completedTasksMatches.length;
const unfinishedTasksMatches = [...taskContent.matchAll(unfinishedTasksRegex)];
result.unfinishedTasksList = unfinishedTasksMatches.map((match) => match[1].trim());
return result;
}
async function yesterdayStatisticsExists(vault, filePath, date) {
try {
const file = vault.getAbstractFileByPath(filePath);
if (!file || !(file instanceof import_obsidian.TFile)) {
console.log(`\u627E\u4E0D\u5230\u6587\u4EF6: ${filePath}`);
return false;
}
const content = await vault.read(file);
const statisticsTitleRegex = new RegExp(`## [^\\n]*${date}[^\\n]*\\n.*?${getTranslation("statistics.title")}`, "s");
return statisticsTitleRegex.test(content);
} catch (error) {
console.error(`\u68C0\u67E5\u6628\u65E5\u7EDF\u8BA1\u4FE1\u606F\u65F6\u51FA\u9519: ${error}`);
return false;
}
}
function generateStatisticsContent(tasks, t) {
let totalTasks;
let completedTasks;
let unfinishedTasks = [];
if (Array.isArray(tasks)) {
totalTasks = tasks.length;
completedTasks = tasks.filter((task) => task.isCompleted).length;
unfinishedTasks = tasks.filter((task) => !task.isCompleted).map((task) => ({ task: task.task }));
} else {
totalTasks = tasks.totalTasks;
completedTasks = tasks.completedTasks;
unfinishedTasks = tasks.unfinishedTasksList.map((task) => ({ task }));
}
const completionRate = totalTasks > 0 ? Math.round(completedTasks / totalTasks * 100) : 0;
const displayTasks = unfinishedTasks.slice(0, 5);
let content = `## ${t("statistics.title")}
---
`;
content += `- ${t("statistics.totalTasks")}: ${totalTasks}
`;
content += `- ${t("statistics.completedTasks")}: ${completedTasks}
`;
content += `- ${t("statistics.completionRate")}: ${completionRate}%
`;
if (unfinishedTasks.length > 0) {
content += `### ${t("statistics.suggestions")}
---
`;
displayTasks.forEach((item) => {
content += `- [ ] ${item.task}
`;
});
if (unfinishedTasks.length > 5) {
const remaining = unfinishedTasks.length - 5;
const moreTasks = remaining === 1 ? t("statistics.moreTasks.singular") : `${remaining} ${t("statistics.moreTasks.plural")}`;
content += `- *${moreTasks}*
`;
}
}
return content;
}
// src/taskGenerator.ts
var TaskGenerator = class {
constructor(app, settingsManager) {
this.app = app;
this.vault = app.vault;
this.settingsManager = settingsManager;
}
/**
* 生成每日任务
* @param openFile 是否打开文件
* @param quietMode 静默模式,减少日志输出
* @returns 成功或失败
*/
async generateDailyTask(openFile = true, quietMode = false) {
try {
const settings = this.settingsManager.getSettings();
const rootDir = settings.rootDir.trim() || "DailyTasks";
const filePath = getTaskFilePath(rootDir);
if (!quietMode)
console.log(`\u751F\u6210\u4EFB\u52A1\u6587\u4EF6\u8DEF\u5F84: ${filePath}`);
const pathParts = filePath.split("/");
const year = pathParts.length > 1 ? pathParts[1] : "";
const monthName = pathParts.length > 2 ? pathParts[2].replace(".md", "") : "";
const yearFolder = `${rootDir}/${year}`;
if (!quietMode)
console.log(`\u6B63\u5728\u786E\u4FDD\u6839\u76EE\u5F55\u5B58\u5728: ${rootDir}`);
const rootCreated = await ensureFolderExists(this.vault, rootDir);
if (!rootCreated) {
console.error(`\u65E0\u6CD5\u8BBF\u95EE\u6216\u521B\u5EFA\u6839\u76EE\u5F55: ${rootDir}`);
throw new Error(`\u65E0\u6CD5\u8BBF\u95EE\u6839\u76EE\u5F55: ${rootDir}\uFF0C\u53EF\u80FD\u662F\u5B58\u5728\u540C\u540D\u6587\u4EF6\u6216\u6743\u9650\u95EE\u9898`);
}
if (!quietMode)
console.log(`\u6839\u76EE\u5F55\u786E\u8BA4: ${rootDir}`);
if (!quietMode)
console.log(`\u6B63\u5728\u786E\u4FDD\u5E74\u4EFD\u76EE\u5F55\u5B58\u5728: ${yearFolder}`);
const yearCreated = await ensureFolderExists(this.vault, yearFolder);
if (!yearCreated) {
console.error(`\u65E0\u6CD5\u8BBF\u95EE\u6216\u521B\u5EFA\u5E74\u4EFD\u76EE\u5F55: ${yearFolder}`);
throw new Error(`\u65E0\u6CD5\u8BBF\u95EE\u5E74\u4EFD\u76EE\u5F55: ${yearFolder}\uFF0C\u53EF\u80FD\u662F\u5B58\u5728\u540C\u540D\u6587\u4EF6\u6216\u6743\u9650\u95EE\u9898`);
}
if (!quietMode)
console.log(`\u5E74\u4EFD\u76EE\u5F55\u786E\u8BA4: ${yearFolder}`);
if (!quietMode)
console.log(`\u6B63\u5728\u786E\u4FDD\u6708\u4EFD\u6587\u4EF6\u5B58\u5728: ${filePath} (${monthName})`);
const fileCreated = await ensureFileExists(this.vault, filePath);
if (!fileCreated) {
console.error(`\u65E0\u6CD5\u8BBF\u95EE\u6216\u521B\u5EFA\u6708\u4EFD\u6587\u4EF6: ${filePath}`);
throw new Error(`\u65E0\u6CD5\u8BBF\u95EE\u6708\u4EFD\u6587\u4EF6: ${filePath}\uFF0C\u8BF7\u68C0\u67E5\u662F\u5426\u5B58\u5728\u540C\u540D\u76EE\u5F55\u6216\u6743\u9650\u95EE\u9898`);
}
if (!quietMode)
console.log(`\u6708\u4EFD\u6587\u4EF6\u786E\u8BA4: ${filePath}`);
const date = getCurrentDate();
const dateRegex = new RegExp(`## [^\\n]*${date}[^\\n]*\\n`);
const fileContent = await this.vault.read(this.vault.getAbstractFileByPath(filePath));
const existingTaskCheck = dateRegex.test(fileContent);
if (existingTaskCheck) {
console.log(`\u4ECA\u65E5(${date})\u4EFB\u52A1\u5DF2\u5B58\u5728\u4E8E\u6587\u4EF6\u4E2D\uFF0C\u8DF3\u8FC7\u521B\u5EFA`);
if (openFile) {
this.showWarningNotice(`\u{1F4CC} ${getTranslation("notification.taskExists")}`);
const file = this.vault.getAbstractFileByPath(filePath);
if (file && file instanceof import_obsidian2.TFile) {
const leaf = this.app.workspace.getLeaf();
await leaf.openFile(file);
}
}
return true;
}
let statisticsContent = "";
if (settings.taskStatistics) {
statisticsContent = await this.generateYesterdayStatistics(rootDir, date, quietMode);
}
let template = "";
if (this.settingsManager.hasCustomTemplate()) {
template = this.settingsManager.getSettings().customTemplate;
} else {
template = this.settingsManager.getTemplateByLanguage();
}
const renderedContent = renderTemplate(template);
const fullContent = statisticsContent ? `${renderedContent}
${statisticsContent}` : renderedContent;
if (!quietMode)
console.log(`\u6B63\u5728\u5411\u6587\u4EF6\u8FFD\u52A0\u5185\u5BB9`);
const success = await appendToFile(this.vault, filePath, fullContent);
if (success) {
console.log(`\u2705 \u4EFB\u52A1\u5185\u5BB9\u8FFD\u52A0\u6210\u529F ${date}`);
if (openFile) {
const file = this.vault.getAbstractFileByPath(filePath);
if (file && file instanceof import_obsidian2.TFile) {
const leaf = this.app.workspace.getLeaf();
await leaf.openFile(file);
setTimeout(() => {
this.showSuccessNotice(`\u2728 ${getTranslation("notification.taskAdded")}`);
}, 300);
} else {
throw new Error(`\u6587\u4EF6\u521B\u5EFA\u6210\u529F\u4F46\u65E0\u6CD5\u6253\u5F00: ${filePath}`);
}
} else {
console.log(`\u2728 \u4ECA\u65E5(${date})\u4EFB\u52A1\u5DF2\u9759\u9ED8\u6DFB\u52A0\uFF0C\u65E0\u9700\u6253\u5F00\u6587\u4EF6`);
}
} else {
throw new Error(`\u65E0\u6CD5\u5411\u6587\u4EF6\u8FFD\u52A0\u5185\u5BB9: ${filePath}`);
}
return success;
} catch (error) {
console.error("Error generating daily task:", error);
const errorMsg = error instanceof Error ? error.message : String(error);
this.showErrorNotice(`${getTranslation("notification.error")} ${errorMsg}`);
return false;
}
}
/**
* 生成昨日任务统计信息
* @param rootDir 根目录
* @param todayDate 今日日期(用于检查是否已存在统计)
* @param quietMode 静默模式
* @returns 统计信息内容或空字符串
*/
async generateYesterdayStatistics(rootDir, todayDate, quietMode = false) {
try {
const yesterdayDate = getYesterdayDate();
const yesterdayFilePath = getYesterdayTaskFilePath(rootDir);
if (!quietMode)
console.log(`\u6B63\u5728\u83B7\u53D6\u6628\u65E5(${yesterdayDate})\u4EFB\u52A1\u7EDF\u8BA1\uFF0C\u6587\u4EF6\u8DEF\u5F84: ${yesterdayFilePath}`);
const todayFilePath = getTaskFilePath(rootDir);
const statsExists = await yesterdayStatisticsExists(this.vault, todayFilePath, todayDate);
if (statsExists) {
if (!quietMode)
console.log("\u6628\u65E5\u7EDF\u8BA1\u4FE1\u606F\u5DF2\u5B58\u5728\uFF0C\u8DF3\u8FC7\u751F\u6210");
return "";
}
const yesterdayContent = await extractTasksForDate(this.vault, yesterdayFilePath, yesterdayDate);
if (!yesterdayContent) {
if (!quietMode)
console.log(`\u627E\u4E0D\u5230\u6628\u65E5(${yesterdayDate})\u4EFB\u52A1\u5185\u5BB9\uFF0C\u8DF3\u8FC7\u7EDF\u8BA1`);
return "";
}
const taskStats = analyzeTaskCompletion(yesterdayContent);
if (!quietMode) {
console.log(`\u6628\u65E5\u4EFB\u52A1\u7EDF\u8BA1: \u603B\u6570=${taskStats.totalTasks}, \u5DF2\u5B8C\u6210=${taskStats.completedTasks}`);
console.log(`\u672A\u5B8C\u6210\u4EFB\u52A1: ${taskStats.unfinishedTasksList.length}\u4E2A`);
}
if (taskStats.totalTasks === 0) {
if (!quietMode)
console.log("\u6628\u65E5\u6CA1\u6709\u4EFB\u52A1\uFF0C\u8DF3\u8FC7\u7EDF\u8BA1");
return "";
}
return generateStatisticsContent(taskStats, getTranslation);
} catch (error) {
console.error(`\u751F\u6210\u6628\u65E5\u7EDF\u8BA1\u4FE1\u606F\u65F6\u51FA\u9519:`, error);
return "";
}
}
/**
* 手动添加今日任务
* @returns 成功或失败
*/
async addTaskManually() {
try {
const settings = this.settingsManager.getSettings();
const rootDir = settings.rootDir.trim() || "DailyTasks";
const exists = await todayTaskExists(this.vault, rootDir);
if (exists) {
this.showWarningNotice(`\u{1F4CC} ${getTranslation("notification.taskExists")}`);
return false;
}
return await this.generateDailyTask();
} catch (error) {
console.error("Error adding task manually:", error);
const errorMsg = error instanceof Error ? error.message : String(error);
this.showErrorNotice(`${getTranslation("notification.error")} ${errorMsg}`);
return false;
}
}
/**
* 显示成功通知
* @param message 通知内容
*/
showSuccessNotice(message) {
const notice = new import_obsidian2.Notice(
message,
this.settingsManager.getSettings().successNotificationDuration
);
if (notice.noticeEl) {
notice.noticeEl.addClass("daily-task-success-notice");
}
}
/**
* 显示警告通知
* @param message 通知内容
*/
showWarningNotice(message) {
const notice = new import_obsidian2.Notice(
message,
this.settingsManager.getSettings().successNotificationDuration
);
if (notice.noticeEl) {
notice.noticeEl.addClass("daily-task-warning-notice");
}
}
/**
* 显示错误通知
* @param message 通知内容
*/
showErrorNotice(message) {
const notice = new import_obsidian2.Notice(
message,
this.settingsManager.getSettings().successNotificationDuration
);
if (notice.noticeEl) {
notice.noticeEl.addClass("daily-task-error-notice");
}
}
};
// src/settings/settings.ts
var TextCenterCSS = "daily-task-text-center";
var DailyTaskSettingTab = class extends import_obsidian3.PluginSettingTab {
constructor(app, plugin) {
super(app, plugin);
this.previewEl = null;
this.addTaskButton = null;
// 目录输入框
this.rootDirInput = null;
// 标记设置是否已修改但未保存
this.dirtySettings = false;
this.plugin = plugin;
this.settingsManager = plugin.settingsManager;
this.taskGenerator = new TaskGenerator(app, this.settingsManager);
}
display() {
const { containerEl } = this;
containerEl.empty();
containerEl.classList.add("daily-task-setting-tab");
const settings = this.settingsManager.getSettings();
const topSpacing = containerEl.createEl("div");
topSpacing.style.marginTop = "30px";
const rootDirSetting = new import_obsidian3.Setting(containerEl).setName(getTranslation("settings.rootDir")).setDesc(getTranslation("settings.rootDir.desc"));
const inputContainer = document.createElement("div");
inputContainer.style.display = "flex";
inputContainer.style.width = "100%";
inputContainer.style.position = "relative";
rootDirSetting.controlEl.appendChild(inputContainer);
this.rootDirInput = new import_obsidian3.TextComponent(inputContainer).setValue(settings.rootDir).onChange(async (value) => {
if (value.trim() !== "") {
this.dirtySettings = true;
this.autoSaveRootDir(value);
}
});
if (this.rootDirInput && this.rootDirInput.inputEl) {
this.rootDirInput.inputEl.placeholder = "DailyTasks";
this.rootDirInput.inputEl.style.width = "100%";
this.rootDirInput.inputEl.style.borderRadius = "4px";
this.rootDirInput.inputEl.style.padding = "8px 35px 8px 10px";
this.rootDirInput.inputEl.style.transition = "all 0.3s ease";
}
const saveIndicator = document.createElement("div");
saveIndicator.classList.add("save-indicator");
saveIndicator.style.position = "absolute";
saveIndicator.style.right = "10px";
saveIndicator.style.top = "50%";
saveIndicator.style.transform = "translateY(-50%)";
saveIndicator.style.opacity = "0";
saveIndicator.style.transition = "opacity 0.3s ease";
inputContainer.appendChild(saveIndicator);
const saveSuccessIcon = createSpan({ cls: "svg-icon lucide-check" });
saveSuccessIcon.style.color = "#4CAF50";
saveSuccessIcon.style.width = "18px";
saveSuccessIcon.style.height = "18px";
saveIndicator.appendChild(saveSuccessIcon);
let autoSaveTimer = null;
this.autoSaveRootDir = async (value) => {
if (autoSaveTimer !== null) {
clearTimeout(autoSaveTimer);
}
autoSaveTimer = setTimeout(async () => {
let pathToSave = value.trim();
if (pathToSave === "") {
pathToSave = "DailyTasks";
}
await this.settingsManager.updateSettings({ rootDir: pathToSave });
this.dirtySettings = false;
saveIndicator.style.opacity = "1";
setTimeout(() => {
saveIndicator.style.opacity = "0";
}, 2e3);
}, 800);
};
const autoGenSetting = new import_obsidian3.Setting(containerEl).setName(getTranslation("settings.autoGenerate")).setDesc(getTranslation("settings.autoGenerate.desc"));
const toggleContainer = document.createElement("div");
toggleContainer.classList.add("mode-toggle-container");
toggleContainer.style.width = "20%";
toggleContainer.style.marginLeft = "auto";
const modes = [
{ value: "none" /* NONE */, label: getTranslation("settings.mode.none") },
{ value: "daily" /* DAILY */, label: getTranslation("settings.mode.daily") },
{ value: "workday" /* WORKDAY */, label: getTranslation("settings.mode.workday") }
];
const slider = document.createElement("div");
slider.classList.add("mode-toggle-slider");
toggleContainer.appendChild(slider);
const updateSlider = (index) => {
slider.style.left = `${index * 33.33}%`;
};
let currentModeIndex = modes.findIndex((mode) => mode.value === settings.autoGenerateMode);
if (currentModeIndex === -1) {
currentModeIndex = modes.findIndex((mode) => mode.value === "workday" /* WORKDAY */);
this.settingsManager.updateSettings({ autoGenerateMode: "workday" /* WORKDAY */ });
}
updateSlider(currentModeIndex);
modes.forEach((mode, index) => {
const option = document.createElement("div");
option.classList.add("mode-toggle-option");
option.textContent = mode.label;
if (mode.value === settings.autoGenerateMode) {
option.classList.add("active");
}
option.addEventListener("click", async () => {
toggleContainer.querySelectorAll(".mode-toggle-option").forEach((el) => {
el.classList.remove("active");
});
option.classList.add("active");
updateSlider(index);
await this.settingsManager.updateSettings({ autoGenerateMode: mode.value });
});
toggleContainer.appendChild(option);
});
autoGenSetting.controlEl.appendChild(toggleContainer);
new import_obsidian3.Setting(containerEl).setName(getTranslation("settings.language")).setDesc(getTranslation("settings.language.desc")).addDropdown((dropdown) => {
dropdown.addOption("auto" /* AUTO */, getTranslation("settings.language.auto")).addOption("zh" /* ZH */, getTranslation("settings.language.zh")).addOption("en" /* EN */, getTranslation("settings.language.en")).setValue(settings.language).onChange(async (value) => {
await this.settingsManager.updateSettings({ language: value });
this.display();
});
});
new import_obsidian3.Setting(containerEl).setName(getTranslation("settings.notificationDuration")).setDesc(getTranslation("settings.notificationDuration.desc")).addText((text) => {
const component = text.setValue(settings.successNotificationDuration.toString()).onChange(async (value) => {
const duration = parseInt(value);
if (!isNaN(duration) && duration > 0) {
await this.settingsManager.updateSettings({ successNotificationDuration: duration });
}
});
component.inputEl.placeholder = "3000";
return component;
});
new import_obsidian3.Setting(containerEl).setName(getTranslation("settings.taskStatistics")).setDesc(getTranslation("settings.taskStatistics.desc")).addToggle((toggle) => {
const toggleEl = toggle.setValue(settings.taskStatistics).onChange(async (value) => {
await this.settingsManager.updateSettings({ taskStatistics: value });
});
const toggleControl = toggle.toggleEl || toggle.containerEl.querySelector(".checkbox-container");
if (toggleControl) {
toggleControl.classList.add("task-statistics-toggle");
const toggleContainer2 = toggleControl.parentElement;
if (toggleContainer2) {
const iconEl = createSpan({ cls: "svg-icon lucide-bar-chart-2" });
iconEl.style.marginRight = "8px";
iconEl.style.color = "var(--text-accent)";
toggleContainer2.prepend(iconEl);
toggleContainer2.style.transition = "all 0.3s ease";
toggleControl.style.transition = "all 0.3s ease";
}
}
return toggleEl;
});
containerEl.createEl("h3", { text: getTranslation("settings.template") });
const templateDescription = containerEl.createEl("p", {
text: this.settingsManager.getCurrentLanguage() === "zh" ? "\u6CE8\u610F\uFF1A\u9ED8\u8BA4\u6A21\u677F\u4F1A\u6839\u636E\u5F53\u524D\u8BED\u8A00\u73AF\u5883\u81EA\u52A8\u9009\u62E9\u5BF9\u5E94\u8BED\u8A00\u7684\u5185\u5BB9\u3002\u5982\u679C\u60A8\u81EA\u5B9A\u4E49\u6A21\u677F\uFF0C\u5C06\u5728\u6240\u6709\u8BED\u8A00\u73AF\u5883\u4E2D\u4F7F\u7528\u60A8\u7684\u81EA\u5B9A\u4E49\u5185\u5BB9\u3002" : "Note: Default template automatically adapts to your language environment. If you customize the template, your content will be used in all language environments."
});
templateDescription.style.fontSize = "0.85em";
templateDescription.style.opacity = "0.8";
templateDescription.style.marginBottom = "15px";
const templateVariablesEl = containerEl.createEl("p");
templateVariablesEl.innerHTML = this.settingsManager.getCurrentLanguage() === "zh" ? "<strong>\u53EF\u7528\u53D8\u91CF\uFF1A</strong> {{date}} - \u65E5\u671F, {{dateWithIcon}} - \u5E26\u56FE\u6807\u7684\u65E5\u671F, {{weekday}} - \u661F\u671F\u51E0, {{yearProgress}} - \u5E74\u8FDB\u5EA6, {{monthProgress}} - \u6708\u8FDB\u5EA6, {{time}} - \u5F53\u524D\u65F6\u95F4" : "<strong>Available variables:</strong> {{date}} - Date, {{dateWithIcon}} - Date with icon, {{weekday}} - Day of week, {{yearProgress}} - Year progress, {{monthProgress}} - Month progress, {{time}} - Current time";
templateVariablesEl.style.fontSize = "0.85em";
templateVariablesEl.style.marginBottom = "10px";
const templateSetting = new import_obsidian3.Setting(containerEl).setName(getTranslation("settings.template")).setClass("template-setting");
const templateContainer = document.createElement("div");
templateContainer.style.width = "100%";
const currentTemplate = this.settingsManager.hasCustomTemplate() ? this.settingsManager.getSettings().customTemplate : this.settingsManager.getTemplateByLanguage();
const textarea = new import_obsidian3.TextAreaComponent(templateContainer).setValue(currentTemplate).setPlaceholder(this.settingsManager.getCurrentLanguage() === "zh" ? "\u5728\u6B64\u5904\u8F93\u5165\u4EFB\u52A1\u6A21\u677F..." : "Enter task template here...").onChange(async (value) => {
await this.settingsManager.updateSettings({
customTemplate: value,
hasCustomTemplate: true
});
this.updatePreview(this.previewEl, value);
});
textarea.inputEl.classList.add("template-editor");
textarea.inputEl.style.height = "200px";
textarea.inputEl.style.border = "1px solid var(--background-modifier-border-hover)";
textarea.inputEl.style.borderRadius = "4px";
textarea.inputEl.style.padding = "12px";
textarea.inputEl.style.lineHeight = "1.5";
textarea.inputEl.style.fontSize = "14px";
textarea.inputEl.style.fontFamily = "var(--font-monospace)";
textarea.inputEl.style.transition = "all 0.2s ease";
textarea.inputEl.style.boxShadow = "inset 0 1px 3px rgba(0, 0, 0, 0.1)";
textarea.inputEl.style.backgroundColor = "var(--background-primary)";
textarea.inputEl.style.color = "var(--text-normal)";
textarea.inputEl.style.resize = "vertical";
textarea.inputEl.addEventListener("focus", () => {
textarea.inputEl.style.border = "1px solid var(--interactive-accent)";
textarea.inputEl.style.boxShadow = "0 0 0 2px rgba(var(--interactive-accent-rgb), 0.2), inset 0 1px 3px rgba(0, 0, 0, 0.1)";
textarea.inputEl.style.outline = "none";
});
textarea.inputEl.addEventListener("blur", () => {
textarea.inputEl.style.border = "1px solid var(--background-modifier-border-hover)";
textarea.inputEl.style.boxShadow = "inset 0 1px 3px rgba(0, 0, 0, 0.1)";
});
const previewHeader = document.createElement("div");
previewHeader.classList.add("template-preview-header");
previewHeader.style.display = "flex";
previewHeader.style.justifyContent = "space-between";
previewHeader.style.marginTop = "15px";
previewHeader.style.marginBottom = "10px";
previewHeader.style.width = "100%";
const previewBtnContainer = document.createElement("div");
previewBtnContainer.style.display = "flex";
previewBtnContainer.style.alignItems = "center";
const resetBtnContainer = document.createElement("div");
resetBtnContainer.style.display = "flex";
resetBtnContainer.style.alignItems = "center";
const toggleButton = new import_obsidian3.ButtonComponent(previewBtnContainer).setButtonText(getTranslation("settings.template.preview"));
toggleButton.buttonEl.addClass(TextCenterCSS);
toggleButton.buttonEl.style.textAlign = "center";
toggleButton.buttonEl.style.display = "flex";
toggleButton.buttonEl.style.alignItems = "center";
toggleButton.buttonEl.style.justifyContent = "center";
toggleButton.buttonEl.style.width = "130px";
toggleButton.buttonEl.style.borderRadius = "4px";
toggleButton.buttonEl.style.boxShadow = "0 2px 5px rgba(0,0,0,0.1)";
toggleButton.buttonEl.style.transition = "all 0.2s ease";
const eyeIcon = createSpan({ cls: "svg-icon lucide-eye" });
eyeIcon.style.marginRight = "6px";
toggleButton.buttonEl.prepend(eyeIcon);
this.previewEl = document.createElement("div");
this.previewEl.classList.add("template-preview");
this.previewEl.style.marginTop = "15px";
this.previewEl.style.padding = "15px";
this.previewEl.style.border = "1px dashed var(--background-modifier-border)";
this.previewEl.style.borderRadius = "8px";
this.previewEl.style.backgroundColor = "var(--background-secondary)";
this.previewEl.style.display = "none";
this.previewEl.style.maxHeight = "200px";
this.previewEl.style.overflow = "auto";
this.previewEl.style.boxShadow = "inset 0 0 5px rgba(0,0,0,0.1)";
this.updatePreview(this.previewEl, currentTemplate);
templateContainer.appendChild(this.previewEl);
toggleButton.onClick(() => {
this.togglePreview(this.previewEl);
if (this.previewEl && this.previewEl.classList.contains("visible")) {
eyeIcon.className = "svg-icon lucide-eye-off";
toggleButton.setButtonText(getTranslation("settings.template.hide"));
toggleButton.buttonEl.style.backgroundColor = "var(--background-modifier-success)";
} else {
eyeIcon.className = "svg-icon lucide-eye";
toggleButton.setButtonText(getTranslation("settings.template.preview"));
toggleButton.buttonEl.style.backgroundColor = "";
}
});
const resetBtn = new import_obsidian3.ButtonComponent(resetBtnContainer).setButtonText(getTranslation("settings.resetDefault"));
resetBtn.buttonEl.addClass(TextCenterCSS);
resetBtn.buttonEl.style.textAlign = "center";
resetBtn.buttonEl.style.display = "flex";
resetBtn.buttonEl.style.alignItems = "center";
resetBtn.buttonEl.style.justifyContent = "center";
resetBtn.buttonEl.style.width = "150px";
resetBtn.buttonEl.style.borderRadius = "4px";
resetBtn.buttonEl.style.boxShadow = "0 2px 5px rgba(0,0,0,0.1)";
resetBtn.buttonEl.style.transition = "all 0.2s ease";
const resetIcon = createSpan({ cls: "svg-icon lucide-refresh-cw" });
resetIcon.style.marginRight = "6px";
resetBtn.buttonEl.prepend(resetIcon);
resetBtn.onClick(async () => {
await this.settingsManager.updateSettings({
customTemplate: "",
hasCustomTemplate: false
});
const defaultTemplate = this.settingsManager.getTemplateByLanguage();
textarea.setValue(defaultTemplate);
this.updatePreview(this.previewEl, defaultTemplate);
resetBtn.buttonEl.style.backgroundColor = "var(--background-modifier-success)";
setTimeout(() => {
resetBtn.buttonEl.style.backgroundColor = "";
}, 1e3);
});
previewHeader.appendChild(previewBtnContainer);
previewHeader.appendChild(resetBtnContainer);
templateContainer.appendChild(previewHeader);
templateSetting.controlEl.appendChild(templateContainer);
const resetContainer = document.createElement("div");
resetContainer.style.display = "flex";
resetContainer.style.justifyContent = "flex-end";
resetContainer.style.marginTop = "20px";
resetContainer.style.marginBottom = "10px";
containerEl.appendChild(resetContainer);
const resetDefaultBtn = new import_obsidian3.ButtonComponent(resetContainer).setButtonText(getTranslation("settings.resetToDefault"));
resetDefaultBtn.buttonEl.addClass(TextCenterCSS);
resetDefaultBtn.buttonEl.addClass("danger-button");
resetDefaultBtn.buttonEl.style.textAlign = "center";
resetDefaultBtn.buttonEl.style.display = "flex";
resetDefaultBtn.buttonEl.style.alignItems = "center";
resetDefaultBtn.buttonEl.style.justifyContent = "center";
resetDefaultBtn.buttonEl.style.width = "150px";
resetDefaultBtn.buttonEl.prepend(createSpan({ cls: "svg-icon lucide-refresh-cw" }));
resetDefaultBtn.onClick(async () => {
await this.settingsManager.resetToDefaults();
this.display();
});
const addTaskContainer = document.createElement("div");
addTaskContainer.style.display = "flex";
addTaskContainer.style.justifyContent = "flex-end";
addTaskContainer.style.marginTop = "20px";
containerEl.appendChild(addTaskContainer);
this.addTaskButton = new import_obsidian3.ButtonComponent(addTaskContainer).setButtonText(getTranslation("settings.addTaskButton")).setCta();
if (this.addTaskButton && this.addTaskButton.buttonEl) {
this.addTaskButton.buttonEl.addClass(TextCenterCSS);
this.addTaskButton.buttonEl.style.textAlign = "center";
this.addTaskButton.buttonEl.style.display = "flex";
this.addTaskButton.buttonEl.style.alignItems = "center";
this.addTaskButton.buttonEl.style.justifyContent = "center";
}
this.addTaskButton.onClick(async () => {
var _a;
const rootDir = this.settingsManager.getSettings().rootDir;
if (this.addTaskButton && this.addTaskButton.buttonEl) {
this.addTaskButton.buttonEl.classList.add("loading");
}
(_a = this.addTaskButton) == null ? void 0 : _a.setDisabled(true);
try {
await this.taskGenerator.addTaskManually();
} catch (e) {
console.error("\u6DFB\u52A0\u4EFB\u52A1\u51FA\u9519:", e);
new import_obsidian3.Notice(`\u6DFB\u52A0\u4EFB\u52A1\u5931\u8D25: ${e.message || e}`);
} finally {
setTimeout(() => {
var _a2;
if (this.addTaskButton && this.addTaskButton.buttonEl) {
this.addTaskButton.buttonEl.classList.remove("loading");
}
(_a2 = this.addTaskButton) == null ? void 0 : _a2.setDisabled(false);
}, 500);
}
});
this.addTaskButton.buttonEl.prepend(createSpan({ cls: "svg-icon lucide-calendar-plus" }));
}
/**
* 更新模板预览
*/
updatePreview(previewEl, template) {
if (!previewEl)
return;
const renderedContent = renderTemplate(template);
previewEl.innerHTML = renderedContent.replace(/\n/g, "<br>");
}
/**
* 切换预览的显示/隐藏
*/
togglePreview(previewEl) {
if (!previewEl)
return;
if (previewEl.style.display === "none") {
previewEl.style.display = "block";
previewEl.classList.add("visible");
} else {
previewEl.style.display = "none";
previewEl.classList.remove("visible");
}
}
};
var SettingsManager = class {
constructor(plugin) {
this.plugin = plugin;
this.settings = Object.assign({}, DEFAULT_SETTINGS);
}
/**
* 获取当前设置
*/
getSettings() {
return this.settings;
}
/**
* 更新设置并保存
* @param settings 要更新的设置
*/
async updateSettings(settings) {
this.settings = {
...this.settings,
...settings
};
await this.saveSettings();
this.updateCurrentLanguage();
}
/**
* 保存设置到数据存储
*/
async saveSettings() {
await this.plugin.saveData(this.settings);
}
/**
* 加载设置
*/
async loadSettings() {
const loadedData = await this.plugin.loadData();
if (loadedData) {
this.settings = {
...DEFAULT_SETTINGS,
...loadedData
};
this.ensureSettingsCompleteness();
} else {
this.settings = {
...DEFAULT_SETTINGS,
autoGenerateMode: "workday" /* WORKDAY */
};
}
this.updateCurrentLanguage();
}
/**
* 确保设置完整性,为新增的设置项提供默认值
*/
ensureSettingsCompleteness() {
const defaultKeys = Object.keys(DEFAULT_SETTINGS);
defaultKeys.forEach((key) => {
if (!(key in this.settings)) {
this.settings[key] = DEFAULT_SETTINGS[key];
}
});
}
/**
* 恢复默认设置
*/
async resetToDefaults() {
this.settings = Object.assign({}, DEFAULT_SETTINGS);
await this.saveSettings();
this.updateCurrentLanguage();
}
/**
* 根据语言获取当前使用的模板
* 如果当前模板不是默认模板,则不再区分语言
*/
getCurrentTemplate() {
const language = this.getCurrentLanguage();
if (language === "zh") {
if (this.settings.templateZh !== DEFAULT_TEMPLATE_ZH) {
return this.settings.templateZh;
}
if (this.settings.templateEn !== DEFAULT_TEMPLATE_EN) {
return this.settings.templateEn;
}
return this.settings.templateZh;
} else {
if (this.settings.templateEn !== DEFAULT_TEMPLATE_EN) {
return this.settings.templateEn;
}
if (this.settings.templateZh !== DEFAULT_TEMPLATE_ZH) {
return this.settings.templateZh;
}
return this.settings.templateEn;
}
}
/**
* 获取当前语言设置
*/
getCurrentLanguage() {
if (this.settings.language === "auto" /* AUTO */) {
const systemLanguage = window.navigator.language.toLowerCase();
return systemLanguage.startsWith("zh") ? "zh" : "en";
}
return this.settings.language;
}
/**
* 更新当前语言
*/
updateCurrentLanguage() {
const language = this.getCurrentLanguage();
setCurrentLanguage(language);
}
/**
* 获取当前语言的模板
*/
getTemplateByLanguage() {
const language = this.getCurrentLanguage();
if (language === "zh") {
if (this.settings.templateZh !== DEFAULT_TEMPLATE_ZH) {
return this.settings.templateZh;
}
if (this.settings.templateEn !== DEFAULT_TEMPLATE_EN) {
return this.settings.templateEn;
}
return this.settings.templateZh;
} else {
if (this.settings.templateEn !== DEFAULT_TEMPLATE_EN) {
return this.settings.templateEn;
}
if (this.settings.templateZh !== DEFAULT_TEMPLATE_ZH) {
return this.settings.templateZh;
}
return this.settings.templateEn;
}
}
/**
* 检查是否存在自定义模板
*/
hasCustomTemplate() {
return !!this.settings.customTemplate;
}
};
// src/main.ts
var ICON = `<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M12 2L2 7l10 5 10-5-10-5zM2 17l10 5 10-5M2 12l10 5 10-5"/>
</svg>`;
var DailyTaskPlugin = class extends import_obsidian4.Plugin {
/**
* 插件加载时调用
*/
async onload() {
console.log("Loading Daily Task Auto Generator plugin");
(0, import_obsidian4.addIcon)("daily-task", ICON);
this.settingsManager = new SettingsManager(this);
await this.settingsManager.loadSettings();
this.taskGenerator = new TaskGenerator(this.app, this.settingsManager);
setCurrentLanguage(this.settingsManager.getCurrentLanguage());
this.addSettingTab(new DailyTaskSettingTab(this.app, this));
this.addCommand({
id: "add-daily-task",
name: "\u624B\u52A8\u6DFB\u52A0\u4ECA\u65E5\u4EFB\u52A1",
callback: async () => {
await this.taskGenerator.addTaskManually();
}
});
console.log("\u8BA1\u5212\u572810\u79D2\u540E\u68C0\u67E5\u662F\u5426\u9700\u8981\u81EA\u52A8\u751F\u6210\u4EFB\u52A1");
setTimeout(async () => {
console.log("\u5F00\u59CB\u68C0\u67E5\u662F\u5426\u9700\u8981\u81EA\u52A8\u751F\u6210\u4EFB\u52A1");
await this.checkAutoGenerate();
}, 1e4);
}
/**
* 插件卸载时调用
*/
onunload() {
console.log("Unloading Daily Task Auto Generator plugin");
}
/**
* 检查是否需要自动生成任务
*/
async checkAutoGenerate() {
const settings = this.settingsManager.getSettings();
switch (settings.autoGenerateMode) {
case "daily" /* DAILY */:
console.log("\u6839\u636E\u8BBE\u7F6E\uFF0C\u6BCF\u5929\u81EA\u52A8\u751F\u6210\u4EFB\u52A1\uFF08\u9759\u9ED8\u6A21\u5F0F\uFF09");
await this.taskGenerator.generateDailyTask(false, true);
break;
case "workday" /* WORKDAY */:
if (isWorkday()) {
console.log("\u6839\u636E\u8BBE\u7F6E\uFF0C\u5DE5\u4F5C\u65E5\u81EA\u52A8\u751F\u6210\u4EFB\u52A1\uFF08\u9759\u9ED8\u6A21\u5F0F\uFF09");
await this.taskGenerator.generateDailyTask(false, true);
} else {
console.log("\u4ECA\u5929\u4E0D\u662F\u5DE5\u4F5C\u65E5\uFF0C\u8DF3\u8FC7\u81EA\u52A8\u751F\u6210\u4EFB\u52A1");
}
break;
case "none" /* NONE */:
default:
console.log("\u5DF2\u7981\u7528\u81EA\u52A8\u751F\u6210\u4EFB\u52A1\u529F\u80FD");
break;
}
}
};