Files
StudyDiary-20261009/.obsidian/plugins/generate-timeline/main.js
CrazyJasonwell e97be9ac8c commit all
2026-10-09 22:06:40 +08:00

1371 lines
59 KiB
JavaScript
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
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 __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
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);
var __publicField = (obj, key, value) => {
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
return value;
};
// src/main.ts
var main_exports = {};
__export(main_exports, {
MetadataInputModal: () => MetadataInputModal,
default: () => TimelinePlugin
});
module.exports = __toCommonJS(main_exports);
var import_obsidian6 = require("obsidian");
// src/i18n.ts
var zhCN = {
settings: {
resetSettings: "\u91CD\u7F6E\u8BBE\u7F6E",
resetSettingsDesc: "\u5C06\u6240\u6709\u8BBE\u7F6E\u6062\u590D\u4E3A\u9ED8\u8BA4\u503C",
resetSettingsButton: "\u91CD\u7F6E\u4E3A\u9ED8\u8BA4\u503C",
lineWidth: "\u65F6\u95F4\u8F74\u7EBF\u5BBD\u5EA6",
lineWidthDesc: "\u8BBE\u7F6E\u4E3B\u65F6\u95F4\u8F74\u7EBF\u7684\u5BBD\u5EA6\uFF08\u50CF\u7D20\uFF09",
lineColor: "\u65F6\u95F4\u8F74\u7EBF\u989C\u8272",
lineColorDesc: "\u8BBE\u7F6E\u65F6\u95F4\u8F74\u7EBF\u7684\u989C\u8272",
colorPickerPlaceholder: "\u70B9\u51FB\u5DE6\u4FA7\u8272\u76D8\u9009\u62E9\u989C\u8272",
itemSpacing: "\u9879\u76EE\u95F4\u8DDD",
itemSpacingDesc: "\u8BBE\u7F6E\u65F6\u95F4\u8F74\u9879\u76EE\u4E4B\u95F4\u7684\u95F4\u8DDD\uFF08\u50CF\u7D20\uFF09",
cardBackground: "\u5361\u7247\u80CC\u666F\u8272",
cardBackgroundDesc: "\u8BBE\u7F6E\u5185\u5BB9\u5361\u7247\u7684\u80CC\u666F\u989C\u8272",
cardTextColor: "\u5361\u7247\u6587\u5B57\u989C\u8272",
cardTextColorDesc: "\u8BBE\u7F6E\u666E\u901A\u4E8B\u4EF6\u5361\u7247\u7684\u6587\u5B57\u989C\u8272",
cardBorderColor: "\u5361\u7247\u8FB9\u6846\u989C\u8272",
cardBorderColorDesc: "\u8BBE\u7F6E\u666E\u901A\u4E8B\u4EF6\u5361\u7247\u7684\u8FB9\u6846\u989C\u8272",
milestoneCardBackground: "\u91CC\u7A0B\u7891\u5361\u7247\u80CC\u666F\u8272",
milestoneCardBackgroundDesc: "\u8BBE\u7F6E\u91CC\u7A0B\u7891\u4E8B\u4EF6\u5361\u7247\u7684\u80CC\u666F\u989C\u8272",
milestoneCardTextColor: "\u91CC\u7A0B\u7891\u5361\u7247\u6587\u5B57\u989C\u8272",
milestoneCardTextColorDesc: "\u8BBE\u7F6E\u91CC\u7A0B\u7891\u4E8B\u4EF6\u5361\u7247\u7684\u6587\u5B57\u989C\u8272",
milestoneCardBorderColor: "\u91CC\u7A0B\u7891\u5361\u7247\u8FB9\u6846\u989C\u8272",
milestoneCardBorderColorDesc: "\u8BBE\u7F6E\u91CC\u7A0B\u7891\u4E8B\u4EF6\u5361\u7247\u7684\u8FB9\u6846\u989C\u8272",
animationDuration: "\u52A8\u753B\u6301\u7EED\u65F6\u95F4",
animationDurationDesc: "\u8BBE\u7F6E\u60AC\u505C\u52A8\u753B\u7684\u6301\u7EED\u65F6\u95F4\uFF08\u6BEB\u79D2\uFF09",
dateAttribute: "\u65E5\u671F\u5C5E\u6027",
dateAttributeDesc: "\u9009\u62E9\u7528\u4E8E\u65F6\u95F4\u8F74\u6392\u5E8F\u7684 frontmatter \u65E5\u671F\u5C5E\u6027\uFF08\u5982\uFF1Acreated, updated, date \u7B49\uFF09",
fileNamePrefix: "\u6587\u4EF6\u540D\u524D\u7F00",
fileNamePrefixDesc: "\u8BBE\u7F6E\u751F\u6210\u7684\u65F6\u95F4\u8F74\u6587\u4EF6\u540D\u524D\u7F00",
fileNameSuffix: "\u6587\u4EF6\u540D\u540E\u7F00",
fileNameSuffixDesc: "\u8BBE\u7F6E\u751F\u6210\u7684\u65F6\u95F4\u8F74\u6587\u4EF6\u540D\u540E\u7F00",
defaultPosition: "\u9ED8\u8BA4\u4F4D\u7F6E",
defaultPositionDesc: "\u9009\u62E9\u65F6\u95F4\u8F74\u89C6\u56FE\u5728\u5DE6\u4FA7\u8FD8\u662F\u53F3\u4FA7\u8FB9\u680F\u663E\u793A",
leftSidebar: "\u5DE6\u4FA7\u8FB9\u680F",
rightSidebar: "\u53F3\u4FA7\u8FB9\u680F",
language: "\u8BED\u8A00",
languageDesc: "\u9009\u62E9\u63D2\u4EF6\u754C\u9762\u8BED\u8A00",
milestoneAttribute: "\u91CC\u7A0B\u7891\u5C5E\u6027",
milestoneAttributeDesc: "\u7528\u4E8E\u6807\u8BB0\u91CC\u7A0B\u7891\u4E8B\u4EF6\u7684 frontmatter \u5C5E\u6027\u540D\u79F0\uFF08\u4F8B\u5982\uFF1Amilestone\uFF09",
milestoneValue: "\u91CC\u7A0B\u7891\u503C",
milestoneValueDesc: "\u91CC\u7A0B\u7891\u5C5E\u6027\u9700\u8981\u5339\u914D\u7684\u503C\uFF08\u7559\u7A7A\u5219\u8868\u793A\u53EA\u8981\u5C5E\u6027\u5B58\u5728\u5373\u53EF\uFF0C\u4F8B\u5982\uFF1Atrue, 1\uFF09"
},
commands: {
openTimelineView: "\u6253\u5F00\u65F6\u95F4\u8F74\u89C6\u56FE",
generateFromFolder: "\u4ECE\u6587\u4EF6\u5939\u751F\u6210\u65F6\u95F4\u8F74\u89C6\u56FE",
generateFileFromFolder: "\u4ECE\u6587\u4EF6\u5939\u751F\u6210\u65F6\u95F4\u8F74\u6587\u4EF6",
generateFromTag: "\u4ECE\u6807\u7B7E\u751F\u6210\u65F6\u95F4\u8F74\u89C6\u56FE",
generateFileFromTag: "\u4ECE\u6807\u7B7E\u751F\u6210\u65F6\u95F4\u8F74\u6587\u4EF6",
generateFromFileLinks: "\u4ECE\u5F53\u524D\u6587\u4EF6\u94FE\u63A5\u751F\u6210\u65F6\u95F4\u8F74\u89C6\u56FE",
generateFileFromFileLinks: "\u4ECE\u5F53\u524D\u6587\u4EF6\u94FE\u63A5\u751F\u6210\u65F6\u95F4\u8F74\u6587\u4EF6",
generateFromMetadata: "\u4ECE\u5143\u6570\u636E\u751F\u6210\u65F6\u95F4\u8F74\u89C6\u56FE",
generateFileFromMetadata: "\u4ECE\u5143\u6570\u636E\u751F\u6210\u65F6\u95F4\u8F74\u6587\u4EF6"
},
modal: {
metadataInputTitle: "\u8F93\u5165\u5143\u6570\u636E\u5B57\u7B26\u4E32",
metadataQueryName: "\u5143\u6570\u636E\u67E5\u8BE2",
metadataQueryDesc: "\u4F8B\u5982\uFF1Aauthor: - \u6211 \u6216 status: ongoing",
metadataInputPlaceholder: "\u8F93\u5165\u5143\u6570\u636E...",
submitButton: "\u786E\u5B9A",
cancelButton: "\u53D6\u6D88",
emptyInputNotice: "\u8BF7\u8F93\u5165\u5143\u6570\u636E\u5B57\u7B26\u4E32"
},
errors: {
renderFailed: "\u65F6\u95F4\u8F74\u89C6\u56FE\u6E32\u67D3\u5931\u8D25",
generateFolderFailed: "\u751F\u6210\u6587\u4EF6\u5939\u65F6\u95F4\u8F74\u89C6\u56FE\u65F6\u51FA\u9519",
generateTagFailed: "\u751F\u6210\u6807\u7B7E\u65F6\u95F4\u8F74\u89C6\u56FE\u65F6\u51FA\u9519",
generateFileFailed: "\u4ECE\u6587\u4EF6\u94FE\u63A5\u751F\u6210\u65F6\u95F4\u8F74\u89C6\u56FE\u65F6\u51FA\u9519",
noTaggedFiles: "\u6CA1\u6709\u627E\u5230\u5305\u542B\u6807\u7B7E #{tag} \u53CA\u5176\u5B50\u6807\u7B7E\u7684\u6587\u4EF6",
noFileLinks: "\u6587\u4EF6 {filename} \u4E2D\u6CA1\u6709\u627E\u5230\u53EF\u7528\u7684\u94FE\u63A5\u6216\u65E5\u671F\u4FE1\u606F",
createViewFailed: "\u65E0\u6CD5\u521B\u5EFA\u65F6\u95F4\u8F74\u89C6\u56FE\uFF1A\u8BF7\u68C0\u67E5\u4FA7\u8FB9\u680F\u7A7A\u95F4",
noMetadataFiles: "\u6CA1\u6709\u627E\u5230\u4E0E\u5143\u6570\u636E\u67E5\u8BE2 \u201C{query}\u201D \u5339\u914D\u7684\u6587\u4EF6",
generateMetadataFailed: "\u4ECE\u5143\u6570\u636E\u751F\u6210\u65F6\u95F4\u8F74\u5931\u8D25"
}
};
var enUS = {
settings: {
resetSettings: "Reset Settings",
resetSettingsDesc: "Restore all settings to default values",
resetSettingsButton: "Reset to Defaults",
lineWidth: "Timeline Line Width",
lineWidthDesc: "Set the width of the main timeline line (pixels)",
lineColor: "Timeline Line Color",
lineColorDesc: "Set the color of the timeline line",
colorPickerPlaceholder: "Click the color picker on the left",
itemSpacing: "Item Spacing",
itemSpacingDesc: "Set the spacing between timeline items (pixels)",
cardBackground: "Card Background Color",
cardBackgroundDesc: "Set the background color of content cards",
cardTextColor: "Card Text Color",
cardTextColorDesc: "Set the text color of regular event cards",
cardBorderColor: "Card Border Color",
cardBorderColorDesc: "Set the border color of regular event cards",
milestoneCardBackground: "Milestone Card Background",
milestoneCardBackgroundDesc: "Set the background color of milestone event cards",
milestoneCardTextColor: "Milestone Card Text Color",
milestoneCardTextColorDesc: "Set the text color of milestone event cards",
milestoneCardBorderColor: "Milestone Card Border Color",
milestoneCardBorderColorDesc: "Set the border color of milestone event cards",
animationDuration: "Animation Duration",
animationDurationDesc: "Set the duration of hover animations (milliseconds)",
dateAttribute: "Date Attribute",
dateAttributeDesc: "Choose the frontmatter date attribute for timeline sorting (e.g., created, updated, date)",
fileNamePrefix: "File Name Prefix",
fileNamePrefixDesc: "Set the prefix for generated timeline file names",
fileNameSuffix: "File Name Suffix",
fileNameSuffixDesc: "Set the suffix for generated timeline file names",
defaultPosition: "Default Position",
defaultPositionDesc: "Choose whether to display the timeline view in the left or right sidebar",
leftSidebar: "Left Sidebar",
rightSidebar: "Right Sidebar",
language: "Language",
languageDesc: "Select plugin interface language",
milestoneAttribute: "Milestone Attribute",
milestoneAttributeDesc: "The frontmatter attribute name used to mark milestone events (e.g., milestone)",
milestoneValue: "Milestone Value",
milestoneValueDesc: "The value the milestone attribute needs to match (leave empty to match if the attribute exists, e.g., true, 1)"
},
commands: {
openTimelineView: "Open Timeline View",
generateFromFolder: "Generate Timeline View from any Folder",
generateFileFromFolder: "Generate Timeline File from any Folder",
generateFromTag: "Generate Timeline View from any Tag",
generateFileFromTag: "Generate Timeline File from any Tag",
generateFromFileLinks: "Generate Timeline View from Current File Links",
generateFileFromFileLinks: "Generate Timeline File from Current File Links",
generateFromMetadata: "Generate Timeline View from any Metadata",
generateFileFromMetadata: "Generate Timeline File from any Metadata"
},
modal: {
metadataInputTitle: "Enter Metadata String",
metadataQueryName: "Metadata Query",
metadataQueryDesc: "e.g., author: - Me or status: ongoing",
metadataInputPlaceholder: "Enter metadata...",
submitButton: "Submit",
cancelButton: "Cancel",
emptyInputNotice: "Please enter a metadata string"
},
errors: {
renderFailed: "Failed to render timeline view",
generateFolderFailed: "Error generating folder timeline view",
generateTagFailed: "Error generating tag timeline view",
generateFileFailed: "Error generating file links timeline view",
noTaggedFiles: "No files found with tag #{tag} or its subtags",
noFileLinks: "No usable links or date information found in file {filename}",
createViewFailed: "Cannot create timeline view: Please check sidebar space",
noMetadataFiles: 'No files found matching metadata query "{query}"',
generateMetadataFailed: "Failed to generate timeline from metadata"
}
};
// src/TimelineView.ts
var import_obsidian2 = require("obsidian");
// src/Timeline.ts
var import_obsidian = require("obsidian");
var Timeline = class {
constructor(app, settings) {
__publicField(this, "app");
__publicField(this, "settings");
this.app = app;
this.settings = settings;
}
// 辅助函数:检查文件是否在timelines文件夹中
isInTimelinesFolder(file) {
return file.path.startsWith("timelines/") || file.path === "timelines";
}
async getFilePreview(file, tag) {
const content = await this.app.vault.cachedRead(file);
const normalizedTag = tag.replace(/^#/, "");
const tagLines = content.split("\n").filter((line) => {
const tagRegex = new RegExp(`(^|s)#${normalizedTag}(?=s|$|[^w/])`);
return tagRegex.test(line);
});
if (tagLines.length > 0) {
const firstTagLine = tagLines[0];
return firstTagLine.slice(0, 100) + (firstTagLine.length > 100 ? "..." : "");
}
const previewContent = content.replace(/^---[\s\S]*?---/, "").trim();
return previewContent.slice(0, 50) + (previewContent.length > 50 ? "..." : "");
}
async createTimelineItem(file, tag, metadataQuery) {
var _a;
const metadata = this.app.metadataCache.getFileCache(file);
const dateValue = (_a = metadata == null ? void 0 : metadata.frontmatter) == null ? void 0 : _a[this.settings.dateAttribute];
if (dateValue) {
const preview = tag ? await this.getFilePreview(file, tag) : await this.getFilePreview(file, "");
return {
date: new Date(dateValue),
title: file.basename,
path: file.path,
preview,
isMilestone: this.checkMilestone(metadata == null ? void 0 : metadata.frontmatter)
// 检查是否为里程碑
};
}
return null;
}
checkMilestone(frontmatter) {
if (!this.settings.milestoneAttribute || !frontmatter) {
return false;
}
const attributeValue = frontmatter[this.settings.milestoneAttribute];
if (attributeValue === void 0 || attributeValue === null) {
return false;
}
if (this.settings.milestoneValue === "") {
return true;
}
return String(attributeValue).toLowerCase() === String(this.settings.milestoneValue).toLowerCase();
}
sortItemsByDate(items) {
return items.sort((a, b) => b.date.getTime() - a.date.getTime());
}
extractLinkedFiles(content) {
const linkedFiles = [];
const linkRegex = /\[\[([^\]]+)\]\]/g;
let match;
while ((match = linkRegex.exec(content)) !== null) {
const linkPath = match[1].split("|")[0];
const file = this.app.metadataCache.getFirstLinkpathDest(linkPath, "");
if (file && file instanceof import_obsidian.TFile) {
linkedFiles.push(file);
}
}
return linkedFiles;
}
async generateFromFileLinks(file) {
const content = await this.app.vault.cachedRead(file);
const linkedFiles = this.extractLinkedFiles(content);
const items = [];
for (const linkedFile of linkedFiles) {
if (!this.isInTimelinesFolder(linkedFile)) {
const item = await this.createTimelineItem(linkedFile);
if (item) {
items.push(item);
}
}
}
return this.sortItemsByDate(items);
}
async generateFromMetadata(metadataQuery) {
const allFiles = this.app.vault.getMarkdownFiles();
const filteredFiles = allFiles.filter((file) => !this.isInTimelinesFolder(file));
const items = [];
let queryKey;
let queryValue = null;
const firstColonIndex = metadataQuery.indexOf(":");
if (firstColonIndex > 0) {
queryKey = metadataQuery.substring(0, firstColonIndex).trim();
queryValue = metadataQuery.substring(firstColonIndex + 1).trim();
if (queryValue === "") {
queryValue = null;
}
} else {
queryKey = metadataQuery.trim();
}
for (const file of filteredFiles) {
try {
const cache = this.app.metadataCache.getFileCache(file);
if (!cache || !cache.frontmatter)
continue;
const frontmatter = cache.frontmatter;
let match = false;
if (queryValue !== null) {
const fmValue = frontmatter[queryKey];
if (fmValue !== void 0 && fmValue !== null) {
if (Array.isArray(fmValue)) {
const cleanedQueryValue = queryValue.startsWith("- ") ? queryValue.substring(2) : queryValue;
match = fmValue.some((item) => {
const itemStr = String(item).trim().toLowerCase();
const queryStr = cleanedQueryValue.toLowerCase();
return itemStr === queryStr || itemStr.includes(queryStr) || queryStr.includes(itemStr);
});
} else {
const fmValueStr = String(fmValue).trim().toLowerCase();
const queryValueStr = queryValue.toLowerCase();
match = fmValueStr === queryValueStr || fmValueStr.includes(queryValueStr) || queryValueStr.includes(fmValueStr);
}
}
} else {
match = Object.prototype.hasOwnProperty.call(frontmatter, queryKey);
}
if (match) {
const item = await this.createTimelineItem(file, void 0, metadataQuery);
if (item) {
items.push(item);
}
}
} catch (error) {
console.error(`\u5904\u7406\u6587\u4EF6 ${file.path} \u65F6\u51FA\u9519:`, error);
continue;
}
}
return this.sortItemsByDate(items);
}
async generateFromFolder(folder) {
if (folder.path === "timelines" || folder.path.startsWith("timelines/")) {
return [];
}
const timelineItems = [];
const processFolder = async (currentFolder) => {
var _a;
if (currentFolder.path === "timelines" || currentFolder.path.startsWith("timelines/")) {
return;
}
for (const item of currentFolder.children) {
if (item instanceof import_obsidian.TFile && item.extension === "md") {
const metadata = this.app.metadataCache.getFileCache(item);
const dateValue = (_a = metadata == null ? void 0 : metadata.frontmatter) == null ? void 0 : _a[this.settings.dateAttribute];
if (dateValue) {
timelineItems.push({
date: new Date(dateValue),
title: item.basename,
path: item.path,
preview: await this.getFilePreview(item, ""),
isMilestone: this.checkMilestone(metadata == null ? void 0 : metadata.frontmatter)
});
}
} else if (item instanceof import_obsidian.TFolder) {
await processFolder(item);
}
}
};
await processFolder(folder);
return timelineItems.sort((a, b) => b.date.getTime() - a.date.getTime());
}
async generateFromTag(tag) {
var _a;
const allFiles = this.app.vault.getMarkdownFiles();
const filteredFiles = allFiles.filter((file) => !this.isInTimelinesFolder(file));
const items = [];
const normalizedTag = tag.replace(/^#/, "").trim();
const isMatchingTag = (fileTag, searchTag) => {
const cleanFileTag = fileTag.replace(/^#/, "").trim().toLowerCase();
const cleanSearchTag = searchTag.toLowerCase();
return cleanFileTag === cleanSearchTag || cleanFileTag.startsWith(cleanSearchTag + "/") || cleanSearchTag.includes(cleanFileTag);
};
for (const file of filteredFiles) {
try {
const cache = this.app.metadataCache.getFileCache(file);
if (!cache)
continue;
let hasMatchingTag = false;
if (cache.tags && cache.tags.length > 0) {
hasMatchingTag = cache.tags.some((tagObj) => {
return isMatchingTag(tagObj.tag, normalizedTag);
});
}
if (!hasMatchingTag && ((_a = cache.frontmatter) == null ? void 0 : _a.tags)) {
const frontmatterTags = cache.frontmatter.tags;
if (Array.isArray(frontmatterTags)) {
hasMatchingTag = frontmatterTags.some((frontmatterTag) => {
if (typeof frontmatterTag !== "string")
return false;
return isMatchingTag(frontmatterTag, normalizedTag);
});
} else if (typeof frontmatterTags === "string") {
const normalizedTags = frontmatterTags.replace(/[,;]/g, " ").trim();
const tagList = normalizedTags.split(/\s+/);
hasMatchingTag = tagList.some((tagItem) => {
return isMatchingTag(tagItem, normalizedTag);
});
}
}
if (hasMatchingTag) {
const item = await this.createTimelineItem(file, normalizedTag);
if (item) {
items.push(item);
}
}
} catch (error) {
console.error(`\u5904\u7406\u6587\u4EF6 ${file.path} \u65F6\u51FA\u9519:`, error);
continue;
}
}
return this.sortItemsByDate(items);
}
async generateTimelineMarkdown(items, title, source) {
let generatedFromValue = source.value;
if (source.type === "metadata") {
const parts = source.value.split(":");
const key = parts[0].trim();
const value = parts.slice(1).join(":").trim();
generatedFromValue = `${key}:${value}`;
}
let markdown = `---
generated_from: ${source.type}:${generatedFromValue}
---
`;
markdown += `# ${title}
`;
let currentYear = null;
let currentMonth = null;
for (const item of items) {
const date = item.date;
const year = date.getFullYear();
const month = date.getMonth();
if (currentYear !== year) {
markdown += `
## ${year}
`;
currentYear = year;
currentMonth = null;
}
if (currentMonth !== month) {
const monthName = this.settings.language === "zh-CN" ? date.toLocaleString("zh-CN", { month: "long" }) : date.toLocaleString("en-US", { month: "long" });
markdown += `
### ${monthName}
`;
currentMonth = month;
}
const dateFormat = this.settings.language === "zh-CN" ? date.toLocaleDateString("zh-CN") : date.toLocaleDateString("en-US");
markdown += `#### ${dateFormat} - [[${item.title}]]
`;
}
return markdown;
}
};
// src/TimelineView.ts
var VIEW_TYPE_TIMELINE = "timeline-view";
var CLASS_TIMELINE_HEADER = "timeline-header";
var CLASS_TIMELINE_CONTAINER = "timeline-container";
var CLASS_TIMELINE_LINE = "timeline-line";
var CLASS_TIMELINE_ERA = "timeline-era";
var CLASS_TIMELINE_ERA_TITLE = "timeline-era-title";
var CLASS_TIMELINE_ITEM = "timeline-item";
var CLASS_TIMELINE_CARD = "timeline-card";
var CLASS_TIMELINE_DATE = "timeline-date";
var CLASS_TIMELINE_TITLE = "timeline-title";
var CLASS_TIMELINE_PREVIEW = "timeline-preview";
var TimelineView = class extends import_obsidian2.ItemView {
constructor(leaf, settings, i18n) {
super(leaf);
__publicField(this, "timeline");
__publicField(this, "settings");
__publicField(this, "i18n");
__publicField(this, "items", []);
__publicField(this, "currentTitle", "");
this.timeline = new Timeline(this.app, settings);
this.settings = settings;
this.i18n = i18n;
}
getViewType() {
return VIEW_TYPE_TIMELINE;
}
getDisplayText() {
return this.i18n.commands.openTimelineView;
}
async onOpen() {
try {
await this.render();
} catch (error) {
new import_obsidian2.Notice(this.i18n.errors.renderFailed);
}
}
async updateFromMetadata(metadataQuery) {
try {
this.currentTitle = `\u{1F50D} ${metadataQuery}`;
this.items = await this.timeline.generateFromMetadata(metadataQuery);
if (this.items.length === 0) {
new import_obsidian2.Notice(this.i18n.errors.noMetadataFiles.replace("{query}", metadataQuery));
return;
}
await this.render();
} catch (error) {
new import_obsidian2.Notice(this.i18n.errors.generateMetadataFailed);
console.error("Error generating timeline from metadata:", error);
}
}
renderTitle(container) {
const titleContainer = container.createEl("div", { cls: CLASS_TIMELINE_HEADER });
titleContainer.createEl("h2", { text: this.currentTitle });
}
groupItemsByYear() {
const itemsByYear = /* @__PURE__ */ new Map();
this.items.forEach((item) => {
var _a;
const year = item.date.getFullYear();
if (!itemsByYear.has(year)) {
itemsByYear.set(year, []);
}
(_a = itemsByYear.get(year)) == null ? void 0 : _a.push(item);
});
return itemsByYear;
}
renderItem(container, item, index, itemsLength) {
const itemClasses = [`${CLASS_TIMELINE_ITEM}${this.getItemClasses(index, itemsLength)}`];
if (item.isMilestone) {
itemClasses.push("timeline-item-milestone");
}
const itemEl = container.createEl("div", {
cls: itemClasses.join(" "),
attr: { style: `--timeline-line-color: ${this.settings.lineColor}` }
});
const card = itemEl.createEl("div", { cls: CLASS_TIMELINE_CARD });
card.createEl("div", {
cls: CLASS_TIMELINE_DATE,
text: item.date.toLocaleDateString(this.settings.language === "zh-CN" ? "zh-CN" : "en-US")
});
const titleEl = card.createEl("div", {
cls: CLASS_TIMELINE_TITLE,
attr: { style: `color: ${item.isMilestone ? this.settings.milestoneCardTextColor : this.settings.cardTextColor} !important` }
});
titleEl.textContent = item.title;
titleEl.dataset.colorSetting = item.isMilestone ? "milestoneCardTextColor" : "cardTextColor";
if (item.preview) {
const previewEl = card.createEl("div", {
cls: CLASS_TIMELINE_PREVIEW,
attr: { style: `color: ${item.isMilestone ? this.settings.milestoneCardTextColor : this.settings.cardTextColor} !important` }
});
previewEl.textContent = item.preview;
previewEl.dataset.colorSetting = item.isMilestone ? "milestoneCardTextColor" : "cardTextColor";
}
titleEl.addEventListener("click", async () => {
const file = this.app.vault.getAbstractFileByPath(item.path);
if (file instanceof import_obsidian2.TFile) {
await this.app.workspace.getLeaf().openFile(file);
}
});
}
getItemClasses(index, itemsLength) {
return (index === 0 ? " first-item" : "") + (index === itemsLength - 1 ? " last-item" : "");
}
renderEra(container, year, items) {
const era = container.createEl("div", { cls: CLASS_TIMELINE_ERA });
era.createEl("div", { cls: CLASS_TIMELINE_ERA_TITLE, text: `${year}` });
items.forEach((item, index) => this.renderItem(era, item, index, items.length));
}
async render() {
const container = this.containerEl.children[1];
container.empty();
if (this.currentTitle) {
this.renderTitle(container);
}
const timelineContainer = container.createEl("div", { cls: CLASS_TIMELINE_CONTAINER });
timelineContainer.createEl("div", { cls: CLASS_TIMELINE_LINE });
const itemsByYear = this.groupItemsByYear();
Array.from(itemsByYear.entries()).sort(([yearA], [yearB]) => yearB - yearA).forEach(([year, items]) => this.renderEra(timelineContainer, year, items));
}
async updateFromFolder(folderPath) {
const folder = this.app.vault.getAbstractFileByPath(folderPath);
if (folder) {
this.currentTitle = `\u{1F4C2} ${folder.name}`;
this.items = await this.timeline.generateFromFolder(folder);
await this.render();
}
}
async updateFromTag(tag) {
try {
this.currentTitle = `\u{1F3F7}\uFE0F ${tag}`;
this.items = await this.timeline.generateFromTag(tag);
if (this.items.length === 0) {
new import_obsidian2.Notice(this.i18n.errors.noTaggedFiles.replace("{tag}", tag));
return;
}
await this.render();
} catch (error) {
new import_obsidian2.Notice("\u751F\u6210\u65F6\u95F4\u8F74\u5931\u8D25");
throw error;
}
}
async updateFromFile(filePath) {
try {
const file = this.app.vault.getAbstractFileByPath(filePath);
if (file && file instanceof import_obsidian2.TFile) {
this.currentTitle = `\u{1F4C4} ${file.basename}`;
this.items = await this.timeline.generateFromFileLinks(file);
if (this.items.length === 0) {
new import_obsidian2.Notice(this.i18n.errors.noFileLinks.replace("{filename}", file.basename));
return;
}
await this.render();
}
} catch (error) {
new import_obsidian2.Notice(this.i18n.errors.generateFileFailed);
console.error(error);
}
}
getIcon() {
return "history";
}
};
// src/FolderSuggest.ts
var import_obsidian3 = require("obsidian");
var FolderSuggestModal = class extends import_obsidian3.FuzzySuggestModal {
constructor(app, settings) {
super(app);
this.settings = settings;
__publicField(this, "resolve");
this.setPlaceholder(this.settings.language === "zh-CN" ? "\u9009\u62E9\u4E00\u4E2A\u6587\u4EF6\u5939" : "Select a folder");
}
getItems() {
const folders = [];
const shouldFilterFolder = (folderPath) => {
return folderPath === "timelines" || folderPath.startsWith("timelines/");
};
const pushFolder = (folder) => {
if (!shouldFilterFolder(folder.path)) {
folders.push(folder);
folder.children.filter((child) => child instanceof import_obsidian3.TFolder).forEach(pushFolder);
}
};
const rootFolder = this.app.vault.getRoot();
pushFolder(rootFolder);
return folders;
}
getItemText(folder) {
return folder.path;
}
onChooseItem(folder) {
this.resolve(folder.path);
this.close();
}
async openAndGetValue() {
return new Promise((resolve) => {
this.resolve = resolve;
this.open();
}).then((value) => {
if (value === void 0) {
return null;
}
return value;
});
}
};
// src/TagSuggest.ts
var import_obsidian4 = require("obsidian");
var TagSuggestModal = class extends import_obsidian4.FuzzySuggestModal {
constructor(app, settings) {
super(app);
this.settings = settings;
__publicField(this, "resolve");
this.setPlaceholder(this.settings.language === "zh-CN" ? "\u9009\u62E9\u4E00\u4E2A\u6807\u7B7E" : "Select a tag");
}
getItems() {
const tags = /* @__PURE__ */ new Set();
const files = this.app.vault.getMarkdownFiles();
files.forEach((file) => {
var _a, _b;
const cache = this.app.metadataCache.getFileCache(file);
(_a = cache == null ? void 0 : cache.tags) == null ? void 0 : _a.forEach((tag) => {
tags.add(tag.tag.replace("#", ""));
});
const frontmatterTags = (_b = cache == null ? void 0 : cache.frontmatter) == null ? void 0 : _b.tags;
if (Array.isArray(frontmatterTags)) {
frontmatterTags.forEach((tag) => {
tags.add(tag.replace("#", ""));
});
} else if (typeof frontmatterTags === "string") {
const normalizedTags = frontmatterTags.replace(/[,;]/g, " ").trim();
normalizedTags.split(/\s+/).forEach((tag) => {
if (tag) {
tags.add(tag.trim().replace("#", ""));
}
});
}
});
const tagArray = Array.from(tags);
console.log("\u53EF\u7528\u7684\u6807\u7B7E:", tagArray);
return tagArray;
}
getItemText(tag) {
return tag;
}
onChooseItem(tag) {
console.log("\u9009\u62E9\u7684\u6807\u7B7E:", tag);
this.resolve(tag);
this.close();
}
async openAndGetValue() {
return new Promise((resolve) => {
this.resolve = resolve;
this.open();
});
}
};
// src/FileSuggest.ts
var import_obsidian5 = require("obsidian");
var FileSuggestModal = class extends import_obsidian5.FuzzySuggestModal {
constructor(app, settings) {
super(app);
this.settings = settings;
__publicField(this, "resolve");
this.setPlaceholder(this.settings.language === "zh-CN" ? "\u9009\u62E9\u4E00\u4E2AMarkdown\u6587\u4EF6" : "Select a Markdown file");
}
async openAndGetValue() {
return new Promise((resolve) => {
this.resolve = resolve;
this.open();
});
}
getItems() {
return this.app.vault.getMarkdownFiles().filter(
(file) => !file.path.startsWith("timelines/") && file.path !== "timelines"
);
}
getItemText(file) {
return file.path;
}
onChooseItem(file) {
this.resolve(file);
this.close();
}
};
// src/TimelineSettings.ts
function getCssVariable(name) {
return `var(${name})`;
}
var DEFAULT_SETTINGS = {
lineWidth: 2,
lineColor: getCssVariable("--interactive-accent"),
itemSpacing: 30,
cardBackground: getCssVariable("--background-primary-alt"),
cardTextColor: getCssVariable("--text-normal"),
cardBorderColor: getCssVariable("--background-modifier-border"),
milestoneCardBackground: "#ffffcc",
milestoneCardTextColor: getCssVariable("--text-normal"),
milestoneCardBorderColor: "#f0e68c",
animationDuration: 200,
dateAttribute: "created",
// 默认使用 frontmatter 中的 date 属性作为时间轴排序依据
fileNamePrefix: "",
fileNameSuffix: "",
defaultPosition: "right",
// 默认在右侧边栏
language: "zh-CN",
// 默认使用中文
milestoneAttribute: "",
// 默认不使用里程碑属性
milestoneValue: ""
// 默认值为空
};
// src/main.ts
var import_obsidian7 = require("obsidian");
var TimelinePlugin = class extends import_obsidian6.Plugin {
constructor() {
super(...arguments);
__publicField(this, "settings");
__publicField(this, "i18n");
}
async onload() {
await this.loadSettings();
this.i18n = this.settings.language === "zh-CN" ? zhCN : enUS;
this.addSettingTab(new TimelineSettingTab(this.app, this));
console.log("\u52A0\u8F7D Timeline \u63D2\u4EF6");
try {
this.registerView(
VIEW_TYPE_TIMELINE,
(leaf) => new TimelineView(leaf, this.settings, this.i18n)
);
this.registerEvent(
this.app.workspace.on("file-menu", (menu, abstractFile) => {
var _a;
if (abstractFile instanceof import_obsidian6.TFile && abstractFile.path.startsWith("timelines/") && abstractFile.extension === "md") {
const cache = this.app.metadataCache.getFileCache(abstractFile);
const generatedFrom = (_a = cache == null ? void 0 : cache.frontmatter) == null ? void 0 : _a.generated_from;
if (generatedFrom) {
const [type, ...valueParts] = generatedFrom.split(":");
const value = valueParts.join(":");
menu.addItem((item) => {
item.setTitle(this.i18n.commands.openTimelineView).setIcon("clock").onClick(async () => {
await this.activateView(this.settings.defaultPosition);
const view = this.getTimelineView();
if (view) {
if (type === "folder") {
await view.updateFromFolder(value);
} else if (type === "tag") {
await view.updateFromTag(value);
} else if (type === "file") {
await view.updateFromFile(value);
} else if (type === "metadata") {
await view.updateFromMetadata(value);
}
}
});
});
}
}
})
);
this.addCommand({
id: "generate-timeline-view-from-folder",
name: this.i18n.commands.generateFromFolder,
callback: async () => {
try {
const folderPath = await this.selectFolder();
if (folderPath) {
await this.activateView(this.settings.defaultPosition);
const view = this.getTimelineView();
if (view) {
await view.updateFromFolder(folderPath);
}
}
} catch (error) {
console.error("\u751F\u6210\u6587\u4EF6\u5939\u65F6\u95F4\u8F74\u89C6\u56FE\u65F6\u51FA\u9519:", error);
}
}
});
this.addCommand({
id: "generate-timeline-file-from-folder",
name: this.i18n.commands.generateFileFromFolder,
callback: async () => {
try {
const folderPath = await this.selectFolder();
if (folderPath) {
const folder = this.app.vault.getAbstractFileByPath(folderPath);
if (!(folder instanceof import_obsidian7.TFolder)) {
throw new Error(`Invalid folder path: ${folderPath}`);
}
const timeline = new Timeline(this.app, this.settings);
const items = await timeline.generateFromFolder(folder);
const content = await timeline.generateTimelineMarkdown(items, `Timeline - ${folderPath}`, { type: "folder", value: folderPath });
const { folderPath: targetFolder, fileName } = await this.createNestedFolders(folderPath);
const finalFileName = this.generateFileName(fileName || folderPath.split("/").pop() || "");
const filePath = `${targetFolder}/${finalFileName}.md`;
const existingFile = this.app.vault.getAbstractFileByPath(filePath);
if (existingFile) {
await this.app.vault.delete(existingFile);
}
const file = await this.app.vault.create(filePath, content);
await this.app.workspace.getLeaf().openFile(file);
}
} catch (error) {
console.error("\u751F\u6210\u6587\u4EF6\u5939\u65F6\u95F4\u8F74\u6587\u4EF6\u65F6\u51FA\u9519:", error);
}
}
});
this.addCommand({
id: "generate-timeline-view-from-tag",
name: this.i18n.commands.generateFromTag,
callback: async () => {
try {
const tag = await this.selectTag();
if (tag) {
await this.activateView(this.settings.defaultPosition);
const view = this.getTimelineView();
if (view) {
await view.updateFromTag(tag);
}
}
} catch (error) {
console.error("\u751F\u6210\u6807\u7B7E\u65F6\u95F4\u8F74\u89C6\u56FE\u65F6\u51FA\u9519:", error);
}
}
});
this.addCommand({
id: "generate-timeline-file-from-tag",
name: this.i18n.commands.generateFileFromTag,
callback: async () => {
try {
const tag = await this.selectTag();
if (tag) {
await this.generateTimelineFileFromTag(tag);
}
} catch (error) {
console.error("\u751F\u6210\u6807\u7B7E\u65F6\u95F4\u8F74\u6587\u4EF6\u65F6\u51FA\u9519:", error);
}
}
});
this.addCommand({
id: "generate-timeline-view-from-file-links",
name: this.i18n.commands.generateFromFileLinks,
callback: async () => {
try {
const file = this.app.workspace.getActiveFile();
if (!file || !(file instanceof import_obsidian6.TFile) || file.extension !== "md") {
new import_obsidian6.Notice(this.i18n.errors.generateFileFailed);
return;
}
const cache = this.app.metadataCache.getFileCache(file);
if (!cache || !cache.links || cache.links.length === 0) {
new import_obsidian6.Notice(this.i18n.errors.noFileLinks.replace("{filename}", file.basename));
return;
}
await this.activateView(this.settings.defaultPosition);
const view = this.getTimelineView();
if (view) {
const timeline = new Timeline(this.app, this.settings);
const items = await timeline.generateFromFileLinks(file);
view.items = items;
view.currentTitle = `\u{1F517} ${file.basename} `;
await view.render();
}
} catch (error) {
console.error("\u4ECE\u6587\u4EF6\u94FE\u63A5\u751F\u6210\u65F6\u95F4\u8F74\u89C6\u56FE\u65F6\u51FA\u9519:", error);
new import_obsidian6.Notice(this.i18n.errors.generateFileFailed);
}
}
});
this.addCommand({
id: "generate-timeline-file-from-file-links",
name: this.i18n.commands.generateFileFromFileLinks,
callback: async () => {
try {
const file = this.app.workspace.getActiveFile();
if (!file || !(file instanceof import_obsidian6.TFile) || file.extension !== "md") {
new import_obsidian6.Notice(this.i18n.errors.generateFileFailed);
return;
}
const cache = this.app.metadataCache.getFileCache(file);
if (!cache || !cache.links || cache.links.length === 0) {
new import_obsidian6.Notice(this.i18n.errors.noFileLinks.replace("{filename}", file.basename));
return;
}
const timeline = new Timeline(this.app, this.settings);
const items = await timeline.generateFromFileLinks(file);
const content = await timeline.generateTimelineMarkdown(
items,
`Timeline - Links in ${file.basename}`,
{ type: "file", value: file.path }
);
const { folderPath } = await this.createNestedFolders("linked-files");
const finalFileName = this.generateFileName(file.basename);
const filePath = `${folderPath}/${finalFileName}.md`;
const existingFile = this.app.vault.getAbstractFileByPath(filePath);
if (existingFile) {
await this.app.vault.delete(existingFile);
}
const newFile = await this.app.vault.create(filePath, content);
await this.app.workspace.getLeaf().openFile(newFile);
} catch (error) {
console.error("\u4ECE\u6587\u4EF6\u94FE\u63A5\u751F\u6210\u65F6\u95F4\u8F74\u6587\u4EF6\u65F6\u51FA\u9519:", error);
new import_obsidian6.Notice(this.i18n.errors.generateFileFailed);
}
}
});
this.addCommand({
id: "generate-timeline-view-from-metadata",
name: this.i18n.commands.generateFromMetadata,
callback: async () => {
try {
const metadataQuery = await this.selectMetadataString();
if (metadataQuery) {
await this.activateView(this.settings.defaultPosition);
const view = this.getTimelineView();
if (view) {
await view.updateFromMetadata(metadataQuery);
}
}
} catch (error) {
console.error("\u4ECE\u5143\u6570\u636E\u751F\u6210\u65F6\u95F4\u8F74\u89C6\u56FE\u65F6\u51FA\u9519:", error);
new import_obsidian6.Notice(this.i18n.errors.generateMetadataFailed);
}
}
});
this.addCommand({
id: "generate-timeline-file-from-metadata",
name: this.i18n.commands.generateFileFromMetadata,
callback: async () => {
try {
const metadataQuery = await this.selectMetadataString();
if (metadataQuery) {
const timeline = new Timeline(this.app, this.settings);
const items = await timeline.generateFromMetadata(metadataQuery);
const content = await timeline.generateTimelineMarkdown(
items,
`Timeline - Metadata: ${metadataQuery}`,
{ type: "metadata", value: metadataQuery }
);
const { folderPath } = await this.createNestedFolders("metadata-search");
const safeBaseName = metadataQuery.substring(0, 30).replace(/[^a-zA-Z0-9_\-]+/g, "_") || "metadata_query";
const finalFileName = this.generateFileName(safeBaseName);
const filePath = `${folderPath}/${finalFileName}.md`;
const existingFile = this.app.vault.getAbstractFileByPath(filePath);
if (existingFile) {
await this.app.vault.delete(existingFile);
}
const newFile = await this.app.vault.create(filePath, content);
await this.app.workspace.getLeaf().openFile(newFile);
}
} catch (error) {
console.error("\u4ECE\u5143\u6570\u636E\u751F\u6210\u65F6\u95F4\u8F74\u6587\u4EF6\u65F6\u51FA\u9519:", error);
new import_obsidian6.Notice(this.i18n.errors.generateMetadataFailed);
}
}
});
this.registerEvent(
this.app.workspace.on("file-open", async (file) => {
var _a;
if (file instanceof import_obsidian6.TFile && file.path.startsWith("timelines/") && file.extension === "md") {
const cache = this.app.metadataCache.getFileCache(file);
const generatedFrom = (_a = cache == null ? void 0 : cache.frontmatter) == null ? void 0 : _a.generated_from;
if (generatedFrom) {
const [type, ...valueParts] = generatedFrom.split(":");
const value = valueParts.join(":");
const timeline = new Timeline(this.app, this.settings);
let items = [];
if (type === "folder") {
const folder = this.app.vault.getAbstractFileByPath(value);
if (folder instanceof import_obsidian7.TFolder) {
items = await timeline.generateFromFolder(folder);
}
} else if (type === "tag") {
items = await timeline.generateFromTag(value);
} else if (type === "file") {
const targetFile = this.app.vault.getAbstractFileByPath(value);
if (targetFile instanceof import_obsidian6.TFile) {
items = await timeline.generateFromFileLinks(targetFile);
}
} else if (type === "metadata") {
items = await timeline.generateFromMetadata(value);
}
const content = await timeline.generateTimelineMarkdown(items, `Timeline - ${value}`, { type, value });
await this.app.vault.modify(file, content);
}
}
})
);
} catch (error) {
console.error("\u63D2\u4EF6\u52A0\u8F7D\u65F6\u51FA\u9519:", error);
}
}
async selectFolder() {
const modal = new FolderSuggestModal(this.app, this.settings);
return await modal.openAndGetValue();
}
async selectFile() {
const modal = new FileSuggestModal(this.app, this.settings);
return await modal.openAndGetValue();
}
async selectTag() {
const modal = new TagSuggestModal(this.app, this.settings);
return await modal.openAndGetValue();
}
async selectMetadataString() {
const modal = new MetadataInputModal(this.app, this);
return await modal.openAndGetValue();
}
async activateView(position = this.settings.defaultPosition) {
const { workspace } = this.app;
const leaves = workspace.getLeavesOfType(VIEW_TYPE_TIMELINE);
if (leaves.length > 0) {
workspace.revealLeaf(leaves[0]);
return leaves[0];
}
const newLeaf = position === "left" ? workspace.getLeftLeaf(false) : workspace.getRightLeaf(false);
if (!newLeaf) {
new import_obsidian6.Notice("\u65E0\u6CD5\u521B\u5EFA\u65F6\u95F4\u8F74\u89C6\u56FE\uFF1A\u8BF7\u68C0\u67E5\u4FA7\u8FB9\u680F\u7A7A\u95F4");
return null;
}
await newLeaf.setViewState({ type: VIEW_TYPE_TIMELINE });
workspace.revealLeaf(newLeaf);
return newLeaf;
}
getTimelineView() {
const leaves = this.app.workspace.getLeavesOfType(VIEW_TYPE_TIMELINE);
if (leaves.length === 0) {
return null;
}
return leaves[0].view;
}
async loadSettings() {
this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());
this.updateStyles();
}
async saveSettings() {
await this.saveData(this.settings);
this.updateStyles();
}
updateStyles() {
var _a;
const style = document.createElement("style");
style.id = "timeline-custom-styles";
style.textContent = `
.timeline-line {
width: ${this.settings.lineWidth}px !important;
background: ${this.settings.lineColor} !important;
}
.timeline-item::after {
background: var(--timeline-line-color, ${this.settings.lineColor}) !important;
}
.timeline-item {
margin: ${this.settings.itemSpacing}px 0 !important;
}
.timeline-card {
background: ${this.settings.cardBackground} !important;
color: ${this.settings.cardTextColor} !important;
border: 1px solid ${this.settings.cardBorderColor} !important;
transition: transform ${this.settings.animationDuration}ms !important;
}
.timeline-item-milestone .timeline-card {
background: ${this.settings.milestoneCardBackground} !important;
color: ${this.settings.milestoneCardTextColor} !important;
border: 1px solid ${this.settings.milestoneCardBorderColor} !important;
}
[data-color-setting="cardTextColor"] {
color: ${this.settings.cardTextColor} !important;
}
[data-color-setting="milestoneCardTextColor"] {
color: ${this.settings.milestoneCardTextColor} !important;
}
.timeline-date {
color: ${this.settings.cardTextColor} !important;
}
.timeline-item-milestone .timeline-date {
color: ${this.settings.milestoneCardTextColor} !important;
}
.timeline-era-title {
color: var(--timeline-line-color, ${this.settings.lineColor}) !important;
}
`;
(_a = document.getElementById("timeline-custom-styles")) == null ? void 0 : _a.remove();
document.head.appendChild(style);
}
async createNestedFolders(tagPath) {
const rootPath = "timelines";
if (!this.app.vault.getAbstractFileByPath(rootPath)) {
try {
await this.app.vault.createFolder(rootPath);
} catch (error) {
new import_obsidian6.Notice(`\u521B\u5EFA\u6839\u76EE\u5F55\u5931\u8D25: ${rootPath}`);
throw error;
}
}
const parts = tagPath.split("/");
const fileName = parts.pop();
let currentPath = rootPath;
for (const part of parts) {
currentPath = (0, import_obsidian6.normalizePath)(`${currentPath}/${part}`);
const folder = this.app.vault.getAbstractFileByPath(currentPath);
if (!folder) {
try {
await this.app.vault.createFolder(currentPath);
} catch (error) {
new import_obsidian6.Notice(`\u521B\u5EFA\u6587\u4EF6\u5939\u5931\u8D25: ${currentPath}`);
throw error;
}
}
}
return { folderPath: currentPath, fileName };
}
generateFileName(baseName) {
const prefix = this.settings.fileNamePrefix || "";
const suffix = this.settings.fileNameSuffix || "";
return `${prefix}${baseName}${suffix}`;
}
async generateTimelineFileFromTag(tag) {
try {
const tagPath = tag.replace("#", "");
const { folderPath, fileName } = await this.createNestedFolders(tagPath);
const finalFileName = this.generateFileName(fileName || "");
const filePath = `${folderPath}/${finalFileName}.md`;
const existingFile = this.app.vault.getAbstractFileByPath(filePath);
if (existingFile) {
await this.app.vault.delete(existingFile);
}
const timeline = new Timeline(this.app, this.settings);
const items = await timeline.generateFromTag(tag);
const content = await timeline.generateTimelineMarkdown(items, `Timeline - ${tag}`, { type: "tag", value: tag });
const file = await this.app.vault.create(filePath, content);
await this.app.workspace.getLeaf().openFile(file);
} catch (error) {
console.error("\u751F\u6210\u6807\u7B7E\u65F6\u95F4\u8F74\u6587\u4EF6\u65F6\u51FA\u9519:", error);
throw error;
}
}
};
var MetadataInputModal = class extends import_obsidian6.Modal {
constructor(app, plugin) {
super(app);
__publicField(this, "plugin");
// Add plugin reference
__publicField(this, "value", "");
__publicField(this, "resolvePromise");
__publicField(this, "inputEl");
this.plugin = plugin;
}
async openAndGetValue() {
return new Promise((resolve) => {
this.resolvePromise = resolve;
this.open();
});
}
onOpen() {
const { contentEl } = this;
contentEl.empty();
contentEl.addClass("metadata-input-modal");
contentEl.createEl("h2", { text: this.plugin.i18n.modal.metadataInputTitle });
new import_obsidian6.Setting(contentEl).setName(this.plugin.i18n.modal.metadataQueryName).setDesc(this.plugin.i18n.modal.metadataQueryDesc).addText((text) => {
this.inputEl = text;
text.setPlaceholder(this.plugin.i18n.modal.metadataInputPlaceholder).onChange((value) => this.value = value.trim());
text.inputEl.style.width = "100%";
text.inputEl.addEventListener("keydown", (evt) => {
if (evt.key === "Enter") {
evt.preventDefault();
this.submit();
}
});
});
new import_obsidian6.Setting(contentEl).addButton((button) => button.setButtonText(this.plugin.i18n.modal.submitButton).setCta().onClick(() => this.submit())).addButton((button) => button.setButtonText(this.plugin.i18n.modal.cancelButton).onClick(() => this.closeAndResolve(null)));
setTimeout(() => {
if (this.inputEl && this.inputEl.inputEl) {
this.inputEl.inputEl.focus();
}
}, 50);
}
submit() {
if (this.value) {
this.closeAndResolve(this.value);
} else {
new import_obsidian6.Notice(this.plugin.i18n.modal.emptyInputNotice);
}
}
closeAndResolve(value) {
if (this.resolvePromise) {
this.resolvePromise(value);
}
this.close();
}
onClose() {
const { contentEl } = this;
contentEl.empty();
}
};
var TimelineSettingTab = class extends import_obsidian6.PluginSettingTab {
constructor(app, plugin) {
super(app, plugin);
__publicField(this, "plugin");
this.plugin = plugin;
}
display() {
const { containerEl } = this;
containerEl.empty();
new import_obsidian6.Setting(containerEl).setName(this.plugin.i18n.settings.resetSettings).setDesc(this.plugin.i18n.settings.resetSettingsDesc).addButton((button) => button.setButtonText(this.plugin.i18n.settings.resetSettingsButton).onClick(async () => {
this.plugin.settings = Object.assign({}, DEFAULT_SETTINGS);
await this.plugin.saveSettings();
this.display();
}));
new import_obsidian6.Setting(containerEl).setName(this.plugin.i18n.settings.language).setDesc(this.plugin.i18n.settings.languageDesc).addDropdown((dropdown) => dropdown.addOption("zh-CN", "\u4E2D\u6587").addOption("en-US", "English").setValue(this.plugin.settings.language).onChange(async (value) => {
this.plugin.settings.language = value;
this.plugin.i18n = value === "zh-CN" ? zhCN : enUS;
await this.plugin.saveSettings();
this.display();
}));
new import_obsidian6.Setting(containerEl).setName(this.plugin.i18n.settings.milestoneAttribute).setDesc(this.plugin.i18n.settings.milestoneAttributeDesc).addText((text) => text.setPlaceholder("milestone").setValue(this.plugin.settings.milestoneAttribute).onChange(async (value) => {
this.plugin.settings.milestoneAttribute = value;
await this.plugin.saveSettings();
}));
new import_obsidian6.Setting(containerEl).setName(this.plugin.i18n.settings.milestoneValue).setDesc(this.plugin.i18n.settings.milestoneValueDesc).addText((text) => text.setPlaceholder("true or 1 (leave empty to match any value)").setValue(this.plugin.settings.milestoneValue).onChange(async (value) => {
this.plugin.settings.milestoneValue = value;
await this.plugin.saveSettings();
}));
new import_obsidian6.Setting(containerEl).setName(this.plugin.i18n.settings.lineWidth).setDesc(this.plugin.i18n.settings.lineWidthDesc).addSlider((slider) => slider.setLimits(1, 10, 1).setValue(this.plugin.settings.lineWidth).onChange(async (value) => {
this.plugin.settings.lineWidth = value;
await this.plugin.saveSettings();
}));
new import_obsidian6.Setting(containerEl).setName(this.plugin.i18n.settings.lineColor).setDesc(this.plugin.i18n.settings.lineColorDesc).addColorPicker((color) => color.setValue(this.plugin.settings.lineColor).onChange(async (value) => {
this.plugin.settings.lineColor = value;
await this.plugin.saveSettings();
})).addText((text) => text.setPlaceholder(this.plugin.i18n.settings.colorPickerPlaceholder).setValue("").onChange(async (value) => {
if (value) {
this.plugin.settings.lineColor = value;
await this.plugin.saveSettings();
}
}));
new import_obsidian6.Setting(containerEl).setName(this.plugin.i18n.settings.itemSpacing).setDesc(this.plugin.i18n.settings.itemSpacingDesc).addSlider((slider) => slider.setLimits(10, 100, 5).setValue(this.plugin.settings.itemSpacing).onChange(async (value) => {
this.plugin.settings.itemSpacing = value;
await this.plugin.saveSettings();
}));
new import_obsidian6.Setting(containerEl).setName(this.plugin.i18n.settings.cardBackground).setDesc(this.plugin.i18n.settings.cardBackgroundDesc).addColorPicker(
(color) => color.setValue(this.plugin.settings.cardBackground).onChange(async (value) => {
this.plugin.settings.cardBackground = value;
await this.plugin.saveSettings();
})
).setTooltip(this.plugin.i18n.settings.colorPickerPlaceholder);
new import_obsidian6.Setting(containerEl).setName(this.plugin.i18n.settings.cardTextColor).setDesc(this.plugin.i18n.settings.cardTextColorDesc).addColorPicker(
(color) => color.setValue(this.plugin.settings.cardTextColor).onChange(async (value) => {
this.plugin.settings.cardTextColor = value;
await this.plugin.saveSettings();
})
);
new import_obsidian6.Setting(containerEl).setName(this.plugin.i18n.settings.cardBorderColor).setDesc(this.plugin.i18n.settings.cardBorderColorDesc).addColorPicker(
(color) => color.setValue(this.plugin.settings.cardBorderColor).onChange(async (value) => {
this.plugin.settings.cardBorderColor = value;
await this.plugin.saveSettings();
})
);
new import_obsidian6.Setting(containerEl).setName(this.plugin.i18n.settings.milestoneCardBackground).setDesc(this.plugin.i18n.settings.milestoneCardBackgroundDesc).addColorPicker(
(color) => color.setValue(this.plugin.settings.milestoneCardBackground).onChange(async (value) => {
this.plugin.settings.milestoneCardBackground = value;
await this.plugin.saveSettings();
})
);
new import_obsidian6.Setting(containerEl).setName(this.plugin.i18n.settings.milestoneCardTextColor).setDesc(this.plugin.i18n.settings.milestoneCardTextColorDesc).addColorPicker(
(color) => color.setValue(this.plugin.settings.milestoneCardTextColor).onChange(async (value) => {
this.plugin.settings.milestoneCardTextColor = value;
await this.plugin.saveSettings();
})
);
new import_obsidian6.Setting(containerEl).setName(this.plugin.i18n.settings.milestoneCardBorderColor).setDesc(this.plugin.i18n.settings.milestoneCardBorderColorDesc).addColorPicker(
(color) => color.setValue(this.plugin.settings.milestoneCardBorderColor).onChange(async (value) => {
this.plugin.settings.milestoneCardBorderColor = value;
await this.plugin.saveSettings();
})
);
new import_obsidian6.Setting(containerEl).setName(this.plugin.i18n.settings.animationDuration).setDesc(this.plugin.i18n.settings.animationDurationDesc).addSlider((slider) => slider.setLimits(0, 1e3, 50).setValue(this.plugin.settings.animationDuration).onChange(async (value) => {
this.plugin.settings.animationDuration = value;
await this.plugin.saveSettings();
}));
new import_obsidian6.Setting(containerEl).setName(this.plugin.i18n.settings.dateAttribute).setDesc(this.plugin.i18n.settings.dateAttributeDesc).addText((text) => text.setPlaceholder("created").setValue(this.plugin.settings.dateAttribute).onChange(async (value) => {
this.plugin.settings.dateAttribute = value;
await this.plugin.saveSettings();
}));
new import_obsidian6.Setting(containerEl).setName(this.plugin.i18n.settings.fileNamePrefix).setDesc(this.plugin.i18n.settings.fileNamePrefixDesc).addText((text) => text.setPlaceholder("").setValue(this.plugin.settings.fileNamePrefix).onChange(async (value) => {
this.plugin.settings.fileNamePrefix = value;
await this.plugin.saveSettings();
}));
new import_obsidian6.Setting(containerEl).setName(this.plugin.i18n.settings.fileNameSuffix).setDesc(this.plugin.i18n.settings.fileNameSuffixDesc).addText((text) => text.setPlaceholder("").setValue(this.plugin.settings.fileNameSuffix).onChange(async (value) => {
this.plugin.settings.fileNameSuffix = value;
await this.plugin.saveSettings();
}));
new import_obsidian6.Setting(containerEl).setName(this.plugin.i18n.settings.defaultPosition).setDesc(this.plugin.i18n.settings.defaultPositionDesc).addDropdown(
(dropdown) => dropdown.addOption("left", this.plugin.i18n.settings.leftSidebar).addOption("right", this.plugin.i18n.settings.rightSidebar).setValue(this.plugin.settings.defaultPosition).onChange(async (value) => {
this.plugin.settings.defaultPosition = value;
await this.plugin.saveSettings();
})
);
}
};
/* nosourcemap */