diff --git a/CHANGELOG.md b/CHANGELOG.md index 61fc363..fe16130 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,20 @@ All notable changes to Rich Foot will be documented in this file. +## [1.7.2] - 2024-11-29 +### ✨ Added +- `Date Display Format` option to allow users to specify their own date format + +### 🐛 Fixed +- Date not formatted correctly if timestamp was included in the Custom Created/Modified Date Property + +## [1.7.1] - 2024-11-27 +### 🐛 Fixed +- Note embeds in canvas now have the correct height +- Duplicate "show dates" option in settings + +### ✨ Added +- If using custom created/modified date properties, the date now displays in the format of "Month Day, Year" if in proper date format, otherwise it displays the raw frontmatter filed string value. ## [1.7.0] - 2024-11-26 ### ✨ Added diff --git a/UPDATE.md b/UPDATE.md index 6e30f41..bc153bb 100644 --- a/UPDATE.md +++ b/UPDATE.md @@ -1,5 +1,20 @@ ## 📆 Dates Your Way +### v1.7.2 +#### ✨ Added +- `Date Display Format` option to allow users to specify their own date format + +#### 🐛 Fixed +- Date not formatted correctly if timestamp was included in the Custom Created/Modified Date Property + +### v1.7.1 +#### 🐛 Fixed +- Note embeds in canvas now have the correct height +- Duplicate "show dates" option in settings + +#### ✨ Added +- If using custom created/modified date properties, the date now displays in the format of "Month Day, Year" if in proper date format, otherwise it displays the raw frontmatter filed string value. + ### v1.7.0 #### ✨ Added - `Custom Created/Modified Date Property` fields to allow users to specify their own frontmatter properties for dates, useful when file system dates are affected by sync processes and you track them separately. diff --git a/example-vault.zip b/example-vault.zip index c3769c7..d5e3f16 100644 Binary files a/example-vault.zip and b/example-vault.zip differ diff --git a/example-vault/rich-foot-example/.obsidian/core-plugins.json b/example-vault/rich-foot-example/.obsidian/core-plugins.json index 5fcbb97..be7dab5 100644 --- a/example-vault/rich-foot-example/.obsidian/core-plugins.json +++ b/example-vault/rich-foot-example/.obsidian/core-plugins.json @@ -4,7 +4,7 @@ "switcher": true, "graph": false, "backlink": false, - "canvas": false, + "canvas": true, "outgoing-link": false, "tag-pane": true, "properties": true, diff --git a/example-vault/rich-foot-example/.obsidian/plugins/rich-foot/data.json b/example-vault/rich-foot-example/.obsidian/plugins/rich-foot/data.json index 19c7f28..d785919 100644 --- a/example-vault/rich-foot-example/.obsidian/plugins/rich-foot/data.json +++ b/example-vault/rich-foot-example/.obsidian/plugins/rich-foot/data.json @@ -16,8 +16,9 @@ "linkBorderColor": "rgba(255, 255, 255, 0.204)", "customCreatedDateProp": "created", "customModifiedDateProp": "modified", + "dateDisplayFormat": "mmmm dd, yyyy", "showBacklinks": true, "showOutlinks": true, "showDates": true, - "lastVersion": "1.6.0" + "lastVersion": "1.7.1" } \ No newline at end of file diff --git a/example-vault/rich-foot-example/.obsidian/plugins/rich-foot/main.js b/example-vault/rich-foot-example/.obsidian/plugins/rich-foot/main.js index 1385e6a..c67c486 100644 --- a/example-vault/rich-foot-example/.obsidian/plugins/rich-foot/main.js +++ b/example-vault/rich-foot-example/.obsidian/plugins/rich-foot/main.js @@ -107,7 +107,7 @@ var ReleaseNotesModal = class extends import_obsidian.Modal { }; // virtual-module:virtual:release-notes -var releaseNotes = '

\u{1F4C6} Dates Your Way

\n

v1.7.0

\n

\u2728 Added

\n\n

screenshot

\n'; +var releaseNotes = '

