@real1ty-obsidian-plugins/utils 2.24.0 → 2.26.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/whats-new-modal.d.ts +11 -4
- package/dist/components/whats-new-modal.d.ts.map +1 -1
- package/dist/components/whats-new-modal.js +66 -35
- package/dist/components/whats-new-modal.js.map +1 -1
- package/dist/file/frontmatter-propagation.d.ts +0 -8
- package/dist/file/frontmatter-propagation.d.ts.map +1 -1
- package/dist/file/frontmatter-propagation.js +0 -14
- package/dist/file/frontmatter-propagation.js.map +1 -1
- package/package.json +1 -1
- package/src/components/whats-new-modal.ts +77 -39
- package/src/file/frontmatter-propagation.ts +0 -25
|
@@ -22,15 +22,16 @@ export interface WhatsNewModalConfig {
|
|
|
22
22
|
/**
|
|
23
23
|
* URL to support/donate page.
|
|
24
24
|
*/
|
|
25
|
-
support
|
|
25
|
+
support: string;
|
|
26
26
|
/**
|
|
27
27
|
* URL to full changelog page.
|
|
28
28
|
*/
|
|
29
|
-
changelog
|
|
29
|
+
changelog: string;
|
|
30
30
|
/**
|
|
31
|
-
* URL to
|
|
31
|
+
* Base URL for documentation (used to resolve relative links in changelog).
|
|
32
|
+
* Example: "https://docs.example.com" or "https://docs.example.com/"
|
|
32
33
|
*/
|
|
33
|
-
documentation
|
|
34
|
+
documentation: string;
|
|
34
35
|
};
|
|
35
36
|
}
|
|
36
37
|
/**
|
|
@@ -51,6 +52,12 @@ export declare class WhatsNewModal extends Modal {
|
|
|
51
52
|
* Helper to add CSS class to an element.
|
|
52
53
|
*/
|
|
53
54
|
private addCls;
|
|
55
|
+
/**
|
|
56
|
+
* Makes external links in rendered markdown clickable by adding click handlers.
|
|
57
|
+
* Handles both absolute URLs (http/https) and relative URLs (starting with /).
|
|
58
|
+
* Relative URLs are resolved against the documentation base URL.
|
|
59
|
+
*/
|
|
60
|
+
private makeExternalLinksClickable;
|
|
54
61
|
onOpen(): Promise<void>;
|
|
55
62
|
onClose(): void;
|
|
56
63
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"whats-new-modal.d.ts","sourceRoot":"","sources":["../../src/components/whats-new-modal.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAC5C,OAAO,EAAoB,KAAK,EAAE,MAAM,UAAU,CAAC;AAGnD,MAAM,WAAW,mBAAmB;IACnC;;;OAGG;IACH,SAAS,EAAE,MAAM,CAAC;IAElB;;;OAGG;IACH,UAAU,EAAE,MAAM,CAAC;IAEnB;;OAEG;IACH,gBAAgB,EAAE,MAAM,CAAC;IAEzB;;OAEG;IACH,KAAK,EAAE;QACN;;WAEG;QACH,OAAO,
|
|
1
|
+
{"version":3,"file":"whats-new-modal.d.ts","sourceRoot":"","sources":["../../src/components/whats-new-modal.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAC5C,OAAO,EAAoB,KAAK,EAAE,MAAM,UAAU,CAAC;AAGnD,MAAM,WAAW,mBAAmB;IACnC;;;OAGG;IACH,SAAS,EAAE,MAAM,CAAC;IAElB;;;OAGG;IACH,UAAU,EAAE,MAAM,CAAC;IAEnB;;OAEG;IACH,gBAAgB,EAAE,MAAM,CAAC;IAEzB;;OAEG;IACH,KAAK,EAAE;QACN;;WAEG;QACH,OAAO,EAAE,MAAM,CAAC;QAEhB;;WAEG;QACH,SAAS,EAAE,MAAM,CAAC;QAElB;;;WAGG;QACH,aAAa,EAAE,MAAM,CAAC;KACtB,CAAC;CACF;AAED;;;GAGG;AACH,qBAAa,aAAc,SAAQ,KAAK;IAGtC,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,MAAM;IACd,OAAO,CAAC,WAAW;IACnB,OAAO,CAAC,SAAS;gBAJjB,GAAG,EAAE,GAAG,EACA,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,mBAAmB,EAC3B,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM;IAK1B;;OAEG;IACH,OAAO,CAAC,GAAG;IAIX;;OAEG;IACH,OAAO,CAAC,MAAM;IAId;;;;OAIG;IACH,OAAO,CAAC,0BAA0B;IAmC5B,MAAM;IAgGZ,OAAO;CAGP"}
|
|
@@ -25,6 +25,41 @@ export class WhatsNewModal extends Modal {
|
|
|
25
25
|
addCls(el, suffix) {
|
|
26
26
|
el.classList.add(this.cls(suffix));
|
|
27
27
|
}
|
|
28
|
+
/**
|
|
29
|
+
* Makes external links in rendered markdown clickable by adding click handlers.
|
|
30
|
+
* Handles both absolute URLs (http/https) and relative URLs (starting with /).
|
|
31
|
+
* Relative URLs are resolved against the documentation base URL.
|
|
32
|
+
*/
|
|
33
|
+
makeExternalLinksClickable(container) {
|
|
34
|
+
const links = container.querySelectorAll("a[href]");
|
|
35
|
+
// Convert NodeList to Array for iteration
|
|
36
|
+
Array.from(links).forEach((link) => {
|
|
37
|
+
const href = link.getAttribute("href");
|
|
38
|
+
if (!href)
|
|
39
|
+
return;
|
|
40
|
+
let finalUrl = null;
|
|
41
|
+
// Handle absolute HTTP(S) links
|
|
42
|
+
if (href.startsWith("http://") || href.startsWith("https://")) {
|
|
43
|
+
finalUrl = href;
|
|
44
|
+
}
|
|
45
|
+
// Handle relative links (starting with /)
|
|
46
|
+
else if (href.startsWith("/")) {
|
|
47
|
+
// Get base documentation URL and ensure proper slash handling
|
|
48
|
+
const baseUrl = this.config.links.documentation;
|
|
49
|
+
const normalizedBase = baseUrl.endsWith("/") ? baseUrl.slice(0, -1) : baseUrl;
|
|
50
|
+
finalUrl = `${normalizedBase}${href}`;
|
|
51
|
+
}
|
|
52
|
+
// Add click handler for external links
|
|
53
|
+
if (finalUrl) {
|
|
54
|
+
link.addEventListener("click", (event) => {
|
|
55
|
+
event.preventDefault();
|
|
56
|
+
window.open(finalUrl, "_blank");
|
|
57
|
+
});
|
|
58
|
+
// Add visual indicator that it's an external link
|
|
59
|
+
link.classList.add("external-link");
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
}
|
|
28
63
|
onOpen() {
|
|
29
64
|
return __awaiter(this, void 0, void 0, function* () {
|
|
30
65
|
const { contentEl } = this;
|
|
@@ -39,23 +74,21 @@ export class WhatsNewModal extends Modal {
|
|
|
39
74
|
text: `Changes since v${this.fromVersion}`,
|
|
40
75
|
cls: this.cls("whats-new-subtitle"),
|
|
41
76
|
});
|
|
42
|
-
// Support section
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
contentEl.createEl("hr");
|
|
58
|
-
}
|
|
77
|
+
// Support section
|
|
78
|
+
const supportSection = contentEl.createDiv({
|
|
79
|
+
cls: this.cls("whats-new-support"),
|
|
80
|
+
});
|
|
81
|
+
supportSection.createEl("h3", { text: "Support My Work" });
|
|
82
|
+
const supportText = supportSection.createEl("p");
|
|
83
|
+
supportText.createSpan({ text: "If you enjoy using this plugin, please consider " });
|
|
84
|
+
supportText.createEl("a", {
|
|
85
|
+
text: "supporting my work",
|
|
86
|
+
href: this.config.links.support,
|
|
87
|
+
});
|
|
88
|
+
supportText.createSpan({
|
|
89
|
+
text: ". Your support helps keep this plugin maintained and improved!",
|
|
90
|
+
});
|
|
91
|
+
contentEl.createEl("hr");
|
|
59
92
|
// Changelog content
|
|
60
93
|
const changelogSections = getChangelogSince(this.config.changelogContent, this.fromVersion, this.toVersion);
|
|
61
94
|
if (changelogSections.length === 0) {
|
|
@@ -70,29 +103,27 @@ export class WhatsNewModal extends Modal {
|
|
|
70
103
|
});
|
|
71
104
|
const markdownContent = formatChangelogSections(changelogSections);
|
|
72
105
|
yield MarkdownRenderer.render(this.app, markdownContent, changelogContainer, "/", this.plugin);
|
|
106
|
+
// Make external links clickable
|
|
107
|
+
this.makeExternalLinksClickable(changelogContainer);
|
|
73
108
|
}
|
|
74
109
|
// Action buttons
|
|
75
110
|
const buttonContainer = contentEl.createDiv({
|
|
76
111
|
cls: this.cls("whats-new-buttons"),
|
|
77
112
|
});
|
|
78
|
-
// Full changelog button
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
docsBtn.addEventListener("click", () => {
|
|
93
|
-
window.open(this.config.links.documentation, "_blank");
|
|
94
|
-
});
|
|
95
|
-
}
|
|
113
|
+
// Full changelog button
|
|
114
|
+
const changelogBtn = buttonContainer.createEl("button", {
|
|
115
|
+
text: "Full Changelog",
|
|
116
|
+
});
|
|
117
|
+
changelogBtn.addEventListener("click", () => {
|
|
118
|
+
window.open(this.config.links.changelog, "_blank");
|
|
119
|
+
});
|
|
120
|
+
// Documentation button
|
|
121
|
+
const docsBtn = buttonContainer.createEl("button", {
|
|
122
|
+
text: "Documentation",
|
|
123
|
+
});
|
|
124
|
+
docsBtn.addEventListener("click", () => {
|
|
125
|
+
window.open(this.config.links.documentation, "_blank");
|
|
126
|
+
});
|
|
96
127
|
// Close button (always present)
|
|
97
128
|
const closeBtn = buttonContainer.createEl("button", {
|
|
98
129
|
text: "Close",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"whats-new-modal.js","sourceRoot":"","sources":["../../src/components/whats-new-modal.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,gBAAgB,EAAE,KAAK,EAAE,MAAM,UAAU,CAAC;AACnD,OAAO,EAAE,uBAAuB,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAyCxF;;;GAGG;AACH,MAAM,OAAO,aAAc,SAAQ,KAAK;IACvC,YACC,GAAQ,EACA,MAAc,EACd,MAA2B,EAC3B,WAAmB,EACnB,SAAiB;QAEzB,KAAK,CAAC,GAAG,CAAC,CAAC;QALH,WAAM,GAAN,MAAM,CAAQ;QACd,WAAM,GAAN,MAAM,CAAqB;QAC3B,gBAAW,GAAX,WAAW,CAAQ;QACnB,cAAS,GAAT,SAAS,CAAQ;IAG1B,CAAC;IAED;;OAEG;IACK,GAAG,CAAC,MAAc;QACzB,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,SAAS,IAAI,MAAM,EAAE,CAAC;IAC7C,CAAC;IAED;;OAEG;IACK,MAAM,CAAC,EAAe,EAAE,MAAc;QAC7C,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC;IACpC,CAAC;IAEK,MAAM;;YACX,MAAM,EAAE,SAAS,EAAE,GAAG,IAAI,CAAC;YAC3B,SAAS,CAAC,KAAK,EAAE,CAAC;YAElB,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,iBAAiB,CAAC,CAAC;YAE1C,iBAAiB;YACjB,MAAM,MAAM,GAAG,SAAS,CAAC,SAAS,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,kBAAkB,CAAC,EAAE,CAAC,CAAC;YAC1E,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE;gBACrB,IAAI,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC,UAAU,gBAAgB,IAAI,CAAC,SAAS,EAAE;aAC/D,CAAC,CAAC;YAEH,MAAM,CAAC,QAAQ,CAAC,GAAG,EAAE;gBACpB,IAAI,EAAE,kBAAkB,IAAI,CAAC,WAAW,EAAE;gBAC1C,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,oBAAoB,CAAC;aACnC,CAAC,CAAC;YAEH,6BAA6B;YAC7B,IAAI,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC;gBAC/B,MAAM,cAAc,GAAG,SAAS,CAAC,SAAS,CAAC;oBAC1C,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,mBAAmB,CAAC;iBAClC,CAAC,CAAC;gBAEH,cAAc,CAAC,QAAQ,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,iBAAiB,EAAE,CAAC,CAAC;gBAE3D,MAAM,WAAW,GAAG,cAAc,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;gBACjD,WAAW,CAAC,UAAU,CAAC,EAAE,IAAI,EAAE,kDAAkD,EAAE,CAAC,CAAC;gBACrF,WAAW,CAAC,QAAQ,CAAC,GAAG,EAAE;oBACzB,IAAI,EAAE,oBAAoB;oBAC1B,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO;iBAC/B,CAAC,CAAC;gBACH,WAAW,CAAC,UAAU,CAAC;oBACtB,IAAI,EAAE,gEAAgE;iBACtE,CAAC,CAAC;gBAEH,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;YAC1B,CAAC;YAED,oBAAoB;YACpB,MAAM,iBAAiB,GAAG,iBAAiB,CAC1C,IAAI,CAAC,MAAM,CAAC,gBAAgB,EAC5B,IAAI,CAAC,WAAW,EAChB,IAAI,CAAC,SAAS,CACd,CAAC;YAEF,IAAI,iBAAiB,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACpC,SAAS,CAAC,QAAQ,CAAC,GAAG,EAAE;oBACvB,IAAI,EAAE,8CAA8C;oBACpD,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,iBAAiB,CAAC;iBAChC,CAAC,CAAC;YACJ,CAAC;iBAAM,CAAC;gBACP,MAAM,kBAAkB,GAAG,SAAS,CAAC,SAAS,CAAC;oBAC9C,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,mBAAmB,CAAC;iBAClC,CAAC,CAAC;gBAEH,MAAM,eAAe,GAAG,uBAAuB,CAAC,iBAAiB,CAAC,CAAC;gBAEnE,MAAM,gBAAgB,CAAC,MAAM,CAC5B,IAAI,CAAC,GAAG,EACR,eAAe,EACf,kBAAkB,EAClB,GAAG,EACH,IAAI,CAAC,MAAM,CACX,CAAC;YACH,CAAC;YAED,iBAAiB;YACjB,MAAM,eAAe,GAAG,SAAS,CAAC,SAAS,CAAC;gBAC3C,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,mBAAmB,CAAC;aAClC,CAAC,CAAC;YAEH,mCAAmC;YACnC,IAAI,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,EAAE,CAAC;gBACjC,MAAM,YAAY,GAAG,eAAe,CAAC,QAAQ,CAAC,QAAQ,EAAE;oBACvD,IAAI,EAAE,gBAAgB;iBACtB,CAAC,CAAC;gBACH,YAAY,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE;oBAC3C,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;gBACpD,CAAC,CAAC,CAAC;YACJ,CAAC;YAED,kCAAkC;YAClC,IAAI,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,aAAa,EAAE,CAAC;gBACrC,MAAM,OAAO,GAAG,eAAe,CAAC,QAAQ,CAAC,QAAQ,EAAE;oBAClD,IAAI,EAAE,eAAe;iBACrB,CAAC,CAAC;gBACH,OAAO,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE;oBACtC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,aAAa,EAAE,QAAQ,CAAC,CAAC;gBACxD,CAAC,CAAC,CAAC;YACJ,CAAC;YAED,gCAAgC;YAChC,MAAM,QAAQ,GAAG,eAAe,CAAC,QAAQ,CAAC,QAAQ,EAAE;gBACnD,IAAI,EAAE,OAAO;gBACb,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC;aACxB,CAAC,CAAC;YACH,QAAQ,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;QACxD,CAAC;KAAA;IAED,OAAO;QACN,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC;IACxB,CAAC;CACD","sourcesContent":["import type { App, Plugin } from \"obsidian\";\nimport { MarkdownRenderer, Modal } from \"obsidian\";\nimport { formatChangelogSections, getChangelogSince } from \"../string/changelog-parser\";\n\nexport interface WhatsNewModalConfig {\n\t/**\n\t * The CSS class prefix/suffix to use for styling.\n\t * Example: \"custom-calendar\" will generate classes like \"custom-calendar-whats-new-modal\"\n\t */\n\tcssPrefix: string;\n\n\t/**\n\t * Display name of the plugin.\n\t * Example: \"Custom Calendar\"\n\t */\n\tpluginName: string;\n\n\t/**\n\t * Raw changelog markdown content to parse.\n\t */\n\tchangelogContent: string;\n\n\t/**\n\t * Links to external resources.\n\t */\n\tlinks: {\n\t\t/**\n\t\t * URL to support/donate page.\n\t\t */\n\t\tsupport?: string;\n\n\t\t/**\n\t\t * URL to full changelog page.\n\t\t */\n\t\tchangelog?: string;\n\n\t\t/**\n\t\t * URL to documentation.\n\t\t */\n\t\tdocumentation?: string;\n\t};\n}\n\n/**\n * Generic \"What's New\" modal that displays changelog entries between versions.\n * Supports custom CSS prefixes, plugin names, and configurable links.\n */\nexport class WhatsNewModal extends Modal {\n\tconstructor(\n\t\tapp: App,\n\t\tprivate plugin: Plugin,\n\t\tprivate config: WhatsNewModalConfig,\n\t\tprivate fromVersion: string,\n\t\tprivate toVersion: string\n\t) {\n\t\tsuper(app);\n\t}\n\n\t/**\n\t * Helper to create CSS class names with the configured prefix.\n\t */\n\tprivate cls(suffix: string): string {\n\t\treturn `${this.config.cssPrefix}-${suffix}`;\n\t}\n\n\t/**\n\t * Helper to add CSS class to an element.\n\t */\n\tprivate addCls(el: HTMLElement, suffix: string): void {\n\t\tel.classList.add(this.cls(suffix));\n\t}\n\n\tasync onOpen() {\n\t\tconst { contentEl } = this;\n\t\tcontentEl.empty();\n\n\t\tthis.addCls(contentEl, \"whats-new-modal\");\n\n\t\t// Header section\n\t\tconst header = contentEl.createDiv({ cls: this.cls(\"whats-new-header\") });\n\t\theader.createEl(\"h2\", {\n\t\t\ttext: `${this.config.pluginName} updated to v${this.toVersion}`,\n\t\t});\n\n\t\theader.createEl(\"p\", {\n\t\t\ttext: `Changes since v${this.fromVersion}`,\n\t\t\tcls: this.cls(\"whats-new-subtitle\"),\n\t\t});\n\n\t\t// Support section (optional)\n\t\tif (this.config.links.support) {\n\t\t\tconst supportSection = contentEl.createDiv({\n\t\t\t\tcls: this.cls(\"whats-new-support\"),\n\t\t\t});\n\n\t\t\tsupportSection.createEl(\"h3\", { text: \"Support My Work\" });\n\n\t\t\tconst supportText = supportSection.createEl(\"p\");\n\t\t\tsupportText.createSpan({ text: \"If you enjoy using this plugin, please consider \" });\n\t\t\tsupportText.createEl(\"a\", {\n\t\t\t\ttext: \"supporting my work\",\n\t\t\t\thref: this.config.links.support,\n\t\t\t});\n\t\t\tsupportText.createSpan({\n\t\t\t\ttext: \". Your support helps keep this plugin maintained and improved!\",\n\t\t\t});\n\n\t\t\tcontentEl.createEl(\"hr\");\n\t\t}\n\n\t\t// Changelog content\n\t\tconst changelogSections = getChangelogSince(\n\t\t\tthis.config.changelogContent,\n\t\t\tthis.fromVersion,\n\t\t\tthis.toVersion\n\t\t);\n\n\t\tif (changelogSections.length === 0) {\n\t\t\tcontentEl.createEl(\"p\", {\n\t\t\t\ttext: \"No significant changes found in this update.\",\n\t\t\t\tcls: this.cls(\"whats-new-empty\"),\n\t\t\t});\n\t\t} else {\n\t\t\tconst changelogContainer = contentEl.createDiv({\n\t\t\t\tcls: this.cls(\"whats-new-content\"),\n\t\t\t});\n\n\t\t\tconst markdownContent = formatChangelogSections(changelogSections);\n\n\t\t\tawait MarkdownRenderer.render(\n\t\t\t\tthis.app,\n\t\t\t\tmarkdownContent,\n\t\t\t\tchangelogContainer,\n\t\t\t\t\"/\",\n\t\t\t\tthis.plugin\n\t\t\t);\n\t\t}\n\n\t\t// Action buttons\n\t\tconst buttonContainer = contentEl.createDiv({\n\t\t\tcls: this.cls(\"whats-new-buttons\"),\n\t\t});\n\n\t\t// Full changelog button (optional)\n\t\tif (this.config.links.changelog) {\n\t\t\tconst changelogBtn = buttonContainer.createEl(\"button\", {\n\t\t\t\ttext: \"Full Changelog\",\n\t\t\t});\n\t\t\tchangelogBtn.addEventListener(\"click\", () => {\n\t\t\t\twindow.open(this.config.links.changelog, \"_blank\");\n\t\t\t});\n\t\t}\n\n\t\t// Documentation button (optional)\n\t\tif (this.config.links.documentation) {\n\t\t\tconst docsBtn = buttonContainer.createEl(\"button\", {\n\t\t\t\ttext: \"Documentation\",\n\t\t\t});\n\t\t\tdocsBtn.addEventListener(\"click\", () => {\n\t\t\t\twindow.open(this.config.links.documentation, \"_blank\");\n\t\t\t});\n\t\t}\n\n\t\t// Close button (always present)\n\t\tconst closeBtn = buttonContainer.createEl(\"button\", {\n\t\t\ttext: \"Close\",\n\t\t\tcls: this.cls(\"mod-cta\"),\n\t\t});\n\t\tcloseBtn.addEventListener(\"click\", () => this.close());\n\t}\n\n\tonClose() {\n\t\tthis.contentEl.empty();\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"whats-new-modal.js","sourceRoot":"","sources":["../../src/components/whats-new-modal.ts"],"names":[],"mappings":"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","sourcesContent":["import type { App, Plugin } from \"obsidian\";\nimport { MarkdownRenderer, Modal } from \"obsidian\";\nimport { formatChangelogSections, getChangelogSince } from \"../string/changelog-parser\";\n\nexport interface WhatsNewModalConfig {\n\t/**\n\t * The CSS class prefix/suffix to use for styling.\n\t * Example: \"custom-calendar\" will generate classes like \"custom-calendar-whats-new-modal\"\n\t */\n\tcssPrefix: string;\n\n\t/**\n\t * Display name of the plugin.\n\t * Example: \"Custom Calendar\"\n\t */\n\tpluginName: string;\n\n\t/**\n\t * Raw changelog markdown content to parse.\n\t */\n\tchangelogContent: string;\n\n\t/**\n\t * Links to external resources.\n\t */\n\tlinks: {\n\t\t/**\n\t\t * URL to support/donate page.\n\t\t */\n\t\tsupport: string;\n\n\t\t/**\n\t\t * URL to full changelog page.\n\t\t */\n\t\tchangelog: string;\n\n\t\t/**\n\t\t * Base URL for documentation (used to resolve relative links in changelog).\n\t\t * Example: \"https://docs.example.com\" or \"https://docs.example.com/\"\n\t\t */\n\t\tdocumentation: string;\n\t};\n}\n\n/**\n * Generic \"What's New\" modal that displays changelog entries between versions.\n * Supports custom CSS prefixes, plugin names, and configurable links.\n */\nexport class WhatsNewModal extends Modal {\n\tconstructor(\n\t\tapp: App,\n\t\tprivate plugin: Plugin,\n\t\tprivate config: WhatsNewModalConfig,\n\t\tprivate fromVersion: string,\n\t\tprivate toVersion: string\n\t) {\n\t\tsuper(app);\n\t}\n\n\t/**\n\t * Helper to create CSS class names with the configured prefix.\n\t */\n\tprivate cls(suffix: string): string {\n\t\treturn `${this.config.cssPrefix}-${suffix}`;\n\t}\n\n\t/**\n\t * Helper to add CSS class to an element.\n\t */\n\tprivate addCls(el: HTMLElement, suffix: string): void {\n\t\tel.classList.add(this.cls(suffix));\n\t}\n\n\t/**\n\t * Makes external links in rendered markdown clickable by adding click handlers.\n\t * Handles both absolute URLs (http/https) and relative URLs (starting with /).\n\t * Relative URLs are resolved against the documentation base URL.\n\t */\n\tprivate makeExternalLinksClickable(container: HTMLElement): void {\n\t\tconst links = container.querySelectorAll<HTMLAnchorElement>(\"a[href]\");\n\n\t\t// Convert NodeList to Array for iteration\n\t\tArray.from(links).forEach((link) => {\n\t\t\tconst href = link.getAttribute(\"href\");\n\t\t\tif (!href) return;\n\n\t\t\tlet finalUrl: string | null = null;\n\n\t\t\t// Handle absolute HTTP(S) links\n\t\t\tif (href.startsWith(\"http://\") || href.startsWith(\"https://\")) {\n\t\t\t\tfinalUrl = href;\n\t\t\t}\n\t\t\t// Handle relative links (starting with /)\n\t\t\telse if (href.startsWith(\"/\")) {\n\t\t\t\t// Get base documentation URL and ensure proper slash handling\n\t\t\t\tconst baseUrl = this.config.links.documentation;\n\t\t\t\tconst normalizedBase = baseUrl.endsWith(\"/\") ? baseUrl.slice(0, -1) : baseUrl;\n\t\t\t\tfinalUrl = `${normalizedBase}${href}`;\n\t\t\t}\n\n\t\t\t// Add click handler for external links\n\t\t\tif (finalUrl) {\n\t\t\t\tlink.addEventListener(\"click\", (event: MouseEvent) => {\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\twindow.open(finalUrl, \"_blank\");\n\t\t\t\t});\n\n\t\t\t\t// Add visual indicator that it's an external link\n\t\t\t\tlink.classList.add(\"external-link\");\n\t\t\t}\n\t\t});\n\t}\n\n\tasync onOpen() {\n\t\tconst { contentEl } = this;\n\t\tcontentEl.empty();\n\n\t\tthis.addCls(contentEl, \"whats-new-modal\");\n\n\t\t// Header section\n\t\tconst header = contentEl.createDiv({ cls: this.cls(\"whats-new-header\") });\n\t\theader.createEl(\"h2\", {\n\t\t\ttext: `${this.config.pluginName} updated to v${this.toVersion}`,\n\t\t});\n\n\t\theader.createEl(\"p\", {\n\t\t\ttext: `Changes since v${this.fromVersion}`,\n\t\t\tcls: this.cls(\"whats-new-subtitle\"),\n\t\t});\n\n\t\t// Support section\n\t\tconst supportSection = contentEl.createDiv({\n\t\t\tcls: this.cls(\"whats-new-support\"),\n\t\t});\n\n\t\tsupportSection.createEl(\"h3\", { text: \"Support My Work\" });\n\n\t\tconst supportText = supportSection.createEl(\"p\");\n\t\tsupportText.createSpan({ text: \"If you enjoy using this plugin, please consider \" });\n\t\tsupportText.createEl(\"a\", {\n\t\t\ttext: \"supporting my work\",\n\t\t\thref: this.config.links.support,\n\t\t});\n\t\tsupportText.createSpan({\n\t\t\ttext: \". Your support helps keep this plugin maintained and improved!\",\n\t\t});\n\n\t\tcontentEl.createEl(\"hr\");\n\n\t\t// Changelog content\n\t\tconst changelogSections = getChangelogSince(\n\t\t\tthis.config.changelogContent,\n\t\t\tthis.fromVersion,\n\t\t\tthis.toVersion\n\t\t);\n\n\t\tif (changelogSections.length === 0) {\n\t\t\tcontentEl.createEl(\"p\", {\n\t\t\t\ttext: \"No significant changes found in this update.\",\n\t\t\t\tcls: this.cls(\"whats-new-empty\"),\n\t\t\t});\n\t\t} else {\n\t\t\tconst changelogContainer = contentEl.createDiv({\n\t\t\t\tcls: this.cls(\"whats-new-content\"),\n\t\t\t});\n\n\t\t\tconst markdownContent = formatChangelogSections(changelogSections);\n\n\t\t\tawait MarkdownRenderer.render(\n\t\t\t\tthis.app,\n\t\t\t\tmarkdownContent,\n\t\t\t\tchangelogContainer,\n\t\t\t\t\"/\",\n\t\t\t\tthis.plugin\n\t\t\t);\n\n\t\t\t// Make external links clickable\n\t\t\tthis.makeExternalLinksClickable(changelogContainer);\n\t\t}\n\n\t\t// Action buttons\n\t\tconst buttonContainer = contentEl.createDiv({\n\t\t\tcls: this.cls(\"whats-new-buttons\"),\n\t\t});\n\n\t\t// Full changelog button\n\t\tconst changelogBtn = buttonContainer.createEl(\"button\", {\n\t\t\ttext: \"Full Changelog\",\n\t\t});\n\t\tchangelogBtn.addEventListener(\"click\", () => {\n\t\t\twindow.open(this.config.links.changelog, \"_blank\");\n\t\t});\n\n\t\t// Documentation button\n\t\tconst docsBtn = buttonContainer.createEl(\"button\", {\n\t\t\ttext: \"Documentation\",\n\t\t});\n\t\tdocsBtn.addEventListener(\"click\", () => {\n\t\t\twindow.open(this.config.links.documentation, \"_blank\");\n\t\t});\n\n\t\t// Close button (always present)\n\t\tconst closeBtn = buttonContainer.createEl(\"button\", {\n\t\t\ttext: \"Close\",\n\t\t\tcls: this.cls(\"mod-cta\"),\n\t\t});\n\t\tcloseBtn.addEventListener(\"click\", () => this.close());\n\t}\n\n\tonClose() {\n\t\tthis.contentEl.empty();\n\t}\n}\n"]}
|
|
@@ -1,12 +1,4 @@
|
|
|
1
1
|
import type { App } from "obsidian";
|
|
2
2
|
import type { Frontmatter, FrontmatterDiff } from "./frontmatter-diff";
|
|
3
|
-
export interface NexusPropertiesSettings {
|
|
4
|
-
excludedPropagatedProps?: string;
|
|
5
|
-
parentProp: string;
|
|
6
|
-
childrenProp: string;
|
|
7
|
-
relatedProp: string;
|
|
8
|
-
zettelIdProp: string;
|
|
9
|
-
}
|
|
10
|
-
export declare function parseExcludedProps(settings: NexusPropertiesSettings): Set<string>;
|
|
11
3
|
export declare function applyFrontmatterChanges(app: App, targetPath: string, sourceFrontmatter: Frontmatter, diff: FrontmatterDiff): Promise<void>;
|
|
12
4
|
//# sourceMappingURL=frontmatter-propagation.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"frontmatter-propagation.d.ts","sourceRoot":"","sources":["../../src/file/frontmatter-propagation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAEpC,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAEvE,
|
|
1
|
+
{"version":3,"file":"frontmatter-propagation.d.ts","sourceRoot":"","sources":["../../src/file/frontmatter-propagation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAEpC,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAEvE,wBAAsB,uBAAuB,CAC5C,GAAG,EAAE,GAAG,EACR,UAAU,EAAE,MAAM,EAClB,iBAAiB,EAAE,WAAW,EAC9B,IAAI,EAAE,eAAe,GACnB,OAAO,CAAC,IAAI,CAAC,CAwBf"}
|
|
@@ -1,19 +1,5 @@
|
|
|
1
1
|
import { __awaiter } from "tslib";
|
|
2
2
|
import { TFile } from "obsidian";
|
|
3
|
-
export function parseExcludedProps(settings) {
|
|
4
|
-
const excludedPropsStr = settings.excludedPropagatedProps || "";
|
|
5
|
-
const userExcluded = excludedPropsStr
|
|
6
|
-
.split(",")
|
|
7
|
-
.map((prop) => prop.trim())
|
|
8
|
-
.filter((prop) => prop.length > 0);
|
|
9
|
-
const alwaysExcluded = [
|
|
10
|
-
settings.parentProp,
|
|
11
|
-
settings.childrenProp,
|
|
12
|
-
settings.relatedProp,
|
|
13
|
-
settings.zettelIdProp,
|
|
14
|
-
];
|
|
15
|
-
return new Set([...alwaysExcluded, ...userExcluded]);
|
|
16
|
-
}
|
|
17
3
|
export function applyFrontmatterChanges(app, targetPath, sourceFrontmatter, diff) {
|
|
18
4
|
return __awaiter(this, void 0, void 0, function* () {
|
|
19
5
|
try {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"frontmatter-propagation.js","sourceRoot":"","sources":["../../src/file/frontmatter-propagation.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,KAAK,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"frontmatter-propagation.js","sourceRoot":"","sources":["../../src/file/frontmatter-propagation.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,KAAK,EAAE,MAAM,UAAU,CAAC;AAGjC,MAAM,UAAgB,uBAAuB,CAC5C,GAAQ,EACR,UAAkB,EAClB,iBAA8B,EAC9B,IAAqB;;QAErB,IAAI,CAAC;YACJ,MAAM,IAAI,GAAG,GAAG,CAAC,KAAK,CAAC,qBAAqB,CAAC,UAAU,CAAC,CAAC;YACzD,IAAI,CAAC,CAAC,IAAI,YAAY,KAAK,CAAC,EAAE,CAAC;gBAC9B,OAAO,CAAC,IAAI,CAAC,0BAA0B,UAAU,EAAE,CAAC,CAAC;gBACrD,OAAO;YACR,CAAC;YAED,MAAM,GAAG,CAAC,WAAW,CAAC,kBAAkB,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,EAAE;gBACrD,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;oBACjC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,iBAAiB,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;gBAChD,CAAC;gBAED,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;oBACpC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,iBAAiB,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;gBAChD,CAAC;gBAED,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;oBACnC,OAAO,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;gBACvB,CAAC;YACF,CAAC,CAAC,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,OAAO,CAAC,KAAK,CAAC,yCAAyC,UAAU,GAAG,EAAE,KAAK,CAAC,CAAC;QAC9E,CAAC;IACF,CAAC;CAAA","sourcesContent":["import type { App } from \"obsidian\";\nimport { TFile } from \"obsidian\";\nimport type { Frontmatter, FrontmatterDiff } from \"./frontmatter-diff\";\n\nexport async function applyFrontmatterChanges(\n\tapp: App,\n\ttargetPath: string,\n\tsourceFrontmatter: Frontmatter,\n\tdiff: FrontmatterDiff\n): Promise<void> {\n\ttry {\n\t\tconst file = app.vault.getAbstractFileByPath(targetPath);\n\t\tif (!(file instanceof TFile)) {\n\t\t\tconsole.warn(`Target file not found: ${targetPath}`);\n\t\t\treturn;\n\t\t}\n\n\t\tawait app.fileManager.processFrontMatter(file, (fm) => {\n\t\t\tfor (const change of diff.added) {\n\t\t\t\tfm[change.key] = sourceFrontmatter[change.key];\n\t\t\t}\n\n\t\t\tfor (const change of diff.modified) {\n\t\t\t\tfm[change.key] = sourceFrontmatter[change.key];\n\t\t\t}\n\n\t\t\tfor (const change of diff.deleted) {\n\t\t\t\tdelete fm[change.key];\n\t\t\t}\n\t\t});\n\t} catch (error) {\n\t\tconsole.error(`Error applying frontmatter changes to ${targetPath}:`, error);\n\t}\n}\n"]}
|
package/package.json
CHANGED
|
@@ -27,17 +27,18 @@ export interface WhatsNewModalConfig {
|
|
|
27
27
|
/**
|
|
28
28
|
* URL to support/donate page.
|
|
29
29
|
*/
|
|
30
|
-
support
|
|
30
|
+
support: string;
|
|
31
31
|
|
|
32
32
|
/**
|
|
33
33
|
* URL to full changelog page.
|
|
34
34
|
*/
|
|
35
|
-
changelog
|
|
35
|
+
changelog: string;
|
|
36
36
|
|
|
37
37
|
/**
|
|
38
|
-
* URL to
|
|
38
|
+
* Base URL for documentation (used to resolve relative links in changelog).
|
|
39
|
+
* Example: "https://docs.example.com" or "https://docs.example.com/"
|
|
39
40
|
*/
|
|
40
|
-
documentation
|
|
41
|
+
documentation: string;
|
|
41
42
|
};
|
|
42
43
|
}
|
|
43
44
|
|
|
@@ -70,6 +71,46 @@ export class WhatsNewModal extends Modal {
|
|
|
70
71
|
el.classList.add(this.cls(suffix));
|
|
71
72
|
}
|
|
72
73
|
|
|
74
|
+
/**
|
|
75
|
+
* Makes external links in rendered markdown clickable by adding click handlers.
|
|
76
|
+
* Handles both absolute URLs (http/https) and relative URLs (starting with /).
|
|
77
|
+
* Relative URLs are resolved against the documentation base URL.
|
|
78
|
+
*/
|
|
79
|
+
private makeExternalLinksClickable(container: HTMLElement): void {
|
|
80
|
+
const links = container.querySelectorAll<HTMLAnchorElement>("a[href]");
|
|
81
|
+
|
|
82
|
+
// Convert NodeList to Array for iteration
|
|
83
|
+
Array.from(links).forEach((link) => {
|
|
84
|
+
const href = link.getAttribute("href");
|
|
85
|
+
if (!href) return;
|
|
86
|
+
|
|
87
|
+
let finalUrl: string | null = null;
|
|
88
|
+
|
|
89
|
+
// Handle absolute HTTP(S) links
|
|
90
|
+
if (href.startsWith("http://") || href.startsWith("https://")) {
|
|
91
|
+
finalUrl = href;
|
|
92
|
+
}
|
|
93
|
+
// Handle relative links (starting with /)
|
|
94
|
+
else if (href.startsWith("/")) {
|
|
95
|
+
// Get base documentation URL and ensure proper slash handling
|
|
96
|
+
const baseUrl = this.config.links.documentation;
|
|
97
|
+
const normalizedBase = baseUrl.endsWith("/") ? baseUrl.slice(0, -1) : baseUrl;
|
|
98
|
+
finalUrl = `${normalizedBase}${href}`;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Add click handler for external links
|
|
102
|
+
if (finalUrl) {
|
|
103
|
+
link.addEventListener("click", (event: MouseEvent) => {
|
|
104
|
+
event.preventDefault();
|
|
105
|
+
window.open(finalUrl, "_blank");
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
// Add visual indicator that it's an external link
|
|
109
|
+
link.classList.add("external-link");
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
|
|
73
114
|
async onOpen() {
|
|
74
115
|
const { contentEl } = this;
|
|
75
116
|
contentEl.empty();
|
|
@@ -87,26 +128,24 @@ export class WhatsNewModal extends Modal {
|
|
|
87
128
|
cls: this.cls("whats-new-subtitle"),
|
|
88
129
|
});
|
|
89
130
|
|
|
90
|
-
// Support section
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
});
|
|
131
|
+
// Support section
|
|
132
|
+
const supportSection = contentEl.createDiv({
|
|
133
|
+
cls: this.cls("whats-new-support"),
|
|
134
|
+
});
|
|
95
135
|
|
|
96
|
-
|
|
136
|
+
supportSection.createEl("h3", { text: "Support My Work" });
|
|
97
137
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
138
|
+
const supportText = supportSection.createEl("p");
|
|
139
|
+
supportText.createSpan({ text: "If you enjoy using this plugin, please consider " });
|
|
140
|
+
supportText.createEl("a", {
|
|
141
|
+
text: "supporting my work",
|
|
142
|
+
href: this.config.links.support,
|
|
143
|
+
});
|
|
144
|
+
supportText.createSpan({
|
|
145
|
+
text: ". Your support helps keep this plugin maintained and improved!",
|
|
146
|
+
});
|
|
107
147
|
|
|
108
|
-
|
|
109
|
-
}
|
|
148
|
+
contentEl.createEl("hr");
|
|
110
149
|
|
|
111
150
|
// Changelog content
|
|
112
151
|
const changelogSections = getChangelogSince(
|
|
@@ -134,6 +173,9 @@ export class WhatsNewModal extends Modal {
|
|
|
134
173
|
"/",
|
|
135
174
|
this.plugin
|
|
136
175
|
);
|
|
176
|
+
|
|
177
|
+
// Make external links clickable
|
|
178
|
+
this.makeExternalLinksClickable(changelogContainer);
|
|
137
179
|
}
|
|
138
180
|
|
|
139
181
|
// Action buttons
|
|
@@ -141,25 +183,21 @@ export class WhatsNewModal extends Modal {
|
|
|
141
183
|
cls: this.cls("whats-new-buttons"),
|
|
142
184
|
});
|
|
143
185
|
|
|
144
|
-
// Full changelog button
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
});
|
|
152
|
-
}
|
|
186
|
+
// Full changelog button
|
|
187
|
+
const changelogBtn = buttonContainer.createEl("button", {
|
|
188
|
+
text: "Full Changelog",
|
|
189
|
+
});
|
|
190
|
+
changelogBtn.addEventListener("click", () => {
|
|
191
|
+
window.open(this.config.links.changelog, "_blank");
|
|
192
|
+
});
|
|
153
193
|
|
|
154
|
-
// Documentation button
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
});
|
|
162
|
-
}
|
|
194
|
+
// Documentation button
|
|
195
|
+
const docsBtn = buttonContainer.createEl("button", {
|
|
196
|
+
text: "Documentation",
|
|
197
|
+
});
|
|
198
|
+
docsBtn.addEventListener("click", () => {
|
|
199
|
+
window.open(this.config.links.documentation, "_blank");
|
|
200
|
+
});
|
|
163
201
|
|
|
164
202
|
// Close button (always present)
|
|
165
203
|
const closeBtn = buttonContainer.createEl("button", {
|
|
@@ -2,31 +2,6 @@ import type { App } from "obsidian";
|
|
|
2
2
|
import { TFile } from "obsidian";
|
|
3
3
|
import type { Frontmatter, FrontmatterDiff } from "./frontmatter-diff";
|
|
4
4
|
|
|
5
|
-
export interface NexusPropertiesSettings {
|
|
6
|
-
excludedPropagatedProps?: string;
|
|
7
|
-
parentProp: string;
|
|
8
|
-
childrenProp: string;
|
|
9
|
-
relatedProp: string;
|
|
10
|
-
zettelIdProp: string;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export function parseExcludedProps(settings: NexusPropertiesSettings): Set<string> {
|
|
14
|
-
const excludedPropsStr = settings.excludedPropagatedProps || "";
|
|
15
|
-
const userExcluded = excludedPropsStr
|
|
16
|
-
.split(",")
|
|
17
|
-
.map((prop) => prop.trim())
|
|
18
|
-
.filter((prop) => prop.length > 0);
|
|
19
|
-
|
|
20
|
-
const alwaysExcluded = [
|
|
21
|
-
settings.parentProp,
|
|
22
|
-
settings.childrenProp,
|
|
23
|
-
settings.relatedProp,
|
|
24
|
-
settings.zettelIdProp,
|
|
25
|
-
];
|
|
26
|
-
|
|
27
|
-
return new Set([...alwaysExcluded, ...userExcluded]);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
5
|
export async function applyFrontmatterChanges(
|
|
31
6
|
app: App,
|
|
32
7
|
targetPath: string,
|