@openparachute/app 0.22.10 → 0.22.12

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 (49) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/dist/.parachute/info +1 -1
  3. package/dist/assets/{Account-DYfzZj5S.js → Account-CdkJMAPi.js} +1 -1
  4. package/dist/assets/Activity-DqsfIB-3.js +1 -0
  5. package/dist/assets/{AddVault-DKBqKeyq.js → AddVault-D1K_D6Y0.js} +1 -1
  6. package/dist/assets/{AddVaultChooser-BW2Q-Yue.js → AddVaultChooser-DCs3tJPw.js} +1 -1
  7. package/dist/assets/{AddVaultCreate-CtO9yrS5.js → AddVaultCreate-B3yMKaiU.js} +1 -1
  8. package/dist/assets/Calendar-DcVL4_q0.js +1 -0
  9. package/dist/assets/{CheckEmail-CIv1Gt1o.js → CheckEmail-taTm_0KJ.js} +1 -1
  10. package/dist/assets/{ConnectAI-BL20KQ5Y.js → ConnectAI-CsKHus0o.js} +1 -1
  11. package/dist/assets/DayView-BTm_sLsN.js +1 -0
  12. package/dist/assets/{Export-BynzqvGJ.js → Export-pVqCJjpd.js} +1 -1
  13. package/dist/assets/{Import-6SmwJlgO.js → Import-DDHJzkGw.js} +1 -1
  14. package/dist/assets/{NoteEditor-OPipzN_Z.js → NoteEditor-h3CHfMT1.js} +1 -1
  15. package/dist/assets/{NoteNew-Dy1AbHxm.js → NoteNew-DUVNgXN7.js} +2 -2
  16. package/dist/assets/{NoteRenderer-BXeTxHnB.js → NoteRenderer-BzRFYOTP.js} +1 -1
  17. package/dist/assets/NoteView-GsOFyCey.js +3 -0
  18. package/dist/assets/{OAuthCallback-D35vvyoO.js → OAuthCallback-BoeL9Unb.js} +1 -1
  19. package/dist/assets/{PinArchiveButtons-DyFdYBrq.js → PinArchiveButtons-DBJ9XC87.js} +1 -1
  20. package/dist/assets/{Settings-UmrOUQH_.js → Settings-C14K5QIf.js} +1 -1
  21. package/dist/assets/{TagPage-B7bGWyY4.js → TagPage-Dth86gwn.js} +1 -1
  22. package/dist/assets/{TagSchemaEditor-Bas3UMIJ.js → TagSchemaEditor-DrsKXHjg.js} +1 -1
  23. package/dist/assets/{Tags-CTF2n8-H.js → Tags-BAMUSxtu.js} +1 -1
  24. package/dist/assets/{VaultGraph-BLefh0Zh.js → VaultGraph-CUiB0dxf.js} +3 -3
  25. package/dist/assets/{Vaults-tXitT9QI.js → Vaults-YV2Gt5rq.js} +1 -1
  26. package/dist/assets/{ViewNew-DRZyYhEC.js → ViewNew--9bYKDKm.js} +1 -1
  27. package/dist/assets/ViewSurface-BhLi1m3l.js +1 -0
  28. package/dist/assets/Welcome-CG-4UtgI.js +1 -0
  29. package/dist/assets/{WizardShell-B0Fjh0Vt.js → WizardShell-BPt_HrH0.js} +1 -1
  30. package/dist/assets/{attachment-upload-B8YiOVGU.js → attachment-upload-DbV0j1WH.js} +1 -1
  31. package/dist/assets/{history-Ce29a331.js → history-Dwz434D-.js} +1 -1
  32. package/dist/assets/index-B9w7QdRL.css +1 -0
  33. package/dist/assets/index-CpyANXLa.js +66 -0
  34. package/dist/assets/{provenance-DDSHYRnT.js → provenance-O7CbiScI.js} +1 -1
  35. package/dist/assets/{react-force-graph-2d-G4yaBBi0.js → react-force-graph-2d-CQUSRInM.js} +1 -1
  36. package/dist/assets/{transcribe-default-B7i-j3pr.js → transcribe-default-DIcTpM6A.js} +1 -1
  37. package/dist/assets/{useAttachmentUploader-C78HTrMx.js → useAttachmentUploader-t5hlKCgS.js} +2 -2
  38. package/dist/index.html +2 -2
  39. package/dist/sw.js +1 -1
  40. package/meta.json +1 -1
  41. package/package.json +3 -2
  42. package/dist/assets/Activity-CKF0o1vW.js +0 -1
  43. package/dist/assets/Calendar-DFuh1M3x.js +0 -1
  44. package/dist/assets/DayView-Dr2pAVmN.js +0 -1
  45. package/dist/assets/NoteView-B0eNsUUX.js +0 -3
  46. package/dist/assets/ViewSurface-DzU1BogH.js +0 -1
  47. package/dist/assets/Welcome-yAs98HfO.js +0 -1
  48. package/dist/assets/index-H6VNro-x.js +0 -66
  49. package/dist/assets/index-rEtUY3V3.css +0 -1
