diff --git a/main.js b/main.js index e7fa1ea..5bd7118 100644 --- a/main.js +++ b/main.js @@ -5,7 +5,7 @@ `).trim()),i=[]),i.push(n);return i.some(n=>n.trim())&&t.push(i.join(` `).trim()),t.filter(Boolean)}function be(d,r,e){d.empty();try{(0,$a.setIcon)(d,r)}catch{}let t=d.querySelector("svg");t&&t.querySelector("path, line, circle, rect, polyline, polygon, ellipse")||(d.empty(),d.createSpan({cls:"stashpad-icon-fallback",text:e}))}function Ya(d){if(d instanceof Element&&d.closest(".modal, .modal-container, .suggestion-container, .menu, .prompt"))return!0;let r=new Set([document]);d instanceof Element&&d.ownerDocument&&r.add(d.ownerDocument);for(let e of r)if(e.body?.querySelector(".modal-bg")||e.body?.querySelector(".modal-container .modal")||e.body?.querySelector(".suggestion-container")||e.body?.querySelector(".menu.mod-active"))return!0;return!1}function za(d){let r=[],e=/^([ \t]*)(`{3,})[ \t]*([^\n`]*)\n([\s\S]*?)\n\1\2[ \t]*$/gm,t;for(;(t=e.exec(d))!=null;)r.push({lang:t[3].trim(),code:t[4]});return r}function zi(d){return d.split("/").map(r=>r.split(" ").map(e=>e&&/^[a-z]/.test(e)?e[0].toUpperCase()+e.slice(1):e).join(" ")).join("/")}function Va(d,r,e){let t=new Set(r),i=d.filter(n=>!t.has(n)),s=d.findIndex(n=>t.has(n));if(s<0)return d.slice();switch(e){case"top":return[...r,...i];case"bottom":return[...i,...r];case"up":{let n=Math.max(0,s-1),o=i.slice();return o.splice(n,0,...r),o}case"down":{let n=(()=>{let c=-1;return d.forEach((A,h)=>{t.has(A)&&(c=h)}),c})(),o=0;for(let c=0;c0){let n=t[i-1];return(!/[a-z0-9]/.test(n)?600:500)-Math.min(i,99)}let s=0;for(let n=0;n({t,s:jl(e,t.raw)})).filter(t=>t.s>=0).sort((t,i)=>i.s-t.s||i.t.count-t.t.count||t.t.label.localeCompare(i.t.label)).map(t=>t.t):r}var $a,ci,qt,$t,Vi=Ze(()=>{"use strict";$a=require("obsidian"),ci={lines:"Each line",paragraphs:"Paragraphs (blank line)",headings:"Headings"};qt="__stashpad:tagged__",$t="__stashpad:untagged__"});function _l(d,r){return d===0?0:d>12?d>=24?0:d:r==="am"?d===12?0:d:d===12?12:d+12}function Os(d,r){d.addClass("stashpad-when-pop-time");let e=r.seedPeriod,t=d.createDiv({cls:"stashpad-when-time-display"}),i=t.createEl("input",{cls:"stashpad-when-time-field",attr:{type:"text",inputmode:"numeric",maxlength:"2"}});i.value=String(r.seedH),t.createSpan({cls:"stashpad-when-time-colon",text:":"});let s=t.createEl("input",{cls:"stashpad-when-time-field",attr:{type:"text",inputmode:"numeric",maxlength:"2"}});s.value=String(r.seedM).padStart(2,"0");let n=t.createDiv({cls:"stashpad-when-time-period"}),o=n.createEl("button",{cls:"stashpad-when-time-ampm",text:"AM"});o.type="button";let a=n.createEl("button",{cls:"stashpad-when-time-ampm",text:"PM"});a.type="button";let l=()=>{o.toggleClass("is-active",e==="am"),a.toggleClass("is-active",e==="pm")};l(),o.addEventListener("mousedown",B=>B.preventDefault()),a.addEventListener("mousedown",B=>B.preventDefault()),o.addEventListener("click",B=>{B.preventDefault(),e="am",l()}),a.addEventListener("click",B=>{B.preventDefault(),e="pm",l()});let c=i;i.addEventListener("focus",()=>{c=i,i.select()}),s.addEventListener("focus",()=>{c=s,s.select()});let A=()=>{let E=(parseInt(i.value||"0",10)||0)>12;o.toggleClass("is-disabled",E),a.toggleClass("is-disabled",E),o.disabled=E,a.disabled=E},h=B=>{let E=B.value.replace(/\D/g,"").slice(0,2);if(B.value=E,E===""){B===i&&A();return}let y=parseInt(E,10),Q=B===i?24:59;y>Q&&(B.value=String(Q)),B===i&&A()};for(let B of[i,s])B.addEventListener("input",()=>h(B));A();let p=()=>{let B=parseInt(i.value,10),E=Number.isNaN(B)?12:B,y=parseInt(s.value||"0",10)||0,Q=E>12||E===0;r.onFinalize({hours24:_l(E,e),minutes:y,raw:{hh:E,mm:y,period:e,is24:Q}}),r.close()};r.setOnEnter?.(p);let f=[i,s,o,a],u=(B,E)=>{let y=f.indexOf(B);if(y===-1)return;let Q=(y+E+f.length)%f.length;f[Q].focus()},g=B=>{B.addEventListener("keydown",E=>{E.key==="Enter"?(E.preventDefault(),E.stopPropagation(),p()):E.key==="Escape"?(E.preventDefault(),E.stopPropagation(),r.close()):E.key==="Tab"&&(E.preventDefault(),E.stopPropagation(),u(B,E.shiftKey?-1:1))})},I=d.createDiv({cls:"stashpad-when-time-pad"}),m=["1","2","3","4","5","6","7","8","9","backspace","0","insert"],C=null;for(let B of m){let E=I.createEl("button",{cls:"stashpad-when-time-padbtn"});E.type="button",B==="backspace"?(0,Xa.setIcon)(E,"delete"):B==="insert"?(E.setText("OK"),C=E):E.setText(B),B==="insert"&&E.addClass("is-go"),E.addEventListener("mousedown",y=>y.preventDefault()),E.addEventListener("click",y=>{if(y.preventDefault(),B==="insert"){p();return}if(B==="backspace"){c.value=c.value.slice(0,-1),h(c),c.focus();return}let Q=c.selectionStart===0&&c.selectionEnd===c.value.length&&c.value.length>0,w=2,v=Q||c.value.length>=w?B:c.value+B;c.value=v,h(c),c.focus(),c.setSelectionRange(c.value.length,c.value.length),c===i&&c.value.length>=w&&(s.focus(),s.select())})}C&&f.push(C);for(let B of f)g(B);i.focus(),i.select()}function Za(d){let{hh:r,mm:e,period:t,is24:i}=d.raw;return i?`${r}:${String(e).padStart(2,"0")}`:`${r}:${String(e).padStart(2,"0")}${t}`}var Xa,mo=Ze(()=>{"use strict";Xa=require("obsidian")});function _a(d){let r=Math.floor(4294967296/d)*d,e=new Uint32Array(1),t;do crypto.getRandomValues(e),t=e[0];while(t>=r);return t%d}function Co(d=5){let r=[];for(let e=0;e=1&&s.every(a=>/^[a-zA-Z]+$/.test(a))&&(i=Math.min(i,s.length*11)),ec.has(d.toLowerCase())&&(i=Math.min(i,12));let n=i<36?0:i<56?1:i<76?2:3,o=["Weak \u2014 easily guessed","Fair","Good","Strong"][n];return{bits:i,level:n,label:o}}function tc(d){let r=2166136261;for(let e=0;e>>0).toString(16).padStart(8,"0")}function di(d){let r="stashpad-",e=tc(d),t=64-r.length-1-e.length,i=d.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").slice(0,Math.max(0,t)).replace(/-+$/g,"");return`${r}${i}-${e}`}var ja,ec,Ks=Ze(()=>{"use strict";ja="able acid acorn actor adept agile alarm album alert algae amber amble anchor angle ankle apple april arbor arc arctic arena armor arrow ascot aspen atlas atom attic auburn audio autumn award axis bacon badge bagel baker balmy bamboo banjo barge basil basin batch beach beam bean bear beaver begin belt bench berry birch bison black blade blaze bliss bloom blue board boat bold bolt bonus boost booth borax bother bottle boulder bounce bovine bowl brave bread breeze brick bridge brisk broad bronze brook broom brown brush bubble bucket bug bulb bundle burst cabin cable cacao cactus camel cameo candle canoe canvas canyon cargo carol carrot castle catch cedar cello chalk charm chart cheese cherry chess chime chirp cider cinder circle citrus clamp clay clever cliff cloak clock cloud clover coast cobra cocoa comet coral cosmos cotton couch cougar crane crater cream crest cricket crisp crown crumb crystal cube cumin curio dagger daisy dapper dawn deck deer delta denim depot desert dial diamond dingo ditch dock dodge dolphin domino donut draft dragon drift drum dune dusk eagle early earth easel ebony echo eclipse edge eel eagle elbow elder ember emboss emerald ember emu engine ermine ether ever fable falcon fancy farm fawn feather felt fennel fern ferry fiber fiddle field fig finch flame flask flax fleet flint float flock flora flute focus foam forest fossil fox frame frost fudge garden gecko ginger glacier glade glass glide globe glory glove gnat goat golden gopher gourd grape grass gravel grove guava gull hammer hamlet harbor hatch hazel heron hickory hippo honey hornet hostel ivory ivy jade jaguar jasmine jelly jetty jewel jolly jungle juniper kayak kelp kettle kiwi koala ladle lagoon lamp lantern larch lark lasso lava ledge lemon lentil leopard lever lilac lime linen lizard llama lobby locket lodge lotus lunar lupine lynx maple marble marsh meadow medal melon mellow mentor mesa metro mimic mint mirror mocha morsel moss mottle mural muslin nacho nectar nest noble nomad noodle nougat nutmeg oasis oat ocean ochre olive onyx opal orbit orca otter oval owl oxide oyster pace paddle palm panda pantry papaya parka parsley pasta pearl pebble pelican pepper pewter phantom piano picnic pigeon pilot pine pixel plank plaza plum pocket pollen pond poplar poppy portal potato pottery prairie prism puffin pumice quail quartz quill quilt quince rabbit radish raft rapid raven reed reef relish ribbon ridge rind ripple river robin rocket rope rover ruby rudder rust saffron sage salmon sandal sash satin sauce scout sedge sequin shadow shale shark shell shore shrub silk silo silver siren sketch slate sleet slope sloth smoke snail sonar sorrel spark sparrow spice spire sprig spruce squid stable stamp starling steam stem stilt stone stork storm stove straw stream stucco summit sundae sunset swan sweater syrup tabby talon tango tapir tassel tawny teal tempo thicket thimble thistle thorn thunder tidal tiger timber toffee token topaz torch totem trail tulip tundra turtle tusk twig umber unicorn valley vanilla velvet vermil violet viper vista vivid vortex waffle walnut warbler wasp water weasel wharf wheat whisk willow window winter wisp wombat wonder woven yam yarn yeast yew yodel yonder zebra zenith zephyr zigzag zinc zircon".split(/\s+/).filter(Boolean).filter((d,r,e)=>e.indexOf(d)===r);ec=new Set(["password","passw0rd","password1","123456","12345678","123456789","qwerty","abc123","letmein","welcome","admin","iloveyou","monkey","dragon","sunshine","princess","football","baseball","trustno1","000000","111111","secret"])});var ns={};Oi(ns,{BreadcrumbLevelsModal:()=>_i,ColorPickerModal:()=>Vt,ConfirmDeleteModal:()=>hi,ConfirmModal:()=>j,CustomColorModal:()=>Js,DEFAULT_QUICK_ADJUSTS:()=>tr,DueDatePickerModal:()=>Je,EncryptionPasswordModal:()=>Re,ExportStashModal:()=>ui,ImportDupChoiceModal:()=>ts,ImportLogModal:()=>yo,LogModal:()=>Ai,NoteWorkbench:()=>Xi,NoteWorkbenchModal:()=>pi,NoteWorkbenchView:()=>gi,NotificationHistoryModal:()=>es,OpenDeepLinkModal:()=>ji,ReEncryptReviewModal:()=>is,StashPasswordModal:()=>Zi,TypeToConfirmModal:()=>fi,WORKBENCH_VIEW_TYPE:()=>ss,buildAssigneePicker:()=>sr,parseAdjustMinutes:()=>ir});function ir(d){let r=/^\s*(\d+)\s*(m|h|d|w)\s*$/i.exec(d);if(!r)return null;let e=parseInt(r[1],10);if(!Number.isFinite(e)||e<=0)return null;let t={m:1,h:60,d:1440,w:10080}[r[2].toLowerCase()]??1;return e*t}function er(d,r){let e=d.split(/(\s+)/),t=r.split(/(\s+)/),i=e.length,s=t.length,n=Array.from({length:i+1},()=>new Array(s+1).fill(0));for(let A=i-1;A>=0;A--)for(let h=s-1;h>=0;h--)n[A][h]=e[A]===t[h]?n[A+1][h+1]+1:Math.max(n[A+1][h],n[A][h+1]);let o=[],a=(A,h)=>{let p=o[o.length-1];p&&p.t===A?p.s+=h:o.push({t:A,s:h})},l=0,c=0;for(;l=n[l][c+1]?(a("del",e[l]),l++):(a("ins",t[c]),c++);for(;le.toUpperCase());case"sentence":return d.toLowerCase().replace(/(^\s*\w|[.!?]\s+\w)/g,e=>e.toUpperCase())}}function nc(d,r){let e=d.createDiv({cls:"stashpad-export-content"});e.createEl("label",{cls:"stashpad-export-label",text:"Content"});let t=e.createDiv({cls:"stashpad-export-content-seg"}),i=[{id:"full",label:"Full note"},{id:"frontmatter",label:"Frontmatter only"},{id:"body",label:"Body only"}],s=new Map,n=o=>{s.forEach((a,l)=>a.toggleClass("is-active",l===o)),r(o)};for(let o of i){let a=t.createEl("button",{cls:"stashpad-export-content-opt",text:o.label});a.onclick=l=>{l.preventDefault(),n(o.id)},s.set(o.id,a)}n("full")}function sr(d,r){let e=[...r.initial],t=r.knownAuthors,i=d.createDiv({cls:"stashpad-assign"});i.createDiv({cls:"stashpad-assign-label",text:"Assign to"});let s=i.createDiv({cls:"stashpad-assign-chips"}),n=i.createDiv({cls:"stashpad-assign-input-wrap"}),o=n.createEl("input",{type:"text",cls:"stashpad-assign-input",attr:{placeholder:"Add a person \u2014 type a name\u2026"}}),a=n.createDiv({cls:"stashpad-assign-suggest"});a.setCssStyles({display:"none"});let l=()=>r.onChange([...e]),c=()=>{s.empty(),e.length===0&&s.createSpan({cls:"stashpad-assign-empty",text:"No one yet"});for(let p of e){let f=s.createSpan({cls:"stashpad-assign-chip"});f.createSpan({cls:"stashpad-assign-chip-name",text:p.name});let u=f.createSpan({cls:"stashpad-assign-chip-x",text:"\xD7"});u.title=`Remove ${p.name}`,u.onclick=()=>{e=e.filter(g=>g.id!==p.id),l(),c()}}},A=p=>{p.name.trim()&&(e.some(f=>f.id===p.id)||e.push(p),o.value="",a.setCssStyles({display:"none"}),l(),c(),o.focus())},h=()=>{let p=o.value.trim();a.empty();let f=new Set(e.map(I=>I.id)),g=t.filter(I=>!f.has(I.id)&&Ls(p,I.name)).slice(0,6).map(I=>({label:I.name,onPick:()=>A(I)}));if(p&&!t.some(I=>I.name.toLowerCase()===p.toLowerCase())&&g.push({label:`Create \u201C${p}\u201D`,onPick:()=>A({id:Ae(6),name:p})}),g.length===0){a.setCssStyles({display:"none"});return}a.setCssStyles({display:""});for(let I of g){let m=a.createDiv({cls:"stashpad-assign-suggest-item",text:I.label});m.onmousedown=C=>{C.preventDefault(),I.onPick()}}};o.addEventListener("input",h),o.addEventListener("focus",h),o.addEventListener("keydown",p=>{if(p.key==="Enter"){p.preventDefault();let f=a.querySelector(".stashpad-assign-suggest-item");f&&f.dispatchEvent(new MouseEvent("mousedown"))}else p.key==="Escape"&&a.style.display!=="none"&&(p.stopPropagation(),a.setCssStyles({display:"none"}))}),o.addEventListener("blur",()=>{window.setTimeout(()=>{a.setCssStyles({display:"none"})},120)}),c()}var G,tr,ic,Yt,Ai,hi,Xi,ss,pi,gi,ui,Zi,Re,fi,ji,Js,Wi,Vt,j,_i,Je,zt,es,yo,ts,is,we=Ze(()=>{"use strict";G=require("obsidian");Vi();mo();ce();Ks();pt();tr=["5m","15m","30m","1h","1d","1w"];ic=G.moment,Yt=class Yt extends G.Modal{constructor(e,t,i){super(e);this.text=t;this.jsonlPath=i;this.events=[];this.visible=[];this.shownCount=0;this.typeFilter=null;this.listEl=null;this.footerEl=null;this.countEl=null;this.filterSelEl=null}onOpen(){this.contentEl.empty(),this.titleEl.setText("Stashpad log"),this.modalEl.addClass("stashpad-log-modal"),this.events=[];for(let o of this.text.trim().split(/\r?\n/))if(o)try{this.events.push(JSON.parse(o))}catch{}this.events.reverse();let e=this.contentEl.createDiv({cls:"stashpad-log-toolbar"});if(this.countEl=e.createSpan({cls:"stashpad-log-count"}),this.updateCount(),this.filterSelEl=e.createEl("select",{cls:"stashpad-log-type-filter"}),this.filterSelEl.onchange=()=>this.setTypeFilter(this.filterSelEl.value||null),this.refreshTypeFilter(),!G.Platform.isMobile){let o=e.createEl("button",{text:"Reveal JSONL"});o.onclick=()=>this.shellAct("reveal");let a=e.createEl("button",{text:"Open in default app"});a.onclick=()=>this.shellAct("open")}let t=e.createEl("button",{text:"Copy raw JSONL"}),i=null;t.onclick=async()=>{await navigator.clipboard.writeText(this.text),t.setText("Copied"),i!=null&&window.clearTimeout(i),i=window.setTimeout(()=>{t.setText("Copy raw JSONL"),i=null},1500)};let s=e.createEl("button",{text:"Export copy"});s.onclick=()=>this.exportCopy();let n=e.createEl("button",{cls:"mod-warning",text:"Clear log"});n.onclick=()=>this.clearLog(),this.listEl=this.contentEl.createDiv({cls:"stashpad-log-list"}),this.refreshList(),this.footerEl=this.contentEl.createDiv({cls:"stashpad-log-footer"}),this.renderFooter()}refreshList(){if(this.listEl){if(this.visible=this.typeFilter?this.events.filter(e=>e.type===this.typeFilter):this.events.slice(),this.shownCount=0,this.listEl.empty(),!this.visible.length){this.listEl.createDiv({cls:"stashpad-log-empty",text:this.typeFilter?`No "${this.typeFilter}" events.`:"No events yet."}),this.updateCount();return}this.appendMore(Yt.PAGE)}}setTypeFilter(e){(this.typeFilter??null)!==(e??null)&&(this.typeFilter=e,this.refreshList(),this.renderFooter())}refreshTypeFilter(){if(!this.filterSelEl)return;let e=this.filterSelEl;e.empty();let t=new Map;for(let n of this.events)t.set(n.type,(t.get(n.type)??0)+1);let i=[...t.entries()].sort((n,o)=>o[1]-n[1]||n[0].localeCompare(o[0])),s=e.createEl("option",{text:`All types (${this.events.length})`});s.value="";for(let[n,o]of i){let a=e.createEl("option",{text:`${n} (${o})`});a.value=n}this.typeFilter&&!t.has(this.typeFilter)&&(this.typeFilter=null),e.value=this.typeFilter??""}updateCount(){if(!this.countEl)return;let e=this.visible.length,t=this.typeFilter?`${e} ${this.typeFilter} event${e===1?"":"s"}`:`${e} event${e===1?"":"s"}`;this.shownCount===0||this.shownCount>=e?this.countEl.setText(t):this.countEl.setText(`Showing ${this.shownCount} of ${t}`)}appendMore(e){if(!this.listEl)return;let t=Math.min(this.visible.length,this.shownCount+e);for(let i=this.shownCount;i{this.appendMore(Yt.PAGE),this.renderFooter()},e>Yt.PAGE){let i=this.footerEl.createEl("button",{text:`Load all (${e})`});i.onclick=()=>{this.appendMore(e),this.renderFooter()}}}shellAct(e){try{let t=this.app.vault.adapter.getFullPath?.(this.jsonlPath);if(!t)throw new Error("no full path");let{shell:i}=window.require("electron");e==="reveal"?i.showItemInFolder(t):i.openPath(t)}catch(t){new G.Notice(`Couldn't ${e}: ${t.message}`)}}async exportCopy(){try{let e=(0,G.moment)().format("YYYY-MM-DD_HHmmss"),t=this.jsonlPath.replace(/\/[^/]+$/,"")||"",i=t?`${t}/${e}-log.jsonl`:`${e}-log.jsonl`;return await this.app.vault.adapter.write(i,this.text),new G.Notice(`Exported log \u2192 ${i}`),i}catch(e){return new G.Notice(`Export failed: ${e.message}`),null}}clearLog(){new j(this.app,"Clear log?","A timestamped copy will be saved alongside the active log before it's truncated.","Export & clear",async e=>{if(!(!e||!await this.exportCopy())){try{await this.app.vault.adapter.write(this.jsonlPath,"")}catch(i){new G.Notice(`Clear failed: ${i.message}`);return}this.text="",this.events=[],this.typeFilter=null,this.shownCount=0,this.refreshTypeFilter(),this.refreshList(),this.footerEl&&this.footerEl.empty(),new G.Notice("Log cleared.")}},"Cancel",!0).open()}renderEvent(e){let t=document.createElement("div");t.className=`stashpad-log-row stashpad-log-${e.type}`;let i=(0,G.moment)(e.ts).isValid()?(0,G.moment)(e.ts).format("YYYY-MM-DD HH:mm:ss"):e.ts,s=document.createElement("span");s.className="stashpad-log-ts",s.textContent=i,t.appendChild(s);let n=document.createElement("span");n.className="stashpad-log-type",n.textContent=e.type,t.appendChild(n);let o=document.createElement("span");o.className="stashpad-log-author",o.textContent=e.author?e.author:"\u2014",e.author||o.classList.add("is-empty"),t.appendChild(o);let a=document.createElement("span");return a.className="stashpad-log-msg",a.textContent=this.describe(e),t.appendChild(a),t}describe(e){let t=e.payload??{};switch(e.type){case"create":return`Created "${t.path??e.id}" under ${t.parent??"?"}`;case"delete":{let i=Array.isArray(t.attachmentsRemoved)?t.attachmentsRemoved.length:0,s=t.mergedInto?` (merged into ${t.mergedInto})`:"",n=t.to==="trash"?" \u2192 Trash":"";return`Deleted ${e.id}${n}${s}${i?` \u2014 also removed ${i} attachment${i===1?"":"s"}`:""}`}case"missing":return`Missing: ${t.lastPath??e.id}`;case"parent_change":{let i=t.reason?` (${t.reason})`:"";return`Moved ${e.id} from ${t.from??"null"} \u2192 ${t.to??"null"}${i}`}case"rename":return`Renamed ${t.from??"?"} \u2192 ${t.to??"?"}`;case"reorder":{let i=t.count??1,s=t.dir??"?",n=t.parent??e.id??"?";return`Reordered ${i} note${i===1?"":"s"} (${s}) under ${n}`}case"complete":{let i=t.count??1,s=t.undo?" (undo)":t.redo?" (redo)":"";return`Marked ${i} note${i===1?"":"s"} complete${s}`}case"uncomplete":{let i=t.count??1,s=t.undo?" (undo)":t.redo?" (redo)":"";return`Unmarked ${i} note${i===1?"":"s"}${s}`}case"stash_export":{let i=t.noteCount??"?";return`Exported ${i} note${i===1?"":"s"} \u2192 ${t.path??"?"}`}case"stash_import":{let i=t.noteCount??"?",s=[];t.attachmentsWritten&&s.push(`${t.attachmentsWritten} attachment${t.attachmentsWritten===1?"":"s"}`),t.collisionsRenamed&&s.push(`${t.collisionsRenamed} renamed`);let n=s.length?` (${s.join(", ")})`:"";return`Imported ${i} note${i===1?"":"s"} from ${t.from??"?"} \u2192 ${t.into??"?"}${n}`}case"attachment_add":return`Added attachment ${t.path??e.id}`;case"attachment_remove":return`Removed attachment ${t.path??e.id}`;case"palette_color_add":return`Added palette color ${t.color??e.id}`;case"palette_color_remove":return`Removed palette color ${t.color??e.id}`;case"lock":return`Locked (encrypted) ${e.id}`;case"unlock":return`Unlocked ${e.id}`;case"archive":return`Archived ${e.id}${t.to?` \u2192 ${t.to}`:""}${t.encrypted===!1?" (plaintext)":""}`;case"restore":return`Restored ${e.id}${t.to?` \u2192 ${t.to}`:""} from trash`;default:return JSON.stringify(t)}}onClose(){this.contentEl.empty()}};Yt.PAGE=100;Ai=Yt,hi=class extends G.Modal{constructor(e,t,i,s,n,o){super(e);this.noteTitle=t;this.descendantCount=i;this.attachmentCount=s;this.offerAttachmentDelete=n;this.onChoose=o}onOpen(){this.modalEl?.addClass("stashpad-compact-modal"),this.contentEl.empty(),this.titleEl.setText(`Delete "${this.noteTitle}"?`);let e=[];this.descendantCount>0&&e.push(`${this.descendantCount} descendant note${this.descendantCount===1?"":"s"} will also be deleted.`),this.attachmentCount>0&&e.push(`${this.attachmentCount} attachment${this.attachmentCount===1?"":"s"} found across these notes.`),this.contentEl.createEl("p",{text:e.join(" ")});let t=this.offerAttachmentDelete&&this.attachmentCount>0;if(this.offerAttachmentDelete&&this.attachmentCount>0){let o=this.contentEl.createEl("label",{cls:"stashpad-modal-check"}),a=o.createEl("input",{type:"checkbox"});a.checked=t,a.onchange=()=>{t=a.checked},o.createSpan({text:" Also delete attachments"})}let i=this.contentEl.createDiv({cls:"stashpad-modal-btns"}),s=i.createEl("button",{text:"Cancel"});s.onclick=()=>this.close();let n=i.createEl("button",{cls:"mod-warning",text:"Delete"});n.onclick=()=>{this.close(),this.onChoose(t)}}onClose(){this.contentEl.empty()}};Xi=class{constructor(r,e,t,i,s){this.app=r;this.host=e;this.body=t;this.cb=s;this.surface="split";this.mode="line";this.presetMode="paragraphs";this.nest=!1;this.cursorTextarea=null;this.caseCycleIndex=0;this.cursorText=i.cursorText??t,this.collapsed={orig:G.Platform.isMobile,changes:G.Platform.isMobile,edit:!1},this.lines=t.replace(/\r\n/g,` `).split(` -`),this.lineCursorIdx=i.lineCursorIdx??Math.max(1,Math.min(this.lines.length-1,Math.floor(this.lines.length/2))),i.mode?this.mode=i.mode:this.lines.length<2&&(this.mode="cursor"),i.presetMode&&(this.presetMode=i.presetMode),i.nest!=null&&(this.nest=i.nest),i.surface&&(this.surface=i.surface),this.host.addEventListener("keydown",n=>this.onTabKey(n)),this.render()}visibleFocusables(){return Array.from(this.host.querySelectorAll('button:not([disabled]), input:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])')).filter(e=>e.offsetParent!==null)}onTabKey(r){if(r.key!=="Tab")return;let e=this.visibleFocusables();if(e.length===0)return;let t=e[0],i=e[e.length-1],s=document.activeElement;r.shiftKey&&s===t?(r.preventDefault(),i.focus()):!r.shiftKey&&s===i&&(r.preventDefault(),t.focus())}getState(){return{surface:this.surface,mode:this.mode,presetMode:this.presetMode,nest:this.nest,cursorText:this.cursorTextarea?.value??this.cursorText,lineCursorIdx:this.lineCursorIdx}}async commit(){if(this.surface==="edit"){await this.saveEdit();return}this.mode==="line"?await this.commitLine():this.mode==="cursor"?await this.commitCursor():await this.commitPreset()}async saveEdit(){let r=this.cursorTextarea;r&&(await this.cb.onSave(r.value),this.cb.onDone())}isDirty(){return(this.cursorTextarea?.value??this.cursorText)!==this.body}setSurface(r){this.surface!==r&&(this.surface=r,this.render())}moveDivider(r){return this.mode!=="line"?!1:(this.lineCursorIdx=Math.max(1,Math.min(this.lines.length-1,this.lineCursorIdx+r)),this.render(),!0)}async commitLine(){await this.cb.onSplitAtLine(this.lineCursorIdx,this.nest),this.cb.onDone()}async commitCursor(){let r=this.cursorTextarea;if(!r)return;let e=r.selectionStart;if(e<=0||e>=r.value.length){new G.Notice("Move the cursor inside the text \u2014 neither end can be empty.");return}await this.cb.onSplitAtChar(r.value,e,this.nest),this.cb.onDone()}async commitPreset(){let r=Jt(this.body,this.presetMode);if(r.length<2){new G.Notice("That delimiter wouldn't split this note.");return}await this.cb.onSplitMany(r,this.nest),this.cb.onDone()}render(){if(this.host.empty(),this.host.toggleClass("stashpad-edit-surface",this.surface==="edit"),this.cb.onTitle?.(this.surface==="edit"?"Edit note":"Split note"),this.renderSurfaceToggle(),this.surface==="edit"){this.renderEditSurface();return}this.renderSplitSurface()}renderSurfaceToggle(){let r=this.host.createDiv({cls:"stashpad-split-surface"}),e=G.Platform.isMacOS?"\u2318":"Ctrl+",t=(i,s,n,o)=>{let a=r.createEl("button",{cls:"stashpad-split-surface-btn"});(0,G.setIcon)(a.createSpan({cls:"stashpad-split-btn-icon"}),n),a.createSpan({text:i}),a.createSpan({cls:"stashpad-split-kbd-hint",text:`${e}${o}`}),a.toggleClass("is-active",this.surface===s),a.onmousedown=l=>l.preventDefault(),a.onclick=()=>this.setSurface(s)};t("Edit","edit","pencil-line","E"),t("Split","split","split","S")}renderPopOut(r){if(!this.cb.popOut)return;let e=r.createEl("button",{cls:"stashpad-split-popout-btn"});(0,G.setIcon)(e.createSpan({cls:"stashpad-split-popout-icon"}),"maximize-2"),e.createSpan({text:"Open in a tab"}),e.setAttr("aria-label","Open in a full tab"),e.onmousedown=t=>t.preventDefault(),e.onclick=()=>this.cb.popOut(this.getState())}renderOpenExternal(r){if(!this.cb.onOpenExternal)return;let e=r.createEl("button",{cls:"stashpad-split-popout-btn"});(0,G.setIcon)(e.createSpan({cls:"stashpad-split-popout-icon"}),"pencil"),e.createSpan({text:"Obsidian editor"}),e.setAttr("aria-label","Open in a full Obsidian editor tab"),e.onmousedown=t=>t.preventDefault(),e.onclick=()=>{this.cb.onOpenExternal(),this.cb.close()}}renderEditSurface(){this.renderEditorSections();let r=this.host.createDiv({cls:"stashpad-split-edit-tools"}),e=r.createSpan({cls:"stashpad-split-count"}),t=()=>{let c=this.cursorTextarea?.value??"",A=(c.trim().match(/\S+/g)||[]).length;e.setText(`${A} word${A===1?"":"s"} \xB7 ${c.length} char${c.length===1?"":"s"}`)},i=r.createEl("button",{cls:"stashpad-split-case-btn"});(0,G.setIcon)(i.createSpan({cls:"stashpad-split-btn-icon"}),"case-sensitive"),i.createSpan({text:"Case"}),i.setAttr("aria-label","Cycle case of the selection (or all text): lower \u2192 UPPER \u2192 Title \u2192 Sentence"),i.onmousedown=c=>c.preventDefault(),i.onclick=()=>this.cycleCase(t),this.cursorTextarea?.addEventListener("input",t),t();let s=this.host.createDiv({cls:"stashpad-split-help"});G.Platform.isPhone||s.setText("Edit the note, then Save. \xB7 \u2318/Ctrl+Enter or Save to write \xB7 \u2318/Ctrl+S \u2192 Split \xB7 Esc discards.");let n=this.host.createDiv({cls:"stashpad-split-actions"}),o=n.createEl("button",{cls:"stashpad-split-cancel-btn"});(0,G.setIcon)(o.createSpan({cls:"stashpad-split-btn-icon"}),"x"),o.createSpan({text:"Cancel"}),o.createSpan({cls:"stashpad-split-esc-hint",text:" (Esc)"}),o.onmousedown=c=>c.preventDefault(),o.onclick=()=>this.cb.close(),this.renderPopOut(n),this.renderOpenExternal(n);let l=n.createDiv({cls:"stashpad-split-actions-right"}).createEl("button",{cls:"stashpad-split-confirm-btn mod-cta"});(0,G.setIcon)(l.createSpan({cls:"stashpad-split-btn-icon"}),"save"),l.createSpan({text:"Save"}),l.onmousedown=c=>c.preventDefault(),l.onclick=()=>void this.commit()}cycleCase(r){let e=this.cursorTextarea;if(!e)return;let t=e.selectionStart!==e.selectionEnd,i=t?e.selectionStart:0,s=t?e.selectionEnd:e.value.length,n=e.value.slice(i,s),o=["lower","upper","title","sentence"],a=o[this.caseCycleIndex%o.length];this.caseCycleIndex+=1;let l=sc(n,a);e.value=e.value.slice(0,i)+l+e.value.slice(s),e.setSelectionRange(i,i+l.length),this.cursorText=e.value,e.dispatchEvent(new Event("input")),r(),e.focus()}renderSplitSurface(){let r=this.host.createDiv({cls:"stashpad-split-modes"}),e=(p,f,u,g,I=!1)=>{let m=r.createEl("button",{cls:"stashpad-split-mode-btn"});(0,G.setIcon)(m.createSpan({cls:"stashpad-split-btn-icon"}),g),m.createSpan({text:p}),m.toggleClass("is-active",f),m.disabled=I,m.onmousedown=C=>C.preventDefault(),I||(m.onclick=u)};this.lines.length>=2&&e("Line",this.mode==="line",()=>{this.mode="line",this.render()},"separator-horizontal"),e("Cursor",this.mode==="cursor",()=>{this.mode="cursor",this.render()},"text-cursor-input");let t={lines:"list",paragraphs:"pilcrow",headings:"heading"};["lines","paragraphs","headings"].forEach(p=>{let f=Jt(this.body,p).length,u=f<2,g=p==="paragraphs"?"Blank line(s)":ci[p],I=u?g:`${g} (${f})`;e(I,this.mode==="preset"&&this.presetMode===p,()=>{this.mode="preset",this.presetMode=p,this.render()},t[p],u)}),this.mode==="line"?this.renderLineMode():this.mode==="cursor"?this.renderEditorSections():this.renderPresetMode();let i=this.host.createDiv({cls:"stashpad-split-help"}),s=()=>{if(G.Platform.isPhone){i.setCssStyles({display:"none"});return}i.setCssStyles({display:""});let p=this.nest?"New part nested under the original.":"New part added as a sibling.",f=this.nest?"New parts nested under the original.":"New parts added as siblings.",u="\u2318/Ctrl+Enter or Split to confirm";i.setText(this.mode==="line"?`\u2191/\u2193 or click to pick the split line \xB7 ${u} \xB7 ${p}`:this.mode==="cursor"?`Click or arrow to position the cursor \xB7 ${u} \xB7 ${p}`:`Preview of the resulting parts \xB7 ${u} \xB7 ${f}`)};s();let n=this.host.createDiv({cls:"stashpad-split-actions"}),o=n.createEl("button",{cls:"stashpad-split-cancel-btn"});(0,G.setIcon)(o.createSpan({cls:"stashpad-split-btn-icon"}),"x"),o.createSpan({text:"Cancel"}),o.createSpan({cls:"stashpad-split-esc-hint",text:" (Esc)"}),o.onmousedown=p=>p.preventDefault(),o.onclick=()=>this.cb.close(),this.renderPopOut(n),this.renderOpenExternal(n);let a=n.createDiv({cls:"stashpad-split-actions-right"}),l=a.createEl("label",{cls:"stashpad-split-nest"}),c=l.createEl("input",{type:"checkbox"});c.checked=this.nest,l.createSpan({text:"Nest under original"}),c.onchange=()=>{this.nest=c.checked,s()};let A=this.mode==="preset"?Jt(this.body,this.presetMode).length:0,h=a.createEl("button",{cls:"stashpad-split-confirm-btn mod-cta"});(0,G.setIcon)(h.createSpan({cls:"stashpad-split-btn-icon"}),"split"),h.createSpan({text:this.mode==="preset"&&A>=2?`Split into ${A}`:"Split"}),h.onmousedown=p=>p.preventDefault(),h.onclick=()=>this.commit()}renderPresetMode(){let r=Jt(this.body,this.presetMode),e=this.host.createDiv({cls:"stashpad-split-preset-list"});if(r.length<2){e.createDiv({cls:"stashpad-split-empty",text:"This delimiter wouldn't split the note into more than one part."});return}r.forEach((t,i)=>{let s=e.createDiv({cls:"stashpad-split-part-card"}),n=s.createDiv({cls:"stashpad-split-part-num"});n.createSpan({cls:"stashpad-split-part-title",text:`Part ${i+1}`}),n.appendChild(this.makeCopyButton(()=>t,`Copy part ${i+1}`)),s.createDiv({cls:"stashpad-split-part-body",text:t})})}renderLineMode(){let r=this.host.createDiv({cls:"stashpad-split-list"}),e=null;for(let t=0;t{let s=Math.max(1,Math.min(this.lines.length-1,t+1));s!==this.lineCursorIdx&&(this.lineCursorIdx=s,this.render())}}e&&window.requestAnimationFrame(()=>e.scrollIntoView({block:"center"}))}buildSplitSection(r,e,t){let i=r.createDiv({cls:`stashpad-split-section stashpad-split-${e}`}),s=i.createEl("button",{cls:"stashpad-split-section-header"});s.setAttr("type","button");let n=s.createSpan({cls:"stashpad-split-chevron"});(0,G.setIcon)(n,"chevron-down"),s.createSpan({cls:"stashpad-split-section-title",text:t});let o=i.createDiv({cls:"stashpad-split-section-body"}),a=()=>{i.toggleClass("is-collapsed",this.collapsed[e]),s.setAttr("aria-expanded",String(!this.collapsed[e]))};return s.onmousedown=l=>l.preventDefault(),s.onclick=l=>{l.preventDefault(),this.collapsed[e]=!this.collapsed[e],a()},a(),{section:i,body:o}}makeCopyButton(r,e,t="stashpad-split-copy-btn"){let i=createEl("button",{cls:t});return(0,G.setIcon)(i,"copy"),i.setAttr("aria-label",e),i.onmousedown=s=>s.preventDefault(),i.onclick=s=>{s.preventDefault(),s.stopPropagation();let n=r();navigator.clipboard?.writeText(n).then(()=>new G.Notice("Copied to clipboard."),()=>new G.Notice("Couldn't access the clipboard."))},i}renderEditorSections(){if(G.Platform.isMobile){this.renderEditorTabbed();return}let r=this.buildSplitSection(this.host,"orig","Original \u2014 will be replaced");r.body.createDiv({cls:"stashpad-split-panel-body",text:this.body}),r.section.appendChild(this.makeCopyButton(()=>this.body,"Copy the original text","stashpad-split-copy-btn stashpad-split-section-copy"));let e=this.buildSplitSection(this.host,"changes","Changes"),t=e.body.createDiv({cls:"stashpad-split-panel-body stashpad-split-diff-body"}),s=this.buildSplitSection(this.host,"edit",this.surface==="edit"?"Your edit":"Your edit \u2014 the split uses this").body.createEl("textarea",{cls:"stashpad-split-cursor-ta"});s.value=this.cursorText,s.readOnly=!1,this.cursorTextarea=s;let n=()=>{t.empty();for(let h of er(this.body,s.value)){let p=h.t==="ins"?"stashpad-diff-ins":h.t==="del"?"stashpad-diff-del":"stashpad-diff-eq";t.createSpan({cls:p,text:h.s})}},o=()=>{let h=s.value!==this.body;r.section.setCssStyles({display:h?"":"none"}),e.section.setCssStyles({display:h?"":"none"}),h&&n()},a=parseFloat(getComputedStyle(s).lineHeight)||22,l=this.surface==="edit"?G.Platform.isMobile?10:40:G.Platform.isMobile?3:12,c=2,A=()=>{s.setCssStyles({height:"auto"});let h=Math.min(s.scrollHeight,a*l+16);s.setCssStyles({height:`${Math.max(h,a*c+16)}px`})};o(),requestAnimationFrame(()=>{A(),s.focus();let h=this.surface==="edit"?s.value.length:Math.floor(s.value.length/2);s.setSelectionRange(h,h)}),s.addEventListener("input",()=>{this.cursorText=s.value,A(),o()})}renderEditorTabbed(){let r=this.host.createDiv({cls:"stashpad-split-tabs"}),e=r.createDiv({cls:"stashpad-split-tabbar"}),t=r.createDiv({cls:"stashpad-split-tabbody"}),i=t.createDiv({cls:"stashpad-split-tabpanel stashpad-split-tabpanel-edit"}),s=i.createEl("textarea",{cls:"stashpad-split-cursor-ta"});s.value=this.cursorText,s.readOnly=!1,this.cursorTextarea=s;let n=t.createDiv({cls:"stashpad-split-tabpanel"});n.createDiv({cls:"stashpad-split-panel-body",text:this.body}),n.appendChild(this.makeCopyButton(()=>this.body,"Copy the original text","stashpad-split-copy-btn stashpad-split-tab-copy"));let o=t.createDiv({cls:"stashpad-split-tabpanel"}),a=o.createDiv({cls:"stashpad-split-panel-body stashpad-split-diff-body"}),l=[{key:"edit",label:this.surface==="edit"?"Your edit":"Edit",panel:i},{key:"orig",label:"Original",panel:n},{key:"changes",label:"Changes",panel:o}],c={},A="edit",h=m=>{A=m;for(let C of l)C.panel.toggleClass("is-active",C.key===m),c[C.key]?.toggleClass("is-active",C.key===m);m==="edit"&&s.focus()};for(let m of l){let C=e.createEl("button",{cls:"stashpad-split-tab",text:m.label});C.onmousedown=B=>B.preventDefault(),C.onclick=()=>h(m.key),c[m.key]=C}let p=()=>{a.empty();for(let m of er(this.body,s.value)){let C=m.t==="ins"?"stashpad-diff-ins":m.t==="del"?"stashpad-diff-del":"stashpad-diff-eq";a.createSpan({cls:C,text:m.s})}},f=()=>{let m=s.value!==this.body;c.orig.toggleClass("is-hidden",!m),c.changes.toggleClass("is-hidden",!m),m&&p(),!m&&(A==="orig"||A==="changes")&&h("edit")},u=parseFloat(getComputedStyle(s).lineHeight)||22,g=this.surface==="edit"?8:4;s.setCssStyles({maxHeight:`${u*g+16}px`,overflowY:"auto"});let I=()=>{s.setCssStyles({height:"auto"});let m=Math.min(s.scrollHeight,u*g+16);s.setCssStyles({height:`${Math.max(m,u*2+16)}px`})};f(),h("edit"),requestAnimationFrame(()=>{I(),s.focus();let m=this.surface==="edit"?s.value.length:Math.floor(s.value.length/2);s.setSelectionRange(m,m)}),s.addEventListener("input",()=>{this.cursorText=s.value,I(),f()})}},ss="stashpad-split-view",pi=class extends G.Modal{constructor(e,t,i,s={}){super(e);this.body=t;this.cbs=i;this.init=s;this.ui=null;this.committing=!1}onOpen(){this.modalEl.addClass("stashpad-split-modal"),this.ui=new Xi(this.app,this.contentEl,this.body,this.init,{onSplitAtLine:this.cbs.onSplitAtLine,onSplitAtChar:this.cbs.onSplitAtChar,onSplitMany:this.cbs.onSplitMany,onSave:this.cbs.onSave,onOpenExternal:this.cbs.onOpenExternal,close:()=>this.close(),onDone:()=>{this.committing=!0,this.close()},onTitle:e=>this.titleEl.setText(e),popOut:this.cbs.popOut?e=>{this.committing=!0,this.close(),this.cbs.popOut(e)}:void 0}),this.scope.register(["Mod"],"Enter",e=>{e.preventDefault(),this.ui?.commit()}),this.scope.register([],"ArrowUp",e=>{this.ui?.moveDivider(-1)&&e.preventDefault()}),this.scope.register([],"ArrowDown",e=>{this.ui?.moveDivider(1)&&e.preventDefault()}),this.scope.register(["Mod"],"e",e=>{e.preventDefault(),this.ui?.setSurface("edit")}),this.scope.register(["Mod"],"s",e=>{e.preventDefault(),this.ui?.setSurface("split")})}close(){if(this.committing||!this.ui?.isDirty()){super.close();return}new j(this.app,"Discard unsaved edits?","You've edited this note but haven't saved. Close and discard your changes?","Discard",e=>{e&&(this.committing=!0,this.close())},"Keep editing",!0).open()}onClose(){this.ui=null,this.contentEl.empty()}},gi=class extends G.ItemView{constructor(e){super(e);this.ui=null;this.ctx=null;this.prevLeaf=null;this.autoCloseTimer=null;this.expiredGrace=null;this.title="Note";this.viewIcon="pencil-line"}getViewType(){return ss}getDisplayText(){return this.title}getIcon(){return this.viewIcon}setHeader(e,t){this.title=e,this.viewIcon=t,this.leaf.updateHeader?.()}setContext(e){this.expiredGrace!=null&&(window.clearTimeout(this.expiredGrace),this.expiredGrace=null),this.ctx=e,this.prevLeaf=e.prevLeaf??null;let t=e.init.surface==="edit";this.setHeader(t?"Edit note":"Split note",t?"pencil-line":"split"),this.renderUI()}async onOpen(){this.contentEl.addClass("stashpad-split-modal","stashpad-split-view"),this.ctx||(this.expiredGrace=window.setTimeout(()=>{this.expiredGrace=null,this.ctx||this.renderExpired()},800))}renderUI(){let e=this.contentEl;e.empty(),e.addClass("stashpad-split-modal","stashpad-split-view"),this.ctx&&(this.ui=new Xi(this.app,e,this.ctx.body,this.ctx.init,{onSplitAtLine:this.ctx.cbs.onSplitAtLine,onSplitAtChar:this.ctx.cbs.onSplitAtChar,onSplitMany:this.ctx.cbs.onSplitMany,onSave:this.ctx.cbs.onSave,onOpenExternal:this.ctx.cbs.onOpenExternal,close:()=>this.guardedDetach(),onDone:()=>this.startClosePanel("\u2713 Done.",null,!0),onTitle:t=>this.setHeader(t,t.startsWith("Edit")?"pencil-line":"split")}),this.registerDomEvent(e,"keydown",t=>{let i=t.metaKey||t.ctrlKey;i&&t.key==="Enter"?(t.preventDefault(),this.ui?.commit()):i&&(t.key==="e"||t.key==="E")?(t.preventDefault(),this.ui?.setSurface("edit")):i&&(t.key==="s"||t.key==="S")?(t.preventDefault(),this.ui?.setSurface("split")):t.key==="ArrowUp"?this.ui?.moveDivider(-1)&&t.preventDefault():t.key==="ArrowDown"&&this.ui?.moveDivider(1)&&t.preventDefault()}))}renderExpired(){this.setHeader("Expired","clock"),this.startClosePanel("This session has expired.","It can't be restored \u2014 closing this tab\u2026",!1)}startClosePanel(e,t,i){let s=this.contentEl;s.empty(),this.ui=null;let n=s.createDiv({cls:"stashpad-split-done"});n.createDiv({cls:"stashpad-split-done-title",text:e}),t&&n.createDiv({cls:"stashpad-split-countdown",text:t});let o=n.createDiv({cls:"stashpad-split-countdown"}),a=n.createDiv({cls:"stashpad-split-done-btns"}),l=a.createEl("button",{cls:"mod-cta",text:"Close now"}),c=a.createEl("button",{text:"Keep tab open"}),A=4,h=()=>o.setText(`Closing this tab in ${A}\u2026`),p=()=>{this.autoCloseTimer!=null&&(window.clearInterval(this.autoCloseTimer),this.autoCloseTimer=null)},f=()=>{p(),i?this.closeAndRefocus():this.leaf.detach()};h(),this.autoCloseTimer=window.setInterval(()=>{A-=1,A<=0?f():h()},1e3),l.onclick=f,c.onclick=()=>{p(),o.setText("Close this tab whenever you're ready."),c.remove(),l.setText("Close tab")}}guardedDetach(){if(!this.ui?.isDirty()){this.leaf.detach();return}new j(this.app,"Discard unsaved edits?","You've edited this note but haven't saved. Close this tab and discard your changes?","Discard",e=>{e&&this.leaf.detach()},"Keep editing",!0).open()}leafStillOpen(e){let t=!1;return this.app.workspace.iterateAllLeaves(i=>{i===e&&(t=!0)}),t}closeAndRefocus(){let e=this.prevLeaf;this.leaf.detach(),e&&this.leafStillOpen(e)&&this.app.workspace.setActiveLeaf(e,{focus:!0})}async onClose(){this.autoCloseTimer!=null&&(window.clearInterval(this.autoCloseTimer),this.autoCloseTimer=null),this.expiredGrace!=null&&(window.clearTimeout(this.expiredGrace),this.expiredGrace=null),this.ui=null,this.contentEl.empty()}};ui=class extends G.Modal{constructor(e,t,i,s,n={}){super(e);this.defaultBaseName=t;this.noteCount=i;this.onConfirm=s;this.opts=n;this.delivered=!1}onOpen(){this.contentEl.empty();let e=!!this.opts.locked;this.titleEl.setText(e?"Export encrypted bundle":"Export"),this.modalEl.addClass("stashpad-export-modal"),this.contentEl.createEl("p",{cls:"stashpad-export-desc",text:e?`Re-export this locked bundle (${this.noteCount} note${this.noteCount===1?"":"s"}) as a shareable .stash.`:`Export ${this.noteCount} note${this.noteCount===1?"":"s"}.`});let t=this.contentEl.createDiv({cls:"stashpad-export-field"});t.createEl("label",{cls:"stashpad-export-label",text:"File name"});let i=t.createEl("input",{type:"text"});i.addClass("stashpad-export-name"),i.value=this.defaultBaseName;let s=this.contentEl.createEl("div",{cls:"stashpad-export-preview"}),n="full",o=()=>{},a=this.contentEl.createDiv();nc(a,Y=>{n=Y,o()}),e&&a.setCssStyles({display:"none"});let l="stash",c=this.contentEl.createDiv({cls:"stashpad-export-format"});c.createEl("label",{cls:"stashpad-export-label",text:"Format"});let A=c.createDiv({cls:"stashpad-export-content-seg"}),h=[{id:"stash",label:"Stashpad .stash"},...this.opts.okfEnabled?[{id:"okf",label:"OKF bundle"}]:[],{id:"zip",label:"Plain .zip"}],p=new Map;for(let Y of h){let Se=A.createEl("button",{cls:"stashpad-export-content-opt",text:Y.label});Se.toggleClass("is-active",Y.id===l),Se.onclick=Ce=>{Ce.preventDefault(),l=Y.id,p.forEach((Me,Xe)=>Me.toggleClass("is-active",Xe===l)),o()},p.set(Y.id,Se)}let f=this.contentEl.createDiv({cls:"stashpad-okf-formats"}),u=(Y,Se)=>{let Ce=f.createDiv({cls:"stashpad-okf-fmt"}),Me=Ce.createEl("input",{type:"checkbox"});return Me.checked=Se,Ce.createEl("label",{text:Y}),Me.onchange=()=>o(),Me},g=u(".zip \u2014 OKF bundle (portable)",!0),I=u(".tar.gz \u2014 OKF bundle (tarball)",!1),m=f.createDiv({cls:"stashpad-export-pw-hint is-error"});m.setText("Pick at least one OKF format."),m.setCssStyles({display:"none"}),e&&c.setCssStyles({display:"none"});let C=this.contentEl.createDiv({cls:"stashpad-export-zipwarn"});C.setText("Frontmatter-only / body-only exports save as a plain .zip of the selected markdown (with referenced attachments) \u2014 not a re-importable .stash."),C.setCssStyles({display:"none"});let B=this.contentEl.createDiv({cls:"stashpad-export-encrypt"}),E=B.createDiv({cls:"stashpad-export-toggle"}),y=E.createEl("input",{type:"checkbox"});y.id="stashpad-export-encrypt-cb";let Q=E.createEl("label",{text:"Encrypt with a password"});Q.htmlFor=y.id;let w=B.createDiv({cls:"stashpad-export-pw-area"});w.setCssStyles({display:"none"});let v=[],F=Y=>{let Se=w.createDiv({cls:"stashpad-export-pw-row"}),Ce=Se.createEl("input",{type:"password"});Ce.addClass("stashpad-export-name"),Ce.placeholder=Y;let Me=Se.createEl("button",{cls:"stashpad-export-copy"}),Xe=()=>{let kt=Ce.value.length===0;Me.setText(kt?"Paste":"Copy"),Me.toggleClass("is-paste",kt),Me.setAttr("aria-label",`${kt?"Paste into":"Copy"} ${Y.toLowerCase()}`)};return Me.onclick=async kt=>{if(kt.preventDefault(),Ce.value.length===0)try{let Ps=(await navigator.clipboard?.readText())?.trim();if(!Ps){new G.Notice("Clipboard is empty.");return}Ce.value=Ps,Ce.dispatchEvent(new Event("input")),new G.Notice("Pasted from clipboard.")}catch{new G.Notice("Couldn't read the clipboard.")}else navigator.clipboard?.writeText(Ce.value).then(()=>new G.Notice("Passphrase copied to clipboard."),()=>new G.Notice("Couldn't access the clipboard."))},Xe(),v.push(Xe),Ce},D=F("Password"),H=F("Confirm password"),R=w.createDiv({cls:"stashpad-export-strength"}),L=R.createDiv({cls:"stashpad-strength-bar"}),x=[0,1,2,3].map(()=>L.createDiv({cls:"stashpad-strength-seg"})),U=R.createEl("span",{cls:"stashpad-strength-label"}),N=w.createDiv({cls:"stashpad-export-genrow"}),b=N.createEl("button",{cls:"stashpad-export-gen",text:"Generate strong passphrase"}),M=N.createEl("button",{cls:"stashpad-export-show",text:"Show"}),O=w.createEl("div",{cls:"stashpad-export-pw-hint"}),K=w.createEl("div",{cls:"stashpad-export-pw-suite"});K.setText("Encryption: AES-256-GCM. Checking key-derivation suite for this device\u2026"),this.opts.kdfProbe?this.opts.kdfProbe().then(Y=>{K.toggleClass("is-weak",!Y),K.setText(Y?"Encryption: Argon2id + AES-256-GCM \u2014 the strongest suite (used on this device).":"\u26A0\uFE0F Argon2id can't run on this device, so this export will use the weaker PBKDF2 (600k) + AES-256-GCM fallback.")}).catch(()=>{K.setText("Encryption: AES-256-GCM with a password-derived key.")}):K.setText("Encryption: Argon2id + AES-256-GCM (falls back to PBKDF2 if Argon2 can't run here).");let $=this.app.secretStorage,Z=w.createDiv({cls:"stashpad-export-remember"}),V=Z.createEl("input",{type:"checkbox"});V.checked=!0,V.id="stashpad-export-remember-cb";let q=Z.createEl("label",{text:"Remember in this vault (this device) \u2014 skips the prompt when you re-import here."});q.htmlFor=V.id;let ee=w.createDiv({cls:"stashpad-export-remember-note"});ee.setText("Saved only in this device's keychain \u2014 it doesn't sync to your other devices and isn't shared with anyone you send this file to. Keep the passphrase somewhere safe if you'll open this export elsewhere."),ee.setCssStyles({display:V.checked?"":"none"}),V.onchange=()=>{ee.setCssStyles({display:V.checked?"":"none"})},$||Z.setCssStyles({display:"none"});let ge=()=>e?"stash":n!=="full"?"zip":l,oe=()=>{let Y=i.value.trim()||this.defaultBaseName;return!e&&n!=="full"?`${Y}-${n}`:ge()==="stash"&&y.checked?`${Y}-encrypted`:Y},ie=()=>{let Y=ge();if(Y==="stash"){s.setText(`Saves as: ${oe()}-.stash`);return}if(Y==="okf"){s.setText(`Saves as: ${oe()}-.zip / .tar.gz (OKF bundle)`);return}s.setText(`Saves as: ${oe()}-.zip (plain archive \u2014 not re-importable)`)};i.oninput=ie;let te=this.contentEl.createDiv({cls:"stashpad-export-footer"}),ue=te.createEl("button",{text:"Cancel"});ue.onclick=()=>this.close();let ye=te.createEl("button",{cls:"mod-cta",text:"Export"}),se=()=>{let Y=Bo(D.value);R.style.visibility=D.value?"visible":"hidden",x.forEach((Se,Ce)=>Se.toggleClass("is-on",D.value!==""&&Ce<=Y.level)),L.dataset.level=String(Y.level),U.setText(Y.label)},de=()=>{let Y=!e&&n!=="full",Se=ge();c.setCssStyles({display:!e&&!Y?"":"none"}),f.setCssStyles({display:!e&&!Y&&l==="okf"?"":"none"}),C.setCssStyles({display:Y?"":"none"});let Ce=Se==="stash";B.setCssStyles({display:Ce?"":"none"});let Me=Ce&&y.checked;w.setCssStyles({display:Me?"":"none"});let Xe=!0;Me&&(D.value?D.value!==H.value?(O.setText("Passwords don't match."),O.addClass("is-error"),Xe=!1):(O.setText("\u26A0\uFE0F If you lose this password, the export can't be recovered."),O.removeClass("is-error")):(O.setText("Enter a password to encrypt this export."),O.removeClass("is-error"),Xe=!1));let kt=!e&&!Y&&l==="okf"&&!g.checked&&!I.checked;m.setCssStyles({display:kt?"":"none"}),kt&&(Xe=!1),se(),v.forEach(Ps=>Ps()),ye.disabled=!Xe,ye.toggleClass("is-disabled",!Xe),ie()},We=!1,si=Y=>{We=Y,D.type=H.type=Y?"text":"password",M.setText(Y?"Hide":"Show")};M.onclick=Y=>{Y.preventDefault(),si(!We)},b.onclick=Y=>{Y.preventDefault(),D.value=H.value=Co(),si(!1),new G.Notice("Passphrase generated (hidden) \u2014 Show to view, or Copy to save it."),de()},y.onchange=de,D.oninput=de,H.oninput=de,o=de,de();let Ms=()=>{let Y=ge(),Se=Y==="stash"&&y.checked?D.value:null;this.commit({baseName:oe(),content:n,format:Y,okf:{zip:g.checked,targz:I.checked},password:Se,remember:!!Se&&V.checked})};ye.onclick=Ms,this.scope.register([],"Enter",Y=>{Y.preventDefault(),ye.disabled||Ms()}),requestAnimationFrame(()=>{i.focus(),i.select()})}commit(e){let t=e.baseName.trim()||this.defaultBaseName,i=e.password&&e.password.length?e.password:null;this.delivered=!0,this.close(),this.onConfirm({...e,baseName:t,password:i,remember:!!i&&e.remember})}onClose(){this.contentEl.empty()}},Zi=class extends G.Modal{constructor(e,t,i,s){super(e);this.errorMsg=t;this.allowLater=i;this.onResult=s;this.delivered=!1}onOpen(){this.contentEl.empty(),this.titleEl.setText("Encrypted .stash"),this.modalEl.addClass("stashpad-export-modal"),this.contentEl.createEl("p",{cls:"stashpad-export-desc",text:"This export is password-protected. Enter its password to import it."}),this.errorMsg&&this.contentEl.createEl("div",{cls:"stashpad-export-error",text:this.errorMsg});let e=this.contentEl.createEl("input",{type:"password"});e.addClass("stashpad-export-name"),e.placeholder="Password";let t=this.contentEl.createDiv({cls:"stashpad-export-footer"});if(t.createEl("button",{text:"Cancel"}).onclick=()=>this.close(),this.allowLater){let s=t.createEl("button",{text:"Remind me later"});s.title="Don't import now \u2014 surface the reminder again later.",s.onclick=()=>this.finish({kind:"later"})}let i=t.createEl("button",{cls:"mod-cta",text:"Decrypt & import"});i.onclick=()=>this.submit(e.value),this.scope.register([],"Enter",s=>{s.preventDefault(),this.submit(e.value)}),requestAnimationFrame(()=>e.focus())}submit(e){e&&this.finish({kind:"password",value:e})}finish(e){this.delivered=!0,this.close(),this.onResult(e)}onClose(){this.delivered||(this.delivered=!0,this.onResult({kind:"cancel"})),this.contentEl.empty()}},Re=class extends G.Modal{constructor(e,t){super(e);this.opts=t;this.succeeded=!1}onOpen(){let{mode:e}=this.opts;this.contentEl.empty(),this.modalEl.addClass("stashpad-export-modal","stashpad-encryption-modal"),this.titleEl.setText(this.opts.title??(e==="setup"?"Set up encryption password":e==="change"?"Change encryption password":"Unlock encryption")),this.contentEl.createDiv({cls:"stashpad-beta-row"}).createEl("span",{cls:"stashpad-beta-badge",text:"BETA"}),this.opts.intro?this.contentEl.createEl("p",{cls:"stashpad-export-desc",text:this.opts.intro}):e==="setup"&&this.contentEl.createEl("p",{cls:"stashpad-export-desc",text:"This single password protects everything you encrypt in this vault. It is stored only on this device. There is NO recovery \u2014 if you lose it, anything you've encrypted is gone for good."});let t=[],i=g=>{let I=this.contentEl.createDiv({cls:"stashpad-export-pw-row stashpad-encryption-row"}),m=I.createEl("input",{type:"password"});m.addClass("stashpad-export-name","stashpad-encryption-field"),m.placeholder=g;let C=I.createEl("button",{cls:"stashpad-export-copy"}),B=()=>{let E=m.value.length===0;C.setText(E?"Paste":"Copy"),C.toggleClass("is-paste",E),C.setAttr("aria-label",`${E?"Paste into":"Copy"} ${g.toLowerCase()}`)};return C.onclick=async E=>{if(E.preventDefault(),m.value.length===0)try{let y=(await navigator.clipboard?.readText())?.trim();if(!y){new G.Notice("Clipboard is empty.");return}m.value=y,m.dispatchEvent(new Event("input")),new G.Notice("Pasted from clipboard.")}catch{new G.Notice("Couldn't read the clipboard.")}else navigator.clipboard?.writeText(m.value).then(()=>new G.Notice("Copied to clipboard."),()=>new G.Notice("Couldn't access the clipboard."))},m.addEventListener("input",B),B(),t.push(B),m},s=null,n=null,o=null;if((e==="unlock"||e==="change")&&(s=i("Current password")),(e==="setup"||e==="change")&&(n=i(e==="change"?"New password":"Password"),o=i("Confirm password")),n){let g=this.contentEl.createDiv({cls:"stashpad-export-strength"}),I=g.createDiv({cls:"stashpad-strength-bar"}),m=[0,1,2,3].map(()=>I.createDiv({cls:"stashpad-strength-seg"})),C=g.createEl("span",{cls:"stashpad-strength-label"}),B=this.contentEl.createDiv({cls:"stashpad-encryption-counter"}),E=()=>{let v=n.value,F=Bo(v);m.forEach((D,H)=>D.toggleClass("is-on",H0&&v.length<6?" \u2014 use at least 6":""}`),B.toggleClass("is-weak",v.length>0&&v.length<6)};n.addEventListener("input",E),E();let y=this.contentEl.createDiv({cls:"stashpad-export-genrow"});y.createEl("button",{cls:"stashpad-export-gen",text:"Generate strong passphrase"}).onclick=v=>{v.preventDefault();let F=Co(5);n.value=F,o&&(o.value=F),E(),t.forEach(D=>D()),new G.Notice("Generated \u2014 copy it somewhere safe; there's no recovery."),navigator.clipboard?.writeText(F).catch(()=>{})};let Q=y.createEl("button",{cls:"stashpad-export-show",text:"Show"});Q.onclick=v=>{v.preventDefault();let F=n.type==="password";n.type=F?"text":"password",o&&(o.type=F?"text":"password"),Q.setText(F?"Hide":"Show")};let w=this.contentEl.createEl("div",{cls:"stashpad-export-pw-suite"});w.setText("Encryption: AES-256-GCM. Checking key-derivation suite\u2026"),this.opts.kdfProbe?this.opts.kdfProbe().then(v=>{w.toggleClass("is-weak",!v),w.setText(v?"Encryption: Argon2id + AES-256-GCM \u2014 the strongest suite (used on this device).":"\u26A0\uFE0F Argon2id can't run here, so this will use the weaker PBKDF2 (600k) + AES-256-GCM fallback.")}).catch(()=>w.setText("Encryption: AES-256-GCM with a password-derived key.")):w.setText("Encryption: Argon2id + AES-256-GCM (PBKDF2 fallback if Argon2 can't run here).")}let a=null,l=this.app.secretStorage;if(this.opts.offerKeychain&&l){let g=this.contentEl.createDiv({cls:"stashpad-export-remember"});a=g.createEl("input",{type:"checkbox"}),a.id="stashpad-enc-remember",a.checked=!0;let I=g.createEl("label",{text:"Remember on this device (keychain) \u2014 auto-unlock here without re-typing."});I.htmlFor=a.id;let m=this.contentEl.createDiv({cls:"stashpad-export-remember-note"});m.setText("Stored only in this device's keychain \u2014 doesn't sync to your other devices. Anyone with access to this unlocked device + keychain could decrypt."),m.setCssStyles({display:a.checked?"":"none"}),a.onchange=()=>{m.setCssStyles({display:a.checked?"":"none"})}}let c=this.contentEl.createEl("div",{cls:"stashpad-export-error"});c.setCssStyles({display:"none"});let A=g=>{c.setText(g),c.setCssStyles({display:""})},h=this.contentEl.createDiv({cls:"stashpad-export-footer"});h.createEl("button",{text:"Cancel"}).onclick=()=>this.close();let p=h.createEl("button",{cls:"mod-cta",text:e==="setup"?"Set up":e==="change"?"Change":"Unlock"}),f=!1,u=async()=>{if(f)return;let g=s?.value??void 0,I=n?.value??void 0;if((e==="unlock"||e==="change")&&!g){A("Enter your current password.");return}if(e==="setup"||e==="change"){if(!I){A("Enter a password.");return}if(I.length<6){A("Use at least 6 characters.");return}if(I!==o?.value){A("Passwords don't match.");return}}f=!0,p.disabled=!0,c.setCssStyles({display:"none"});let m=p.textContent;p.setText("Working\u2026");try{let C=await this.opts.onSubmit({current:g,next:I,remember:!!a?.checked});if(C){A(C),f=!1,p.disabled=!1,p.setText(m??"OK");return}this.succeeded=!0,this.close()}catch(C){A(`Failed: ${C.message}`),f=!1,p.disabled=!1,p.setText(m??"OK")}};p.onclick=()=>void u(),this.scope.register([],"Enter",g=>{g.preventDefault(),u()}),requestAnimationFrame(()=>(s??n)?.focus())}onClose(){this.contentEl.empty(),this.succeeded||this.opts.onCancel?.()}},fi=class extends G.Modal{constructor(e,t){super(e);this.opts=t}onOpen(){this.contentEl.empty(),this.modalEl.addClass("stashpad-export-modal","stashpad-encryption-modal"),this.titleEl.setText(this.opts.title),this.contentEl.createEl("p",{cls:"stashpad-export-desc",text:this.opts.body});let e=null;this.opts.requirePassword&&(this.contentEl.createEl("p",{cls:"stashpad-export-desc"}).setText("Enter your encryption password:"),e=this.contentEl.createEl("input",{type:"password"}),e.addClass("stashpad-export-name","stashpad-encryption-field"),e.placeholder="Password"),this.contentEl.createEl("p",{cls:"stashpad-export-desc"}).setText(`Type "${this.opts.phrase}" to confirm.`);let t=this.contentEl.createEl("input",{type:"text"});t.addClass("stashpad-export-name","stashpad-encryption-field"),t.placeholder=this.opts.phrase;let i=this.contentEl.createEl("div",{cls:"stashpad-export-error"});i.setCssStyles({display:"none"});let s=this.contentEl.createDiv({cls:"stashpad-export-footer"});s.createEl("button",{text:"Cancel"}).onclick=()=>this.close();let n=s.createEl("button",{cls:"mod-cta mod-warning",text:this.opts.confirmText}),o=()=>t.value.trim().toLowerCase()===this.opts.phrase.trim().toLowerCase(),a=()=>{n.disabled=!o()||!!this.opts.requirePassword&&!e?.value};t.addEventListener("input",a),e?.addEventListener("input",a),a();let l=!1,c=async()=>{if(!(l||!o())){if(this.opts.requirePassword&&(l=!0,n.disabled=!0,i.setCssStyles({display:"none"}),!await this.opts.requirePassword(e.value))){i.setText("Wrong password."),i.setCssStyles({display:""}),l=!1,a();return}this.close(),await this.opts.onConfirm()}};n.onclick=()=>void c(),this.scope.register([],"Enter",A=>{A.preventDefault(),c()}),requestAnimationFrame(()=>(e??t).focus())}onClose(){this.contentEl.empty()}},ji=class extends G.Modal{constructor(e,t){super(e);this.onSubmit=t}onOpen(){this.contentEl.empty(),this.modalEl.addClass("stashpad-export-modal"),this.titleEl.setText("Open Stashpad link"),this.contentEl.createEl("p",{cls:"stashpad-export-desc",text:"Paste one or more obsidian://stashpad links (one per line) to jump to the notes they point to. Multiple links each open in their own tab."});let e=this.contentEl.createDiv({cls:"stashpad-open-link-row"}),t=e.createEl("button",{cls:"stashpad-open-link-paste"});(0,G.setIcon)(t.createSpan({cls:"stashpad-open-link-paste-icon"}),"clipboard-paste"),t.createSpan({text:"Paste"}),t.title="Paste from clipboard";let i=e.createEl("textarea",{attr:{rows:"3"}});i.addClass("stashpad-export-name"),i.placeholder="obsidian://stashpad?folder=\u2026¬e=\u2026",t.onclick=async()=>{try{let l=(await navigator.clipboard?.readText?.())?.trim();l&&(i.value=l,s.hide()),i.focus()}catch{new G.Notice("Couldn't read the clipboard \u2014 paste manually.")}},i.addEventListener("input",()=>s.hide());let s=this.contentEl.createEl("div",{cls:"stashpad-open-link-autohint"});(0,G.setIcon)(s.createSpan({cls:"stashpad-open-link-autohint-icon"}),"clipboard-check"),s.createSpan({text:"Link automatically pasted from your clipboard."}),s.hide();let n=this.contentEl.createDiv({cls:"stashpad-export-footer"});n.createEl("button",{text:"Cancel"}).onclick=()=>this.close();let o=n.createEl("button",{cls:"mod-cta",text:"Open"}),a=()=>{let l=i.value.trim();l&&(this.close(),this.onSubmit(l))};o.onclick=()=>a(),this.scope.register([],"Enter",l=>{l.preventDefault(),a()}),requestAnimationFrame(()=>{i.focus(),navigator.clipboard?.readText?.().then(l=>{!i.value&&l&&/obsidian:\/\/stashpad\?/i.test(l.trim())&&(i.value=l.trim(),i.select(),s.show())}).catch(()=>{})})}onClose(){this.contentEl.empty()}},Js=class extends G.Modal{constructor(e,t,i){super(e);this.onResult=i;this.delivered=!1;this.touched=!1;this.value=t&&/^#[0-9a-f]{6}$/i.test(t)?t:"#888888"}onOpen(){this.contentEl.empty(),this.titleEl.setText("Custom color"),this.modalEl.addClass("stashpad-custom-color-modal");let e=this.contentEl.createDiv({cls:"stashpad-custom-color-row"}),t=e.createDiv({cls:"stashpad-custom-color-preview"});t.style.background=this.value;let i=e.createEl("input",{type:"color"});i.value=this.value,i.addClass("stashpad-custom-color-wheel"),t.onclick=()=>i.click();let s=e.createEl("input",{type:"text"});s.addClass("stashpad-custom-color-hex"),s.placeholder="#RRGGBB",s.value=this.value,s.maxLength=7;let n=A=>{let h=A.startsWith("#")?A:"#"+A;/^#[0-9a-f]{6}$/i.test(h)&&(this.touched=!0,this.value=h,t.style.background=h,i.value=h,s.value!==h&&(s.value=h))};i.oninput=()=>n(i.value),s.oninput=()=>n(s.value);let o=this.contentEl.createDiv({cls:"stashpad-color-footer"}),a=o.createEl("button",{text:"Cancel"});a.onclick=()=>{this.delivered=!0,this.close()};let l=o.createEl("button",{cls:"mod-cta",text:"Save"});l.title="Apply this color to the selection (without adding to your palette).",l.onclick=()=>this.commit({addToPalette:!1});let c=o.createEl("button",{cls:"mod-cta",text:"Add to palette"});c.title="Apply and save this color so it appears as a tile next time.",c.onclick=()=>this.commit({addToPalette:!0}),this.scope.register([],"Enter",A=>{A.preventDefault(),this.commit({addToPalette:!1})}),this.scope.register(["Mod"],"Enter",A=>{A.preventDefault(),this.commit({addToPalette:!0})}),requestAnimationFrame(()=>s.focus())}commit(e){this.delivered=!0,this.close(),this.onResult(this.value,e)}onClose(){!this.delivered&&this.touched&&(this.delivered=!0,this.onResult(this.value,{addToPalette:!1})),this.contentEl.empty()}},Wi=class Wi extends G.Modal{constructor(e,t,i,s,n){super(e);this.currentColor=t;this.customPalette=i;this.onPick=s;this.onDeleteCustom=n;this.focusIdx=-1;this.scopeBound=!1;this.items=[]}onOpen(){this.contentEl.empty(),this.titleEl.setText("Pick a color"),this.modalEl.addClass("stashpad-color-modal");let e=this.contentEl.createDiv({cls:"stashpad-color-grid"});this.items=[];let t=e.createDiv({cls:"stashpad-color-tile stashpad-color-none"});t.title="No color",t.onclick=()=>this.activate(0),this.items.push({kind:"none",color:null,el:t});let i=[...Wi.DEFAULT_PALETTE,...this.customPalette];for(let a of i){let l=e.createDiv({cls:"stashpad-color-tile"});l.style.background=a,l.title=a;let c=!Wi.DEFAULT_PALETTE.some(h=>h.toLowerCase()===a.toLowerCase()),A=this.items.length;if(l.onclick=()=>this.activate(A),c&&this.onDeleteCustom){let h=l.createSpan({cls:"stashpad-color-tile-del",text:"\xD7"});h.title="Remove from palette",h.onclick=p=>{p.stopPropagation(),this.handleDelete(a)}}this.items.push({kind:c?"custom":"preset",color:a,el:l})}let s=e.createDiv({cls:"stashpad-color-tile stashpad-color-add"});s.title="Custom color\u2026";let n=this.items.length;s.onclick=()=>this.activate(n),this.items.push({kind:"add",color:null,el:s});let o=this.items.findIndex(a=>this.currentColor===null?a.kind==="none":this.currentColor?a.color!==null&&a.color.toLowerCase()===this.currentColor.toLowerCase():!1);this.focusIdx=o>=0?o:0,this.refreshActive(),this.scopeBound||(this.scope.register([],"ArrowRight",a=>{a.preventDefault(),this.moveFocus(1)}),this.scope.register([],"ArrowLeft",a=>{a.preventDefault(),this.moveFocus(-1)}),this.scope.register([],"ArrowDown",a=>{a.preventDefault(),this.moveFocus(this.columns())}),this.scope.register([],"ArrowUp",a=>{a.preventDefault(),this.moveFocus(-this.columns())}),this.scope.register([],"Enter",a=>{a.preventDefault(),this.activate(this.focusIdx)}),this.scopeBound=!0),requestAnimationFrame(()=>this.modalEl.focus())}activate(e){if(e<0||e>=this.items.length)return;this.focusIdx=e,this.refreshActive();let t=this.items[e];if(t.kind==="add"){this.close(),new Js(this.app,this.currentColor,(i,s)=>{this.onPick(i,s)}).open();return}this.close(),this.onPick(t.color,{addToPalette:!1})}columns(){if(!this.items.length)return 1;let e=this.items[0].el.parentElement;if(!e)return 1;let t=e.getBoundingClientRect(),i=this.items[0].el.getBoundingClientRect();if(i.width<=0)return 1;let s=i.top,n=0;for(let o of this.items){let a=o.el.getBoundingClientRect();if(Math.abs(a.top-s)<1)n++;else break}return Math.max(1,n)}async handleDelete(e){if(this.onDeleteCustom)try{let t=await this.onDeleteCustom(e);this.customPalette=Array.isArray(t)?t:this.customPalette.filter(i=>i.toLowerCase()!==e.toLowerCase()),this.onOpen()}catch(t){console.warn("Stashpad: palette delete failed",t)}}moveFocus(e){if(!this.items.length)return;let t=Math.max(0,Math.min(this.items.length-1,this.focusIdx+e));this.focusIdx=t,this.refreshActive()}refreshActive(){for(let e=0;ethis.onTabKey(n)),this.render()}visibleFocusables(){return Array.from(this.host.querySelectorAll('button:not([disabled]), input:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])')).filter(e=>e.offsetParent!==null)}onTabKey(r){if(r.key!=="Tab")return;let e=this.visibleFocusables();if(e.length===0)return;let t=e[0],i=e[e.length-1],s=document.activeElement;r.shiftKey&&s===t?(r.preventDefault(),i.focus()):!r.shiftKey&&s===i&&(r.preventDefault(),t.focus())}getState(){return{surface:this.surface,mode:this.mode,presetMode:this.presetMode,nest:this.nest,cursorText:this.cursorTextarea?.value??this.cursorText,lineCursorIdx:this.lineCursorIdx}}async commit(){if(this.surface==="edit"){await this.saveEdit();return}this.mode==="line"?await this.commitLine():this.mode==="cursor"?await this.commitCursor():await this.commitPreset()}async saveEdit(){let r=this.cursorTextarea;r&&(await this.cb.onSave(r.value),this.cb.onDone())}isDirty(){return(this.cursorTextarea?.value??this.cursorText)!==this.body}setSurface(r){this.surface!==r&&(this.surface=r,this.render())}moveDivider(r){return this.mode!=="line"?!1:(this.lineCursorIdx=Math.max(1,Math.min(this.lines.length-1,this.lineCursorIdx+r)),this.render(),!0)}async commitLine(){await this.cb.onSplitAtLine(this.lineCursorIdx,this.nest),this.cb.onDone()}async commitCursor(){let r=this.cursorTextarea;if(!r)return;let e=r.selectionStart;if(e<=0||e>=r.value.length){new G.Notice("Move the cursor inside the text \u2014 neither end can be empty.");return}await this.cb.onSplitAtChar(r.value,e,this.nest),this.cb.onDone()}async commitPreset(){let r=Jt(this.body,this.presetMode);if(r.length<2){new G.Notice("That delimiter wouldn't split this note.");return}await this.cb.onSplitMany(r,this.nest),this.cb.onDone()}render(){if(this.host.empty(),this.host.toggleClass("stashpad-edit-surface",this.surface==="edit"),this.cb.onTitle?.(this.surface==="edit"?"Edit note":"Split note"),this.renderSurfaceToggle(),this.surface==="edit"){this.renderEditSurface();return}this.renderSplitSurface()}renderSurfaceToggle(){let r=this.host.createDiv({cls:"stashpad-split-surface"}),e=G.Platform.isMacOS?"\u2318":"Ctrl+",t=(i,s,n,o)=>{let a=r.createEl("button",{cls:"stashpad-split-surface-btn"});(0,G.setIcon)(a.createSpan({cls:"stashpad-split-btn-icon"}),n),a.createSpan({text:i}),a.createSpan({cls:"stashpad-split-kbd-hint",text:`${e}${o}`}),a.toggleClass("is-active",this.surface===s),a.onmousedown=l=>l.preventDefault(),a.onclick=()=>this.setSurface(s)};t("Edit","edit","pencil-line","E"),t("Split","split","split","S")}renderPopOut(r){if(!this.cb.popOut)return;let e=r.createEl("button",{cls:"stashpad-split-popout-btn"});(0,G.setIcon)(e.createSpan({cls:"stashpad-split-popout-icon"}),"maximize-2"),e.createSpan({text:G.Platform.isMobile?"Pop-out":"Open in a tab"}),e.setAttr("aria-label","Open in a full tab"),e.onmousedown=t=>t.preventDefault(),e.onclick=()=>this.cb.popOut(this.getState())}renderOpenExternal(r){if(!this.cb.onOpenExternal)return;let e=r.createEl("button",{cls:"stashpad-split-popout-btn"});(0,G.setIcon)(e.createSpan({cls:"stashpad-split-popout-icon"}),"pencil"),e.createSpan({text:G.Platform.isMobile?"Advanced":"Obsidian editor"}),e.setAttr("aria-label","Open in a full Obsidian editor tab"),e.onmousedown=t=>t.preventDefault(),e.onclick=()=>{this.cb.onOpenExternal(),this.cb.close()}}renderEditSurface(){this.renderEditorSections();let r=this.host.createDiv({cls:"stashpad-split-edit-tools"}),e=r.createSpan({cls:"stashpad-split-count"}),t=()=>{let c=this.cursorTextarea?.value??"",A=(c.trim().match(/\S+/g)||[]).length;e.setText(`${A} word${A===1?"":"s"} \xB7 ${c.length} char${c.length===1?"":"s"}`)},i=r.createEl("button",{cls:"stashpad-split-case-btn"});(0,G.setIcon)(i.createSpan({cls:"stashpad-split-btn-icon"}),"case-sensitive"),i.createSpan({text:"Case"}),i.setAttr("aria-label","Cycle case of the selection (or all text): lower \u2192 UPPER \u2192 Title \u2192 Sentence"),i.onmousedown=c=>c.preventDefault(),i.onclick=()=>this.cycleCase(t),this.cursorTextarea?.addEventListener("input",t),t();let s=this.host.createDiv({cls:"stashpad-split-help"});G.Platform.isPhone||s.setText("Edit the note, then Save. \xB7 \u2318/Ctrl+Enter or Save to write \xB7 \u2318/Ctrl+S \u2192 Split \xB7 Esc discards.");let n=this.host.createDiv({cls:"stashpad-split-actions"}),o=n.createEl("button",{cls:"stashpad-split-cancel-btn"});(0,G.setIcon)(o.createSpan({cls:"stashpad-split-btn-icon"}),"x"),o.createSpan({text:"Cancel"}),o.createSpan({cls:"stashpad-split-esc-hint",text:" (Esc)"}),o.onmousedown=c=>c.preventDefault(),o.onclick=()=>this.cb.close(),this.renderPopOut(n),this.renderOpenExternal(n);let l=n.createDiv({cls:"stashpad-split-actions-right"}).createEl("button",{cls:"stashpad-split-confirm-btn mod-cta"});(0,G.setIcon)(l.createSpan({cls:"stashpad-split-btn-icon"}),"save"),l.createSpan({text:"Save"}),l.onmousedown=c=>c.preventDefault(),l.onclick=()=>void this.commit()}cycleCase(r){let e=this.cursorTextarea;if(!e)return;let t=e.selectionStart!==e.selectionEnd,i=t?e.selectionStart:0,s=t?e.selectionEnd:e.value.length,n=e.value.slice(i,s),o=["lower","upper","title","sentence"],a=o[this.caseCycleIndex%o.length];this.caseCycleIndex+=1;let l=sc(n,a);e.value=e.value.slice(0,i)+l+e.value.slice(s),e.setSelectionRange(i,i+l.length),this.cursorText=e.value,e.dispatchEvent(new Event("input")),r(),e.focus()}renderSplitSurface(){let r=this.host.createDiv({cls:"stashpad-split-modes"}),e=(p,f,u,g,I=!1)=>{let m=r.createEl("button",{cls:"stashpad-split-mode-btn"});(0,G.setIcon)(m.createSpan({cls:"stashpad-split-btn-icon"}),g),m.createSpan({text:p}),m.toggleClass("is-active",f),m.disabled=I,m.onmousedown=C=>C.preventDefault(),I||(m.onclick=u)};this.lines.length>=2&&e("Line",this.mode==="line",()=>{this.mode="line",this.render()},"separator-horizontal"),e("Cursor",this.mode==="cursor",()=>{this.mode="cursor",this.render()},"text-cursor-input");let t={lines:"list",paragraphs:"pilcrow",headings:"heading"};["lines","paragraphs","headings"].forEach(p=>{let f=Jt(this.body,p).length,u=f<2,g=p==="paragraphs"?"Blank line(s)":ci[p],I=u?g:`${g} (${f})`;e(I,this.mode==="preset"&&this.presetMode===p,()=>{this.mode="preset",this.presetMode=p,this.render()},t[p],u)}),this.mode==="line"?this.renderLineMode():this.mode==="cursor"?this.renderEditorSections():this.renderPresetMode();let i=this.host.createDiv({cls:"stashpad-split-help"}),s=()=>{if(G.Platform.isPhone){i.setCssStyles({display:"none"});return}i.setCssStyles({display:""});let p=this.nest?"New part nested under the original.":"New part added as a sibling.",f=this.nest?"New parts nested under the original.":"New parts added as siblings.",u="\u2318/Ctrl+Enter or Split to confirm";i.setText(this.mode==="line"?`\u2191/\u2193 or click to pick the split line \xB7 ${u} \xB7 ${p}`:this.mode==="cursor"?`Click or arrow to position the cursor \xB7 ${u} \xB7 ${p}`:`Preview of the resulting parts \xB7 ${u} \xB7 ${f}`)};s();let n=this.host.createDiv({cls:"stashpad-split-actions"}),o=n.createEl("button",{cls:"stashpad-split-cancel-btn"});(0,G.setIcon)(o.createSpan({cls:"stashpad-split-btn-icon"}),"x"),o.createSpan({text:"Cancel"}),o.createSpan({cls:"stashpad-split-esc-hint",text:" (Esc)"}),o.onmousedown=p=>p.preventDefault(),o.onclick=()=>this.cb.close(),this.renderPopOut(n),this.renderOpenExternal(n);let a=n.createDiv({cls:"stashpad-split-actions-right"}),l=a.createEl("label",{cls:"stashpad-split-nest"}),c=l.createEl("input",{type:"checkbox"});c.checked=this.nest,l.createSpan({text:"Nest under original"}),c.onchange=()=>{this.nest=c.checked,s()};let A=this.mode==="preset"?Jt(this.body,this.presetMode).length:0,h=a.createEl("button",{cls:"stashpad-split-confirm-btn mod-cta"});(0,G.setIcon)(h.createSpan({cls:"stashpad-split-btn-icon"}),"split"),h.createSpan({text:this.mode==="preset"&&A>=2?`Split into ${A}`:"Split"}),h.onmousedown=p=>p.preventDefault(),h.onclick=()=>this.commit()}renderPresetMode(){let r=Jt(this.body,this.presetMode),e=this.host.createDiv({cls:"stashpad-split-preset-list"});if(r.length<2){e.createDiv({cls:"stashpad-split-empty",text:"This delimiter wouldn't split the note into more than one part."});return}r.forEach((t,i)=>{let s=e.createDiv({cls:"stashpad-split-part-card"}),n=s.createDiv({cls:"stashpad-split-part-num"});n.createSpan({cls:"stashpad-split-part-title",text:`Part ${i+1}`}),n.appendChild(this.makeCopyButton(()=>t,`Copy part ${i+1}`)),s.createDiv({cls:"stashpad-split-part-body",text:t})})}renderLineMode(){let r=this.host.createDiv({cls:"stashpad-split-list"}),e=null;for(let t=0;t{let s=Math.max(1,Math.min(this.lines.length-1,t+1));s!==this.lineCursorIdx&&(this.lineCursorIdx=s,this.render())}}e&&window.requestAnimationFrame(()=>e.scrollIntoView({block:"center"}))}buildSplitSection(r,e,t){let i=r.createDiv({cls:`stashpad-split-section stashpad-split-${e}`}),s=i.createEl("button",{cls:"stashpad-split-section-header"});s.setAttr("type","button");let n=s.createSpan({cls:"stashpad-split-chevron"});(0,G.setIcon)(n,"chevron-down"),s.createSpan({cls:"stashpad-split-section-title",text:t});let o=i.createDiv({cls:"stashpad-split-section-body"}),a=()=>{i.toggleClass("is-collapsed",this.collapsed[e]),s.setAttr("aria-expanded",String(!this.collapsed[e]))};return s.onmousedown=l=>l.preventDefault(),s.onclick=l=>{l.preventDefault(),this.collapsed[e]=!this.collapsed[e],a()},a(),{section:i,body:o}}makeCopyButton(r,e,t="stashpad-split-copy-btn"){let i=createEl("button",{cls:t});return(0,G.setIcon)(i,"copy"),i.setAttr("aria-label",e),i.onmousedown=s=>s.preventDefault(),i.onclick=s=>{s.preventDefault(),s.stopPropagation();let n=r();navigator.clipboard?.writeText(n).then(()=>new G.Notice("Copied to clipboard."),()=>new G.Notice("Couldn't access the clipboard."))},i}renderEditorSections(){if(G.Platform.isMobile){this.renderEditorTabbed();return}let r=this.buildSplitSection(this.host,"orig","Original \u2014 will be replaced");r.body.createDiv({cls:"stashpad-split-panel-body",text:this.body}),r.section.appendChild(this.makeCopyButton(()=>this.body,"Copy the original text","stashpad-split-copy-btn stashpad-split-section-copy"));let e=this.buildSplitSection(this.host,"changes","Changes"),t=e.body.createDiv({cls:"stashpad-split-panel-body stashpad-split-diff-body"}),s=this.buildSplitSection(this.host,"edit",this.surface==="edit"?"Your edit":"Your edit \u2014 the split uses this").body.createEl("textarea",{cls:"stashpad-split-cursor-ta"});s.value=this.cursorText,s.readOnly=!1,this.cursorTextarea=s;let n=()=>{t.empty();for(let h of er(this.body,s.value)){let p=h.t==="ins"?"stashpad-diff-ins":h.t==="del"?"stashpad-diff-del":"stashpad-diff-eq";t.createSpan({cls:p,text:h.s})}},o=()=>{let h=s.value!==this.body;r.section.setCssStyles({display:h?"":"none"}),e.section.setCssStyles({display:h?"":"none"}),h&&n()},a=parseFloat(getComputedStyle(s).lineHeight)||22,l=this.surface==="edit"?G.Platform.isMobile?10:40:G.Platform.isMobile?3:12,c=2,A=()=>{s.setCssStyles({height:"auto"});let h=Math.min(s.scrollHeight,a*l+16);s.setCssStyles({height:`${Math.max(h,a*c+16)}px`})};o(),requestAnimationFrame(()=>{A(),s.focus();let h=this.surface==="edit"?s.value.length:Math.floor(s.value.length/2);s.setSelectionRange(h,h)}),s.addEventListener("input",()=>{this.cursorText=s.value,A(),o()})}renderEditorTabbed(){let r=this.host.createDiv({cls:"stashpad-split-tabs"}),e=r.createDiv({cls:"stashpad-split-tabbar"}),t=r.createDiv({cls:"stashpad-split-tabbody"}),i=t.createDiv({cls:"stashpad-split-tabpanel stashpad-split-tabpanel-edit"}),s=i.createEl("textarea",{cls:"stashpad-split-cursor-ta"});s.value=this.cursorText,s.readOnly=!1,this.cursorTextarea=s;let n=t.createDiv({cls:"stashpad-split-tabpanel"});n.createDiv({cls:"stashpad-split-tab-copybar"}).appendChild(this.makeCopyButton(()=>this.body,"Copy the original text","stashpad-split-copy-btn stashpad-split-tab-copy")),n.createDiv({cls:"stashpad-split-panel-body",text:this.body});let a=t.createDiv({cls:"stashpad-split-tabpanel"}),l=a.createDiv({cls:"stashpad-split-panel-body stashpad-split-diff-body"}),c=[{key:"edit",label:this.surface==="edit"?"Your edit":"Edit",panel:i},{key:"orig",label:"Original",panel:n},{key:"changes",label:"Changes",panel:a}],A={},h="edit",p=g=>{h=g;for(let I of c)I.panel.toggleClass("is-active",I.key===g),A[I.key]?.toggleClass("is-active",I.key===g);g==="edit"&&s.focus()};for(let g of c){let I=e.createEl("button",{cls:"stashpad-split-tab",text:g.label});I.onmousedown=m=>m.preventDefault(),I.onclick=()=>p(g.key),A[g.key]=I}let f=()=>{l.empty();for(let g of er(this.body,s.value)){let I=g.t==="ins"?"stashpad-diff-ins":g.t==="del"?"stashpad-diff-del":"stashpad-diff-eq";l.createSpan({cls:I,text:g.s})}},u=()=>{let g=s.value!==this.body;A.orig.toggleClass("is-hidden",!g),A.changes.toggleClass("is-hidden",!g),g&&f(),!g&&(h==="orig"||h==="changes")&&p("edit")};s.setCssStyles({overflowY:"auto"}),u(),p("edit"),requestAnimationFrame(()=>{s.focus();let g=this.surface==="edit"?s.value.length:Math.floor(s.value.length/2);s.setSelectionRange(g,g)}),s.addEventListener("input",()=>{this.cursorText=s.value,u()})}},ss="stashpad-split-view",pi=class extends G.Modal{constructor(e,t,i,s={}){super(e);this.body=t;this.cbs=i;this.init=s;this.ui=null;this.committing=!1}onOpen(){this.modalEl.addClass("stashpad-split-modal"),this.ui=new Xi(this.app,this.contentEl,this.body,this.init,{onSplitAtLine:this.cbs.onSplitAtLine,onSplitAtChar:this.cbs.onSplitAtChar,onSplitMany:this.cbs.onSplitMany,onSave:this.cbs.onSave,onOpenExternal:this.cbs.onOpenExternal,close:()=>this.close(),onDone:()=>{this.committing=!0,this.close()},onTitle:e=>this.titleEl.setText(e),popOut:this.cbs.popOut?e=>{this.committing=!0,this.close(),this.cbs.popOut(e)}:void 0}),this.scope.register(["Mod"],"Enter",e=>{e.preventDefault(),this.ui?.commit()}),this.scope.register([],"ArrowUp",e=>{this.ui?.moveDivider(-1)&&e.preventDefault()}),this.scope.register([],"ArrowDown",e=>{this.ui?.moveDivider(1)&&e.preventDefault()}),this.scope.register(["Mod"],"e",e=>{e.preventDefault(),this.ui?.setSurface("edit")}),this.scope.register(["Mod"],"s",e=>{e.preventDefault(),this.ui?.setSurface("split")})}close(){if(this.committing||!this.ui?.isDirty()){super.close();return}new j(this.app,"Discard unsaved edits?","You've edited this note but haven't saved. Close and discard your changes?","Discard",e=>{e&&(this.committing=!0,this.close())},"Keep editing",!0).open()}onClose(){this.ui=null,this.contentEl.empty()}},gi=class extends G.ItemView{constructor(e){super(e);this.ui=null;this.ctx=null;this.prevLeaf=null;this.autoCloseTimer=null;this.expiredGrace=null;this.title="Note";this.viewIcon="pencil-line"}getViewType(){return ss}getDisplayText(){return this.title}getIcon(){return this.viewIcon}setHeader(e,t){this.title=e,this.viewIcon=t,this.leaf.updateHeader?.()}setContext(e){this.expiredGrace!=null&&(window.clearTimeout(this.expiredGrace),this.expiredGrace=null),this.ctx=e,this.prevLeaf=e.prevLeaf??null;let t=e.init.surface==="edit";this.setHeader(t?"Edit note":"Split note",t?"pencil-line":"split"),this.renderUI()}async onOpen(){this.contentEl.addClass("stashpad-split-modal","stashpad-split-view"),this.ctx||(this.expiredGrace=window.setTimeout(()=>{this.expiredGrace=null,this.ctx||this.renderExpired()},800))}renderUI(){let e=this.contentEl;e.empty(),e.addClass("stashpad-split-modal","stashpad-split-view"),this.ctx&&(this.ui=new Xi(this.app,e,this.ctx.body,this.ctx.init,{onSplitAtLine:this.ctx.cbs.onSplitAtLine,onSplitAtChar:this.ctx.cbs.onSplitAtChar,onSplitMany:this.ctx.cbs.onSplitMany,onSave:this.ctx.cbs.onSave,onOpenExternal:this.ctx.cbs.onOpenExternal,close:()=>this.guardedDetach(),onDone:()=>this.startClosePanel("\u2713 Done.",null,!0),onTitle:t=>this.setHeader(t,t.startsWith("Edit")?"pencil-line":"split")}),this.registerDomEvent(e,"keydown",t=>{let i=t.metaKey||t.ctrlKey;i&&t.key==="Enter"?(t.preventDefault(),this.ui?.commit()):i&&(t.key==="e"||t.key==="E")?(t.preventDefault(),this.ui?.setSurface("edit")):i&&(t.key==="s"||t.key==="S")?(t.preventDefault(),this.ui?.setSurface("split")):t.key==="ArrowUp"?this.ui?.moveDivider(-1)&&t.preventDefault():t.key==="ArrowDown"&&this.ui?.moveDivider(1)&&t.preventDefault()}))}renderExpired(){this.setHeader("Expired","clock"),this.startClosePanel("This session has expired.","It can't be restored \u2014 closing this tab\u2026",!1)}startClosePanel(e,t,i){let s=this.contentEl;s.empty(),this.ui=null;let n=s.createDiv({cls:"stashpad-split-done"});n.createDiv({cls:"stashpad-split-done-title",text:e}),t&&n.createDiv({cls:"stashpad-split-countdown",text:t});let o=n.createDiv({cls:"stashpad-split-countdown"}),a=n.createDiv({cls:"stashpad-split-done-btns"}),l=a.createEl("button",{cls:"mod-cta",text:"Close now"}),c=a.createEl("button",{text:"Keep tab open"}),A=4,h=()=>o.setText(`Closing this tab in ${A}\u2026`),p=()=>{this.autoCloseTimer!=null&&(window.clearInterval(this.autoCloseTimer),this.autoCloseTimer=null)},f=()=>{p(),i?this.closeAndRefocus():this.leaf.detach()};h(),this.autoCloseTimer=window.setInterval(()=>{A-=1,A<=0?f():h()},1e3),l.onclick=f,c.onclick=()=>{p(),o.setText("Close this tab whenever you're ready."),c.remove(),l.setText("Close tab")}}guardedDetach(){if(!this.ui?.isDirty()){this.leaf.detach();return}new j(this.app,"Discard unsaved edits?","You've edited this note but haven't saved. Close this tab and discard your changes?","Discard",e=>{e&&this.leaf.detach()},"Keep editing",!0).open()}leafStillOpen(e){let t=!1;return this.app.workspace.iterateAllLeaves(i=>{i===e&&(t=!0)}),t}closeAndRefocus(){let e=this.prevLeaf;this.leaf.detach(),e&&this.leafStillOpen(e)&&this.app.workspace.setActiveLeaf(e,{focus:!0})}async onClose(){this.autoCloseTimer!=null&&(window.clearInterval(this.autoCloseTimer),this.autoCloseTimer=null),this.expiredGrace!=null&&(window.clearTimeout(this.expiredGrace),this.expiredGrace=null),this.ui=null,this.contentEl.empty()}};ui=class extends G.Modal{constructor(e,t,i,s,n={}){super(e);this.defaultBaseName=t;this.noteCount=i;this.onConfirm=s;this.opts=n;this.delivered=!1}onOpen(){this.contentEl.empty();let e=!!this.opts.locked;this.titleEl.setText(e?"Export encrypted bundle":"Export"),this.modalEl.addClass("stashpad-export-modal"),this.contentEl.createEl("p",{cls:"stashpad-export-desc",text:e?`Re-export this locked bundle (${this.noteCount} note${this.noteCount===1?"":"s"}) as a shareable .stash.`:`Export ${this.noteCount} note${this.noteCount===1?"":"s"}.`});let t=this.contentEl.createDiv({cls:"stashpad-export-field"});t.createEl("label",{cls:"stashpad-export-label",text:"File name"});let i=t.createEl("input",{type:"text"});i.addClass("stashpad-export-name"),i.value=this.defaultBaseName;let s=this.contentEl.createEl("div",{cls:"stashpad-export-preview"}),n="full",o=()=>{},a=this.contentEl.createDiv();nc(a,Y=>{n=Y,o()}),e&&a.setCssStyles({display:"none"});let l="stash",c=this.contentEl.createDiv({cls:"stashpad-export-format"});c.createEl("label",{cls:"stashpad-export-label",text:"Format"});let A=c.createDiv({cls:"stashpad-export-content-seg"}),h=[{id:"stash",label:"Stashpad .stash"},...this.opts.okfEnabled?[{id:"okf",label:"OKF bundle"}]:[],{id:"zip",label:"Plain .zip"}],p=new Map;for(let Y of h){let Se=A.createEl("button",{cls:"stashpad-export-content-opt",text:Y.label});Se.toggleClass("is-active",Y.id===l),Se.onclick=Ce=>{Ce.preventDefault(),l=Y.id,p.forEach((Me,Xe)=>Me.toggleClass("is-active",Xe===l)),o()},p.set(Y.id,Se)}let f=this.contentEl.createDiv({cls:"stashpad-okf-formats"}),u=(Y,Se)=>{let Ce=f.createDiv({cls:"stashpad-okf-fmt"}),Me=Ce.createEl("input",{type:"checkbox"});return Me.checked=Se,Ce.createEl("label",{text:Y}),Me.onchange=()=>o(),Me},g=u(".zip \u2014 OKF bundle (portable)",!0),I=u(".tar.gz \u2014 OKF bundle (tarball)",!1),m=f.createDiv({cls:"stashpad-export-pw-hint is-error"});m.setText("Pick at least one OKF format."),m.setCssStyles({display:"none"}),e&&c.setCssStyles({display:"none"});let C=this.contentEl.createDiv({cls:"stashpad-export-zipwarn"});C.setText("Frontmatter-only / body-only exports save as a plain .zip of the selected markdown (with referenced attachments) \u2014 not a re-importable .stash."),C.setCssStyles({display:"none"});let B=this.contentEl.createDiv({cls:"stashpad-export-encrypt"}),E=B.createDiv({cls:"stashpad-export-toggle"}),y=E.createEl("input",{type:"checkbox"});y.id="stashpad-export-encrypt-cb";let Q=E.createEl("label",{text:"Encrypt with a password"});Q.htmlFor=y.id;let w=B.createDiv({cls:"stashpad-export-pw-area"});w.setCssStyles({display:"none"});let v=[],F=Y=>{let Se=w.createDiv({cls:"stashpad-export-pw-row"}),Ce=Se.createEl("input",{type:"password"});Ce.addClass("stashpad-export-name"),Ce.placeholder=Y;let Me=Se.createEl("button",{cls:"stashpad-export-copy"}),Xe=()=>{let kt=Ce.value.length===0;Me.setText(kt?"Paste":"Copy"),Me.toggleClass("is-paste",kt),Me.setAttr("aria-label",`${kt?"Paste into":"Copy"} ${Y.toLowerCase()}`)};return Me.onclick=async kt=>{if(kt.preventDefault(),Ce.value.length===0)try{let Ps=(await navigator.clipboard?.readText())?.trim();if(!Ps){new G.Notice("Clipboard is empty.");return}Ce.value=Ps,Ce.dispatchEvent(new Event("input")),new G.Notice("Pasted from clipboard.")}catch{new G.Notice("Couldn't read the clipboard.")}else navigator.clipboard?.writeText(Ce.value).then(()=>new G.Notice("Passphrase copied to clipboard."),()=>new G.Notice("Couldn't access the clipboard."))},Xe(),v.push(Xe),Ce},D=F("Password"),H=F("Confirm password"),R=w.createDiv({cls:"stashpad-export-strength"}),L=R.createDiv({cls:"stashpad-strength-bar"}),x=[0,1,2,3].map(()=>L.createDiv({cls:"stashpad-strength-seg"})),U=R.createEl("span",{cls:"stashpad-strength-label"}),N=w.createDiv({cls:"stashpad-export-genrow"}),b=N.createEl("button",{cls:"stashpad-export-gen",text:"Generate strong passphrase"}),M=N.createEl("button",{cls:"stashpad-export-show",text:"Show"}),O=w.createEl("div",{cls:"stashpad-export-pw-hint"}),K=w.createEl("div",{cls:"stashpad-export-pw-suite"});K.setText("Encryption: AES-256-GCM. Checking key-derivation suite for this device\u2026"),this.opts.kdfProbe?this.opts.kdfProbe().then(Y=>{K.toggleClass("is-weak",!Y),K.setText(Y?"Encryption: Argon2id + AES-256-GCM \u2014 the strongest suite (used on this device).":"\u26A0\uFE0F Argon2id can't run on this device, so this export will use the weaker PBKDF2 (600k) + AES-256-GCM fallback.")}).catch(()=>{K.setText("Encryption: AES-256-GCM with a password-derived key.")}):K.setText("Encryption: Argon2id + AES-256-GCM (falls back to PBKDF2 if Argon2 can't run here).");let $=this.app.secretStorage,Z=w.createDiv({cls:"stashpad-export-remember"}),V=Z.createEl("input",{type:"checkbox"});V.checked=!0,V.id="stashpad-export-remember-cb";let q=Z.createEl("label",{text:"Remember in this vault (this device) \u2014 skips the prompt when you re-import here."});q.htmlFor=V.id;let ee=w.createDiv({cls:"stashpad-export-remember-note"});ee.setText("Saved only in this device's keychain \u2014 it doesn't sync to your other devices and isn't shared with anyone you send this file to. Keep the passphrase somewhere safe if you'll open this export elsewhere."),ee.setCssStyles({display:V.checked?"":"none"}),V.onchange=()=>{ee.setCssStyles({display:V.checked?"":"none"})},$||Z.setCssStyles({display:"none"});let ge=()=>e?"stash":n!=="full"?"zip":l,oe=()=>{let Y=i.value.trim()||this.defaultBaseName;return!e&&n!=="full"?`${Y}-${n}`:ge()==="stash"&&y.checked?`${Y}-encrypted`:Y},ie=()=>{let Y=ge();if(Y==="stash"){s.setText(`Saves as: ${oe()}-.stash`);return}if(Y==="okf"){s.setText(`Saves as: ${oe()}-.zip / .tar.gz (OKF bundle)`);return}s.setText(`Saves as: ${oe()}-.zip (plain archive \u2014 not re-importable)`)};i.oninput=ie;let te=this.contentEl.createDiv({cls:"stashpad-export-footer"}),ue=te.createEl("button",{text:"Cancel"});ue.onclick=()=>this.close();let ye=te.createEl("button",{cls:"mod-cta",text:"Export"}),se=()=>{let Y=Bo(D.value);R.style.visibility=D.value?"visible":"hidden",x.forEach((Se,Ce)=>Se.toggleClass("is-on",D.value!==""&&Ce<=Y.level)),L.dataset.level=String(Y.level),U.setText(Y.label)},de=()=>{let Y=!e&&n!=="full",Se=ge();c.setCssStyles({display:!e&&!Y?"":"none"}),f.setCssStyles({display:!e&&!Y&&l==="okf"?"":"none"}),C.setCssStyles({display:Y?"":"none"});let Ce=Se==="stash";B.setCssStyles({display:Ce?"":"none"});let Me=Ce&&y.checked;w.setCssStyles({display:Me?"":"none"});let Xe=!0;Me&&(D.value?D.value!==H.value?(O.setText("Passwords don't match."),O.addClass("is-error"),Xe=!1):(O.setText("\u26A0\uFE0F If you lose this password, the export can't be recovered."),O.removeClass("is-error")):(O.setText("Enter a password to encrypt this export."),O.removeClass("is-error"),Xe=!1));let kt=!e&&!Y&&l==="okf"&&!g.checked&&!I.checked;m.setCssStyles({display:kt?"":"none"}),kt&&(Xe=!1),se(),v.forEach(Ps=>Ps()),ye.disabled=!Xe,ye.toggleClass("is-disabled",!Xe),ie()},We=!1,si=Y=>{We=Y,D.type=H.type=Y?"text":"password",M.setText(Y?"Hide":"Show")};M.onclick=Y=>{Y.preventDefault(),si(!We)},b.onclick=Y=>{Y.preventDefault(),D.value=H.value=Co(),si(!1),new G.Notice("Passphrase generated (hidden) \u2014 Show to view, or Copy to save it."),de()},y.onchange=de,D.oninput=de,H.oninput=de,o=de,de();let Ms=()=>{let Y=ge(),Se=Y==="stash"&&y.checked?D.value:null;this.commit({baseName:oe(),content:n,format:Y,okf:{zip:g.checked,targz:I.checked},password:Se,remember:!!Se&&V.checked})};ye.onclick=Ms,this.scope.register([],"Enter",Y=>{Y.preventDefault(),ye.disabled||Ms()}),requestAnimationFrame(()=>{i.focus(),i.select()})}commit(e){let t=e.baseName.trim()||this.defaultBaseName,i=e.password&&e.password.length?e.password:null;this.delivered=!0,this.close(),this.onConfirm({...e,baseName:t,password:i,remember:!!i&&e.remember})}onClose(){this.contentEl.empty()}},Zi=class extends G.Modal{constructor(e,t,i,s){super(e);this.errorMsg=t;this.allowLater=i;this.onResult=s;this.delivered=!1}onOpen(){this.contentEl.empty(),this.titleEl.setText("Encrypted .stash"),this.modalEl.addClass("stashpad-export-modal"),this.contentEl.createEl("p",{cls:"stashpad-export-desc",text:"This export is password-protected. Enter its password to import it."}),this.errorMsg&&this.contentEl.createEl("div",{cls:"stashpad-export-error",text:this.errorMsg});let e=this.contentEl.createEl("input",{type:"password"});e.addClass("stashpad-export-name"),e.placeholder="Password";let t=this.contentEl.createDiv({cls:"stashpad-export-footer"});if(t.createEl("button",{text:"Cancel"}).onclick=()=>this.close(),this.allowLater){let s=t.createEl("button",{text:"Remind me later"});s.title="Don't import now \u2014 surface the reminder again later.",s.onclick=()=>this.finish({kind:"later"})}let i=t.createEl("button",{cls:"mod-cta",text:"Decrypt & import"});i.onclick=()=>this.submit(e.value),this.scope.register([],"Enter",s=>{s.preventDefault(),this.submit(e.value)}),requestAnimationFrame(()=>e.focus())}submit(e){e&&this.finish({kind:"password",value:e})}finish(e){this.delivered=!0,this.close(),this.onResult(e)}onClose(){this.delivered||(this.delivered=!0,this.onResult({kind:"cancel"})),this.contentEl.empty()}},Re=class extends G.Modal{constructor(e,t){super(e);this.opts=t;this.succeeded=!1}onOpen(){let{mode:e}=this.opts;this.contentEl.empty(),this.modalEl.addClass("stashpad-export-modal","stashpad-encryption-modal"),this.titleEl.setText(this.opts.title??(e==="setup"?"Set up encryption password":e==="change"?"Change encryption password":"Unlock encryption")),this.contentEl.createDiv({cls:"stashpad-beta-row"}).createEl("span",{cls:"stashpad-beta-badge",text:"BETA"}),this.opts.intro?this.contentEl.createEl("p",{cls:"stashpad-export-desc",text:this.opts.intro}):e==="setup"&&this.contentEl.createEl("p",{cls:"stashpad-export-desc",text:"This single password protects everything you encrypt in this vault. It is stored only on this device. There is NO recovery \u2014 if you lose it, anything you've encrypted is gone for good."});let t=[],i=g=>{let I=this.contentEl.createDiv({cls:"stashpad-export-pw-row stashpad-encryption-row"}),m=I.createEl("input",{type:"password"});m.addClass("stashpad-export-name","stashpad-encryption-field"),m.placeholder=g;let C=I.createEl("button",{cls:"stashpad-export-copy"}),B=()=>{let E=m.value.length===0;C.setText(E?"Paste":"Copy"),C.toggleClass("is-paste",E),C.setAttr("aria-label",`${E?"Paste into":"Copy"} ${g.toLowerCase()}`)};return C.onclick=async E=>{if(E.preventDefault(),m.value.length===0)try{let y=(await navigator.clipboard?.readText())?.trim();if(!y){new G.Notice("Clipboard is empty.");return}m.value=y,m.dispatchEvent(new Event("input")),new G.Notice("Pasted from clipboard.")}catch{new G.Notice("Couldn't read the clipboard.")}else navigator.clipboard?.writeText(m.value).then(()=>new G.Notice("Copied to clipboard."),()=>new G.Notice("Couldn't access the clipboard."))},m.addEventListener("input",B),B(),t.push(B),m},s=null,n=null,o=null;if((e==="unlock"||e==="change")&&(s=i("Current password")),(e==="setup"||e==="change")&&(n=i(e==="change"?"New password":"Password"),o=i("Confirm password")),n){let g=this.contentEl.createDiv({cls:"stashpad-export-strength"}),I=g.createDiv({cls:"stashpad-strength-bar"}),m=[0,1,2,3].map(()=>I.createDiv({cls:"stashpad-strength-seg"})),C=g.createEl("span",{cls:"stashpad-strength-label"}),B=this.contentEl.createDiv({cls:"stashpad-encryption-counter"}),E=()=>{let v=n.value,F=Bo(v);m.forEach((D,H)=>D.toggleClass("is-on",H0&&v.length<6?" \u2014 use at least 6":""}`),B.toggleClass("is-weak",v.length>0&&v.length<6)};n.addEventListener("input",E),E();let y=this.contentEl.createDiv({cls:"stashpad-export-genrow"});y.createEl("button",{cls:"stashpad-export-gen",text:"Generate strong passphrase"}).onclick=v=>{v.preventDefault();let F=Co(5);n.value=F,o&&(o.value=F),E(),t.forEach(D=>D()),new G.Notice("Generated \u2014 copy it somewhere safe; there's no recovery."),navigator.clipboard?.writeText(F).catch(()=>{})};let Q=y.createEl("button",{cls:"stashpad-export-show",text:"Show"});Q.onclick=v=>{v.preventDefault();let F=n.type==="password";n.type=F?"text":"password",o&&(o.type=F?"text":"password"),Q.setText(F?"Hide":"Show")};let w=this.contentEl.createEl("div",{cls:"stashpad-export-pw-suite"});w.setText("Encryption: AES-256-GCM. Checking key-derivation suite\u2026"),this.opts.kdfProbe?this.opts.kdfProbe().then(v=>{w.toggleClass("is-weak",!v),w.setText(v?"Encryption: Argon2id + AES-256-GCM \u2014 the strongest suite (used on this device).":"\u26A0\uFE0F Argon2id can't run here, so this will use the weaker PBKDF2 (600k) + AES-256-GCM fallback.")}).catch(()=>w.setText("Encryption: AES-256-GCM with a password-derived key.")):w.setText("Encryption: Argon2id + AES-256-GCM (PBKDF2 fallback if Argon2 can't run here).")}let a=null,l=this.app.secretStorage;if(this.opts.offerKeychain&&l){let g=this.contentEl.createDiv({cls:"stashpad-export-remember"});a=g.createEl("input",{type:"checkbox"}),a.id="stashpad-enc-remember",a.checked=!0;let I=g.createEl("label",{text:"Remember on this device (keychain) \u2014 auto-unlock here without re-typing."});I.htmlFor=a.id;let m=this.contentEl.createDiv({cls:"stashpad-export-remember-note"});m.setText("Stored only in this device's keychain \u2014 doesn't sync to your other devices. Anyone with access to this unlocked device + keychain could decrypt."),m.setCssStyles({display:a.checked?"":"none"}),a.onchange=()=>{m.setCssStyles({display:a.checked?"":"none"})}}let c=this.contentEl.createEl("div",{cls:"stashpad-export-error"});c.setCssStyles({display:"none"});let A=g=>{c.setText(g),c.setCssStyles({display:""})},h=this.contentEl.createDiv({cls:"stashpad-export-footer"});h.createEl("button",{text:"Cancel"}).onclick=()=>this.close();let p=h.createEl("button",{cls:"mod-cta",text:e==="setup"?"Set up":e==="change"?"Change":"Unlock"}),f=!1,u=async()=>{if(f)return;let g=s?.value??void 0,I=n?.value??void 0;if((e==="unlock"||e==="change")&&!g){A("Enter your current password.");return}if(e==="setup"||e==="change"){if(!I){A("Enter a password.");return}if(I.length<6){A("Use at least 6 characters.");return}if(I!==o?.value){A("Passwords don't match.");return}}f=!0,p.disabled=!0,c.setCssStyles({display:"none"});let m=p.textContent;p.setText("Working\u2026");try{let C=await this.opts.onSubmit({current:g,next:I,remember:!!a?.checked});if(C){A(C),f=!1,p.disabled=!1,p.setText(m??"OK");return}this.succeeded=!0,this.close()}catch(C){A(`Failed: ${C.message}`),f=!1,p.disabled=!1,p.setText(m??"OK")}};p.onclick=()=>void u(),this.scope.register([],"Enter",g=>{g.preventDefault(),u()}),requestAnimationFrame(()=>(s??n)?.focus())}onClose(){this.contentEl.empty(),this.succeeded||this.opts.onCancel?.()}},fi=class extends G.Modal{constructor(e,t){super(e);this.opts=t}onOpen(){this.contentEl.empty(),this.modalEl.addClass("stashpad-export-modal","stashpad-encryption-modal"),this.titleEl.setText(this.opts.title),this.contentEl.createEl("p",{cls:"stashpad-export-desc",text:this.opts.body});let e=null;this.opts.requirePassword&&(this.contentEl.createEl("p",{cls:"stashpad-export-desc"}).setText("Enter your encryption password:"),e=this.contentEl.createEl("input",{type:"password"}),e.addClass("stashpad-export-name","stashpad-encryption-field"),e.placeholder="Password"),this.contentEl.createEl("p",{cls:"stashpad-export-desc"}).setText(`Type "${this.opts.phrase}" to confirm.`);let t=this.contentEl.createEl("input",{type:"text"});t.addClass("stashpad-export-name","stashpad-encryption-field"),t.placeholder=this.opts.phrase;let i=this.contentEl.createEl("div",{cls:"stashpad-export-error"});i.setCssStyles({display:"none"});let s=this.contentEl.createDiv({cls:"stashpad-export-footer"});s.createEl("button",{text:"Cancel"}).onclick=()=>this.close();let n=s.createEl("button",{cls:"mod-cta mod-warning",text:this.opts.confirmText}),o=()=>t.value.trim().toLowerCase()===this.opts.phrase.trim().toLowerCase(),a=()=>{n.disabled=!o()||!!this.opts.requirePassword&&!e?.value};t.addEventListener("input",a),e?.addEventListener("input",a),a();let l=!1,c=async()=>{if(!(l||!o())){if(this.opts.requirePassword&&(l=!0,n.disabled=!0,i.setCssStyles({display:"none"}),!await this.opts.requirePassword(e.value))){i.setText("Wrong password."),i.setCssStyles({display:""}),l=!1,a();return}this.close(),await this.opts.onConfirm()}};n.onclick=()=>void c(),this.scope.register([],"Enter",A=>{A.preventDefault(),c()}),requestAnimationFrame(()=>(e??t).focus())}onClose(){this.contentEl.empty()}},ji=class extends G.Modal{constructor(e,t){super(e);this.onSubmit=t}onOpen(){this.contentEl.empty(),this.modalEl.addClass("stashpad-export-modal"),this.titleEl.setText("Open Stashpad link"),this.contentEl.createEl("p",{cls:"stashpad-export-desc",text:"Paste one or more obsidian://stashpad links (one per line) to jump to the notes they point to. Multiple links each open in their own tab."});let e=this.contentEl.createDiv({cls:"stashpad-open-link-row"}),t=e.createEl("button",{cls:"stashpad-open-link-paste"});(0,G.setIcon)(t.createSpan({cls:"stashpad-open-link-paste-icon"}),"clipboard-paste"),t.createSpan({text:"Paste"}),t.title="Paste from clipboard";let i=e.createEl("textarea",{attr:{rows:"3"}});i.addClass("stashpad-export-name"),i.placeholder="obsidian://stashpad?folder=\u2026¬e=\u2026",t.onclick=async()=>{try{let l=(await navigator.clipboard?.readText?.())?.trim();l&&(i.value=l,s.hide()),i.focus()}catch{new G.Notice("Couldn't read the clipboard \u2014 paste manually.")}},i.addEventListener("input",()=>s.hide());let s=this.contentEl.createEl("div",{cls:"stashpad-open-link-autohint"});(0,G.setIcon)(s.createSpan({cls:"stashpad-open-link-autohint-icon"}),"clipboard-check"),s.createSpan({text:"Link automatically pasted from your clipboard."}),s.hide();let n=this.contentEl.createDiv({cls:"stashpad-export-footer"});n.createEl("button",{text:"Cancel"}).onclick=()=>this.close();let o=n.createEl("button",{cls:"mod-cta",text:"Open"}),a=()=>{let l=i.value.trim();l&&(this.close(),this.onSubmit(l))};o.onclick=()=>a(),this.scope.register([],"Enter",l=>{l.preventDefault(),a()}),requestAnimationFrame(()=>{i.focus(),navigator.clipboard?.readText?.().then(l=>{!i.value&&l&&/obsidian:\/\/stashpad\?/i.test(l.trim())&&(i.value=l.trim(),i.select(),s.show())}).catch(()=>{})})}onClose(){this.contentEl.empty()}},Js=class extends G.Modal{constructor(e,t,i){super(e);this.onResult=i;this.delivered=!1;this.touched=!1;this.value=t&&/^#[0-9a-f]{6}$/i.test(t)?t:"#888888"}onOpen(){this.contentEl.empty(),this.titleEl.setText("Custom color"),this.modalEl.addClass("stashpad-custom-color-modal");let e=this.contentEl.createDiv({cls:"stashpad-custom-color-row"}),t=e.createDiv({cls:"stashpad-custom-color-preview"});t.style.background=this.value;let i=e.createEl("input",{type:"color"});i.value=this.value,i.addClass("stashpad-custom-color-wheel"),t.onclick=()=>i.click();let s=e.createEl("input",{type:"text"});s.addClass("stashpad-custom-color-hex"),s.placeholder="#RRGGBB",s.value=this.value,s.maxLength=7;let n=A=>{let h=A.startsWith("#")?A:"#"+A;/^#[0-9a-f]{6}$/i.test(h)&&(this.touched=!0,this.value=h,t.style.background=h,i.value=h,s.value!==h&&(s.value=h))};i.oninput=()=>n(i.value),s.oninput=()=>n(s.value);let o=this.contentEl.createDiv({cls:"stashpad-color-footer"}),a=o.createEl("button",{text:"Cancel"});a.onclick=()=>{this.delivered=!0,this.close()};let l=o.createEl("button",{cls:"mod-cta",text:"Save"});l.title="Apply this color to the selection (without adding to your palette).",l.onclick=()=>this.commit({addToPalette:!1});let c=o.createEl("button",{cls:"mod-cta",text:"Add to palette"});c.title="Apply and save this color so it appears as a tile next time.",c.onclick=()=>this.commit({addToPalette:!0}),this.scope.register([],"Enter",A=>{A.preventDefault(),this.commit({addToPalette:!1})}),this.scope.register(["Mod"],"Enter",A=>{A.preventDefault(),this.commit({addToPalette:!0})}),requestAnimationFrame(()=>s.focus())}commit(e){this.delivered=!0,this.close(),this.onResult(this.value,e)}onClose(){!this.delivered&&this.touched&&(this.delivered=!0,this.onResult(this.value,{addToPalette:!1})),this.contentEl.empty()}},Wi=class Wi extends G.Modal{constructor(e,t,i,s,n){super(e);this.currentColor=t;this.customPalette=i;this.onPick=s;this.onDeleteCustom=n;this.focusIdx=-1;this.scopeBound=!1;this.items=[]}onOpen(){this.contentEl.empty(),this.titleEl.setText("Pick a color"),this.modalEl.addClass("stashpad-color-modal");let e=this.contentEl.createDiv({cls:"stashpad-color-grid"});this.items=[];let t=e.createDiv({cls:"stashpad-color-tile stashpad-color-none"});t.title="No color",t.onclick=()=>this.activate(0),this.items.push({kind:"none",color:null,el:t});let i=[...Wi.DEFAULT_PALETTE,...this.customPalette];for(let a of i){let l=e.createDiv({cls:"stashpad-color-tile"});l.style.background=a,l.title=a;let c=!Wi.DEFAULT_PALETTE.some(h=>h.toLowerCase()===a.toLowerCase()),A=this.items.length;if(l.onclick=()=>this.activate(A),c&&this.onDeleteCustom){let h=l.createSpan({cls:"stashpad-color-tile-del",text:"\xD7"});h.title="Remove from palette",h.onclick=p=>{p.stopPropagation(),this.handleDelete(a)}}this.items.push({kind:c?"custom":"preset",color:a,el:l})}let s=e.createDiv({cls:"stashpad-color-tile stashpad-color-add"});s.title="Custom color\u2026";let n=this.items.length;s.onclick=()=>this.activate(n),this.items.push({kind:"add",color:null,el:s});let o=this.items.findIndex(a=>this.currentColor===null?a.kind==="none":this.currentColor?a.color!==null&&a.color.toLowerCase()===this.currentColor.toLowerCase():!1);this.focusIdx=o>=0?o:0,this.refreshActive(),this.scopeBound||(this.scope.register([],"ArrowRight",a=>{a.preventDefault(),this.moveFocus(1)}),this.scope.register([],"ArrowLeft",a=>{a.preventDefault(),this.moveFocus(-1)}),this.scope.register([],"ArrowDown",a=>{a.preventDefault(),this.moveFocus(this.columns())}),this.scope.register([],"ArrowUp",a=>{a.preventDefault(),this.moveFocus(-this.columns())}),this.scope.register([],"Enter",a=>{a.preventDefault(),this.activate(this.focusIdx)}),this.scopeBound=!0),requestAnimationFrame(()=>this.modalEl.focus())}activate(e){if(e<0||e>=this.items.length)return;this.focusIdx=e,this.refreshActive();let t=this.items[e];if(t.kind==="add"){this.close(),new Js(this.app,this.currentColor,(i,s)=>{this.onPick(i,s)}).open();return}this.close(),this.onPick(t.color,{addToPalette:!1})}columns(){if(!this.items.length)return 1;let e=this.items[0].el.parentElement;if(!e)return 1;let t=e.getBoundingClientRect(),i=this.items[0].el.getBoundingClientRect();if(i.width<=0)return 1;let s=i.top,n=0;for(let o of this.items){let a=o.el.getBoundingClientRect();if(Math.abs(a.top-s)<1)n++;else break}return Math.max(1,n)}async handleDelete(e){if(this.onDeleteCustom)try{let t=await this.onDeleteCustom(e);this.customPalette=Array.isArray(t)?t:this.customPalette.filter(i=>i.toLowerCase()!==e.toLowerCase()),this.onOpen()}catch(t){console.warn("Stashpad: palette delete failed",t)}}moveFocus(e){if(!this.items.length)return;let t=Math.max(0,Math.min(this.items.length-1,this.focusIdx+e));this.focusIdx=t,this.refreshActive()}refreshActive(){for(let e=0;e{this.didChoose=!0,this.close(),this.onChoose(!1)};let s=t.createEl("button",{cls:"mod-cta",text:this.confirmText});s.onclick=()=>{this.didChoose=!0,this.close(),this.onChoose(!0)},requestAnimationFrame(()=>(this.dangerous?i:s).focus())}onClose(){this.contentEl.empty(),this.didChoose||(this.didChoose=!0,this.onChoose(!1))}},_i=class extends G.Modal{constructor(e,t,i,s={}){super(e);this.levels=t;this.onPick=i;this.opts=s}onOpen(){this.modalEl?.addClass("stashpad-compact-modal"),this.modalEl?.addClass("stashpad-breadcrumb-modal"),this.contentEl.empty(),this.titleEl.setText("Jump to level");let e=this.contentEl.createDiv({cls:"stashpad-bc-levels"});for(let t of this.levels){let i=e.createDiv({cls:"stashpad-bc-level-row"});if(t.isCurrent&&i.addClass("is-current"),i.createSpan({cls:"stashpad-bc-level-num",text:String(t.level)}),i.createSpan({cls:"stashpad-bc-level-label",text:t.label}),!t.isCurrent){i.setAttribute("role","button"),i.setAttribute("tabindex","0");let s=()=>{this.close(),this.onPick(t.id)};i.onclick=s,i.onkeydown=n=>{(n.key==="Enter"||n.key===" ")&&(n.preventDefault(),s())}}this.opts.onContext&&(i.oncontextmenu=s=>{s.preventDefault(),this.opts.onContext(t.id,s,i,()=>this.close())},this.opts.attachLongPress?.(i,()=>this.opts.onContext(t.id,null,i,()=>this.close())))}}onClose(){this.contentEl.empty()}};Je=class extends G.Modal{constructor(e,t,i,s={}){super(e);this.current=t;this.onPick=i;this.opts=s;this.didChoose=!1;this.assignees=[];this.tinyClosePopover=null;this.assignees=[...s.currentAssignees??[]]}onOpen(){this.modalEl?.addClass("stashpad-compact-modal"),this.contentEl.empty(),this.titleEl.setText(this.opts.title??"Set due date");let e=null;if(this.current){let w=Date.parse(this.current);Number.isNaN(w)||(e=new Date(w))}let t=this.contentEl.createDiv({cls:"stashpad-due-picker"}),i=t.createDiv({cls:"stashpad-due-fields"}),s=i.createDiv({cls:"stashpad-due-field"}),n=s.createSpan({cls:"stashpad-due-field-icon"});(0,G.setIcon)(n,"calendar");let o=s.createEl("input",{type:"date",cls:"stashpad-due-date"}),a=s.createSpan({cls:"stashpad-due-clear",attr:{"aria-label":"Clear date"}});(0,G.setIcon)(a,"x"),a.onclick=()=>{o.value="",o.focus()};let l=i.createDiv({cls:"stashpad-due-field"}),c=l.createSpan({cls:"stashpad-due-field-icon"});(0,G.setIcon)(c,"clock");let A=l.createEl("input",{type:"time",cls:"stashpad-due-time"}),h=l.createSpan({cls:"stashpad-due-clear",attr:{"aria-label":"Clear time"}});(0,G.setIcon)(h,"x"),h.onclick=()=>{A.value="",A.focus()},n.onclick=()=>{try{o.showPicker?.()}catch{}},c.onclick=()=>this.openTimeNumpad(c,A),e&&(o.value=this.toDateValue(e),A.value=this.toTimeValue(e));let p=(this.opts.quickAdjusts??tr).map(w=>({raw:w,min:ir(w)})).filter(w=>w.min!=null);if(p.length>0){let w=1,v=t.createDiv({cls:"stashpad-due-quickadjust"}),F=v.createEl("button",{cls:"stashpad-due-adjust-flip",attr:{type:"button"}}),D=()=>{F.setText(w>0?"+":"\u2212"),F.toggleClass("is-minus",w<0),F.title=w>0?"Adding time (click to subtract)":"Subtracting time (click to add)"};D(),F.onclick=()=>{w=-w,D()};let H=R=>{let L=new Date,x,U,N;if(o.value){let[K,$,Z]=o.value.split("-").map(V=>parseInt(V,10));x=K,U=$-1,N=Z}else x=L.getFullYear(),U=L.getMonth(),N=L.getDate();let b,M;if(A.value){let[K,$]=A.value.split(":").map(Z=>parseInt(Z,10));b=K,M=$}else b=L.getHours(),M=L.getMinutes();let O=new Date(x,U,N,b,M,0,0);O.setMinutes(O.getMinutes()+w*R),o.value=this.toDateValue(O),A.value=this.toTimeValue(O)};for(let R of p){let L=v.createEl("button",{cls:"stashpad-due-adjust-btn",text:R.raw,attr:{type:"button"}});L.onclick=()=>H(R.min)}}this.opts.hideAssignees||this.renderAssignSection(t);let f=t.createDiv({cls:"stashpad-due-grid"}),u=(w,v)=>{let F=f.createEl("button",{cls:"stashpad-due-btn stashpad-due-preset",text:w});F.onclick=()=>{let D=v();o.value=this.toDateValue(D),A.value||(A.value=this.toTimeValue(D))}},g=w=>(w.setHours(9,0,0,0),w);u("Today",()=>g(this.startOfTodayLocal())),u("Tomorrow",()=>{let w=this.startOfTodayLocal();return w.setDate(w.getDate()+1),g(w)}),u("Next week",()=>{let w=this.startOfTodayLocal();return w.setDate(w.getDate()+7),g(w)});let I=f.createEl("button",{cls:"stashpad-due-btn",text:"Clear"});I.onclick=()=>{o.value="",A.value="",o.focus()};let m=null,C=null,B=null;if(this.opts.showRecurrence){let w=t.createEl("details",{cls:"stashpad-due-recur"});(this.opts.currentRepeat||this.opts.currentAutoDoneAfter||this.opts.currentRemindEvery)&&(w.open=!0),w.createEl("summary",{text:"\u{1F501} Repeat & reminders"});let v=(F,D,H)=>{let R=w.createDiv({cls:"stashpad-due-recur-row"});R.createEl("label",{text:F});let L=R.createEl("input",{type:"text",attr:{placeholder:D}});return H&&(L.value=H),L};m=v("Repeat",'e.g. "every weekday", "every 30 days when done"',this.opts.currentRepeat),C=v("Auto-complete after",'e.g. "1d" \u2014 mark done once this overdue',this.opts.currentAutoDoneAfter),B=v("Remind every",'e.g. "2h" \u2014 re-notify until done',this.opts.currentRemindEvery)}let E=()=>this.opts.showRecurrence?{repeat:m.value.trim(),autoDoneAfter:C.value.trim(),remindEvery:B.value.trim()}:{},y=f.createEl("button",{cls:"stashpad-due-btn",text:"Cancel"});y.onclick=()=>{this.didChoose=!0,this.close()};let Q=f.createEl("button",{cls:"stashpad-due-btn mod-cta",text:"Set"});Q.onclick=()=>{if(!o.value){this.didChoose=!0,this.close(),this.onPick({iso:null,assignees:this.assignees,...E()});return}let[w,v,F]=o.value.split("-").map(L=>parseInt(L,10)),D=9,H=0;if(A.value){let[L,x]=A.value.split(":").map(U=>parseInt(U,10));D=L,H=x}let R=new Date(w,v-1,F,D,H,0,0);this.didChoose=!0,this.close(),this.onPick({iso:R.toISOString(),assignees:this.assignees,...E()})},requestAnimationFrame(()=>o.focus())}onClose(){this.tinyClosePopover?.(),this.contentEl.empty(),this.didChoose}renderAssignSection(e){sr(e,{knownAuthors:this.opts.knownAuthors??[],initial:this.assignees,onChange:t=>{this.assignees=t}})}openTimeNumpad(e,t){this.tinyClosePopover?.();let i=e.ownerDocument??document,s=i.defaultView??window,n=9,o=0;if(t.value){let[I,m]=t.value.split(":").map(C=>parseInt(C,10));Number.isFinite(I)&&(n=I),Number.isFinite(m)&&(o=m)}else{let I=new Date;n=I.getHours(),o=I.getMinutes()}let a=n>=12?"pm":"am",l=n===0?12:n>12?n-12:n,A=(this.modalEl??i.body).createDiv({cls:"stashpad-when-popover stashpad-due-time-pop"});A.setCssStyles({position:"fixed",zIndex:"9999"});let h=null,p=()=>{A.remove(),i.removeEventListener("mousedown",f,!0),i.removeEventListener("keydown",u,!0),this.tinyClosePopover===p&&(this.tinyClosePopover=null)},f=I=>{!A.contains(I.target)&&I.target!==e&&!e.contains(I.target)&&p()},u=I=>{I.key==="Escape"?(I.preventDefault(),I.stopPropagation(),p()):I.key==="Enter"&&h&&(I.preventDefault(),I.stopPropagation(),h())};this.tinyClosePopover=p,Os(A,{seedH:l,seedM:o,seedPeriod:a,close:p,setOnEnter:I=>{h=I},onFinalize:I=>{t.value=`${String(I.hours24).padStart(2,"0")}:${String(I.minutes).padStart(2,"0")}`}});let g=e.getBoundingClientRect();A.setCssStyles({left:`${Math.max(8,Math.min(g.left,s.innerWidth-220))}px`,top:`${g.bottom+4}px`}),setTimeout(()=>{i.addEventListener("mousedown",f,!0),i.addEventListener("keydown",u,!0),A.querySelector(".stashpad-when-time-field")?.focus()},0)}startOfTodayLocal(){let e=new Date;return e.setHours(0,0,0,0),e}toDateValue(e){let t=e.getFullYear(),i=String(e.getMonth()+1).padStart(2,"0"),s=String(e.getDate()).padStart(2,"0");return`${t}-${i}-${s}`}toTimeValue(e){let t=String(e.getHours()).padStart(2,"0"),i=String(e.getMinutes()).padStart(2,"0");return`${t}:${i}`}},zt=class zt extends G.Modal{constructor(e,t,i,s=null,n){super(e);this.service=t;this.openLog=i;this.currentAuthorId=s;this.getNoteAuthorIds=n;this.records=[];this.visible=[];this.shownCount=0;this.categoryFilter=null;this.listEl=null;this.footerEl=null;this.countEl=null;this.filterSelEl=null;this.unsubscribe=null;this.authorFilter="all";this.authorSelEl=null}onOpen(){this.contentEl.empty(),this.titleEl.setText("Stashpad notification history"),this.modalEl.addClass("stashpad-log-modal"),this.modalEl.addClass("stashpad-notif-history-modal"),this.records=this.service.recent();let e=this.contentEl.createDiv({cls:"stashpad-log-toolbar"});if(this.countEl=e.createSpan({cls:"stashpad-log-count"}),this.updateCount(),this.filterSelEl=e.createEl("select",{cls:"stashpad-log-type-filter"}),this.filterSelEl.onchange=()=>this.setCategoryFilter(this.filterSelEl.value||null),this.refreshCategoryFilter(),this.authorSelEl=e.createEl("select",{cls:"stashpad-log-type-filter stashpad-notif-author-filter"}),this.authorSelEl.onchange=()=>this.setAuthorFilter(this.authorSelEl.value||"all"),this.refreshAuthorFilter(),this.openLog){let i=e.createEl("button",{text:"Open log"});i.title="Open the per-folder Stashpad log for the most recent notification's folder.",i.onclick=()=>{let s=this.records.find(n=>!!n.folder);this.openLog?.(s?.folder)}}let t=e.createEl("button",{cls:"mod-warning",text:"Clear history"});t.onclick=()=>{new j(this.app,"Clear notification history?",`This will permanently remove all ${this.records.length} stored notifications from the history. The current toasts on screen are unaffected. This can't be undone.`,"Clear history",i=>{i&&this.service.clearHistory()},"Cancel",!0).open()},this.listEl=this.contentEl.createDiv({cls:"stashpad-log-list"}),this.refreshList(),this.footerEl=this.contentEl.createDiv({cls:"stashpad-log-footer"}),this.renderFooter(),this.unsubscribe=this.service.onChange(()=>{this.records=this.service.recent(),this.refreshCategoryFilter(),this.refreshAuthorFilter(),this.refreshList(),this.renderFooter()})}setAuthorFilter(e){this.authorFilter!==e&&(this.authorFilter=e,this.refreshList(),this.renderFooter())}refreshAuthorFilter(){if(!this.authorSelEl)return;let e=this.authorSelEl;e.empty(),e.createEl("option",{text:"All authors"}).value="all",this.currentAuthorId&&(e.createEl("option",{text:"Me"}).value="me"),e.createEl("option",{text:"Cross-author"}).value="cross";let t=new Set;for(let s of this.records)s.authorId&&s.authorId!==this.currentAuthorId&&t.add(s.authorId);if(t.size>0){let s=e.createEl("option",{text:"\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"});s.disabled=!0;for(let n of[...t].sort())e.createEl("option",{text:n}).value=n}new Set(["all","cross",...this.currentAuthorId?["me"]:[],...t]).has(this.authorFilter)||(this.authorFilter="all"),e.value=this.authorFilter}isCrossAuthor(e){let t=e.authorId??null;if(!t)return!1;for(let i of e.affectedAuthorIds??[])if(i&&i!==t)return!0;if(!this.getNoteAuthorIds)return!1;for(let i of e.affectedIds){let s=this.getNoteAuthorIds(i);for(let n of s)if(n&&n!==t)return!0}return!1}onClose(){this.unsubscribe?.(),this.unsubscribe=null,this.contentEl.empty()}setCategoryFilter(e){(this.categoryFilter??null)!==(e??null)&&(this.categoryFilter=e,this.refreshList(),this.renderFooter())}refreshCategoryFilter(){if(!this.filterSelEl)return;let e=this.filterSelEl;e.empty();let t=new Map;for(let n of this.records)t.set(n.category,(t.get(n.category)??0)+1);let i=[...t.entries()].sort((n,o)=>o[1]-n[1]||n[0].localeCompare(o[0])),s=e.createEl("option",{text:`All categories (${this.records.length})`});s.value="";for(let[n,o]of i){let a=e.createEl("option",{text:`${n} (${o})`});a.value=n}this.categoryFilter&&!t.has(this.categoryFilter)&&(this.categoryFilter=null),e.value=this.categoryFilter??""}refreshList(){if(this.listEl){if(this.visible=this.records.filter(e=>{if(this.categoryFilter&&e.category!==this.categoryFilter)return!1;switch(this.authorFilter){case"all":return!0;case"me":return!!this.currentAuthorId&&e.authorId===this.currentAuthorId;case"cross":return this.isCrossAuthor(e);default:return e.authorId===this.authorFilter}}),this.shownCount=0,this.listEl.empty(),!this.visible.length){this.listEl.createDiv({cls:"stashpad-log-empty",text:this.categoryFilter?`No "${this.categoryFilter}" notifications.`:"No notifications yet."}),this.updateCount();return}this.appendMore(zt.PAGE)}}appendMore(e){if(!this.listEl)return;let t=Math.min(this.visible.length,this.shownCount+e);for(let i=this.shownCount;i0){let c=i.createDiv({cls:"stashpad-notif-actions-snapshot"});for(let A of t.actionLabels){let h=c.createSpan({cls:"stashpad-notif-action-chip"});h.setText(A),h.title="Action button was shown on the original toast (handler not retained)."}}}updateCount(){if(!this.countEl)return;let e=this.visible.length,t=this.categoryFilter?`${e} ${this.categoryFilter} notification${e===1?"":"s"}`:`${e} notification${e===1?"":"s"}`;this.shownCount===0||this.shownCount>=e?this.countEl.setText(t):this.countEl.setText(`Showing ${this.shownCount} of ${t}`)}renderFooter(){if(!this.footerEl)return;this.footerEl.empty();let e=this.visible.length-this.shownCount;if(e<=0)return;let t=this.footerEl.createEl("button",{text:`Load ${Math.min(zt.PAGE,e)} more`});if(t.onclick=()=>{this.appendMore(zt.PAGE),this.renderFooter()},e>zt.PAGE){let i=this.footerEl.createEl("button",{text:`Load all (${e})`});i.onclick=()=>{this.appendMore(e),this.renderFooter()}}}};zt.PAGE=100;es=zt,yo=class extends G.Modal{constructor(e,t){super(e);this.entries=t}onOpen(){if(this.contentEl.empty(),this.titleEl.setText("Stashpad import log"),this.entries.length===0){this.contentEl.createDiv({cls:"stashpad-log-empty",text:"Nothing imported yet."});return}let e=this.contentEl.createDiv({cls:"stashpad-import-log-list"});for(let t of this.entries){let i=e.createDiv({cls:"stashpad-import-log-row"}),s=(0,G.moment)(t.ts).format("YYYY-MM-DD HH:mm");i.createSpan({cls:"stashpad-import-log-when",text:s});let n=t.kind==="folder"?"folder":t.kind==="md"?"note":"file";i.createSpan({cls:`stashpad-import-log-kind is-${t.kind}`,text:n}),i.createSpan({cls:"stashpad-import-log-name",text:t.originalName});let o=[t.folder.split("/").pop()||t.folder];t.notePaths.length>1&&o.push(`${t.notePaths.length} notes`),i.createSpan({cls:"stashpad-import-log-meta",text:o.join(" \xB7 ")})}}onClose(){this.contentEl.empty()}},ts=class extends G.Modal{constructor(e,t,i){super(e);this.message=t;this.onChoose=i;this.chose=!1}onOpen(){this.modalEl?.addClass("stashpad-compact-modal"),this.contentEl.empty(),this.titleEl.setText("Possible duplicate import");let e=this.contentEl.createDiv({cls:"stashpad-confirm-body"});for(let o of this.message.split(` `))e.createDiv({cls:"stashpad-confirm-line",text:o});let t=this.contentEl.createDiv({cls:"stashpad-modal-btns"}),i=t.createEl("button",{text:"Skip duplicates"});i.onclick=()=>{this.chose=!0,this.close(),this.onChoose("skip")};let s=t.createEl("button",{text:"Replace existing"});s.onclick=()=>{this.chose=!0,this.close(),this.onChoose("replace")};let n=t.createEl("button",{cls:"mod-cta",text:"Import anyway"});n.onclick=()=>{this.chose=!0,this.close(),this.onChoose("anyway")}}onClose(){this.chose||this.onChoose("skip"),this.contentEl.empty()}},is=class extends G.Modal{constructor(e,t,i){super(e);this.items=t;this.onConfirm=i}onOpen(){this.titleEl.setText("Re-encrypt everything applicable?");let{contentEl:e}=this;e.createEl("p",{cls:"setting-item-description",text:"These notes should be encrypted (they were unlocked/restored, or their folder is set to encrypt) but are currently plaintext. Untick anything you want to leave readable."});let t=e.createDiv({cls:"stashpad-reenc-list"}),i=[];this.items.forEach(o=>{let a=t.createEl("label",{cls:"stashpad-reenc-row"}),l=a.createEl("input",{type:"checkbox"});l.checked=!0,i.push(l);let c=a.createDiv({cls:"stashpad-reenc-body"});c.createDiv({cls:"stashpad-reenc-label",text:o.label}),c.createDiv({cls:"stashpad-reenc-detail",text:o.detail})});let s=e.createDiv({cls:"modal-button-container"}),n=s.createEl("button",{cls:"mod-cta",text:"Re-encrypt checked"});n.onclick=()=>{let o=i.map((a,l)=>a.checked?l:-1).filter(a=>a>=0);this.close(),o.length&&this.onConfirm(o)},s.createEl("button",{text:"Cancel"}).onclick=()=>this.close()}onClose(){this.contentEl.empty()}}});function De(d,r=nt){let e=r instanceof Set?r:new Set(r.map(o=>o.toLowerCase())),t=(d.split(/\r?\n/).find(o=>o.trim().length>0)??"").trim();if(!t)return"Untitled";let s=t.replace(/['‘-‛ʼ]/g,"").replace(/[^A-Za-z0-9\s]+/g," ").split(/\s+/).filter(o=>o&&!e.has(o.toLowerCase())).map(o=>o.length>=2&&/^[A-Z0-9]+$/.test(o)?o:o.charAt(0).toUpperCase()+o.slice(1).toLowerCase()),n="";for(let o of s){let a=n?`${n}-${o}`:o;if(a.length>50)break;n=a}return n||"Untitled"}function xe(d,r){return`${d}-${r}.md`}function ot(d){let r=d.match(/-([abcdefghijkmnpqrstuvwxyz23456789]{6})$/);return r?r[1]:null}function rs(d){return typeof d=="string"&&/^[abcdefghijkmnpqrstuvwxyz23456789]{6}$/.test(d)}function Vs(d,r){let e=d.lastIndexOf(".");return e>0?`${d.slice(0,e)}-${r}${d.slice(e)}`:`${d}-${r}`}function or(d){let r=d.match(/^([0-9a-z]{7,9})-(.+)$/);if(!r)return null;let e=parseInt(r[1],36);return!Number.isFinite(e)||e<142e10||e>Date.now()+864e5?null:{stamp:r[1],rest:r[2]}}var nt,mi=Ze(()=>{"use strict";nt=["a","an","the","and","or","but","if","then","else","of","in","on","at","to","for","with","by","from","as","is","are","was","were","be","been","being","i","you","he","she","it","we","they","this","that","these","those","my","your","our","their","do","does","did","so","just","very","really","im"]});var Zs={};Oi(Zs,{JdBuildConfirmModal:()=>ls,buildJdIndexNotes:()=>vo,buildJdIndexPreview:()=>Ws,buildJdPreviewNotice:()=>Xs,scanForJdNotes:()=>Ci});function Qo(d,r){if(/^\d+-\d+$/.test(d))return null;if(d.includes(".")){let t=d.split(".").slice(0,-1).join(".");return r.has(t)?t:Qo(t,r)}if(/^\d+$/.test(d)){let e=parseInt(d,10);for(let t of r){let i=t.match(/^(\d+)-(\d+)$/);if(!i)continue;let s=parseInt(i[1],10),n=parseInt(i[2],10);if(e>=s&&e<=n)return t}return null}return null}function Ci(d,r,e){let t=d.vault.getMarkdownFiles(),i=lc(t,e),s=e.jdIndexIncludeStashpadFolders===!0,n=s?new Set:new Set(r.discoverStashpadFolders()),o=f=>s?!1:Array.from(n).some(u=>f===u||f.startsWith(u+"/")),a=[],l=[],c=[];for(let f of i){let u=f.parent?.path?.replace(/\/+$/,"")??"";if(o(u)){c.push(f);continue}let g=f.basename.match(ar);g?a.push({prefix:g[1],segments:g[1].split("."),title:g[2],file:f,folder:null}):l.push(f)}let A=(e.jdIndexScope??"vault")==="folder"?(e.jdIndexScopeFolder??"").trim().replace(/^\/+|\/+$/g,""):"",h=f=>{let u=f.path.replace(/\/+$/,"");if(!(A&&u&&u!==A&&!u.startsWith(A+"/"))){if(u&&!o(u)){let g=f.name.match(ar);g&&a.push({prefix:g[1],segments:g[1].split("."),title:g[2],file:null,folder:f})}}for(let g of f.children)g instanceof Ee.TFolder&&h(g)};h(d.vault.getRoot());let p=e.jdIndexSort??"natural";return a.sort((f,u)=>cc(f,u,p)),{indexed:a,nonIndex:l,skippedStashpadNotes:c}}async function Ws(d,r,e){let t=Fo(e.jdIndexStashpadFolder??"");if(!t)return{...Ci(d,r,e),previewPath:null,error:"no-dest"};let i=Ci(d,r,e),s=rc(d,t);if(!s)return{...i,previewPath:null,error:"no-home"};let n=dc(i.indexed,i.nonIndex,i.skippedStashpadNotes),a=(await d.vault.read(s)).match(/^---\r?\n[\s\S]*?\r?\n---\r?\n/),l=a?`${a[0]}${n}`:n;return await d.vault.modify(s,l),{...i,previewPath:s.path}}function rc(d,r){let e=d.vault.getAbstractFileByPath(r);if(!(e instanceof Ee.TFolder))return null;for(let t of e.children){if(!(t instanceof Ee.TFile)||t.extension!=="md")continue;if((d.metadataCache.getFileCache(t)?.frontmatter??{}).id===k)return t}return null}async function vo(d,r,e){let t=Fo(e.jdIndexStashpadFolder??"");if(!t)return{created:0,updated:0,skipped:0,destFolder:"",error:"no-dest"};if(!new Set(r.discoverStashpadFolders()).has(t))return{created:0,updated:0,skipped:0,destFolder:t,error:"dest-not-stashpad"};let s=Ci(d,r,e),n=new Map;for(let I of s.indexed)n.set(I.prefix,I);for(let I of s.indexed)if(I.prefix.includes("."))for(let m=1;m{l.push(I);for(let m of a.get(I)??[])c(m)};for(let I of o)c(I);let A=new Map,h=d.vault.getAbstractFileByPath(t);if(h instanceof Ee.TFolder)for(let I of h.children){if(!(I instanceof Ee.TFile)||I.extension!=="md")continue;let m=d.metadataCache.getFileCache(I)?.frontmatter??{};typeof m.jdPrefix=="string"&&A.set(m.jdPrefix,I)}let p=new Map,f=0,u=0,g=0;for(let I of l){let m=n.get(I)??null,C=Qo(I,new Set(n.keys())),B=C?p.get(C)??k:k,E=m?`${I} ${m.title}`:I,y=m?.file?`[[${m.file.basename}]]`:"",Q=y?`${y} `:`${E} diff --git a/manifest.json b/manifest.json index b62f98b..7dd92fc 100644 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "id": "stashpad", "name": "Stashpad", - "version": "0.181.0", + "version": "0.183.4", "minAppVersion": "1.13.0", "description": "A chat-style, nested-notes workspace: rapid capture, outliner navigation, fast search, tasks, and per-folder templates, with one-click Open Knowledge Format (OKF) export for LLMs and agents.", "author": "Human", diff --git a/package.json b/package.json index 503d67e..fe2c889 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "stashpad-obsidian", - "version": "0.181.0", + "version": "0.183.4", "private": true, "scripts": { "dev": "node esbuild.config.mjs", diff --git a/release-notes/0.183.4.md b/release-notes/0.183.4.md new file mode 100644 index 0000000..49f2355 --- /dev/null +++ b/release-notes/0.183.4.md @@ -0,0 +1,30 @@ +# 0.183.4 + +A focused pass on the mobile edit / split experience. + +## Mobile edit & split modal + +- **Tabbed editor.** On a phone, the Original / Changes / Your-edit sections now + share one space as tabs (one visible at a time) instead of stacking, so the + modal stays compact. +- **Top-anchored sheet.** The modal anchors to the top of the screen (clear of the + notch / Dynamic Island) with a consistent height, and the editor fills it and + scrolls — the action bar stays put above the keyboard instead of being pushed + off or lifted/distorted when the keyboard opens. +- **Slimmer, cleaner controls.** Compact Edit/Split toggle, tabs, and buttons; the + bottom action bar reads as part of the modal (no stray black box); the pop-out + and Obsidian-editor buttons are labelled **"Pop-out"** and **"Advanced"**. +- **Copy button** for the Original text moved to a small button above the text + (it used to overlay the text's right edge). + +## Pop-out tab + +- Opening the editor **in its own tab** now uses the **full width** of the tab, the + editor fills the leaf (it no longer collapses to a sliver when the keyboard is + up), the content clears Obsidian's bottom toolbar, and all the action buttons + stay reachable. + +## Composer + +- The composer's **full-screen button** (open your draft in the roomy in-app + editor) is a bit larger and easier to tap. diff --git a/src/modals.ts b/src/modals.ts index 69809c9..50cd215 100644 --- a/src/modals.ts +++ b/src/modals.ts @@ -652,7 +652,7 @@ export class NoteWorkbench { if (!this.cb.popOut) return; const pop = actions.createEl("button", { cls: "stashpad-split-popout-btn" }); setIcon(pop.createSpan({ cls: "stashpad-split-popout-icon" }), "maximize-2"); - pop.createSpan({ text: "Open in a tab" }); + pop.createSpan({ text: Platform.isMobile ? "Pop-out" : "Open in a tab" }); pop.setAttr("aria-label", "Open in a full tab"); pop.onmousedown = (e) => e.preventDefault(); pop.onclick = () => this.cb.popOut!(this.getState()); @@ -663,7 +663,7 @@ export class NoteWorkbench { if (!this.cb.onOpenExternal) return; const b = actions.createEl("button", { cls: "stashpad-split-popout-btn" }); setIcon(b.createSpan({ cls: "stashpad-split-popout-icon" }), "pencil"); - b.createSpan({ text: "Obsidian editor" }); + b.createSpan({ text: Platform.isMobile ? "Advanced" : "Obsidian editor" }); b.setAttr("aria-label", "Open in a full Obsidian editor tab"); b.onmousedown = (e) => e.preventDefault(); b.onclick = () => { this.cb.onOpenExternal!(); this.cb.close(); }; @@ -980,10 +980,12 @@ export class NoteWorkbench { ta.readOnly = false; this.cursorTextarea = ta; - // Original (read-only) — copy button lives inside the panel (top-right). + // Original (read-only). 0.183.3: copy button in a right-aligned bar ABOVE the + // text (it used to overlay the text's right edge as a full-height strip). const origPanel = bodyHost.createDiv({ cls: "stashpad-split-tabpanel" }); + const origCopyBar = origPanel.createDiv({ cls: "stashpad-split-tab-copybar" }); + origCopyBar.appendChild(this.makeCopyButton(() => this.body, "Copy the original text", "stashpad-split-copy-btn stashpad-split-tab-copy")); origPanel.createDiv({ cls: "stashpad-split-panel-body", text: this.body }); - origPanel.appendChild(this.makeCopyButton(() => this.body, "Copy the original text", "stashpad-split-copy-btn stashpad-split-tab-copy")); // Changes (word diff). const changesPanel = bodyHost.createDiv({ cls: "stashpad-split-tabpanel" }); @@ -1027,26 +1029,20 @@ export class NoteWorkbench { if (!edited && (active === "orig" || active === "changes")) showTab("edit"); }; - // Firm height cap so the editor scrolls instead of pushing the action bar - // past the keyboard (fewer lines than desktop — space is at a premium). - const lineHeight = parseFloat(getComputedStyle(ta).lineHeight) || 22; - const maxLines = this.surface === "edit" ? 8 : 4; - ta.setCssStyles({ maxHeight: `${lineHeight * maxLines + 16}px`, overflowY: "auto" }); - const fit = (): void => { - ta.setCssStyles({ height: "auto" }); - const needed = Math.min(ta.scrollHeight, lineHeight * maxLines + 16); - ta.setCssStyles({ height: `${Math.max(needed, lineHeight * 2 + 16)}px` }); - }; + // 0.183.0: the editor FILLS the fixed-height modal (flex, via CSS) and scrolls + // internally — no explicit line cap. With the modal at a fixed height it can't + // grow past the keyboard anyway, so filling looks better than a hard cap that + // leaves an empty gap under a short note. + ta.setCssStyles({ overflowY: "auto" }); syncEdited(); showTab("edit"); requestAnimationFrame(() => { - fit(); ta.focus(); const pos = this.surface === "edit" ? ta.value.length : Math.floor(ta.value.length / 2); ta.setSelectionRange(pos, pos); }); - ta.addEventListener("input", () => { this.cursorText = ta.value; fit(); syncEdited(); }); + ta.addEventListener("input", () => { this.cursorText = ta.value; syncEdited(); }); } } diff --git a/styles.css b/styles.css index 717e68a..1fe8514 100644 --- a/styles.css +++ b/styles.css @@ -1737,8 +1737,8 @@ body.is-phone .modal.stashpad-compact-modal.stashpad-breadcrumb-modal { position: absolute; top: 4px; right: 6px; - width: 22px; - height: 22px; + width: 27px; + height: 27px; padding: 0; display: inline-flex; align-items: center; @@ -1752,7 +1752,7 @@ body.is-phone .modal.stashpad-compact-modal.stashpad-breadcrumb-modal { opacity: 0.65; } .stashpad-composer-fullscreen:hover { background: var(--background-modifier-hover); color: var(--text-normal); opacity: 1; } -.stashpad-composer-fullscreen .svg-icon { width: 14px; height: 14px; } +.stashpad-composer-fullscreen .svg-icon { width: 17px; height: 17px; } /* Keep typed text clear of the button. */ .stashpad-composer-input { padding-right: 32px; } @@ -2266,6 +2266,33 @@ body.is-phone .modal.stashpad-compact-modal.stashpad-breadcrumb-modal { max-width: 860px; margin: 0 auto; } +/* 0.183.1: the popped-out editor VIEW on mobile. Make it a FLEX column so the + editor fills the leaf — it collapsed to <1 line when the keyboard shrank the + viewport because the host wasn't a flex container. Bottom padding clears + Obsidian's mobile bottom toolbar + the home indicator. */ +.is-mobile .stashpad-split-view { + display: flex; + flex-direction: column; + /* 0.183.3: SCROLLABLE so no button is ever permanently tucked when the keyboard + shrinks the leaf. 0.183.4: FULL WIDTH — the base rule's max-width:860px + + margin:0 auto was centering it (auto side margins), leaving it inset. */ + overflow-y: auto; + width: 100%; + max-width: none; + margin: 0; + padding: 10px 8px calc(env(safe-area-inset-bottom, 0px) + 52px); +} +.is-mobile .stashpad-split-view .stashpad-split-tabpanel.is-active .stashpad-split-cursor-ta { + min-height: calc(1.5em * 6); +} +/* Help text is empty on phones anyway — hide it so it doesn't eat vertical space. */ +.is-mobile .stashpad-split-help { display: none; } +/* In the scrollable VIEW the editor already fills via flex; margin-top:auto + misbehaves with overflow. 0.183.4: give it a fixed gap so the separator line + isn't jammed against the text box / Case row — a touch more in split mode + (text box edge) than edit mode (Case row). */ +.is-mobile .stashpad-split-view:not(.stashpad-edit-surface) .stashpad-split-actions { margin-top: 21px; } +.is-mobile .stashpad-split-view.stashpad-edit-surface .stashpad-split-actions { margin-top: 18px; } /* In a full tab there's room — let the read-only previews and the preset list breathe (they stay short/scrolly inside the cramped modal). */ .stashpad-split-view .stashpad-split-panel-body { max-height: calc(1.5em * 10 + 0.8em); } @@ -2287,14 +2314,28 @@ body.is-phone .modal.stashpad-compact-modal.stashpad-breadcrumb-modal { end of the flow, so a long note (tall textarea) pushed Save/Cancel off-screen and — with the keyboard up — behind it. Now the content scrolls and the actions stick to the bottom of the visible area, always reachable. */ -.is-mobile .stashpad-split-modal { +/* 0.182.0: anchor the sheet to the TOP (was centered) — with a notch / Dynamic + Island offset — so it has more vertical room and its bottom sits well clear of + the keyboard + the keyboard's autocomplete suggestion strip. */ +.is-mobile .modal-container:has(> .stashpad-split-modal) { + align-items: flex-start; +} +/* FLOATING modal only (`:not(.stashpad-split-view)`) — the popped-out tab shares + the .stashpad-split-modal class but is a full leaf, so it must NOT inherit the + modal's min-height / margin / max-height (that collapsed it). */ +.is-mobile .stashpad-split-modal:not(.stashpad-split-view) { width: 100vw; max-width: 100vw; - height: 100%; - max-height: 100%; + height: auto; + /* Consistent, roomier height regardless of content; the editor fills it. + 0.183.1: 20px shorter so the action bar stays clear of the keyboard. */ + min-height: calc(58vh - 20px); + /* Notch/Dynamic-Island offset, a quarter shorter (0.75× the inset). */ + margin-top: calc(env(safe-area-inset-top, 0px) * 0.75 + 8px); + max-height: calc(100% - env(safe-area-inset-top, 0px) - 32px); display: flex; flex-direction: column; - border-radius: 0; + border-radius: 0 0 14px 14px; } .is-mobile .stashpad-split-modal .modal-content { flex: 1 1 auto; @@ -2305,18 +2346,17 @@ body.is-phone .modal.stashpad-compact-modal.stashpad-breadcrumb-modal { padding: 10px 12px; -webkit-overflow-scrolling: touch; } -/* Pinned, full-bleed action bar (Save/Cancel/pop-out). Sticks to the bottom of - the scrollport so it stays visible above the keyboard; wraps on narrow width. */ +/* 0.183.0: action bar pinned to the BOTTOM of the modal via margin-top:auto — + NOT position:sticky. Sticky made iOS lift/distort the row when the keyboard + opened. No env(safe-area-inset-bottom) padding either (the sheet is top-anchored, + not a bottom sheet — that padding drew empty space beneath the buttons on iOS). */ .is-mobile .stashpad-split-modal .stashpad-split-actions { - position: sticky; - bottom: 0; - margin: 8px -12px -10px; - padding: 8px 12px calc(8px + env(safe-area-inset-bottom, 0px)); - background: var(--background-primary); + margin-top: auto; /* pin to the bottom of the modal/leaf (not sticky) */ + padding-top: 10px; + /* 0.183.2: NO opaque background — it read as a separate black box floating on + the modal in iOS dark mode. Just a hairline separator. */ border-top: 1px solid var(--background-modifier-border); - flex-wrap: wrap; gap: 8px; - z-index: 3; } /* On a phone the primary Save spans the row; secondary actions wrap under it. */ .is-mobile .stashpad-split-modal .stashpad-split-actions-right { @@ -2353,23 +2393,61 @@ body.is-phone .modal.stashpad-compact-modal.stashpad-breadcrumb-modal { .stashpad-split-tab.is-hidden { display: none; } .stashpad-split-tabpanel { position: relative; } .stashpad-split-tabpanel:not(.is-active) { display: none; } -/* Copy button sits in the Original panel (top-right), scaled small. */ -.stashpad-split-tab-copy { position: absolute; top: 4px; right: 4px; z-index: 2; padding: 4px; } +/* 0.183.0: the editor FILLS the fixed-height modal (no empty gap under short + notes). Flex chain: modal-content → tabs → tabbody → active panel → textarea, + each stretching; the textarea/preview scrolls internally. */ +.is-mobile .stashpad-split-tabs { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; } +.is-mobile .stashpad-split-tabbody { flex: 1 1 auto; min-height: 0; display: flex; } +.is-mobile .stashpad-split-tabpanel.is-active { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; } +.is-mobile .stashpad-split-tabpanel.is-active .stashpad-split-cursor-ta { flex: 1 1 auto; min-height: 0; height: auto; } +.is-mobile .stashpad-split-tabpanel.is-active .stashpad-split-panel-body { flex: 1 1 auto; min-height: 0; max-height: none; } +/* 0.183.3: copy button lives in its own right-aligned bar ABOVE the Original text + (no longer a full-height strip overlaying the text's right edge). */ +.stashpad-split-tab-copybar { display: flex; justify-content: flex-end; margin-bottom: 4px; flex: 0 0 auto; } +.stashpad-split-tab-copy { + position: static; + height: auto; + width: auto; + padding: 5px 12px; + gap: 5px; + background: var(--background-secondary); + border: 1px solid var(--background-modifier-border); +} +.stashpad-split-tab-copy svg { width: 1.15em; height: 1.15em; } +/* Slimmer mobile modal buttons — the toggle / tabs / mode / action buttons were + too chunky. Tight vertical padding + line-height, no min-height. */ +.is-mobile .stashpad-split-surface-btn, +.is-mobile .stashpad-split-tab, +.is-mobile .stashpad-split-mode-btn, +.is-mobile .stashpad-split-cancel-btn, +.is-mobile .stashpad-split-confirm-btn, +.is-mobile .stashpad-split-popout-btn, +.is-mobile .stashpad-split-case-btn { + /* Obsidian mobile forces height: 44px on buttons — override to size to content. */ + height: auto; + padding-top: 4px; + padding-bottom: 4px; + min-height: 0; + line-height: 1.25; +} .stashpad-split-tabpanel .stashpad-split-panel-body { max-height: calc(1.5em * 7 + 12px); overflow-y: auto; padding: 8px 10px; margin: 0; } -/* Action bar: keep all buttons on ONE row, compact. Cancel drops its "(Esc)" hint, - and pop-out + Obsidian-editor go icon-only, so Cancel / ⤢ / ✎ / Save fit. */ -.is-mobile .stashpad-split-modal .stashpad-split-actions { flex-wrap: nowrap; gap: 6px; margin-top: 6px; } +/* Action bar: compact buttons; Cancel drops its "(Esc)" hint. 0.183.0: pop-out + + Obsidian-editor now SHOW short text labels ("Pop-out" / "Advanced"), so the row + is allowed to wrap. */ +.is-mobile .stashpad-split-modal .stashpad-split-actions { flex-wrap: wrap; gap: 6px; } .is-mobile .stashpad-split-cancel-btn, .is-mobile .stashpad-split-confirm-btn, .is-mobile .stashpad-split-popout-btn { padding: 6px 10px; } .is-mobile .stashpad-split-esc-hint { display: none; } -.is-mobile .stashpad-split-popout-btn span:not([class*="icon"]) { display: none; } -.is-mobile .stashpad-split-actions-right { margin-left: auto; gap: 8px; } +/* Let Save flow inline with the others (wraps to a tidy grid) instead of being + pushed to its own row by margin-left:auto. */ +.is-mobile .stashpad-split-actions-right { margin-left: 0; gap: 8px; } +.is-mobile .stashpad-split-confirm-btn { flex: 1 1 auto; justify-content: center; } /* Tap-friendly line picker — make each line look interactable. */ .stashpad-split-line { cursor: pointer; } .stashpad-split-line:hover { background: var(--background-modifier-hover); }