Files
thpeetz-notes/.obsidian/plugins/friend-tracker/main.js
T

11 lines
34 KiB
JavaScript

/*
THIS IS A GENERATED/BUNDLED FILE BY ESBUILD
if you want to view the source, please visit the github repository of this plugin
*/
var U=Object.defineProperty;var tt=Object.getOwnPropertyDescriptor;var et=Object.getOwnPropertyNames;var nt=Object.prototype.hasOwnProperty;var at=(p,c)=>{for(var t in c)U(p,t,{get:c[t],enumerable:!0})},it=(p,c,t,e)=>{if(c&&typeof c=="object"||typeof c=="function")for(let n of et(c))!nt.call(p,n)&&n!==t&&U(p,n,{get:()=>c[n],enumerable:!(e=tt(c,n))||e.enumerable});return p};var rt=p=>it(U({},"__esModule",{value:!0}),p);var st={};at(st,{default:()=>_});module.exports=rt(st);var b=require("obsidian");var q={contactsFolder:"FriendTracker",defaultSortColumn:"daysUntilBirthday",defaultSortDirection:"asc",relationshipTypes:["family","friend","colleague","pet"],defaultActiveTab:"notes"};var k=require("obsidian");var G=require("obsidian"),I=class{constructor(c){this.view=c}async render(c,t,e){let n=c.createEl("div",{cls:"friend-tracker-header"});n.createEl("h2",{text:"Friend tracker"}),n.createEl("button",{text:"Add contact",cls:"friend-tracker-button button-outlined"}).addEventListener("click",()=>this.view.openAddContactModal());let i=c.createEl("div",{cls:"friend-tracker-content"});if(t.length===0){i.createEl("div",{cls:"friend-tracker-empty-state"}).createEl("p",{text:"No contacts found. Get started by creating your first contact!"});return}let s=i.createEl("div",{cls:"friend-tracker-table-container"}).createEl("table",{cls:"friend-tracker-table"});this.renderTableHeader(s,e),this.renderTableRows(s,t)}renderTableHeader(c,t){let e=c.createEl("tr");[{key:"name",label:"Name",sortable:!0},{key:"age",label:"Age",sortable:!0},{key:"birthday",label:"Birthday",sortable:!0},{key:"daysUntilBirthday",label:"Days left",sortable:!0},{key:"relationship",label:"Type",sortable:!0},{key:"lastInteraction",label:"Last interaction",sortable:!0},{key:"actions",label:"",sortable:!1}].forEach(({key:a,label:i,sortable:r})=>{let s=e.createEl("th");if(r){let o=s.createEl("button",{cls:"friend-tracker-sort-button"});o.createEl("span",{text:i}),o.createEl("span",{cls:"sort-indicator",text:t.column===a?t.direction==="asc"?"\u2191":"\u2193":""}),o.addEventListener("click",()=>{a!=="actions"&&this.view.handleSort(a)})}else s.setText(i)})}renderTableRows(c,t){this.sortContacts(t,this.view.currentSort).forEach(n=>{var o;let a=c.createEl("tr"),i=this.renderNameCell(n);a.appendChild(i),i.addEventListener("click",l=>{l.stopPropagation(),this.view.openContact(n.file)}),a.createEl("td",{text:((o=n.age)==null?void 0:o.toString())||"N/A"}),a.createEl("td",{text:n.formattedBirthday||"N/A"}),a.createEl("td",{text:n.daysUntilBirthday!==null?`${n.daysUntilBirthday} days`:"N/A"}),a.createEl("td",{text:n.relationship||"N/A",cls:"friend-tracker-relationship-cell"}),a.createEl("td",{text:n.lastInteraction||""});let s=a.createEl("td",{cls:"friend-tracker-actions"}).createEl("button",{cls:"friend-tracker-delete-button",attr:{"aria-label":"Remove contact"}});(0,G.setIcon)(s,"trash"),s.addEventListener("click",l=>{l.stopPropagation(),this.view.openDeleteModal(n.file)})})}renderNameCell(c){let t=document.createElement("td");if(t.className="friend-tracker-name-cell",c.daysUntilBirthday!==null)if(c.daysUntilBirthday===0){let e=t.createEl("div",{cls:"table-birthday-indicator birthday-today",text:"\u{1F382}"})}else c.daysUntilBirthday<=7&&t.createEl("div",{cls:"table-birthday-status-dot"}).createEl("div",{cls:"table-birthday-status-dot-inner"});return t.createSpan({text:c.name}),t}sortContacts(c,t){return[...c].sort((e,n)=>{if(t.column==="birthday"){let s=new Date(e.birthday),o=new Date(n.birthday),l=(s.getMonth()+1)*100+s.getDate(),d=(o.getMonth()+1)*100+o.getDate();return t.direction==="asc"?l-d:d-l}if(t.column==="daysUntilBirthday")return e.daysUntilBirthday===null&&n.daysUntilBirthday===null?0:e.daysUntilBirthday===null?1:n.daysUntilBirthday===null?-1:(e.daysUntilBirthday-n.daysUntilBirthday)*(t.direction==="asc"?1:-1);let a=e[t.column],i=n[t.column];if(!a&&!i)return 0;if(!a)return 1;if(!i)return-1;let r=t.direction==="asc"?1:-1;if(t.column==="relationship"||t.column==="name"){let s=String(a).toLowerCase(),o=String(i).toLowerCase();return s<o?-r:s>o?r:0}else if(typeof a=="number"&&typeof i=="number")return(a-i)*r;return a<i?-r:a>i?r:0})}};var C=require("obsidian"),S=class{constructor(c){this.plugin=c}async getContacts(){var i;let c=this.plugin.settings.contactsFolder,t=this.plugin.app.vault,e=t.getFolderByPath(c);if(!e)return new C.Notice("Friend Tracker folder not found."),[];let n=e.children.filter(r=>r instanceof C.TFile),a=[];for(let r of n)if(r instanceof C.TFile)try{let o=(await t.read(r)).match(/^---\n([\s\S]*?)\n---/);if(o){let l=(0,C.parseYaml)(o[1]),d=((i=l.interactions)==null?void 0:i.length)>0?this.formatDaysAgo(l.interactions[0].date):null;a.push({name:l.name||"Unknown",birthday:l.birthday||"",formattedBirthday:this.formatBirthday(l.birthday),relationship:l.relationship||"",age:this.calculateAge(l.birthday),daysUntilBirthday:this.calculateDaysUntilBirthday(l.birthday),lastInteraction:d,file:r})}}catch(s){console.error(`Error reading contact file ${r.path}:`,s)}return a}calculateAge(c){if(!c)return null;let[t,e,n]=c.split("-").map(Number),a=new Date(t,e-1,n);if(a.setHours(0,0,0,0),isNaN(a.getTime()))return null;let i=new Date;i.setHours(0,0,0,0);let r=i.getFullYear()-a.getFullYear(),s=i.getMonth()-a.getMonth();return(s<0||s===0&&i.getDate()<a.getDate())&&r--,r}calculateDetailedAge(c){if(!c)return"";let[t,e,n]=c.split("-").map(Number),a=new Date(t,e-1,n);if(a.setHours(0,0,0,0),isNaN(a.getTime()))return"";let i=new Date;i.setHours(0,0,0,0);let r=i.getFullYear()-a.getFullYear(),s=i.getMonth()-a.getMonth(),o=i.getDate()-a.getDate();if(o<0){s--;let d=new Date(i.getFullYear(),i.getMonth(),0);o+=d.getDate()}s<0&&(r--,s+=12);let l=[];return r>0&&l.push(`${r} ${r===1?"year":"years"}`),s>0&&l.push(`${s} ${s===1?"month":"months"}`),o>0&&l.push(`${o} ${o===1?"day":"days"}`),l.join(", ")+" old"}formatBirthday(c){if(!c)return"";let[t,e,n]=c.split("-").map(Number),a=new Date(t,e-1,n);return a.setHours(0,0,0,0),isNaN(a.getTime())?c:a.toLocaleDateString("en-US",{month:"long",day:"numeric"})}calculateDaysUntilBirthday(c){if(!c)return null;let[t,e,n]=c.split("-").map(Number),a=new Date(t,e-1,n);if(a.setHours(0,0,0,0),isNaN(a.getTime()))return null;let i=new Date;i.setHours(0,0,0,0);let r=new Date(i.getFullYear(),a.getMonth(),a.getDate());r.setHours(0,0,0,0),r<i&&r.setFullYear(i.getFullYear()+1);let s=r.getTime()-i.getTime();return Math.round(s/(1e3*60*60*24))}formatDaysAgo(c){let t=new Date(c),n=new Date().getTime()-t.getTime();return`${Math.floor(n/(1e3*60*60*24))} days`}};var g=require("obsidian");var f={NAME:"name",BIRTHDAY:"birthday",EMAIL:"email",PHONE:"phone",ADDRESS:"address",RELATIONSHIP:"relationship",INTERACTIONS:"interactions",CREATED:"created",UPDATED:"updated",NOTES:"notes",EXTRAS:"extras"},W=[f.NAME,f.INTERACTIONS,f.CREATED,f.UPDATED,f.NOTES,f.EXTRAS],ut={[f.BIRTHDAY]:"date",[f.PHONE]:"tel",[f.EMAIL]:"email"};function Y(p,c,t="",e){let n=p.createEl("input",{cls:"friend-tracker-modal-input",attr:{type:"text",value:t||"",placeholder:"Friend, Family, Colleague, etc.",list:"relationship-types",autocomplete:"on",role:"combobox","aria-autocomplete":"list"}}),a=document.getElementById("relationship-types");a||(a=document.createElement("datalist"),a.id="relationship-types",document.body.appendChild(a));let i=r=>{a.empty(),c.settings.relationshipTypes.filter(o=>!r||o.includes(r.toLowerCase())).forEach(o=>{let l=a.createEl("option");l.text=o.charAt(0).toUpperCase()+o.slice(1)})};return i(),n.addEventListener("input",()=>{i(n.value)}),e&&n.addEventListener("change",()=>{e(n.value)}),n}var M=class{constructor(c){this.view=c}createRelationshipField(c,t){let e=Y(c,this.view.plugin,t,async n=>{let a=n.toLowerCase();if(await this.view.updateContactData(f.RELATIONSHIP,a),a&&!this.view.getRelationshipTypes().includes(a)){let i=this.view.getRelationshipTypes().filter(r=>r.toLowerCase()!==a);await this.view.addRelationshipType(a,i)}});e.className="contact-field-input"}createInfoField(c,t,e){let n=c.createEl("div",{cls:"contact-field"});n.createEl("label",{text:t}),t.toLowerCase()===f.BIRTHDAY?this.createBirthdayField(n,e):t.toLowerCase()===f.PHONE?this.createPhoneField(n,e):t.toLowerCase()===f.RELATIONSHIP?this.createRelationshipField(n,e):this.createTextField(n,t,e)}createBirthdayField(c,t){let e=c.createEl("input",{cls:"contact-field-input",attr:{type:"date",value:t||"",placeholder:"YYYY-MM-DD",pattern:"\\d{4}-\\d{2}-\\d{2}"}});e.addEventListener("change",async()=>{if(!this.view.file)return;let n=e.value;await this.view.updateContactData("birthday",n)})}createPhoneField(c,t){let e=c.createEl("input",{cls:"contact-field-input",attr:{type:"tel",value:t||"",placeholder:"+1234567890",pattern:"^[0-9+\\-]*$"}});e.addEventListener("input",n=>{let a=n.target;a.value=a.value.replace(/[^0-9+-]/g,"")}),e.addEventListener("change",async()=>{await this.view.updateContactData("phone",e.value)})}createTextField(c,t,e){let n=c.createEl("input",{cls:"contact-field-input",attr:{type:"text",value:e||"",placeholder:"Not set"}});n.addEventListener("change",async()=>{await this.view.updateContactData(t.toLowerCase(),n.value)})}};var $=require("obsidian"),B=class{constructor(c){this.view=c}render(c,t){let e=c.createEl("div",{cls:"contact-interactions-list"});[...t].sort((a,i)=>new Date(i.date).getTime()-new Date(a.date).getTime()).forEach((a,i)=>{this.createInteractionItem(e,a,i)})}createInteractionItem(c,t,e){let n=c.createEl("div",{cls:"contact-interaction-item"}),[a,i,r]=t.date.split("-").map(Number),o=new Date(a,i-1,r).toLocaleDateString(void 0,{year:"numeric",month:"short",day:"numeric"});n.createEl("div",{cls:"contact-interaction-date",text:o}),n.createEl("div",{cls:"contact-interaction-text",text:t.text});let l=n.createEl("div",{cls:"contact-interaction-actions"}),d=l.createEl("button",{cls:"friend-tracker-button button-icon",attr:{"aria-label":"Edit interaction"}});(0,$.setIcon)(d,"pencil"),d.addEventListener("click",()=>{this.view.openEditInteractionModal(e,t)});let u=l.createEl("button",{cls:"friend-tracker-button button-icon button-danger",attr:{"aria-label":"Delete interaction"}});(0,$.setIcon)(u,"trash"),u.addEventListener("click",()=>{this.view.deleteInteraction(e)})}};var K=require("obsidian"),N=class extends K.Modal{constructor(t,e){super(t);this.onSubmit=e}onOpen(){let{contentEl:t}=this;t.empty(),t.createEl("h2",{text:"Add custom field"});let e=t.createEl("form");e.addEventListener("submit",a=>{a.preventDefault();let i=e.querySelector("input");i!=null&&i.value&&(this.onSubmit(i.value.toLowerCase()),this.close())}),e.createEl("input",{attr:{type:"text",placeholder:"Field name",pattern:"[a-zA-Z][a-zA-Z0-9]*"},cls:"contact-field-input"}).focus(),e.createEl("button",{text:"Add field",attr:{type:"submit"},cls:"friend-tracker-button button-primary button-full-width"})}onClose(){let{contentEl:t}=this;t.empty()}};var Z=require("obsidian"),x=class extends Z.Modal{constructor(t,e,n){super(t);this.interaction=e,this.onSubmit=n}onOpen(){var a,i;let{contentEl:t}=this;t.empty(),t.createEl("h2",{text:this.interaction?"Edit interaction":"Add interaction"});let e=t.createEl("form");e.addEventListener("submit",r=>{r.preventDefault();let s=e.querySelector("[type=date]"),o=e.querySelector("textarea");s!=null&&s.value&&(o!=null&&o.value)&&(this.onSubmit(s.value,o.value),this.close())}),e.createEl("input",{attr:{type:"date",value:((a=this.interaction)==null?void 0:a.date)||new Date().toISOString().split("T")[0],required:"true"},cls:"contact-interaction-date-input"});let n=e.createEl("textarea",{attr:{placeholder:"What happened?",required:"true"},cls:"contact-interaction-text-input"});n.value=((i=this.interaction)==null?void 0:i.text)||"",e.createEl("button",{text:this.interaction?"Save changes":"Add interaction",attr:{type:"submit"},cls:"friend-tracker-button button-primary"})}onClose(){let{contentEl:t}=this;t.empty()}};var D="contact-page-view",R=class extends g.ItemView{constructor(t,e){super(t);this._plugin=e;this._file=null;this.contactData={};this.plugin=e,this.contactFields=new M(this),this.interactionView=new B(this),this.activeTab=this.plugin.settings.defaultActiveTab}getRelationshipTypes(){return this.plugin.settings.relationshipTypes}async addRelationshipType(t,e){this.plugin.settings.relationshipTypes=[...e||this.plugin.settings.relationshipTypes,t],await this.plugin.saveSettings()}getViewType(){return D}getDisplayText(){var t;return((t=this._file)==null?void 0:t.basename)||"Contact"}get file(){return this._file}async setState(t,e){let n=this.app.vault.getFileByPath(t.filePath);n&&await this.setFile(n),await super.setState(t,e)}getState(){var t;return{type:D,filePath:(t=this._file)==null?void 0:t.path}}async setFile(t){var n,a;this._file=t;let e=t.path;try{let i=await this.app.vault.read(t);if(((n=this._file)==null?void 0:n.path)!==e)return;let r=i.match(/^---\n([\s\S]*?)\n---/);this.contactData=r?(0,g.parseYaml)(r[1]):{}}catch(i){console.error(`Error reading contact file ${t.path}:`,i),this.contactData={}}((a=this._file)==null?void 0:a.path)===e&&this.render()}render(){let t=this.containerEl.children[1];if(t.empty(),!this.contactData||!this.contactData.name){t.createEl("div",{text:"No contact data available",cls:"contact-empty-state"});return}let n=t.createEl("div",{cls:"contact-page-header"}).createEl("div",{cls:"contact-name-container"});this.renderNameSection(n);let a=t.createEl("div",{cls:"contact-info-section"});this.renderInfoSection(a);let i=t.createEl("div",{cls:"contact-tabs"});[{id:"notes",icon:"pencil",label:"Notes"},{id:"interactions",icon:"clock",label:"Interactions"},{id:"markdown",icon:"document",label:"Markdown"}].forEach(o=>{let l=i.createEl("button",{cls:`contact-tab ${this.activeTab===o.id?"active":""}`});(0,g.setIcon)(l,o.icon),l.createSpan({text:o.label}),l.addEventListener("click",async()=>{this.activeTab=o.id,this.plugin.settings.defaultActiveTab=o.id,await this.plugin.saveSettings(),this.render()})});let s=t.createEl("div",{cls:"contact-content"});switch(this.activeTab){case"notes":this.renderNotesSection(s);break;case"interactions":this.renderInteractionsSection(s);break;case"markdown":this.renderExtrasSection(s);break}}renderNameSection(t){let n=t.createEl("div",{cls:"contact-name-section"}).createEl("div",{cls:"contact-name-display"}),a=n.createEl("div",{cls:"contact-name-row"}),i=a.createEl("h1",{text:this.contactData.name||"Unnamed Contact"}),r=a.createEl("input",{type:"text",value:this.contactData.name||"",placeholder:"Contact name",cls:"contact-name-input"}),s=a.createEl("button",{cls:"friend-tracker-button button-icon contact-name-edit"});if((0,g.setIcon)(s,"pencil"),this.contactData.birthday){let l=this.plugin.contactOperations.calculateDetailedAge(this.contactData.birthday);n.createEl("span",{text:l,cls:"contact-age-display"});let[d,u,m]=this.contactData.birthday.split("-").map(Number),h=["Rat","Ox","Tiger","Rabbit","Dragon","Snake","Horse","Goat","Monkey","Rooster","Dog","Pig"][(d-4)%12],v=this.getZodiacSign(u,m),V=this.getSeason(u,m),J=this.getBirthstone(u);n.createEl("span",{text:`${v} \u2022 Year of the ${h}`,cls:"contact-age-display"}),n.createEl("span",{text:`${V} baby \u2022 Birthstone: ${J}`,cls:"contact-age-display"});let L=this.calculateDaysUntilBirthday(this.contactData.birthday);if(L!==null){let A=n.createEl("div",{cls:"contact-birthday-countdown"});if(L===0)A.createEl("div",{cls:"table-birthday-indicator birthday-today",text:"\u{1F382}"}),A.createSpan({text:"Birthday today!"});else{L<=7&&A.createEl("div",{cls:"birthday-status-dot"}).createEl("div",{cls:"birthday-status-dot-inner"});let Q=L===1?"Birthday tomorrow!":`${L} days until birthday`;A.createSpan({text:Q})}}}s.addEventListener("click",()=>{r.classList.contains("editing")?o():(i.classList.add("editing"),r.classList.add("editing"),(0,g.setIcon)(s,"checkmark"),r.focus())});let o=async()=>{if(!this._file)return;let l=r.value.trim();if(l&&(this.contactData.name=r.value,await this.saveContactData(),this._file.parent)){let d=`${this._file.parent.path}/${l}.md`;try{await this.app.fileManager.renameFile(this._file,d),new g.Notice("Updated contact name");let u=this.app.workspace.getLeavesOfType(E);for(let m of u){let T=await m.view;if(T instanceof w){await T.refresh();break}}}catch(u){new g.Notice(`Error updating file name: ${u}`)}}i.textContent=r.value||"Unnamed Contact",i.classList.remove("editing"),r.classList.remove("editing"),(0,g.setIcon)(s,"pencil")};r.addEventListener("change",o)}calculateDetailedAge(t){let e=new Date(t+"T00:00:00Z"),n=new Date,a=new Date(Date.UTC(n.getFullYear(),n.getMonth(),n.getDate())),i=a.getUTCFullYear()-e.getUTCFullYear(),r=a.getUTCMonth()-e.getUTCMonth(),s=a.getUTCDate()-e.getUTCDate();if(s<0){r--;let o=new Date(Date.UTC(a.getFullYear(),a.getMonth(),0));s+=o.getUTCDate()}return r<0&&(i--,r+=12),s===0?`${i} years, ${r} months old`:`${i} years, ${r} months, ${s} days old`}calculateDaysUntilBirthday(t){return this.plugin.contactOperations.calculateDaysUntilBirthday(t)}getZodiacSign(t,e){return t===3&&e>=21||t===4&&e<=19?"Aries":t===4&&e>=20||t===5&&e<=20?"Taurus":t===5&&e>=21||t===6&&e<=20?"Gemini":t===6&&e>=21||t===7&&e<=22?"Cancer":t===7&&e>=23||t===8&&e<=22?"Leo":t===8&&e>=23||t===9&&e<=22?"Virgo":t===9&&e>=23||t===10&&e<=22?"Libra":t===10&&e>=23||t===11&&e<=21?"Scorpio":t===11&&e>=22||t===12&&e<=21?"Sagittarius":t===12&&e>=22||t===1&&e<=19?"Capricorn":t===1&&e>=20||t===2&&e<=18?"Aquarius":"Pisces"}getSeason(t,e){return t===3&&e>=20||t===4||t===5||t===6&&e<21?"Spring":t===6&&e>=21||t===7||t===8||t===9&&e<22?"Summer":t===9&&e>=22||t===10||t===11||t===12&&e<21?"Autumn":"Winter"}getBirthstone(t){return{1:"Garnet",2:"Amethyst",3:"Aquamarine",4:"Diamond",5:"Emerald",6:"Pearl",7:"Ruby",8:"Peridot",9:"Sapphire",10:"Opal",11:"Topaz",12:"Turquoise"}[t]||"Unknown"}renderInfoSection(t){let n=t.createEl("div",{cls:"contact-info-section"}).createEl("div",{cls:"contact-fields-container"}),a=()=>{n.empty(),n.classList.remove("editing"),Object.entries(this.contactData).filter(([s])=>!["name","notes","interactions","created","updated"].includes(s)).forEach(([s,o])=>{if(!o)return;let l=n.createEl("div",{cls:"contact-field-view",attr:{"data-field":s.toLowerCase()}});l.createEl("div",{cls:"contact-field-label",text:s});let d=s==="birthday"&&o?(()=>{let[u,m,T]=o.split("-").map(Number),h=new Date(u,m-1,T);return h.setHours(0,0,0,0),h.toLocaleDateString("en-US",{month:"long",day:"numeric",year:"numeric"})})():o;l.createEl("div",{cls:"contact-field-value",text:d})}),n.createEl("button",{cls:"friend-tracker-button",text:"Edit"}).addEventListener("click",()=>{i()})},i=()=>{n.empty(),n.classList.add("editing"),Object.values(f).filter(l=>!W.includes(l)).forEach(l=>{this.createInfoField(n,l,this.contactData[l])});let r=[...W,...Object.values(f).map(l=>l.toLowerCase()),"created","updated"];Object.entries(this.contactData).filter(([l])=>!r.includes(l.toLowerCase())).forEach(([l,d])=>{this.createInfoField(n,l,d)}),n.createEl("button",{cls:"friend-tracker-button button-outlined",text:"Add custom field"}).addEventListener("click",()=>{this.openAddFieldModal()}),n.createEl("button",{cls:"friend-tracker-button button-primary button-full-width",text:"Done"}).addEventListener("click",async()=>{await this.saveContactData(),a()})};a()}createInfoField(t,e,n){let a=t.createEl("div",{cls:"contact-field"});a.createEl("label",{text:e});let i=a.createEl("input",{cls:"contact-field-input",attr:{type:e==="birthday"?"date":"text",placeholder:`Enter ${e.toLowerCase()}`,value:n||"",...e==="relationship"&&{list:"relationship-types"}}});i.addEventListener("change",()=>{this.updateContactData(e,i.value)})}renderNotesSection(t){let n=t.createEl("div",{cls:"contact-notes-section"}).createEl("textarea",{cls:"contact-notes-input",attr:{placeholder:"Add notes about family members, parents' names, or anything else you want to remember..."}});n.value=this.contactData.notes||"",n.addEventListener("input",()=>{this.adjustTextareaHeight(n)}),setTimeout(()=>{this.adjustTextareaHeight(n)},0),n.addEventListener("change",async()=>{this._file&&(this.contactData.notes=n.value,await this.saveContactData())})}renderInteractionsSection(t){let e=t.createEl("div",{cls:"contact-interactions"}),n=e.createEl("div",{cls:"contact-interactions-header"});(!Array.isArray(this.contactData.interactions)||this.contactData.interactions.length===0)&&n.createEl("div",{cls:"section-helper-text",text:"Log meaningful touchpoints like meetings, calls, or important conversations to help maintain strong relationships"}),n.createEl("button",{cls:"friend-tracker-button button-align-right",text:"Add interaction"}).addEventListener("click",()=>{this.openAddInteractionModal()}),Array.isArray(this.contactData.interactions)&&this.interactionView.render(e,this.contactData.interactions)}async renderExtrasSection(t){let e=t.createEl("div",{cls:"contact-extras-section"});if(!this._file)return;let n=e.createEl("div",{cls:"contact-extras-header"});((await this.app.vault.read(this._file)).split(/^---\n([\s\S]*?)\n---/).pop()||"").trim()||n.createEl("div",{cls:"section-helper-text",text:"Add formatted text, links, and other Markdown content"}),n.createEl("button",{cls:"friend-tracker-button button-align-right",text:"Edit markdown"}).addEventListener("click",()=>{var s;this.app.workspace.openLinkText(((s=this._file)==null?void 0:s.path)||"","",!0)});try{let o=(await this.app.vault.read(this._file)).split(/^---\n([\s\S]*?)\n---/).pop()||"";if(o.trim()){let l=e.createEl("div",{cls:"contact-extras-content"});await g.MarkdownRenderer.renderMarkdown(o,l,this._file.path,this),l.addEventListener("click",d=>{var m;let u=d.target;if(u.tagName==="A"){let h=u.getAttribute("href");if(h!=null&&h.startsWith("#")){d.preventDefault();let v=l.querySelector(h);v==null||v.scrollIntoView()}else h!=null&&h.startsWith("http")||(d.preventDefault(),this.app.workspace.openLinkText(h||"",((m=this._file)==null?void 0:m.path)||"",d.ctrlKey||d.metaKey))}})}}catch(s){console.error(`Error reading extras from file ${this._file.path}:`,s)}}adjustTextareaHeight(t){t.classList.add("measuring"),t.style.setProperty("--scroll-height",`${t.scrollHeight}px`),t.classList.remove("measuring")}async saveContactData(){this._file&&(this.contactData.interactions&&this.contactData.interactions.sort((t,e)=>new Date(e.date).getTime()-new Date(t.date).getTime()),await this.app.fileManager.processFrontMatter(this._file,t=>{Object.assign(t,this.contactData)}))}async openAddFieldModal(){new N(this.app,async e=>{this.contactData[e]?new g.Notice("Field already exists!"):(this.contactData[e]="",await this.saveContactData(),this.render())}).open()}async openAddInteractionModal(){new x(this.app,null,async(e,n)=>{Array.isArray(this.contactData.interactions)||(this.contactData.interactions=[]),this.contactData.interactions.push({date:e,text:n}),await this.saveContactData(),this.render()}).open()}async openEditInteractionModal(t,e){new x(this.app,e,async(a,i)=>{Array.isArray(this.contactData.interactions)||(this.contactData.interactions=[]),this.contactData.interactions[t]={date:a,text:i},await this.saveContactData(),this.render()}).open()}async deleteInteraction(t){this.contactData.interactions.splice(t,1),await this.saveContactData(),this.render()}async updateContactData(t,e){this.contactData[t]=e,await this.saveContactData()}};var F=require("obsidian"),z=require("obsidian");var O=class extends F.Modal{constructor(t,e){super(t);this.plugin=e}onOpen(){let{contentEl:t}=this;t.empty(),t.createEl("h2",{text:"Add new contact"});let e=t.createEl("form",{cls:"friend-tracker-add-contact-form"}),n=e.createDiv({cls:"friend-tracker-modal-field"});n.createEl("label",{text:"Name *"});let a=n.createEl("input",{attr:{type:"text",name:"name",required:!0,placeholder:"Contact name"},cls:"friend-tracker-modal-input"});a.focus();let i=e.createDiv({cls:"friend-tracker-modal-field"});i.createEl("label",{text:"Birthday"});let r=i.createEl("input",{attr:{type:"date",name:"birthday",placeholder:"YYYY-MM-DD",pattern:"\\d{4}-\\d{2}-\\d{2}"},cls:"friend-tracker-modal-input"}),s=e.createDiv({cls:"friend-tracker-modal-field"});s.createEl("label",{text:"Email"});let o=s.createEl("input",{attr:{type:"email",name:"email",placeholder:"email@example.com"},cls:"friend-tracker-modal-input"}),l=e.createDiv({cls:"friend-tracker-modal-field"});l.createEl("label",{text:"Phone"});let d=l.createEl("input",{attr:{type:"tel",name:"phone",placeholder:"000-000-0000"},cls:"friend-tracker-modal-input"}),u=e.createDiv({cls:"friend-tracker-modal-field"});u.createEl("label",{text:"Relationship"});let m=Y(u,this.plugin);e.createEl("button",{text:"Create contact",attr:{type:"submit"},cls:"friend-tracker-button button-primary"}),e.addEventListener("submit",T=>{T.preventDefault();let h={name:a.value};if(r.value&&(h.birthday=r.value),o.value&&(h.email=o.value),d.value&&(h.phone=d.value),m.value){let v=m.value.toLowerCase();h.relationship=m.value.toLowerCase(),this.plugin.settings.relationshipTypes.includes(v)||(this.plugin.settings.relationshipTypes=[...new Set(this.plugin.settings.relationshipTypes.filter(V=>V.toLowerCase()!==v)),v],this.plugin.saveSettings())}h.name&&(this.onSubmit(h),this.close())})}async onSubmit(t){let e=`${t.name}.md`,n=`${this.plugin.settings.contactsFolder}/${e}`,a=this.plugin.settings.contactsFolder;this.app.vault.getFolderByPath(a)||await this.app.vault.createFolder(a);let r=`---
${(0,z.stringifyYaml)(t)}
---
`;try{await this.app.vault.create(n,r),await new Promise(o=>setTimeout(o,300));let s=this.app.workspace.getLeavesOfType(E);for(let o of s){let l=o.view;if(l instanceof w){await l.refresh();break}}new F.Notice(`Created contact: ${t.name}`)}catch(s){new F.Notice(`Error creating contact: ${s}`)}}onClose(){let{contentEl:t}=this;t.empty()}};var X=require("obsidian"),H=class extends X.Modal{constructor(t,e,n){super(t);this.file=e;this.onDelete=n}onOpen(){let{contentEl:t}=this;t.empty(),t.createEl("h2",{text:"Delete contact"}),t.createEl("p",{text:`Are you sure you want to delete ${this.file.basename}?`});let e=t.createEl("div",{cls:"friend-tracker-modal-buttons"});e.createEl("button",{text:"Cancel",cls:"friend-tracker-modal-button"}).addEventListener("click",()=>this.close()),e.createEl("button",{text:"Delete",cls:"friend-tracker-modal-button friend-tracker-modal-button-danger"}).addEventListener("click",async()=>{await this.onDelete(),this.close()})}onClose(){let{contentEl:t}=this;t.empty()}};var E="friend-tracker-view",w=class extends k.ItemView{constructor(t,e){super(t);this.plugin=e;this.fileChangeHandler=null;this.isRefreshing=!1;this._contacts=null;this.handleVisibilityChange=()=>{document.visibilityState==="visible"&&this.refresh()};this.handleWindowFocus=()=>{this.refresh()};this.currentSort={column:this.plugin.settings.defaultSortColumn,direction:this.plugin.settings.defaultSortDirection},this.tableView=new I(this),this.contactOps=new S(this.plugin)}async openAddContactModal(){new O(this.app,this.plugin).open()}handleSort(t){this.currentSort.column===t?this.currentSort.direction=this.currentSort.direction==="asc"?"desc":"asc":this.currentSort={column:t,direction:"asc"},this.refresh()}async openContact(t){let e=this.app.workspace.getLeavesOfType(D),n=e.length>0?e[0]:this.app.workspace.getLeaf("tab");await n.setViewState({type:D,state:{filePath:t.path}}),this.app.workspace.setActiveLeaf(n,{focus:!0}),this.app.workspace.revealLeaf(n),k.Platform.isMobile&&this.app.workspace.rightSplit.collapse()}async openDeleteModal(t){new H(this.app,t,async()=>{await this.app.fileManager.trashFile(t),await this.refresh()}).open()}getViewType(){return E}getDisplayText(){return"Friend tracker"}async onOpen(){this.registerEvent(this.app.vault.on("modify",t=>{t instanceof k.TFile&&this.isContactFile(t)&&setTimeout(()=>this.refresh(),100)})),document.addEventListener("visibilitychange",this.handleVisibilityChange),window.addEventListener("focus",this.handleWindowFocus),await this.refresh()}onunload(){document.removeEventListener("visibilitychange",this.handleVisibilityChange),window.removeEventListener("focus",this.handleWindowFocus)}async refresh(){if(!this.isRefreshing){this.isRefreshing=!0;try{this._contacts=null;let t=this.containerEl.children[1];for(;t.firstChild;)t.removeChild(t.firstChild);let e=await this.contactOps.getContacts(),n=this.currentSort.column&&this.currentSort.direction?this.currentSort:{column:"name",direction:"asc"},a=e.sort((r,s)=>{let o=r[n.column],l=s[n.column];return o===null&&l===null?0:o===null?n.direction==="asc"?-1:1:l===null?n.direction==="asc"?1:-1:o<l?n.direction==="asc"?-1:1:o>l?n.direction==="asc"?1:-1:0}),i=t.createDiv();await this.tableView.render(i,a,n)}finally{this.isRefreshing=!1}}}isContactFile(t){let e=this.plugin.settings.contactsFolder;return t.path.startsWith(e+"/")}async sortContacts(t,e){this.currentSort={column:t,direction:e},await this.refresh()}};var y=require("obsidian"),j=class extends y.AbstractInputSuggest{constructor(t,e){super(t,e);this.inputEl=e}getSuggestions(t){return this.app.vault.getAllLoadedFiles().filter(n=>n instanceof y.TFolder).map(n=>n.path).filter(n=>n.toLowerCase().includes(t.toLowerCase()))}renderSuggestion(t,e){e.setText(t)}selectSuggestion(t){this.inputEl.value=t,this.inputEl.trigger("input"),this.close()}},P=class extends y.PluginSettingTab{constructor(t,e){super(t,e);this.plugin=e}display(){let{containerEl:t}=this;t.empty();let e=[{value:"name",label:"Name"},{value:"age",label:"Age"},{value:"birthday",label:"Birthday"},{value:"daysUntilBirthday",label:"Days until birthday"},{value:"relationship",label:"Relationship"},{value:"lastInteraction",label:"Last interaction"}];new y.Setting(t).setName("Contacts folder").setDesc("Folder where contact files will be stored").addText(i=>(new j(this.app,i.inputEl),i.setPlaceholder("Enter folder name").setValue(this.plugin.settings.contactsFolder).onChange(async r=>{this.plugin.settings.contactsFolder=(0,y.normalizePath)(r),await this.plugin.saveSettings()}))),new y.Setting(t).setName("Default sort").setDesc("Choose how contacts are sorted by default").addDropdown(i=>(e.forEach(({value:r,label:s})=>{i.addOption(r,s)}),i.setValue(this.plugin.settings.defaultSortColumn).onChange(async r=>{this.plugin.settings.defaultSortColumn=r,await this.plugin.saveSettings()}))).addDropdown(i=>{i.addOption("asc","Ascending").addOption("desc","Descending").setValue(this.plugin.settings.defaultSortDirection).onChange(async r=>{this.plugin.settings.defaultSortDirection=r,await this.plugin.saveSettings()})});let n=t.createEl("div",{cls:"friend-tracker-relationship-header"});n.createEl("h3",{text:"Relationship types"}),new y.Setting(n).addButton(i=>i.setButtonText("Add relationship type").onClick(async()=>{let r=document.createElement("input");r.type="text",r.placeholder="Enter relationship type",r.className="friend-tracker-modal-input relationship-type-input",i.buttonEl.replaceWith(r),r.focus();let s=async()=>{let l=(r.value||"").trim();if(l){let d=l.toLowerCase();this.plugin.settings.relationshipTypes.includes(d)||(this.plugin.settings.relationshipTypes.push(d),await this.plugin.saveSettings())}setTimeout(()=>this.display(),0)};r.addEventListener("keydown",async o=>{o.key==="Enter"?(o.preventDefault(),await s()):o.key==="Escape"&&this.display()}),r.addEventListener("blur",async()=>{var o;(o=r.value)!=null&&o.trim()?await s():this.display()})}));let a=t.createEl("div",{cls:"friend-tracker-relationship-types"});this.plugin.settings.relationshipTypes.forEach(i=>{new y.Setting(a).addText(r=>r.setValue(i).setPlaceholder("Type name").then(s=>{s.inputEl.addEventListener("keypress",async o=>{o.key==="Enter"&&(o.preventDefault(),s.inputEl.blur())}),s.inputEl.addEventListener("blur",async()=>{let o=s.inputEl.value,l=this.plugin.settings.relationshipTypes.indexOf(i);if(o.toLowerCase()!==i||o!==o.toLowerCase()){let d=o.toLowerCase();this.plugin.settings.relationshipTypes=[...this.plugin.settings.relationshipTypes.filter((u,m)=>m===l||u.toLowerCase()!==d)],this.plugin.settings.relationshipTypes[l]=d,await this.plugin.saveSettings(),setTimeout(()=>this.display(),0)}})})).addExtraButton(r=>{r.setIcon("trash").setTooltip("Delete relationship type").onClick(async()=>{let s=this.plugin.settings.relationshipTypes.indexOf(i);this.plugin.settings.relationshipTypes.splice(s,1),await this.plugin.saveSettings(),this.display()})})}),new y.Setting(t).setName("Default tab").setDesc("Choose which tab opens by default").addDropdown(i=>{i.addOption("notes","Notes").addOption("interactions","Interactions").addOption("markdown","Markdown").setValue(this.plugin.settings.defaultActiveTab).onChange(async r=>{this.plugin.settings.defaultActiveTab=r,await this.plugin.saveSettings()})})}};var _=class extends b.Plugin{async onload(){await this.loadSettings(),this.contactOperations=new S(this),this.app.workspace.onLayoutReady(()=>{this.initialize()})}async initialize(){try{this.registerView(E,t=>new w(t,this)),this.registerView(D,t=>new R(t,this)),this.addRibbonIcon("user","Open friend tracker",async()=>{let t=this.app.workspace,e=t.getLeavesOfType(E);for(let a of e)if(await a.view instanceof w){t.revealLeaf(a);return}let n=t.getRightLeaf(!1);n?(await n.setViewState({type:E,active:!0}),t.revealLeaf(n)):new b.Notice("Could not create Friend Tracker view")}),this.addSettingTab(new P(this.app,this)),await this.checkBirthdays()}catch(t){console.error("Friend Tracker failed to load:",t),new b.Notice("Friend Tracker failed to load: "+t.message)}}async checkBirthdays(){let t=await this.contactOperations.getContacts(),e=t.filter(a=>a.daysUntilBirthday===0);if(e.length>0)if(e.length===1)new b.Notice(`\u{1F382} It's ${e[0].name}'s birthday today!`,8e3);else{let a=e.map(s=>s.name),i=a.pop(),r=a.join(", ")+" and "+i;new b.Notice(`\u{1F382} It's ${r}'s birthday today!`,8e3)}let n=t.filter(a=>a.daysUntilBirthday===1);if(n.length>0)if(n.length===1)new b.Notice(`\u{1F388} ${n[0].name}'s birthday is tomorrow!`,6e3);else{let a=n.map(s=>s.name),i=a.pop(),r=a.join(", ")+" and "+i;new b.Notice(`\u{1F388} ${r}'s birthdays are tomorrow!`,6e3)}}async loadSettings(){this.settings=Object.assign({},q,await this.loadData())}async saveSettings(){await this.saveData(this.settings)}async onunload(){let t=document.getElementById("relationship-types");t&&t.remove()}};
/* nosourcemap */