From b5058a1721248c968e1f58a1ecbede32081f802d Mon Sep 17 00:00:00 2001 From: Jalad Date: Tue, 19 May 2026 02:50:46 -0500 Subject: [PATCH] Added ability for user to toggle showing the last modified date time of a contact note file in the settings tab under Contact Note section. This only shows it in the contact note contact card. Also updated readme to include information on this new setting. --- README.md | 8 +++++++- src/ContactCard.ts | 32 ++++++++++++++++++++++++-------- src/ContactNoteSettingTab.ts | 15 +++++++++++++++ src/main.ts | 2 +- styles.css | 21 +++++++++++++++++---- 5 files changed, 64 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 81f472f..1777241 100644 --- a/README.md +++ b/README.md @@ -185,7 +185,7 @@ Platforms not in this list will still display the handle as plain text without a ![Contact card](assets/screenshots/contact-card.png) -In reading mode, any contact note with a valid `firstName` and `lastName` frontmatter renders a contact card in place of the frontmatter block. The card displays the contact's photo, name, title, company, department, birthday, email addresses, phone numbers, social media profiles, and the date of last interaction. +In reading mode, any contact note with a valid `firstName` and `lastName` frontmatter renders a contact card in place of the frontmatter block. The card displays the contact's photo, name, title, company, department, birthday, email addresses, phone numbers, social media profiles, the date of last interaction, and the date the note was last modified. ### Display Name Resolution @@ -381,6 +381,12 @@ The simplest way to add a contacts view to an existing base is to run **Add cont > The base file name and the in-base view name are entered in the dialog opened by **Create new base with contacts view** or **Add contacts view to base**, not in settings. +### Contact Card + +| Setting | Description | Default | +|---|---|---| +| Show last modified date | Show the date the contact note was last modified in the top-left corner of the contact card. Applies only to the card rendered inside a contact note, not the panel or base views. | Enabled | + ### Frontmatter Properties Customization This section lets you override the frontmatter property names the plugin reads from and writes to, and the icons it displays for properties that show one. diff --git a/src/ContactCard.ts b/src/ContactCard.ts index 3dd56d4..9be3c74 100644 --- a/src/ContactCard.ts +++ b/src/ContactCard.ts @@ -52,6 +52,7 @@ interface ContactCardOptions { lastNameFirst?: boolean; showBirthday?: boolean; showLastInteraction?: boolean; + showLastModified?: boolean; } //#endregion @@ -66,7 +67,7 @@ export function buildContactCard( contact: Contact, options: ContactCardOptions = {} ) { - const { condensed = false, clickable = false, showDetails = true, lastNameFirst: lastNameFirst = false, showBirthday = false, showLastInteraction = false } = options; + const { condensed = false, clickable = false, showDetails = true, lastNameFirst: lastNameFirst = false, showBirthday = false, showLastInteraction = false, showLastModified = false } = options; const displayName = resolveDisplayName(contact, lastNameFirst); const card = container.createDiv({ cls: `${pluginId}-card` }); @@ -93,13 +94,28 @@ export function buildContactCard( return errorEl; } - // Last Interaction - if (showLastInteraction && contact.lastInteraction) { - const lastInteractionEl = card.createDiv({ cls: `${pluginId}-card-last-interaction` }); - const lastInteractionField = contactNote.getField("lastInteraction"); - const iconEl = lastInteractionEl.createSpan({ cls: `${pluginId}-card-last-interaction-icon` }); - setIcon(iconEl, contactNote.getIcon(lastInteractionField!) ?? ""); - lastInteractionEl.createSpan({ text: contact.lastInteraction }); + /* Last Interaction and Last Modified */ + const showModified = showLastModified; + const showInteraction = showLastInteraction && contact.lastInteraction; + if (showModified || showInteraction) { + const stripEl = card.createDiv({ cls: `${pluginId}-card-top-strip` }); + + // Last Modified + if (showModified) { + const modifiedEl = stripEl.createDiv({ cls: `${pluginId}-card-last-modified` }); + const iconEl = modifiedEl.createSpan({ cls: `${pluginId}-card-last-modified-icon` }); + setIcon(iconEl, "file-clock"); + modifiedEl.createSpan({ text: new Date(contact.file.stat.mtime).toLocaleString(undefined, { year: "numeric", month: "short", day: "numeric", hour: "numeric", minute: "2-digit" }) }); + } + + // Last Interaction + if (showInteraction) { + const interactionEl = stripEl.createDiv({ cls: `${pluginId}-card-last-interaction` }); + const lastInteractionField = contactNote.getField("lastInteraction"); + const iconEl = interactionEl.createSpan({ cls: `${pluginId}-card-last-interaction-icon` }); + setIcon(iconEl, contactNote.getIcon(lastInteractionField!) ?? ""); + interactionEl.createSpan({ text: contact.lastInteraction }); + } } /* Photo */ diff --git a/src/ContactNoteSettingTab.ts b/src/ContactNoteSettingTab.ts index 4f6e854..b9aa560 100644 --- a/src/ContactNoteSettingTab.ts +++ b/src/ContactNoteSettingTab.ts @@ -16,6 +16,7 @@ export interface ContactNoteSettings { tag: string; viewName: string; baseFolderPath: string; + showLastModified: boolean; frontmatterCustomizations: Record; } @@ -29,6 +30,7 @@ export const DEFAULT_SETTINGS: ContactNoteSettings = { tag: "contact", viewName: "Contacts", baseFolderPath: "", + showLastModified: true, frontmatterCustomizations: {} }; @@ -139,6 +141,19 @@ export class ContactNoteSettingTab extends PluginSettingTab { new FolderSuggest(this.app, text.inputEl); }); + /* Contact Card */ + new Setting(containerEl).setName("Contact card").setHeading(); + + new Setting(containerEl) + .setName("Show last modified date") + .setDesc("Show the date the contact note was last modified in the top-left corner of the contact card. Applies only to the card rendered inside a contact note, not the panel or base views.") + .addToggle((toggle) => + toggle.setValue(this.plugin.configuration.showLastModified).onChange((value) => { + this.plugin.configuration.showLastModified = value; + void this.plugin.saveConfiguration(); + }) + ); + /* Frontmatter Properties Customization */ new Setting(containerEl).setName("Frontmatter properties customization").setHeading(); diff --git a/src/main.ts b/src/main.ts index 1e47371..c56acb6 100644 --- a/src/main.ts +++ b/src/main.ts @@ -167,7 +167,7 @@ export default class ContactNotePlugin extends Plugin { if (!ctx.frontmatter) return; const cache = this.app.metadataCache.getFileCache(file); const contact = Contact.fromCache(file, ctx.frontmatter as Record, cache?.frontmatterLinks, this.contactNote); - buildContactCard(this.manifest.id, this.app, this.contactNote, el, contact, { showDetails: true, lastNameFirst: false, showBirthday: true, showLastInteraction: true }); + buildContactCard(this.manifest.id, this.app, this.contactNote, el, contact, { showDetails: true, lastNameFirst: false, showBirthday: true, showLastInteraction: true, showLastModified: this.configuration.showLastModified }); }); } diff --git a/styles.css b/styles.css index 496d930..2dbda6c 100644 --- a/styles.css +++ b/styles.css @@ -84,24 +84,37 @@ gap: 6px; } -/* Last Interaction */ -.contact-note-card-last-interaction { +/* Last Modified and Last Interaction */ +.contact-note-card-top-strip { width: 100%; display: flex; - justify-content: flex-end; + justify-content: space-between; align-items: center; - gap: 6px; + gap: 12px; font-size: var(--font-ui-small); color: var(--text-muted); line-height: 1.3; } +.contact-note-card-last-modified, +.contact-note-card-last-interaction { + display: flex; + align-items: center; + gap: 6px; +} + +.contact-note-card-last-interaction { + margin-inline-start: auto; +} + +.contact-note-card-last-modified-icon, .contact-note-card-last-interaction-icon { display: flex; align-items: center; flex-shrink: 0; } +.contact-note-card-last-modified-icon svg, .contact-note-card-last-interaction-icon svg { width: 14px; height: 14px;