@book.dev/ui 1.60.0 → 1.65.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/dist/{EmojiGrid-xK5mPJPo.js → EmojiGrid-BjFEmkhL.js} +75 -84
  2. package/dist/blockeditor/BlockEditor.d.ts +16 -0
  3. package/dist/blockeditor/EmojiMenu.d.ts +17 -0
  4. package/dist/blockeditor/__tests__/EmojiMenu.test.d.ts +1 -0
  5. package/dist/blockeditor/__tests__/readOnly.test.d.ts +1 -0
  6. package/dist/blockeditor/__tests__/titleHandoff.test.d.ts +1 -0
  7. package/dist/blockeditor/__tests__/triggerMenus.test.d.ts +1 -0
  8. package/dist/blockeditor/kit/KitFrame.d.ts +5 -0
  9. package/dist/blockeditor/kit/groupSync.d.ts +10 -1
  10. package/dist/blockeditor/kit/lock.d.ts +14 -0
  11. package/dist/components/LastEditedBy.d.ts +11 -0
  12. package/dist/components/OnboardingNudge.d.ts +11 -0
  13. package/dist/components/ShareDialog.d.ts +25 -0
  14. package/dist/components/__tests__/lastEditedBy.test.d.ts +1 -0
  15. package/dist/components/__tests__/membersSettings.test.d.ts +1 -0
  16. package/dist/components/__tests__/sharingSettings.test.d.ts +1 -0
  17. package/dist/components/settings/AccountSettings.d.ts +4 -0
  18. package/dist/components/settings/AccountSwitcher.d.ts +12 -0
  19. package/dist/components/settings/MembersSettings.d.ts +1 -0
  20. package/dist/components/settings/SharingSettings.d.ts +9 -0
  21. package/dist/emoji-Bmft6RPl.js +11 -0
  22. package/dist/{format-CLQoRoYP.js → format-BXeG5xQH.js} +61 -61
  23. package/dist/i18n/messages/en.d.ts +169 -0
  24. package/dist/index.js +7328 -6057
  25. package/dist/lib/__tests__/useCanWrite.test.d.ts +1 -0
  26. package/dist/lib/hud.d.ts +2 -2
  27. package/dist/lib/sidebarStyles.d.ts +7 -0
  28. package/dist/lib/useCanWrite.d.ts +45 -0
  29. package/dist/{lucideIcons-B6pmC-WQ.js → lucideIcons-DvomlmkS.js} +2093 -1180
  30. package/dist/providers/AccountProvider.d.ts +47 -7
  31. package/dist/providers/ForwardingProvider.d.ts +19 -0
  32. package/dist/providers/PlatformLibraryProvider.d.ts +20 -0
  33. package/dist/providers/PreferencesProvider.d.ts +8 -1
  34. package/dist/providers/WorkspaceProvider.d.ts +4 -2
  35. package/dist/providers/__tests__/AccountProvider.test.d.ts +1 -0
  36. package/dist/providers/__tests__/forwardingAudience.test.d.ts +9 -0
  37. package/dist/providers/forwardingAudience.d.ts +165 -0
  38. package/dist/screens/pageChrome.d.ts +11 -0
  39. package/dist/style.css +1 -1
  40. package/dist/{toHtml-BoPr8Ce4.js → toHtml-B6gQeUnu.js} +2 -2
  41. package/package.json +7 -2
@@ -1,4 +1,4 @@
1
- import { B as e, G as t, Mt as n, V as r, a as i, g as a, kt as o, p as s, r as c } from "./lucideIcons-B6pmC-WQ.js";
1
+ import { At as e, B as t, Nt as n, V as r, a as i, g as a, p as o, r as s, tt as c } from "./lucideIcons-DvomlmkS.js";
2
2
  import { i as l } from "./pageIcon-BWTy7hAh.js";
3
3
  import { t as u } from "./exportBlocks-33D7P_8Q.js";
4
4
  import * as d from "react";
