@openparachute/app 0.22.11 → 0.22.13
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.
- package/CHANGELOG.md +141 -75
- package/dist/.parachute/info +1 -1
- package/dist/assets/{Account-Cl5c8tEo.js → Account-CRPq4eky.js} +1 -1
- package/dist/assets/Activity-BLLN2kgu.js +1 -0
- package/dist/assets/{AddVault-DoCaI37K.js → AddVault-BR5gZWT3.js} +1 -1
- package/dist/assets/{AddVaultChooser-Xvu3Uphy.js → AddVaultChooser-Bq8pAkVc.js} +1 -1
- package/dist/assets/{AddVaultCreate-Di9wcscn.js → AddVaultCreate-m_9BeV_Q.js} +1 -1
- package/dist/assets/Calendar-65Irth8Y.js +1 -0
- package/dist/assets/{CheckEmail-ntqd1kZe.js → CheckEmail-encZZOxl.js} +1 -1
- package/dist/assets/{ConnectAI-CUJNLwHZ.js → ConnectAI-B7gqvDkQ.js} +1 -1
- package/dist/assets/DayView-DsQr2XvT.js +1 -0
- package/dist/assets/{Export-BFGWcvOW.js → Export-BRO5DUzT.js} +1 -1
- package/dist/assets/{Import-2WIsPfSi.js → Import-_1c63gXI.js} +1 -1
- package/dist/assets/NoteEditor-C1s0DRwJ.js +1 -0
- package/dist/assets/NoteNew-D2gDWKnW.js +8 -0
- package/dist/assets/{NoteRenderer-DG6I-BOG.js → NoteRenderer-BwgvmHZD.js} +1 -1
- package/dist/assets/{NoteView-Dy3cUyrT.js → NoteView-BtXvo-Ke.js} +3 -3
- package/dist/assets/{OAuthCallback-W5STO-7I.js → OAuthCallback-Dne6nN7G.js} +1 -1
- package/dist/assets/{PinArchiveButtons-8xFKv2oH.js → PinArchiveButtons-BaeSYCvb.js} +1 -1
- package/dist/assets/{Settings-ClPAPWCJ.js → Settings-C5Q_6IiY.js} +1 -1
- package/dist/assets/{TagPage-pYbWcmlY.js → TagPage-Bz58IORf.js} +1 -1
- package/dist/assets/{TagSchemaEditor-ve19B-tr.js → TagSchemaEditor-YXqxcc95.js} +1 -1
- package/dist/assets/{Tags-DGl9Zubj.js → Tags-DIhbbif6.js} +1 -1
- package/dist/assets/{VaultGraph-BrDsta1c.js → VaultGraph-OyvE7-1G.js} +3 -3
- package/dist/assets/{Vaults-DWoDm-Th.js → Vaults-DZTvLJL0.js} +1 -1
- package/dist/assets/{ViewNew-D3N3bUyp.js → ViewNew-CEWGH98c.js} +1 -1
- package/dist/assets/ViewSurface-BVVt4eto.js +1 -0
- package/dist/assets/Welcome-DcaF7cVO.js +1 -0
- package/dist/assets/{WizardShell-eATuMAXz.js → WizardShell-BpDtpsOX.js} +1 -1
- package/dist/assets/{attachment-upload-D6wfJsr6.js → attachment-upload-BqMcsBiB.js} +1 -1
- package/dist/assets/{history-BHtc79G3.js → history-v1ErfO2u.js} +1 -1
- package/dist/assets/index-BBWRhmyM.css +1 -0
- package/dist/assets/index-C2wr_d3O.js +66 -0
- package/dist/assets/{provenance-BFQb2w9-.js → provenance-C8B5Q0ir.js} +1 -1
- package/dist/assets/{react-force-graph-2d-BZd7whjL.js → react-force-graph-2d-BtLtJaOD.js} +1 -1
- package/dist/assets/{transcribe-default-Cjxt7F_e.js → transcribe-default-BCVfDb3s.js} +1 -1
- package/dist/assets/{useAttachmentUploader-Be6yFw7I.js → useAttachmentUploader-BmtZQjNW.js} +2 -2
- package/dist/index.html +2 -2
- package/dist/sw.js +1 -1
- package/meta.json +1 -1
- package/package.json +3 -2
- package/dist/assets/Activity-BcJHDfuw.js +0 -1
- package/dist/assets/Calendar-DBe5DpLx.js +0 -1
- package/dist/assets/DayView-jTXjnokv.js +0 -1
- package/dist/assets/NoteEditor-DT4kYH2h.js +0 -1
- package/dist/assets/NoteNew-B7fbwu7C.js +0 -8
- package/dist/assets/ViewSurface-CB97Dtg8.js +0 -1
- package/dist/assets/Welcome-C6zOVULl.js +0 -1
- package/dist/assets/index-BKfqr8sS.js +0 -66
- package/dist/assets/index-DBJfPBlG.css +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,55 @@
|
|
|
1
|
+
## [0.22.13] - 2026-08-21
|
|
2
|
+
|
|
3
|
+
**The round-two quality batch: saved views can be renamed in place, a crashed route recovers instead of taking the app down, code toggles stop leaving orphaned markers, Tailwind stops shipping dead CSS, and boot's own crash containment gets its re-key bug fixed before anyone hit it.** Twelve PRs since 0.22.12 — the original six independently reviewed pre-merge with zero must-fix escapes; the six added here each gated on watch-fail evidence plus full `bun run test` / `typecheck` / `lint`.
|
|
4
|
+
|
|
5
|
+
- **CHANGELOG entries for 0.22.10 and 0.22.11 land, reconstructed from npm publish timestamps and the release bump commits (#151, fixes #149).** Provable archaeology: an evidence table backs every date and commit range. Also confirms the existing 0.22.9 heading is correctly labeled — PR #126's own merge commit is the sole commit that ever set `package.json` to 0.22.9 — and documents why #119/#121/#123 (already headed at 0.22.6–0.22.8) aren't also owed entries under 0.22.10.
|
|
6
|
+
- **Toggling code across a bold/italic selection produces a real code span instead of orphaned `**` (#152, fixes #144).** The symmetric gap left by 0.22.12's bold/italic-across-code fix: the code-toggle selection now expands through overlapping strong/emphasis marks and preserves their delimiters as literal content inside the new span, covering both editor modes and the real `Mod-e` keymap.
|
|
7
|
+
- **Tailwind source discovery is rooted at `src/`, so prose text can't compile into CSS (#154, fixes #147).** The v4 scanner previously walked the whole repo, and CHANGELOG.md/STYLE.md prose that happened to look like utility classes silently emitted dead rules. A new `src/styles/tailwind.css` shim scopes discovery to `src/`; review measured 15 prose-derived dead rules plus the `--color-white` theme var removed from dist — every one verified dead, every real utility (including SpeedDial's group-hover variants) verified still present. The #145 bare-`[--var]` guard test tightens to the same boundary so it stops false-positiving on `arr[--i]`.
|
|
8
|
+
- **Date-view overflow stops retrying, polling, and refetching on focus (#155, fixes #148).** `DateViewOverflowError` is now a deterministic ceiling signal to the global retry policy rather than just another transient error, so an overflowed view isn't hammered with the same doomed request every 60 seconds or on every window focus. Explicit retries and invalidation-driven refetches still work — recovery via narrowing the query or changing the underlying data was verified through both paths.
|
|
9
|
+
- **Saved views get a first-class Rename action in the view header (#157, fixes #124).** Previously renaming meant editing the raw path by hand. Rename now turns the human-entered name into the canonical `Views/<name>` path via a same-note PATCH, blocks default/sanitized-duplicate collisions with the same helper the Save dialog already enforces, follows a returned ID change, and updates mounted Views navigation in place — optimistic concurrency throughout.
|
|
10
|
+
- **A render crash inside `/notes` or either BootGate path now shows a recovery card instead of taking the whole app down (#158, fixes #54).** The eager `/notes` VaultSurface and both BootGate paths that render the Recent VaultSurface (local active vault, session-resolved home) are wrapped in `RouteErrorBoundary`. A three-path integration test proves the crash stays contained: the route recovery card appears, app chrome survives where an active vault exists, and the full-page Reload fallback no longer takes over.
|
|
11
|
+
- **CHANGELOG version order restored — 0.22.8 sits above 0.22.7 again (#162, fixes #125).** A pure block swap verified by a heading scan, no content changes; the drift survived four releases before backlog triage caught it.
|
|
12
|
+
- **Strikethrough survives overlapping format-command toggles instead of leaving orphaned markers (#163, fixes #153).** Strikethrough joins the overlap set alongside bold, italic, and inline code — toggling in either direction now preserves and normalizes overlapping markers instead of emitting malformed markdown. Three new overlap cases reproduced the bug against unmodified `next`; boundary-touch and cross-format regression coverage added.
|
|
13
|
+
- **Landing and both boot-route paths are contained in an error boundary, and the boundary now re-keys on the boot decision rather than the URL (#164, fixes #160).** BootLoading and every Landing branch are wrapped in `RouteErrorBoundary`, so a front-door crash leaves the surrounding app shell alive instead of falling through to the app-level Reload boundary. The reset key changes from `location.key` to the boot decision itself: Landing form state now survives same-path history-key churn, while the boundary still clears when the boot decision actually changes. (Known dead end, out of scope here: with no active vault, the recovery card's "Back to notes" action lands back on `/` via VaultSurface's existing no-vault guard.)
|
|
14
|
+
- **Date-view overflow and error surfaces get a Retry action, and the no-retry/no-poll/no-focus-refetch policy is pinned through the real QueryClient (#165, fixes #156).** Activity, Calendar, and Day's overflow/error states can now be retried explicitly; Day's created/updated union refetches both halves together. `DateViewOverflowError`'s policy is now asserted against the actual QueryClient and observer options rather than just the error class, closing the verification gap #155 left open.
|
|
15
|
+
- **Saved-view rename closes its remaining edge cases (#166, fixes #159).** Case-only renames are now allowed, built-in paths compare case-insensitively in the rail, duplicate visible labels are rejected even when the colliding `#view` note lives outside `Views/`, and a raw path that reserves a built-in view name now warns instead of silently colliding.
|
|
16
|
+
- **Voice-note blobs are staged before the note is queued, with rollback on failure (#167, fixes #62).** Every voice-segment blob is staged before the note — or any attachment mutation — is enqueued; if a later staging write fails, earlier staged blobs for the same note roll back and the sync queue is left empty, closing the long-open gap where a blob-store failure could leave a partial note queued for a later, orphaned sync.
|
|
17
|
+
|
|
18
|
+
## [0.22.12] - 2026-08-21
|
|
19
|
+
|
|
20
|
+
**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.)
|
|
21
|
+
|
|
22
|
+
- **"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.
|
|
23
|
+
|
|
24
|
+
- **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.
|
|
25
|
+
|
|
26
|
+
- **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.
|
|
27
|
+
|
|
28
|
+
- **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).
|
|
29
|
+
|
|
30
|
+
- **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.
|
|
31
|
+
|
|
32
|
+
- **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.
|
|
33
|
+
|
|
34
|
+
- **The sync queue sends `transcribe: false` instead of dropping it (#128).** Rode `next` since 08-14.
|
|
35
|
+
|
|
36
|
+
## [0.22.11] - 2026-08-14
|
|
37
|
+
|
|
38
|
+
**A pinned-notes sub-list, honest fallback titles, tablet gets its own nav drawer, and releases stop depending on a human remembering to push a tag.** Four PRs, tag-triggered publish retired in favor of publish-on-merge.
|
|
39
|
+
|
|
40
|
+
- **Up to five pinned notes render under the Pinned rail row (#131).** Desktop Rail only, newest first, each linking to its note; hidden when there are none, no vault is active, or the rail is collapsed. The fetch is local to `Rail.tsx` rather than joining the shared `useNavBands()` derivation, and deliberately non-live (`live:false`) so a 5-note window isn't clobbered by a live subscription that ignores `limit` (app#109) — pin/unpin still updates immediately via query invalidation, cross-device converges on the existing poll/focus refetch. Mobile NavSheet parity is deferred, tangled with the tablet-nav work in #134.
|
|
41
|
+
- **Untitled notes fall back to their first content line, else a human-readable date/time (#132).** Covers voice notes and quick notes together through one shared `displayTitle()` helper, so every title surface (rows, cards, board/calendar/table, quick-switch) behaves the same by construction. Transcription-status markers (`_Transcript pending._`, `_Transcription unavailable._`, the monthly-limit marker, segmented `(part N)` variants), bare attachment embeds, and content that just repeats the note's own path/ULID are never headlined — whole-line matching only, so a real first line that merely contains marker text still titles the note.
|
|
42
|
+
- **Releases publish on merge to `main`, the tag push kept as an override (#133).** Ports hub's publish-on-merge pattern (hub#790): a `plan` job reads `package.json`'s version against the npm registry and publishes when that exact version isn't there yet — skip if already published, refuse rather than guess on an ambiguous registry response, refuse if publishing would move the `rc`/`latest` dist-tag backwards. Also fixes the dist-tag-from-ref bug hub hit for real (hub#792): the tag now derives from `package.json`'s own version rather than `GITHUB_REF_NAME`, which on a merge-triggered run is just `"main"` and would have sent every publish-on-merge to `@latest` regardless of prerelease status. This is the last release in this repo to ship via the old tag-triggered path (0.22.10, PR #130) — 0.22.11 itself published by merging its own bump PR (#135).
|
|
43
|
+
- **A third nav breakpoint band (768–1023px) gets a proper drawer instead of stretched phone chrome (#134).** Phone keeps the bottom-sheet nav below 768px, desktop rail is untouched at ≥1024px. The drawer force-closes via `matchMedia` when the viewport leaves its band in either direction (e.g. an iPad rotating across 1023.98px) and closes on pathname change only, never on the search string, since `VaultSurface` mirrors live filters into `?search=&tag=` and closing on full location would dismiss it per keystroke. The same force-close-at-band-edge protection was added to the phone `NavSheet`, fixing a real strand: rotating a phone to landscape (≥768px) with the sheet open used to leave a scroll-locked page with keyboard nav dead.
|
|
44
|
+
|
|
45
|
+
## [0.22.10] - 2026-08-10
|
|
46
|
+
|
|
47
|
+
**Three measured UI defects, fixed together: a toggle knob that rendered outside its own track, a retention prompt that interrupted recording mid-take, and an attachments panel that leaked raw internals.** One PR (#129), published the old tag-triggered way (release PR #130 bumped the version; the `v0.22.10` tag was pushed separately to trigger the npm publish) — the last release before #133 switched this repo to publish-on-merge.
|
|
48
|
+
|
|
49
|
+
- **The toggle knob now sits inside its track (#129).** It was absolutely positioned with no `left`, so it rendered ~20px outside the track — in `NoteNew`'s `TranscribeToggle` and both Settings toggles alike (the same latent bug, unnoticed in three places). The `NoteNew` wrapper also swaps `justify-between` for `gap-3`, since the label sat hundreds of pixels from its switch.
|
|
50
|
+
- **The first-voice-capture retention prompt now gates on `hasAudio` (#129).** It used to render the moment the mic engaged, interrupting the take with a choice before there was anything to keep; it now appears once recording stops, when the question makes sense. A failed PATCH still re-offers it on the next capture, and Create is never blocked on it.
|
|
51
|
+
- **In-flight attachments show a skeleton + "Processing…" instead of a bare ULID and "(no URL)" (#129).** Known tradeoff, flagged in review: a permanently URL-less attachment (an old failed upload) now shows an indefinite "Processing…" rather than the raw fallback — politer, but not a terminal state; a recency gate can follow if that shows up in practice.
|
|
52
|
+
|
|
1
53
|
## [0.22.9] - 2026-07-27
|
|
2
54
|
|
|
3
55
|
**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.**
|
|
@@ -10,6 +62,52 @@ Root cause: the app sent `segment_index` nested under a `metadata` object; both
|
|
|
10
62
|
|
|
11
63
|
Every new/changed assertion was watched failing first, including a scratch reproduction of the real bug against pre-fix `queue.ts` (confirmed it actually sent `{ metadata: { segment_index: 0 } }`, not `{ segment_index: 0 }`, before any production code changed), and the size-cap test against pre-fix `segmented-recorder.ts` (confirmed it could not roll early at all).
|
|
12
64
|
|
|
65
|
+
(Bookkeeping note, app#149: this heading is correctly labeled. #126's own merge commit (`eea0623`) is the `v0.22.9` tag target and is the sole commit that ever set `package.json` to `0.22.9`; npm published `0.22.9` ~18 minutes later. The 0.22.10 window (`v0.22.9..v0.22.10`) contains only #129 — #119/#121/#123 were already shipped and already have their own headings below, at 0.22.6/0.22.7/0.22.8. Those three intermediate versions were never tagged nor published individually — in that stretch only 0.22.5 and 0.22.9 ever reached npm, and only `v0.22.9` got a git tag — so npm's actual `0.22.9` tarball is the union of the 0.22.6–0.22.9 diffs even though each got its own changelog entry; this entry documents only the slice #126 itself added.)
|
|
66
|
+
|
|
67
|
+
## [0.22.8] - 2026-07-27
|
|
68
|
+
|
|
69
|
+
**The Filters panel no longer pushes the results list off the bottom of the
|
|
70
|
+
screen — it's an overlay now, and the active filters stay visible when it's
|
|
71
|
+
closed.**
|
|
72
|
+
|
|
73
|
+
Aaron's complaint, second half: "how we're doing the filtering, how we're
|
|
74
|
+
selecting the schemas... both in the filter and in the tag page." #119 fixed
|
|
75
|
+
the tag picker; a schema-menus PR fixed GROUP BY/FIELDS. This is the part that
|
|
76
|
+
actually explains why filtering "felt bad": the panel rendered in flow, so
|
|
77
|
+
opening it pushed the whole list down by its own height.
|
|
78
|
+
|
|
79
|
+
| | before | after |
|
|
80
|
+
| --- | --- | --- |
|
|
81
|
+
| Result rows visible, filter open, 1440×900 | **0** — first row landed at y=1174 | 5+ rows read clearly; the popover is a compact 26rem dropdown anchored under the trigger, list position on-screen is byte-for-byte unchanged (same DOM node, same coordinates) whether the panel is open or closed |
|
|
82
|
+
| Phone filter UI height | 945px, in flow, on an 844px screen | a bottom sheet capped at 70dvh (591px) over a scrim; the list is still live directly behind it |
|
|
83
|
+
| Active filters when the panel is closed | invisible (a bare "2" badge on the Filters button, no detail) | a chips row: `#tag ×`, `match any/all ▾` (2+ tags), `title: prefix ×`, `archived shown ×`, `oldest first ×`, trailing `Save as view…` |
|
|
84
|
+
|
|
85
|
+
- **Overlay, not inline flow.** Lifted `FieldsControl`'s own scrim + `fixed`
|
|
86
|
+
bottom-sheet / `sm:absolute` popover dual verbatim — the same pattern
|
|
87
|
+
already shipping elsewhere in this app, not a second overlay idiom. Escape
|
|
88
|
+
and outside-tap close it, same as `FieldsControl`.
|
|
89
|
+
- **Chips row replaces the badge.** Presence depends only on filter state,
|
|
90
|
+
never on whether the panel is open, so it can't itself cause the list to
|
|
91
|
+
shift. Reuses `RefinementChip` (now shared between this surface and
|
|
92
|
+
`ViewSurface`'s own refinement bar) rather than inventing a second
|
|
93
|
+
dismissable-filter affordance.
|
|
94
|
+
- **Saved views, retired as a manager on this surface.** The per-row
|
|
95
|
+
rename/update/delete menu is gone from the Filters panel — "a Filters panel
|
|
96
|
+
shouldn't also be a view manager." What's left is a quiet, closed-by-default
|
|
97
|
+
"Saved filters ▸" disclosure: click a name to load it, same links as today.
|
|
98
|
+
Nothing about the vault notes themselves changed; managing them is a
|
|
99
|
+
different surface's job.
|
|
100
|
+
- **Panel contents are otherwise the same** — Refine (sort, archived, title
|
|
101
|
+
prefix, Untagged/Orphaned), the tag browser + match mode, the lazy Folders
|
|
102
|
+
accordion (fetch-on-open unchanged) — just stacked in a single column now
|
|
103
|
+
that the popover is 26rem instead of the old 52rem-wide inline section.
|
|
104
|
+
|
|
105
|
+
State model and URL params are untouched — `searchParamsToFilters` round-trips
|
|
106
|
+
exactly as before, so old links and legacy saved views keep working.
|
|
107
|
+
Presentation only, same discipline as #119. No live result count anywhere
|
|
108
|
+
(vault#626 still tracks the real one) — the pager's "Showing 1–50 of 50+"
|
|
109
|
+
stays the only number.
|
|
110
|
+
|
|
13
111
|
## [0.22.7] - 2026-07-27
|
|
14
112
|
|
|
15
113
|
**GROUP BY and FIELDS now explain what a field's TYPE means for the menu, instead of offering 9 bare names and letting you find out the hard way.**
|
|
@@ -59,50 +157,6 @@ only. Every new test was watched failing before the fix (stub the type
|
|
|
59
157
|
dispatch, the exclusion, the preview, or the section/hint rendering out;
|
|
60
158
|
confirm each goes red for the stated reason; restore).
|
|
61
159
|
|
|
62
|
-
## [0.22.8] - 2026-07-27
|
|
63
|
-
|
|
64
|
-
**The Filters panel no longer pushes the results list off the bottom of the
|
|
65
|
-
screen — it's an overlay now, and the active filters stay visible when it's
|
|
66
|
-
closed.**
|
|
67
|
-
|
|
68
|
-
Aaron's complaint, second half: "how we're doing the filtering, how we're
|
|
69
|
-
selecting the schemas... both in the filter and in the tag page." #119 fixed
|
|
70
|
-
the tag picker; a schema-menus PR fixed GROUP BY/FIELDS. This is the part that
|
|
71
|
-
actually explains why filtering "felt bad": the panel rendered in flow, so
|
|
72
|
-
opening it pushed the whole list down by its own height.
|
|
73
|
-
|
|
74
|
-
| | before | after |
|
|
75
|
-
| --- | --- | --- |
|
|
76
|
-
| Result rows visible, filter open, 1440×900 | **0** — first row landed at y=1174 | 5+ rows read clearly; the popover is a compact 26rem dropdown anchored under the trigger, list position on-screen is byte-for-byte unchanged (same DOM node, same coordinates) whether the panel is open or closed |
|
|
77
|
-
| Phone filter UI height | 945px, in flow, on an 844px screen | a bottom sheet capped at 70dvh (591px) over a scrim; the list is still live directly behind it |
|
|
78
|
-
| Active filters when the panel is closed | invisible (a bare "2" badge on the Filters button, no detail) | a chips row: `#tag ×`, `match any/all ▾` (2+ tags), `title: prefix ×`, `archived shown ×`, `oldest first ×`, trailing `Save as view…` |
|
|
79
|
-
|
|
80
|
-
- **Overlay, not inline flow.** Lifted `FieldsControl`'s own scrim + `fixed`
|
|
81
|
-
bottom-sheet / `sm:absolute` popover dual verbatim — the same pattern
|
|
82
|
-
already shipping elsewhere in this app, not a second overlay idiom. Escape
|
|
83
|
-
and outside-tap close it, same as `FieldsControl`.
|
|
84
|
-
- **Chips row replaces the badge.** Presence depends only on filter state,
|
|
85
|
-
never on whether the panel is open, so it can't itself cause the list to
|
|
86
|
-
shift. Reuses `RefinementChip` (now shared between this surface and
|
|
87
|
-
`ViewSurface`'s own refinement bar) rather than inventing a second
|
|
88
|
-
dismissable-filter affordance.
|
|
89
|
-
- **Saved views, retired as a manager on this surface.** The per-row
|
|
90
|
-
rename/update/delete menu is gone from the Filters panel — "a Filters panel
|
|
91
|
-
shouldn't also be a view manager." What's left is a quiet, closed-by-default
|
|
92
|
-
"Saved filters ▸" disclosure: click a name to load it, same links as today.
|
|
93
|
-
Nothing about the vault notes themselves changed; managing them is a
|
|
94
|
-
different surface's job.
|
|
95
|
-
- **Panel contents are otherwise the same** — Refine (sort, archived, title
|
|
96
|
-
prefix, Untagged/Orphaned), the tag browser + match mode, the lazy Folders
|
|
97
|
-
accordion (fetch-on-open unchanged) — just stacked in a single column now
|
|
98
|
-
that the popover is 26rem instead of the old 52rem-wide inline section.
|
|
99
|
-
|
|
100
|
-
State model and URL params are untouched — `searchParamsToFilters` round-trips
|
|
101
|
-
exactly as before, so old links and legacy saved views keep working.
|
|
102
|
-
Presentation only, same discipline as #119. No live result count anywhere
|
|
103
|
-
(vault#626 still tracks the real one) — the pager's "Showing 1–50 of 50+"
|
|
104
|
-
stays the only number.
|
|
105
|
-
|
|
106
160
|
## [0.22.6] - 2026-07-27
|
|
107
161
|
|
|
108
162
|
**A typeahead for the tag picker, a shortlist instead of the whole list, and
|
|
@@ -1812,39 +1866,17 @@ at 6 digits with navigation, paste-with-context digit extraction, no-submit-befo
|
|
|
1812
1866
|
wrong-code error state (field cleared, no navigation) — 11 tests total (was 6). Full suite: 158 test
|
|
1813
1867
|
files / 1778 tests, ×2 clean; `typecheck` clean; `lint` clean (2 pre-existing warnings remain in
|
|
1814
1868
|
`src/lib/vault/live-query.ts`, untouched by this PR).
|
|
1815
|
-
## [0.20.9] - 2026-07-17
|
|
1816
1869
|
|
|
1817
|
-
|
|
1818
|
-
ratified direction ("the pack is an override, never a dependency") lands for the two smallest
|
|
1819
|
-
lenses: `/notes?view=pinned` and `/notes?view=archived` now resolve their tag filter from a
|
|
1820
|
-
`ViewDef` instead of a hardcoded literal, while everything else about those pages — search,
|
|
1821
|
-
Filters panel, pagination, `NoteRowList` rendering — is unchanged.
|
|
1822
|
-
|
|
1823
|
-
- **`src/lib/views/defaults.ts`** — `builtInDefaultViewDef(pageId, roles)`: the app's own
|
|
1824
|
-
fallback `ViewDef` for Pinned/Archive, mirroring the `starter-ontology` pack's own queries
|
|
1825
|
-
(`{tag: "pinned"}` / `{tag: "archived"}`, `core/src/seed-packs.ts`) byte-for-intent but through
|
|
1826
|
-
`roles.pinned`/`roles.archived` — a vault that renamed those tags still gets a correct default.
|
|
1827
|
-
`resolveDefaultViewDef(pageId, packNote, roles)`: the pure resolver — a `Views/Pinned` or
|
|
1828
|
-
`Views/Archive` note wins when it's present, tagged `#view`, and its query parses
|
|
1829
|
-
(authoring-time-explicit); anything else (no note, wrong tag, unparseable query) falls back to
|
|
1830
|
-
the built-in instantly. A default page is load-bearing navigation, not a place to show "this
|
|
1831
|
-
view is broken" over someone else's corrupted note — that honesty stays scoped to `/views/:id`.
|
|
1832
|
-
Also lifted the pack's four view paths to named constants (`PINNED_VIEW_PATH`, etc.) so
|
|
1833
|
-
`DEFAULT_VIEW_PATHS` and the new page-path lookup can't drift from each other.
|
|
1834
|
-
- **`src/lib/views/queries.ts`** — `useDefaultViewDef(pageId, roles)`: looks up the pack note at
|
|
1835
|
-
its canonical path (exact `path=` match, not `path_prefix`) via TanStack Query, then resolves
|
|
1836
|
-
through the pure function above. `pageId === null` skips the lookup (every other preset).
|
|
1837
|
-
- **`VaultSurface.tsx`** — `SearchableLenses`'s `effectiveTags` for the pinned/archived presets
|
|
1838
|
-
now reads `queryTags(resolvedDef.query)` (unioned with whatever the Filters panel's TagBrowser
|
|
1839
|
-
adds) instead of inlining `roles.pinned`/`roles.archived` directly. Resolution never blocks or
|
|
1840
|
-
blanks the page: the built-in def is available synchronously on first render, and the query
|
|
1841
|
-
quietly upgrades if/when a pack note resolves.
|
|
1870
|
+
## [0.20.11] - 2026-07-17
|
|
1842
1871
|
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1872
|
+
**Bookkeeping only: this version was reserved during parallel branch work but never existed as a
|
|
1873
|
+
release.** PR #53's draft said it would take 0.20.11 after the sibling 0.20.9/0.20.10 branches,
|
|
1874
|
+
but its merge commit (`8b5abdb`) actually set `package.json` to 0.20.10. The next first-parent
|
|
1875
|
+
commit that changed the version (`c2bcb45`, PR #56) moved directly to 0.20.12. No reachable commit
|
|
1876
|
+
ever set `package.json` to 0.20.11, no `v0.20.11` tag exists, and neither historical npm package
|
|
1877
|
+
published a 0.20.11 artifact. There are therefore no release contents to reconstruct for this
|
|
1878
|
+
heading; it records the intentional evidence-backed gap rather than assigning a later PR to a
|
|
1879
|
+
version it did not ship as.
|
|
1848
1880
|
|
|
1849
1881
|
## [0.20.10] - 2026-07-17
|
|
1850
1882
|
|
|
@@ -1888,6 +1920,40 @@ the class of bug remained). Display-only, small.
|
|
|
1888
1920
|
`App.error-boundary.chrome.test.tsx` (a mocked `Header` throws → the top-level net's full-page
|
|
1889
1921
|
card, no route chrome survives).
|
|
1890
1922
|
|
|
1923
|
+
## [0.20.9] - 2026-07-17
|
|
1924
|
+
|
|
1925
|
+
**Views Wave 2a — the first default-pages cutover (Pinned + Archive).** VIEWS-RENDER-SPEC §7's
|
|
1926
|
+
ratified direction ("the pack is an override, never a dependency") lands for the two smallest
|
|
1927
|
+
lenses: `/notes?view=pinned` and `/notes?view=archived` now resolve their tag filter from a
|
|
1928
|
+
`ViewDef` instead of a hardcoded literal, while everything else about those pages — search,
|
|
1929
|
+
Filters panel, pagination, `NoteRowList` rendering — is unchanged.
|
|
1930
|
+
|
|
1931
|
+
- **`src/lib/views/defaults.ts`** — `builtInDefaultViewDef(pageId, roles)`: the app's own
|
|
1932
|
+
fallback `ViewDef` for Pinned/Archive, mirroring the `starter-ontology` pack's own queries
|
|
1933
|
+
(`{tag: "pinned"}` / `{tag: "archived"}`, `core/src/seed-packs.ts`) byte-for-intent but through
|
|
1934
|
+
`roles.pinned`/`roles.archived` — a vault that renamed those tags still gets a correct default.
|
|
1935
|
+
`resolveDefaultViewDef(pageId, packNote, roles)`: the pure resolver — a `Views/Pinned` or
|
|
1936
|
+
`Views/Archive` note wins when it's present, tagged `#view`, and its query parses
|
|
1937
|
+
(authoring-time-explicit); anything else (no note, wrong tag, unparseable query) falls back to
|
|
1938
|
+
the built-in instantly. A default page is load-bearing navigation, not a place to show "this
|
|
1939
|
+
view is broken" over someone else's corrupted note — that honesty stays scoped to `/views/:id`.
|
|
1940
|
+
Also lifted the pack's four view paths to named constants (`PINNED_VIEW_PATH`, etc.) so
|
|
1941
|
+
`DEFAULT_VIEW_PATHS` and the new page-path lookup can't drift from each other.
|
|
1942
|
+
- **`src/lib/views/queries.ts`** — `useDefaultViewDef(pageId, roles)`: looks up the pack note at
|
|
1943
|
+
its canonical path (exact `path=` match, not `path_prefix`) via TanStack Query, then resolves
|
|
1944
|
+
through the pure function above. `pageId === null` skips the lookup (every other preset).
|
|
1945
|
+
- **`VaultSurface.tsx`** — `SearchableLenses`'s `effectiveTags` for the pinned/archived presets
|
|
1946
|
+
now reads `queryTags(resolvedDef.query)` (unioned with whatever the Filters panel's TagBrowser
|
|
1947
|
+
adds) instead of inlining `roles.pinned`/`roles.archived` directly. Resolution never blocks or
|
|
1948
|
+
blanks the page: the built-in def is available synchronously on first render, and the query
|
|
1949
|
+
quietly upgrades if/when a pack note resolves.
|
|
1950
|
+
|
|
1951
|
+
Tests: `defaults.test.ts` (10, pure — built-in query shape, role indirection, pack-wins,
|
|
1952
|
+
malformed-note fallback, non-`#view`-tagged decoy ignored), `VaultSurface.defaultViews.test.tsx`
|
|
1953
|
+
(5, integration — no-pack-note is byte-equivalent to today's hardcoded `tag=pinned`/`tag=archived`
|
|
1954
|
+
query, a well-formed pack note's tag wins, a malformed pack note falls back without blanking the
|
|
1955
|
+
page). All-notes + Recent are unaffected (wave 2b).
|
|
1956
|
+
|
|
1891
1957
|
## [0.20.8] - 2026-07-17
|
|
1892
1958
|
|
|
1893
1959
|
**Editor Wave 2 — focus mode.** POLISH-WAVE PR 4, plus EDITOR-STUDY §3.3's addition: one gesture
|
package/dist/.parachute/info
CHANGED
|
@@ -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-BKfqr8sS.js";import{f as K,a as S}from"./provenance-BFQb2w9-.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-C2wr_d3O.js";import{f as K,a as S}from"./provenance-C8B5Q0ir.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 y,t as f,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-C2wr_d3O.js";const x=1440*60*1e3,S=5e3;function T(a,i=30,t=new Date){const n=t.getTime()-i*x,r=[];for(const s of a){const o=s.path??s.id,d=Date.parse(s.createdAt);if(Number.isFinite(d)&&d>=n&&r.push({id:`${s.id}:created`,noteId:s.id,noteName:o,kind:"created",at:s.createdAt,preview:s.preview,tags:s.tags}),s.updatedAt){const l=Date.parse(s.updatedAt);Number.isFinite(l)&&l>=n&&Number.isFinite(d)&&l-d>S&&r.push({id:`${s.id}:updated`,noteId:s.id,noteName:o,kind:"updated",at:s.updatedAt,preview:s.preview,tags:s.tags})}}return r.sort((s,o)=>Date.parse(o.at)-Date.parse(s.at)),r}const _=["today","yesterday","thisWeek","older"],B={today:"Today",yesterday:"Yesterday",thisWeek:"This week",older:"Older"};function C(a,i=new Date){const t=Date.parse(a);if(!Number.isFinite(t))return null;const n=p(i),r=p(new Date(t)),s=Math.round((n.getTime()-r.getTime())/x);return s<0||s===0?"today":s===1?"yesterday":s<7?"thisWeek":"older"}function p(a){return new Date(a.getFullYear(),a.getMonth(),a.getDate())}function I(a,i=new Date){const t={today:[],yesterday:[],thisWeek:[],older:[]};for(const n of a){const r=C(n.at,i);r&&t[r].push(n)}return t}const h=50;function O(){const a=y(c=>c.getActiveVault()),i=f(g(),-29),t=j({field:"updated_at",from:N(i),limit:v}),[n,r]=u.useState(h),s=u.useMemo(()=>t.data?T(t.data):[],[t.data]),o=u.useMemo(()=>s.slice(0,n),[s,n]),d=u.useMemo(()=>I(o),[o]),l=s.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."})]}),t.isPending?e.jsx(V,{}):t.isError?e.jsx(F,{error:t.error,retry:()=>t.refetch()}):s.length===0?e.jsx(M,{}):e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"space-y-8",children:_.map(c=>d[c].length>0?e.jsx(R,{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 R({title:a,events:i}){return e.jsxs("section",{children:[e.jsxs("h2",{className:"eyebrow mb-3",children:[a," (",i.length,")"]}),e.jsx("ol",{className:"card shadow-soft divide-y divide-border rounded-xl",children:i.map(t=>e.jsx("li",{children:e.jsxs(m,{to:`/n/${encodeURIComponent(t.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(L,{kind:t.kind}),e.jsx("span",{className:"truncate font-mono text-sm text-fg",children:t.noteName})]}),e.jsx("span",{className:"shrink-0 text-xs text-fg-dim",children:k(t.at)})]}),t.preview?e.jsx("p",{className:"mt-1 truncate text-sm text-fg-muted",children:t.preview}):null,t.tags&&t.tags.length>0?e.jsx("div",{className:"mt-2 flex flex-wrap gap-1.5",children:t.tags.map(n=>e.jsxs("span",{className:"chip chip-tag max-w-full break-all",children:["#",n]},n))}):null]})},t.id))})]})}function L({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 M(){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,retry:i}){const t=a instanceof A;return e.jsx(D,{title:t?"Session expired":"Could not load activity",message:a.message,action:t?e.jsx(m,{to:"/add",className:"btn btn-primary",children:"Reconnect vault"}):e.jsx("button",{type:"button",onClick:i,className:"btn btn-secondary",children:"Retry"})})}export{O as Activity};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
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-C2wr_d3O.js";import{W as L}from"./WizardShell-BpDtpsOX.js";import{s as M}from"./url-QSQwrjSV.js";import"./history-v1ErfO2u.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,
|
|
1
|
+
import{b as o,Q as c,a as d,j as e,P as m}from"./index-C2wr_d3O.js";import{W as x}from"./WizardShell-BpDtpsOX.js";import"./history-v1ErfO2u.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,
|
|
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-C2wr_d3O.js";import{W as g}from"./WizardShell-BpDtpsOX.js";import"./history-v1ErfO2u.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 C,Y as v,Z as m,_ as V,L as c,D as P,V as Y}from"./index-C2wr_d3O.js";const I=["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],g=5;function W(){const s=S(t=>t.getActiveVault()),[d]=k(),n=d.get("month"),r=j(n)??j(N()),x=A(),l=u.useMemo(()=>T(r.year,r.month),[r.year,r.month]),$=u.useMemo(()=>{const t=l[0],a=l[l.length-1];return{from:t.toISOString(),to:new Date(a.getFullYear(),a.getMonth(),a.getDate()+1).toISOString()}},[l]),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 i=K(a.createdAt);i&&t.set(i,(t.get(i)??0)+1)}return t},[o.data]);if(!s)return e.jsx(C,{to:"/",replace:!0});const p=v(r.year,r.month,-1),b=v(r.year,r.month,1),y=`${p.year}-${m(p.month)}`,f=`${b.year}-${m(b.month)}`,D=N(),w=`${r.year}-${m(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:V(r.year,r.month)})]}),e.jsxs("div",{className:"flex flex-wrap items-center gap-2 text-sm",children:[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":"Previous month",children:["← ",y]}),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=${f}`,className:"rounded-lg border border-border bg-card px-3 py-1.5 text-fg-muted hover:text-accent","aria-label":"Next month",children:[f," →"]}),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(F,{error:o.error,retry:()=>o.refetch()}):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:l.map(t=>{const a=`${t.getFullYear()}-${m(t.getMonth()+1)}-${m(t.getDate())}`,i=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 ${i?"":"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(R,{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 R({count:s}){const d=Math.min(s,g),n=s>g?s-g:0;return e.jsxs("span",{className:"flex flex-wrap items-center gap-0.5",children:[Array.from({length:d}).map((r,x)=>e.jsx("span",{className:"h-1.5 w-1.5 rounded-full bg-accent","aria-hidden":"true"},x)),n>0?e.jsxs("span",{className:"ml-0.5 text-[10px] text-fg-dim",children:["+",n]}):null]})}function F({error:s,retry:d}){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"}):e.jsx("button",{type:"button",onClick:d,className:"btn btn-secondary",children:"Retry"})]})}export{W as Calendar};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{b as S,r as s,
|
|
1
|
+
import{b as S,r as s,Q as E,j as e,N as R,P as I,g as f,bF as L,bG as M,bH as O}from"./index-C2wr_d3O.js";import{W}from"./WizardShell-BpDtpsOX.js";import"./history-v1ErfO2u.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
|
|
1
|
+
import{a as m,j as e,N as h,L as l,$ as o}from"./index-C2wr_d3O.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,j as e,N as v,v as L,a0 as B,x as w,t as p,w as k,D as E,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-C2wr_d3O.js";import{u as Q}from"./history-v1ErfO2u.js";function Z(){const a=R(t=>t.getActiveVault()),[n]=C(),s=n.get("date");return a?s===null?e.jsx(v,{to:"/",replace:!0}):e.jsx(W,{dateParam:s}):e.jsx(v,{to:"/",replace:!0})}function W({dateParam:a}){const n=Q("/"),s=L(),t=a||s,r=B(t),b=w(t)??"",j=w(p(t,1))??"",c=k({field:"created_at",from:b,to:j,limit:E,enabled:!!r}),i=k({field:"updated_at",from:b,to:j,limit:E,enabled:!!r}),x=S.useMemo(()=>{if(!(!c.data||!i.data))return[...new Map([...c.data,...i.data].map(l=>[l.id,l])).values()]},[c.data,i.data]),P=c.isPending||i.isPending,h=c.error??i.error,d=S.useMemo(()=>{const l=[],y=[];if(!x||!r)return{created:l,edited:y};for(const m of x){const g=D(m.createdAt),V=D(m.updatedAt??m.createdAt);g===t&&l.push(m),V===t&&g!==t&&y.push(m)}return{created:l,edited:y}},[x,r,t]);if(!r)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===s,f=p(t,-1),N=p(t,1),T=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:n,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=${f}`,className:"btn btn-secondary btn-sm","aria-label":"Previous day",children:["← ",f]}),u?null:e.jsx(o,{to:"/",className:"btn btn-secondary btn-sm",children:"Today"}),e.jsxs(o,{to:`/today?date=${N}`,className:"btn btn-secondary btn-sm","aria-label":"Next day",children:[N," →"]}),e.jsx(o,{to:`/calendar?month=${T}`,className:"btn btn-secondary btn-sm",children:"Calendar"}),e.jsx(o,{to:"/new",className:"btn btn-primary btn-sm",children:"+ New note"})]})]}),P?e.jsx(Y,{}):h&&!x?e.jsx(q,{error:h,retry:()=>{Promise.all([c.refetch(),i.refetch()])}}):d.created.length===0&&d.edited.length===0?e.jsx(X,{isToday:u,targetKey:t}):e.jsxs("div",{className:"space-y-8",children:[h?e.jsx(I,{}):null,d.created.length>0?e.jsx(A,{title:u?"Created today":`Created on ${t}`,notes:d.created}):null,d.edited.length>0?e.jsx(A,{title:u?"Edited today":`Edited on ${t}`,notes:d.edited}):null]})]})}function A({title:a,notes:n}){const s=R(r=>r.getActiveVault()),{roles:t}=O((s==null?void 0:s.id)??null);return e.jsxs("section",{children:[e.jsxs(U,{children:[a," (",n.length,")"]}),e.jsx(z,{children:n.map(r=>e.jsx(F,{note:r,pinnedTag:t.pinned,archivedTag:t.archived},r.id))})]})}function X({isToday:a,targetKey:n}){return e.jsx(M,{title:a?"Nothing yet today — start capturing.":`Nothing on ${n}.`,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,retry:n}){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"}):e.jsx("button",{type:"button",onClick:n,className:"btn btn-secondary",children:"Retry"})})}export{Z as DayView};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{a as u,
|
|
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-C2wr_d3O.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};
|