package/CHANGELOG.md CHANGED
@@ -1,3 +1,21 @@
1
+ ## [0.22.12] - 2026-08-21
2
+
3
+ **The daily-driver batch: saved views appear where you look, formatting toggles stop silently failing, boot stops fetching 5,000 notes, and three chronic test flakes die.** Eight PRs, every one through an independent sandboxed review with mutation/live probes; three were bounced and re-verified before landing. (Bookkeeping note: 0.22.10 and 0.22.11 shipped without changelog entries — app#149 tracks the backfill; this entry covers only 0.22.12.)
4
+
5
+ - **"Save view" writes the canonical shape the rail actually reads (#141, fixes #127).** The All-notes save wrote the legacy saved-view format, which the rail's Views band excludes — saved views were invisible where users look first. Now writes `#view` / `Views/<name>` (verified field-for-field against the band's query), preserves the active query including archived-exclusion, and seeds the view-list cache so the rail updates immediately. Existing legacy `UI/Views/` saved filters remain as notes but no longer appear anywhere in the UI (no migration — per the #127 scope cut); re-save from All notes. Follow-ups from review landed in #142: reserved default names and sanitized duplicates blocked in the dialog.
6
+
7
+ - **Bold/italic across an inline-code span produces real formatting (#142, fixes #58).** Toggling bold over a selection spanning bold + italic + inline code inserted the closing `**` inside the code span — literal asterisks, zero effect. The ragged-selection union now expands through intersecting code spans; an exhaustive positional sweep found zero marker-parity violations. Known behavior note: a selection merely touching a code span absorbs the whole span into the toggled range, consistent with the editor's touch-a-mark convention. The symmetric gap in the code toggle is app#144.
8
+
9
+ - **Date views request their real windows with an honest ceiling (#146, fixes #110).** Boot ran a `limit=5000` fetch-everything query on every visit. Recent/Activity/Calendar/Day now send exact local-midnight date brackets (DST-verified in four timezones) with an explicit 5,000-row safety ceiling that ERRORS loudly instead of truncating silently — the first cut of this fix dropped `limit` entirely and fell into the vault's default of 50, which review caught live (Recent's 419-note window came back as 50 rows). The offline mirror evaluates the same brackets edge-for-edge, and in-app edits/deletes now invalidate the date views. Behavior change: Activity lists the current + previous 29 local days, matching its "Last 30 days" header — older history is no longer listed.
10
+
11
+ - **Tailwind `[--var]` utilities compile again (#145, fixes #41).** The bracket syntax emitted invalid CSS that was silently dropped — including the WCAG-AA on-accent text fix. The last live usage is repaired, the misleading guide corrected, and a source-level guard test fails the suite if the pattern returns (guard-coverage follow-up: app#147).
12
+
13
+ - **meta.json in the npm tarball carries the real version (#139, fixes #136).** It was hand-maintained and stuck at 0.1.3 since forever; now derived from package.json at pack time, validated before write, with tarball assertions in both CI and the publish workflow.
14
+
15
+ - **Three chronic flakes root-caused, not band-aided (#140, #143 — part of #57).** nav-history waited out a fixed 3.2s sleep for a 3s poll; now waits on the actual post-poll state. Rail's helper drains in-flight fetches; the markdown test waits on the rendered nodes it asserts. CI-log archaeology showed Rail never actually failed in the blamed runs — the real failures were the navLog race fixed in #137/#138 (#120 closed against them). #57 stays open: an AppFocusMode face was reproduced during review and remains uncharacterized.
16
+
17
+ - **The sync queue sends `transcribe: false` instead of dropping it (#128).** Rode `next` since 08-14.
18
+
1
19
  ## [0.22.9] - 2026-07-27
2
20
 
3
21
  **A 26-minute voice memo used to render as three "Transcript pending" placeholders with only one transcript actually written back, out of order — while all three sat complete in attachment metadata. Nothing was lost; the write-back was broken.**
@@ -2,7 +2,7 @@
2
2
  "name": "parachute-app",
3
3
  "displayName": "Parachute",
4
4
  "tagline": "The super-surface for your Parachute",
5
- "version": "0.22.10",
5
+ "version": "0.22.12",
6
6
  "iconUrl": "/icon.svg",
7
7
  "kind": "frontend"
8
8
  }
@@ -1 +1 @@
1
- import{r as m,u as N,g as M,j as e,a as A,L as j,b as $,c as T,s as O,l as k,m as q,d as Y,I as _,e as D,f as F,h as U,i as G,o as H,k as Q,n as X,p as z,S as I,q as C,B as J}from"./index-H6VNro-x.js";import{f as K,a as S}from"./provenance-DDSHYRnT.js";function fe(){const[t,s]=m.useState({kind:"loading"}),n=N(a=>a.identityEpoch);return m.useEffect(()=>{let a=!0;return(async()=>{let l;try{l=await M()}catch{a&&s({kind:"device"});return}a&&s(l.signed_in?{kind:"manager",email:l.email,username:l.username,csrf:l.csrf}:{kind:"device"})})(),()=>{a=!1}},[n]),e.jsxs("div",{className:"page-prose",children:[e.jsxs("header",{className:"mb-8",children:[e.jsx("h1",{className:"page-title",children:"Your parachute"}),e.jsx("p",{className:"mt-2 max-w-prose text-fg-muted",children:"Your account, plan, vaults, and connections — managed here."})]}),t.kind==="loading"?e.jsx("output",{"aria-live":"polite",className:"block py-10 text-center text-sm text-fg-dim",children:e.jsx("span",{className:"animate-pulse",children:"Loading your account…"})}):t.kind==="device"?e.jsx(me,{}):e.jsx(W,{email:t.email,username:t.username,csrf:t.csrf})]})}function W({email:t,username:s,csrf:n}){const a=$(),l=A(d=>d.getActiveVault()),c=N(d=>d.identityEpoch),i=T(),x=i.isPending?"loading":i.data??null,h=O(i.data),f=m.useCallback(()=>i.refetch(),[i.refetch]),[b,r]=m.useState("loading"),[o,g]=m.useState(null);m.useEffect(()=>{let d=!0;return k().then(y=>{d&&r(y.vaults)}).catch(y=>{q(y),d&&r("error")}),Y().then(y=>{d&&g(y)}),()=>{d=!1}},[c]);const u=m.useCallback(async()=>{try{const{vaults:d}=await k();r(d)}catch{r("error")}},[]);async function p(){try{await U(n)}finally{G(),a("/",{replace:!0})}}return e.jsxs("div",{className:"space-y-6",children:[e.jsx(Z,{email:t,username:s,summary:h,onSignOut:p}),e.jsx(te,{state:x,descriptor:o,onRetry:f,retrying:i.isFetching}),e.jsx(ue,{vaults:b,summary:h,onReload:u}),e.jsx(L,{hasActiveVault:!!l})]})}function Z({email:t,username:s,summary:n,onSignOut:a}){return e.jsx("section",{"aria-label":"Account",className:"card p-6 shadow-soft",children:e.jsxs("div",{className:"flex flex-wrap items-start justify-between gap-4",children:[e.jsxs("div",{className:"min-w-0",children:[e.jsx("p",{className:"eyebrow mb-1",children:"Signed in as"}),e.jsxs("div",{className:"flex flex-wrap items-center gap-x-3 gap-y-1",children:[e.jsx("p",{className:"break-words font-serif text-xl text-fg",children:t??s??"your account"}),e.jsx(ee,{summary:n})]})]}),e.jsx("button",{type:"button",onClick:a,className:"focus-ring shrink-0 text-sm text-fg-dim hover:text-accent",children:"Sign out"})]})})}function ee({summary:t}){if(!t)return null;const s=t.plan.trial_days_left;return typeof s=="number"?e.jsxs("span",{className:"chip border-transparent bg-sun-soft font-medium text-sun-ink",children:["Free trial · ",s===0?"ends today":`${s} day${s===1?"":"s"} left`]}):e.jsx("span",{className:"chip",children:t.plan.label})}function te({state:t,descriptor:s,onRetry:n,retrying:a}){return t===null||t!=="loading"&&t!=="error"&&!t.billing_enabled?null:e.jsxs("section",{"aria-label":"Plan & billing",className:"card p-6 shadow-soft",children:[e.jsx("h2",{className:"font-serif text-xl text-fg",children:"Plan & billing"}),t==="loading"?e.jsxs("div",{"aria-busy":"true",className:"mt-4 space-y-2.5",children:[e.jsx("div",{className:"skeleton h-4 w-3/5 rounded-md"}),e.jsx("div",{className:"skeleton h-4 w-2/5 rounded-md"})]}):t==="error"?e.jsxs("div",{className:"mt-4 text-center",children:[e.jsx("p",{className:"mb-1 font-serif text-lg text-fg",children:"Couldn't load your plan."}),e.jsx("p",{className:"mb-5 text-sm text-fg-muted",children:"A hiccup reaching your account — your plan hasn't changed."}),e.jsx("button",{type:"button",onClick:n,disabled:a,className:"btn btn-primary btn-touch",children:a?"Retrying…":"Retry"})]}):t.has_billing_customer?e.jsx(se,{summary:t}):e.jsx(oe,{summary:t,plans:(s==null?void 0:s.plans)??[]})]})}function se({summary:t}){const[s,n]=m.useState(!1),[a,l]=m.useState(null);async function c(){n(!0),l(null);try{const{url:i}=await z();window.location.assign(i)}catch(i){if(n(!1),i instanceof I){N.getState().markExpired();return}l("Billing isn't available right now.")}}return e.jsxs("div",{className:"mt-4",children:[e.jsx("p",{className:"text-sm text-fg-muted",children:R(t)}),e.jsx("button",{type:"button",onClick:c,disabled:s,className:"btn btn-primary btn-touch mt-4",children:s?"Opening…":"Manage plan & billing ↗"}),a?e.jsx(B,{text:a}):null]})}const v=["monthly","quarterly","yearly"],E={monthly:"Monthly",quarterly:"Quarterly",yearly:"Yearly"},ne={monthly:"/mo",quarterly:"/quarter",yearly:"/yr"},ae={monthly:1,quarterly:3,yearly:12};function le(t){var n,a;const s=new Set;for(const l of t)for(const c of v)(a=(n=l.intervals)==null?void 0:n[c])!=null&&a.available&&s.add(c);return v.filter(l=>s.has(l))}function V(t,s){return t.label?t.label:typeof t.price=="number"?`$${t.price}${ne[s]}`:null}function re(t){var s;for(const n of v){const a=(s=t.intervals)==null?void 0:s[n];if(a!=null&&a.available)return{interval:n,entry:a}}return null}function ie(t,s){if(!s||!t.intervals)return typeof t.price_month=="number"?`$${t.price_month}/mo`:null;const n=[];let a=!1,l=null;for(const i of v){const x=t.intervals[i];if(!(x!=null&&x.available))continue;i==="monthly"&&(a=!0);const h=V(x,i);if(h&&n.push(h),typeof x.price=="number"){const f=x.price/ae[i];l=l===null?f:Math.min(l,f)}}if(n.length===0)return null;const c=n.join(" · ");return a||l===null?c:`${c} — about $${Math.max(1,Math.round(l))}/mo`}function ce(t){if(t instanceof J)switch(t.code){case"already_subscribed":return"You're already subscribed — refresh to see your plan.";case"invalid_plan":case"invalid_interval":case"invalid_tier":return"That plan isn't offered on this cycle — pick another."}return"Billing isn't available right now."}function B({text:t}){return e.jsx("p",{className:"mt-3 rounded-lg border border-danger-border bg-danger-soft px-3 py-2 text-sm text-danger",children:t})}function oe({summary:t,plans:s}){const n=le(s),[a,l]=m.useState(null),c=a!==null&&n.includes(a)?a:n[0]??null,[i,x]=m.useState(null),[h,f]=m.useState(null);async function b(r){if(!i){x(r),f(null);try{const{url:o}=c?await C(r,c):await C(r);window.location.assign(o)}catch(o){if(x(null),o instanceof I){N.getState().markExpired();return}f(ce(o))}}}return e.jsxs("div",{className:"mt-4",children:[e.jsx("p",{className:"text-sm text-fg-muted",children:R(t)}),c&&n.length>1?e.jsxs("fieldset",{className:"mt-4 flex flex-wrap items-center gap-1.5",children:[e.jsx("legend",{className:"sr-only",children:"Billing interval"}),n.map(r=>{const o=r===c;return e.jsx("button",{type:"button",onClick:()=>l(r),"aria-pressed":o,className:`chip focus-ring ${o?"chip-tag-active font-medium":"chip-tag"}`,children:E[r]},r)})]}):null,s.length>0?e.jsx("ul",{className:"mt-4 grid gap-3 sm:grid-cols-2",children:s.map(r=>{var y;const o=r.id===t.plan.tier,g=c?(y=r.intervals)==null?void 0:y[c]:void 0,u=n.length===0||(g==null?void 0:g.available)===!0,p=ie(r,n.length>0),d=u?null:re(r);return e.jsxs("li",{className:"rounded-xl border border-border bg-bg p-4",children:[e.jsxs("div",{className:"flex items-center justify-between gap-2",children:[e.jsx("span",{className:"font-serif text-lg text-fg",children:r.name}),o?e.jsx("span",{className:"chip",children:"Current"}):null]}),p?e.jsx("p",{className:"mt-1 text-sm text-fg-muted",children:p}):null,typeof r.vaults=="number"?e.jsxs("p",{className:"mt-0.5 text-xs text-fg-dim",children:[r.vaults," vault",r.vaults===1?"":"s"]}):null,o?null:u?e.jsx("button",{type:"button",onClick:()=>b(r.id),disabled:i!==null,className:"btn btn-primary btn-sm btn-touch mt-3 w-full",children:i===r.id?"Starting…":`Upgrade to ${r.name}`}):e.jsxs("div",{className:"mt-3",children:[e.jsxs("button",{type:"button",disabled:!0,className:"btn btn-secondary btn-sm btn-touch w-full",children:["Not available"," ",E[c].toLowerCase()]}),d?e.jsxs("p",{className:"mt-1 text-xs text-fg-dim",children:["Available from ",V(d.entry,d.interval)]}):null]})]},r.id)})}):null,h?e.jsx(B,{text:h}):null]})}function R(t){const{plan:s}=t,n=[s.label];typeof s.trial_days_left=="number"?n.push(`${s.trial_days_left} day${s.trial_days_left===1?"":"s"} left`):typeof s.price_monthly_usd=="number"&&s.price_monthly_usd>0&&n.push(`$${s.price_monthly_usd}/mo`),typeof s.vault_limit=="number"&&typeof s.vaults_used=="number"&&n.push(`${s.vaults_used} of ${s.vault_limit} vaults`);const a=S(s.storage_used_bytes??0);if(a){const l=s.storage_limit_bytes?S(s.storage_limit_bytes):null;n.push(l?`${a} of ${l}`:a)}return n.join(" · ")}function ue({vaults:t,summary:s,onReload:n}){const a=$(),[l,c]=m.useState(null),[i,x]=m.useState(null),[h,f]=m.useState(!1);async function b(u){if(!l){c(u.name),x(null);try{await H(u.name),Q(u.name),a("/")}catch(p){c(null),x(X(p,"Couldn't open that vault."))}}}async function r(){f(!0);try{await n()}finally{f(!1)}}const o=s==null?void 0:s.plan,g=o&&typeof o.vault_limit=="number"&&typeof o.vaults_used=="number"?`${o.vaults_used} of ${o.vault_limit} on your plan`:null;return e.jsxs("section",{"aria-label":"Your vaults",className:"card p-6 shadow-soft",children:[e.jsxs("div",{className:"flex flex-wrap items-baseline justify-between gap-x-4 gap-y-1",children:[e.jsx("h2",{className:"font-serif text-xl text-fg",children:"Your vaults"}),g?e.jsx("span",{className:"text-xs text-fg-muted",children:g}):null]}),t==="loading"?e.jsxs("div",{"aria-busy":"true",className:"mt-4 space-y-2.5",children:[e.jsx("div",{className:"skeleton h-9 rounded-lg"}),e.jsx("div",{className:"skeleton h-9 w-4/5 rounded-lg"})]}):t==="error"?e.jsxs("div",{className:"mt-4 text-center",children:[e.jsx("p",{className:"mb-1 font-serif text-lg text-fg",children:"Couldn't load your vaults."}),e.jsx("p",{className:"mb-5 text-sm text-fg-muted",children:"A hiccup reaching your account — nothing's lost, your vaults are safe."}),e.jsx("button",{type:"button",onClick:r,disabled:h,className:"btn btn-primary btn-touch",children:h?"Retrying…":"Retry"})]}):t.length===0?e.jsxs("div",{className:"mt-4 text-center",children:[e.jsx("p",{className:"mb-1 font-serif text-lg text-fg",children:"No vaults yet."}),e.jsx("p",{className:"mb-5 text-sm text-fg-muted",children:"Create your first — a private home for your notes, always yours to export."}),e.jsx(j,{to:"/add-vault/create",className:"btn btn-primary btn-touch",children:"Create a vault"})]}):e.jsxs(e.Fragment,{children:[e.jsx("ul",{className:"mt-3 divide-y divide-border-light",children:t.map(u=>{const p=K(u.usage),d=u.url?u.url.replace(/^https?:\/\//,""):null;return e.jsxs("li",{className:"flex items-center gap-3 py-3",children:[e.jsx(de,{name:u.name}),e.jsxs("div",{className:"min-w-0 flex-1",children:[e.jsx("p",{className:"truncate font-serif text-lg leading-snug text-fg",children:u.name}),d?e.jsx("p",{className:"mt-0.5 truncate note-id",children:d}):null,p?e.jsx("p",{className:"mt-0.5 text-xs text-fg-muted",children:p}):null]}),e.jsx("button",{type:"button",onClick:()=>b(u),disabled:l===u.name,className:"btn btn-primary btn-sm btn-touch shrink-0",children:l===u.name?"Opening…":"Open →"})]},u.name)})}),e.jsx("p",{className:"mt-3 border-t border-border-light pt-3 text-sm",children:e.jsx(j,{to:"/add-vault",className:"focus-ring font-semibold text-accent hover:underline",children:"+ Add a vault"})})]}),i?e.jsx("p",{className:"mt-4 rounded-lg border border-danger-border bg-danger-soft px-3 py-2 text-sm text-danger",children:i}):null]})}function de({name:t}){const s=(t.trim()[0]??"?").toUpperCase();return e.jsx("span",{"aria-hidden":!0,className:"grid h-9 w-9 shrink-0 place-items-center rounded-full bg-grass-soft text-sm font-semibold text-grass-ink",children:s})}function L({hasActiveVault:t}){return e.jsxs("section",{"aria-label":"Connections",className:"card p-6 shadow-soft",children:[e.jsx("h2",{className:"font-serif text-xl text-fg",children:"Connections"}),e.jsxs("div",{className:"mt-2 divide-y divide-border-light",children:[t?e.jsx(w,{to:"/connect",tone:"sky",icon:e.jsx(_,{width:18,height:18}),title:"Connect your AI",description:"Claude, ChatGPT, or any MCP client — one memory, shared."}):e.jsxs("div",{className:"-mx-2 flex items-center gap-3 px-2 py-3 opacity-60",children:[e.jsx(P,{tone:"sky",children:e.jsx(_,{width:18,height:18})}),e.jsxs("div",{className:"min-w-0 flex-1",children:[e.jsx("p",{className:"font-medium text-fg",children:"Connect your AI"}),e.jsx("p",{className:"mt-0.5 text-sm text-fg-muted",children:"Open a vault above to connect an AI to it."})]})]}),e.jsx(w,{to:"/import",tone:"grass",icon:e.jsx(D,{width:18,height:18}),title:"Import notes",description:"Bring your notes over from anywhere markdown lives."}),e.jsx(w,{to:"/export",tone:"sun",icon:e.jsx(F,{width:18,height:18}),title:"Export notes",description:"Download your vault as open Markdown — yours to keep."})]})]})}function w({to:t,tone:s,icon:n,title:a,description:l}){return e.jsxs(j,{to:t,className:"focus-ring -mx-2 flex items-center gap-3 rounded-lg px-2 py-3 hover:bg-bg-soft",children:[e.jsx(P,{tone:s,children:n}),e.jsxs("span",{className:"min-w-0 flex-1",children:[e.jsx("span",{className:"block font-medium text-fg",children:a}),e.jsx("span",{className:"mt-0.5 block text-sm text-fg-muted",children:l})]}),e.jsx("span",{"aria-hidden":!0,className:"shrink-0 text-lg text-fg-dim",children:"›"})]})}function P({tone:t,children:s}){const n=t==="grass"?"bg-grass-soft text-grass-ink":t==="sun"?"bg-sun-soft text-sun-ink":"bg-bg-soft";return e.jsx("span",{"aria-hidden":!0,className:`grid h-10 w-10 shrink-0 place-items-center rounded-full ${n}`,style:t==="sky"?{color:"var(--color-sky)"}:void 0,children:s})}function me(){const t=A(n=>n.vaults),s=Object.values(t);return e.jsxs("div",{className:"space-y-6",children:[e.jsxs("section",{className:"card p-6 shadow-soft",children:[e.jsx("h2",{className:"font-serif text-xl text-fg",children:"This device"}),e.jsx("p",{className:"mt-1 text-sm text-fg-muted",children:"You're managing the vaults connected on this device. Sign in to your account to manage your plan and hosted vaults from anywhere."}),e.jsxs("div",{className:"mt-4 flex flex-wrap gap-3",children:[e.jsx(j,{to:"/",className:"btn btn-primary btn-touch",children:"Sign in"}),e.jsx(j,{to:"/vaults",className:"btn btn-ghost btn-touch",children:s.length>0?`${s.length} connected`:"Connect a vault"})]})]}),e.jsx(L,{hasActiveVault:s.length>0})]})}export{fe as Account};
1
+ import{r as m,u as N,g as M,j as e,a as A,L as j,b as $,c as T,s as O,l as k,m as q,d as Y,I as _,e as D,f as F,h as U,i as G,o as H,k as Q,n as X,p as z,S as I,q as C,B as J}from"./index-CpyANXLa.js";import{f as K,a as S}from"./provenance-O7CbiScI.js";function fe(){const[t,s]=m.useState({kind:"loading"}),n=N(a=>a.identityEpoch);return m.useEffect(()=>{let a=!0;return(async()=>{let l;try{l=await M()}catch{a&&s({kind:"device"});return}a&&s(l.signed_in?{kind:"manager",email:l.email,username:l.username,csrf:l.csrf}:{kind:"device"})})(),()=>{a=!1}},[n]),e.jsxs("div",{className:"page-prose",children:[e.jsxs("header",{className:"mb-8",children:[e.jsx("h1",{className:"page-title",children:"Your parachute"}),e.jsx("p",{className:"mt-2 max-w-prose text-fg-muted",children:"Your account, plan, vaults, and connections — managed here."})]}),t.kind==="loading"?e.jsx("output",{"aria-live":"polite",className:"block py-10 text-center text-sm text-fg-dim",children:e.jsx("span",{className:"animate-pulse",children:"Loading your account…"})}):t.kind==="device"?e.jsx(me,{}):e.jsx(W,{email:t.email,username:t.username,csrf:t.csrf})]})}function W({email:t,username:s,csrf:n}){const a=$(),l=A(d=>d.getActiveVault()),c=N(d=>d.identityEpoch),i=T(),x=i.isPending?"loading":i.data??null,h=O(i.data),f=m.useCallback(()=>i.refetch(),[i.refetch]),[b,r]=m.useState("loading"),[o,g]=m.useState(null);m.useEffect(()=>{let d=!0;return k().then(y=>{d&&r(y.vaults)}).catch(y=>{q(y),d&&r("error")}),Y().then(y=>{d&&g(y)}),()=>{d=!1}},[c]);const u=m.useCallback(async()=>{try{const{vaults:d}=await k();r(d)}catch{r("error")}},[]);async function p(){try{await U(n)}finally{G(),a("/",{replace:!0})}}return e.jsxs("div",{className:"space-y-6",children:[e.jsx(Z,{email:t,username:s,summary:h,onSignOut:p}),e.jsx(te,{state:x,descriptor:o,onRetry:f,retrying:i.isFetching}),e.jsx(ue,{vaults:b,summary:h,onReload:u}),e.jsx(L,{hasActiveVault:!!l})]})}function Z({email:t,username:s,summary:n,onSignOut:a}){return e.jsx("section",{"aria-label":"Account",className:"card p-6 shadow-soft",children:e.jsxs("div",{className:"flex flex-wrap items-start justify-between gap-4",children:[e.jsxs("div",{className:"min-w-0",children:[e.jsx("p",{className:"eyebrow mb-1",children:"Signed in as"}),e.jsxs("div",{className:"flex flex-wrap items-center gap-x-3 gap-y-1",children:[e.jsx("p",{className:"break-words font-serif text-xl text-fg",children:t??s??"your account"}),e.jsx(ee,{summary:n})]})]}),e.jsx("button",{type:"button",onClick:a,className:"focus-ring shrink-0 text-sm text-fg-dim hover:text-accent",children:"Sign out"})]})})}function ee({summary:t}){if(!t)return null;const s=t.plan.trial_days_left;return typeof s=="number"?e.jsxs("span",{className:"chip border-transparent bg-sun-soft font-medium text-sun-ink",children:["Free trial · ",s===0?"ends today":`${s} day${s===1?"":"s"} left`]}):e.jsx("span",{className:"chip",children:t.plan.label})}function te({state:t,descriptor:s,onRetry:n,retrying:a}){return t===null||t!=="loading"&&t!=="error"&&!t.billing_enabled?null:e.jsxs("section",{"aria-label":"Plan & billing",className:"card p-6 shadow-soft",children:[e.jsx("h2",{className:"font-serif text-xl text-fg",children:"Plan & billing"}),t==="loading"?e.jsxs("div",{"aria-busy":"true",className:"mt-4 space-y-2.5",children:[e.jsx("div",{className:"skeleton h-4 w-3/5 rounded-md"}),e.jsx("div",{className:"skeleton h-4 w-2/5 rounded-md"})]}):t==="error"?e.jsxs("div",{className:"mt-4 text-center",children:[e.jsx("p",{className:"mb-1 font-serif text-lg text-fg",children:"Couldn't load your plan."}),e.jsx("p",{className:"mb-5 text-sm text-fg-muted",children:"A hiccup reaching your account — your plan hasn't changed."}),e.jsx("button",{type:"button",onClick:n,disabled:a,className:"btn btn-primary btn-touch",children:a?"Retrying…":"Retry"})]}):t.has_billing_customer?e.jsx(se,{summary:t}):e.jsx(oe,{summary:t,plans:(s==null?void 0:s.plans)??[]})]})}function se({summary:t}){const[s,n]=m.useState(!1),[a,l]=m.useState(null);async function c(){n(!0),l(null);try{const{url:i}=await z();window.location.assign(i)}catch(i){if(n(!1),i instanceof I){N.getState().markExpired();return}l("Billing isn't available right now.")}}return e.jsxs("div",{className:"mt-4",children:[e.jsx("p",{className:"text-sm text-fg-muted",children:R(t)}),e.jsx("button",{type:"button",onClick:c,disabled:s,className:"btn btn-primary btn-touch mt-4",children:s?"Opening…":"Manage plan & billing ↗"}),a?e.jsx(B,{text:a}):null]})}const v=["monthly","quarterly","yearly"],E={monthly:"Monthly",quarterly:"Quarterly",yearly:"Yearly"},ne={monthly:"/mo",quarterly:"/quarter",yearly:"/yr"},ae={monthly:1,quarterly:3,yearly:12};function le(t){var n,a;const s=new Set;for(const l of t)for(const c of v)(a=(n=l.intervals)==null?void 0:n[c])!=null&&a.available&&s.add(c);return v.filter(l=>s.has(l))}function V(t,s){return t.label?t.label:typeof t.price=="number"?`$${t.price}${ne[s]}`:null}function re(t){var s;for(const n of v){const a=(s=t.intervals)==null?void 0:s[n];if(a!=null&&a.available)return{interval:n,entry:a}}return null}function ie(t,s){if(!s||!t.intervals)return typeof t.price_month=="number"?`$${t.price_month}/mo`:null;const n=[];let a=!1,l=null;for(const i of v){const x=t.intervals[i];if(!(x!=null&&x.available))continue;i==="monthly"&&(a=!0);const h=V(x,i);if(h&&n.push(h),typeof x.price=="number"){const f=x.price/ae[i];l=l===null?f:Math.min(l,f)}}if(n.length===0)return null;const c=n.join(" · ");return a||l===null?c:`${c} — about $${Math.max(1,Math.round(l))}/mo`}function ce(t){if(t instanceof J)switch(t.code){case"already_subscribed":return"You're already subscribed — refresh to see your plan.";case"invalid_plan":case"invalid_interval":case"invalid_tier":return"That plan isn't offered on this cycle — pick another."}return"Billing isn't available right now."}function B({text:t}){return e.jsx("p",{className:"mt-3 rounded-lg border border-danger-border bg-danger-soft px-3 py-2 text-sm text-danger",children:t})}function oe({summary:t,plans:s}){const n=le(s),[a,l]=m.useState(null),c=a!==null&&n.includes(a)?a:n[0]??null,[i,x]=m.useState(null),[h,f]=m.useState(null);async function b(r){if(!i){x(r),f(null);try{const{url:o}=c?await C(r,c):await C(r);window.location.assign(o)}catch(o){if(x(null),o instanceof I){N.getState().markExpired();return}f(ce(o))}}}return e.jsxs("div",{className:"mt-4",children:[e.jsx("p",{className:"text-sm text-fg-muted",children:R(t)}),c&&n.length>1?e.jsxs("fieldset",{className:"mt-4 flex flex-wrap items-center gap-1.5",children:[e.jsx("legend",{className:"sr-only",children:"Billing interval"}),n.map(r=>{const o=r===c;return e.jsx("button",{type:"button",onClick:()=>l(r),"aria-pressed":o,className:`chip focus-ring ${o?"chip-tag-active font-medium":"chip-tag"}`,children:E[r]},r)})]}):null,s.length>0?e.jsx("ul",{className:"mt-4 grid gap-3 sm:grid-cols-2",children:s.map(r=>{var y;const o=r.id===t.plan.tier,g=c?(y=r.intervals)==null?void 0:y[c]:void 0,u=n.length===0||(g==null?void 0:g.available)===!0,p=ie(r,n.length>0),d=u?null:re(r);return e.jsxs("li",{className:"rounded-xl border border-border bg-bg p-4",children:[e.jsxs("div",{className:"flex items-center justify-between gap-2",children:[e.jsx("span",{className:"font-serif text-lg text-fg",children:r.name}),o?e.jsx("span",{className:"chip",children:"Current"}):null]}),p?e.jsx("p",{className:"mt-1 text-sm text-fg-muted",children:p}):null,typeof r.vaults=="number"?e.jsxs("p",{className:"mt-0.5 text-xs text-fg-dim",children:[r.vaults," vault",r.vaults===1?"":"s"]}):null,o?null:u?e.jsx("button",{type:"button",onClick:()=>b(r.id),disabled:i!==null,className:"btn btn-primary btn-sm btn-touch mt-3 w-full",children:i===r.id?"Starting…":`Upgrade to ${r.name}`}):e.jsxs("div",{className:"mt-3",children:[e.jsxs("button",{type:"button",disabled:!0,className:"btn btn-secondary btn-sm btn-touch w-full",children:["Not available"," ",E[c].toLowerCase()]}),d?e.jsxs("p",{className:"mt-1 text-xs text-fg-dim",children:["Available from ",V(d.entry,d.interval)]}):null]})]},r.id)})}):null,h?e.jsx(B,{text:h}):null]})}function R(t){const{plan:s}=t,n=[s.label];typeof s.trial_days_left=="number"?n.push(`${s.trial_days_left} day${s.trial_days_left===1?"":"s"} left`):typeof s.price_monthly_usd=="number"&&s.price_monthly_usd>0&&n.push(`$${s.price_monthly_usd}/mo`),typeof s.vault_limit=="number"&&typeof s.vaults_used=="number"&&n.push(`${s.vaults_used} of ${s.vault_limit} vaults`);const a=S(s.storage_used_bytes??0);if(a){const l=s.storage_limit_bytes?S(s.storage_limit_bytes):null;n.push(l?`${a} of ${l}`:a)}return n.join(" · ")}function ue({vaults:t,summary:s,onReload:n}){const a=$(),[l,c]=m.useState(null),[i,x]=m.useState(null),[h,f]=m.useState(!1);async function b(u){if(!l){c(u.name),x(null);try{await H(u.name),Q(u.name),a("/")}catch(p){c(null),x(X(p,"Couldn't open that vault."))}}}async function r(){f(!0);try{await n()}finally{f(!1)}}const o=s==null?void 0:s.plan,g=o&&typeof o.vault_limit=="number"&&typeof o.vaults_used=="number"?`${o.vaults_used} of ${o.vault_limit} on your plan`:null;return e.jsxs("section",{"aria-label":"Your vaults",className:"card p-6 shadow-soft",children:[e.jsxs("div",{className:"flex flex-wrap items-baseline justify-between gap-x-4 gap-y-1",children:[e.jsx("h2",{className:"font-serif text-xl text-fg",children:"Your vaults"}),g?e.jsx("span",{className:"text-xs text-fg-muted",children:g}):null]}),t==="loading"?e.jsxs("div",{"aria-busy":"true",className:"mt-4 space-y-2.5",children:[e.jsx("div",{className:"skeleton h-9 rounded-lg"}),e.jsx("div",{className:"skeleton h-9 w-4/5 rounded-lg"})]}):t==="error"?e.jsxs("div",{className:"mt-4 text-center",children:[e.jsx("p",{className:"mb-1 font-serif text-lg text-fg",children:"Couldn't load your vaults."}),e.jsx("p",{className:"mb-5 text-sm text-fg-muted",children:"A hiccup reaching your account — nothing's lost, your vaults are safe."}),e.jsx("button",{type:"button",onClick:r,disabled:h,className:"btn btn-primary btn-touch",children:h?"Retrying…":"Retry"})]}):t.length===0?e.jsxs("div",{className:"mt-4 text-center",children:[e.jsx("p",{className:"mb-1 font-serif text-lg text-fg",children:"No vaults yet."}),e.jsx("p",{className:"mb-5 text-sm text-fg-muted",children:"Create your first — a private home for your notes, always yours to export."}),e.jsx(j,{to:"/add-vault/create",className:"btn btn-primary btn-touch",children:"Create a vault"})]}):e.jsxs(e.Fragment,{children:[e.jsx("ul",{className:"mt-3 divide-y divide-border-light",children:t.map(u=>{const p=K(u.usage),d=u.url?u.url.replace(/^https?:\/\//,""):null;return e.jsxs("li",{className:"flex items-center gap-3 py-3",children:[e.jsx(de,{name:u.name}),e.jsxs("div",{className:"min-w-0 flex-1",children:[e.jsx("p",{className:"truncate font-serif text-lg leading-snug text-fg",children:u.name}),d?e.jsx("p",{className:"mt-0.5 truncate note-id",children:d}):null,p?e.jsx("p",{className:"mt-0.5 text-xs text-fg-muted",children:p}):null]}),e.jsx("button",{type:"button",onClick:()=>b(u),disabled:l===u.name,className:"btn btn-primary btn-sm btn-touch shrink-0",children:l===u.name?"Opening…":"Open →"})]},u.name)})}),e.jsx("p",{className:"mt-3 border-t border-border-light pt-3 text-sm",children:e.jsx(j,{to:"/add-vault",className:"focus-ring font-semibold text-accent hover:underline",children:"+ Add a vault"})})]}),i?e.jsx("p",{className:"mt-4 rounded-lg border border-danger-border bg-danger-soft px-3 py-2 text-sm text-danger",children:i}):null]})}function de({name:t}){const s=(t.trim()[0]??"?").toUpperCase();return e.jsx("span",{"aria-hidden":!0,className:"grid h-9 w-9 shrink-0 place-items-center rounded-full bg-grass-soft text-sm font-semibold text-grass-ink",children:s})}function L({hasActiveVault:t}){return e.jsxs("section",{"aria-label":"Connections",className:"card p-6 shadow-soft",children:[e.jsx("h2",{className:"font-serif text-xl text-fg",children:"Connections"}),e.jsxs("div",{className:"mt-2 divide-y divide-border-light",children:[t?e.jsx(w,{to:"/connect",tone:"sky",icon:e.jsx(_,{width:18,height:18}),title:"Connect your AI",description:"Claude, ChatGPT, or any MCP client — one memory, shared."}):e.jsxs("div",{className:"-mx-2 flex items-center gap-3 px-2 py-3 opacity-60",children:[e.jsx(P,{tone:"sky",children:e.jsx(_,{width:18,height:18})}),e.jsxs("div",{className:"min-w-0 flex-1",children:[e.jsx("p",{className:"font-medium text-fg",children:"Connect your AI"}),e.jsx("p",{className:"mt-0.5 text-sm text-fg-muted",children:"Open a vault above to connect an AI to it."})]})]}),e.jsx(w,{to:"/import",tone:"grass",icon:e.jsx(D,{width:18,height:18}),title:"Import notes",description:"Bring your notes over from anywhere markdown lives."}),e.jsx(w,{to:"/export",tone:"sun",icon:e.jsx(F,{width:18,height:18}),title:"Export notes",description:"Download your vault as open Markdown — yours to keep."})]})]})}function w({to:t,tone:s,icon:n,title:a,description:l}){return e.jsxs(j,{to:t,className:"focus-ring -mx-2 flex items-center gap-3 rounded-lg px-2 py-3 hover:bg-bg-soft",children:[e.jsx(P,{tone:s,children:n}),e.jsxs("span",{className:"min-w-0 flex-1",children:[e.jsx("span",{className:"block font-medium text-fg",children:a}),e.jsx("span",{className:"mt-0.5 block text-sm text-fg-muted",children:l})]}),e.jsx("span",{"aria-hidden":!0,className:"shrink-0 text-lg text-fg-dim",children:"›"})]})}function P({tone:t,children:s}){const n=t==="grass"?"bg-grass-soft text-grass-ink":t==="sun"?"bg-sun-soft text-sun-ink":"bg-bg-soft";return e.jsx("span",{"aria-hidden":!0,className:`grid h-10 w-10 shrink-0 place-items-center rounded-full ${n}`,style:t==="sky"?{color:"var(--color-sky)"}:void 0,children:s})}function me(){const t=A(n=>n.vaults),s=Object.values(t);return e.jsxs("div",{className:"space-y-6",children:[e.jsxs("section",{className:"card p-6 shadow-soft",children:[e.jsx("h2",{className:"font-serif text-xl text-fg",children:"This device"}),e.jsx("p",{className:"mt-1 text-sm text-fg-muted",children:"You're managing the vaults connected on this device. Sign in to your account to manage your plan and hosted vaults from anywhere."}),e.jsxs("div",{className:"mt-4 flex flex-wrap gap-3",children:[e.jsx(j,{to:"/",className:"btn btn-primary btn-touch",children:"Sign in"}),e.jsx(j,{to:"/vaults",className:"btn btn-ghost btn-touch",children:s.length>0?`${s.length} connected`:"Connect a vault"})]})]}),e.jsx(L,{hasActiveVault:s.length>0})]})}export{fe as Account};
@@ -0,0 +1 @@
1
+ import{a as f,t as y,v as g,w as j,x as N,r as u,j as e,N as b,D as v,y as w,E as D,L as m,z as E,A as k,V as A}from"./index-CpyANXLa.js";const x=1440*60*1e3,S=5e3;function T(a,n=30,s=new Date){const i=s.getTime()-n*x,r=[];for(const t of a){const o=t.path??t.id,d=Date.parse(t.createdAt);if(Number.isFinite(d)&&d>=i&&r.push({id:`${t.id}:created`,noteId:t.id,noteName:o,kind:"created",at:t.createdAt,preview:t.preview,tags:t.tags}),t.updatedAt){const l=Date.parse(t.updatedAt);Number.isFinite(l)&&l>=i&&Number.isFinite(d)&&l-d>S&&r.push({id:`${t.id}:updated`,noteId:t.id,noteName:o,kind:"updated",at:t.updatedAt,preview:t.preview,tags:t.tags})}}return r.sort((t,o)=>Date.parse(o.at)-Date.parse(t.at)),r}const _=["today","yesterday","thisWeek","older"],B={today:"Today",yesterday:"Yesterday",thisWeek:"This week",older:"Older"};function I(a,n=new Date){const s=Date.parse(a);if(!Number.isFinite(s))return null;const i=p(n),r=p(new Date(s)),t=Math.round((i.getTime()-r.getTime())/x);return t<0||t===0?"today":t===1?"yesterday":t<7?"thisWeek":"older"}function p(a){return new Date(a.getFullYear(),a.getMonth(),a.getDate())}function C(a,n=new Date){const s={today:[],yesterday:[],thisWeek:[],older:[]};for(const i of a){const r=I(i.at,n);r&&s[r].push(i)}return s}const h=50;function O(){const a=f(c=>c.getActiveVault()),n=y(g(),-29),s=j({field:"updated_at",from:N(n),limit:v}),[i,r]=u.useState(h),t=u.useMemo(()=>s.data?T(s.data):[],[s.data]),o=u.useMemo(()=>t.slice(0,i),[t,i]),d=u.useMemo(()=>C(o),[o]),l=t.length-o.length;return a?e.jsxs("div",{className:"page-prose",children:[e.jsxs("header",{className:"mb-8",children:[e.jsx("p",{className:"eyebrow mb-1",children:"Activity"}),e.jsx("h1",{className:"page-title",children:"Recent changes"}),e.jsx("p",{className:"mt-2 text-fg-muted",children:"Last 30 days, newest first. Deletions aren't tracked yet."})]}),s.isPending?e.jsx(V,{}):s.isError?e.jsx(F,{error:s.error}):t.length===0?e.jsx(R,{}):e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"space-y-8",children:_.map(c=>d[c].length>0?e.jsx(L,{title:B[c],events:d[c]},c):null)}),l>0?e.jsx("div",{className:"mt-8 flex justify-center",children:e.jsxs("button",{type:"button",onClick:()=>r(c=>c+h),className:"btn btn-secondary btn-touch",children:["Load more (",l," remaining)"]})}):null]})]}):e.jsx(b,{to:"/",replace:!0})}function L({title:a,events:n}){return e.jsxs("section",{children:[e.jsxs("h2",{className:"eyebrow mb-3",children:[a," (",n.length,")"]}),e.jsx("ol",{className:"card shadow-soft divide-y divide-border rounded-xl",children:n.map(s=>e.jsx("li",{children:e.jsxs(m,{to:`/n/${encodeURIComponent(s.noteId)}`,className:"focus-ring block px-5 py-4 transition-colors hover:bg-bg-soft",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(M,{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:k(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.5",children:s.tags.map(i=>e.jsxs("span",{className:"chip chip-tag max-w-full break-all",children:["#",i]},i))}):null]})},s.id))})]})}function M({kind:a}){return a==="created"?e.jsx("span",{className:"chip chip-tag shrink-0",children:"Created"}):e.jsx("span",{className:"chip shrink-0",children:"Edited"})}function R(){return e.jsx(E,{title:"No activity in the last 30 days.",action:e.jsx(m,{to:"/new",className:"btn btn-primary",children:"New note"})})}function V(){return e.jsx("div",{className:"space-y-3","aria-busy":"true",children:[0,1,2,3,4].map(a=>e.jsx(w,{className:"h-16 rounded-xl"},a))})}function F({error:a}){const n=a instanceof A;return e.jsx(D,{title:n?"Session expired":"Could not load activity",message:a.message,action:n?e.jsx(m,{to:"/add",className:"btn btn-primary",children:"Reconnect vault"}):void 0})}export{O as Activity};
@@ -1 +1 @@
1
- import{y as z,b as E,r,z as I,A as g,C as V,D as A,a as F,F as H,G as q,j as e,P as B,H as D}from"./index-H6VNro-x.js";import{W as L}from"./WizardShell-B0Fjh0Vt.js";import{s as O}from"./url-QSQwrjSV.js";import"./history-Ce29a331.js";function W(s){const o=s.trim();if(!o)return null;try{return new URL(g(o)).host}catch{return null}}function J(){const[s,o]=z(),b=E(),m=s.get("url")??"",u=s.get("add")??"",f=/^https?:\/\//i.test(u),v=m||(f?u:""),i=O(s.get("redirect")),[a,y]=r.useState(v),[j,x]=r.useState(null),[R,w]=r.useState(!1),[h,N]=r.useState(!1),S=r.useRef(null),C=r.useRef(v.length>0),U=r.useRef(!1),c=I();r.useEffect(()=>{var t;(t=S.current)==null||t.focus()},[]),r.useEffect(()=>{C.current||c.status==="found"&&c.origin&&a===""&&(y(c.origin),C.current=!0)},[c.status,c.origin,a]);const p=r.useCallback(async t=>{x(null),w(!1);let l;try{l=g(t)}catch(n){x(n.message);return}N(!0);try{const{authorizeUrl:n}=await V(l,void 0,void 0,{...i?{redirect:i}:{}});window.location.assign(n)}catch(n){n instanceof A?w(!0):x(n.message),N(!1)}},[i]);r.useEffect(()=>{if(U.current||!u)return;U.current=!0;const t=new URLSearchParams(s);if(t.delete("add"),o(t,{replace:!0}),m||!f)return;let l;try{l=g(u)}catch{return}const P=F.getState().vaults[H(l)];if(P){q(P.id,{toast:!0}),b(i??"/",{replace:!0});return}p(l)},[u,f,m,i,s,o,b,p]);function k(t){t.preventDefault(),p(a)}const d=W(a);return e.jsxs(L,{escape:{kind:"back",to:"/"},children:[e.jsx(B,{size:60,className:"mx-auto mb-6 drop-in"}),e.jsx("p",{className:"eyebrow mb-3",children:"Self-hosted"}),e.jsxs("h1",{className:"hero-title mb-4",children:["Connect your ",e.jsx("span",{className:"accent-word",children:"own"})," vault."]}),e.jsx("p",{className:"mx-auto mb-8 max-w-sm text-lg leading-relaxed text-fg-muted",children:"Point Parachute at a vault running on your own server."}),e.jsxs("form",{onSubmit:k,className:"mx-auto w-full max-w-sm text-left",children:[e.jsx("label",{htmlFor:"vault-url",className:"eyebrow mb-2 block",children:"Vault address"}),e.jsx("input",{id:"vault-url",ref:S,type:"url",required:!0,placeholder:"hub.your-domain.com",value:a,onChange:t=>y(t.target.value),disabled:h,className:"input input-on-bg font-mono"}),e.jsxs("p",{className:"mt-1.5 text-xs text-fg-dim",children:["A local install lives at ",e.jsx("code",{className:"note-id",children:"http://localhost:1939"}),"."]}),R?e.jsx("div",{className:"mt-3",children:e.jsx(D,{})}):null,j?e.jsx("p",{className:"mt-3 rounded-xl border border-danger-border bg-danger-soft px-3 py-2 text-sm text-danger",children:j}):null,d?e.jsxs("div",{className:"mt-5 rounded-2xl border border-sun bg-sun-soft px-4 py-3 text-left font-round text-sm leading-relaxed text-sun-ink",children:["Next, ",e.jsx("b",{className:"font-semibold text-fg",children:d})," — your server, not ours — will ask you to sign in and approve this app. Then you land right back here."]}):null,e.jsx("button",{type:"submit",disabled:h||!a,className:"btn btn-primary btn-lg mt-5 w-full justify-center rounded-full shadow-soft",children:h?"Continuing…":d?`Continue to ${d} →`:"Continue"})]})]})}export{J as AddVault};
1
+ import{C as E,b as I,r,F as z,G as g,H as V,J as F,a as H,K as A,M as O,j as e,P as q,O as B}from"./index-CpyANXLa.js";import{W as L}from"./WizardShell-BPt_HrH0.js";import{s as M}from"./url-QSQwrjSV.js";import"./history-Dwz434D-.js";function W(s){const o=s.trim();if(!o)return null;try{return new URL(g(o)).host}catch{return null}}function T(){const[s,o]=E(),b=I(),m=s.get("url")??"",u=s.get("add")??"",f=/^https?:\/\//i.test(u),v=m||(f?u:""),i=M(s.get("redirect")),[a,j]=r.useState(v),[y,x]=r.useState(null),[R,w]=r.useState(!1),[h,N]=r.useState(!1),S=r.useRef(null),C=r.useRef(v.length>0),U=r.useRef(!1),c=z();r.useEffect(()=>{var t;(t=S.current)==null||t.focus()},[]),r.useEffect(()=>{C.current||c.status==="found"&&c.origin&&a===""&&(j(c.origin),C.current=!0)},[c.status,c.origin,a]);const p=r.useCallback(async t=>{x(null),w(!1);let l;try{l=g(t)}catch(n){x(n.message);return}N(!0);try{const{authorizeUrl:n}=await V(l,void 0,void 0,{...i?{redirect:i}:{}});window.location.assign(n)}catch(n){n instanceof F?w(!0):x(n.message),N(!1)}},[i]);r.useEffect(()=>{if(U.current||!u)return;U.current=!0;const t=new URLSearchParams(s);if(t.delete("add"),o(t,{replace:!0}),m||!f)return;let l;try{l=g(u)}catch{return}const P=H.getState().vaults[A(l)];if(P){O(P.id,{toast:!0}),b(i??"/",{replace:!0});return}p(l)},[u,f,m,i,s,o,b,p]);function k(t){t.preventDefault(),p(a)}const d=W(a);return e.jsxs(L,{escape:{kind:"back",to:"/"},children:[e.jsx(q,{size:60,className:"mx-auto mb-6 drop-in"}),e.jsx("p",{className:"eyebrow mb-3",children:"Self-hosted"}),e.jsxs("h1",{className:"hero-title mb-4",children:["Connect your ",e.jsx("span",{className:"accent-word",children:"own"})," vault."]}),e.jsx("p",{className:"mx-auto mb-8 max-w-sm text-lg leading-relaxed text-fg-muted",children:"Point Parachute at a vault running on your own server."}),e.jsxs("form",{onSubmit:k,className:"mx-auto w-full max-w-sm text-left",children:[e.jsx("label",{htmlFor:"vault-url",className:"eyebrow mb-2 block",children:"Vault address"}),e.jsx("input",{id:"vault-url",ref:S,type:"url",required:!0,placeholder:"hub.your-domain.com",value:a,onChange:t=>j(t.target.value),disabled:h,className:"input input-on-bg font-mono"}),e.jsxs("p",{className:"mt-1.5 text-xs text-fg-dim",children:["A local install lives at ",e.jsx("code",{className:"note-id",children:"http://localhost:1939"}),"."]}),R?e.jsx("div",{className:"mt-3",children:e.jsx(B,{})}):null,y?e.jsx("p",{className:"mt-3 rounded-xl border border-danger-border bg-danger-soft px-3 py-2 text-sm text-danger",children:y}):null,d?e.jsxs("div",{className:"mt-5 rounded-2xl border border-sun bg-sun-soft px-4 py-3 text-left font-round text-sm leading-relaxed text-sun-ink",children:["Next, ",e.jsx("b",{className:"font-semibold text-fg",children:d})," — your server, not ours — will ask you to sign in and approve this app. Then you land right back here."]}):null,e.jsx("button",{type:"submit",disabled:h||!a,className:"btn btn-primary btn-lg mt-5 w-full justify-center rounded-full shadow-soft",children:h?"Continuing…":d?`Continue to ${d} →`:"Continue"})]})]})}export{T as AddVault};
@@ -1 +1 @@
1
- import{b as o,J as c,a as d,j as e,P as m}from"./index-H6VNro-x.js";import{W as x}from"./WizardShell-B0Fjh0Vt.js";import"./history-Ce29a331.js";function f(){const s=o(),a=c(),t=d(l=>l.getActiveVault()),n=null,r=t?"/vaults":"/";return e.jsxs(x,{wide:!0,escape:{kind:"back",to:r},children:[e.jsx(m,{size:56,className:"mx-auto mb-6"}),a?e.jsxs("p",{className:"chip mb-4 inline-flex border-grass/40 bg-grass-soft text-grass-ink",children:[e.jsx("span",{"aria-hidden":"true",children:"✓"})," Signed in as ",a]}):null,e.jsx("p",{className:"eyebrow mb-3",children:"Add a vault"}),e.jsxs("h1",{className:"hero-title mb-8",style:{fontSize:"clamp(1.8rem, 4vw, 2.4rem)"},children:["Bring another ",e.jsx("span",{className:"accent-word",children:"vault"})," in."]}),e.jsxs("div",{className:"grid gap-4 sm:grid-cols-3",children:[e.jsx(i,{icon:"📂",verb:"Open",description:"One of your account's vaults not on this device.",onClick:()=>s("/welcome?pick=1")}),e.jsx(i,{icon:"✦",verb:"Create",description:t?e.jsxs(e.Fragment,{children:["Brand-new and empty — separate from"," ",e.jsx("b",{className:"font-semibold text-fg",children:t.name}),"."]}):"Brand-new and empty — its own private space, nothing shared.",foot:n,onClick:()=>s("/add-vault/create")}),e.jsx(i,{icon:"⌂",verb:"Connect",description:"A self-hosted vault on your own server.",onClick:()=>s("/add")})]})]})}function i({icon:s,verb:a,description:t,foot:n,onClick:r}){return e.jsxs("button",{type:"button",onClick:r,"aria-label":a,className:"tile flex flex-col items-center gap-2 p-6 text-center",children:[e.jsx("span",{"aria-hidden":"true",className:"text-xl",children:s}),e.jsx("span",{"aria-hidden":"true",className:"font-round text-base font-bold text-fg",children:a}),e.jsx("span",{className:"font-round text-xs leading-relaxed text-fg-muted",children:t}),n?e.jsx("span",{className:"mt-1 font-round text-xs text-fg-dim",children:n}):null]})}export{f as AddVaultChooser};
1
+ import{b as o,Q as c,a as d,j as e,P as m}from"./index-CpyANXLa.js";import{W as x}from"./WizardShell-BPt_HrH0.js";import"./history-Dwz434D-.js";function f(){const s=o(),a=c(),t=d(l=>l.getActiveVault()),n=null,r=t?"/vaults":"/";return e.jsxs(x,{wide:!0,escape:{kind:"back",to:r},children:[e.jsx(m,{size:56,className:"mx-auto mb-6"}),a?e.jsxs("p",{className:"chip mb-4 inline-flex border-grass/40 bg-grass-soft text-grass-ink",children:[e.jsx("span",{"aria-hidden":"true",children:"✓"})," Signed in as ",a]}):null,e.jsx("p",{className:"eyebrow mb-3",children:"Add a vault"}),e.jsxs("h1",{className:"hero-title mb-8",style:{fontSize:"clamp(1.8rem, 4vw, 2.4rem)"},children:["Bring another ",e.jsx("span",{className:"accent-word",children:"vault"})," in."]}),e.jsxs("div",{className:"grid gap-4 sm:grid-cols-3",children:[e.jsx(i,{icon:"📂",verb:"Open",description:"One of your account's vaults not on this device.",onClick:()=>s("/welcome?pick=1")}),e.jsx(i,{icon:"✦",verb:"Create",description:t?e.jsxs(e.Fragment,{children:["Brand-new and empty — separate from"," ",e.jsx("b",{className:"font-semibold text-fg",children:t.name}),"."]}):"Brand-new and empty — its own private space, nothing shared.",foot:n,onClick:()=>s("/add-vault/create")}),e.jsx(i,{icon:"⌂",verb:"Connect",description:"A self-hosted vault on your own server.",onClick:()=>s("/add")})]})]})}function i({icon:s,verb:a,description:t,foot:n,onClick:r}){return e.jsxs("button",{type:"button",onClick:r,"aria-label":a,className:"tile flex flex-col items-center gap-2 p-6 text-center",children:[e.jsx("span",{"aria-hidden":"true",className:"text-xl",children:s}),e.jsx("span",{"aria-hidden":"true",className:"font-round text-base font-bold text-fg",children:a}),e.jsx("span",{className:"font-round text-xs leading-relaxed text-fg-muted",children:t}),n?e.jsx("span",{className:"mt-1 font-round text-xs text-fg-dim",children:n}):null]})}export{f as AddVaultChooser};
@@ -1 +1 @@
1
- import{b as j,y as N,r as n,K as k,n as v,j as e,N as S,P as b,J as C,a as E,d as T,o as A,k as V}from"./index-H6VNro-x.js";import{W as g}from"./WizardShell-B0Fjh0Vt.js";import"./history-Ce29a331.js";const h=["Name","Making it","Ready"];function y(t){return t.toLowerCase().replace(/[^a-z0-9-]/g,"")}function M(){const t=j(),[o]=N(),a=o.get("first")==="1",[s,l]=n.useState({kind:"naming"}),i=n.useRef(null);return n.useEffect(()=>{if(s.kind!=="creating"||i.current===s.name)return;i.current=s.name;const{name:r}=s;(async()=>{try{const c=await k(r),d=new URLSearchParams({vault:c});a&&d.set("first","1"),t(`/add-vault/ready?${d.toString()}`,{replace:!0})}catch(c){i.current=null,l({kind:"naming",attemptedName:r,error:v(c,"Couldn't create your vault. Try a different name.")})}})()},[s,t,a]),s.kind==="creating"?e.jsx(g,{escape:{kind:"none"},progress:{labels:h,current:1},children:e.jsx(P,{name:s.name})}):e.jsx(g,{escape:{kind:"back",to:a?"/":"/add-vault"},progress:{labels:h,current:0},children:e.jsx(L,{first:a,initialName:s.attemptedName,error:s.error,onCreate:r=>l({kind:"creating",name:r})})})}function R({email:t}){return t?e.jsxs("p",{className:"chip mb-4 inline-flex border-grass/40 bg-grass-soft text-grass-ink",children:[e.jsx("span",{"aria-hidden":"true",children:"✓"})," Signed in as ",t]}):null}function L({first:t,initialName:o,error:a,onCreate:s}){const[l,i]=n.useState(()=>y(o??"")),[r,c]=n.useState(null),d=C(),p=E(m=>{var x;return((x=m.getActiveVault())==null?void 0:x.name)??null}),u=l.trim();n.useEffect(()=>{let m=!0;return T().then(x=>{m&&c((x==null?void 0:x.vault_url_template)??null)}),()=>{m=!1}},[]);function w(m){m.preventDefault(),u&&s(u)}return e.jsxs(e.Fragment,{children:[e.jsx(b,{size:60,className:"mx-auto mb-6 drop-in"}),e.jsx(R,{email:d}),e.jsx("p",{className:"eyebrow mb-3",children:t?"Account created ✓":"Adding a vault"}),e.jsxs("h1",{className:"hero-title mb-4",children:[t?"Let's make your first":"Let's make your new"," ",e.jsx("span",{className:"accent-word",children:"vault."})]}),e.jsx("p",{className:"mx-auto mb-8 max-w-md text-lg leading-relaxed text-fg-muted",children:t?e.jsxs(e.Fragment,{children:["A vault is the private home for your notes — any AI you invite can read it, always yours to export. ",e.jsx("b",{className:"font-semibold text-fg",children:"This creates a brand-new, empty one."})]}):e.jsxs(e.Fragment,{children:["This one's separate from"," ",e.jsx("b",{className:"font-semibold text-fg",children:p??"your other vault"})," — its own private space, nothing shared."]})}),e.jsxs("form",{onSubmit:w,children:[e.jsx("input",{autoFocus:!0,value:l,onChange:m=>i(y(m.target.value)),placeholder:"moss",autoComplete:"off",spellCheck:!1,"aria-label":"Vault name",className:"mx-auto mb-2 block w-full max-w-sm border-0 border-b-2 border-border bg-transparent pb-2 text-center font-serif text-3xl text-fg outline-none transition-colors focus:border-accent-light"}),e.jsx("p",{className:"mb-6 min-h-6 font-round text-sm text-fg-muted",children:u?e.jsxs("span",{children:["Your vault:"," ",e.jsx("b",{className:"rounded-md bg-grass-soft px-2 py-0.5 text-grass-ink",children:u}),r?e.jsxs(e.Fragment,{children:[" — it will live at ",e.jsx("span",{className:"font-mono text-xs",children:r.replace("{name}",u)})]}):null]}):"Letters, numbers, hyphens — pick a word you like."}),e.jsxs("p",{className:"mx-auto mb-8 max-w-sm font-round text-xs text-fg-dim",children:[e.jsx("span",{className:"font-semibold text-fg-muted",children:"The address is permanent"}),", so pick a word you like. Letters, numbers, hyphens."]}),a?e.jsx("p",{className:"mx-auto mb-6 max-w-sm rounded-lg border border-danger-border bg-danger-soft px-3 py-2 text-sm text-danger",children:a}):null,e.jsx("button",{type:"submit",disabled:!u,className:"btn btn-primary btn-lg justify-center rounded-full px-6 shadow-soft",children:u?`Create ${u} →`:"Create →"})]})]})}const f=["Setting up your vault…","Preparing your keys…","Almost there…"];function z(){const[t,o]=n.useState(0);return n.useEffect(()=>{if(t>=f.length-1)return;const a=setTimeout(()=>o(s=>Math.min(s+1,f.length-1)),650);return()=>clearTimeout(a)},[t]),e.jsx("output",{"aria-live":"polite",className:"font-round text-sm text-fg-muted",children:f[t]})}function P({name:t}){return e.jsxs(e.Fragment,{children:[e.jsx(b,{size:96,className:"mx-auto mb-6 animate-pulse"}),e.jsxs("h1",{className:"hero-title mb-3",style:{fontSize:"clamp(1.6rem, 3.5vw, 1.9rem)"},children:["Making a place for ",e.jsxs("span",{className:"accent-word",children:[t,"…"]})]}),e.jsx(z,{})]})}function _(){const t=j(),[o]=N(),a=o.get("vault")??"",s=o.get("first")==="1",[l,i]=n.useState(!1),[r,c]=n.useState(null);if(!a)return e.jsx(S,{to:"/add-vault",replace:!0});async function d(){if(!l){i(!0),c(null);try{await A(a),V(a),t("/")}catch(p){i(!1),c(v(p,"Couldn't open your vault. Try again."))}}}return e.jsxs(g,{escape:s?{kind:"none"}:{kind:"maybe-later",to:"/"},progress:{labels:h,current:2},children:[e.jsx(b,{size:90,className:"mx-auto mb-6 fade-up"}),e.jsx("p",{className:"eyebrow mb-3",children:"Ready"}),e.jsxs("h1",{className:"hero-title mb-3",style:{fontSize:"clamp(1.8rem, 4vw, 2.3rem)"},children:[a," is ",e.jsx("span",{className:"accent-word",children:"ready."})]}),e.jsx("p",{className:"mx-auto mb-8 max-w-sm text-fg-muted",children:"Everything inside is yours. Open format. Export anytime."}),r?e.jsx("p",{className:"mx-auto mb-6 max-w-sm rounded-lg border border-danger-border bg-danger-soft px-3 py-2 text-sm text-danger",children:r}):null,e.jsx("button",{type:"button",onClick:d,disabled:l,className:"btn btn-primary btn-lg justify-center rounded-full px-6 shadow-soft",children:l?"Opening…":`Open ${a} →`})]})}export{M as AddVaultCreate,_ as AddVaultReady};
1
+ import{b as j,C as N,r as n,R as k,n as v,j as e,N as S,P as b,Q as C,a as E,d as T,o as A,k as R}from"./index-CpyANXLa.js";import{W as g}from"./WizardShell-BPt_HrH0.js";import"./history-Dwz434D-.js";const h=["Name","Making it","Ready"];function y(t){return t.toLowerCase().replace(/[^a-z0-9-]/g,"")}function M(){const t=j(),[o]=N(),a=o.get("first")==="1",[s,l]=n.useState({kind:"naming"}),i=n.useRef(null);return n.useEffect(()=>{if(s.kind!=="creating"||i.current===s.name)return;i.current=s.name;const{name:r}=s;(async()=>{try{const c=await k(r),d=new URLSearchParams({vault:c});a&&d.set("first","1"),t(`/add-vault/ready?${d.toString()}`,{replace:!0})}catch(c){i.current=null,l({kind:"naming",attemptedName:r,error:v(c,"Couldn't create your vault. Try a different name.")})}})()},[s,t,a]),s.kind==="creating"?e.jsx(g,{escape:{kind:"none"},progress:{labels:h,current:1},children:e.jsx(P,{name:s.name})}):e.jsx(g,{escape:{kind:"back",to:a?"/":"/add-vault"},progress:{labels:h,current:0},children:e.jsx(L,{first:a,initialName:s.attemptedName,error:s.error,onCreate:r=>l({kind:"creating",name:r})})})}function V({email:t}){return t?e.jsxs("p",{className:"chip mb-4 inline-flex border-grass/40 bg-grass-soft text-grass-ink",children:[e.jsx("span",{"aria-hidden":"true",children:"✓"})," Signed in as ",t]}):null}function L({first:t,initialName:o,error:a,onCreate:s}){const[l,i]=n.useState(()=>y(o??"")),[r,c]=n.useState(null),d=C(),p=E(m=>{var x;return((x=m.getActiveVault())==null?void 0:x.name)??null}),u=l.trim();n.useEffect(()=>{let m=!0;return T().then(x=>{m&&c((x==null?void 0:x.vault_url_template)??null)}),()=>{m=!1}},[]);function w(m){m.preventDefault(),u&&s(u)}return e.jsxs(e.Fragment,{children:[e.jsx(b,{size:60,className:"mx-auto mb-6 drop-in"}),e.jsx(V,{email:d}),e.jsx("p",{className:"eyebrow mb-3",children:t?"Account created ✓":"Adding a vault"}),e.jsxs("h1",{className:"hero-title mb-4",children:[t?"Let's make your first":"Let's make your new"," ",e.jsx("span",{className:"accent-word",children:"vault."})]}),e.jsx("p",{className:"mx-auto mb-8 max-w-md text-lg leading-relaxed text-fg-muted",children:t?e.jsxs(e.Fragment,{children:["A vault is the private home for your notes — any AI you invite can read it, always yours to export. ",e.jsx("b",{className:"font-semibold text-fg",children:"This creates a brand-new, empty one."})]}):e.jsxs(e.Fragment,{children:["This one's separate from"," ",e.jsx("b",{className:"font-semibold text-fg",children:p??"your other vault"})," — its own private space, nothing shared."]})}),e.jsxs("form",{onSubmit:w,children:[e.jsx("input",{autoFocus:!0,value:l,onChange:m=>i(y(m.target.value)),placeholder:"moss",autoComplete:"off",spellCheck:!1,"aria-label":"Vault name",className:"mx-auto mb-2 block w-full max-w-sm border-0 border-b-2 border-border bg-transparent pb-2 text-center font-serif text-3xl text-fg outline-none transition-colors focus:border-accent-light"}),e.jsx("p",{className:"mb-6 min-h-6 font-round text-sm text-fg-muted",children:u?e.jsxs("span",{children:["Your vault:"," ",e.jsx("b",{className:"rounded-md bg-grass-soft px-2 py-0.5 text-grass-ink",children:u}),r?e.jsxs(e.Fragment,{children:[" — it will live at ",e.jsx("span",{className:"font-mono text-xs",children:r.replace("{name}",u)})]}):null]}):"Letters, numbers, hyphens — pick a word you like."}),e.jsxs("p",{className:"mx-auto mb-8 max-w-sm font-round text-xs text-fg-dim",children:[e.jsx("span",{className:"font-semibold text-fg-muted",children:"The address is permanent"}),", so pick a word you like. Letters, numbers, hyphens."]}),a?e.jsx("p",{className:"mx-auto mb-6 max-w-sm rounded-lg border border-danger-border bg-danger-soft px-3 py-2 text-sm text-danger",children:a}):null,e.jsx("button",{type:"submit",disabled:!u,className:"btn btn-primary btn-lg justify-center rounded-full px-6 shadow-soft",children:u?`Create ${u} →`:"Create →"})]})]})}const f=["Setting up your vault…","Preparing your keys…","Almost there…"];function z(){const[t,o]=n.useState(0);return n.useEffect(()=>{if(t>=f.length-1)return;const a=setTimeout(()=>o(s=>Math.min(s+1,f.length-1)),650);return()=>clearTimeout(a)},[t]),e.jsx("output",{"aria-live":"polite",className:"font-round text-sm text-fg-muted",children:f[t]})}function P({name:t}){return e.jsxs(e.Fragment,{children:[e.jsx(b,{size:96,className:"mx-auto mb-6 animate-pulse"}),e.jsxs("h1",{className:"hero-title mb-3",style:{fontSize:"clamp(1.6rem, 3.5vw, 1.9rem)"},children:["Making a place for ",e.jsxs("span",{className:"accent-word",children:[t,"…"]})]}),e.jsx(z,{})]})}function _(){const t=j(),[o]=N(),a=o.get("vault")??"",s=o.get("first")==="1",[l,i]=n.useState(!1),[r,c]=n.useState(null);if(!a)return e.jsx(S,{to:"/add-vault",replace:!0});async function d(){if(!l){i(!0),c(null);try{await A(a),R(a),t("/")}catch(p){i(!1),c(v(p,"Couldn't open your vault. Try again."))}}}return e.jsxs(g,{escape:s?{kind:"none"}:{kind:"maybe-later",to:"/"},progress:{labels:h,current:2},children:[e.jsx(b,{size:90,className:"mx-auto mb-6 fade-up"}),e.jsx("p",{className:"eyebrow mb-3",children:"Ready"}),e.jsxs("h1",{className:"hero-title mb-3",style:{fontSize:"clamp(1.8rem, 4vw, 2.3rem)"},children:[a," is ",e.jsx("span",{className:"accent-word",children:"ready."})]}),e.jsx("p",{className:"mx-auto mb-8 max-w-sm text-fg-muted",children:"Everything inside is yours. Open format. Export anytime."}),r?e.jsx("p",{className:"mx-auto mb-6 max-w-sm rounded-lg border border-danger-border bg-danger-soft px-3 py-2 text-sm text-danger",children:r}):null,e.jsx("button",{type:"button",onClick:d,disabled:l,className:"btn btn-primary btn-lg justify-center rounded-full px-6 shadow-soft",children:l?"Opening…":`Open ${a} →`})]})}export{M as AddVaultCreate,_ as AddVaultReady};
@@ -0,0 +1 @@
1
+ import{a as S,C as k,T as j,U as N,v as A,r as u,W as T,w as _,X as K,j as e,N as V,Y as v,Z as i,_ as C,L as c,D as P,V as Y}from"./index-CpyANXLa.js";const I=["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],g=5;function W(){const s=S(t=>t.getActiveVault()),[n]=k(),m=n.get("month"),r=j(m)??j(N()),x=A(),d=u.useMemo(()=>T(r.year,r.month),[r.year,r.month]),$=u.useMemo(()=>{const t=d[0],a=d[d.length-1];return{from:t.toISOString(),to:new Date(a.getFullYear(),a.getMonth(),a.getDate()+1).toISOString()}},[d]),o=_({field:"created_at",...$,limit:P}),M=u.useMemo(()=>{const t=new Map;if(!o.data)return t;for(const a of o.data){const l=K(a.createdAt);l&&t.set(l,(t.get(l)??0)+1)}return t},[o.data]);if(!s)return e.jsx(V,{to:"/",replace:!0});const p=v(r.year,r.month,-1),b=v(r.year,r.month,1),f=`${p.year}-${i(p.month)}`,y=`${b.year}-${i(b.month)}`,D=N(),w=`${r.year}-${i(r.month)}`===D;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(c,{to:`/calendar?month=${f}`,className:"rounded-lg border border-border bg-card px-3 py-1.5 text-fg-muted hover:text-accent","aria-label":"Previous month",children:["← ",f]}),w?null:e.jsx(c,{to:"/calendar",className:"rounded-lg border border-border bg-card px-3 py-1.5 text-fg-muted hover:text-accent",children:"This month"}),e.jsxs(c,{to:`/calendar?month=${y}`,className:"rounded-lg border border-border bg-card px-3 py-1.5 text-fg-muted hover:text-accent","aria-label":"Next month",children:[y," →"]}),e.jsx(c,{to:`/today?date=${x}`,className:"rounded-lg border border-border bg-card px-3 py-1.5 text-fg-muted hover:text-accent",children:"Today"})]})]}),o.isError?e.jsx(L,{error:o.error}):e.jsxs("div",{className:"rounded-md border border-border bg-card","aria-busy":o.isPending,children:[e.jsx("div",{className:"grid grid-cols-7 border-b border-border text-xs uppercase tracking-wider text-fg-dim",children:I.map(t=>e.jsx("div",{className:"px-2 py-2 text-center",children:t},t))}),e.jsx("div",{className:"grid grid-cols-7",children:d.map(t=>{const a=`${t.getFullYear()}-${i(t.getMonth()+1)}-${i(t.getDate())}`,l=t.getMonth()+1===r.month,h=M.get(a)??0,E=a===x;return e.jsxs(c,{to:`/today?date=${a}`,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 ${l?"":"opacity-40"}`,"aria-label":`${a} — ${h} notes`,children:[e.jsx("span",{className:`mb-1 inline-flex h-6 w-6 items-center justify-center rounded-full tabular-nums ${E?"bg-accent text-(--color-on-accent)":"text-fg"}`,children:t.getDate()}),h>0?e.jsx(F,{count:h}):e.jsx("span",{className:"sr-only",children:"no notes"})]},a)})})]}),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:s}){const n=Math.min(s,g),m=s>g?s-g:0;return e.jsxs("span",{className:"flex flex-wrap items-center gap-0.5",children:[Array.from({length:n}).map((r,x)=>e.jsx("span",{className:"h-1.5 w-1.5 rounded-full bg-accent","aria-hidden":"true"},x)),m>0?e.jsxs("span",{className:"ml-0.5 text-[10px] text-fg-dim",children:["+",m]}):null]})}function L({error:s}){const n=s 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:n?"Session expired":"Could not load notes"}),e.jsx("p",{className:"mb-4 text-sm text-fg-muted",children:s.message}),n?e.jsx(c,{to:"/add",className:"inline-block rounded-lg bg-accent px-4 py-2 text-sm font-medium text-(--color-on-accent) hover:bg-accent-hover",children:"Reconnect vault"}):null]})}export{W as Calendar};
@@ -1 +1 @@
1
- import{b as S,r as s,J as E,j as e,N as R,P as I,g as f,bB as L,bC as M,bD as O}from"./index-H6VNro-x.js";import{W}from"./WizardShell-B0Fjh0Vt.js";import"./history-Ce29a331.js";const h="/welcome",_=3e3,N="That code didn't work — check it and try again.";function T(){const c=S(),[a,v]=s.useState(()=>E()??""),[r,i]=s.useState("idle"),[g,j]=s.useState(""),[w,o]=s.useState(""),[l,d]=s.useState(null),[b,p]=s.useState(!1),u=s.useRef(!1),m=s.useRef(!1);if(s.useEffect(()=>{let t=!1;const x=setInterval(async()=>{try{const k=await f();!t&&k.signed_in&&c(h,{replace:!0})}catch{}},_);return()=>{t=!0,clearInterval(x)}},[c]),!a)return e.jsx(R,{to:"/",replace:!0});async function y(t=a){if(!u.current){u.current=!0;try{const n=await f();await L(t,n.csrf,h),t!==a&&(M(t),v(t)),i("resent")}catch{i("idle")}finally{u.current=!1}}}async function C(t){const n=t.replace(/\D/g,"").slice(0,6);if(o(n),d(null),!(n.length<6||m.current)){m.current=!0,p(!0);try{const x=await f();if(await O(a,n,x.csrf)){c(h,{replace:!0});return}d(N),o("")}catch{d(N),o("")}finally{m.current=!1,p(!1)}}}return e.jsxs(W,{escape:{kind:"back",to:"/",label:"← Back to sign in"},children:[e.jsx(I,{size:56,className:"mx-auto mb-6"}),e.jsx("p",{className:"eyebrow mb-3",children:"Check your email"}),e.jsxs("h1",{className:"hero-title mb-3",style:{fontSize:"clamp(1.6rem, 3.5vw, 2.1rem)"},children:["We sent a sign-in link to ",e.jsx("span",{className:"accent-word",children:a})]}),e.jsx("p",{className:"text-fg-muted",children:"Works once, expires in 10 min."}),e.jsx("p",{className:"mx-auto mt-3 mb-6 max-w-sm font-round text-sm text-fg-muted",children:"New here? That same link creates your account — the email says which."}),e.jsxs("div",{className:"flex flex-wrap items-center justify-center gap-4",children:[e.jsx("button",{type:"button",onClick:()=>y(),className:"btn btn-secondary btn-touch rounded-full",children:"Resend the link"}),e.jsx("button",{type:"button",onClick:()=>i(r==="code"?"idle":"code"),className:"font-round text-sm font-semibold text-link hover:underline",style:{color:"var(--color-sky)"},children:r==="code"?"Hide the code field":"Or type the code from the email"}),e.jsx("button",{type:"button",onClick:()=>i("changeemail"),className:"font-round text-sm font-semibold text-link hover:underline",style:{color:"var(--color-sky)"},children:"Use a different email"})]}),r==="resent"?e.jsx("p",{className:"mx-auto mt-4 max-w-sm rounded-xl border border-grass bg-grass-soft px-4 py-3 text-sm text-grass-ink",children:"✓ Sent again — check your inbox."}):null,r==="code"?e.jsxs("div",{className:"mx-auto mt-4 max-w-xs",children:[e.jsx("label",{htmlFor:"signin-code",className:"mb-2 block font-round text-sm text-fg-muted",children:"6-digit code"}),e.jsx("input",{id:"signin-code",value:w,onChange:t=>{C(t.target.value)},inputMode:"numeric",autoComplete:"one-time-code",pattern:"[0-9]*",placeholder:"123456",disabled:b,"aria-invalid":l?!0:void 0,"aria-describedby":l?"signin-code-error":void 0,autoFocus:!0,className:"input w-full text-center text-2xl tracking-[0.4em]"}),e.jsx("output",{"aria-live":"polite",className:"mt-2 block text-center text-xs text-fg-dim",children:b?"Checking…":" "}),l?e.jsx("p",{id:"signin-code-error",role:"alert",className:"rounded-lg border border-danger-border bg-danger-soft px-3 py-2 text-center text-sm text-danger",children:l}):null]}):null,r==="changeemail"?e.jsxs("div",{className:"mx-auto mt-4 max-w-sm",children:[e.jsxs("div",{className:"flex gap-2",children:[e.jsx("input",{value:g,onChange:t=>j(t.target.value),placeholder:"you@example.com","aria-label":"Email address",type:"email",className:"input"}),e.jsx("button",{type:"button",onClick:()=>{const t=g.trim();/.+@.+\..+/.test(t)&&y(t)},className:"btn btn-primary btn-touch shrink-0 rounded-full",children:"Send link"})]}),e.jsx("button",{type:"button",onClick:()=>i("idle"),className:"mt-2 font-round text-sm text-fg-dim hover:text-accent",children:"Cancel"})]}):null]})}export{T as CheckEmail};
1
+ import{b as S,r as s,Q as E,j as e,N as R,P as I,g as f,bE as L,bF as M,bG as O}from"./index-CpyANXLa.js";import{W}from"./WizardShell-BPt_HrH0.js";import"./history-Dwz434D-.js";const h="/welcome",_=3e3,N="That code didn't work — check it and try again.";function T(){const c=S(),[a,v]=s.useState(()=>E()??""),[r,i]=s.useState("idle"),[g,j]=s.useState(""),[w,o]=s.useState(""),[l,d]=s.useState(null),[b,p]=s.useState(!1),u=s.useRef(!1),m=s.useRef(!1);if(s.useEffect(()=>{let t=!1;const x=setInterval(async()=>{try{const k=await f();!t&&k.signed_in&&c(h,{replace:!0})}catch{}},_);return()=>{t=!0,clearInterval(x)}},[c]),!a)return e.jsx(R,{to:"/",replace:!0});async function y(t=a){if(!u.current){u.current=!0;try{const n=await f();await L(t,n.csrf,h),t!==a&&(M(t),v(t)),i("resent")}catch{i("idle")}finally{u.current=!1}}}async function C(t){const n=t.replace(/\D/g,"").slice(0,6);if(o(n),d(null),!(n.length<6||m.current)){m.current=!0,p(!0);try{const x=await f();if(await O(a,n,x.csrf)){c(h,{replace:!0});return}d(N),o("")}catch{d(N),o("")}finally{m.current=!1,p(!1)}}}return e.jsxs(W,{escape:{kind:"back",to:"/",label:"← Back to sign in"},children:[e.jsx(I,{size:56,className:"mx-auto mb-6"}),e.jsx("p",{className:"eyebrow mb-3",children:"Check your email"}),e.jsxs("h1",{className:"hero-title mb-3",style:{fontSize:"clamp(1.6rem, 3.5vw, 2.1rem)"},children:["We sent a sign-in link to ",e.jsx("span",{className:"accent-word",children:a})]}),e.jsx("p",{className:"text-fg-muted",children:"Works once, expires in 10 min."}),e.jsx("p",{className:"mx-auto mt-3 mb-6 max-w-sm font-round text-sm text-fg-muted",children:"New here? That same link creates your account — the email says which."}),e.jsxs("div",{className:"flex flex-wrap items-center justify-center gap-4",children:[e.jsx("button",{type:"button",onClick:()=>y(),className:"btn btn-secondary btn-touch rounded-full",children:"Resend the link"}),e.jsx("button",{type:"button",onClick:()=>i(r==="code"?"idle":"code"),className:"font-round text-sm font-semibold text-link hover:underline",style:{color:"var(--color-sky)"},children:r==="code"?"Hide the code field":"Or type the code from the email"}),e.jsx("button",{type:"button",onClick:()=>i("changeemail"),className:"font-round text-sm font-semibold text-link hover:underline",style:{color:"var(--color-sky)"},children:"Use a different email"})]}),r==="resent"?e.jsx("p",{className:"mx-auto mt-4 max-w-sm rounded-xl border border-grass bg-grass-soft px-4 py-3 text-sm text-grass-ink",children:"✓ Sent again — check your inbox."}):null,r==="code"?e.jsxs("div",{className:"mx-auto mt-4 max-w-xs",children:[e.jsx("label",{htmlFor:"signin-code",className:"mb-2 block font-round text-sm text-fg-muted",children:"6-digit code"}),e.jsx("input",{id:"signin-code",value:w,onChange:t=>{C(t.target.value)},inputMode:"numeric",autoComplete:"one-time-code",pattern:"[0-9]*",placeholder:"123456",disabled:b,"aria-invalid":l?!0:void 0,"aria-describedby":l?"signin-code-error":void 0,autoFocus:!0,className:"input w-full text-center text-2xl tracking-[0.4em]"}),e.jsx("output",{"aria-live":"polite",className:"mt-2 block text-center text-xs text-fg-dim",children:b?"Checking…":" "}),l?e.jsx("p",{id:"signin-code-error",role:"alert",className:"rounded-lg border border-danger-border bg-danger-soft px-3 py-2 text-center text-sm text-danger",children:l}):null]}):null,r==="changeemail"?e.jsxs("div",{className:"mx-auto mt-4 max-w-sm",children:[e.jsxs("div",{className:"flex gap-2",children:[e.jsx("input",{value:g,onChange:t=>j(t.target.value),placeholder:"you@example.com","aria-label":"Email address",type:"email",className:"input"}),e.jsx("button",{type:"button",onClick:()=>{const t=g.trim();/.+@.+\..+/.test(t)&&y(t)},className:"btn btn-primary btn-touch shrink-0 rounded-full",children:"Send link"})]}),e.jsx("button",{type:"button",onClick:()=>i("idle"),className:"mt-2 font-round text-sm text-fg-dim hover:text-accent",children:"Cancel"})]}):null]})}export{T as CheckEmail};
@@ -1 +1 @@
1
- import{a as m,j as e,N as h,L as l,Y as o}from"./index-H6VNro-x.js";function u(s){return`${s.replace(/\/+$/,"")}/mcp`}function x(s){return`parachute-${s.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"")||"vault"}`}function p(s,t){return`claude mcp add --transport http ${x(s)} ${t}`}function y(){const s=m(n=>n.getActiveVault());if(!s)return e.jsx(h,{to:"/",replace:!0});const t=u(s.url),a=p(s.name,t);return e.jsxs("div",{className:"page-prose",children:[e.jsx("nav",{className:"mb-4 text-sm text-fg-dim",children:e.jsx(l,{to:"/",className:"focus-ring hover:text-accent",children:"← Home"})}),e.jsxs("header",{className:"mb-8",children:[e.jsx("p",{className:"eyebrow mb-1",children:s.name}),e.jsx("h1",{className:"page-title",children:"Connect your AI"}),e.jsx("p",{className:"mt-3 text-fg-muted",children:"Your vault speaks MCP — an open standard — so any AI can read and write it: Claude, ChatGPT, Claude Code, Cursor, or an agent you build. One memory, shared with every assistant you choose to connect."})]}),e.jsxs("section",{"aria-labelledby":"mcp-url-heading",className:"mb-8",children:[e.jsx("h2",{id:"mcp-url-heading",className:"eyebrow mb-2",children:"Your vault address"}),e.jsxs("p",{className:"mb-3 text-sm text-fg-muted",children:["Paste this wherever an AI asks for an MCP server. The"," ",e.jsx("code",{className:"rounded bg-bg-soft px-1 font-mono text-fg",children:"/mcp"})," suffix matters — it's the connection endpoint, not a page to open."]}),e.jsx(o,{value:t,label:"vault MCP URL"}),e.jsxs("p",{className:"mt-3 text-sm text-fg-muted",children:["It reads and writes only inside"," ",e.jsx("b",{className:"rounded-md bg-grass-soft px-2 py-0.5 font-medium text-grass-ink",children:s.name})," ","— never anywhere else. Disconnect anytime from your vault's settings."]})]}),e.jsx("h2",{className:"eyebrow mb-3",children:"Bring your AI in"}),e.jsxs("div",{className:"grid gap-4 sm:grid-cols-2",children:[e.jsx(d,{title:"Claude",initial:"C",tone:"coral",steps:g}),e.jsx(d,{title:"ChatGPT",initial:"G",tone:"grass",steps:b,note:"Exact menu names vary by ChatGPT version; the shape is the same — add an MCP server, paste the URL."})]}),e.jsxs("section",{"aria-labelledby":"other-clients-heading",className:"mt-8",children:[e.jsx("h2",{id:"other-clients-heading",className:"eyebrow mb-2",children:"Other AIs & the command line"}),e.jsx("p",{className:"mb-3 text-sm text-fg-muted",children:"That same URL works in any MCP-compatible client — Cursor, an agent you build, anywhere an AI asks for an MCP server. For Claude Code:"}),e.jsx(o,{value:a,label:"Claude Code command"})]}),e.jsx("div",{className:"mt-10 flex flex-wrap items-center gap-3 border-t border-border pt-6",children:e.jsx(l,{to:"/",className:"btn btn-primary btn-touch",children:"Done — back to your vault"})})]})}const g=[{key:"settings",body:e.jsxs(e.Fragment,{children:["Open"," ",e.jsx("a",{href:"https://claude.ai",target:"_blank",rel:"noopener noreferrer",className:"text-accent hover:underline",children:"claude.ai"})," ","and go to ",e.jsx("strong",{className:"text-fg",children:"Settings → Connectors"}),"."]})},{key:"add",body:e.jsxs(e.Fragment,{children:["Choose ",e.jsx("strong",{className:"text-fg",children:"Add custom connector"}),"."]})},{key:"paste",body:"Paste your vault address above and connect."}],b=[{key:"settings",body:e.jsxs(e.Fragment,{children:["Open ChatGPT's ",e.jsx("strong",{className:"text-fg",children:"Settings"})," and find its connectors (custom connectors need a paid ChatGPT plan)."]})},{key:"add",body:"Add a custom connector / MCP server."},{key:"paste",body:"Paste the same vault address and connect."}];function d({title:s,initial:t,tone:a,steps:n,note:r}){const i=a==="coral"?"bg-coral-soft text-coral-ink":"bg-grass-soft text-grass-ink";return e.jsxs("section",{className:"tile p-5","aria-label":`Connect ${s}`,children:[e.jsxs("div",{className:"mb-3 flex items-center gap-3",children:[e.jsx("span",{"aria-hidden":"true",className:`grid h-9 w-9 shrink-0 place-items-center rounded-full font-round text-sm font-semibold ${i}`,children:t}),e.jsx("h2",{className:"font-serif text-xl text-fg",children:s})]}),e.jsx("ol",{className:"list-decimal space-y-2 pl-5 text-sm text-fg-muted",children:n.map(c=>e.jsx("li",{children:c.body},c.key))}),r?e.jsx("p",{className:"mt-3 text-xs text-fg-dim",children:r}):null]})}export{y as ConnectAI};
1
+ import{a as m,j as e,N as h,L as l,$ as o}from"./index-CpyANXLa.js";function u(s){return`${s.replace(/\/+$/,"")}/mcp`}function x(s){return`parachute-${s.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"")||"vault"}`}function p(s,t){return`claude mcp add --transport http ${x(s)} ${t}`}function y(){const s=m(n=>n.getActiveVault());if(!s)return e.jsx(h,{to:"/",replace:!0});const t=u(s.url),a=p(s.name,t);return e.jsxs("div",{className:"page-prose",children:[e.jsx("nav",{className:"mb-4 text-sm text-fg-dim",children:e.jsx(l,{to:"/",className:"focus-ring hover:text-accent",children:"← Home"})}),e.jsxs("header",{className:"mb-8",children:[e.jsx("p",{className:"eyebrow mb-1",children:s.name}),e.jsx("h1",{className:"page-title",children:"Connect your AI"}),e.jsx("p",{className:"mt-3 text-fg-muted",children:"Your vault speaks MCP — an open standard — so any AI can read and write it: Claude, ChatGPT, Claude Code, Cursor, or an agent you build. One memory, shared with every assistant you choose to connect."})]}),e.jsxs("section",{"aria-labelledby":"mcp-url-heading",className:"mb-8",children:[e.jsx("h2",{id:"mcp-url-heading",className:"eyebrow mb-2",children:"Your vault address"}),e.jsxs("p",{className:"mb-3 text-sm text-fg-muted",children:["Paste this wherever an AI asks for an MCP server. The"," ",e.jsx("code",{className:"rounded bg-bg-soft px-1 font-mono text-fg",children:"/mcp"})," suffix matters — it's the connection endpoint, not a page to open."]}),e.jsx(o,{value:t,label:"vault MCP URL"}),e.jsxs("p",{className:"mt-3 text-sm text-fg-muted",children:["It reads and writes only inside"," ",e.jsx("b",{className:"rounded-md bg-grass-soft px-2 py-0.5 font-medium text-grass-ink",children:s.name})," ","— never anywhere else. Disconnect anytime from your vault's settings."]})]}),e.jsx("h2",{className:"eyebrow mb-3",children:"Bring your AI in"}),e.jsxs("div",{className:"grid gap-4 sm:grid-cols-2",children:[e.jsx(d,{title:"Claude",initial:"C",tone:"coral",steps:g}),e.jsx(d,{title:"ChatGPT",initial:"G",tone:"grass",steps:b,note:"Exact menu names vary by ChatGPT version; the shape is the same — add an MCP server, paste the URL."})]}),e.jsxs("section",{"aria-labelledby":"other-clients-heading",className:"mt-8",children:[e.jsx("h2",{id:"other-clients-heading",className:"eyebrow mb-2",children:"Other AIs & the command line"}),e.jsx("p",{className:"mb-3 text-sm text-fg-muted",children:"That same URL works in any MCP-compatible client — Cursor, an agent you build, anywhere an AI asks for an MCP server. For Claude Code:"}),e.jsx(o,{value:a,label:"Claude Code command"})]}),e.jsx("div",{className:"mt-10 flex flex-wrap items-center gap-3 border-t border-border pt-6",children:e.jsx(l,{to:"/",className:"btn btn-primary btn-touch",children:"Done — back to your vault"})})]})}const g=[{key:"settings",body:e.jsxs(e.Fragment,{children:["Open"," ",e.jsx("a",{href:"https://claude.ai",target:"_blank",rel:"noopener noreferrer",className:"text-accent hover:underline",children:"claude.ai"})," ","and go to ",e.jsx("strong",{className:"text-fg",children:"Settings → Connectors"}),"."]})},{key:"add",body:e.jsxs(e.Fragment,{children:["Choose ",e.jsx("strong",{className:"text-fg",children:"Add custom connector"}),"."]})},{key:"paste",body:"Paste your vault address above and connect."}],b=[{key:"settings",body:e.jsxs(e.Fragment,{children:["Open ChatGPT's ",e.jsx("strong",{className:"text-fg",children:"Settings"})," and find its connectors (custom connectors need a paid ChatGPT plan)."]})},{key:"add",body:"Add a custom connector / MCP server."},{key:"paste",body:"Paste the same vault address and connect."}];function d({title:s,initial:t,tone:a,steps:n,note:r}){const i=a==="coral"?"bg-coral-soft text-coral-ink":"bg-grass-soft text-grass-ink";return e.jsxs("section",{className:"tile p-5","aria-label":`Connect ${s}`,children:[e.jsxs("div",{className:"mb-3 flex items-center gap-3",children:[e.jsx("span",{"aria-hidden":"true",className:`grid h-9 w-9 shrink-0 place-items-center rounded-full font-round text-sm font-semibold ${i}`,children:t}),e.jsx("h2",{className:"font-serif text-xl text-fg",children:s})]}),e.jsx("ol",{className:"list-decimal space-y-2 pl-5 text-sm text-fg-muted",children:n.map(c=>e.jsx("li",{children:c.body},c.key))}),r?e.jsx("p",{className:"mt-3 text-xs text-fg-dim",children:r}):null]})}export{y as ConnectAI};
@@ -0,0 +1 @@
1
+ import{a as R,C as P,j as e,N as v,v as B,a0 as C,x as w,t as y,w as E,D as k,r as S,X as D,L as o,a1 as $,a2 as I,y as K,E as _,z as M,a3 as O,a4 as U,a5 as z,a6 as F,V as H}from"./index-CpyANXLa.js";import{u as Q}from"./history-Dwz434D-.js";function Z(){const a=R(t=>t.getActiveVault()),[s]=P(),r=s.get("date");return a?r===null?e.jsx(v,{to:"/",replace:!0}):e.jsx(W,{dateParam:r}):e.jsx(v,{to:"/",replace:!0})}function W({dateParam:a}){const s=Q("/"),r=B(),t=a||r,n=C(t),j=w(t)??"",b=w(y(t,1))??"",d=E({field:"created_at",from:j,to:b,limit:k,enabled:!!n}),l=E({field:"updated_at",from:j,to:b,limit:k,enabled:!!n}),x=S.useMemo(()=>{if(!(!d.data||!l.data))return[...new Map([...d.data,...l.data].map(i=>[i.id,i])).values()]},[d.data,l.data]),T=d.isPending||l.isPending,h=d.error??l.error,c=S.useMemo(()=>{const i=[],p=[];if(!x||!n)return{created:i,edited:p};for(const m of x){const g=D(m.createdAt),L=D(m.updatedAt??m.createdAt);g===t&&i.push(m),L===t&&g!==t&&p.push(m)}return{created:i,edited:p}},[x,n,t]);if(!n)return e.jsxs("div",{className:"page-prose",children:[e.jsxs("p",{className:"text-sm text-danger",children:["Invalid date in URL: ",t]}),e.jsx(o,{to:"/",className:"text-sm text-accent hover:underline",children:"Back to today"})]});const u=t===r,N=y(t,-1),f=y(t,1),V=t.slice(0,7);return e.jsxs("div",{className:"page-prose",children:[e.jsx("nav",{className:"mb-6 text-sm text-fg-dim",children:e.jsx("button",{type:"button",onClick:s,className:"hover:text-accent",children:"← Back"})}),e.jsxs("header",{className:"mb-6 flex flex-wrap items-baseline justify-between gap-3",children:[e.jsxs("div",{children:[e.jsx("p",{className:"eyebrow",children:u?"Today":"On"}),e.jsx("h1",{className:"page-title",children:$(t)})]}),e.jsxs("div",{className:"flex flex-wrap items-center gap-2 text-sm",children:[e.jsxs(o,{to:`/today?date=${N}`,className:"btn btn-secondary btn-sm","aria-label":"Previous day",children:["← ",N]}),u?null:e.jsx(o,{to:"/",className:"btn btn-secondary btn-sm",children:"Today"}),e.jsxs(o,{to:`/today?date=${f}`,className:"btn btn-secondary btn-sm","aria-label":"Next day",children:[f," →"]}),e.jsx(o,{to:`/calendar?month=${V}`,className:"btn btn-secondary btn-sm",children:"Calendar"}),e.jsx(o,{to:"/new",className:"btn btn-primary btn-sm",children:"+ New note"})]})]}),T?e.jsx(Y,{}):h&&!x?e.jsx(q,{error:h}):c.created.length===0&&c.edited.length===0?e.jsx(X,{isToday:u,targetKey:t}):e.jsxs("div",{className:"space-y-8",children:[h?e.jsx(I,{}):null,c.created.length>0?e.jsx(A,{title:u?"Created today":`Created on ${t}`,notes:c.created}):null,c.edited.length>0?e.jsx(A,{title:u?"Edited today":`Edited on ${t}`,notes:c.edited}):null]})]})}function A({title:a,notes:s}){const r=R(n=>n.getActiveVault()),{roles:t}=O((r==null?void 0:r.id)??null);return e.jsxs("section",{children:[e.jsxs(U,{children:[a," (",s.length,")"]}),e.jsx(z,{children:s.map(n=>e.jsx(F,{note:n,pinnedTag:t.pinned,archivedTag:t.archived},n.id))})]})}function X({isToday:a,targetKey:s}){return e.jsx(M,{title:a?"Nothing yet today — start capturing.":`Nothing on ${s}.`,action:a?e.jsx(o,{to:"/new",className:"btn btn-primary",children:"New note"}):void 0})}function Y(){return e.jsx("div",{className:"space-y-3","aria-busy":"true",children:[0,1,2,3].map(a=>e.jsx(K,{className:"h-14 rounded-xl"},a))})}function q({error:a}){const s=a instanceof H;return e.jsx(_,{title:s?"Session expired":"Could not load notes",message:a.message,action:s?e.jsx(o,{to:"/add",className:"btn btn-primary",children:"Reconnect vault"}):void 0})}export{Z as DayView};
@@ -1 +1 @@
1
- import{a as u,a5 as m,a6 as p,r as d,j as e,N as x,a7 as h,L as g}from"./index-H6VNro-x.js";function j(){const a=u(s=>s.getActiveVault()),n=m(),r=p(s=>s.push),[t,o]=d.useState({kind:"idle"});if(!a)return e.jsx(x,{to:"/",replace:!0});const i=d.useCallback(async()=>{if(!n){r("Vault session unavailable — reconnect first","error");return}o({kind:"preparing"});try{const s=await n.exportVault(),c=new Date().toISOString().slice(0,10);f(s,`${a.name}-export-${c}.tar`),o({kind:"idle"}),r("Export downloaded.","success")}catch(s){if(s instanceof h){o({kind:"unsupported"});return}o({kind:"error",message:"Couldn't reach your vault — try again."})}},[n,a.name,r]),l=t.kind==="preparing";return e.jsxs("div",{className:"page-prose",children:[e.jsx("nav",{className:"mb-4 text-sm text-fg-dim",children:e.jsx(g,{to:"/notes",className:"focus-ring hover:text-accent",children:"← All notes"})}),e.jsxs("header",{className:"mb-8",children:[e.jsxs("h1",{className:"page-title",children:["Export notes from ",e.jsx("span",{className:"text-accent",children:a.name})]}),e.jsx("p",{className:"mt-3 text-fg-muted",children:"A portable folder of your notes — plain Markdown, with your tags, links, and attachments included. Yours to keep, no matter what happens to Parachute."})]}),e.jsxs("section",{className:"card space-y-5 rounded-xl p-6 shadow-soft",children:[e.jsxs("div",{children:[e.jsx("h2",{className:"font-serif text-lg text-fg",children:"What's in the download"}),e.jsxs("ul",{className:"mt-2 list-disc space-y-1 pl-5 text-sm text-fg-muted",children:[e.jsx("li",{children:"One markdown file per note, with tags, metadata, and links as frontmatter."}),e.jsx("li",{children:"Your tag definitions, so an import elsewhere keeps their structure."}),e.jsx("li",{children:"Attachment files — images, audio, PDF, video — alongside the notes that use them."})]})]}),e.jsxs("div",{className:"flex flex-wrap items-center gap-3",children:[e.jsx("button",{type:"button",onClick:i,disabled:l,className:"btn btn-primary btn-touch",children:l?"Preparing your export…":"Export my vault"}),l?e.jsx("span",{className:"text-sm text-fg-dim",children:"This can take a moment."}):null]}),t.kind==="error"?e.jsx("p",{className:"rounded-lg border border-danger-border bg-danger-soft px-3 py-2 text-sm text-danger",children:t.message}):null,t.kind==="unsupported"?e.jsxs("div",{className:"rounded-lg border border-border bg-bg-soft px-3 py-2 text-sm text-fg-muted",children:[e.jsx("p",{children:"Export over the web isn't available on this vault yet — self-hosted vaults don't carry this door today."}),e.jsxs("p",{className:"mt-1",children:["From the vault's command line, run"," ",e.jsx("code",{className:"rounded bg-card px-1 font-mono text-fg",children:"parachute-vault export <dir>"})," ","to get the same portable folder."]})]}):null]})]})}function f(a,n){const r=URL.createObjectURL(a),t=document.createElement("a");t.href=r,t.download=n,document.body.appendChild(t),t.click(),t.remove(),URL.revokeObjectURL(r)}export{j as Export};
1
+ import{a as u,a7 as m,a8 as p,r as d,j as e,N as x,a9 as h,L as g}from"./index-CpyANXLa.js";function j(){const a=u(s=>s.getActiveVault()),n=m(),r=p(s=>s.push),[t,o]=d.useState({kind:"idle"});if(!a)return e.jsx(x,{to:"/",replace:!0});const i=d.useCallback(async()=>{if(!n){r("Vault session unavailable — reconnect first","error");return}o({kind:"preparing"});try{const s=await n.exportVault(),c=new Date().toISOString().slice(0,10);f(s,`${a.name}-export-${c}.tar`),o({kind:"idle"}),r("Export downloaded.","success")}catch(s){if(s instanceof h){o({kind:"unsupported"});return}o({kind:"error",message:"Couldn't reach your vault — try again."})}},[n,a.name,r]),l=t.kind==="preparing";return e.jsxs("div",{className:"page-prose",children:[e.jsx("nav",{className:"mb-4 text-sm text-fg-dim",children:e.jsx(g,{to:"/notes",className:"focus-ring hover:text-accent",children:"← All notes"})}),e.jsxs("header",{className:"mb-8",children:[e.jsxs("h1",{className:"page-title",children:["Export notes from ",e.jsx("span",{className:"text-accent",children:a.name})]}),e.jsx("p",{className:"mt-3 text-fg-muted",children:"A portable folder of your notes — plain Markdown, with your tags, links, and attachments included. Yours to keep, no matter what happens to Parachute."})]}),e.jsxs("section",{className:"card space-y-5 rounded-xl p-6 shadow-soft",children:[e.jsxs("div",{children:[e.jsx("h2",{className:"font-serif text-lg text-fg",children:"What's in the download"}),e.jsxs("ul",{className:"mt-2 list-disc space-y-1 pl-5 text-sm text-fg-muted",children:[e.jsx("li",{children:"One markdown file per note, with tags, metadata, and links as frontmatter."}),e.jsx("li",{children:"Your tag definitions, so an import elsewhere keeps their structure."}),e.jsx("li",{children:"Attachment files — images, audio, PDF, video — alongside the notes that use them."})]})]}),e.jsxs("div",{className:"flex flex-wrap items-center gap-3",children:[e.jsx("button",{type:"button",onClick:i,disabled:l,className:"btn btn-primary btn-touch",children:l?"Preparing your export…":"Export my vault"}),l?e.jsx("span",{className:"text-sm text-fg-dim",children:"This can take a moment."}):null]}),t.kind==="error"?e.jsx("p",{className:"rounded-lg border border-danger-border bg-danger-soft px-3 py-2 text-sm text-danger",children:t.message}):null,t.kind==="unsupported"?e.jsxs("div",{className:"rounded-lg border border-border bg-bg-soft px-3 py-2 text-sm text-fg-muted",children:[e.jsx("p",{children:"Export over the web isn't available on this vault yet — self-hosted vaults don't carry this door today."}),e.jsxs("p",{className:"mt-1",children:["From the vault's command line, run"," ",e.jsx("code",{className:"rounded bg-card px-1 font-mono text-fg",children:"parachute-vault export <dir>"})," ","to get the same portable folder."]})]}):null]})]})}function f(a,n){const r=URL.createObjectURL(a),t=document.createElement("a");t.href=r,t.download=n,document.body.appendChild(t),t.click(),t.remove(),URL.revokeObjectURL(r)}export{j as Export};
@@ -1,4 +1,4 @@
1
- import{a8 as te,a9 as ee,V as re,aa as Mt,ab as kt,ac as ne,a as se,a5 as ie,b as ae,y as oe,a6 as le,r as gt,j as D,N as Tt,L as ce}from"./index-H6VNro-x.js";import{f as ue,A as he}from"./attachment-upload-B8YiOVGU.js";const de=new Set(["png","jpg","jpeg","gif","webp"]),fe=new Set(["wav","mp3","m4a","ogg","webm"]),pe=new Set(["mp4"]),me=new Set(["txt","json","csv","yaml","yml","svg","tsv","log"]);function ge(y){const S=y.toLowerCase();return de.has(S)?"image":S==="pdf"?"pdf":fe.has(S)?"audio":pe.has(S)?"video":me.has(S)?"text":"unsupported"}function _e(y){return ge(ue(y))}function be(y){return y==="image"||y==="pdf"||y==="audio"||y==="video"}function $t(y){return typeof y.text=="function"?y.text():new Promise((S,o)=>{const b=new FileReader;b.onload=()=>S(b.result),b.onerror=()=>o(b.error??new Error("FileReader failed")),b.readAsText(y)})}function ye(y){const S=new Map,o=new Map;for(const b of y){const h=b.filename.toLowerCase();S.has(h)||S.set(h,b),o.set(Nt(b.sourcePath),b)}return{byBasename:S,byPath:o}}function Nt(y){let S=y.trim();try{S=decodeURIComponent(S)}catch{}return S=S.replace(/\\/g,"/").replace(/^\.\//,"").replace(/^\/+/,""),S.toLowerCase()}function Ct(y){const S=Nt(y),o=S.lastIndexOf("/");return o>=0?S.slice(o+1):S}function Bt(y){return/\.[a-z0-9]+$/i.test(Ct(y))}function Dt(y,S){const o=Nt(S),b=y.byPath.get(o);if(b)return b;for(const[h,i]of y.byPath)if(h===o||h.endsWith(`/${o}`))return i;return y.byBasename.get(Ct(S))??null}function Ft(y,S){const o=`/api/storage/${y.storagePath}`,b=S||y.filename;return y.isImage?`![${b}](${o})`:`[${b}](${o})`}function ve(y,S){let o=0;const b=new Set,h=/(!?)\[\[([^\]|#]+)(?:[#|][^\]]*)?\]\]/g,i=y.replace(h,(c,m,v)=>{if(!Bt(v))return c;const _=Dt(S,v);return _?(o++,b.add(_.sourcePath),Ft(_,Ct(v))):c}),n=/(!?)\[([^\]]*)\]\(\s*(<[^>]+>|[^)\s]+)(\s+[^)]*)?\)/g;return{content:i.replace(n,(c,m,v,_,w)=>{const s=_.startsWith("<")&&_.endsWith(">")?_.slice(1,-1):_;if(/^(https?:|mailto:|tel:|#|\/api\/storage\/)/i.test(s.trim())||!Bt(s))return c;const d=Dt(S,s);if(!d)return c;o++,b.add(d.sourcePath);const a=v.trim()||Ct(s);return Ft(d,a)}),rewritten:o,referenced:b}}const we=5,ke=500;async function It(y){const{client:S,notes:o,onProgress:b,signal:h}=y,i=Math.max(1,y.concurrency??we),n=[];let r=0,c=0,m=!1;const v=o.map(ze);async function _(){for(;;){if(h!=null&&h.aborted||m)return;const l=r++;if(l>=o.length)return;const u=o[l],p=v[l],x=await xe(S,u,p,h);n[l]=x,c++,x.status==="errored"&&x.reason.startsWith("auth:")&&(m=!0),b==null||b({done:c,total:o.length})}}const w=Array.from({length:Math.min(i,o.length)},()=>_());await Promise.all(w);for(let l=0;l<o.length;l++)n[l]||(n[l]={status:"errored",sourcePath:o[l].sourcePath,reason:m?"Skipped — vault session ended before this note was reached.":"Skipped — import was cancelled."});let s=0,d=0,a=0;for(const l of n)l.status==="created"?s++:l.status==="skipped"?d++:a++;return{created:s,skipped:d,errored:a,outcomes:n}}async function xe(y,S,o,b){try{const h=await Se(y,o,b);return{status:"created",sourcePath:S.sourcePath,noteId:h.id}}catch(h){return h instanceof te||h instanceof ee?{status:"skipped",sourcePath:S.sourcePath,reason:h.message||"Already exists in vault"}:h instanceof re?{status:"errored",sourcePath:S.sourcePath,reason:`auth: ${h.message}`}:h instanceof Mt?{status:"errored",sourcePath:S.sourcePath,reason:`vault unreachable (${h.status}): ${h.message}`}:{status:"errored",sourcePath:S.sourcePath,reason:h instanceof Error?h.message:String(h)}}}async function Se(y,S,o){const b={};o&&(b.signal=o);try{return await y.createNote(S,b)}catch(h){if(!Ce(h)||o!=null&&o.aborted)throw h;return await Ee(ke,o),await y.createNote(S,b)}}function Ce(y){return y instanceof Mt}function Ee(y,S){return new Promise(o=>{const b=setTimeout(()=>{S==null||S.removeEventListener("abort",h),o()},y),h=()=>{clearTimeout(b),o()};S&&S.addEventListener("abort",h,{once:!0})})}function ze(y){const S={content:y.content};y.path&&(S.path=y.path),y.tags.length>0&&(S.tags=y.tags),Object.keys(y.metadata).length>0&&(S.metadata=y.metadata);const o=S;return y.id&&(o.id=y.id),y.createdAt&&(o.created_at=y.createdAt),S}const Lt="Imported files",Ae=20;async function Ie(y){const{client:S,parsed:o,signal:b}=y,h=[],i=[],n=[],r=[];for(const l of o.attachments)be(l.kind)?i.push(l):l.kind==="text"?n.push(l):r.push(l);const c=new Map;for(const l of i){if(b!=null&&b.aborted){h.push({status:"skipped",sourcePath:l.sourcePath,reason:"Skipped — import was cancelled."});continue}try{const u=new File([l.blob],l.filename,{type:l.blob.type||void 0}),p=await S.uploadStorageFile(u,{signal:b});c.set(l.sourcePath,{attachment:l,storagePath:p.path,mimeType:p.mimeType,isImage:p.mimeType.startsWith("image/")})}catch(u){h.push({status:"errored",sourcePath:l.sourcePath,reason:`Upload failed: ${u instanceof Error?u.message:String(u)}`})}}const m=Ne(c),v=new Map,_=o.notes.map(l=>{const{content:u,referenced:p}=ve(l.content,m);return v.set(l.sourcePath,p),{...l,content:u}}),w=await It({client:S,notes:_,...y.concurrency!==void 0?{concurrency:y.concurrency}:{},...y.onProgress?{onProgress:y.onProgress}:{},...b?{signal:b}:{}}),s=new Map;for(const l of w.outcomes)l.status==="created"&&s.set(l.sourcePath,l.noteId);const d=new Map;for(const[l,u]of v){const p=s.get(l);if(p)for(const x of u){let E=d.get(x);E||(E=new Set,d.set(x,E)),E.add(p)}}for(const[l,u]of c){const p=d.get(l);if(!p||p.size===0)continue;let x=0;for(const E of p){if(b!=null&&b.aborted)break;try{await S.linkAttachment(E,{path:u.storagePath,mimeType:u.mimeType}),x++}catch{}}h.push({status:"uploaded",sourcePath:l,storagePath:u.storagePath,references:x})}if(n.length>0&&!(b!=null&&b.aborted)){const l=[];for(const p of n)l.push(await je(p));const u=await It({client:S,notes:l,...y.concurrency!==void 0?{concurrency:y.concurrency}:{},...b?{signal:b}:{}});for(let p=0;p<n.length;p++){const x=n[p],E=u.outcomes[p];(E==null?void 0:E.status)==="created"?h.push({status:"uploaded",sourcePath:x.sourcePath,storagePath:`note:${E.noteId}`,references:1,asNote:!0}):h.push({status:"skipped",sourcePath:x.sourcePath,reason:(E==null?void 0:E.status)==="skipped"?`Imported as note, but ${E.reason}`:`Could not import as note: ${(E==null?void 0:E.status)==="errored"?E.reason:"unknown"}`})}}else if(n.length>0)for(const l of n)h.push({status:"skipped",sourcePath:l.sourcePath,reason:"Skipped — import was cancelled."});const a=[...c.entries()].filter(([l])=>{var u;return!(((u=d.get(l))==null?void 0:u.size)??0)}).map(([,l])=>l);if(a.length>0)if(b!=null&&b.aborted)for(const l of a)h.push({status:"uploaded",sourcePath:l.attachment.sourcePath,storagePath:l.storagePath,references:0});else await Re(S,a,h,y.concurrency,b);for(const l of r)h.push({status:"skipped",sourcePath:l.sourcePath,reason:`.${l.ext||"?"} is not a vault storage type — not imported. (Re-save it in a supported format to bring it across.)`});return Te(w,h)}function Ne(y){return ye([...y.values()].map(S=>({sourcePath:S.attachment.sourcePath,storagePath:S.storagePath,isImage:S.isImage,filename:S.attachment.filename})))}async function je(y){let S="";try{S=await $t(y.blob)}catch{S=""}const o=Pe(y.ext)?`\`\`\`${Oe(y.ext)}
1
+ import{aa as te,ab as ee,V as re,ac as Mt,ad as kt,ae as ne,a as se,a7 as ie,b as ae,C as oe,a8 as le,r as gt,j as D,N as Tt,L as ce}from"./index-CpyANXLa.js";import{f as ue,A as he}from"./attachment-upload-DbV0j1WH.js";const de=new Set(["png","jpg","jpeg","gif","webp"]),fe=new Set(["wav","mp3","m4a","ogg","webm"]),pe=new Set(["mp4"]),me=new Set(["txt","json","csv","yaml","yml","svg","tsv","log"]);function ge(y){const S=y.toLowerCase();return de.has(S)?"image":S==="pdf"?"pdf":fe.has(S)?"audio":pe.has(S)?"video":me.has(S)?"text":"unsupported"}function _e(y){return ge(ue(y))}function be(y){return y==="image"||y==="pdf"||y==="audio"||y==="video"}function $t(y){return typeof y.text=="function"?y.text():new Promise((S,o)=>{const b=new FileReader;b.onload=()=>S(b.result),b.onerror=()=>o(b.error??new Error("FileReader failed")),b.readAsText(y)})}function ye(y){const S=new Map,o=new Map;for(const b of y){const h=b.filename.toLowerCase();S.has(h)||S.set(h,b),o.set(Nt(b.sourcePath),b)}return{byBasename:S,byPath:o}}function Nt(y){let S=y.trim();try{S=decodeURIComponent(S)}catch{}return S=S.replace(/\\/g,"/").replace(/^\.\//,"").replace(/^\/+/,""),S.toLowerCase()}function Ct(y){const S=Nt(y),o=S.lastIndexOf("/");return o>=0?S.slice(o+1):S}function Bt(y){return/\.[a-z0-9]+$/i.test(Ct(y))}function Dt(y,S){const o=Nt(S),b=y.byPath.get(o);if(b)return b;for(const[h,i]of y.byPath)if(h===o||h.endsWith(`/${o}`))return i;return y.byBasename.get(Ct(S))??null}function Ft(y,S){const o=`/api/storage/${y.storagePath}`,b=S||y.filename;return y.isImage?`![${b}](${o})`:`[${b}](${o})`}function ve(y,S){let o=0;const b=new Set,h=/(!?)\[\[([^\]|#]+)(?:[#|][^\]]*)?\]\]/g,i=y.replace(h,(c,m,v)=>{if(!Bt(v))return c;const _=Dt(S,v);return _?(o++,b.add(_.sourcePath),Ft(_,Ct(v))):c}),n=/(!?)\[([^\]]*)\]\(\s*(<[^>]+>|[^)\s]+)(\s+[^)]*)?\)/g;return{content:i.replace(n,(c,m,v,_,w)=>{const s=_.startsWith("<")&&_.endsWith(">")?_.slice(1,-1):_;if(/^(https?:|mailto:|tel:|#|\/api\/storage\/)/i.test(s.trim())||!Bt(s))return c;const d=Dt(S,s);if(!d)return c;o++,b.add(d.sourcePath);const a=v.trim()||Ct(s);return Ft(d,a)}),rewritten:o,referenced:b}}const we=5,ke=500;async function It(y){const{client:S,notes:o,onProgress:b,signal:h}=y,i=Math.max(1,y.concurrency??we),n=[];let r=0,c=0,m=!1;const v=o.map(ze);async function _(){for(;;){if(h!=null&&h.aborted||m)return;const l=r++;if(l>=o.length)return;const u=o[l],p=v[l],x=await xe(S,u,p,h);n[l]=x,c++,x.status==="errored"&&x.reason.startsWith("auth:")&&(m=!0),b==null||b({done:c,total:o.length})}}const w=Array.from({length:Math.min(i,o.length)},()=>_());await Promise.all(w);for(let l=0;l<o.length;l++)n[l]||(n[l]={status:"errored",sourcePath:o[l].sourcePath,reason:m?"Skipped — vault session ended before this note was reached.":"Skipped — import was cancelled."});let s=0,d=0,a=0;for(const l of n)l.status==="created"?s++:l.status==="skipped"?d++:a++;return{created:s,skipped:d,errored:a,outcomes:n}}async function xe(y,S,o,b){try{const h=await Se(y,o,b);return{status:"created",sourcePath:S.sourcePath,noteId:h.id}}catch(h){return h instanceof te||h instanceof ee?{status:"skipped",sourcePath:S.sourcePath,reason:h.message||"Already exists in vault"}:h instanceof re?{status:"errored",sourcePath:S.sourcePath,reason:`auth: ${h.message}`}:h instanceof Mt?{status:"errored",sourcePath:S.sourcePath,reason:`vault unreachable (${h.status}): ${h.message}`}:{status:"errored",sourcePath:S.sourcePath,reason:h instanceof Error?h.message:String(h)}}}async function Se(y,S,o){const b={};o&&(b.signal=o);try{return await y.createNote(S,b)}catch(h){if(!Ce(h)||o!=null&&o.aborted)throw h;return await Ee(ke,o),await y.createNote(S,b)}}function Ce(y){return y instanceof Mt}function Ee(y,S){return new Promise(o=>{const b=setTimeout(()=>{S==null||S.removeEventListener("abort",h),o()},y),h=()=>{clearTimeout(b),o()};S&&S.addEventListener("abort",h,{once:!0})})}function ze(y){const S={content:y.content};y.path&&(S.path=y.path),y.tags.length>0&&(S.tags=y.tags),Object.keys(y.metadata).length>0&&(S.metadata=y.metadata);const o=S;return y.id&&(o.id=y.id),y.createdAt&&(o.created_at=y.createdAt),S}const Lt="Imported files",Ae=20;async function Ie(y){const{client:S,parsed:o,signal:b}=y,h=[],i=[],n=[],r=[];for(const l of o.attachments)be(l.kind)?i.push(l):l.kind==="text"?n.push(l):r.push(l);const c=new Map;for(const l of i){if(b!=null&&b.aborted){h.push({status:"skipped",sourcePath:l.sourcePath,reason:"Skipped — import was cancelled."});continue}try{const u=new File([l.blob],l.filename,{type:l.blob.type||void 0}),p=await S.uploadStorageFile(u,{signal:b});c.set(l.sourcePath,{attachment:l,storagePath:p.path,mimeType:p.mimeType,isImage:p.mimeType.startsWith("image/")})}catch(u){h.push({status:"errored",sourcePath:l.sourcePath,reason:`Upload failed: ${u instanceof Error?u.message:String(u)}`})}}const m=Ne(c),v=new Map,_=o.notes.map(l=>{const{content:u,referenced:p}=ve(l.content,m);return v.set(l.sourcePath,p),{...l,content:u}}),w=await It({client:S,notes:_,...y.concurrency!==void 0?{concurrency:y.concurrency}:{},...y.onProgress?{onProgress:y.onProgress}:{},...b?{signal:b}:{}}),s=new Map;for(const l of w.outcomes)l.status==="created"&&s.set(l.sourcePath,l.noteId);const d=new Map;for(const[l,u]of v){const p=s.get(l);if(p)for(const x of u){let E=d.get(x);E||(E=new Set,d.set(x,E)),E.add(p)}}for(const[l,u]of c){const p=d.get(l);if(!p||p.size===0)continue;let x=0;for(const E of p){if(b!=null&&b.aborted)break;try{await S.linkAttachment(E,{path:u.storagePath,mimeType:u.mimeType}),x++}catch{}}h.push({status:"uploaded",sourcePath:l,storagePath:u.storagePath,references:x})}if(n.length>0&&!(b!=null&&b.aborted)){const l=[];for(const p of n)l.push(await je(p));const u=await It({client:S,notes:l,...y.concurrency!==void 0?{concurrency:y.concurrency}:{},...b?{signal:b}:{}});for(let p=0;p<n.length;p++){const x=n[p],E=u.outcomes[p];(E==null?void 0:E.status)==="created"?h.push({status:"uploaded",sourcePath:x.sourcePath,storagePath:`note:${E.noteId}`,references:1,asNote:!0}):h.push({status:"skipped",sourcePath:x.sourcePath,reason:(E==null?void 0:E.status)==="skipped"?`Imported as note, but ${E.reason}`:`Could not import as note: ${(E==null?void 0:E.status)==="errored"?E.reason:"unknown"}`})}}else if(n.length>0)for(const l of n)h.push({status:"skipped",sourcePath:l.sourcePath,reason:"Skipped — import was cancelled."});const a=[...c.entries()].filter(([l])=>{var u;return!(((u=d.get(l))==null?void 0:u.size)??0)}).map(([,l])=>l);if(a.length>0)if(b!=null&&b.aborted)for(const l of a)h.push({status:"uploaded",sourcePath:l.attachment.sourcePath,storagePath:l.storagePath,references:0});else await Re(S,a,h,y.concurrency,b);for(const l of r)h.push({status:"skipped",sourcePath:l.sourcePath,reason:`.${l.ext||"?"} is not a vault storage type — not imported. (Re-save it in a supported format to bring it across.)`});return Te(w,h)}function Ne(y){return ye([...y.values()].map(S=>({sourcePath:S.attachment.sourcePath,storagePath:S.storagePath,isImage:S.isImage,filename:S.attachment.filename})))}async function je(y){let S="";try{S=await $t(y.blob)}catch{S=""}const o=Pe(y.ext)?`\`\`\`${Oe(y.ext)}
2
2
  ${S}
3
3
  \`\`\`
4
4
  `:`${S}
@@ -1 +1 @@
1
- import{r as n,j as e,a6 as H,ad as oe,V as I,a7 as le,ae as ce,a as K,af as de,N as ue,L as $,E as me,w as fe,b as he,ag as q,ah as xe,ai as pe,aj as ge,ak as be,a8 as ve,al as T,am as je,an as Ne,x as F,ao as we}from"./index-H6VNro-x.js";import{A as ye}from"./attachment-upload-B8YiOVGU.js";import{u as Se,C as ke,A as Ce,a as Ee}from"./useAttachmentUploader-C78HTrMx.js";import{P as Re,D as Ae}from"./PinArchiveButtons-DyFdYBrq.js";import{b as De,N as Te}from"./NoteRenderer-BXeTxHnB.js";import{r as Pe}from"./editor-mode-D9fveTEx.js";const Ie=250;function $e({noteId:t,attachment:a}){const[r,l]=n.useState(!1),x=Le(a);return e.jsxs(e.Fragment,{children:[e.jsx("button",{type:"button",onClick:()=>l(!0),"aria-label":`Remove attachment ${x}`,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:"✕"}),r?e.jsx(Fe,{noteId:t,attachment:a,label:x,onClose:()=>l(!1)}):null]})}function Fe({noteId:t,attachment:a,label:r,onClose:l}){const x=H(o=>o.push),i=oe(),[u,m]=n.useState(!1),[f,N]=n.useState(null),d=n.useRef(null);n.useEffect(()=>{const o=setTimeout(()=>m(!0),Ie);return()=>clearTimeout(o)},[]),n.useEffect(()=>{var o;(o=d.current)==null||o.focus()},[]),n.useEffect(()=>{const o=k=>{k.key==="Escape"&&l()};return window.addEventListener("keydown",o),()=>window.removeEventListener("keydown",o)},[l]);const g=n.useCallback(()=>{!u||i.isPending||(N(null),i.mutate({noteId:t,attachmentId:a.id},{onSuccess:()=>{x(`Removed ${r}`,"success"),l()},onError:o=>{if(o instanceof I){N("Session expired. Reconnect to remove attachments.");return}if(o instanceof le){x(`Already removed ${r}`,"info"),l();return}N(o instanceof Error?o.message:"Remove failed")}}))},[u,a.id,r,i,t,l,x]);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:o=>{o.target===o.currentTarget&&l()},children:e.jsxs("div",{className:"w-full max-w-md rounded-2xl border border-border bg-card p-6 shadow-lift",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:r})," ","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."]}),f?e.jsx("p",{role:"alert",className:"mb-3 text-sm text-red-400",children:f}):null,e.jsxs("div",{className:"flex justify-end gap-2",children:[e.jsx("button",{ref:d,type:"button",onClick:l,className:"min-h-11 rounded-lg 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:g,disabled:!u||i.isPending,className:"btn btn-danger-solid btn-touch",children:i.isPending?"Removing…":"Remove"})]})]})})}function Le(t){if(t.filename)return t.filename;if(t.path){const a=t.path.split("/").pop();return a||t.path}return t.id}function Ge(){const{id:t}=ce(),a=K(l=>l.getActiveVault()),r=de(t);return a?e.jsxs("div",{className:"page",children:[e.jsx("nav",{className:"mb-6 text-sm text-fg-dim",children:e.jsx($,{to:t?`/n/${encodeURIComponent(t)}`:"/",className:"focus-ring hover:text-accent",children:"← Back to note"})}),r.isPending?e.jsx(Ve,{}):r.isError?e.jsx(_e,{error:r.error}):r.data?e.jsx(Be,{note:r.data}):e.jsx(Oe,{id:t??""})]}):e.jsx(ue,{to:"/",replace:!0})}function S(t){return{content:t.content??"",path:t.path??"",tags:[...t.tags??[]]}}function Be({note:t}){const a=he(),r=H(s=>s.push),l=q(s=>s.on),x=q(s=>s.setOn),i=n.useRef(K.getState().activeVaultId).current,u=n.useRef(Pe()).current,m=n.useMemo(()=>De(t),[t]),[f,N]=n.useState(()=>S(t)),[d,g]=n.useState(()=>S(t)),[o,k]=n.useState(()=>{if(!i)return null;const s=xe(i,t.id);return!s||pe(s.body,S(t))?null:s}),[Z,L]=n.useState(""),[B,C]=n.useState(null),[M,E]=n.useState(null),[U,V]=n.useState(!1),w=n.useRef(null);n.useEffect(()=>()=>{w.current!==null&&window.clearTimeout(w.current)},[]);const[R,G]=n.useState("edit"),j=ge(t.id),A=n.useRef(t),P=n.useRef(null),O=n.useRef(null),v=Se({noteId:t.id,onInsert:s=>{P.current?P.current.insertAtCursor(s):g(c=>({...c,content:`${c.content}${s}`}))},onLinked:()=>{r("Attachment added","success")},onError:s=>r(s,"error")});n.useEffect(()=>{A.current=t},[t]);const h=d.content!==f.content||d.path!==f.path||!We(d.tags,f.tags);be(i,t.id,d,h);const y=v.uploads.some(s=>s.status==="uploading"||s.status==="linking"),D=n.useCallback(({navigateToView:s})=>{if(!h||j.isPending||y)return;const c={};d.content!==f.content&&(c.content=d.content),d.path!==f.path&&(c.path=d.path);const b=ze(f.tags,d.tags);(b.add.length||b.remove.length)&&(c.tags=b);const z=A.current.updatedAt??A.current.createdAt;z&&(c.if_updated_at=z),E(null),C(null),j.mutate(c,{onSuccess:p=>{N(S(p)),g(S(p)),A.current=p,i&&T(i,t.id),s?a(`/n/${encodeURIComponent(p.id)}`,{replace:!0}):p.id!==t.id&&a(`/n/${encodeURIComponent(p.id)}/edit`,{replace:!0}),s||(V(!0),w.current!==null&&window.clearTimeout(w.current),w.current=window.setTimeout(()=>V(!1),1500))},onError:p=>{p instanceof ve?C(p):p instanceof I?E("Session expired. Reconnect to save."):E(p instanceof Error?p.message:"Save failed")}})},[f,d,h,j,a,t.id,y,i]),Q=n.useCallback(()=>{o&&g(o.body),k(null)},[o]),X=n.useCallback(()=>{i&&T(i,t.id),k(null)},[i,t.id]),ee=n.useCallback(()=>D({navigateToView:!0}),[D]),te=n.useCallback(()=>D({navigateToView:!1}),[D]),se=n.useCallback(()=>{h&&confirm("Discard all edits and revert to last saved version?")&&(g(f),C(null),E(null))},[f,h]),_=n.useCallback(()=>{h&&!confirm("Discard unsaved changes?")||(i&&T(i,t.id),a(`/n/${encodeURIComponent(t.id)}`))},[h,a,t.id,i]);n.useEffect(()=>{if(!h)return;const s=c=>{c.preventDefault(),c.returnValue=""};return window.addEventListener("beforeunload",s),()=>window.removeEventListener("beforeunload",s)},[h]);const ne=d.path!==f.path,ae=s=>{const c=we(s);c&&(d.tags.includes(c)||(g(b=>({...b,tags:[...b.tags,c]})),L("")))},re=s=>{g(c=>({...c,tags:c.tags.filter(b=>b!==s)}))},ie=d.content,W=l?"h-[85dvh]":"h-[60dvh]";return e.jsxs("article",{children:[l?e.jsx("div",{className:"glass-panel enter-fade fixed top-4 left-4 z-30 rounded-full border border-border px-3 py-1.5 text-xs shadow-lift",style:{marginTop:"env(safe-area-inset-top)"},children:e.jsx(Y,{isDirty:h,justSaved:U,updatedAt:t.updatedAt})}):e.jsxs("header",{className:"card mb-6 p-5 shadow-soft md:p-6",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:"eyebrow",children:"Editing"}),e.jsx(Y,{isDirty:h,justSaved:U,updatedAt:t.updatedAt})]}),e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[e.jsx(Re,{note:t}),e.jsx(Ae,{note:t}),e.jsxs("button",{type:"button",onClick:()=>x(!0),className:"btn btn-ghost btn-touch",title:"Focus (⌘.)",children:[e.jsx(je,{width:16,height:16}),"Focus"]}),e.jsx("span",{className:"mx-1 h-5 w-px bg-border","aria-hidden":"true"}),e.jsx("button",{type:"button",onClick:se,disabled:!h||j.isPending,className:"btn btn-secondary btn-touch",children:"Revert"}),e.jsx("button",{type:"button",onClick:_,className:"btn btn-secondary btn-touch",children:"Cancel"}),e.jsx("button",{type:"button",onClick:ee,disabled:!h||j.isPending||y,className:"btn btn-primary btn-touch",title:y?"Waiting for upload…":"Save (⌘S)","aria-label":y?"Save — waiting for upload…":"Save",children:j.isPending?"Saving…":"Save"})]})]}),e.jsx("div",{className:"mt-4",children:e.jsx(Ne,{tags:d.tags,input:Z,onInputChange:L,onAdd:ae,onRemove:re})}),e.jsxs("div",{className:"mt-4 flex items-center gap-2 text-fg-dim",children:[e.jsx("span",{"aria-hidden":"true",className:"shrink-0 text-xs",children:"Path"}),e.jsx("input",{type:"text",value:d.path,onChange:s=>g(c=>({...c,path:s.target.value})),className:"focus-ring w-full min-w-0 truncate rounded border-0 bg-transparent font-mono text-xs text-fg-dim outline-none transition-colors hover:text-fg-muted focus:text-fg placeholder:text-fg-dim","aria-label":"Note path",placeholder:"(no path)",title:d.path||void 0})]}),ne?e.jsx("p",{className:"mt-1 text-xs text-accent",children:"Renaming moves the note — its id may change."}):null]}),o?e.jsxs("div",{role:"status","data-testid":"draft-offer",className:"mb-4 flex flex-wrap items-center justify-between gap-2 rounded-xl border border-accent/30 bg-accent/5 px-3 py-2 text-sm",children:[e.jsxs("span",{className:"text-fg-muted",children:["You have an unsaved draft from ",F(o.savedAt),"."]}),e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx("button",{type:"button",onClick:Q,className:"focus-ring font-medium text-accent hover:underline",children:"Restore"}),e.jsx("button",{type:"button",onClick:X,className:"focus-ring text-fg-dim hover:text-danger",children:"Discard"})]})]}):null,B?e.jsx(Ue,{conflict:B,onReload:()=>{i&&T(i,t.id),window.location.reload()},onDismiss:()=>C(null)}):null,M?e.jsx("div",{className:"mb-4 rounded-xl border border-danger-border bg-danger-soft p-3 text-sm text-danger",children:M}):null,u?null:e.jsx("div",{role:"tablist","aria-label":"Editor view",className:"mb-3 inline-flex rounded-lg border border-border bg-card p-0.5 text-sm lg:hidden",children:["edit","preview"].map(s=>e.jsx("button",{type:"button",role:"tab","aria-selected":R===s,onClick:()=>G(s),className:`rounded-sm px-3 py-1.5 capitalize ${R===s?"bg-accent text-on-accent":"text-fg-muted hover:text-accent"}`,children:s},s))}),e.jsxs("div",{className:`grid ${l?"min-h-[85dvh]":"min-h-[60dvh]"} gap-4 ${u?"":"lg:grid-cols-2"}`,children:[e.jsx(ye,{onDropFiles:v.start,className:`card min-h-0 ${W} min-w-0 ${u||R==="edit"?"":"hidden lg:block"}`,hint:J,children:e.jsx(ke,{ref:P,value:d.content,onChange:s=>g(c=>({...c,content:s})),onSave:te,onCancel:_,onPasteFile:s=>(v.start(s),!0),onRequestAttachment:()=>{var s;return(s=O.current)==null?void 0:s.open()},livePreview:u})}),u?null:e.jsx("div",{className:`card min-h-0 ${W} min-w-0 overflow-auto p-4 ${R==="preview"?"":"hidden lg:block"}`,children:e.jsx(Te,{note:{path:d.path,content:ie},resolve:m})})]}),e.jsx(Me,{noteId:t.id,pickerRef:O,attachments:t.attachments??[],uploads:v.uploads,onPickFiles:v.start,onCancel:v.cancel,onDismiss:v.dismiss})]})}const J=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:"text-accent hover:underline",children:"PDF + mp4 coming"})]});function Me({noteId:t,pickerRef:a,attachments:r,uploads:l,onPickFiles:x,onCancel:i,onDismiss:u}){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-xl",children:"Attachments"}),e.jsx(Ce,{ref:a,onPickFiles:x})]}),e.jsxs("p",{className:"mb-3 text-xs text-fg-dim",children:["Drop or paste files into the editor. Max 100 MB each. ",J,"."]}),e.jsx(Ee,{uploads:l,onCancel:i,onDismiss:u}),r.length>0?e.jsx("ul",{className:"mt-3 space-y-1 text-sm",children:r.map(m=>e.jsxs("li",{className:"flex items-center justify-between gap-2 rounded-lg border border-border bg-card/50 px-3 py-1.5 font-mono text-xs",children:[e.jsx("span",{className:"truncate",title:m.path??m.id,children:m.filename??m.path??m.id}),e.jsxs("div",{className:"flex shrink-0 items-center gap-2",children:[m.mimeType?e.jsx("span",{className:"text-fg-dim",children:m.mimeType}):null,e.jsx($e,{noteId:t,attachment:m})]})]},m.id))}):null]})}function Ue({conflict:t,onReload:a,onDismiss:r}){return e.jsxs("div",{className:"mb-4 rounded-xl border border-warning bg-warning-soft p-4",children:[e.jsx("p",{className:"mb-1 font-medium text-warning",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 ${F(t.currentUpdatedAt)}.`:""]}),e.jsxs("div",{className:"flex flex-wrap gap-2",children:[e.jsx("button",{type:"button",onClick:a,className:"btn btn-primary btn-touch",children:"Reload latest (discard my edits)"}),e.jsx("button",{type:"button",onClick:r,className:"btn btn-secondary btn-touch",children:"Keep editing"})]})]})}function Ve(){return e.jsxs("div",{className:"grid min-h-[60dvh] gap-4 lg:grid-cols-2","aria-busy":"true",children:[e.jsx("div",{className:"card animate-pulse"}),e.jsx("div",{className:"card animate-pulse"})]})}function Oe({id:t}){return e.jsx(fe,{title:e.jsx("span",{className:"font-serif text-xl text-fg",children:"Note not found"}),description:e.jsxs(e.Fragment,{children:["No note with id ",e.jsx("span",{className:"font-mono",children:t})," in this vault."]}),action:e.jsx($,{to:"/notes",className:"text-sm text-accent hover:underline",children:"Back to all notes"})})}function Y({isDirty:t,justSaved:a,updatedAt:r}){return t?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"]}):a?e.jsx("span",{className:"text-xs text-accent","aria-label":"saved",children:"Saved ✓"}):e.jsxs("span",{className:"text-xs text-fg-dim",children:["saved ",F(r)]})}function _e({error:t}){const a=t instanceof I;return e.jsx(me,{title:a?"Session expired":"Could not load note",message:t.message,action:a?e.jsx($,{to:"/add",className:"btn btn-primary",children:"Reconnect vault"}):void 0})}function We(t,a){if(t.length!==a.length)return!1;const r=new Set(t);for(const l of a)if(!r.has(l))return!1;return!0}function ze(t,a){const r=new Set(t),l=new Set(a),x=a.filter(u=>!r.has(u)),i=t.filter(u=>!l.has(u));return{add:x,remove:i}}export{Ge as NoteEditor};
1
+ import{r as n,j as e,a8 as H,af as oe,V as I,a9 as le,ag as ce,a as K,ah as de,N as ue,L as $,E as me,z as fe,b as he,ai as q,aj as xe,ak as pe,al as ge,am as be,aa as ve,an as T,ao as je,ap as Ne,A as F,aq as we}from"./index-CpyANXLa.js";import{A as ye}from"./attachment-upload-DbV0j1WH.js";import{u as Se,C as ke,A as Ce,a as Ee}from"./useAttachmentUploader-t5hlKCgS.js";import{P as Re,D as Ae}from"./PinArchiveButtons-DBJ9XC87.js";import{b as De,N as Te}from"./NoteRenderer-BzRFYOTP.js";import{r as Pe}from"./editor-mode-D9fveTEx.js";const Ie=250;function $e({noteId:t,attachment:a}){const[r,l]=n.useState(!1),x=Le(a);return e.jsxs(e.Fragment,{children:[e.jsx("button",{type:"button",onClick:()=>l(!0),"aria-label":`Remove attachment ${x}`,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:"✕"}),r?e.jsx(Fe,{noteId:t,attachment:a,label:x,onClose:()=>l(!1)}):null]})}function Fe({noteId:t,attachment:a,label:r,onClose:l}){const x=H(o=>o.push),i=oe(),[u,m]=n.useState(!1),[f,N]=n.useState(null),d=n.useRef(null);n.useEffect(()=>{const o=setTimeout(()=>m(!0),Ie);return()=>clearTimeout(o)},[]),n.useEffect(()=>{var o;(o=d.current)==null||o.focus()},[]),n.useEffect(()=>{const o=k=>{k.key==="Escape"&&l()};return window.addEventListener("keydown",o),()=>window.removeEventListener("keydown",o)},[l]);const g=n.useCallback(()=>{!u||i.isPending||(N(null),i.mutate({noteId:t,attachmentId:a.id},{onSuccess:()=>{x(`Removed ${r}`,"success"),l()},onError:o=>{if(o instanceof I){N("Session expired. Reconnect to remove attachments.");return}if(o instanceof le){x(`Already removed ${r}`,"info"),l();return}N(o instanceof Error?o.message:"Remove failed")}}))},[u,a.id,r,i,t,l,x]);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:o=>{o.target===o.currentTarget&&l()},children:e.jsxs("div",{className:"w-full max-w-md rounded-2xl border border-border bg-card p-6 shadow-lift",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:r})," ","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."]}),f?e.jsx("p",{role:"alert",className:"mb-3 text-sm text-red-400",children:f}):null,e.jsxs("div",{className:"flex justify-end gap-2",children:[e.jsx("button",{ref:d,type:"button",onClick:l,className:"min-h-11 rounded-lg 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:g,disabled:!u||i.isPending,className:"btn btn-danger-solid btn-touch",children:i.isPending?"Removing…":"Remove"})]})]})})}function Le(t){if(t.filename)return t.filename;if(t.path){const a=t.path.split("/").pop();return a||t.path}return t.id}function Ge(){const{id:t}=ce(),a=K(l=>l.getActiveVault()),r=de(t);return a?e.jsxs("div",{className:"page",children:[e.jsx("nav",{className:"mb-6 text-sm text-fg-dim",children:e.jsx($,{to:t?`/n/${encodeURIComponent(t)}`:"/",className:"focus-ring hover:text-accent",children:"← Back to note"})}),r.isPending?e.jsx(Ve,{}):r.isError?e.jsx(_e,{error:r.error}):r.data?e.jsx(Be,{note:r.data}):e.jsx(Oe,{id:t??""})]}):e.jsx(ue,{to:"/",replace:!0})}function S(t){return{content:t.content??"",path:t.path??"",tags:[...t.tags??[]]}}function Be({note:t}){const a=he(),r=H(s=>s.push),l=q(s=>s.on),x=q(s=>s.setOn),i=n.useRef(K.getState().activeVaultId).current,u=n.useRef(Pe()).current,m=n.useMemo(()=>De(t),[t]),[f,N]=n.useState(()=>S(t)),[d,g]=n.useState(()=>S(t)),[o,k]=n.useState(()=>{if(!i)return null;const s=xe(i,t.id);return!s||pe(s.body,S(t))?null:s}),[Z,L]=n.useState(""),[B,C]=n.useState(null),[M,E]=n.useState(null),[U,V]=n.useState(!1),w=n.useRef(null);n.useEffect(()=>()=>{w.current!==null&&window.clearTimeout(w.current)},[]);const[R,G]=n.useState("edit"),j=ge(t.id),A=n.useRef(t),P=n.useRef(null),O=n.useRef(null),v=Se({noteId:t.id,onInsert:s=>{P.current?P.current.insertAtCursor(s):g(c=>({...c,content:`${c.content}${s}`}))},onLinked:()=>{r("Attachment added","success")},onError:s=>r(s,"error")});n.useEffect(()=>{A.current=t},[t]);const h=d.content!==f.content||d.path!==f.path||!ze(d.tags,f.tags);be(i,t.id,d,h);const y=v.uploads.some(s=>s.status==="uploading"||s.status==="linking"),D=n.useCallback(({navigateToView:s})=>{if(!h||j.isPending||y)return;const c={};d.content!==f.content&&(c.content=d.content),d.path!==f.path&&(c.path=d.path);const b=We(f.tags,d.tags);(b.add.length||b.remove.length)&&(c.tags=b);const W=A.current.updatedAt??A.current.createdAt;W&&(c.if_updated_at=W),E(null),C(null),j.mutate(c,{onSuccess:p=>{N(S(p)),g(S(p)),A.current=p,i&&T(i,t.id),s?a(`/n/${encodeURIComponent(p.id)}`,{replace:!0}):p.id!==t.id&&a(`/n/${encodeURIComponent(p.id)}/edit`,{replace:!0}),s||(V(!0),w.current!==null&&window.clearTimeout(w.current),w.current=window.setTimeout(()=>V(!1),1500))},onError:p=>{p instanceof ve?C(p):p instanceof I?E("Session expired. Reconnect to save."):E(p instanceof Error?p.message:"Save failed")}})},[f,d,h,j,a,t.id,y,i]),Q=n.useCallback(()=>{o&&g(o.body),k(null)},[o]),X=n.useCallback(()=>{i&&T(i,t.id),k(null)},[i,t.id]),ee=n.useCallback(()=>D({navigateToView:!0}),[D]),te=n.useCallback(()=>D({navigateToView:!1}),[D]),se=n.useCallback(()=>{h&&confirm("Discard all edits and revert to last saved version?")&&(g(f),C(null),E(null))},[f,h]),_=n.useCallback(()=>{h&&!confirm("Discard unsaved changes?")||(i&&T(i,t.id),a(`/n/${encodeURIComponent(t.id)}`))},[h,a,t.id,i]);n.useEffect(()=>{if(!h)return;const s=c=>{c.preventDefault(),c.returnValue=""};return window.addEventListener("beforeunload",s),()=>window.removeEventListener("beforeunload",s)},[h]);const ne=d.path!==f.path,ae=s=>{const c=we(s);c&&(d.tags.includes(c)||(g(b=>({...b,tags:[...b.tags,c]})),L("")))},re=s=>{g(c=>({...c,tags:c.tags.filter(b=>b!==s)}))},ie=d.content,z=l?"h-[85dvh]":"h-[60dvh]";return e.jsxs("article",{children:[l?e.jsx("div",{className:"glass-panel enter-fade fixed top-4 left-4 z-30 rounded-full border border-border px-3 py-1.5 text-xs shadow-lift",style:{marginTop:"env(safe-area-inset-top)"},children:e.jsx(Y,{isDirty:h,justSaved:U,updatedAt:t.updatedAt})}):e.jsxs("header",{className:"card mb-6 p-5 shadow-soft md:p-6",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:"eyebrow",children:"Editing"}),e.jsx(Y,{isDirty:h,justSaved:U,updatedAt:t.updatedAt})]}),e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[e.jsx(Re,{note:t}),e.jsx(Ae,{note:t}),e.jsxs("button",{type:"button",onClick:()=>x(!0),className:"btn btn-ghost btn-touch",title:"Focus (⌘.)",children:[e.jsx(je,{width:16,height:16}),"Focus"]}),e.jsx("span",{className:"mx-1 h-5 w-px bg-border","aria-hidden":"true"}),e.jsx("button",{type:"button",onClick:se,disabled:!h||j.isPending,className:"btn btn-secondary btn-touch",children:"Revert"}),e.jsx("button",{type:"button",onClick:_,className:"btn btn-secondary btn-touch",children:"Cancel"}),e.jsx("button",{type:"button",onClick:ee,disabled:!h||j.isPending||y,className:"btn btn-primary btn-touch",title:y?"Waiting for upload…":"Save (⌘S)","aria-label":y?"Save — waiting for upload…":"Save",children:j.isPending?"Saving…":"Save"})]})]}),e.jsx("div",{className:"mt-4",children:e.jsx(Ne,{tags:d.tags,input:Z,onInputChange:L,onAdd:ae,onRemove:re})}),e.jsxs("div",{className:"mt-4 flex items-center gap-2 text-fg-dim",children:[e.jsx("span",{"aria-hidden":"true",className:"shrink-0 text-xs",children:"Path"}),e.jsx("input",{type:"text",value:d.path,onChange:s=>g(c=>({...c,path:s.target.value})),className:"focus-ring w-full min-w-0 truncate rounded border-0 bg-transparent font-mono text-xs text-fg-dim outline-none transition-colors hover:text-fg-muted focus:text-fg placeholder:text-fg-dim","aria-label":"Note path",placeholder:"(no path)",title:d.path||void 0})]}),ne?e.jsx("p",{className:"mt-1 text-xs text-accent",children:"Renaming moves the note — its id may change."}):null]}),o?e.jsxs("div",{role:"status","data-testid":"draft-offer",className:"mb-4 flex flex-wrap items-center justify-between gap-2 rounded-xl border border-accent/30 bg-accent/5 px-3 py-2 text-sm",children:[e.jsxs("span",{className:"text-fg-muted",children:["You have an unsaved draft from ",F(o.savedAt),"."]}),e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx("button",{type:"button",onClick:Q,className:"focus-ring font-medium text-accent hover:underline",children:"Restore"}),e.jsx("button",{type:"button",onClick:X,className:"focus-ring text-fg-dim hover:text-danger",children:"Discard"})]})]}):null,B?e.jsx(Ue,{conflict:B,onReload:()=>{i&&T(i,t.id),window.location.reload()},onDismiss:()=>C(null)}):null,M?e.jsx("div",{className:"mb-4 rounded-xl border border-danger-border bg-danger-soft p-3 text-sm text-danger",children:M}):null,u?null:e.jsx("div",{role:"tablist","aria-label":"Editor view",className:"mb-3 inline-flex rounded-lg border border-border bg-card p-0.5 text-sm lg:hidden",children:["edit","preview"].map(s=>e.jsx("button",{type:"button",role:"tab","aria-selected":R===s,onClick:()=>G(s),className:`rounded-sm px-3 py-1.5 capitalize ${R===s?"bg-accent text-on-accent":"text-fg-muted hover:text-accent"}`,children:s},s))}),e.jsxs("div",{className:`grid ${l?"min-h-[85dvh]":"min-h-[60dvh]"} gap-4 ${u?"":"lg:grid-cols-2"}`,children:[e.jsx(ye,{onDropFiles:v.start,className:`card min-h-0 ${z} min-w-0 ${u||R==="edit"?"":"hidden lg:block"}`,hint:J,children:e.jsx(ke,{ref:P,value:d.content,onChange:s=>g(c=>({...c,content:s})),onSave:te,onCancel:_,onPasteFile:s=>(v.start(s),!0),onRequestAttachment:()=>{var s;return(s=O.current)==null?void 0:s.open()},livePreview:u})}),u?null:e.jsx("div",{className:`card min-h-0 ${z} min-w-0 overflow-auto p-4 ${R==="preview"?"":"hidden lg:block"}`,children:e.jsx(Te,{note:{path:d.path,content:ie},resolve:m})})]}),e.jsx(Me,{noteId:t.id,pickerRef:O,attachments:t.attachments??[],uploads:v.uploads,onPickFiles:v.start,onCancel:v.cancel,onDismiss:v.dismiss})]})}const J=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:"text-accent hover:underline",children:"PDF + mp4 coming"})]});function Me({noteId:t,pickerRef:a,attachments:r,uploads:l,onPickFiles:x,onCancel:i,onDismiss:u}){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-xl",children:"Attachments"}),e.jsx(Ce,{ref:a,onPickFiles:x})]}),e.jsxs("p",{className:"mb-3 text-xs text-fg-dim",children:["Drop or paste files into the editor. Max 100 MB each. ",J,"."]}),e.jsx(Ee,{uploads:l,onCancel:i,onDismiss:u}),r.length>0?e.jsx("ul",{className:"mt-3 space-y-1 text-sm",children:r.map(m=>e.jsxs("li",{className:"flex items-center justify-between gap-2 rounded-lg border border-border bg-card/50 px-3 py-1.5 font-mono text-xs",children:[e.jsx("span",{className:"truncate",title:m.path??m.id,children:m.filename??m.path??m.id}),e.jsxs("div",{className:"flex shrink-0 items-center gap-2",children:[m.mimeType?e.jsx("span",{className:"text-fg-dim",children:m.mimeType}):null,e.jsx($e,{noteId:t,attachment:m})]})]},m.id))}):null]})}function Ue({conflict:t,onReload:a,onDismiss:r}){return e.jsxs("div",{className:"mb-4 rounded-xl border border-warning bg-warning-soft p-4",children:[e.jsx("p",{className:"mb-1 font-medium text-warning",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 ${F(t.currentUpdatedAt)}.`:""]}),e.jsxs("div",{className:"flex flex-wrap gap-2",children:[e.jsx("button",{type:"button",onClick:a,className:"btn btn-primary btn-touch",children:"Reload latest (discard my edits)"}),e.jsx("button",{type:"button",onClick:r,className:"btn btn-secondary btn-touch",children:"Keep editing"})]})]})}function Ve(){return e.jsxs("div",{className:"grid min-h-[60dvh] gap-4 lg:grid-cols-2","aria-busy":"true",children:[e.jsx("div",{className:"card animate-pulse"}),e.jsx("div",{className:"card animate-pulse"})]})}function Oe({id:t}){return e.jsx(fe,{title:e.jsx("span",{className:"font-serif text-xl text-fg",children:"Note not found"}),description:e.jsxs(e.Fragment,{children:["No note with id ",e.jsx("span",{className:"font-mono",children:t})," in this vault."]}),action:e.jsx($,{to:"/notes",className:"text-sm text-accent hover:underline",children:"Back to all notes"})})}function Y({isDirty:t,justSaved:a,updatedAt:r}){return t?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"]}):a?e.jsx("span",{className:"text-xs text-accent","aria-label":"saved",children:"Saved ✓"}):e.jsxs("span",{className:"text-xs text-fg-dim",children:["saved ",F(r)]})}function _e({error:t}){const a=t instanceof I;return e.jsx(me,{title:a?"Session expired":"Could not load note",message:t.message,action:a?e.jsx($,{to:"/add",className:"btn btn-primary",children:"Reconnect vault"}):void 0})}function ze(t,a){if(t.length!==a.length)return!1;const r=new Set(t);for(const l of a)if(!r.has(l))return!1;return!0}function We(t,a){const r=new Set(t),l=new Set(a),x=a.filter(u=>!r.has(u)),i=t.filter(u=>!l.has(u));return{add:x,remove:i}}export{Ge as NoteEditor};
@@ -1,8 +1,8 @@
1
- import{ap as _e,r as o,aq as Me,ar as $e,as as he,a as Le,b as Ue,a6 as qe,at as Fe,au as Ve,av as Oe,aw as Ge,a1 as Be,a5 as He,ax as We,ah as Ye,ay as ze,y as Ke,ak as Qe,j as e,N as Ze,az as Je,aA as ge,V as Xe,al as G,aB as et,aC as tt,aD as J,aE as st,aF as nt,aG as at,aH as I,L as rt,an as ot,x as it,aI as ct,ao as lt}from"./index-H6VNro-x.js";import{v as dt,A as ut}from"./attachment-upload-B8YiOVGU.js";import{u as mt,C as pt,A as ft,a as ht}from"./useAttachmentUploader-C78HTrMx.js";import{b as gt,N as xt}from"./NoteRenderer-BXeTxHnB.js";import{l as xe,u as bt,a as vt,b as yt}from"./transcribe-default-B7i-j3pr.js";import{r as jt}from"./editor-mode-D9fveTEx.js";import"./types-BaJkUfo6.js";const kt=30*6e4,wt=20*1024*1024,Rt=1e4;function Nt(t){const c=t.segmentMs??kt,l=t.setTimer??((x,T)=>setTimeout(x,T)),b=t.clearTimer??(x=>clearTimeout(x)),w=t.makeRecorder??(x=>_e({...x,releaseStreamOnStop:!1})),g=[];let n=null,d=null,f="idle",u=0,h=0,y=!1;const m=()=>{for(const x of t.stream.getTracks())x.stop()},r=()=>{d!==null&&(b(d),d=null)},p=()=>{d=l(()=>{d=null,R()},c)},i=()=>{h+=1;const x=h;n=w({stream:t.stream,mimeType:t.mimeType,releaseStreamOnStop:!1,now:t.now,MediaRecorderCtor:t.MediaRecorderCtor,dataIntervalMs:Rt,onData:T=>{x===h&&T>=wt&&R()}}),n.start(),u+=1,p()},R=()=>{var x;f!=="recording"||!n||y||(y=!0,r(),g.push(n.stop()),i(),(x=t.onRoll)==null||x.call(t,u),y=!1)};return{get state(){return f},get activePart(){return u},start(){if(f!=="idle")throw new Error(`Cannot start from ${f}`);f="recording",i()},async stop(){if(f!=="recording"||!n)throw new Error(`Cannot stop from ${f}`);f="stopped",r(),g.push(n.stop()),n=null;const x=await Promise.all(g);return m(),x},cancel(){r(),n&&n.cancel(),n=null,f="stopped",m()}}}function Tt(){const[t,c]=o.useState({kind:"idle"}),[l,b]=o.useState(0),[w,g]=o.useState(0),n=o.useRef(null),d=o.useRef(null);o.useEffect(()=>{if(t.kind!=="recording")return;const m=setInterval(()=>b(Date.now()-t.startedAt),250);return()=>clearInterval(m)},[t]),o.useEffect(()=>()=>{d.current&&URL.revokeObjectURL(d.current),n.current&&n.current.state==="recording"&&n.current.cancel()},[]);const f=o.useCallback(async()=>{if(!(t.kind==="recording"||t.kind==="requesting")){c({kind:"requesting"});try{const m=Me();if(!m){c({kind:"denied",message:"This browser can't record audio in a format we can save."});return}const r=await $e(),p=Nt({stream:r,mimeType:m,onRoll:i=>g(i)});n.current=p,p.start(),b(0),g(p.activePart),c({kind:"recording",startedAt:Date.now()})}catch(m){const r=m,p=r.kind==="permission-denied"?"Microphone access was denied. Update your browser's site settings to record.":r.kind==="no-device"?"No microphone was found on this device.":r instanceof Error?r.message:"Microphone is not available in this browser.";c({kind:"denied",message:p})}}},[t]),u=o.useCallback(async()=>{var r;const m=n.current;if(!(!m||t.kind!=="recording"))try{const p=await m.stop();n.current=null,g(0);const i=((r=p[0])==null?void 0:r.mimeType)??"",R=p.reduce((B,U)=>B+U.durationMs,0),x=p[0],T=x?URL.createObjectURL(new Blob([x.data],{type:x.mimeType})):"";d.current&&URL.revokeObjectURL(d.current),d.current=T||null,c({kind:"have-audio",segments:p,mimeType:i,url:T,durationMs:R})}catch(p){console.warn(p instanceof Error?`Recording failed: ${p.message}`:"Recording failed."),g(0),c({kind:"idle"})}},[t]),h=o.useCallback(()=>{d.current&&(URL.revokeObjectURL(d.current),d.current=null),c({kind:"idle"}),b(0),g(0)},[]),y=o.useCallback(()=>{h()},[h]);return{phase:t,elapsedMs:l,parts:w,startRecording:f,stopRecording:u,discardAudio:h,reset:y}}function St(t){const{segments:c,mimeType:l,recordedAt:b,willTranscribe:w}=t,g=c.length>1,n=t.typedText.trim(),d=c.map((y,m)=>({filename:g?he(l,b,m+1):he(l,b),transcribe:w,...w&&g?{segment_index:m}:{}})),f=w?g?c.map((y,m)=>`_Transcript pending (part ${m+1})._`).join(`
1
+ import{ar as _e,r as o,as as Me,at as $e,au as he,a as Le,b as Ue,a8 as qe,av as Fe,aw as Ve,ax as Oe,ay as Ge,a3 as Be,a7 as He,az as We,aj as Ke,aA as Ye,C as ze,am as Je,j as e,N as Qe,aB as Ze,aC as ge,V as Xe,an as G,aD as et,aE as tt,aF as Z,aG as st,aH as nt,aI as at,aJ as I,L as rt,ap as ot,A as it,aK as ct,aq as lt}from"./index-CpyANXLa.js";import{v as dt,A as ut}from"./attachment-upload-DbV0j1WH.js";import{u as mt,C as pt,A as ft,a as ht}from"./useAttachmentUploader-t5hlKCgS.js";import{b as gt,N as xt}from"./NoteRenderer-BzRFYOTP.js";import{l as xe,u as bt,a as vt,b as yt}from"./transcribe-default-DIcTpM6A.js";import{r as jt}from"./editor-mode-D9fveTEx.js";import"./types-BaJkUfo6.js";const kt=30*6e4,wt=20*1024*1024,Rt=1e4;function Nt(t){const c=t.segmentMs??kt,l=t.setTimer??((x,T)=>setTimeout(x,T)),b=t.clearTimer??(x=>clearTimeout(x)),w=t.makeRecorder??(x=>_e({...x,releaseStreamOnStop:!1})),g=[];let n=null,d=null,f="idle",u=0,h=0,y=!1;const m=()=>{for(const x of t.stream.getTracks())x.stop()},r=()=>{d!==null&&(b(d),d=null)},p=()=>{d=l(()=>{d=null,R()},c)},i=()=>{h+=1;const x=h;n=w({stream:t.stream,mimeType:t.mimeType,releaseStreamOnStop:!1,now:t.now,MediaRecorderCtor:t.MediaRecorderCtor,dataIntervalMs:Rt,onData:T=>{x===h&&T>=wt&&R()}}),n.start(),u+=1,p()},R=()=>{var x;f!=="recording"||!n||y||(y=!0,r(),g.push(n.stop()),i(),(x=t.onRoll)==null||x.call(t,u),y=!1)};return{get state(){return f},get activePart(){return u},start(){if(f!=="idle")throw new Error(`Cannot start from ${f}`);f="recording",i()},async stop(){if(f!=="recording"||!n)throw new Error(`Cannot stop from ${f}`);f="stopped",r(),g.push(n.stop()),n=null;const x=await Promise.all(g);return m(),x},cancel(){r(),n&&n.cancel(),n=null,f="stopped",m()}}}function Tt(){const[t,c]=o.useState({kind:"idle"}),[l,b]=o.useState(0),[w,g]=o.useState(0),n=o.useRef(null),d=o.useRef(null);o.useEffect(()=>{if(t.kind!=="recording")return;const m=setInterval(()=>b(Date.now()-t.startedAt),250);return()=>clearInterval(m)},[t]),o.useEffect(()=>()=>{d.current&&URL.revokeObjectURL(d.current),n.current&&n.current.state==="recording"&&n.current.cancel()},[]);const f=o.useCallback(async()=>{if(!(t.kind==="recording"||t.kind==="requesting")){c({kind:"requesting"});try{const m=Me();if(!m){c({kind:"denied",message:"This browser can't record audio in a format we can save."});return}const r=await $e(),p=Nt({stream:r,mimeType:m,onRoll:i=>g(i)});n.current=p,p.start(),b(0),g(p.activePart),c({kind:"recording",startedAt:Date.now()})}catch(m){const r=m,p=r.kind==="permission-denied"?"Microphone access was denied. Update your browser's site settings to record.":r.kind==="no-device"?"No microphone was found on this device.":r instanceof Error?r.message:"Microphone is not available in this browser.";c({kind:"denied",message:p})}}},[t]),u=o.useCallback(async()=>{var r;const m=n.current;if(!(!m||t.kind!=="recording"))try{const p=await m.stop();n.current=null,g(0);const i=((r=p[0])==null?void 0:r.mimeType)??"",R=p.reduce((B,U)=>B+U.durationMs,0),x=p[0],T=x?URL.createObjectURL(new Blob([x.data],{type:x.mimeType})):"";d.current&&URL.revokeObjectURL(d.current),d.current=T||null,c({kind:"have-audio",segments:p,mimeType:i,url:T,durationMs:R})}catch(p){console.warn(p instanceof Error?`Recording failed: ${p.message}`:"Recording failed."),g(0),c({kind:"idle"})}},[t]),h=o.useCallback(()=>{d.current&&(URL.revokeObjectURL(d.current),d.current=null),c({kind:"idle"}),b(0),g(0)},[]),y=o.useCallback(()=>{h()},[h]);return{phase:t,elapsedMs:l,parts:w,startRecording:f,stopRecording:u,discardAudio:h,reset:y}}function St(t){const{segments:c,mimeType:l,recordedAt:b,willTranscribe:w}=t,g=c.length>1,n=t.typedText.trim(),d=c.map((y,m)=>({filename:g?he(l,b,m+1):he(l,b),transcribe:w,...w&&g?{segment_index:m}:{}})),f=w?g?c.map((y,m)=>`_Transcript pending (part ${m+1})._`).join(`
2
2
 
3
3
  `):"_Transcript pending._":"",u=d.map(y=>`![[${y.filename}]]`).join(`
4
4
 
5
5
  `),h=[];return n&&h.push(n),f&&h.push(f),h.push(u),{body:`${h.join(`
6
6
 
7
7
  `)}
8
- `,segments:d}}const be={content:"",path:"",tags:[]};function Ut(){const t=Le(s=>s.getActiveVault()),c=Ue(),l=qe(s=>s.push),b=Fe(),w=Ve(),g=Oe(),{db:n,blobStore:d,engine:f}=Ge(),{roles:u}=Be((t==null?void 0:t.id)??null),h=He(),y=o.useRef(We()),m=o.useRef(jt()).current,r=o.useRef((t==null?void 0:t.id)??null).current,p=o.useRef(null),[i,R]=o.useState(()=>{if(r){const s=Ye(r,I);if(s)return p.current=s.savedAt,s.body}return{...be,path:y.current}}),[x,T]=o.useState(()=>p.current),[B,U]=o.useState(""),[ee,C]=o.useState(null),[q,ye]=o.useState([]),[je,te]=o.useState(!1),H=o.useRef(null),se=o.useRef(null),v=Tt(),D=ze(),N=D.capability,ke=v.phase.kind==="requesting"||v.phase.kind==="recording"||v.phase.kind==="have-audio",we=(N==null?void 0:N.enabled)===!1&&!ke,W=typeof(N==null?void 0:N.minutes_remaining)=="number"?N.minutes_remaining:void 0,Y=W!==void 0&&W<=0,[z,ne]=o.useState(()=>r?xe(r):!0),Re=(N==null?void 0:N.enabled)!==!1,ae=o.useRef(v.phase.kind);o.useEffect(()=>{const s=ae.current,a=v.phase.kind;ae.current=a,a==="idle"&&s!=="idle"&&r&&ne(xe(r))},[v.phase.kind,r]);const[Ne]=Ke(),re=Ne.has("voice"),oe=o.useRef(!1);o.useEffect(()=>{var s;!re||oe.current||D.settled&&((s=D.capability)==null?void 0:s.enabled)!==!1&&(oe.current=!0,v.startRecording())},[re,D.settled,D.capability,v.startRecording]);const A=mt({noteId:null,onInsert:s=>{H.current?H.current.insertAtCursor(s):R(a=>({...a,content:`${a.content}${s}`}))},onStaged:s=>ye(a=>[...a,s]),onError:s=>l(s,"error")}),_=o.useRef(p.current!==null),F=o.useRef(null);o.useEffect(()=>{_.current||(R(s=>{const a=F.current?s.tags.filter(P=>P!==F.current):s.tags,j=a.includes(u.captureText)?a:[...a,u.captureText];return j===s.tags?s:{...s,tags:j}}),F.current=u.captureText)},[u.captureText]);const ie=!_.current&&(i.tags.length===0||i.tags.length===1&&i.tags[0]===u.captureText),Te=i.content.trim().length>0||!ie||i.path.trim().length>0&&i.path!==y.current;if(Qe(r,I,i,Te),!t)return e.jsx(Ze,{to:"/",replace:!0});const M=v.phase.kind==="have-audio",K=i.content.trim().length>0,V=i.content.length>0||i.path!==y.current||!ie||M,$=i.path.trim().length>0&&(K||M),E=b.isPending||je,ce=o.useCallback(()=>{if(!$||E)return;const s=Je({content:i.content,path:i.path,tags:i.tags});h&&ge(t.id,h),C(null),b.mutate(s,{onSuccess:async a=>{for(const j of q)try{await w.mutateAsync({noteId:a.id,path:j.path,mimeType:j.mimeType})}catch(P){const Q=P instanceof Error?P.message:"Link failed";l(`Failed to attach ${j.filename}: ${Q}`,"error")}r&&G(r,I),l(`Created ${a.path??a.id}`,"success"),c(`/n/${encodeURIComponent(a.id)}`,{replace:!0})},onError:a=>{a instanceof Xe?C("Session expired. Reconnect to save."):C(a instanceof Error?`${a.message} — if the path is taken, try a different one.`:"Create failed")}})},[t,r,h,i,$,w,b,c,E,l,q]),le=o.useCallback(async()=>{if(!$||E||v.phase.kind!=="have-audio")return;if(!n||!d){l("Sync queue not ready — try again in a moment.","error");return}C(null);const s=v.phase,a=s.segments,j=s.mimeType,P=i.path.trim(),Q=i.tags,Pe=et(i.content),me=Array.from(new Set([u.captureVoice,...Q,...Pe].filter(k=>k.length>0)));K&&me.push(u.captureText);const pe=Array.from(new Set(me)),Ie=new Date,L=tt(),De=!Y&&z,O=St({segments:a,mimeType:j,typedText:i.content,recordedAt:Ie,willTranscribe:De});for(let k=0;k<a.length;k++){const S=dt(new File([a[k].data],O.segments[k].filename,{type:j}));if(S){l(S,"error"),C(S);return}}te(!0),h&&ge(t.id,h);const fe={content:O.body,path:P,metadata:{source:"voice"},...pe.length?{tags:pe}:{}};try{await J(n,{kind:"create-note",localId:L,payload:fe},{vaultId:t.id});for(let k=0;k<O.segments.length;k++){const S=O.segments[k],Z=st();await d.put(Z,a[k].data,j,t.id),await J(n,{kind:"upload-attachment",blobId:Z,filename:S.filename,mimeType:j},{vaultId:t.id}),await J(n,{kind:"link-attachment",noteId:L,pathRef:nt(Z),mimeType:j,transcribe:S.transcribe,...S.segment_index!==void 0?{segment_index:S.segment_index}:{}},{vaultId:t.id})}f==null||f.runOnce(),g.setQueryData(["note",t.id,L],at(fe,L)),r&&G(r,I),l("Captured — syncing audio.","success"),v.discardAudio(),c(`/n/${encodeURIComponent(L)}`,{replace:!0})}catch(k){l(k instanceof Error?`Capture failed: ${k.message}`:"Capture failed.","error"),C(k instanceof Error?k.message:"Capture failed")}finally{te(!1)}},[t,r,d,h,n,i,f,K,$,c,Y,E,l,g,u.captureText,u.captureVoice,z,v]),de=o.useCallback(()=>{M?le():ce()},[M,ce,le]),ue=o.useCallback(()=>{V&&!confirm("Discard this draft?")||(r&&G(r,I),v.discardAudio(),c("/"))},[r,V,c,v]),Se=o.useCallback(()=>{r&&G(r,I),_.current=!1,F.current=u.captureText,R({...be,path:y.current,tags:[u.captureText]}),v.discardAudio(),T(null)},[r,v,u.captureText]);o.useEffect(()=>{if(!V)return;const s=a=>{a.preventDefault(),a.returnValue=""};return window.addEventListener("beforeunload",s),()=>window.removeEventListener("beforeunload",s)},[V]);const Ce=s=>{const a=lt(s);!a||i.tags.includes(a)||(_.current=!0,R(j=>({...j,tags:[...j.tags,a]})),U(""))},Ae=s=>{_.current=!0,R(a=>({...a,tags:a.tags.filter(j=>j!==s)}))},Ee=gt({id:"__new__",createdAt:new Date().toISOString()});return e.jsxs("div",{className:"page",children:[e.jsx("nav",{className:"mb-6 text-sm text-fg-dim",children:e.jsx(rt,{to:"/notes",className:"hover:text-accent",children:"← All notes"})}),e.jsxs("article",{children:[e.jsxs("header",{className:"composer mb-6 p-5 md:p-6",children:[e.jsxs("div",{className:"flex flex-wrap items-center justify-between gap-3",children:[e.jsx("span",{className:"eyebrow",children:"New note"}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("button",{type:"button",onClick:ue,className:"btn btn-secondary btn-touch",children:"Cancel"}),e.jsx("button",{type:"button",onClick:de,disabled:!$||E,className:"btn btn-primary btn-touch",title:"Create (⌘S)",children:E?"Creating…":"Create"})]})]}),e.jsx("input",{type:"text",value:i.path,onChange:s=>R(a=>({...a,path:s.target.value})),className:i.path===y.current?"mt-4 w-full border-0 bg-transparent font-sans text-sm text-fg-dim outline-none placeholder:text-fg-dim":"mt-4 w-full border-0 bg-transparent font-serif text-2xl text-fg outline-none placeholder:text-fg-dim md:text-3xl","aria-label":"Note path",placeholder:"Name your note — or just start writing"}),e.jsx("div",{className:"mt-4",children:e.jsx(ot,{tags:i.tags,input:B,onInputChange:U,onAdd:Ce,onRemove:Ae})})]}),x?e.jsxs("div",{role:"status","data-testid":"draft-restored",className:"mb-4 flex flex-wrap items-center justify-between gap-2 rounded-xl border border-accent/30 bg-accent/5 px-3 py-2 text-sm",children:[e.jsxs("span",{className:"text-fg-muted",children:["Unsaved draft restored from ",it(x),"."]}),e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx("button",{type:"button",onClick:Se,className:"text-fg-dim hover:text-danger",children:"Discard draft"}),e.jsx("button",{type:"button",onClick:()=>T(null),"aria-label":"Dismiss draft-restored notice",className:"text-fg-dim hover:text-accent",children:"✕"})]})]}):null,ee?e.jsx("div",{role:"alert",className:"mb-4 rounded-xl border border-danger-border bg-danger-soft p-3 text-sm text-danger",children:ee}):null,we?e.jsx(ct,{capability:N}):e.jsxs(e.Fragment,{children:[e.jsx(Et,{voice:v,minutesRemaining:W,outOfMinutes:Y,transcribe:z,onTranscribeChange:ne,showTranscribeToggle:Re}),e.jsx(Ct,{vaultId:t.id,captureEngaged:M})]}),e.jsxs("div",{className:`grid min-h-[60dvh] gap-4 ${m?"":"lg:grid-cols-2"}`,children:[e.jsx(ut,{onDropFiles:A.start,className:"card min-h-0 h-[60dvh] min-w-0",hint:"Images, audio, webm video",children:e.jsx(pt,{ref:H,value:i.content,onChange:s=>R(a=>({...a,content:s})),onSave:de,onCancel:ue,placeholder:"Start writing…",onPasteFile:s=>(A.start(s),!0),onRequestAttachment:()=>{var s;return(s=se.current)==null?void 0:s.open()},livePreview:m})}),m?null:e.jsx("div",{className:"card min-w-0 overflow-auto p-4 lg:h-[60dvh] lg:min-h-0",children:i.content.trim()?e.jsx(xt,{note:{path:i.path,content:i.content},resolve:Ee}):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-xl",children:"Attachments"}),e.jsx(ft,{ref:se,onPickFiles:A.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:"text-accent hover:underline",children:"PDF + mp4 coming"}),"."]}),e.jsx(ht,{uploads:A.uploads,onCancel:A.cancel,onDismiss:A.dismiss}),q.length>0?e.jsx("ul",{className:"mt-3 space-y-1 text-sm",children:q.map(s=>e.jsxs("li",{className:"flex items-center justify-between gap-2 rounded-lg 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:s.filename}),e.jsx("span",{className:"shrink-0 text-fg-dim",children:"staged"})]},s.path))}):null]})]})]})}function Ct({vaultId:t,captureEngaged:c}){const l=bt(),b=vt(),{made:w,markMade:g}=yt(t),[n,d]=o.useState(null);if(!(c&&!w&&l.supported&&l.value==="keep"))return null;const u=h=>{d(null),b.mutate(h,{onSuccess:()=>g(),onError:()=>d("Couldn't save that choice — this recording is kept (the vault default). We'll ask again next time; you can also set it in Settings.")})};return e.jsxs("div",{"data-testid":"retention-choice",className:"mb-4 flex flex-col gap-2 rounded-xl border border-border bg-card/60 p-3",children:[e.jsx("p",{className:"text-xs text-fg-muted",children:"First voice note here — should this vault keep your audio files after transcribing?"}),e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[e.jsx("button",{type:"button",onClick:()=>u("keep"),disabled:b.isPending,className:"btn btn-secondary btn-touch",children:"Keep my recordings"}),e.jsx("button",{type:"button",onClick:()=>u("until_transcribed"),disabled:b.isPending,className:"btn btn-secondary btn-touch",children:"Just keep the words"}),e.jsx("span",{className:"text-xs text-fg-dim",children:"(audio deleted after transcribing)"})]}),e.jsx("p",{className:"text-xs text-fg-dim",children:"Either way your capture saves now. Change this anytime in Settings."}),n?e.jsx("p",{className:"text-xs text-danger","data-testid":"retention-choice-error",children:n}):null]})}const At=30;function ve({checked:t,disabled:c,onChange:l}){return e.jsxs("div",{className:"flex basis-full items-center gap-3",children:[e.jsx("span",{className:"text-xs text-fg-dim",children:"Transcribe this recording"}),e.jsx("button",{type:"button",role:"switch","aria-checked":t,"aria-label":"Transcribe this recording","data-testid":"transcribe-toggle",disabled:c,onClick:()=>l(!t),className:`relative h-7 w-12 shrink-0 rounded-full transition-colors disabled:opacity-40 ${t?"bg-accent":"bg-border"}`,children:e.jsx("span",{className:`absolute top-0.5 left-0 h-6 w-6 rounded-full bg-card shadow-sm transition-transform ${t?"translate-x-5":"translate-x-0.5"}`})})]})}function Et({voice:t,minutesRemaining:c,outOfMinutes:l,transcribe:b,onTranscribeChange:w,showTranscribeToggle:g}){const{phase:n,elapsedMs:d,parts:f,startRecording:u,stopRecording:h,discardAudio:y}=t,m=n.kind==="recording",r=n.kind==="requesting",p=!l&&b,i=typeof c=="number"&&c<=At;return n.kind==="have-audio"?e.jsxs("div",{className:"mb-4 flex flex-col gap-2 rounded-xl border border-accent/30 bg-accent/5 p-3",children:[e.jsxs("div",{className:"flex items-center justify-between gap-3",children:[e.jsxs("span",{className:"text-sm text-fg-muted",children:["🎙 Recorded ",X(n.durationMs),n.segments.length>1?` · ${n.segments.length} parts`:""]}),e.jsx("button",{type:"button",onClick:y,className:"text-xs text-fg-dim hover:text-danger",children:"Discard"})]}),e.jsx("audio",{controls:!0,src:n.url,className:"w-full",children:e.jsx("track",{kind:"captions"})}),g?e.jsx(ve,{checked:p,disabled:l,onChange:w}):null,e.jsx("p",{className:"text-xs text-fg-dim",children:l?"Saved as audio-only — you're out of transcription minutes this month.":p?"Transcript will be appended once your vault processes it. Save to commit.":"Saved as audio-only — transcription is off for this recording."})]}):e.jsxs("div",{className:"mb-4 flex flex-wrap items-center justify-between gap-3 rounded-xl border border-border bg-card/60 p-3",children:[e.jsx("div",{className:"text-xs text-fg-dim",children:m?f>1?`Recording — tap Stop to finish. (part ${f})`:"Recording — tap Stop to finish.":r?"Requesting microphone…":l?"You're out of transcription minutes this month — this saves as audio-only.":p?"Add a voice memo to this note. Audio gets transcribed and appended.":"Add a voice memo to this note. Saved as audio-only — transcription is off for this recording."}),m?e.jsxs("button",{type:"button",onClick:()=>void h(),"aria-label":`Recording — ${X(d)} — stop`,"aria-pressed":"true",className:"flex min-h-11 items-center gap-2 rounded-full border border-danger-border bg-danger-soft px-4 py-2 text-sm font-medium text-danger",children:[e.jsx("span",{"aria-hidden":"true",className:"animate-pulse",children:"🎙"}),e.jsxs("span",{children:["Stop ",X(d)]})]}):e.jsxs("button",{type:"button",onClick:()=>void u(),"aria-label":"Record voice memo",disabled:r,className:"flex min-h-11 items-center gap-2 rounded-full border border-accent/30 bg-accent/10 px-4 py-2 text-sm font-medium text-accent hover:bg-accent/15 disabled:opacity-40",children:[e.jsx("span",{"aria-hidden":"true",children:"🎙"}),e.jsx("span",{children:r?"Requesting…":"Record"})]}),g?e.jsx(ve,{checked:p,disabled:l,onChange:w}):null,i&&!l?e.jsxs("p",{className:"basis-full text-xs text-fg-dim","data-testid":"voice-minutes-left",children:["About ",Math.round(c)," min of transcription left this month."]}):null,n.kind==="denied"?e.jsx("p",{className:"basis-full rounded-xl border border-danger-border bg-danger-soft px-3 py-2 text-xs text-danger",children:n.message}):null]})}function X(t){const c=Math.floor(t/1e3),l=Math.floor(c/60),b=c%60;return`${String(l).padStart(2,"0")}:${String(b).padStart(2,"0")}`}export{Ut as NoteNew};
8
+ `,segments:d}}const be={content:"",path:"",tags:[]};function Ut(){const t=Le(s=>s.getActiveVault()),c=Ue(),l=qe(s=>s.push),b=Fe(),w=Ve(),g=Oe(),{db:n,blobStore:d,engine:f}=Ge(),{roles:u}=Be((t==null?void 0:t.id)??null),h=He(),y=o.useRef(We()),m=o.useRef(jt()).current,r=o.useRef((t==null?void 0:t.id)??null).current,p=o.useRef(null),[i,R]=o.useState(()=>{if(r){const s=Ke(r,I);if(s)return p.current=s.savedAt,s.body}return{...be,path:y.current}}),[x,T]=o.useState(()=>p.current),[B,U]=o.useState(""),[ee,C]=o.useState(null),[q,ye]=o.useState([]),[je,te]=o.useState(!1),H=o.useRef(null),se=o.useRef(null),v=Tt(),D=Ye(),N=D.capability,ke=v.phase.kind==="requesting"||v.phase.kind==="recording"||v.phase.kind==="have-audio",we=(N==null?void 0:N.enabled)===!1&&!ke,W=typeof(N==null?void 0:N.minutes_remaining)=="number"?N.minutes_remaining:void 0,K=W!==void 0&&W<=0,[Y,ne]=o.useState(()=>r?xe(r):!0),Re=(N==null?void 0:N.enabled)!==!1,ae=o.useRef(v.phase.kind);o.useEffect(()=>{const s=ae.current,a=v.phase.kind;ae.current=a,a==="idle"&&s!=="idle"&&r&&ne(xe(r))},[v.phase.kind,r]);const[Ne]=ze(),re=Ne.has("voice"),oe=o.useRef(!1);o.useEffect(()=>{var s;!re||oe.current||D.settled&&((s=D.capability)==null?void 0:s.enabled)!==!1&&(oe.current=!0,v.startRecording())},[re,D.settled,D.capability,v.startRecording]);const A=mt({noteId:null,onInsert:s=>{H.current?H.current.insertAtCursor(s):R(a=>({...a,content:`${a.content}${s}`}))},onStaged:s=>ye(a=>[...a,s]),onError:s=>l(s,"error")}),_=o.useRef(p.current!==null),F=o.useRef(null);o.useEffect(()=>{_.current||(R(s=>{const a=F.current?s.tags.filter(P=>P!==F.current):s.tags,j=a.includes(u.captureText)?a:[...a,u.captureText];return j===s.tags?s:{...s,tags:j}}),F.current=u.captureText)},[u.captureText]);const ie=!_.current&&(i.tags.length===0||i.tags.length===1&&i.tags[0]===u.captureText),Te=i.content.trim().length>0||!ie||i.path.trim().length>0&&i.path!==y.current;if(Je(r,I,i,Te),!t)return e.jsx(Qe,{to:"/",replace:!0});const M=v.phase.kind==="have-audio",z=i.content.trim().length>0,V=i.content.length>0||i.path!==y.current||!ie||M,$=i.path.trim().length>0&&(z||M),E=b.isPending||je,ce=o.useCallback(()=>{if(!$||E)return;const s=Ze({content:i.content,path:i.path,tags:i.tags});h&&ge(t.id,h),C(null),b.mutate(s,{onSuccess:async a=>{for(const j of q)try{await w.mutateAsync({noteId:a.id,path:j.path,mimeType:j.mimeType})}catch(P){const J=P instanceof Error?P.message:"Link failed";l(`Failed to attach ${j.filename}: ${J}`,"error")}r&&G(r,I),l(`Created ${a.path??a.id}`,"success"),c(`/n/${encodeURIComponent(a.id)}`,{replace:!0})},onError:a=>{a instanceof Xe?C("Session expired. Reconnect to save."):C(a instanceof Error?`${a.message} — if the path is taken, try a different one.`:"Create failed")}})},[t,r,h,i,$,w,b,c,E,l,q]),le=o.useCallback(async()=>{if(!$||E||v.phase.kind!=="have-audio")return;if(!n||!d){l("Sync queue not ready — try again in a moment.","error");return}C(null);const s=v.phase,a=s.segments,j=s.mimeType,P=i.path.trim(),J=i.tags,Pe=et(i.content),me=Array.from(new Set([u.captureVoice,...J,...Pe].filter(k=>k.length>0)));z&&me.push(u.captureText);const pe=Array.from(new Set(me)),Ie=new Date,L=tt(),De=!K&&Y,O=St({segments:a,mimeType:j,typedText:i.content,recordedAt:Ie,willTranscribe:De});for(let k=0;k<a.length;k++){const S=dt(new File([a[k].data],O.segments[k].filename,{type:j}));if(S){l(S,"error"),C(S);return}}te(!0),h&&ge(t.id,h);const fe={content:O.body,path:P,metadata:{source:"voice"},...pe.length?{tags:pe}:{}};try{await Z(n,{kind:"create-note",localId:L,payload:fe},{vaultId:t.id});for(let k=0;k<O.segments.length;k++){const S=O.segments[k],Q=st();await d.put(Q,a[k].data,j,t.id),await Z(n,{kind:"upload-attachment",blobId:Q,filename:S.filename,mimeType:j},{vaultId:t.id}),await Z(n,{kind:"link-attachment",noteId:L,pathRef:nt(Q),mimeType:j,transcribe:S.transcribe,...S.segment_index!==void 0?{segment_index:S.segment_index}:{}},{vaultId:t.id})}f==null||f.runOnce(),g.setQueryData(["note",t.id,L],at(fe,L)),r&&G(r,I),l("Captured — syncing audio.","success"),v.discardAudio(),c(`/n/${encodeURIComponent(L)}`,{replace:!0})}catch(k){l(k instanceof Error?`Capture failed: ${k.message}`:"Capture failed.","error"),C(k instanceof Error?k.message:"Capture failed")}finally{te(!1)}},[t,r,d,h,n,i,f,z,$,c,K,E,l,g,u.captureText,u.captureVoice,Y,v]),de=o.useCallback(()=>{M?le():ce()},[M,ce,le]),ue=o.useCallback(()=>{V&&!confirm("Discard this draft?")||(r&&G(r,I),v.discardAudio(),c("/"))},[r,V,c,v]),Se=o.useCallback(()=>{r&&G(r,I),_.current=!1,F.current=u.captureText,R({...be,path:y.current,tags:[u.captureText]}),v.discardAudio(),T(null)},[r,v,u.captureText]);o.useEffect(()=>{if(!V)return;const s=a=>{a.preventDefault(),a.returnValue=""};return window.addEventListener("beforeunload",s),()=>window.removeEventListener("beforeunload",s)},[V]);const Ce=s=>{const a=lt(s);!a||i.tags.includes(a)||(_.current=!0,R(j=>({...j,tags:[...j.tags,a]})),U(""))},Ae=s=>{_.current=!0,R(a=>({...a,tags:a.tags.filter(j=>j!==s)}))},Ee=gt({id:"__new__",createdAt:new Date().toISOString()});return e.jsxs("div",{className:"page",children:[e.jsx("nav",{className:"mb-6 text-sm text-fg-dim",children:e.jsx(rt,{to:"/notes",className:"hover:text-accent",children:"← All notes"})}),e.jsxs("article",{children:[e.jsxs("header",{className:"composer mb-6 p-5 md:p-6",children:[e.jsxs("div",{className:"flex flex-wrap items-center justify-between gap-3",children:[e.jsx("span",{className:"eyebrow",children:"New note"}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("button",{type:"button",onClick:ue,className:"btn btn-secondary btn-touch",children:"Cancel"}),e.jsx("button",{type:"button",onClick:de,disabled:!$||E,className:"btn btn-primary btn-touch",title:"Create (⌘S)",children:E?"Creating…":"Create"})]})]}),e.jsx("input",{type:"text",value:i.path,onChange:s=>R(a=>({...a,path:s.target.value})),className:i.path===y.current?"mt-4 w-full border-0 bg-transparent font-sans text-sm text-fg-dim outline-none placeholder:text-fg-dim":"mt-4 w-full border-0 bg-transparent font-serif text-2xl text-fg outline-none placeholder:text-fg-dim md:text-3xl","aria-label":"Note path",placeholder:"Name your note — or just start writing"}),e.jsx("div",{className:"mt-4",children:e.jsx(ot,{tags:i.tags,input:B,onInputChange:U,onAdd:Ce,onRemove:Ae})})]}),x?e.jsxs("div",{role:"status","data-testid":"draft-restored",className:"mb-4 flex flex-wrap items-center justify-between gap-2 rounded-xl border border-accent/30 bg-accent/5 px-3 py-2 text-sm",children:[e.jsxs("span",{className:"text-fg-muted",children:["Unsaved draft restored from ",it(x),"."]}),e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx("button",{type:"button",onClick:Se,className:"text-fg-dim hover:text-danger",children:"Discard draft"}),e.jsx("button",{type:"button",onClick:()=>T(null),"aria-label":"Dismiss draft-restored notice",className:"text-fg-dim hover:text-accent",children:"✕"})]})]}):null,ee?e.jsx("div",{role:"alert",className:"mb-4 rounded-xl border border-danger-border bg-danger-soft p-3 text-sm text-danger",children:ee}):null,we?e.jsx(ct,{capability:N}):e.jsxs(e.Fragment,{children:[e.jsx(Et,{voice:v,minutesRemaining:W,outOfMinutes:K,transcribe:Y,onTranscribeChange:ne,showTranscribeToggle:Re}),e.jsx(Ct,{vaultId:t.id,captureEngaged:M})]}),e.jsxs("div",{className:`grid min-h-[60dvh] gap-4 ${m?"":"lg:grid-cols-2"}`,children:[e.jsx(ut,{onDropFiles:A.start,className:"card min-h-0 h-[60dvh] min-w-0",hint:"Images, audio, webm video",children:e.jsx(pt,{ref:H,value:i.content,onChange:s=>R(a=>({...a,content:s})),onSave:de,onCancel:ue,placeholder:"Start writing…",onPasteFile:s=>(A.start(s),!0),onRequestAttachment:()=>{var s;return(s=se.current)==null?void 0:s.open()},livePreview:m})}),m?null:e.jsx("div",{className:"card min-w-0 overflow-auto p-4 lg:h-[60dvh] lg:min-h-0",children:i.content.trim()?e.jsx(xt,{note:{path:i.path,content:i.content},resolve:Ee}):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-xl",children:"Attachments"}),e.jsx(ft,{ref:se,onPickFiles:A.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:"text-accent hover:underline",children:"PDF + mp4 coming"}),"."]}),e.jsx(ht,{uploads:A.uploads,onCancel:A.cancel,onDismiss:A.dismiss}),q.length>0?e.jsx("ul",{className:"mt-3 space-y-1 text-sm",children:q.map(s=>e.jsxs("li",{className:"flex items-center justify-between gap-2 rounded-lg 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:s.filename}),e.jsx("span",{className:"shrink-0 text-fg-dim",children:"staged"})]},s.path))}):null]})]})]})}function Ct({vaultId:t,captureEngaged:c}){const l=bt(),b=vt(),{made:w,markMade:g}=yt(t),[n,d]=o.useState(null);if(!(c&&!w&&l.supported&&l.value==="keep"))return null;const u=h=>{d(null),b.mutate(h,{onSuccess:()=>g(),onError:()=>d("Couldn't save that choice — this recording is kept (the vault default). We'll ask again next time; you can also set it in Settings.")})};return e.jsxs("div",{"data-testid":"retention-choice",className:"mb-4 flex flex-col gap-2 rounded-xl border border-border bg-card/60 p-3",children:[e.jsx("p",{className:"text-xs text-fg-muted",children:"First voice note here — should this vault keep your audio files after transcribing?"}),e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[e.jsx("button",{type:"button",onClick:()=>u("keep"),disabled:b.isPending,className:"btn btn-secondary btn-touch",children:"Keep my recordings"}),e.jsx("button",{type:"button",onClick:()=>u("until_transcribed"),disabled:b.isPending,className:"btn btn-secondary btn-touch",children:"Just keep the words"}),e.jsx("span",{className:"text-xs text-fg-dim",children:"(audio deleted after transcribing)"})]}),e.jsx("p",{className:"text-xs text-fg-dim",children:"Either way your capture saves now. Change this anytime in Settings."}),n?e.jsx("p",{className:"text-xs text-danger","data-testid":"retention-choice-error",children:n}):null]})}const At=30;function ve({checked:t,disabled:c,onChange:l}){return e.jsxs("div",{className:"flex basis-full items-center gap-3",children:[e.jsx("span",{className:"text-xs text-fg-dim",children:"Transcribe this recording"}),e.jsx("button",{type:"button",role:"switch","aria-checked":t,"aria-label":"Transcribe this recording","data-testid":"transcribe-toggle",disabled:c,onClick:()=>l(!t),className:`relative h-7 w-12 shrink-0 rounded-full transition-colors disabled:opacity-40 ${t?"bg-accent":"bg-border"}`,children:e.jsx("span",{className:`absolute top-0.5 left-0 h-6 w-6 rounded-full bg-card shadow-sm transition-transform ${t?"translate-x-5":"translate-x-0.5"}`})})]})}function Et({voice:t,minutesRemaining:c,outOfMinutes:l,transcribe:b,onTranscribeChange:w,showTranscribeToggle:g}){const{phase:n,elapsedMs:d,parts:f,startRecording:u,stopRecording:h,discardAudio:y}=t,m=n.kind==="recording",r=n.kind==="requesting",p=!l&&b,i=typeof c=="number"&&c<=At;return n.kind==="have-audio"?e.jsxs("div",{className:"mb-4 flex flex-col gap-2 rounded-xl border border-accent/30 bg-accent/5 p-3",children:[e.jsxs("div",{className:"flex items-center justify-between gap-3",children:[e.jsxs("span",{className:"text-sm text-fg-muted",children:["🎙 Recorded ",X(n.durationMs),n.segments.length>1?` · ${n.segments.length} parts`:""]}),e.jsx("button",{type:"button",onClick:y,className:"text-xs text-fg-dim hover:text-danger",children:"Discard"})]}),e.jsx("audio",{controls:!0,src:n.url,className:"w-full",children:e.jsx("track",{kind:"captions"})}),g?e.jsx(ve,{checked:p,disabled:l,onChange:w}):null,e.jsx("p",{className:"text-xs text-fg-dim",children:l?"Saved as audio-only — you're out of transcription minutes this month.":p?"Transcript will be appended once your vault processes it. Save to commit.":"Saved as audio-only — transcription is off for this recording."})]}):e.jsxs("div",{className:"mb-4 flex flex-wrap items-center justify-between gap-3 rounded-xl border border-border bg-card/60 p-3",children:[e.jsx("div",{className:"text-xs text-fg-dim",children:m?f>1?`Recording — tap Stop to finish. (part ${f})`:"Recording — tap Stop to finish.":r?"Requesting microphone…":l?"You're out of transcription minutes this month — this saves as audio-only.":p?"Add a voice memo to this note. Audio gets transcribed and appended.":"Add a voice memo to this note. Saved as audio-only — transcription is off for this recording."}),m?e.jsxs("button",{type:"button",onClick:()=>void h(),"aria-label":`Recording — ${X(d)} — stop`,"aria-pressed":"true",className:"flex min-h-11 items-center gap-2 rounded-full border border-danger-border bg-danger-soft px-4 py-2 text-sm font-medium text-danger",children:[e.jsx("span",{"aria-hidden":"true",className:"animate-pulse",children:"🎙"}),e.jsxs("span",{children:["Stop ",X(d)]})]}):e.jsxs("button",{type:"button",onClick:()=>void u(),"aria-label":"Record voice memo",disabled:r,className:"flex min-h-11 items-center gap-2 rounded-full border border-accent/30 bg-accent/10 px-4 py-2 text-sm font-medium text-accent hover:bg-accent/15 disabled:opacity-40",children:[e.jsx("span",{"aria-hidden":"true",children:"🎙"}),e.jsx("span",{children:r?"Requesting…":"Record"})]}),g?e.jsx(ve,{checked:p,disabled:l,onChange:w}):null,i&&!l?e.jsxs("p",{className:"basis-full text-xs text-fg-dim","data-testid":"voice-minutes-left",children:["About ",Math.round(c)," min of transcription left this month."]}):null,n.kind==="denied"?e.jsx("p",{className:"basis-full rounded-xl border border-danger-border bg-danger-soft px-3 py-2 text-xs text-danger",children:n.message}):null]})}function X(t){const c=Math.floor(t/1e3),l=Math.floor(c/60),b=c%60;return`${String(l).padStart(2,"0")}:${String(b).padStart(2,"0")}`}export{Ut as NoteNew};