@openparachute/notes-ui 0.1.0-rc.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/CHANGELOG.md +100 -0
  2. package/LICENSE +661 -0
  3. package/README.md +27 -0
  4. package/dist/.parachute/info +8 -0
  5. package/dist/apple-touch-icon-180x180.png +0 -0
  6. package/dist/assets/Activity-B6k-9wWy.js +1 -0
  7. package/dist/assets/AddVault-DA_s9Ua2.js +1 -0
  8. package/dist/assets/Calendar-Dgd0dTEM.js +1 -0
  9. package/dist/assets/Capture-C_s94G98.js +9 -0
  10. package/dist/assets/NoteEditor-CxoH85Is.js +1 -0
  11. package/dist/assets/NoteNew-CTTJ_2cU.js +1 -0
  12. package/dist/assets/NoteRenderer-cz03kLyS.js +37 -0
  13. package/dist/assets/NoteView-B8BN-Dm4.js +3 -0
  14. package/dist/assets/OAuthCallback-CHpF2exs.js +1 -0
  15. package/dist/assets/PinArchiveButtons-DogtDLiB.js +1 -0
  16. package/dist/assets/Settings-DpNYPt6E.js +1 -0
  17. package/dist/assets/Tags-C2seZlc0.js +1 -0
  18. package/dist/assets/Today-Co3rl2Tl.js +1 -0
  19. package/dist/assets/VaultGraph-9bEHl7fl.js +3 -0
  20. package/dist/assets/Vaults-GFmUZ3tT.js +1 -0
  21. package/dist/assets/dates-BGZoWpL2.js +1 -0
  22. package/dist/assets/index-BDPMEkxL.js +62 -0
  23. package/dist/assets/index-D_L2igjK.css +1 -0
  24. package/dist/assets/react-force-graph-2d-CokIfB0T.js +46 -0
  25. package/dist/assets/useAttachmentUploader-CRSqlwYK.js +29 -0
  26. package/dist/assets/workbox-window.prod.es5-BBnX5xw4.js +2 -0
  27. package/dist/favicon.ico +0 -0
  28. package/dist/icon.svg +6 -0
  29. package/dist/index.html +28 -0
  30. package/dist/manifest.webmanifest +1 -0
  31. package/dist/maskable-icon-512x512.png +0 -0
  32. package/dist/pwa-192x192.png +0 -0
  33. package/dist/pwa-512x512.png +0 -0
  34. package/dist/pwa-64x64.png +0 -0
  35. package/dist/sw.js +1 -0
  36. package/dist/workbox-b9acee4e.js +1 -0
  37. package/package.json +71 -0
