diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8ebcf1e..c58d0cb 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,10 @@
All notable changes to Rich Foot will be documented in this file.
+## [1.10.5] - 2024-12-26
+### 📦 Updated
+- Support for more date formats in `frontmatter` created/modified fields (ISO, space-separated, and just date)
+
## [1.10.4] - 2024-12-23
### 🐛 Fixed
- Fixed issue with Rich Foot not loading all user defined colors when Obsidian is restarted
diff --git a/UPDATE.md b/UPDATE.md
index 876177a..f5b5775 100644
--- a/UPDATE.md
+++ b/UPDATE.md
@@ -1,5 +1,9 @@
## 🛑 Exclude Me Please
+### [1.10.5] - 2024-12-26
+#### 📦 Updated
+- Support for more date formats in `frontmatter` created/modified fields (ISO, space-separated, and just date)
+
### [1.10.4] - 2024-12-23
#### 🐛 Fixed
- Fixed issue with Rich Foot not loading all user defined colors when Obsidian is restarted
diff --git a/example-vault.zip b/example-vault.zip
index 26e701a..b098ff7 100644
Binary files a/example-vault.zip and b/example-vault.zip differ
diff --git a/example-vault/rich-foot-example/.obsidian/plugins/pexels-banner/data.json b/example-vault/rich-foot-example/.obsidian/plugins/pexels-banner/data.json
index c3f643a..dfdfc36 100644
--- a/example-vault/rich-foot-example/.obsidian/plugins/pexels-banner/data.json
+++ b/example-vault/rich-foot-example/.obsidian/plugins/pexels-banner/data.json
@@ -51,7 +51,7 @@
"showReleaseNotes": true,
"lastVersion": "2.16.2",
"showRefreshIcon": true,
- "showViewImageIcon": false,
+ "showViewImageIcon": true,
"hidePixelBannerFields": true,
"hidePropertiesSectionIfOnlyBanner": true,
"titleColor": "var(--inline-title-color)",
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 29f4177..b29f470 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
@@ -26,5 +26,5 @@
"[data-type=\"thino_view\"]"
],
"frontmatterExclusionField": "",
- "lastVersion": "1.10.3"
+ "lastVersion": "1.10.4"
}
\ 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 347b04b..2583efb 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,35 +107,12 @@ var ReleaseNotesModal = class extends import_obsidian.Modal {
};
// virtual-module:virtual:release-notes
-var releaseNotes = '
\u{1F6D1} Exclude Me Please
\n[1.10.4] - 2024-12-23
\n\u{1F41B} Fixed
\n\n- Fixed issue with Rich Foot not loading all user defined colors when Obsidian is restarted
\n
\n[1.10.3] - 2024-12-14
\n\u{1F41B} Fixed
\n\n- Improved parent selector matching to properly detect and exclude Rich Foot when specified selectors are present in the view or its parent elements
\n
\n[1.10.2] - 2024-12-11
\n\u{1F41B} Fixed
\n\n- Missing
Excluded Folders
section in the settings \n
\n[1.10.1] - 2024-12-10
\n\u{1F41B} Fixed
\n\n- Extra padding on the bottom of the editor in Canvas / Kanban Cards
\n
\n[1.10.0] - 2024-12-08
\n\u2728 Added
\n\n- Exclusion rule via
frontmatter
field \n- Custom exclusions using specified DOM parent selectors for advanced control
\n
\n
\n';
+var releaseNotes = '\u{1F6D1} Exclude Me Please
\n[1.10.5] - 2024-12-26
\n\u{1F4E6} Updated
\n\n- Support for more date formats in
frontmatter
created/modified fields (ISO, space-separated, and just date) \n
\n[1.10.4] - 2024-12-23
\n\u{1F41B} Fixed
\n\n- Fixed issue with Rich Foot not loading all user defined colors when Obsidian is restarted
\n
\n[1.10.3] - 2024-12-14
\n\u{1F41B} Fixed
\n\n- Improved parent selector matching to properly detect and exclude Rich Foot when specified selectors are present in the view or its parent elements
\n
\n[1.10.2] - 2024-12-11
\n\u{1F41B} Fixed
\n\n- Missing
Excluded Folders
section in the settings \n
\n[1.10.1] - 2024-12-10
\n\u{1F41B} Fixed
\n\n- Extra padding on the bottom of the editor in Canvas / Kanban Cards
\n
\n[1.10.0] - 2024-12-08
\n\u2728 Added
\n\n- Exclusion rule via
frontmatter
field \n- Custom exclusions using specified DOM parent selectors for advanced control
\n
\n
\n';
// src/settings.js
var import_obsidian2 = require("obsidian");
-var DEFAULT_SETTINGS = {
- borderWidth: 1,
- borderStyle: "dashed",
- borderOpacity: 1,
- borderRadius: 15,
- datesOpacity: 1,
- linksOpacity: 1,
- showReleaseNotes: true,
- excludedFolders: [],
- dateColor: "var(--text-accent)",
- borderColor: "var(--text-accent)",
- linkColor: "var(--link-color)",
- linkBackgroundColor: "var(--tag-background)",
- linkBorderColor: "rgba(255, 255, 255, 0.204)",
- customCreatedDateProp: "",
- customModifiedDateProp: "",
- dateDisplayFormat: "mmmm dd, yyyy",
- showBacklinks: true,
- showOutlinks: true,
- showDates: true,
- combineLinks: false,
- updateDelay: 3e3,
- excludedParentSelectors: [],
- frontmatterExclusionField: ""
-};
+
+// src/utils.js
function rgbToHex(color) {
if (color.startsWith("hsl")) {
const temp = document.createElement("div");
@@ -188,6 +165,33 @@ function formatDate(date, format) {
});
return result;
}
+
+// src/settings.js
+var DEFAULT_SETTINGS = {
+ borderWidth: 1,
+ borderStyle: "dashed",
+ borderOpacity: 1,
+ borderRadius: 15,
+ datesOpacity: 1,
+ linksOpacity: 1,
+ showReleaseNotes: true,
+ excludedFolders: [],
+ dateColor: "var(--text-accent)",
+ borderColor: "var(--text-accent)",
+ linkColor: "var(--link-color)",
+ linkBackgroundColor: "var(--tag-background)",
+ linkBorderColor: "rgba(255, 255, 255, 0.204)",
+ customCreatedDateProp: "",
+ customModifiedDateProp: "",
+ dateDisplayFormat: "mmmm dd, yyyy",
+ showBacklinks: true,
+ showOutlinks: true,
+ showDates: true,
+ combineLinks: false,
+ updateDelay: 3e3,
+ excludedParentSelectors: [],
+ frontmatterExclusionField: ""
+};
var RichFootSettingTab = class extends import_obsidian2.PluginSettingTab {
constructor(app, plugin) {
super(app, plugin);
@@ -646,42 +650,6 @@ var FolderSuggestModal = class extends import_obsidian2.FuzzySuggestModal {
};
// src/main.js
-function formatDate2(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_obsidian3.Plugin {
async onload() {
await this.loadSettings();
@@ -916,7 +884,7 @@ var RichFootPlugin = class extends import_obsidian3.Plugin {
}
async createRichFoot(file) {
const richFoot = createDiv({ cls: "rich-foot rich-foot--hidden" });
- const richFootDashedLine = richFoot.createDiv({ cls: "rich-foot--dashed-line" });
+ richFoot.createDiv({ cls: "rich-foot--dashed-line" });
const backlinksData = this.app.metadataCache.getBacklinksForFile(file);
const outlinks = await this.getOutlinks(file);
if (this.settings.combineLinks) {
@@ -1032,16 +1000,17 @@ var RichFootPlugin = class extends import_obsidian3.Plugin {
}
}
if (isValidDate) {
- const datePart = tempDate.split("T")[0];
- const dateStr = tempDate.includes("T") ? tempDate : `${datePart}T00:00:00`;
- const dateObj = new Date(dateStr);
- modifiedDate = formatDate2(dateObj, this.settings.dateDisplayFormat);
+ if (!tempDate.includes("T") && !tempDate.includes(" ")) {
+ tempDate = `${tempDate}T00:00:00`;
+ }
+ const dateObj = new Date(tempDate);
+ modifiedDate = formatDate(dateObj, this.settings.dateDisplayFormat);
} else {
modifiedDate = modifiedDate;
}
} else {
modifiedDate = new Date(file.stat.mtime);
- modifiedDate = formatDate2(modifiedDate, this.settings.dateDisplayFormat);
+ modifiedDate = formatDate(modifiedDate, this.settings.dateDisplayFormat);
}
datesWrapper.createDiv({
cls: "rich-foot--modified-date",
@@ -1076,16 +1045,17 @@ var RichFootPlugin = class extends import_obsidian3.Plugin {
}
}
if (isValidDate) {
- const datePart = tempDate.split("T")[0];
- const dateStr = tempDate.includes("T") ? tempDate : `${datePart}T00:00:00`;
- const dateObj = new Date(dateStr);
- createdDate = formatDate2(dateObj, this.settings.dateDisplayFormat);
+ if (!tempDate.includes("T") && !tempDate.includes(" ")) {
+ tempDate = `${tempDate}T00:00:00`;
+ }
+ const dateObj = new Date(tempDate);
+ createdDate = formatDate(dateObj, this.settings.dateDisplayFormat);
} else {
createdDate = createdDate;
}
} else {
createdDate = new Date(file.stat.ctime);
- createdDate = formatDate2(createdDate, this.settings.dateDisplayFormat);
+ createdDate = formatDate(createdDate, this.settings.dateDisplayFormat);
}
datesWrapper.createDiv({
cls: "rich-foot--created-date",
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 b39727c..e1989bd 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.10.4",
+ "version": "1.10.5",
"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/workspace.json b/example-vault/rich-foot-example/.obsidian/workspace.json
index cfeae76..34a71d4 100644
--- a/example-vault/rich-foot-example/.obsidian/workspace.json
+++ b/example-vault/rich-foot-example/.obsidian/workspace.json
@@ -15,7 +15,7 @@
"state": {
"file": "🦶 Rich Foot.md",
"mode": "preview",
- "source": false,
+ "source": true,
"backlinks": false
},
"icon": "lucide-file",
@@ -3378,6 +3378,236 @@
{
"id": "5825c202c1412179",
"type": "leaf",
+ "state": {
+ "type": "empty",
+ "state": {},
+ "icon": "lucide-file",
+ "title": "New tab"
+ }
+ },
+ {
+ "id": "58cbb175b1e021d0",
+ "type": "leaf",
+ "state": {
+ "type": "empty",
+ "state": {},
+ "icon": "lucide-file",
+ "title": "New tab"
+ }
+ },
+ {
+ "id": "1ecf112a5bef5476",
+ "type": "leaf",
+ "state": {
+ "type": "empty",
+ "state": {},
+ "icon": "lucide-file",
+ "title": "New tab"
+ }
+ },
+ {
+ "id": "6c7c4645339063cd",
+ "type": "leaf",
+ "state": {
+ "type": "empty",
+ "state": {},
+ "icon": "lucide-file",
+ "title": "New tab"
+ }
+ },
+ {
+ "id": "46d4d1d12fec7d05",
+ "type": "leaf",
+ "state": {
+ "type": "empty",
+ "state": {},
+ "icon": "lucide-file",
+ "title": "New tab"
+ }
+ },
+ {
+ "id": "358e834d45b842ce",
+ "type": "leaf",
+ "state": {
+ "type": "empty",
+ "state": {},
+ "icon": "lucide-file",
+ "title": "New tab"
+ }
+ },
+ {
+ "id": "836d8dd8e3440b19",
+ "type": "leaf",
+ "state": {
+ "type": "empty",
+ "state": {},
+ "icon": "lucide-file",
+ "title": "New tab"
+ }
+ },
+ {
+ "id": "cfa6590c4831d5f2",
+ "type": "leaf",
+ "state": {
+ "type": "empty",
+ "state": {},
+ "icon": "lucide-file",
+ "title": "New tab"
+ }
+ },
+ {
+ "id": "39008dea0d9a08f7",
+ "type": "leaf",
+ "state": {
+ "type": "empty",
+ "state": {},
+ "icon": "lucide-file",
+ "title": "New tab"
+ }
+ },
+ {
+ "id": "ab2478293c8deb0b",
+ "type": "leaf",
+ "state": {
+ "type": "empty",
+ "state": {},
+ "icon": "lucide-file",
+ "title": "New tab"
+ }
+ },
+ {
+ "id": "cc33c974312c0128",
+ "type": "leaf",
+ "state": {
+ "type": "empty",
+ "state": {},
+ "icon": "lucide-file",
+ "title": "New tab"
+ }
+ },
+ {
+ "id": "90ae53e2a62b7111",
+ "type": "leaf",
+ "state": {
+ "type": "empty",
+ "state": {},
+ "icon": "lucide-file",
+ "title": "New tab"
+ }
+ },
+ {
+ "id": "3974a8d195b7af6d",
+ "type": "leaf",
+ "state": {
+ "type": "empty",
+ "state": {},
+ "icon": "lucide-file",
+ "title": "New tab"
+ }
+ },
+ {
+ "id": "45eda246386b4e48",
+ "type": "leaf",
+ "state": {
+ "type": "empty",
+ "state": {},
+ "icon": "lucide-file",
+ "title": "New tab"
+ }
+ },
+ {
+ "id": "7faf0fc3ff5c1075",
+ "type": "leaf",
+ "state": {
+ "type": "empty",
+ "state": {},
+ "icon": "lucide-file",
+ "title": "New tab"
+ }
+ },
+ {
+ "id": "8ed38d383b0fef94",
+ "type": "leaf",
+ "state": {
+ "type": "empty",
+ "state": {},
+ "icon": "lucide-file",
+ "title": "New tab"
+ }
+ },
+ {
+ "id": "c6b64c6c59683a9d",
+ "type": "leaf",
+ "state": {
+ "type": "empty",
+ "state": {},
+ "icon": "lucide-file",
+ "title": "New tab"
+ }
+ },
+ {
+ "id": "fa96e498f26cdffe",
+ "type": "leaf",
+ "state": {
+ "type": "empty",
+ "state": {},
+ "icon": "lucide-file",
+ "title": "New tab"
+ }
+ },
+ {
+ "id": "bf6c559efc6f85ba",
+ "type": "leaf",
+ "state": {
+ "type": "empty",
+ "state": {},
+ "icon": "lucide-file",
+ "title": "New tab"
+ }
+ },
+ {
+ "id": "48f06b6059f3d67b",
+ "type": "leaf",
+ "state": {
+ "type": "empty",
+ "state": {},
+ "icon": "lucide-file",
+ "title": "New tab"
+ }
+ },
+ {
+ "id": "989c29a17fd427fa",
+ "type": "leaf",
+ "state": {
+ "type": "empty",
+ "state": {},
+ "icon": "lucide-file",
+ "title": "New tab"
+ }
+ },
+ {
+ "id": "01b6e00a0e3ef6bf",
+ "type": "leaf",
+ "state": {
+ "type": "empty",
+ "state": {},
+ "icon": "lucide-file",
+ "title": "New tab"
+ }
+ },
+ {
+ "id": "fb6f8327a3f0b8d2",
+ "type": "leaf",
+ "state": {
+ "type": "empty",
+ "state": {},
+ "icon": "lucide-file",
+ "title": "New tab"
+ }
+ },
+ {
+ "id": "9ccbc65e7fda67bf",
+ "type": "leaf",
"state": {
"type": "Saved Queries View",
"state": {},
@@ -3386,7 +3616,7 @@
}
}
],
- "currentTab": 328
+ "currentTab": 351
}
],
"direction": "horizontal",
@@ -3406,9 +3636,15 @@
"cmdr:Open Plugin Settings: Rich Foot": false
}
},
- "active": "bf09cc60e5809e92",
+ "active": "9ccbc65e7fda67bf",
"lastOpenFiles": [
"🦶 Rich Foot.md",
+ "images/rich-feet-3.jpg",
+ "images/rich-feet-2.jpg",
+ "images/rich-feet.jpg",
+ "pixel-banner-images/calendar-feet.png",
+ "pixel-banner-images/stuffed-links.png",
+ "pixel-banner-images/no-fee-allowed.png",
"releases/v1.7.0 - 📆 Dates Your Way.md",
"releases/v1.8.0 - 🫣 Page Preview Support.md",
"releases/v1.9.0 - 🥙 Stuffed Links.md",
@@ -3424,17 +3660,11 @@
"misc-notes/three.md",
"misc-notes/link test.md",
"misc-notes/link test 2.md",
- "pixel-banner-images/no-fee-allowed.png",
"test.md",
- "images/rich-feet-2.jpg",
- "pixel-banner-images/stuffed-links.png",
- "images/rich-feet-3.jpg",
- "pixel-banner-images/calendar-feet.png",
"pixel-banner-images/feet-dreaming.png",
"misc-notes",
"Pasted image 20241129154754.png",
"note with table.md",
- "images/rich-feet.jpg",
"images",
"exclude/me too",
"exclude",
diff --git a/example-vault/rich-foot-example/images/rich-feet-2.jpg b/example-vault/rich-foot-example/images/rich-feet-2.jpg
index 7703f64..5564ace 100644
Binary files a/example-vault/rich-foot-example/images/rich-feet-2.jpg and b/example-vault/rich-foot-example/images/rich-feet-2.jpg differ
diff --git a/example-vault/rich-foot-example/images/rich-feet-3.jpg b/example-vault/rich-foot-example/images/rich-feet-3.jpg
index 8c7e81d..0f999c2 100644
Binary files a/example-vault/rich-foot-example/images/rich-feet-3.jpg and b/example-vault/rich-foot-example/images/rich-feet-3.jpg differ
diff --git a/example-vault/rich-foot-example/images/rich-feet.jpg b/example-vault/rich-foot-example/images/rich-feet.jpg
index d4f3f2d..9de42a2 100644
Binary files a/example-vault/rich-foot-example/images/rich-feet.jpg and b/example-vault/rich-foot-example/images/rich-feet.jpg differ
diff --git "a/example-vault/rich-foot-example/\360\237\246\266 Rich Foot.md" "b/example-vault/rich-foot-example/\360\237\246\266 Rich Foot.md"
index 0cec460..de8aaed 100644
--- "a/example-vault/rich-foot-example/\360\237\246\266 Rich Foot.md"
+++ "b/example-vault/rich-foot-example/\360\237\246\266 Rich Foot.md"
@@ -1,5 +1,5 @@
---
-banner: images/rich-feet-3.jpg
+banner-shuffle: images
links:
- "[[link test]]"
---
diff --git a/manifest.json b/manifest.json
index b39727c..e1989bd 100644
--- a/manifest.json
+++ b/manifest.json
@@ -1,7 +1,7 @@
{
"id": "rich-foot",
"name": "Rich Foot",
- "version": "1.10.4",
+ "version": "1.10.5",
"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 d8cf444..3f7aced 100644
--- a/src/main.js
+++ b/src/main.js
@@ -1,7 +1,8 @@
-import { Plugin, MarkdownView, debounce, Setting } from 'obsidian';
+import { Plugin, MarkdownView, debounce } from 'obsidian';
import { ReleaseNotesModal } from './modals';
import { releaseNotes } from 'virtual:release-notes';
-import { RichFootSettingTab, FolderSuggestModal, DEFAULT_SETTINGS } from './settings';
+import { RichFootSettingTab, DEFAULT_SETTINGS } from './settings';
+import { formatDate } from './utils';
class RichFootSettings {
constructor() {
@@ -31,134 +32,6 @@ class RichFootSettings {
}
}
-// Helper function to convert HSL to Hex
-function hslToHex(h, s, l) {
- // Evaluate calc expressions if present
- const evalCalc = (expr) => {
- if (typeof expr !== 'string') return expr;
- if (expr.includes('calc(')) {
- // Extract the expression inside calc()
- const calcExpr = expr.match(/calc\((.*?)\)/)[1];
- // Basic evaluation of simple math expressions
- return Function(`'use strict'; return (${calcExpr})`)();
- }
- return parseFloat(expr);
- };
-
- h = evalCalc(h);
- s = evalCalc(s);
- l = evalCalc(l);
-
- l /= 100;
- const a = s * Math.min(l, 1 - l) / 100;
- const f = n => {
- const k = (n + h / 30) % 12;
- const color = l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1);
- return Math.round(255 * color).toString(16).padStart(2, '0');
- };
- return `#${f(0)}${f(8)}${f(4)}`;
-}
-
-// Helper function to convert RGB/RGBA to hex
-function rgbToHex(color) {
- // For HSLA colors, create a temporary div to convert to RGB
- if (color.startsWith('hsl')) {
- const temp = document.createElement('div');
- temp.style.color = color;
- document.body.appendChild(temp);
- color = getComputedStyle(temp).color;
- document.body.removeChild(temp);
- }
-
- // Extract RGB values, handling both RGB and RGBA
- const rgb = color.match(/\d+/g);
- if (!rgb || rgb.length < 3) return '#000000';
-
- // Take only the first 3 values (RGB) and ensure they're valid hex values
- const [r, g, b] = rgb.slice(0, 3).map(x => {
- // Ensure value is between 0-255
- const val = Math.min(255, Math.max(0, Math.round(parseFloat(x))));
- return val.toString(16).padStart(2, '0');
- });
-
- return `#${r}${g}${b}`;
-}
-
-// Add the blendRgbaWithBackground function
-function blendRgbaWithBackground(rgba, backgroundRgb) {
- // Extract foreground RGBA values
- const rgbaMatch = rgba.match(/rgba?\((\d+),\s*(\d+),\s*(\d+),\s*(\d*\.?\d+)\)/);
- if (!rgbaMatch) return null;
-
- const [ , fr, fg, fb, fa] = rgbaMatch.map(Number); // Parse to numbers
- const alpha = fa !== undefined ? fa : 1; // Default alpha to 1 if not provided
-
- // Extract background RGB values
- const rgbMatch = backgroundRgb.match(/rgb\((\d+),\s*(\d+),\s*(\d+)\)/);
- if (!rgbMatch) return null;
-
- const [ , br, bg, bb] = rgbMatch.map(Number); // Parse to numbers
-
- // Blend each channel using the formula: result = fg * alpha + bg * (1 - alpha)
- const r = Math.round(fr * alpha + br * (1 - alpha));
- const g = Math.round(fg * alpha + bg * (1 - alpha));
- const b = Math.round(fb * alpha + bb * (1 - alpha));
-
- // Return the blended color as an RGB string
- 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();
@@ -463,7 +336,7 @@ class RichFootPlugin extends Plugin {
async createRichFoot(file) {
// Remove the duplicate removal here since we're handling it in addRichFoot
const richFoot = createDiv({ cls: 'rich-foot rich-foot--hidden' });
- const richFootDashedLine = richFoot.createDiv({ cls: 'rich-foot--dashed-line' });
+ richFoot.createDiv({ cls: 'rich-foot--dashed-line' });
// Get both backlinks and outlinks data
const backlinksData = this.app.metadataCache.getBacklinksForFile(file);
@@ -610,12 +483,11 @@ class RichFootPlugin extends Plugin {
}
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);
+ // if tempDate doesn't have a time component, add it (using midnight in the current timezone)
+ if (!tempDate.includes('T') && !tempDate.includes(' ')) {
+ tempDate = `${tempDate}T00:00:00`;
+ }
+ const dateObj = new Date(tempDate);
modifiedDate = formatDate(dateObj, this.settings.dateDisplayFormat);
} else {
modifiedDate = modifiedDate;
@@ -664,12 +536,11 @@ class RichFootPlugin extends Plugin {
}
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);
+ // if tempDate doesn't have a time component, add it (using midnight in the current timezone)
+ if (!tempDate.includes('T') && !tempDate.includes(' ')) {
+ tempDate = `${tempDate}T00:00:00`;
+ }
+ const dateObj = new Date(tempDate);
createdDate = formatDate(dateObj, this.settings.dateDisplayFormat);
} else {
createdDate = createdDate;
diff --git a/src/settings.js b/src/settings.js
index c632a76..164ac94 100644
--- a/src/settings.js
+++ b/src/settings.js
@@ -1,6 +1,6 @@
-import { App, PluginSettingTab, Setting, debounce, FuzzySuggestModal } from 'obsidian';
+import { PluginSettingTab, Setting, debounce, FuzzySuggestModal } from 'obsidian';
import { ReleaseNotesModal } from './modals';
-import { releaseNotes } from 'virtual:release-notes';
+import { rgbToHex, formatDate } from './utils';
export const DEFAULT_SETTINGS = {
borderWidth: 1,
@@ -28,132 +28,8 @@ export const DEFAULT_SETTINGS = {
frontmatterExclusionField: '',
};
-// Helper function to convert HSL to Hex
-function hslToHex(h, s, l) {
- // Evaluate calc expressions if present
- const evalCalc = (expr) => {
- if (typeof expr !== 'string') return expr;
- if (expr.includes('calc(')) {
- // Extract the expression inside calc()
- const calcExpr = expr.match(/calc\((.*?)\)/)[1];
- // Basic evaluation of simple math expressions
- return Function(`'use strict'; return (${calcExpr})`)();
- }
- return parseFloat(expr);
- };
-
- h = evalCalc(h);
- s = evalCalc(s);
- l = evalCalc(l);
-
- l /= 100;
- const a = s * Math.min(l, 1 - l) / 100;
- const f = n => {
- const k = (n + h / 30) % 12;
- const color = l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1);
- return Math.round(255 * color).toString(16).padStart(2, '0');
- };
- return `#${f(0)}${f(8)}${f(4)}`;
-}
-
-// Helper function to convert RGB/RGBA to hex
-function rgbToHex(color) {
- // For HSLA colors, create a temporary div to convert to RGB
- if (color.startsWith('hsl')) {
- const temp = document.createElement('div');
- temp.style.color = color;
- document.body.appendChild(temp);
- color = getComputedStyle(temp).color;
- document.body.removeChild(temp);
- }
-
- // Extract RGB values, handling both RGB and RGBA
- const rgb = color.match(/\d+/g);
- if (!rgb || rgb.length < 3) return '#000000';
-
- // Take only the first 3 values (RGB) and ensure they're valid hex values
- const [r, g, b] = rgb.slice(0, 3).map(x => {
- // Ensure value is between 0-255
- const val = Math.min(255, Math.max(0, Math.round(parseFloat(x))));
- return val.toString(16).padStart(2, '0');
- });
-
- return `#${r}${g}${b}`;
-}
-
-// Add the blendRgbaWithBackground function
-function blendRgbaWithBackground(rgba, backgroundRgb) {
- // Extract foreground RGBA values
- const rgbaMatch = rgba.match(/rgba?\((\d+),\s*(\d+),\s*(\d+),\s*(\d*\.?\d+)\)/);
- if (!rgbaMatch) return null;
- const [ , fr, fg, fb, fa] = rgbaMatch.map(Number);
- const alpha = fa !== undefined ? fa : 1;
-
- // Extract background RGB values
- const rgbMatch = backgroundRgb.match(/rgb\((\d+),\s*(\d+),\s*(\d+)\)/);
- if (!rgbMatch) return null;
- const [ , br, bg, bb] = rgbMatch.map(Number);
-
- // Blend each channel using the formula: result = fg * alpha + bg * (1 - alpha)
- const r = Math.round(fr * alpha + br * (1 - alpha));
- const g = Math.round(fg * alpha + bg * (1 - alpha));
- const b = Math.round(fb * alpha + bb * (1 - alpha));
-
- 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.toLowerCase(); // Make case-insensitive
- const replacements = new Map();
-
- sortedTokens.forEach((token, index) => {
- const placeholder = `__${index}__`;
- replacements.set(placeholder, tokens[token]);
- result = result.replace(new RegExp(token, 'gi'), placeholder);
- });
-
- // Replace placeholders with final values
- replacements.forEach((value, placeholder) => {
- result = result.replace(new RegExp(placeholder, 'g'), value);
- });
-
- return result;
-}
export class RichFootSettingTab extends PluginSettingTab {
constructor(app, plugin) {
diff --git a/src/utils.js b/src/utils.js
new file mode 100644
index 0000000..2c996d4
--- /dev/null
+++ b/src/utils.js
@@ -0,0 +1,138 @@
+// ------------------------
+// -- convert HSL to Hex --
+// ------------------------
+export function hslToHex(h, s, l) {
+ // Evaluate calc expressions if present
+ const evalCalc = (expr) => {
+ if (typeof expr !== 'string') return expr;
+ if (expr.includes('calc(')) {
+ // Extract the expression inside calc()
+ const calcExpr = expr.match(/calc\((.*?)\)/)[1];
+ // Basic evaluation of simple math expressions
+ return Function(`'use strict'; return (${calcExpr})`)();
+ }
+ return parseFloat(expr);
+ };
+
+ h = evalCalc(h);
+ s = evalCalc(s);
+ l = evalCalc(l);
+
+ l /= 100;
+ const a = s * Math.min(l, 1 - l) / 100;
+ const f = n => {
+ const k = (n + h / 30) % 12;
+ const color = l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1);
+ return Math.round(255 * color).toString(16).padStart(2, '0');
+ };
+ return `#${f(0)}${f(8)}${f(4)}`;
+}
+
+
+// -----------------------------
+// -- convert RGB/RGBA to hex --
+// -----------------------------
+export function rgbToHex(color) {
+ // For HSLA colors, create a temporary div to convert to RGB
+ if (color.startsWith('hsl')) {
+ const temp = document.createElement('div');
+ temp.style.color = color;
+ document.body.appendChild(temp);
+ color = getComputedStyle(temp).color;
+ document.body.removeChild(temp);
+ }
+
+ // Extract RGB values, handling both RGB and RGBA
+ const rgb = color.match(/\d+/g);
+ if (!rgb || rgb.length < 3) return '#000000';
+
+ // Take only the first 3 values (RGB) and ensure they're valid hex values
+ const [r, g, b] = rgb.slice(0, 3).map(x => {
+ // Ensure value is between 0-255
+ const val = Math.min(255, Math.max(0, Math.round(parseFloat(x))));
+ return val.toString(16).padStart(2, '0');
+ });
+
+ return `#${r}${g}${b}`;
+}
+
+
+// -----------------------------
+// -- blendRgbaWithBackground --
+// -----------------------------
+export function blendRgbaWithBackground(rgba, backgroundRgb) {
+ // Extract foreground RGBA values
+ const rgbaMatch = rgba.match(/rgba?\((\d+),\s*(\d+),\s*(\d+),\s*(\d*\.?\d+)\)/);
+ if (!rgbaMatch) return null;
+
+ const [ , fr, fg, fb, fa] = rgbaMatch.map(Number); // Parse to numbers
+ const alpha = fa !== undefined ? fa : 1; // Default alpha to 1 if not provided
+
+ // Extract background RGB values
+ const rgbMatch = backgroundRgb.match(/rgb\((\d+),\s*(\d+),\s*(\d+)\)/);
+ if (!rgbMatch) return null;
+
+ const [ , br, bg, bb] = rgbMatch.map(Number); // Parse to numbers
+
+ // Blend each channel using the formula: result = fg * alpha + bg * (1 - alpha)
+ const r = Math.round(fr * alpha + br * (1 - alpha));
+ const g = Math.round(fg * alpha + bg * (1 - alpha));
+ const b = Math.round(fb * alpha + bb * (1 - alpha));
+
+ // Return the blended color as an RGB string
+ return `rgb(${r}, ${g}, ${b})`;
+}
+
+
+// ------------------
+// -- format dates --
+// ------------------
+export 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.toLowerCase(); // Make case-insensitive
+ const replacements = new Map();
+
+ sortedTokens.forEach((token, index) => {
+ const placeholder = `__${index}__`;
+ replacements.set(placeholder, tokens[token]);
+ result = result.replace(new RegExp(token, 'gi'), placeholder);
+ });
+
+ // Replace placeholders with final values
+ replacements.forEach((value, placeholder) => {
+ result = result.replace(new RegExp(placeholder, 'g'), value);
+ });
+
+ return result;
+}
\ No newline at end of file