\u{1F4C6} Dates Your Way

\n

v1.7.2

\n

\u2728 Added

\n\n

\u{1F41B} Fixed

\n\n

v1.7.1

\n

\u{1F41B} Fixed

\n\n

\u2728 Added

\n\n

v1.7.0

\n

\u2728 Added

\n\n

screenshot

\n'; // src/main.js var DEFAULT_SETTINGS = { @@ -125,7 +125,8 @@ var DEFAULT_SETTINGS = { linkBackgroundColor: "var(--tag-background)", linkBorderColor: "rgba(255, 255, 255, 0.204)", customCreatedDateProp: "", - customModifiedDateProp: "" + customModifiedDateProp: "", + dateDisplayFormat: "mmmm dd, yyyy" }; function rgbToHex(color) { if (color.startsWith("hsl")) { @@ -156,6 +157,42 @@ function blendRgbaWithBackground(rgba, backgroundRgb) { const b = Math.round(fb * alpha + bb * (1 - alpha)); return `rgb(${r}, ${g}, ${b})`; } +function formatDate(date, format) { + const d = new Date(date); + const year = d.getFullYear(); + const month = d.getMonth(); + const day = d.getDate(); + const weekday = d.getDay(); + const months = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]; + const monthsShort = months.map((m) => m.slice(0, 3)); + const weekdays = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]; + const weekdaysShort = weekdays.map((w) => w.slice(0, 3)); + const pad = (num) => num.toString().padStart(2, "0"); + const tokens = { + "dddd": weekdays[weekday], + "ddd": weekdaysShort[weekday], + "dd": pad(day), + "d": day.toString(), + "mmmm": months[month], + "mmm": monthsShort[month], + "mm": pad(month + 1), + "m": (month + 1).toString(), + "yyyy": year.toString(), + "yy": year.toString().slice(-2) + }; + const sortedTokens = Object.keys(tokens).sort((a, b) => b.length - a.length); + let result = format; + const replacements = /* @__PURE__ */ new Map(); + sortedTokens.forEach((token, index) => { + const placeholder = `__${index}__`; + replacements.set(placeholder, tokens[token]); + result = result.replace(new RegExp(token, "g"), placeholder); + }); + replacements.forEach((value, placeholder) => { + result = result.replace(new RegExp(placeholder, "g"), value); + }); + return result; +} var RichFootPlugin = class extends import_obsidian2.Plugin { async onload() { await this.loadSettings(); @@ -168,6 +205,18 @@ var RichFootPlugin = class extends import_obsidian2.Plugin { await this.checkVersion(); this.updateRichFoot = (0, import_obsidian2.debounce)(this.updateRichFoot.bind(this), 100, true); this.addSettingTab(new RichFootSettingTab(this.app, this)); + this.registerEvent( + this.app.metadataCache.on("changed", (file) => { + const cache = this.app.metadataCache.getFileCache(file); + if (cache == null ? void 0 : cache.frontmatter) { + const customCreatedProp = this.settings.customCreatedDateProp; + const customModifiedProp = this.settings.customModifiedDateProp; + if (customCreatedProp && customCreatedProp in cache.frontmatter || customModifiedProp && customModifiedProp in cache.frontmatter) { + this.updateRichFoot(); + } + } + }) + ); this.app.workspace.onLayoutReady(() => { this.registerEvent( this.app.workspace.on("layout-change", this.updateRichFoot) @@ -342,9 +391,42 @@ var RichFootPlugin = class extends import_obsidian2.Plugin { let modifiedDate; if (this.settings.customModifiedDateProp && frontmatter && frontmatter[this.settings.customModifiedDateProp]) { modifiedDate = frontmatter[this.settings.customModifiedDateProp]; + let isValidDate = false; + let tempDate = modifiedDate; + if (!isNaN(Date.parse(tempDate))) { + isValidDate = true; + } + if (!isValidDate) { + let count = 0; + tempDate = modifiedDate.replace(/\./g, (match) => { + count++; + return count <= 2 ? "-" : match; + }); + if (!isNaN(Date.parse(tempDate))) { + isValidDate = true; + } + } + if (!isValidDate) { + let count = 0; + tempDate = modifiedDate.replace(/\//g, (match) => { + count++; + return count <= 2 ? "-" : match; + }); + if (!isNaN(Date.parse(tempDate))) { + isValidDate = true; + } + } + if (isValidDate) { + const datePart = tempDate.split("T")[0]; + const dateStr = tempDate.includes("T") ? tempDate : `${datePart}T00:00:00`; + const dateObj = new Date(dateStr); + modifiedDate = formatDate(dateObj, this.settings.dateDisplayFormat); + } else { + modifiedDate = modifiedDate; + } } else { modifiedDate = new Date(file.stat.mtime); - modifiedDate = `${modifiedDate.toLocaleString("default", { month: "long" })} ${modifiedDate.getDate()}, ${modifiedDate.getFullYear()}`; + modifiedDate = formatDate(modifiedDate, this.settings.dateDisplayFormat); } datesWrapper.createDiv({ cls: "rich-foot--modified-date", @@ -353,9 +435,42 @@ var RichFootPlugin = class extends import_obsidian2.Plugin { let createdDate; if (this.settings.customCreatedDateProp && frontmatter && frontmatter[this.settings.customCreatedDateProp]) { createdDate = frontmatter[this.settings.customCreatedDateProp]; + let isValidDate = false; + let tempDate = createdDate; + if (!isNaN(Date.parse(tempDate))) { + isValidDate = true; + } + if (!isValidDate) { + let count = 0; + tempDate = createdDate.replace(/\./g, (match) => { + count++; + return count <= 2 ? "-" : match; + }); + if (!isNaN(Date.parse(tempDate))) { + isValidDate = true; + } + } + if (!isValidDate) { + let count = 0; + tempDate = createdDate.replace(/\//g, (match) => { + count++; + return count <= 2 ? "-" : match; + }); + if (!isNaN(Date.parse(tempDate))) { + isValidDate = true; + } + } + if (isValidDate) { + const datePart = tempDate.split("T")[0]; + const dateStr = tempDate.includes("T") ? tempDate : `${datePart}T00:00:00`; + const dateObj = new Date(dateStr); + createdDate = formatDate(dateObj, this.settings.dateDisplayFormat); + } else { + createdDate = createdDate; + } } else { createdDate = new Date(file.stat.ctime); - createdDate = `${createdDate.toLocaleString("default", { month: "long" })} ${createdDate.getDate()}, ${createdDate.getFullYear()}`; + createdDate = formatDate(createdDate, this.settings.dateDisplayFormat); } datesWrapper.createDiv({ cls: "rich-foot--created-date", @@ -500,17 +615,38 @@ var RichFootSettingTab = class extends import_obsidian2.PluginSettingTab { await this.plugin.saveSettings(); this.plugin.updateRichFoot(); })); - new import_obsidian2.Setting(containerEl).setName("Show Dates").setDesc("Show creation and modification dates in the footer").addToggle((toggle) => toggle.setValue(this.plugin.settings.showDates).onChange(async (value) => { - this.plugin.settings.showDates = value; - await this.plugin.saveSettings(); - this.plugin.updateRichFoot(); - })); containerEl.createEl("h3", { text: "Date Settings" }); new import_obsidian2.Setting(containerEl).setName("Show Dates").setDesc("Show creation and modification dates in the footer").addToggle((toggle) => toggle.setValue(this.plugin.settings.showDates).onChange(async (value) => { this.plugin.settings.showDates = value; await this.plugin.saveSettings(); this.plugin.updateRichFoot(); })); + new import_obsidian2.Setting(containerEl).setName("Date Display Format").setDesc("Choose how dates should be displayed in the footer").addDropdown((dropdown) => { + const today = /* @__PURE__ */ new Date(); + const formats = [ + "mm/dd/yyyy", + "dd/mm/yyyy", + "yyyy-mm-dd", + "mmm dd, yyyy", + "dd mmm yyyy", + "mmmm dd, yyyy", + "ddd, mmm dd, yyyy", + "dddd, mmmm dd, yyyy", + "mm/dd/yy", + "dd/mm/yy", + "yy-mm-dd", + "m/d/yy" + ]; + formats.forEach((format) => { + const example = formatDate(today, format); + dropdown.addOption(format, `${format} (example: ${example})`); + }); + dropdown.setValue(this.plugin.settings.dateDisplayFormat).onChange(async (value) => { + this.plugin.settings.dateDisplayFormat = value; + await this.plugin.saveSettings(); + this.plugin.updateRichFoot(); + }); + }); new import_obsidian2.Setting(containerEl).setName("Custom Created Date Property").setDesc("Specify a frontmatter property to use for creation date (leave empty to use file creation date)").addText((text) => { text.setValue(this.plugin.settings.customCreatedDateProp).onChange(async (value) => { this.plugin.settings.customCreatedDateProp = value; diff --git a/example-vault/rich-foot-example/.obsidian/plugins/rich-foot/manifest.json b/example-vault/rich-foot-example/.obsidian/plugins/rich-foot/manifest.json index 75890a4..f2b541b 100644 --- a/example-vault/rich-foot-example/.obsidian/plugins/rich-foot/manifest.json +++ b/example-vault/rich-foot-example/.obsidian/plugins/rich-foot/manifest.json @@ -1,7 +1,7 @@ { "id": "rich-foot", "name": "Rich Foot", - "version": "1.7.0", + "version": "1.7.2", "minAppVersion": "1.5.0", "description": "Adds backlink tags and created/modified dates to the footer of your notes.", "author": "Justin Parker (eQui\\\\ Labs)", diff --git a/example-vault/rich-foot-example/.obsidian/plugins/rich-foot/styles.css b/example-vault/rich-foot-example/.obsidian/plugins/rich-foot/styles.css index 5513eaf..0462a84 100644 --- a/example-vault/rich-foot-example/.obsidian/plugins/rich-foot/styles.css +++ b/example-vault/rich-foot-example/.obsidian/plugins/rich-foot/styles.css @@ -156,12 +156,19 @@ body.theme-light .rich-foot--backlinks ul li a { padding-bottom: 0 !important; } +/* fix note embed height scroll in canvas */ +.canvas-node-content.markdown-embed div.cm-sizer, +.canvas-node-content.markdown-embed div.markdown-preview-sizer { + min-height: unset !important; +} + + .cm-sizer .rich-foot--backlinks { margin-top: 0; } .markdown-preview-sizer > div { - flex: 0; + flex: 0 auto; } .markdown-preview-sizer > .rich-foot { diff --git a/example-vault/rich-foot-example/.obsidian/workspace.json b/example-vault/rich-foot-example/.obsidian/workspace.json index e9304e9..5986c69 100644 --- a/example-vault/rich-foot-example/.obsidian/workspace.json +++ b/example-vault/rich-foot-example/.obsidian/workspace.json @@ -13,13 +13,13 @@ "state": { "type": "markdown", "state": { - "file": "🦶 Rich Foot.md", + "file": "releases/v1.7.0 - 📆 Dates Your Way.md", "mode": "preview", "backlinks": false, "source": false }, "icon": "lucide-file", - "title": "🦶 Rich Foot" + "title": "v1.7.0 - 📆 Dates Your Way" } } ] @@ -178,6 +178,196 @@ { "id": "4674f52fab9186d3", "type": "leaf", + "state": { + "type": "empty", + "state": {}, + "icon": "lucide-file", + "title": "New tab" + } + }, + { + "id": "c27c8283769f4466", + "type": "leaf", + "state": { + "type": "empty", + "state": {}, + "icon": "lucide-file", + "title": "New tab" + } + }, + { + "id": "c4f94b5118e3d0e8", + "type": "leaf", + "state": { + "type": "empty", + "state": {}, + "icon": "lucide-file", + "title": "New tab" + } + }, + { + "id": "459a2d3da0268437", + "type": "leaf", + "state": { + "type": "empty", + "state": {}, + "icon": "lucide-file", + "title": "New tab" + } + }, + { + "id": "dbaf43fb57cc4699", + "type": "leaf", + "state": { + "type": "empty", + "state": {}, + "icon": "lucide-file", + "title": "New tab" + } + }, + { + "id": "facf9bbf4043ed4c", + "type": "leaf", + "state": { + "type": "empty", + "state": {}, + "icon": "lucide-file", + "title": "New tab" + } + }, + { + "id": "d1a82455e37d17f2", + "type": "leaf", + "state": { + "type": "empty", + "state": {}, + "icon": "lucide-file", + "title": "New tab" + } + }, + { + "id": "c0acc529bba3c2a2", + "type": "leaf", + "state": { + "type": "empty", + "state": {}, + "icon": "lucide-file", + "title": "New tab" + } + }, + { + "id": "b7f24a3bc892f7ce", + "type": "leaf", + "state": { + "type": "empty", + "state": {}, + "icon": "lucide-file", + "title": "New tab" + } + }, + { + "id": "9c84df65d40032a2", + "type": "leaf", + "state": { + "type": "empty", + "state": {}, + "icon": "lucide-file", + "title": "New tab" + } + }, + { + "id": "ae96266198a50c4c", + "type": "leaf", + "state": { + "type": "empty", + "state": {}, + "icon": "lucide-file", + "title": "New tab" + } + }, + { + "id": "fb7d7d767937b219", + "type": "leaf", + "state": { + "type": "empty", + "state": {}, + "icon": "lucide-file", + "title": "New tab" + } + }, + { + "id": "bcb7b70e87d22128", + "type": "leaf", + "state": { + "type": "empty", + "state": {}, + "icon": "lucide-file", + "title": "New tab" + } + }, + { + "id": "864edfa85a3c930c", + "type": "leaf", + "state": { + "type": "empty", + "state": {}, + "icon": "lucide-file", + "title": "New tab" + } + }, + { + "id": "1618e93fe6d7ef12", + "type": "leaf", + "state": { + "type": "empty", + "state": {}, + "icon": "lucide-file", + "title": "New tab" + } + }, + { + "id": "79156bd6731a2904", + "type": "leaf", + "state": { + "type": "empty", + "state": {}, + "icon": "lucide-file", + "title": "New tab" + } + }, + { + "id": "8aaf706b35cce35a", + "type": "leaf", + "state": { + "type": "empty", + "state": {}, + "icon": "lucide-file", + "title": "New tab" + } + }, + { + "id": "55c54da986a31382", + "type": "leaf", + "state": { + "type": "empty", + "state": {}, + "icon": "lucide-file", + "title": "New tab" + } + }, + { + "id": "138dd6cbe7f3aecb", + "type": "leaf", + "state": { + "type": "empty", + "state": {}, + "icon": "lucide-file", + "title": "New tab" + } + }, + { + "id": "2c847f2d16aaf127", + "type": "leaf", "state": { "type": "Saved Queries View", "state": {}, @@ -186,7 +376,7 @@ } } ], - "currentTab": 8 + "currentTab": 27 } ], "direction": "horizontal", @@ -201,17 +391,20 @@ "cmdr:Reload app without saving": false, "switcher:Open quick switcher": false, "templates:Insert template": true, - "command-palette:Open command palette": false + "command-palette:Open command palette": false, + "canvas:Create new canvas": false } }, "active": "e2b1b7584f7a474c", "lastOpenFiles": [ - "releases/v1.7.0 - 📆 Dates Your Way.md", "🦶 Rich Foot.md", - "pixel-banner-images/calendar-feet.png", + "releases/v1.7.0 - 📆 Dates Your Way.md", + "backlink test.md", + "note with table.md", + "Untitled.canvas", "exclude/no rich-feet here.md", "exclude/me too/no rich-feet here either.md", - "backlink test.md", + "pixel-banner-images/calendar-feet.png", "images/rich-feet-3.jpg", "images/rich-feet-2.jpg", "images/rich-feet.jpg", diff --git "a/example-vault/rich-foot-example/releases/v1.7.0 - \360\237\223\206 Dates Your Way.md" "b/example-vault/rich-foot-example/releases/v1.7.0 - \360\237\223\206 Dates Your Way.md" index 2217e5a..c5b305e 100644 --- "a/example-vault/rich-foot-example/releases/v1.7.0 - \360\237\223\206 Dates Your Way.md" +++ "b/example-vault/rich-foot-example/releases/v1.7.0 - \360\237\223\206 Dates Your Way.md" @@ -3,8 +3,8 @@ banner: "[[calendar-feet.png]]" banner-height: "500" banner-y: "30" content-start: "250" -created: Super Cool Day (who knows when ❔) -modified: Cold day in Nov (2024-11-26) +created: 2024/11/30T23:59:00 +modified: 2024-11-29 --- # 🦶 Rich Foot ⋅ v1.7.0 - 📆 Dates Your Way { .release-title } diff --git a/manifest.json b/manifest.json index 75890a4..f2b541b 100644 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "id": "rich-foot", "name": "Rich Foot", - "version": "1.7.0", + "version": "1.7.2", "minAppVersion": "1.5.0", "description": "Adds backlink tags and created/modified dates to the footer of your notes.", "author": "Justin Parker (eQui\\\\ Labs)", diff --git a/src/main.js b/src/main.js index d633eb7..831cc12 100644 --- a/src/main.js +++ b/src/main.js @@ -18,6 +18,7 @@ const DEFAULT_SETTINGS = { linkBorderColor: 'rgba(255, 255, 255, 0.204)', customCreatedDateProp: '', customModifiedDateProp: '', + dateDisplayFormat: 'mmmm dd, yyyy', }; class RichFootSettings { @@ -40,6 +41,7 @@ class RichFootSettings { this.linkBorderColor = DEFAULT_SETTINGS.linkBorderColor; this.customCreatedDateProp = DEFAULT_SETTINGS.customCreatedDateProp; this.customModifiedDateProp = DEFAULT_SETTINGS.customModifiedDateProp; + this.dateDisplayFormat = DEFAULT_SETTINGS.dateDisplayFormat; } } @@ -120,6 +122,57 @@ function blendRgbaWithBackground(rgba, backgroundRgb) { return `rgb(${r}, ${g}, ${b})`; } +// Add this helper function to format dates +function formatDate(date, format) { + const d = new Date(date); + const year = d.getFullYear(); + const month = d.getMonth(); + const day = d.getDate(); + const weekday = d.getDay(); + + const months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']; + const monthsShort = months.map(m => m.slice(0, 3)); + const weekdays = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']; + const weekdaysShort = weekdays.map(w => w.slice(0, 3)); + + // Helper to pad numbers + const pad = (num) => num.toString().padStart(2, '0'); + + // Create a map of tokens to their values + const tokens = { + 'dddd': weekdays[weekday], + 'ddd': weekdaysShort[weekday], + 'dd': pad(day), + 'd': day.toString(), + 'mmmm': months[month], + 'mmm': monthsShort[month], + 'mm': pad(month + 1), + 'm': (month + 1).toString(), + 'yyyy': year.toString(), + 'yy': year.toString().slice(-2) + }; + + // Sort tokens by length (longest first) to avoid partial matches + const sortedTokens = Object.keys(tokens).sort((a, b) => b.length - a.length); + + // Replace each token with a unique placeholder + let result = format; + const replacements = new Map(); + + sortedTokens.forEach((token, index) => { + const placeholder = `__${index}__`; + replacements.set(placeholder, tokens[token]); + result = result.replace(new RegExp(token, 'g'), placeholder); + }); + + // Replace placeholders with final values + replacements.forEach((value, placeholder) => { + result = result.replace(new RegExp(placeholder, 'g'), value); + }); + + return result; +} + class RichFootPlugin extends Plugin { async onload() { await this.loadSettings(); @@ -139,6 +192,22 @@ class RichFootPlugin extends Plugin { this.addSettingTab(new RichFootSettingTab(this.app, this)); + // Register for frontmatter changes + this.registerEvent( + this.app.metadataCache.on('changed', (file) => { + const cache = this.app.metadataCache.getFileCache(file); + if (cache?.frontmatter) { + const customCreatedProp = this.settings.customCreatedDateProp; + const customModifiedProp = this.settings.customModifiedDateProp; + + if ((customCreatedProp && customCreatedProp in cache.frontmatter) || + (customModifiedProp && customModifiedProp in cache.frontmatter)) { + this.updateRichFoot(); + } + } + }) + ); + // Wait for the layout to be ready before registering events this.app.workspace.onLayoutReady(() => { this.registerEvent( @@ -307,7 +376,9 @@ class RichFootPlugin extends Plugin { const richFoot = createDiv({ cls: 'rich-foot' }); const richFootDashedLine = richFoot.createDiv({ cls: 'rich-foot--dashed-line' }); - // Backlinks + // --------------- + // -- Backlinks -- + // --------------- if (this.settings.showBacklinks) { const backlinksData = this.app.metadataCache.getBacklinksForFile(file); @@ -335,7 +406,9 @@ class RichFootPlugin extends Plugin { } } - // Outlinks + // -------------- + // -- Outlinks -- + // -------------- if (this.settings.showOutlinks) { const outlinks = this.getOutlinks(file); @@ -360,32 +433,116 @@ class RichFootPlugin extends Plugin { } } - // Dates + // ----------- + // -- Dates -- + // ----------- if (this.settings.showDates) { const datesWrapper = richFoot.createDiv({ cls: 'rich-foot--dates-wrapper' }); const cache = this.app.metadataCache.getFileCache(file); const frontmatter = cache?.frontmatter; - // Modified date + // -- Modified date -- let modifiedDate; if (this.settings.customModifiedDateProp && frontmatter && frontmatter[this.settings.customModifiedDateProp]) { modifiedDate = frontmatter[this.settings.customModifiedDateProp]; + let isValidDate = false; + let tempDate = modifiedDate; + + // Try original string + if (!isNaN(Date.parse(tempDate))) { + isValidDate = true; + } + // Try replacing periods with hyphens (only first two occurrences) + if (!isValidDate) { + let count = 0; + tempDate = modifiedDate.replace(/\./g, (match) => { + count++; + return count <= 2 ? '-' : match; + }); + if (!isNaN(Date.parse(tempDate))) { + isValidDate = true; + } + } + // Try replacing forward slashes with hyphens (only first two occurrences) + if (!isValidDate) { + let count = 0; + tempDate = modifiedDate.replace(/\//g, (match) => { + count++; + return count <= 2 ? '-' : match; + }); + if (!isNaN(Date.parse(tempDate))) { + isValidDate = true; + } + } + + if (isValidDate) { + // Split on 'T' to handle timestamps + const datePart = tempDate.split('T')[0]; + // If there's no time component, parse in local timezone by appending T00:00:00 + const dateStr = tempDate.includes('T') ? tempDate : `${datePart}T00:00:00`; + // Create a Date object from the parts + const dateObj = new Date(dateStr); + modifiedDate = formatDate(dateObj, this.settings.dateDisplayFormat); + } else { + modifiedDate = modifiedDate; + } } else { modifiedDate = new Date(file.stat.mtime); - modifiedDate = `${modifiedDate.toLocaleString('default', { month: 'long' })} ${modifiedDate.getDate()}, ${modifiedDate.getFullYear()}`; + modifiedDate = formatDate(modifiedDate, this.settings.dateDisplayFormat); } datesWrapper.createDiv({ cls: 'rich-foot--modified-date', text: `${modifiedDate}` }); - // Created date + // -- Created date -- let createdDate; if (this.settings.customCreatedDateProp && frontmatter && frontmatter[this.settings.customCreatedDateProp]) { createdDate = frontmatter[this.settings.customCreatedDateProp]; + let isValidDate = false; + let tempDate = createdDate; + + // Try original string + if (!isNaN(Date.parse(tempDate))) { + isValidDate = true; + } + // Try replacing periods with hyphens (only first two occurrences) + if (!isValidDate) { + let count = 0; + tempDate = createdDate.replace(/\./g, (match) => { + count++; + return count <= 2 ? '-' : match; + }); + if (!isNaN(Date.parse(tempDate))) { + isValidDate = true; + } + } + // Try replacing forward slashes with hyphens (only first two occurrences) + if (!isValidDate) { + let count = 0; + tempDate = createdDate.replace(/\//g, (match) => { + count++; + return count <= 2 ? '-' : match; + }); + if (!isNaN(Date.parse(tempDate))) { + isValidDate = true; + } + } + + if (isValidDate) { + // Split on 'T' to handle timestamps + const datePart = tempDate.split('T')[0]; + // If there's no time component, parse in local timezone by appending T00:00:00 + const dateStr = tempDate.includes('T') ? tempDate : `${datePart}T00:00:00`; + // Create a Date object from the parts + const dateObj = new Date(dateStr); + createdDate = formatDate(dateObj, this.settings.dateDisplayFormat); + } else { + createdDate = createdDate; + } } else { createdDate = new Date(file.stat.ctime); - createdDate = `${createdDate.toLocaleString('default', { month: 'long' })} ${createdDate.getDate()}, ${createdDate.getFullYear()}`; + createdDate = formatDate(createdDate, this.settings.dateDisplayFormat); } datesWrapper.createDiv({ cls: 'rich-foot--created-date', @@ -582,17 +739,6 @@ class RichFootSettingTab extends PluginSettingTab { this.plugin.updateRichFoot(); })); - new Setting(containerEl) - .setName('Show Dates') - .setDesc('Show creation and modification dates in the footer') - .addToggle(toggle => toggle - .setValue(this.plugin.settings.showDates) - .onChange(async (value) => { - this.plugin.settings.showDates = value; - await this.plugin.saveSettings(); - this.plugin.updateRichFoot(); - })); - // Add Date Settings containerEl.createEl('h3', { text: 'Date Settings' }); @@ -607,6 +753,40 @@ class RichFootSettingTab extends PluginSettingTab { this.plugin.updateRichFoot(); })); + new Setting(containerEl) + .setName('Date Display Format') + .setDesc('Choose how dates should be displayed in the footer') + .addDropdown(dropdown => { + const today = new Date(); + const formats = [ + 'mm/dd/yyyy', + 'dd/mm/yyyy', + 'yyyy-mm-dd', + 'mmm dd, yyyy', + 'dd mmm yyyy', + 'mmmm dd, yyyy', + 'ddd, mmm dd, yyyy', + 'dddd, mmmm dd, yyyy', + 'mm/dd/yy', + 'dd/mm/yy', + 'yy-mm-dd', + 'm/d/yy' + ]; + + formats.forEach(format => { + const example = formatDate(today, format); + dropdown.addOption(format, `${format} (example: ${example})`); + }); + + dropdown + .setValue(this.plugin.settings.dateDisplayFormat) + .onChange(async (value) => { + this.plugin.settings.dateDisplayFormat = value; + await this.plugin.saveSettings(); + this.plugin.updateRichFoot(); + }); + }); + new Setting(containerEl) .setName('Custom Created Date Property') .setDesc('Specify a frontmatter property to use for creation date (leave empty to use file creation date)') diff --git a/styles.css b/styles.css index 5513eaf..0462a84 100644 --- a/styles.css +++ b/styles.css @@ -156,12 +156,19 @@ body.theme-light .rich-foot--backlinks ul li a { padding-bottom: 0 !important; } +/* fix note embed height scroll in canvas */ +.canvas-node-content.markdown-embed div.cm-sizer, +.canvas-node-content.markdown-embed div.markdown-preview-sizer { + min-height: unset !important; +} + + .cm-sizer .rich-foot--backlinks { margin-top: 0; } .markdown-preview-sizer > div { - flex: 0; + flex: 0 auto; } .markdown-preview-sizer > .rich-foot {