package/README.md ADDED
@@ -0,0 +1,27 @@
1
+ # @openparachute/notes-ui
2
+
3
+ The Parachute Notes UI bundle, packaged for installation under [parachute-app][app].
4
+
5
+ [app]: https://github.com/ParachuteComputer/parachute-app
6
+
7
+ ## What's in the box
8
+
9
+ `dist/` is the Vite-built SPA. The package ships nothing else of substance — no node entrypoint, no bin, no daemon. The bundle is mount-path-agnostic when built with `VITE_BASE_PATH=/app/notes/` (or any other path under parachute-app's `/app/<name>/` convention).
10
+
11
+ ## Install via parachute-app
12
+
13
+ ```
14
+ parachute-app add @openparachute/notes-ui --name notes --path /app/notes
15
+ ```
16
+
17
+ parachute-app fetches this package from npm, unpacks `dist/`, and serves it under the declared mount path. OAuth DCR + hub-issued bearers + the standard scopes wiring all flow through parachute-app's bootstrap.
18
+
19
+ ## The other publish target
20
+
21
+ `@openparachute/notes` (in [`../notes-daemon`](../notes-daemon)) is the legacy module-shaped wrapper hub installs via `parachute install notes`. Both ship the same bundle during the [notes migration arc Section 16][s16]; the module form retires in Phase 3.
22
+
23
+ [s16]: https://github.com/ParachuteComputer/parachute.computer/blob/main/design/2026-05-21-parachute-apps-design.md#16-notes-migration-to-app
24
+
25
+ ## Source
26
+
27
+ Notes' source — components, hooks, vault client, sync engine, PWA — lives in `src/`. The development docs (mount-path convention, tag-roles, per-vault settings, transcription) are in the daemon package's [README](../notes-daemon/README.md); they apply unchanged to the UI bundle.
@@ -0,0 +1,8 @@
1
+ {
2
+ "name": "parachute-notes",
3
+ "displayName": "Notes",
4
+ "tagline": "Web client for your Parachute Vault",
5
+ "version": "0.1.0-rc.4",
6
+ "iconUrl": "/notes/icon.svg",
7
+ "kind": "frontend"
8
+ }
@@ -0,0 +1 @@
1
+ import{aa as h,W as g,x as l,r as e,N as f,L as m,z as b,V as y}from"./index-BDPMEkxL.js";const p=1440*60*1e3,j=5e3;function N(n,r=30,s=new Date){const d=s.getTime()-r*p,a=[];for(const t of n){const c=t.path??t.id,o=Date.parse(t.createdAt);if(Number.isFinite(o)&&o>=d&&a.push({id:`${t.id}:created`,noteId:t.id,noteName:c,kind:"created",at:t.createdAt,preview:t.preview,tags:t.tags}),t.updatedAt){const i=Date.parse(t.updatedAt);Number.isFinite(i)&&i>=d&&Number.isFinite(o)&&i-o>j&&a.push({id:`${t.id}:updated`,noteId:t.id,noteName:c,kind:"updated",at:t.updatedAt,preview:t.preview,tags:t.tags})}}return a.sort((t,c)=>Date.parse(c.at)-Date.parse(t.at)),a}const v=["today","yesterday","thisWeek","older"],k={today:"Today",yesterday:"Yesterday",thisWeek:"This week",older:"Older"};function w(n,r=new Date){const s=Date.parse(n);if(!Number.isFinite(s))return null;const d=u(r),a=u(new Date(s)),t=Math.round((d.getTime()-a.getTime())/p);return t<0||t===0?"today":t===1?"yesterday":t<7?"thisWeek":"older"}function u(n){return new Date(n.getFullYear(),n.getMonth(),n.getDate())}function D(n,r=new Date){const s={today:[],yesterday:[],thisWeek:[],older:[]};for(const d of n){const a=w(d.at,r);a&&s[a].push(d)}return s}const x=50;function F(){const n=h(i=>i.getActiveVault()),r=g(),[s,d]=l.useState(x),a=l.useMemo(()=>r.data?N(r.data):[],[r.data]),t=l.useMemo(()=>a.slice(0,s),[a,s]),c=l.useMemo(()=>D(t),[t]),o=a.length-t.length;return n?e.jsxs("div",{className:"mx-auto max-w-3xl px-4 py-6 md:px-6 md:py-10",children:[e.jsxs("header",{className:"mb-5 md:mb-6",children:[e.jsx("p",{className:"text-xs uppercase tracking-wider text-fg-dim",children:"Activity"}),e.jsx("h1",{className:"font-serif text-2xl tracking-tight md:text-3xl",children:"Recent changes"}),e.jsx("p",{className:"mt-1 text-sm text-fg-muted",children:"Last 30 days, newest first. Deletions aren't tracked yet."})]}),r.isPending?e.jsx(T,{}):r.isError?e.jsx(B,{error:r.error}):a.length===0?e.jsx(S,{}):e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"space-y-8",children:v.map(i=>c[i].length>0?e.jsx(E,{title:k[i],events:c[i]},i):null)}),o>0?e.jsx("div",{className:"mt-8 flex justify-center",children:e.jsxs("button",{type:"button",onClick:()=>d(i=>i+x),className:"rounded-md border border-border bg-card px-4 py-2 text-sm text-fg-muted hover:text-accent",children:["Load more (",o," remaining)"]})}):null]})]}):e.jsx(f,{to:"/",replace:!0})}function E({title:n,events:r}){return e.jsxs("section",{children:[e.jsxs("h2",{className:"mb-2 text-xs uppercase tracking-wider text-fg-dim",children:[n," (",r.length,")"]}),e.jsx("ol",{className:"divide-y divide-border rounded-md border border-border bg-card",children:r.map(s=>e.jsx("li",{children:e.jsxs(m,{to:`/n/${encodeURIComponent(s.noteId)}`,className:"block px-4 py-3 hover:bg-bg/60 focus:bg-bg/60 focus:outline-none",children:[e.jsxs("div",{className:"flex items-baseline justify-between gap-4",children:[e.jsxs("div",{className:"flex min-w-0 items-baseline gap-2",children:[e.jsx(A,{kind:s.kind}),e.jsx("span",{className:"truncate font-mono text-sm text-fg",children:s.noteName})]}),e.jsx("span",{className:"shrink-0 text-xs text-fg-dim",children:b(s.at)})]}),s.preview?e.jsx("p",{className:"mt-1 truncate text-sm text-fg-muted",children:s.preview}):null,s.tags&&s.tags.length>0?e.jsx("div",{className:"mt-2 flex flex-wrap gap-1",children:s.tags.map(d=>e.jsxs("span",{className:"rounded-md bg-border/40 px-1.5 py-0.5 text-xs text-fg-dim",children:["#",d]},d))}):null]})},s.id))})]})}function A({kind:n}){return n==="created"?e.jsx("span",{className:"shrink-0 rounded-md bg-accent/10 px-1.5 py-0.5 text-xs text-accent",children:"Created"}):e.jsx("span",{className:"shrink-0 rounded-md bg-border/40 px-1.5 py-0.5 text-xs text-fg-muted",children:"Edited"})}function S(){return e.jsxs("div",{className:"rounded-md border border-border bg-card p-10 text-center",children:[e.jsx("p",{className:"mb-4 text-fg-muted",children:"No activity in the last 30 days."}),e.jsx(m,{to:"/capture",className:"inline-block rounded-md bg-accent px-4 py-2 text-sm font-medium text-white hover:bg-accent-hover",children:"Open capture"})]})}function T(){return e.jsx("div",{className:"space-y-3","aria-busy":"true",children:[0,1,2,3,4].map(n=>e.jsx("div",{className:"h-16 animate-pulse rounded-md bg-border/30"},n))})}function B({error:n}){const r=n instanceof y;return e.jsxs("div",{className:"rounded-md border border-red-500/30 bg-red-500/5 p-6",children:[e.jsx("p",{className:"mb-2 font-medium text-red-400",children:r?"Session expired":"Could not load activity"}),e.jsx("p",{className:"mb-4 text-sm text-fg-muted",children:n.message}),r?e.jsx(m,{to:"/add",className:"inline-block rounded-md bg-accent px-4 py-2 text-sm font-medium text-white hover:bg-accent-hover",children:"Reconnect vault"}):null]})}export{F as Activity};
@@ -0,0 +1 @@
1
+ import{a3 as v,x as t,X as j,r as e,I as y,v as w,j as N,a as S}from"./index-BDPMEkxL.js";function R(){const[b]=v(),u=b.get("url")??"",[a,c]=t.useState(u),[i,l]=t.useState(null),[g,d]=t.useState(!1),[o,m]=t.useState(!1),x=t.useRef(null),h=t.useRef(u.length>0),n=j();t.useEffect(()=>{var s;(s=x.current)==null||s.focus()},[]),t.useEffect(()=>{h.current||n.status==="found"&&n.origin&&a===""&&(c(n.origin),h.current=!0)},[n.status,n.origin,a]);async function p(s){s.preventDefault(),l(null),d(!1);let f;try{f=w(a)}catch(r){l(r.message);return}m(!0);try{const{authorizeUrl:r}=await N(f);window.location.assign(r)}catch(r){r instanceof S?d(!0):l(r.message),m(!1)}}return e.jsxs("div",{className:"mx-auto max-w-xl px-6 py-16",children:[e.jsx("h1",{className:"mb-2 font-serif text-4xl tracking-tight",children:"Connect a vault"}),e.jsx("p",{className:"mb-8 text-fg-muted",children:"Paste your Parachute hub URL. You'll be taken to its consent page to authorize Parachute Notes."}),e.jsxs("form",{onSubmit:p,className:"space-y-4",children:[e.jsxs("div",{children:[e.jsx("label",{htmlFor:"vault-url",className:"mb-1.5 block text-sm font-medium text-fg",children:"Hub URL"}),e.jsx("input",{id:"vault-url",ref:x,type:"url",required:!0,placeholder:"http://localhost:1939",value:a,onChange:s=>c(s.target.value),disabled:o,className:"w-full rounded-md border border-border bg-card px-3 py-2 font-mono text-sm text-fg focus:border-accent focus:outline-none"}),e.jsxs("p",{className:"mt-1.5 text-xs text-fg-dim",children:["For a local install the hub lives at ",e.jsx("code",{children:"http://localhost:1939"}),". A standalone vault URL (e.g. ",e.jsx("code",{children:"https://host/vault/default"}),") also works — Notes will OAuth against whichever issuer answers."]})]}),g?e.jsx(y,{}):null,i?e.jsx("div",{className:"rounded-md border border-red-400/30 bg-red-400/5 px-3 py-2 text-sm text-red-400",children:i}):null,e.jsx("button",{type:"submit",disabled:o||!a,className:"w-full rounded-md bg-accent px-4 py-2.5 text-sm font-medium text-white hover:bg-accent-hover disabled:cursor-not-allowed disabled:opacity-60",children:o?"Starting OAuth…":"Continue"})]})]})}export{R as AddVault};
@@ -0,0 +1 @@
1
+ import{aa as k,a3 as E,W as A,x as y,r as e,N as K,L as d,V as S}from"./index-BDPMEkxL.js";import{d as f,c as j,e as P,m as T,t as V,s as N,p as i,a as C}from"./dates-BGZoWpL2.js";const _=["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],x=5;function Y(){const a=k(t=>t.getActiveVault()),[o]=E(),l=o.get("month"),r=f(l)??f(j()),s=A(),h=P(),v=y.useMemo(()=>T(r.year,r.month),[r.year,r.month]),$=y.useMemo(()=>{const t=new Map;if(!s.data)return t;for(const n of s.data){const c=V(n.createdAt);c&&t.set(c,(t.get(c)??0)+1)}return t},[s.data]);if(!a)return e.jsx(K,{to:"/",replace:!0});const u=N(r.year,r.month,-1),p=N(r.year,r.month,1),b=`${u.year}-${i(u.month)}`,g=`${p.year}-${i(p.month)}`,M=j(),w=`${r.year}-${i(r.month)}`===M;return e.jsxs("div",{className:"mx-auto max-w-4xl px-4 py-6 md:px-6 md:py-10",children:[e.jsxs("header",{className:"mb-6 flex flex-wrap items-baseline justify-between gap-3",children:[e.jsxs("div",{children:[e.jsx("p",{className:"text-xs uppercase tracking-wider text-fg-dim",children:"Calendar"}),e.jsx("h1",{className:"font-serif text-3xl tracking-tight",children:C(r.year,r.month)})]}),e.jsxs("div",{className:"flex flex-wrap items-center gap-2 text-sm",children:[e.jsxs(d,{to:`/calendar?month=${b}`,className:"rounded-md border border-border bg-card px-3 py-1.5 text-fg-muted hover:text-accent","aria-label":"Previous month",children:["← ",b]}),w?null:e.jsx(d,{to:"/calendar",className:"rounded-md border border-border bg-card px-3 py-1.5 text-fg-muted hover:text-accent",children:"This month"}),e.jsxs(d,{to:`/calendar?month=${g}`,className:"rounded-md border border-border bg-card px-3 py-1.5 text-fg-muted hover:text-accent","aria-label":"Next month",children:[g," →"]}),e.jsx(d,{to:`/today?date=${h}`,className:"rounded-md border border-border bg-card px-3 py-1.5 text-fg-muted hover:text-accent",children:"Today"})]})]}),s.isError?e.jsx(L,{error:s.error}):e.jsxs("div",{className:"rounded-md border border-border bg-card","aria-busy":s.isPending,children:[e.jsx("div",{className:"grid grid-cols-7 border-b border-border text-xs uppercase tracking-wider text-fg-dim",children:_.map(t=>e.jsx("div",{className:"px-2 py-2 text-center",children:t},t))}),e.jsx("div",{className:"grid grid-cols-7",children:v.map(t=>{const n=`${t.getFullYear()}-${i(t.getMonth()+1)}-${i(t.getDate())}`,c=t.getMonth()+1===r.month,m=$.get(n)??0,D=n===h;return e.jsxs(d,{to:`/today?date=${n}`,className:`flex min-h-20 flex-col border-b border-r border-border p-1.5 text-xs hover:bg-bg/60 focus:bg-bg/60 focus:outline-none ${c?"":"opacity-40"}`,"aria-label":`${n} — ${m} notes`,children:[e.jsx("span",{className:`mb-1 inline-flex h-6 w-6 items-center justify-center rounded-full ${D?"bg-accent text-white":"text-fg"}`,children:t.getDate()}),m>0?e.jsx(F,{count:m}):e.jsx("span",{className:"sr-only",children:"no notes"})]},n)})})]}),e.jsx("p",{className:"mt-3 text-xs text-fg-dim",children:"Each dot is a note created on that day. Click any day to open /today."})]})}function F({count:a}){const o=Math.min(a,x),l=a>x?a-x:0;return e.jsxs("span",{className:"flex flex-wrap items-center gap-0.5",children:[Array.from({length:o}).map((r,s)=>e.jsx("span",{className:"h-1.5 w-1.5 rounded-full bg-accent","aria-hidden":"true"},s)),l>0?e.jsxs("span",{className:"ml-0.5 text-[10px] text-fg-dim",children:["+",l]}):null]})}function L({error:a}){const o=a instanceof S;return e.jsxs("div",{className:"rounded-md border border-red-500/30 bg-red-500/5 p-6",children:[e.jsx("p",{className:"mb-2 font-medium text-red-400",children:o?"Session expired":"Could not load notes"}),e.jsx("p",{className:"mb-4 text-sm text-fg-muted",children:a.message}),o?e.jsx(d,{to:"/add",className:"inline-block rounded-md bg-accent px-4 py-2 text-sm font-medium text-white hover:bg-accent-hover",children:"Reconnect vault"}):null]})}export{Y as Calendar};
@@ -0,0 +1,9 @@
1
+ import{aa as xe,a7 as be,a4 as ye,a5 as ve,E as we,x as i,t as Y,n as ke,s as Te,m as S,k as Re,r as a,N as Se,z as je,e as Ne,u as oe,L as Ee}from"./index-BDPMEkxL.js";const Ie=["audio/webm;codecs=opus","audio/mp4","audio/ogg;codecs=opus"];function Ce(r=Ie){if(typeof MediaRecorder>"u")return null;for(const t of r)if(MediaRecorder.isTypeSupported(t))return t;return null}function Me(r){return r.startsWith("audio/webm")?"webm":r.startsWith("audio/mp4")?"m4a":r.startsWith("audio/ogg")?"ogg":r.startsWith("audio/wav")?"wav":"bin"}function Ae(r){const t=r.now??(()=>Date.now()),d=r.MediaRecorderCtor??MediaRecorder,n=new d(r.stream,{mimeType:r.mimeType}),l=[];let s="idle",m=0,A=0;n.ondataavailable=k=>{k.data&&k.data.size>0&&l.push(k.data)};const p=()=>{for(const k of r.stream.getTracks())k.stop()};return{get state(){return s},get mimeType(){return r.mimeType},start(){if(s!=="idle")throw new Error(`Cannot start from ${s}`);n.start(),m=t(),s="recording"},pause(){s==="recording"&&(n.pause(),A+=t()-m,s="paused")},resume(){s==="paused"&&(n.resume(),m=t(),s="recording")},async stop(){if(s==="idle"||s==="stopped")throw new Error(`Cannot stop from ${s}`);s==="recording"&&(A+=t()-m);const k=new Promise(x=>{n.onstop=async()=>{const L=await $e(l);x({data:L,mimeType:r.mimeType,durationMs:A})}});return n.stop(),s="stopped",p(),k},cancel(){if(s==="recording"||s==="paused")try{n.stop()}catch{}s="stopped",l.length=0,p()}}}async function De(r){const t=r;return typeof t.arrayBuffer=="function"?t.arrayBuffer():new Promise((d,n)=>{const l=new FileReader;l.onload=()=>d(l.result),l.onerror=()=>n(l.error??new Error("FileReader error")),l.readAsArrayBuffer(r)})}async function $e(r){if(r.length===0)return new ArrayBuffer(0);const t=await Promise.all(r.map(s=>De(s))),d=t.reduce((s,m)=>s+m.byteLength,0),n=new Uint8Array(d);let l=0;for(const s of t)n.set(new Uint8Array(s),l),l+=s.byteLength;return n.buffer}async function Oe(){var r;if(typeof navigator>"u"||!((r=navigator.mediaDevices)!=null&&r.getUserMedia)){const t=new Error("Microphone is not available in this browser.");throw t.kind="unavailable",t}try{return await navigator.mediaDevices.getUserMedia({audio:!0})}catch(t){const d=new Error(t instanceof Error?t.message:"Microphone permission denied."),n=t instanceof DOMException?t.name:"";throw d.kind=n==="NotFoundError"||n==="OverconstrainedError"?"no-device":"permission-denied",d}}function Le(r,t=new Date){return`memo-${t.toISOString().replace(/[:.]/g,"-").replace(/Z$/,"")}.${Me(r)}`}function se(r=new Date){const t=r.getFullYear(),d=String(r.getMonth()+1).padStart(2,"0"),n=String(r.getDate()).padStart(2,"0"),l=String(r.getHours()).padStart(2,"0"),s=String(r.getMinutes()).padStart(2,"0"),m=String(r.getSeconds()).padStart(2,"0");return`Notes/${t}/${d}-${n}/${l}-${s}-${m}`}const Pe=/(?:^|\s)#([a-zA-Z][\w-]*)/g;function Z(r){const t=new Set;for(const d of r.matchAll(Pe)){const n=oe(d[1]??"");n&&t.add(n)}return[...t]}function G(r){const t=Math.floor(r/1e3),d=Math.floor(t/60),n=t%60;return`${String(d).padStart(2,"0")}:${String(n).padStart(2,"0")}`}function Fe({moreFieldsOpenDefault:r=!1}={}){const t=xe(e=>e.getActiveVault()),d=be(e=>e.push),{db:n,blobStore:l,engine:s}=ye(),{roles:m}=ve((t==null?void 0:t.id)??null),A=we(),[p,k]=i.useState(""),[x,L]=i.useState([]),[ie,F]=i.useState(""),[ce,de]=i.useState(r),D=i.useRef(se()),J=i.useRef(!1),[j,Q]=i.useState(()=>D.current),le=i.useCallback(e=>{J.current=e.trim()!==""&&e!==D.current,Q(e)},[]),[N,ue]=i.useState(""),[c,b]=i.useState({kind:"idle"}),[me,B]=i.useState(0),$=i.useRef(null),[q,X]=i.useState(null),[pe,fe]=i.useState(0),V=i.useRef(null),E=i.useRef(null),W=i.useRef(null),P=i.useRef(!1);i.useEffect(()=>{if(c.kind!=="recording")return;const e=setInterval(()=>B(Date.now()-c.startedAt),250);return()=>clearInterval(e)},[c]),i.useEffect(()=>()=>{E.current&&URL.revokeObjectURL(E.current)},[]),i.useEffect(()=>{var e;(e=W.current)==null||e.focus()},[]);const ge=i.useCallback(async()=>{if(!(c.kind==="recording"||c.kind==="requesting")){b({kind:"requesting"});try{const e=Ce();if(!e){b({kind:"denied",message:"This browser can't record audio in a format we can save."});return}const o=await Oe(),u=Ae({stream:o,mimeType:e});V.current=u,u.start(),B(0),b({kind:"recording",startedAt:Date.now()})}catch(e){const o=e,u=o.kind==="permission-denied"?"Microphone access was denied. Update your browser's site settings to record.":o.kind==="no-device"?"No microphone was found on this device.":o instanceof Error?o.message:"Microphone is not available in this browser.";b({kind:"denied",message:u})}}},[c]),ee=i.useCallback(async()=>{const e=V.current;if(!(!e||c.kind!=="recording"))try{const o=await e.stop();V.current=null;const u=new Blob([o.data],{type:o.mimeType}),y=URL.createObjectURL(u);E.current&&URL.revokeObjectURL(E.current),E.current=y,b({kind:"have-audio",data:o.data,mimeType:o.mimeType,url:y,durationMs:o.durationMs})}catch(o){d(o instanceof Error?`Recording failed: ${o.message}`:"Recording failed.","error"),b({kind:"idle"})}},[c,d]);i.useEffect(()=>{if(c.kind!=="recording")return;const e=()=>{ee()};return window.addEventListener("pointerup",e),window.addEventListener("pointercancel",e),()=>{window.removeEventListener("pointerup",e),window.removeEventListener("pointercancel",e)}},[c,ee]);const _=i.useCallback(()=>{E.current&&(URL.revokeObjectURL(E.current),E.current=null),b({kind:"idle"}),B(0)},[]),te=i.useCallback(()=>{var e;if($.current=null,X(null),k(""),L([]),F(""),!J.current){const o=se();D.current=o,Q(o)}_(),(e=W.current)==null||e.focus()},[_]),U=c.kind==="have-audio",T=p.trim().length>0,H=(T||U)&&c.kind!=="saving",z=i.useCallback(async()=>{if(!H||!n||!t)return;if(U&&!l){d("Sync queue not ready — try again in a moment.","error");return}const e=c.kind==="have-audio"?c:null;P.current=!0,b({kind:"saving"});const o=x.filter(g=>g.length>0),u=Z(p),y=[];T&&y.push(m.captureText),e&&y.push(m.captureVoice);const v=Array.from(new Set([...y,...o,...u].filter(g=>g.length>0))),f=$.current,w=(f==null?void 0:f.localId)??Y(),I=j.trim()||D.current,C=N.trim(),h=C?{summary:C}:void 0;A&&ke(t.id,A);try{if(e){const g=new Date,O=Le(e.mimeType,g),M=Te(),R=T?`${p.trim()}
2
+
3
+ _Transcript pending._
4
+
5
+ ![[${O}]]
6
+ `:`_Transcript pending._
7
+
8
+ ![[${O}]]
9
+ `,ae=I;if(!l)throw new Error("blob store missing");await l.put(M,e.data,e.mimeType,t.id),await S(n,{kind:"create-note",localId:w,payload:{content:R,path:ae,...v.length?{tags:v}:{},...h?{metadata:h}:{}}},{vaultId:t.id}),await S(n,{kind:"upload-attachment",blobId:M,filename:O,mimeType:e.mimeType},{vaultId:t.id}),await S(n,{kind:"link-attachment",noteId:w,pathRef:Re(M),mimeType:e.mimeType,transcribe:!0},{vaultId:t.id})}else f!=null&&f.createCommitted?await S(n,{kind:"update-note",targetId:w,payload:{content:p,path:I,...v.length?{tags:{add:v}}:{},...h?{metadata:h}:{}}},{vaultId:t.id}):await S(n,{kind:"create-note",localId:w,payload:{content:p,path:I,...v.length?{tags:v}:{},...h?{metadata:h}:{}}},{vaultId:t.id});s==null||s.runOnce(),d(e?"Captured — syncing audio.":"Captured.","success"),te(),b({kind:"idle"}),P.current=!1}catch(g){d(g instanceof Error?`Capture failed: ${g.message}`:"Capture failed.","error"),P.current=!1,b(e?{kind:"have-audio",data:e.data,mimeType:e.mimeType,url:e.url,durationMs:e.durationMs}:{kind:"idle"})}},[H,n,t,l,A,c,U,T,x,p,j,N,m.captureText,m.captureVoice,s,d,te]),re=i.useCallback(async()=>{if(!n||!t||c.kind!=="idle"||!T)return;const e=x.filter(h=>h.length>0),o=Z(p),u=Array.from(new Set([m.captureText,...e,...o].filter(h=>h.length>0))),y=j.trim()||D.current,v=N.trim(),f=v?{summary:v}:void 0,w=$.current,I=!w,C=(w==null?void 0:w.localId)??Y();I&&($.current={localId:C,createCommitted:!0});try{I?await S(n,{kind:"create-note",localId:C,payload:{content:p,path:y,...u.length?{tags:u}:{},...f?{metadata:f}:{}}},{vaultId:t.id}):await S(n,{kind:"update-note",targetId:C,payload:{content:p,path:y,...u.length?{tags:{add:u}}:{},...f?{metadata:f}:{}}},{vaultId:t.id}),s==null||s.runOnce(),X(Date.now())}catch{I&&($.current=null)}},[n,t,c.kind,T,p,x,j,N,m.captureText,s]),he=i.useCallback(e=>{(e.metaKey||e.ctrlKey)&&e.key==="Enter"&&(e.preventDefault(),z())},[z]),ne=i.useRef({db:n,activeVaultId:(t==null?void 0:t.id)??null,content:p,tags:x,pathOverride:j,summary:N,roles:m});return ne.current={db:n,activeVaultId:(t==null?void 0:t.id)??null,content:p,tags:x,pathOverride:j,summary:N,roles:m},i.useEffect(()=>()=>{if(P.current)return;const{db:e,activeVaultId:o,content:u,tags:y,pathOverride:v,summary:f,roles:w}=ne.current;if(!u.trim()||!e||!o)return;const C=y.filter(K=>K.length>0),h=Z(u),g=Array.from(new Set([w.captureText,...C,...h].filter(K=>K.length>0))),O=v.trim()||D.current,M=f.trim(),R=$.current;(R!=null&&R.createCommitted?S(e,{kind:"update-note",targetId:R.localId,payload:{content:u,path:O,...g.length?{tags:{add:g}}:{},...M?{metadata:{summary:M}}:{}}},{vaultId:o}):S(e,{kind:"create-note",localId:(R==null?void 0:R.localId)??Y(),payload:{content:u,path:O,...g.length?{tags:g}:{},...M?{metadata:{summary:M}}:{}}},{vaultId:o})).catch(()=>{})},[]),i.useEffect(()=>{if(q===null)return;const e=setInterval(()=>{fe(o=>o+1)},15e3);return()=>clearInterval(e)},[q]),i.useEffect(()=>{if(c.kind==="recording"||c.kind==="requesting"||c.kind==="saving"||c.kind==="have-audio"||!T)return;const e=setTimeout(()=>{P.current||re()},5e3);return()=>clearTimeout(e)},[c.kind,T,p,x,j,N,re]),t?a.jsxs("div",{className:"mx-auto max-w-2xl px-4 py-5 md:px-6 md:py-8",children:[a.jsxs("header",{className:"mb-5",children:[a.jsx("h1",{className:"font-serif text-2xl text-fg md:text-3xl",children:"Capture"}),a.jsxs("p",{className:"mt-1 text-xs text-fg-dim",children:["Type a thought, hold the mic to record, or both."," ",a.jsx("kbd",{className:"rounded bg-bg/60 px-1",children:"⌘"}),a.jsx("kbd",{className:"rounded bg-bg/60 px-1",children:"↵"})," to send."]})]}),a.jsxs("section",{className:"flex flex-col gap-4 rounded-xl border border-border bg-card p-5 md:p-6",children:[a.jsx("textarea",{ref:W,value:p,onChange:e=>k(e.target.value),onKeyDown:he,placeholder:"What are you thinking?","aria-label":"Capture content",rows:8,disabled:c.kind==="saving",className:"min-h-[30vh] w-full resize-y rounded-md border border-border bg-bg px-3 py-2 text-sm text-fg placeholder:text-fg-dim focus:border-accent focus:outline-none disabled:opacity-60"}),q!==null?a.jsxs("p",{className:"-mt-2 text-right text-[11px] text-fg-dim","aria-live":"polite","data-indicator-tick":pe,children:["Draft saved · ",je(new Date(q).toISOString())]}):null,c.kind==="have-audio"?a.jsxs("div",{className:"flex flex-col gap-2 rounded-md border border-accent/30 bg-accent/5 p-3",children:[a.jsxs("div",{className:"flex items-center justify-between gap-3",children:[a.jsxs("span",{className:"text-sm text-fg-muted",children:["🎙 Recorded ",G(c.durationMs)]}),a.jsx("button",{type:"button",onClick:_,className:"text-xs text-fg-dim hover:text-red-400",children:"Discard"})]}),a.jsx("audio",{controls:!0,src:c.url,className:"w-full",children:a.jsx("track",{kind:"captions"})}),a.jsx("p",{className:"text-xs text-fg-dim",children:"Transcript will be appended once your vault processes it."})]}):null,c.kind==="denied"?a.jsx("p",{className:"rounded-md border border-red-500/30 bg-red-500/5 px-3 py-2 text-xs text-red-400",children:c.message}):null,a.jsx(Ne,{tags:x,input:ie,onInputChange:F,onAdd:e=>{const o=oe(e);!o||x.includes(o)||(L(u=>[...u,o]),F(""))},onRemove:e=>L(o=>o.filter(u=>u!==e))}),a.jsxs("details",{className:"group rounded-md border border-border bg-bg/50",open:ce,onToggle:e=>de(e.currentTarget.open),children:[a.jsx("summary",{className:"cursor-pointer select-none px-3 py-2 text-xs text-fg-muted hover:text-accent",children:"More fields"}),a.jsxs("div",{className:"space-y-3 px-3 pb-3 pt-1",children:[a.jsxs("label",{className:"flex flex-col gap-1 text-xs",children:[a.jsx("span",{className:"text-fg-dim",children:"Path"}),a.jsx("input",{type:"text",value:j,onChange:e=>le(e.target.value),placeholder:"(blank → uses generated path)","aria-label":"Path override",className:"rounded-md border border-border bg-card px-2.5 py-1.5 font-mono text-xs text-fg focus:border-accent focus:outline-none"})]}),a.jsxs("label",{className:"flex flex-col gap-1 text-xs",children:[a.jsx("span",{className:"text-fg-dim",children:"Summary"}),a.jsx("input",{type:"text",value:N,onChange:e=>ue(e.target.value),placeholder:"(optional one-line description)","aria-label":"Summary",className:"rounded-md border border-border bg-card px-2.5 py-1.5 text-xs text-fg focus:border-accent focus:outline-none"})]}),a.jsxs("p",{className:"text-xs text-fg-dim",children:["Need to attach a file?"," ",a.jsx(Ee,{to:"/new",className:"text-accent hover:underline",children:"Open the full editor"}),"."]})]})]}),a.jsxs("div",{className:"flex items-center justify-between gap-3 pt-2",children:[a.jsx(Ue,{phase:c,elapsedMs:me,onPointerDown:()=>void ge()}),a.jsxs("div",{className:"flex flex-col items-end gap-1",children:[a.jsx("button",{type:"button",onClick:()=>void z(),disabled:!H,className:"min-h-11 rounded-md bg-accent px-4 py-2 text-sm font-medium text-white hover:bg-accent-hover disabled:opacity-40",children:c.kind==="saving"?"Saving…":"Capture"}),a.jsx("span",{className:"text-[11px] text-fg-dim",children:U&&T?"Will save as a note with audio attached.":U?"Will save as a voice memo.":T?"Will save as a text note.":"Type or record to capture."})]})]})]})]}):a.jsx(Se,{to:"/",replace:!0})}function Ue({phase:r,elapsedMs:t,onPointerDown:d}){const n=r.kind==="recording",l=r.kind==="requesting",s=n?`Recording — release to stop (${G(t)})`:l?"Requesting microphone…":"Hold to record";return a.jsxs("button",{type:"button",onPointerDown:m=>{m.preventDefault(),d()},"aria-label":s,"aria-pressed":n,disabled:r.kind==="saving",className:`flex min-h-11 items-center gap-2 rounded-full border px-4 py-2 text-sm font-medium transition select-none ${n?"border-red-500/40 bg-red-500/10 text-red-400":"border-accent/30 bg-accent/10 text-accent hover:bg-accent/15"} disabled:opacity-40`,children:[a.jsx("span",{"aria-hidden":"true",className:n?"animate-pulse":"",children:"🎙"}),a.jsx("span",{children:n?`Rec ${G(t)}`:l?"Requesting…":"Hold to record"})]})}export{Fe as Capture,Z as extractHashtags};
@@ -0,0 +1 @@
1
+ import{x as d,r as e,a7 as D,J as V,V as C,g as _,Y as z,aa as O,U as Y,N as K,L as R,Q as W,a8 as q,f as H,z as T,e as J,u as Q}from"./index-BDPMEkxL.js";import{u as Z,A as G,C as X,a as ee,b as te}from"./useAttachmentUploader-CRSqlwYK.js";import{P as se,D as ne}from"./PinArchiveButtons-DogtDLiB.js";import{b as re,N as ae}from"./NoteRenderer-cz03kLyS.js";const oe=250;function de({noteId:t,attachment:n}){const[l,a]=d.useState(!1),o=ce(n);return e.jsxs(e.Fragment,{children:[e.jsx("button",{type:"button",onClick:()=>a(!0),"aria-label":`Remove attachment ${o}`,className:"shrink-0 rounded border border-transparent px-1.5 py-0.5 text-fg-dim hover:border-red-500/40 hover:text-red-400",children:"✕"}),l?e.jsx(ie,{noteId:t,attachment:n,label:o,onClose:()=>a(!1)}):null]})}function ie({noteId:t,attachment:n,label:l,onClose:a}){const o=D(i=>i.push),m=V(),[s,h]=d.useState(!1),[w,p]=d.useState(null),N=d.useRef(null);d.useEffect(()=>{const i=setTimeout(()=>h(!0),oe);return()=>clearTimeout(i)},[]),d.useEffect(()=>{var i;(i=N.current)==null||i.focus()},[]),d.useEffect(()=>{const i=g=>{g.key==="Escape"&&a()};return window.addEventListener("keydown",i),()=>window.removeEventListener("keydown",i)},[a]);const b=d.useCallback(()=>{!s||m.isPending||(p(null),m.mutate({noteId:t,attachmentId:n.id},{onSuccess:()=>{o(`Removed ${l}`,"success"),a()},onError:i=>{if(i instanceof C){p("Session expired. Reconnect to remove attachments.");return}if(i instanceof _){o(`Already removed ${l}`,"info"),a();return}p(i instanceof Error?i.message:"Remove failed")}}))},[s,n.id,l,m,t,a,o]);return e.jsx("dialog",{open:!0,"aria-labelledby":"confirm-remove-attachment-title",className:"fixed inset-0 z-40 m-0 flex h-full max-h-full w-full max-w-full items-center justify-center bg-black/60 p-4",onMouseDown:i=>{i.target===i.currentTarget&&a()},children:e.jsxs("div",{className:"w-full max-w-md rounded-md border border-border bg-card p-6 shadow-xl",children:[e.jsx("h2",{id:"confirm-remove-attachment-title",className:"mb-2 font-serif text-lg text-red-400",children:"Remove attachment?"}),e.jsxs("p",{className:"mb-3 text-sm text-fg-muted",children:[e.jsx("span",{className:"rounded bg-bg/60 px-1 py-0.5 font-mono text-xs text-fg",children:l})," ","will be detached from this note. If no other note references the file, it will also be deleted from storage. Markdown referencing it will show a broken link until you update it."]}),w?e.jsx("p",{role:"alert",className:"mb-3 text-sm text-red-400",children:w}):null,e.jsxs("div",{className:"flex justify-end gap-2",children:[e.jsx("button",{ref:N,type:"button",onClick:a,className:"min-h-11 rounded-md border border-border bg-card px-3 py-1.5 text-sm text-fg-muted hover:text-fg",children:"Cancel"}),e.jsx("button",{type:"button",onClick:b,disabled:!s||m.isPending,className:"min-h-11 rounded-md bg-red-500 px-4 py-1.5 text-sm font-medium text-white hover:bg-red-600 disabled:opacity-40",children:m.isPending?"Removing…":"Remove"})]})]})})}function ce(t){if(t.filename)return t.filename;if(t.path){const n=t.path.split("/").pop();return n||t.path}return t.id}function we(){const{id:t}=z(),n=t?decodeURIComponent(t):void 0,l=O(o=>o.getActiveVault()),a=Y(n);return l?e.jsxs("div",{className:"mx-auto max-w-6xl px-4 py-5 md:px-6 md:py-8",children:[e.jsx("nav",{className:"mb-4 text-sm text-fg-dim",children:e.jsx(R,{to:n?`/n/${encodeURIComponent(n)}`:"/",className:"hover:text-accent",children:"← Back to note"})}),a.isPending?e.jsx(xe,{}):a.isError?e.jsx(fe,{error:a.error}):a.data?e.jsx(le,{note:a.data}):e.jsx(he,{id:n??""})]}):e.jsx(K,{to:"/",replace:!0})}function S(t){return{content:t.content??"",path:t.path??"",tags:[...t.tags??[]]}}function le({note:t}){const n=W(),l=D(r=>r.push),a=d.useMemo(()=>re(t),[t]),[o,m]=d.useState(()=>S(t)),[s,h]=d.useState(()=>S(t)),[w,p]=d.useState(""),[N,b]=d.useState(null),[i,g]=d.useState(null),[y,L]=d.useState("edit"),v=q(t.id),k=d.useRef(t),E=d.useRef(null),j=Z({noteId:t.id,onInsert:r=>{E.current?E.current.insertAtCursor(r):h(c=>({...c,content:`${c.content}${r}`}))},onLinked:()=>{l("Attachment added","success")},onError:r=>l(r,"error")});d.useEffect(()=>{k.current=t},[t]);const u=s.content!==o.content||s.path!==o.path||!pe(s.tags,o.tags),A=d.useCallback(()=>{if(!u||v.isPending)return;const r={};s.content!==o.content&&(r.content=s.content),s.path!==o.path&&(r.path=s.path);const c=be(o.tags,s.tags);(c.add.length||c.remove.length)&&(r.tags=c);const f=k.current.updatedAt??k.current.createdAt;f&&(r.if_updated_at=f),g(null),b(null),v.mutate(r,{onSuccess:x=>{m(S(x)),h(S(x)),k.current=x,x.id!==t.id&&n(`/n/${encodeURIComponent(x.id)}/edit`,{replace:!0})},onError:x=>{x instanceof H?b(x):x instanceof C?g("Session expired. Reconnect to save."):g(x instanceof Error?x.message:"Save failed")}})},[o,s,u,v,n,t.id]),U=d.useCallback(()=>{u&&confirm("Discard all edits and revert to last saved version?")&&(h(o),b(null),g(null))},[o,u]),P=d.useCallback(()=>{u&&!confirm("Discard unsaved changes?")||n(`/n/${encodeURIComponent(t.id)}`)},[u,n,t.id]);d.useEffect(()=>{if(!u)return;const r=c=>{c.preventDefault(),c.returnValue=""};return window.addEventListener("beforeunload",r),()=>window.removeEventListener("beforeunload",r)},[u]);const $=s.path!==o.path,B=r=>{const c=Q(r);c&&(s.tags.includes(c)||(h(f=>({...f,tags:[...f.tags,c]})),p("")))},F=r=>{h(c=>({...c,tags:c.tags.filter(f=>f!==r)}))},M=s.content;return e.jsxs("article",{children:[e.jsxs("header",{className:"mb-4 border-b border-border pb-4",children:[e.jsxs("div",{className:"flex flex-wrap items-center justify-between gap-3",children:[e.jsxs("div",{className:"flex items-center gap-2 text-sm",children:[e.jsx("span",{className:"text-xs uppercase tracking-wider text-fg-dim",children:"Editing"}),u?e.jsxs("span",{className:"inline-flex items-center gap-1 text-xs text-accent","aria-label":"unsaved changes",children:[e.jsx("span",{className:"h-1.5 w-1.5 rounded-full bg-accent"}),"unsaved"]}):e.jsxs("span",{className:"text-xs text-fg-dim",children:["saved ",T(t.updatedAt)]})]}),e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[e.jsx(se,{note:t}),e.jsx(ne,{note:t}),e.jsx("span",{className:"mx-1 h-5 w-px bg-border","aria-hidden":"true"}),e.jsx("button",{type:"button",onClick:U,disabled:!u||v.isPending,className:"min-h-11 rounded-md border border-border bg-card px-3 py-1.5 text-sm text-fg-muted hover:text-accent disabled:opacity-40",children:"Revert"}),e.jsx("button",{type:"button",onClick:P,className:"min-h-11 rounded-md border border-border bg-card px-3 py-1.5 text-sm text-fg-muted hover:text-accent",children:"Cancel"}),e.jsx("button",{type:"button",onClick:A,disabled:!u||v.isPending,className:"min-h-11 rounded-md bg-accent px-4 py-1.5 text-sm font-medium text-white hover:bg-accent-hover disabled:opacity-40",title:"Save (⌘S)",children:v.isPending?"Saving…":"Save"})]})]}),e.jsxs("div",{className:"mt-3 flex flex-col gap-2",children:[e.jsx(J,{tags:s.tags,input:w,onInputChange:p,onAdd:B,onRemove:F}),e.jsxs("label",{className:"flex items-baseline gap-3 text-sm",children:[e.jsx("span",{className:"shrink-0 text-xs uppercase tracking-wider text-fg-dim",children:"Path"}),e.jsx("input",{type:"text",value:s.path,onChange:r=>h(c=>({...c,path:r.target.value})),className:"flex-1 rounded-md border border-border bg-card px-2.5 py-1 font-mono text-sm text-fg focus:border-accent focus:outline-none","aria-label":"Note path",placeholder:"(no path)"})]}),$?e.jsx("p",{className:"text-xs text-accent",children:"Renaming moves the note — its id may change."}):null]})]}),N?e.jsx(ue,{conflict:N,onReload:()=>{window.location.reload()},onDismiss:()=>b(null)}):null,i?e.jsx("div",{className:"mb-4 rounded-md border border-red-500/30 bg-red-500/5 p-3 text-sm text-red-400",children:i}):null,e.jsx("div",{role:"tablist","aria-label":"Editor view",className:"mb-3 inline-flex rounded-md border border-border bg-card p-0.5 text-sm lg:hidden",children:["edit","preview"].map(r=>e.jsx("button",{type:"button",role:"tab","aria-selected":y===r,onClick:()=>L(r),className:`rounded px-3 py-1.5 capitalize ${y===r?"bg-accent text-white":"text-fg-muted hover:text-accent"}`,children:r},r))}),e.jsxs("div",{className:"grid min-h-[60vh] gap-4 lg:grid-cols-2",children:[e.jsx(G,{onDropFiles:j.start,className:`min-w-0 rounded-md border border-border bg-card ${y==="edit"?"":"hidden lg:block"}`,hint:I,children:e.jsx(X,{ref:E,value:s.content,onChange:r=>h(c=>({...c,content:r})),onSave:A,onCancel:P,onPasteFile:r=>(j.start(r),!0)})}),e.jsx("div",{className:`min-w-0 overflow-auto rounded-md border border-border bg-card p-4 ${y==="preview"?"":"hidden lg:block"}`,children:e.jsx(ae,{note:{path:s.path,content:M},resolve:a})})]}),e.jsx(me,{noteId:t.id,attachments:t.attachments??[],uploads:j.uploads,onPickFiles:j.start,onCancel:j.cancel,onDismiss:j.dismiss})]})}const I=e.jsxs(e.Fragment,{children:["Images, audio, webm video."," ",e.jsx("a",{href:"https://github.com/ParachuteComputer/parachute-vault/issues/127",target:"_blank",rel:"noreferrer",className:"underline",children:"PDF + mp4 coming"})]});function me({noteId:t,attachments:n,uploads:l,onPickFiles:a,onCancel:o,onDismiss:m}){return e.jsxs("section",{className:"mt-6 border-t border-border pt-4",children:[e.jsxs("div",{className:"mb-3 flex items-center justify-between",children:[e.jsx("h2",{className:"font-serif text-lg",children:"Attachments"}),e.jsx(ee,{onPickFiles:a})]}),e.jsxs("p",{className:"mb-3 text-xs text-fg-dim",children:["Drop or paste files into the editor. Max 100 MB each. ",I,"."]}),e.jsx(te,{uploads:l,onCancel:o,onDismiss:m}),n.length>0?e.jsx("ul",{className:"mt-3 space-y-1 text-sm",children:n.map(s=>e.jsxs("li",{className:"flex items-center justify-between gap-2 rounded border border-border bg-card/50 px-3 py-1.5 font-mono text-xs",children:[e.jsx("span",{className:"truncate",title:s.path??s.id,children:s.filename??s.path??s.id}),e.jsxs("div",{className:"flex shrink-0 items-center gap-2",children:[s.mimeType?e.jsx("span",{className:"text-fg-dim",children:s.mimeType}):null,e.jsx(de,{noteId:t,attachment:s})]})]},s.id))}):null]})}function ue({conflict:t,onReload:n,onDismiss:l}){return e.jsxs("div",{className:"mb-4 rounded-md border border-amber-500/40 bg-amber-500/10 p-4",children:[e.jsx("p",{className:"mb-1 font-medium text-amber-500",children:"This note was edited elsewhere."}),e.jsxs("p",{className:"mb-3 text-sm text-fg-muted",children:["Your save was rejected to avoid overwriting the other edit.",t.currentUpdatedAt?` Latest update ${T(t.currentUpdatedAt)}.`:""]}),e.jsxs("div",{className:"flex flex-wrap gap-2",children:[e.jsx("button",{type:"button",onClick:n,className:"rounded-md bg-accent px-3 py-1.5 text-sm font-medium text-white hover:bg-accent-hover",children:"Reload latest (discard my edits)"}),e.jsx("button",{type:"button",onClick:l,className:"rounded-md border border-border px-3 py-1.5 text-sm text-fg-muted hover:text-fg",children:"Keep editing"})]})]})}function xe(){return e.jsxs("div",{className:"grid min-h-[60vh] gap-4 lg:grid-cols-2","aria-busy":"true",children:[e.jsx("div",{className:"animate-pulse rounded-md border border-border bg-card"}),e.jsx("div",{className:"animate-pulse rounded-md border border-border bg-card"})]})}function he({id:t}){return e.jsxs("div",{className:"rounded-md border border-border bg-card p-10 text-center",children:[e.jsx("p",{className:"mb-2 font-serif text-xl",children:"Note not found"}),e.jsxs("p",{className:"mb-4 text-sm text-fg-muted",children:["No note with id ",e.jsx("span",{className:"font-mono",children:t})," in this vault."]}),e.jsx(R,{to:"/",className:"text-sm text-accent hover:underline",children:"Back to all notes"})]})}function fe({error:t}){const n=t instanceof C;return e.jsxs("div",{className:"rounded-md border border-red-500/30 bg-red-500/5 p-6",children:[e.jsx("p",{className:"mb-2 font-medium text-red-400",children:n?"Session expired":"Could not load note"}),e.jsx("p",{className:"mb-4 text-sm text-fg-muted",children:t.message}),n?e.jsx(R,{to:"/add",className:"inline-block rounded-md bg-accent px-4 py-2 text-sm font-medium text-white hover:bg-accent-hover",children:"Reconnect vault"}):null]})}function pe(t,n){if(t.length!==n.length)return!1;const l=new Set(t);for(const a of n)if(!l.has(a))return!1;return!0}function be(t,n){const l=new Set(t),a=new Set(n),o=n.filter(s=>!l.has(s)),m=t.filter(s=>!a.has(s));return{add:o,remove:m}}export{we as NoteEditor};
@@ -0,0 +1 @@
1
+ import{aa as P,Q as T,a7 as I,H as R,M as L,x as n,r as e,N as V,V as $,L as F,e as M,u as _}from"./index-BDPMEkxL.js";import{u as U,A as B,C as z,a as H,b as O}from"./useAttachmentUploader-CRSqlwYK.js";import{b as Q,N as W}from"./NoteRenderer-cz03kLyS.js";const Y={content:"",path:"",tags:[],summary:""};function J(){const w=P(t=>t.getActiveVault()),l=T(),d=I(t=>t.push),c=R(),f=L(),[a,o]=n.useState(Y),[C,b]=n.useState(""),[v,x]=n.useState(null),[m,k]=n.useState([]),p=n.useRef(null),i=U({noteId:null,onInsert:t=>{p.current?p.current.insertAtCursor(t):o(s=>({...s,content:`${s.content}${t}`}))},onStaged:t=>k(s=>[...s,t]),onError:t=>d(t,"error")});if(!w)return e.jsx(V,{to:"/",replace:!0});const u=a.content.length>0||a.path.length>0||a.tags.length>0||a.summary.length>0,h=a.content.trim().length>0&&a.path.trim().length>0,j=n.useCallback(()=>{if(!h||c.isPending)return;const t={content:a.content,path:a.path.trim()};a.tags.length&&(t.tags=a.tags);const s=a.summary.trim();s&&(t.metadata={summary:s}),x(null),c.mutate(t,{onSuccess:async r=>{for(const g of m)try{await f.mutateAsync({noteId:r.id,path:g.path,mimeType:g.mimeType})}catch(y){const D=y instanceof Error?y.message:"Link failed";d(`Failed to attach ${g.filename}: ${D}`,"error")}d(`Created ${r.path??r.id}`,"success"),l(`/n/${encodeURIComponent(r.id)}`)},onError:r=>{r instanceof $?x("Session expired. Reconnect to save."):x(r instanceof Error?`${r.message} — if the path is taken, try a different one.`:"Create failed")}})},[a,h,f,c,l,d,m]),N=n.useCallback(()=>{u&&!confirm("Discard this draft?")||l("/")},[u,l]);n.useEffect(()=>{if(!u)return;const t=s=>{s.preventDefault(),s.returnValue=""};return window.addEventListener("beforeunload",t),()=>window.removeEventListener("beforeunload",t)},[u]);const A=t=>{const s=_(t);!s||a.tags.includes(s)||(o(r=>({...r,tags:[...r.tags,s]})),b(""))},E=t=>{o(s=>({...s,tags:s.tags.filter(r=>r!==t)}))},S=Q({id:"__new__",createdAt:new Date().toISOString()});return e.jsxs("div",{className:"mx-auto max-w-6xl px-4 py-5 md:px-6 md:py-8",children:[e.jsx("nav",{className:"mb-4 text-sm text-fg-dim",children:e.jsx(F,{to:"/",className:"hover:text-accent",children:"← All notes"})}),e.jsxs("article",{children:[e.jsxs("header",{className:"mb-4 border-b border-border pb-4",children:[e.jsxs("div",{className:"flex flex-wrap items-center justify-between gap-3",children:[e.jsx("div",{className:"flex items-center gap-2 text-sm",children:e.jsx("span",{className:"text-xs uppercase tracking-wider text-fg-dim",children:"New note"})}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("button",{type:"button",onClick:N,className:"min-h-11 rounded-md border border-border bg-card px-3 py-1.5 text-sm text-fg-muted hover:text-accent",children:"Cancel"}),e.jsx("button",{type:"button",onClick:j,disabled:!h||c.isPending,className:"min-h-11 rounded-md bg-accent px-4 py-1.5 text-sm font-medium text-white hover:bg-accent-hover disabled:opacity-40",title:"Create (⌘S)",children:c.isPending?"Creating…":"Create"})]})]}),e.jsxs("div",{className:"mt-3 flex flex-col gap-2",children:[e.jsxs("label",{className:"flex items-baseline gap-3 text-sm",children:[e.jsx("span",{className:"shrink-0 text-xs uppercase tracking-wider text-fg-dim",children:"Path"}),e.jsx("input",{type:"text",value:a.path,onChange:t=>o(s=>({...s,path:t.target.value})),className:"flex-1 rounded-md border border-border bg-card px-2.5 py-1 font-mono text-sm text-fg focus:border-accent focus:outline-none","aria-label":"Note path",placeholder:"e.g. Projects/README"})]}),e.jsxs("label",{className:"flex items-baseline gap-3 text-sm",children:[e.jsx("span",{className:"shrink-0 text-xs uppercase tracking-wider text-fg-dim",children:"Summary"}),e.jsx("input",{type:"text",value:a.summary,onChange:t=>o(s=>({...s,summary:t.target.value})),className:"flex-1 rounded-md border border-border bg-card px-2.5 py-1 text-sm text-fg focus:border-accent focus:outline-none","aria-label":"Note summary",placeholder:"(optional one-line description)"})]}),e.jsx(M,{tags:a.tags,input:C,onInputChange:b,onAdd:A,onRemove:E})]})]}),v?e.jsx("div",{role:"alert",className:"mb-4 rounded-md border border-red-500/30 bg-red-500/5 p-3 text-sm text-red-400",children:v}):null,e.jsxs("div",{className:"grid min-h-[60vh] gap-4 lg:grid-cols-2",children:[e.jsx(B,{onDropFiles:i.start,className:"min-w-0 rounded-md border border-border bg-card",hint:"Images, audio, webm video",children:e.jsx(z,{ref:p,value:a.content,onChange:t=>o(s=>({...s,content:t})),onSave:j,onCancel:N,onPasteFile:t=>(i.start(t),!0)})}),e.jsx("div",{className:"min-w-0 overflow-auto rounded-md border border-border bg-card p-4",children:a.content.trim()?e.jsx(W,{note:{path:a.path,content:a.content},resolve:S}):e.jsx("p",{className:"text-sm text-fg-dim",children:"Preview appears here as you type."})})]}),e.jsxs("section",{className:"mt-6 border-t border-border pt-4",children:[e.jsxs("div",{className:"mb-3 flex items-center justify-between",children:[e.jsx("h2",{className:"font-serif text-lg",children:"Attachments"}),e.jsx(H,{onPickFiles:i.start})]}),e.jsxs("p",{className:"mb-3 text-xs text-fg-dim",children:["Drop or paste files into the editor. Attachments link to the note when you save. Max 100 MB each. Images, audio, webm video."," ",e.jsx("a",{href:"https://github.com/ParachuteComputer/parachute-vault/issues/127",target:"_blank",rel:"noreferrer",className:"underline",children:"PDF + mp4 coming"}),"."]}),e.jsx(O,{uploads:i.uploads,onCancel:i.cancel,onDismiss:i.dismiss}),m.length>0?e.jsx("ul",{className:"mt-3 space-y-1 text-sm",children:m.map(t=>e.jsxs("li",{className:"flex items-center justify-between gap-2 rounded border border-border bg-card/50 px-3 py-1.5 font-mono text-xs text-fg-muted",children:[e.jsx("span",{className:"truncate",children:t.filename}),e.jsx("span",{className:"shrink-0 text-fg-dim",children:"staged"})]},t.path))}):null]})]})]})}export{J as NoteNew};