@@ -14,7 +14,7 @@ import * as k from "@radix-ui/react-popover";
14
14
  //#region src/components/PageIcon.tsx
15
15
  function A({ value: e, fallback: t = "📄", className: r }) {
16
16
  if (e && i(e)) {
17
- let i = c(e);
17
+ let i = s(e);
18
18
  return i ? /* @__PURE__ */ v(i, {
19
19
  "aria-hidden": !0,
20
20
  className: n("inline-block shrink-0 align-[-0.125em]", r),
@@ -162,7 +162,7 @@ function Re(e) {
162
162
  }
163
163
  function ze(e) {
164
164
  if (!e || typeof e != "object") return null;
165
- let t = s(e);
165
+ let t = o(e);
166
166
  return t && Object.keys(t).length > 0 ? t : null;
167
167
  }
168
168
  function Be(e, t) {
@@ -348,19 +348,19 @@ var Ze = ({ data: e, onOpen: t }) => /* @__PURE__ */ y("div", {
348
348
  children: e
349
349
  })]
350
350
  });
351
- function $e(t, n) {
351
+ function $e(e, n) {
352
352
  if (n == null || n === "" || Array.isArray(n) && n.length === 0) return null;
353
- switch (t.type) {
353
+ switch (e.type) {
354
354
  case "select":
355
355
  case "status": {
356
- let e = t.options?.find((e) => e.id === n);
357
- return e ? /* @__PURE__ */ v(Qe, {
358
- label: e.label,
359
- color: e.color
356
+ let t = e.options?.find((e) => e.id === n);
357
+ return t ? /* @__PURE__ */ v(Qe, {
358
+ label: t.label,
359
+ color: t.color
360
360
  }) : null;
361
361
  }
362
362
  case "multi_select": {
363
- let e = Array.isArray(n) ? n : [], r = (t.options ?? []).filter((t) => e.includes(t.id));
363
+ let t = Array.isArray(n) ? n : [], r = (e.options ?? []).filter((e) => t.includes(e.id));
364
364
  return r.length ? /* @__PURE__ */ v("span", {
365
365
  className: "truncate",
366
366
  children: r.map((e) => e.label).join(", ")
@@ -368,10 +368,10 @@ function $e(t, n) {
368
368
  }
369
369
  case "relation":
370
370
  case "dependency": {
371
- let t = Array.isArray(n) ? n : [];
372
- return t.length ? /* @__PURE__ */ v("span", {
371
+ let e = Array.isArray(n) ? n : [];
372
+ return e.length ? /* @__PURE__ */ v("span", {
373
373
  className: "truncate",
374
- children: t.map((t) => e.label(t)).join(", ")
374
+ children: e.map((e) => t.label(e)).join(", ")
375
375
  }) : null;
376
376
  }
377
377
  case "checkbox": return n === !0 ? "✓" : null;
@@ -386,27 +386,27 @@ function $e(t, n) {
386
386
  }
387
387
  }
388
388
  var et = /* @__PURE__ */ new Map();
389
- function tt(e, n) {
390
- let r = t(), [i, a] = h(() => et.get(e) ?? null);
389
+ function tt(e, t) {
390
+ let n = c(), [r, i] = h(() => et.get(e) ?? null);
391
391
  return p(() => {
392
- if (!n || i) return;
393
- let t = !0;
392
+ if (!t || r) return;
393
+ let a = !0;
394
394
  return (async () => {
395
- let n = await r.getPage(e);
396
- if (!n || !t) return;
397
- let i = n.databaseId ? (await r.getDatabase(n.databaseId))?.schema.properties ?? [] : [], o = Je(e), s = [];
398
- for (let e of i) {
395
+ let t = await n.getPage(e);
396
+ if (!t || !a) return;
397
+ let r = t.databaseId ? (await n.getDatabase(t.databaseId))?.schema.properties ?? [] : [], o = Je(e), s = [];
398
+ for (let e of r) {
399
399
  if (s.length >= 5) break;
400
400
  if (e.id === ie || e.pageHidden) continue;
401
- let t = $e(e, n.properties[e.id]);
402
- t != null && s.push({
401
+ let n = $e(e, t.properties[e.id]);
402
+ n != null && s.push({
403
403
  id: e.id,
404
404
  label: e.name,
405
- node: t
405
+ node: n
406
406
  });
407
407
  }
408
408
  let c = {
409
- title: n.name?.trim() || "Untitled",
409
+ title: t.name?.trim() || "Untitled",
410
410
  icon: l(e),
411
411
  cover: o?.kind === "gradient" ? { background: o.css } : o?.kind === "image" ? {
412
412
  backgroundImage: `url("${o.url}")`,
@@ -415,19 +415,19 @@ function tt(e, n) {
415
415
  } : void 0,
416
416
  fields: s
417
417
  };
418
- et.set(e, c), t && a(c);
418
+ et.set(e, c), a && i(c);
419
419
  })(), () => {
420
- t = !1;
420
+ a = !1;
421
421
  };
422
422
  }, [
423
- n,
423
+ t,
424
424
  e,
425
- i,
426
- r
427
- ]), i;
425
+ r,
426
+ n
427
+ ]), r;
428
428
  }
429
- var nt = ({ rowId: t, children: n, openDelay: r = 280 }) => {
430
- let [i, a] = h(!1), o = m(void 0), s = tt(t, i), c = () => {
429
+ var nt = ({ rowId: e, children: n, openDelay: r = 280 }) => {
430
+ let [i, a] = h(!1), o = m(void 0), s = tt(e, i), c = () => {
431
431
  clearTimeout(o.current), o.current = setTimeout(() => a(!0), r);
432
432
  }, l = () => {
433
433
  clearTimeout(o.current), o.current = setTimeout(() => a(!1), 140);
@@ -450,7 +450,7 @@ var nt = ({ rowId: t, children: n, openDelay: r = 280 }) => {
450
450
  onOpenAutoFocus: (e) => e.preventDefault(),
451
451
  children: s ? /* @__PURE__ */ v(Ze, {
452
452
  data: s,
453
- onOpen: () => e.openPage(t)
453
+ onOpen: () => t.openPage(e)
454
454
  }) : /* @__PURE__ */ v("div", {
455
455
  className: "p-3 text-xs text-muted-foreground",
456
456
  children: "Loading…"
@@ -464,8 +464,8 @@ function rt(e, t, n, r) {
464
464
  return t.type === "expr" ? e.exports[t.cellName ?? t.name] : t.type === "formula" || t.type === "rollup" ? pe(e, t, n, r) : t.type === "created_time" ? e.createdAt : t.type === "last_edited_time" ? e.updatedAt : e.properties[t.id];
465
465
  }
466
466
  function it() {
467
- let { preferences: e } = o();
468
- return e.profile.displayName.trim() || e.profile.name.trim() || "You";
467
+ let { preferences: t } = e();
468
+ return t.profile.displayName.trim() || t.profile.name.trim() || "You";
469
469
  }
470
470
  var at = ({ name: e }) => /* @__PURE__ */ y("span", {
471
471
  className: "inline-flex max-w-full items-center gap-1 truncate rounded-full bg-muted px-2 py-0.5 text-xs",
@@ -561,9 +561,9 @@ function mt(e, t) {
561
561
  return String(e);
562
562
  }
563
563
  }
564
- function ht(t, n, r, i) {
565
- let a = rt(t, n, r, i);
566
- return n.type === "relation" ? (Array.isArray(a) ? a : []).map((t) => e.label(t)).join("; ") : n.type === "dependency" ? (Array.isArray(a) ? a : []).map((e) => i.find((t) => t.id === e)?.name?.trim() || "Untitled").join("; ") : n.type === "files" ? (Array.isArray(a) ? a : []).join("; ") : Y(n, a);
564
+ function ht(e, n, r, i) {
565
+ let a = rt(e, n, r, i);
566
+ return n.type === "relation" ? (Array.isArray(a) ? a : []).map((e) => t.label(e)).join("; ") : n.type === "dependency" ? (Array.isArray(a) ? a : []).map((e) => i.find((t) => t.id === e)?.name?.trim() || "Untitled").join("; ") : n.type === "files" ? (Array.isArray(a) ? a : []).join("; ") : Y(n, a);
567
567
  }
568
568
  function gt(e, t, n) {
569
569
  let r = (e) => /[",\n]/.test(e) ? `"${e.replace(/"/g, "\"\"")}"` : e, i = [["Name", ...t.map((e) => e.name)].map(r).join(",")];
@@ -1145,57 +1145,57 @@ var X = "w-full bg-transparent px-2 py-1 text-sm outline-hidden placeholder:text
1145
1145
  })]
1146
1146
  })] })]
1147
1147
  })] });
1148
- }, Mt = ({ property: n, value: i, onChange: o }) => {
1149
- let s = Array.isArray(i) ? i : [], [c, l] = h(""), [u, d] = h(!1), [p, m] = h(null), g = t(), { setPageHint: _ } = a(), b = n.relationDatabaseId, x = !!n.relationSingle, [, ee] = f.useReducer((e) => e + 1, 0);
1148
+ }, Mt = ({ property: e, value: n, onChange: i }) => {
1149
+ let o = Array.isArray(n) ? n : [], [s, l] = h(""), [u, d] = h(!1), [p, m] = h(null), g = c(), { setPageHint: _ } = a(), b = e.relationDatabaseId, x = !!e.relationSingle, [, ee] = f.useReducer((e) => e + 1, 0);
1150
1150
  f.useEffect(() => r(ee), []), f.useEffect(() => {
1151
- if (!b || p !== null || !u && s.length === 0) return;
1152
- let t = !0;
1151
+ if (!b || p !== null || !u && o.length === 0) return;
1152
+ let e = !0;
1153
1153
  return g.listRows(b).then((n) => {
1154
- if (!t) return;
1155
- let r = n.map((t) => ({
1156
- id: t.id,
1157
- label: t.name?.trim() || e.label(t.id),
1158
- icon: e.icon(t.id)
1154
+ if (!e) return;
1155
+ let r = n.map((e) => ({
1156
+ id: e.id,
1157
+ label: e.name?.trim() || t.label(e.id),
1158
+ icon: t.icon(e.id)
1159
1159
  }));
1160
1160
  m(r), r.forEach((e) => _(e.id, e.label));
1161
- }).catch(() => t && m([])), () => {
1162
- t = !1;
1161
+ }).catch(() => e && m([])), () => {
1162
+ e = !1;
1163
1163
  };
1164
1164
  }, [
1165
1165
  u,
1166
1166
  b,
1167
- s.length,
1167
+ o.length,
1168
1168
  p,
1169
1169
  g,
1170
1170
  _
1171
1171
  ]);
1172
- let te = (t) => p?.find((e) => e.id === t)?.label ?? e.label(t), ne = c.trim().toLowerCase(), S = b ? (p ?? []).filter((e) => !s.includes(e.id) && (!ne || e.label.toLowerCase().includes(ne))) : e.searchPages(c).filter((e) => !s.includes(e.id)), C = (e) => {
1173
- o(x ? [e] : [...s, e]), l(""), x && d(!1);
1174
- }, re = (e) => o(s.filter((t) => t !== e)), w = b ? "row" : "page";
1172
+ let te = (e) => p?.find((t) => t.id === e)?.label ?? t.label(e), ne = s.trim().toLowerCase(), S = b ? (p ?? []).filter((e) => !o.includes(e.id) && (!ne || e.label.toLowerCase().includes(ne))) : t.searchPages(s).filter((e) => !o.includes(e.id)), C = (e) => {
1173
+ i(x ? [e] : [...o, e]), l(""), x && d(!1);
1174
+ }, re = (e) => i(o.filter((t) => t !== e)), w = b ? "row" : "page";
1175
1175
  return /* @__PURE__ */ y("div", {
1176
1176
  className: "flex min-h-[28px] flex-wrap items-center gap-1 px-2 py-1",
1177
- children: [s.map((t) => /* @__PURE__ */ y("span", {
1177
+ children: [o.map((e) => /* @__PURE__ */ y("span", {
1178
1178
  className: "inline-flex max-w-full items-center gap-1 rounded-md border border-border/60 px-1.5 py-0.5 text-xs",
1179
1179
  children: [/* @__PURE__ */ v(nt, {
1180
- rowId: t,
1180
+ rowId: e,
1181
1181
  children: /* @__PURE__ */ y("span", {
1182
1182
  className: "inline-flex min-w-0 items-center gap-1",
1183
1183
  children: [/* @__PURE__ */ v("span", {
1184
1184
  className: "leading-none",
1185
- children: e.icon(t)
1185
+ children: t.icon(e)
1186
1186
  }), /* @__PURE__ */ v("span", {
1187
1187
  className: "max-w-[120px] truncate",
1188
- children: te(t)
1188
+ children: te(e)
1189
1189
  })]
1190
1190
  })
1191
1191
  }), /* @__PURE__ */ v("button", {
1192
1192
  type: "button",
1193
- onClick: () => re(t),
1193
+ onClick: () => re(e),
1194
1194
  className: "text-muted-foreground/70 transition-colors hover:text-destructive",
1195
1195
  "aria-label": "Remove link",
1196
1196
  children: /* @__PURE__ */ v(D, { className: "h-3 w-3" })
1197
1197
  })]
1198
- }, t)), (!x || s.length === 0) && /* @__PURE__ */ y(W, {
1198
+ }, e)), (!x || o.length === 0) && /* @__PURE__ */ y(W, {
1199
1199
  open: u,
1200
1200
  onOpenChange: d,
1201
1201
  children: [/* @__PURE__ */ v(G, {
@@ -1211,7 +1211,7 @@ var X = "w-full bg-transparent px-2 py-1 text-sm outline-hidden placeholder:text
1211
1211
  className: "w-60 p-1",
1212
1212
  children: [/* @__PURE__ */ v("input", {
1213
1213
  autoFocus: !0,
1214
- value: c,
1214
+ value: s,
1215
1215
  onChange: (e) => l(e.target.value),
1216
1216
  placeholder: `Link a ${w}…`,
1217
1217
  className: "mb-1 w-full rounded bg-accent/40 px-1.5 py-1 text-sm outline-hidden"
@@ -36,6 +36,7 @@ export declare const en: {
36
36
  readonly signin: "Sign-in & email";
37
37
  readonly support: "Support OpenBook";
38
38
  readonly connection: "Connection";
39
+ readonly members: "Members";
39
40
  readonly integrations: "Integrations";
40
41
  readonly extensions: "Extensions";
41
42
  readonly ai: "AI";
@@ -167,6 +168,51 @@ export declare const en: {
167
168
  readonly linkToPage: "Link to page";
168
169
  };
169
170
  };
171
+ readonly share: {
172
+ readonly open: "Share";
173
+ readonly title: "Share this page";
174
+ readonly description: "Choose who can access this page, and invite people to view or edit it.";
175
+ readonly loadError: "Couldn’t load sharing settings for this page.";
176
+ readonly unclaimedNotice: "Sharing takes effect once you claim this instance. Until then, anyone who can reach it can view and edit — these settings are saved but not yet enforced.";
177
+ readonly enforcementCaveat: "People you invite may not be able to open this page through its published book.pub link yet — that’s rolling out. Direct access is already limited as set here.";
178
+ readonly scopeLabel: "Who can access";
179
+ readonly scope: {
180
+ readonly inherit: "Workspace default";
181
+ readonly inheritHint: "Follows the workspace’s default access setting.";
182
+ readonly public: "Anyone with the link";
183
+ readonly publicHint: "Visible to anyone, including people who aren’t signed in.";
184
+ readonly authenticated: "Anyone signed in";
185
+ readonly authenticatedHint: "Limits viewing to people who are signed in.";
186
+ readonly members: "Workspace members";
187
+ readonly membersHint: "Limits viewing to members of this workspace.";
188
+ readonly restricted: "Only people invited";
189
+ readonly restrictedHint: "Limits access to you and the people you invite below.";
190
+ };
191
+ readonly addLabel: "Invite people";
192
+ readonly addPlaceholder: "Email or handle";
193
+ readonly levelLabel: "Access level";
194
+ readonly levelRead: "Can view";
195
+ readonly levelWrite: "Can edit";
196
+ readonly peopleLabel: "People with access";
197
+ readonly loadingPeople: "Loading people…";
198
+ readonly noPeople: "No one’s been invited yet.";
199
+ readonly remove: "Remove {name}";
200
+ readonly linkHints: {
201
+ readonly inherit: "People with workspace access can open this link.";
202
+ readonly public: "Anyone with the link can open this page.";
203
+ readonly authenticated: "Anyone signed in who opens this link can view this page.";
204
+ readonly members: "Only workspace members who open this link can view this page.";
205
+ readonly restricted: "Only the people you invite can open this link.";
206
+ };
207
+ readonly copyLink: "Copy link";
208
+ readonly copied: "Copied";
209
+ readonly error: {
210
+ readonly network: "Couldn’t reach the server. Check your connection and try again.";
211
+ readonly forbidden: "You don’t have permission to change sharing for this page.";
212
+ readonly notFound: "This page no longer exists.";
213
+ readonly generic: "Something went wrong. Please try again.";
214
+ };
215
+ };
170
216
  readonly command: {
171
217
  readonly title: "Command palette";
172
218
  readonly placeholder: "Search pages or run a command…";
@@ -342,6 +388,36 @@ export declare const en: {
342
388
  readonly confirmBodyNone: "No existing pages match — these will be added as new pages.";
343
389
  readonly confirmOverwrite: "Overwrite";
344
390
  };
391
+ readonly schedule: {
392
+ readonly heading: "Scheduled backups";
393
+ readonly intro: "Automatic snapshots on a rolling schedule — kept alongside your manual exports, with older ones pruned for you.";
394
+ readonly webOnly: "Scheduled backups run in the desktop app or on a connected server. In the browser, use Export above to save a copy.";
395
+ readonly enable: "Enable scheduled backups";
396
+ readonly enableHint: "When on, OpenBook writes snapshots to the folder below and keeps a rolling set per interval.";
397
+ readonly cadenceDaily: "Daily";
398
+ readonly cadenceWeekly: "Weekly";
399
+ readonly cadenceMonthly: "Monthly";
400
+ readonly cadenceYearly: "Yearly";
401
+ readonly keptLast: "Last {when} · {count} kept";
402
+ readonly never: "No backup yet";
403
+ readonly backupNow: "Back up now";
404
+ readonly backingUp: "Backing up…";
405
+ readonly ranNow: "Backed up — {file}";
406
+ readonly folder: "Backup folder";
407
+ };
408
+ };
409
+ readonly storage: {
410
+ readonly heading: "Storage";
411
+ readonly intro: "Compact the local database to reclaim disk space. Editing leaves behind storage overhead that this rewrites away; the app pauses briefly while it runs.";
412
+ readonly compact: "Compact database";
413
+ readonly compacting: "Compacting…";
414
+ readonly confirmTitle: "Compact the database?";
415
+ readonly confirmBody: "This rewrites the local database to reclaim space and may take a moment. The app will pause until it finishes.";
416
+ readonly confirmAction: "Compact";
417
+ readonly reclaimed: "Reclaimed {amount} — database is now {size}.";
418
+ readonly alreadyCompact: "Already compact — nothing to reclaim ({size}).";
419
+ readonly unavailable: "Compaction isn’t available for this server.";
420
+ readonly failed: "Compaction failed: {error}";
345
421
  };
346
422
  readonly workspace: {
347
423
  readonly workspaces: "Workspaces";
@@ -890,6 +966,33 @@ export declare const en: {
890
966
  readonly manualPlaceholder: "Paste your code or openbook://auth-callback#token=… link";
891
967
  readonly manualSubmit: "Sign in with code";
892
968
  };
969
+ readonly switcher: {
970
+ readonly heading: "Accounts";
971
+ readonly activeAccount: "Active account";
972
+ readonly active: "Active";
973
+ readonly syncing: "Syncing…";
974
+ readonly error: "Needs attention";
975
+ readonly dormant: "Signed in";
976
+ readonly switchTo: "Switch to {name}";
977
+ readonly addAnother: "Add another account";
978
+ readonly removeAccount: "Remove {name} from this device";
979
+ readonly removeConfirmTitle: "Remove {name}?";
980
+ readonly removeConfirmBody: "This forgets {name} on this device only — sign in again any time to restore it. Your other accounts and your local data are untouched.";
981
+ readonly signOutActiveHint: "Sign out forgets the active account on this device; your other accounts stay signed in. To fully revoke a device, remove it in your account dashboard.";
982
+ };
983
+ readonly error: {
984
+ readonly rejected: "That sign-in was rejected. Please try again.";
985
+ readonly rejectedReauth: "That sign-in was rejected. Please sign in again.";
986
+ readonly unreachable: "Could not reach account.book.pub. Check your connection.";
987
+ readonly syncFailed: "Sync failed — will retry on the next change.";
988
+ readonly invalidCode: "That doesn’t look like a valid code. Paste the code (or the whole openbook:// link) from the browser.";
989
+ };
990
+ readonly nudge: {
991
+ readonly title: "Sync and publish";
992
+ readonly body: "Sign up free to keep your preferences and workspaces in sync across devices — then publish your work to the web. Local-first stays the default.";
993
+ readonly cta: "Get started free";
994
+ readonly dismiss: "Dismiss";
995
+ };
893
996
  readonly support: {
894
997
  readonly title: "Support OpenBook";
895
998
  readonly description: "OpenBook is independent and open source. Sharing it and sending feedback helps it grow. Sponsorship options are on the way.";
@@ -907,6 +1010,14 @@ export declare const en: {
907
1010
  readonly copy: "Copy";
908
1011
  readonly copied: "Copied";
909
1012
  readonly failed: "Couldn’t register: {error}";
1013
+ readonly partialUnscoped: "Forwarding is on, but your account did not issue a site-scoped owner token, so strict audience isolation stays off (a token minted for a different site is still rejected, and the tunnel works normally).";
1014
+ readonly ensureRescope: "Forwarding resumed, but this session could not scope your owner token to the site yet. Your existing access is unchanged; sign in again if a request is refused.";
1015
+ readonly bindFailed: "Forwarding is on, but securing the site audience didn’t finish: {error}";
1016
+ readonly unbindHeld: "Couldn’t fully relax the audience binding while turning forwarding off: {error}";
1017
+ readonly claimWarning: "The first time you turn this on, this device’s books are claimed to your account and made private — only you and members you invite can open them. This can’t be undone.";
1018
+ readonly claimRefusedUnverified: "To publish, your account identity needs to be verified first.";
1019
+ readonly refreshIdentity: "Refresh identity";
1020
+ readonly claimFailed: "Couldn’t claim this device for your account, so it wasn’t published. Try again.";
910
1021
  readonly status: {
911
1022
  readonly live: "Live";
912
1023
  readonly connecting: "Connecting";
@@ -951,6 +1062,64 @@ export declare const en: {
951
1062
  readonly changeFolder: "Change…";
952
1063
  readonly reveal: "Reveal in Finder";
953
1064
  };
1065
+ readonly sharing: {
1066
+ readonly title: "Guests & access";
1067
+ readonly description: "Control what people who haven’t signed in can do on this shared workspace. Your own access is never affected.";
1068
+ readonly youUser: "You’re acting as {name}.";
1069
+ readonly youGuestNamed: "You’re editing as guest “{name}”.";
1070
+ readonly youGuestAnon: "You’re editing as an anonymous guest.";
1071
+ readonly guestAccess: "Guest access";
1072
+ readonly guestAccessHint: "Applies to anyone reaching this workspace without signing in — over the network or a shared ✦.book.pub link.";
1073
+ readonly guestWrite: "Read & edit";
1074
+ readonly guestRead: "Read only";
1075
+ readonly guestOff: "No access";
1076
+ readonly ownerLocked: "Only the workspace owner can change this.";
1077
+ readonly saveError: "Couldn’t update access — {error}";
1078
+ };
1079
+ readonly members: {
1080
+ readonly title: "Members";
1081
+ readonly description: "People with a role on this workspace. Invite by email or handle, change who can manage, and remove access.";
1082
+ readonly youUser: "You’re signed in as {name}.";
1083
+ readonly youGuest: "You’re browsing as a guest.";
1084
+ readonly loading: "Loading members…";
1085
+ readonly empty: "No members yet. Invite someone above to get started.";
1086
+ readonly loadError: "Couldn’t load members — {error}";
1087
+ readonly retry: "Try again";
1088
+ readonly unavailable: "This workspace’s server doesn’t support members yet.";
1089
+ readonly lockedTitle: "Members are managed by admins";
1090
+ readonly locked: "Ask a workspace admin to invite you or change a role.";
1091
+ readonly lockedRoleOwner: "You can’t change the owner’s role";
1092
+ readonly lockedRoleSelf: "You can’t change your own role here";
1093
+ readonly lockedRemoveOwner: "You can’t remove the owner";
1094
+ readonly lockedRemoveSelf: "You can’t remove yourself";
1095
+ readonly inviteLabel: "Invite a member";
1096
+ readonly inviteHint: "Enter an email address or a handle (iss#sub). An email invite is claimed when that person first signs in.";
1097
+ readonly invitePlaceholder: "name@example.com or iss#sub";
1098
+ readonly inviteRole: "Role for the invite";
1099
+ readonly invite: "Invite";
1100
+ readonly inviteError: "Couldn’t invite — {error}";
1101
+ readonly listLabel: "Current members";
1102
+ readonly roleAdmin: "Admin";
1103
+ readonly roleViewer: "Viewer";
1104
+ readonly changeRole: "Change role for {name}";
1105
+ readonly statusActive: "Active";
1106
+ readonly statusInvited: "Invited";
1107
+ readonly statusSuspended: "Suspended";
1108
+ readonly you: "You";
1109
+ readonly owner: "Owner";
1110
+ readonly remove: "Remove {name}";
1111
+ readonly removeTitle: "Remove {name}?";
1112
+ readonly removeBody: "They’ll lose their role on this workspace. An email invite can be re-sent later.";
1113
+ readonly removeConfirm: "Remove";
1114
+ readonly actionError: "Couldn’t update member — {error}";
1115
+ };
1116
+ readonly provenance: {
1117
+ readonly editedBy: "Edited by {name}";
1118
+ readonly justNow: "just now";
1119
+ readonly aGuest: "a guest";
1120
+ readonly someone: "someone";
1121
+ readonly unverified: "unverified identity";
1122
+ };
954
1123
  readonly integrations: {
955
1124
  readonly title: "Integrations";
956
1125
  readonly description: "Connect OpenBook to other tools. Integrations aren’t available yet — this is where they’ll live.";